Click here to Skip to main content
15,861,172 members
Articles / Desktop Programming / WTL

Form Designer

26 Jul 2021CPOL24 min read 349.8K   82.5K   230  
Component for adding scriptable forms capabilities to an application.
// Driver.cpp : Implementation of CDriver
//
// Author : David Shepherd
//			Copyright (c) 2003, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Driver.h"

CDriver::CDriver()
{
	// initialise everything
	m_LockCount=0;
}

HRESULT CDriver::FinalConstruct()
{
	return S_OK;
}

void CDriver::FinalRelease()
{
}

DWORD CDriver::GetLineCount()
{
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw std::exception();
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw std::exception();
	}
	// return the number of lines in the editor
	long LineCount=0;
	if(!SUCCEEDED(spCodeSense->get_LineCount(&LineCount)))
	{
		throw std::exception();
	}
	return LineCount;
}

DWORD CDriver::GetLineLength(DWORD Line)
{
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw std::exception();
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw std::exception();
	}
	// return the length of the specified line in the editor
	long LineLength=0;
	if(!SUCCEEDED(spCodeSense->GetLineLength(Line,&LineLength)))
	{
		throw std::exception();
	}
	return LineLength;
}

CComPtr<CodeSense::IPosition> CDriver::CreatePosition(DWORD Line,DWORD Col)
{
	// create the position
	CComPtr<CodeSense::IPosition> spPosition;
	if(!SUCCEEDED(spPosition.CoCreateInstance(__uuidof(CodeSense::Position))))
	{
		throw std::exception();
	}
	// set the line number
	if(!SUCCEEDED(spPosition->put_LineNo(Line)))
	{
		throw std::exception();
	}
	// set the column number
	if(!SUCCEEDED(spPosition->put_ColNo(Col)))
	{
		throw std::exception();
	}
	return spPosition;
}

CComPtr<CodeSense::IRange> CDriver::CreateRange(
	DWORD StartLine,DWORD StartCol,DWORD EndLine,DWORD EndCol)
{
	// create the range
	CComPtr<CodeSense::IRange> spRange;
	if(!SUCCEEDED(spRange.CoCreateInstance(__uuidof(CodeSense::Range))))
	{
		throw std::exception();
	}
	// disable column selection
	if(!SUCCEEDED(spRange->put_ColumnSel(VARIANT_FALSE)))
	{
		throw std::exception();
	}
	// set the start line number
	if(!SUCCEEDED(spRange->put_StartLineNo(StartLine)))
	{
		throw std::exception();
	}
	// set the start column number
	if(!SUCCEEDED(spRange->put_StartColNo(StartCol)))
	{
		throw std::exception();
	}
	// set the end line number
	if(!SUCCEEDED(spRange->put_EndLineNo(EndLine)))
	{
		throw std::exception();
	}
	// set the end column number
	if(!SUCCEEDED(spRange->put_EndColNo(EndCol)))
	{
		throw std::exception();
	}
	return spRange;
}

STDMETHODIMP CDriver::get_Editor(IUnknown** pVal)
{
IMP_BEGIN
	// check parameters
	if(pVal==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the editor
	*pVal=m_spEditor;
	if(*pVal!=NULL)	// add ref it
	{
		(void)(*pVal)->AddRef();
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::put_Editor(IUnknown* newVal)
{
IMP_BEGIN
	// set the editor
	m_spEditor=newVal;
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::LockExternal(/*[in]*/ BOOL Lock)
{
IMP_BEGIN
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// update the lock count
	Lock ? m_LockCount++ : m_LockCount--;
	// update the editor state
	if(m_LockCount > 0)
	{
		// read only
		if(!SUCCEEDED(spCodeSense->put_ReadOnly(VARIANT_TRUE)))
		{
			throw CHResult(E_FAIL);
		}
	}
	else
	{
		// read writable
		if(!SUCCEEDED(spCodeSense->put_ReadOnly(VARIANT_FALSE)))
		{
			throw CHResult(E_FAIL);
		}
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::GetLineCount(/*[out]*/ DWORD *pCount)
{
IMP_BEGIN
	// check parameters
	if(pCount==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// return the number of lines in the editor
	*pCount=GetLineCount();
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::FindText(
	/*[in]*/ DWORD Start,
	/*[in]*/ LPCOLESTR pText,
	/*[out]*/ BOOL *pFound,
	/*[out]*/ DWORD *pLine)
{
IMP_BEGIN
	// check parameters
	if(Start >= GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(pText==NULL)
	{
		throw CHResult(E_POINTER);
	}
	if(wcslen(pText)==0)
	{
		throw CHResult(E_INVALIDARG);
	}
	if(pFound==NULL)
	{
		throw CHResult(E_POINTER);
	}
	if(pLine==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// look for the text in each line
	*pFound=FALSE;
	for(long l=Start; l<(long)GetLineCount(); l++)
	{
		// get the next line
		CComBSTR Line;
		if(!SUCCEEDED(spCodeSense->GetLine(l,&Line)))
		{
			throw CHResult(E_FAIL);
		}
		// look for an exact substring match
		std::wstring str(BSTR2W(Line));
		if(str.find(pText)!=std::wstring::npos)
		{
			*pLine=l;
			*pFound=TRUE;
			break;	// finished
		}
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::InsertLines(
	/*[in]*/ DWORD Start,
	/*[in]*/ DWORD Count,
	/*[in, size_is(Count)]*/ LPCOLESTR *pLines)
{
IMP_BEGIN
	// check parameters
	if(Start > GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(pLines==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw CHResult(E_FAIL);
	}
	if(Count==0)	// special case
	{
		throw CHResult(S_OK);
	}
	// create CRLF tokenised lines
	std::list<std::wstring> Lines;
	ComServerStringArrayFromClient(Count,pLines,Lines);
	std::wstring TokenisedLines;
	if(Start==GetLineCount())
	{
		TokenisedLines=L"\r\n";	// required to create a new line
	}
	std::list<std::wstring>::const_iterator iter=Lines.begin();
	while(iter!=Lines.end())
	{
		TokenisedLines+=iter->c_str();
		iter++;
		if(iter!=Lines.end())	// if more lines follow
		{
			TokenisedLines+=L"\r\n";
		}
	}
	// begin following lines on a new line
	if(Start!=GetLineCount())
	{
		TokenisedLines+=L"\r\n";
	}
	// get the insertion point
	CComPtr<CodeSense::IPosition> spPosition;
	if(Start==GetLineCount())
	{
		// end of last line
		spPosition=CreatePosition(Start-1,GetLineLength(Start-1));
	}
	else
	{
		// start of new line
		spPosition=CreatePosition(Start,0);
	}
	// insert the text
	if(!SUCCEEDED(spCodeSense->InsertText(
		CComBSTR(TokenisedLines.c_str()),spPosition)))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::GetLines(
	/*[in]*/ DWORD Start,
	/*[in]*/ DWORD Count,
	/*[out, size_is(,Count)]*/ LPOLESTR **ppLines)
{
IMP_BEGIN
	// check parameters
	if(Start >= GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(Start+Count > GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(ppLines==NULL)
	{
		throw CHResult(E_POINTER);
	}
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// get the required lines
	std::list<std::wstring> Lines;
	for(long l=Start; l<(long)(Start+Count); l++)
	{
		// get the next line
		CComBSTR Line;
		if(!SUCCEEDED(spCodeSense->GetLine(l,&Line)))
		{
			throw CHResult(E_FAIL);
		}
		// add it to the array
		Lines.push_back(BSTR2W(Line));
	}
	*ppLines=const_cast<LPOLESTR*>(ComServerStringArrayToClient(Lines));
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::DeleteLines(
	/*[in]*/ DWORD Start,
	/*[in]*/ DWORD Count)
{
IMP_BEGIN
	// check parameters
	if(Start >= GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	if(Start+Count > GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw CHResult(E_FAIL);
	}
	if(Count==0)	// special case
	{
		throw CHResult(S_OK);
	}
	// get the last line to delete
	DWORD End=Start+Count-1;
	// deletion range
	CComPtr<CodeSense::IRange> spRange;
	// case (a)
	// there are no preceding or following lines
	if(Start==0 and End==GetLineCount()-1)
	{
		// create the deletion range
		spRange=CreateRange(Start,0,End,GetLineLength(End));
	}
	// case (b)
	// there are no preceding lines
	else if(Start==0)
	{
		// create the deletion range
		spRange=CreateRange(Start,0,End+1,0);
	}
	// case (c)
	// there are no following lines
	else if(End==GetLineCount()-1)
	{
		// create the deletion range
		spRange=CreateRange(
			Start-1,GetLineLength(Start-1),End,GetLineLength(End));
	}
	// select the deletion range
	if(!SUCCEEDED(spCodeSense->SetSel(spRange,VARIANT_FALSE)))
	{
		throw CHResult(E_FAIL);
	}
	// delete the lines
	if(!SUCCEEDED(spCodeSense->DeleteSel()))
	{
		throw CHResult(E_FAIL);
	}
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::ModifyLines(
	/*[in]*/ DWORD Start,
	/*[in]*/ DWORD End,
	/*[in]*/ DWORD Count,
	/*[in, size_is(Count)]*/ LPCOLESTR *pLines)
{
IMP_BEGIN
	// todo : add this when required
	throw CHResult(E_NOTIMPL);
	// todo : ensure the modified flag is correct
IMP_END
	return RetVal;
}

STDMETHODIMP CDriver::GoToLine(/*[in]*/ DWORD Line)
{
IMP_BEGIN
	// check parameters
	if(Line >= GetLineCount())
	{
		throw CHResult(E_INVALIDARG);
	}
	// get the ICodeSense interface
	if(m_spEditor==NULL)
	{
		throw CHResult(E_FAIL);
	}
	CComQIPtr<CodeSense::ICodeSense> spCodeSense(m_spEditor);
	if(spCodeSense==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// move the cursor to the requested line
	if(!SUCCEEDED(spCodeSense->SetCaretPos(Line,0)))
	{
		throw CHResult(E_FAIL);
	}
	// get the IOleInPlaceObject interface
	CComQIPtr<IOleInPlaceObject> spOleInPlaceObject(spCodeSense);
	if(spOleInPlaceObject==NULL)
	{
		throw CHResult(E_FAIL);
	}
	// give focus to the editor
	HWND hWnd=NULL;
	if(!SUCCEEDED(spOleInPlaceObject->GetWindow(&hWnd)))
	{
		throw CHResult(E_FAIL);
	}
	(void)SetFocus(hWnd);
IMP_END
	return RetVal;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions