建置一個 WINCE 下的 XML BASE 的人機介面引擎 ---- 繪圖引擎篇 (3)

3 篇文章 0 订阅
1 篇文章 0 订阅
由於工作閞係,需要去客戶那駐廠支援,偏偏去支援的廠商老闆太節檢了,不只網路時好時壞,且照明也只有一般公司辨公區的一半照明,為了我眼睛的建康,

在休息時也不想再從事會需要花眼力的事務,所以此篇和上一篇的間格時間會如此久的原因在此,在此真的很配服在ASS辨公的員工,在那超低照明的環境,還能勇敢的作業,

一點也不怕以後視力的問題,以犧牲健康換來的收入,最終還是要連本帶利的加倍還回去,我是不想幫以後的眼科醫生增加收入,在以此養生觀來勸一些想入 SW 這行的的後進



本BLOG所有原創之原始程式碼皆為本人創作,非經本人同意不得轉載,非經本人授權不得使用在營利用途

回到主題上次在簡單說明了,image decoder 的原理後,接下來便是繪圖部份 ,在此請先看先繪圖的部份 source code


#include "atlcoll.h"
#include "..\common\fontobject.h"
#include "..\HLXDocvw\HLXXMLDocument.h"

#pragma once

#define	ANIMATION_EFFECTS_UP		(1)
#define	ANIMATION_EFFECTS_DOWN		(2)
#define	ANIMATION_EFFECTS_LEFT		(4)
#define	ANIMATION_EFFECTS_RIGHT		(8)
#define	ANIMATION_EFFECTS_OPEN		(16)
#define	ANIMATION_EFFECTS_CLOSE		(32)


class CControls;

class CDialogBase :	public CFontObject
{
	DECLARE_DATA_MAP()
public:
	CDialogBase(void);
	~CDialogBase(void);

	bool Construct( void );
	bool SetStorageMonitorMonitor(IStorageMonitor* pMonitor );
	
	inline LONG AddControl( void )
	{
		return ++m_lControlCount;
	}

	void StartMouseFilter( void )
	{
		m_dwDialogTick = ::GetTickCount();
	}

	void OnDialogActive( void );
	void OnDialogDeActive( void );
	BOOL BringWindowToTop() throw()
	{
		if( m_hWndBase != NULL )
		{
			ATLASSERT(::IsWindow(m_hWndBase));
			return ::BringWindowToTop(m_hWndBase);
		}
		return FALSE;
	}

	inline bool IsFocusControl( CControls* pControl )
	{
		return( m_pFocus != NULL && m_pFocus == pControl);
	}

	inline bool SetSafeHWND( HWND hWnd )
	{	
		ATLASSERT(::IsWindow(hWnd));
		m_hWndBase = hWnd;
		return true;
	}

	inline HWND GetSafeHWND( void )
	{	
		return m_hWndBase;
	}


	bool UpdateWindow( void )
	{
		if( m_hWndBase != NULL )
			::UpdateWindow(m_hWndBase);
		return false;
	}

	inline void PumpMessage( void )
	{
		MSG msg;

		while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) 
		{
			BOOL bRet = GetMessage(&msg, NULL, 0, 0); 

			if( bRet > 0 )
			{
				TranslateMessage(&msg); 
				DispatchMessage(&msg); 
			}
			else if(0 == bRet) 
			{
				PostQuitMessage(0); 
			}
			else
			{
				// Error, ignored
			}
		}
	}


	bool WaitMessage( void )
	{
		if( m_hWndBase != NULL )
		{
			PumpMessage();
			return true;
		}
		return false;
	}

	bool InvalidateRect( RECT& rct ,bool bErase )
	{
		if( m_hWndBase != NULL )
			::InvalidateRect(m_hWndBase,&rct,bErase);
		return false;
	}

	bool SetDocument( CHLXXMLDocument* pDocument ,DocumentTypeEnum DocumentOpenType );
	inline CHLXXMLDocument* GetDocument( void )
	{
		return m_pDocument;
	}


	CControls* GetControlObject( LPCWSTR lpID );
	bool GetObject( LPCWSTR lpID ,IDispatch** pDispatch );
	void OnAddControlID( CXMLParse* pControl );

protected:
	static	DWORD			m_dwThreadID;
	static	LONG			m_lEventCount;
	static	EVENT_STRUCT*	m_pEventList;
	static	UINT			m_hEventMessage;

	CComPtr<IStorageMonitor>	m_spMonitor;
	LONG					m_lMessageCount;
	MESSAGE_STRUCT*			m_pMessageList;

protected:
	DWORD					m_dwDialogTick;

	DWORD					m_dwAnimationEffectd;
	bool					m_bAnimation;
	bool					m_bAnimationActiveOnly;
	CComBSTR				m_strAnimation;

	bool					m_bActive;
	RECT					m_rckeep;
	HWND					m_hWndBase;
	POINT					m_ptMouseUpPoint;
	DWORD					m_dwMouseUpTick;
	DocumentTypeEnum		m_DocumentOpenType;
	CHLXXMLDocument*		m_pDocument;
	LONG					m_lControlCount;
	CComBSTR				m_bstrLoad;
	CControls*				m_pFocus;
	CComPtr<IUnknown>		m_spUnkContainer;
	CAtlList<CControls*>	m_list;
	CAtlList<CControls*>	m_namelist;
	CAtlList<CControls*>	m_timerlist;
	

	bool OnMouseEvent( UINT uMsg ,CControls* pControl ,POINT pt );
	bool OnAddControl( CXMLParse* pControl ,CComPtr<IXMLDOMNode>& pNode );
	HRESULT OnTimeControls( void );
	HRESULT OnLoadControls( void );
	HRESULT OnDrawControls(HDC hdcDraw ,LPCRECTL prcWBounds ,HRGN hRgn=NULL );
	LRESULT OnButtonControl(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnEventMessage(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);

	void SetWindowActive(bool bStatus);

public:
	inline bool GetDocumentDispatch(IDispatch** pDocument)
	{
		if( pDocument != NULL && m_pDocument != NULL && SUCCEEDED(m_pDocument->QueryInterface(IID_IDispatch,(LPVOID*)pDocument)) )
			return true;
		return false;
	}

	inline bool GetDispatch( IDispatch** pDispatch)
	{

		if( pDispatch != NULL && SUCCEEDED(m_pDocument->get_window(pDispatch)) )
			return true;
		return false;
	}

	inline bool GetParentDispatch( IDispatch** pDispatch )
	{
		if( pDispatch != NULL && SUCCEEDED(m_pDocument->get_parentwindow(pDispatch)) )
			return true;
		return false;
	}
	virtual bool CloseClientWindow(HWND hWnd)=0;
	bool CloseClient(HWND hWnd)
	{
		return CloseClientWindow(hWnd);
	}
	bool OnLoad( void )
	{
		return true;
	}

	int DrawAnimation(HWND hWnd ,bool bCreate=false );
private:
	static DWORD WINAPI ThreadProc( LPVOID lpParameter );
	DWORD WINAPI OnEventProc( void );
	bool OnCreateEvent(LONG length ,EVENT_STRUCT* pEventList);
	bool OnCreateMessage(LONG length ,MESSAGE_STRUCT* pEventList);
	bool ReleaseControl(void);

};


這是表頭部份,一些小又會常被使用的小功能都用 inline 使 CPU runtime 時不因 clear pipeline 而增加負擔,可能有人注意到, List 我不用 STL 而用 ATL 的 CAtlList 原因是在我比較2 者的模版後,在效能上還是以 CAtlList 在 ATL上比較好

同理在其他方面不用 STD 的理由也是相同, 一切以在 WINCE上效能考慮為優先,當然不代表我完全放棄在各平台的相容性考量,這完全是演算分析用法得失之間的平衡結果,

往後此平衡感的應用會很多


#include "StdAfx.h"
#include <atlctl.h>
#define	ANIMATION_STEP	(6)

#include "DialogBase.h"
#include "..\controls\controls.h"
#include "..\HLXDocvw\XMLElement.h"
#include "..\HLXDocvw\HLXDialogImpl.h"

BEGIN_DATA_MAP( CDialogBase )
	PROP_DATA_STR( "animation"	,m_strAnimation );
	PROP_DATA_BOOL( "animation-active-only"	,m_bAnimationActiveOnly );
	PROP_DATA_LONG( "keep-left",m_rckeep.left );
	PROP_DATA_LONG( "keep-top",m_rckeep.top );
	PROP_DATA_LONG( "keep-right",m_rckeep.right );
	PROP_DATA_LONG( "keep-bottom",m_rckeep.bottom );
	PROP_DATA_STR( "onload",m_bstrLoad );
END_DATA_MAP()

DWORD			CDialogBase::m_dwThreadID;

LONG			CDialogBase::m_lEventCount=0;
EVENT_STRUCT*	CDialogBase::m_pEventList=NULL;
UINT			CDialogBase::m_hEventMessage;

CDialogBase::CDialogBase(void) : m_pFocus(NULL) ,m_hWndBase(NULL) ,m_lControlCount(0) ,m_pDocument(NULL) ,m_bAnimationActiveOnly(false),m_bAnimation(false),m_bActive(false) ,m_pMessageList(NULL) ,m_lMessageCount(0) ,m_dwAnimationEffectd(0)
{
	m_strAnimation.Empty();
	::ZeroMemory(&m_rckeep,sizeof(m_rckeep));
}

CDialogBase::~CDialogBase(void)
{
	if( m_pMessageList != NULL )
		delete m_pMessageList;
	m_pMessageList = NULL;
	m_spMonitor = NULL;
	ReleaseControl();
}

bool CDialogBase::Construct( void )
{
	if( (m_bAnimation=m_strAnimation.Length()>0) )
	{
		if( wcsstr(m_strAnimation,OLESTR("up")) )
			m_dwAnimationEffectd |= ANIMATION_EFFECTS_UP;
		if(  wcsstr(m_strAnimation,OLESTR("down")) )
			m_dwAnimationEffectd |= ANIMATION_EFFECTS_DOWN;
		if(  wcsstr(m_strAnimation,OLESTR("left")) )
			m_dwAnimationEffectd |= ANIMATION_EFFECTS_LEFT;
		if(  wcsstr(m_strAnimation,OLESTR("right")) )
			m_dwAnimationEffectd |= ANIMATION_EFFECTS_RIGHT;
	}
	return __super::Construct();
}

void CDialogBase::OnDialogActive( void )
{
	if( m_spMonitor != NULL )
		m_spMonitor->Resume();
}

void CDialogBase::OnDialogDeActive( void )
{
	CXMLParse*	pParse;
	CControls*	pControl;
	POSITION	ps=m_list.GetHeadPosition();

	while( ps != NULL )
	{
		if( (pParse=m_list.GetNext(ps)) != NULL && pParse->IsControl() == true )
		{
			if( (pControl = static_cast<CControls*>(pParse)) )
				pControl->OnDeactive();
		}
	}
	if( m_spMonitor != NULL )
		m_spMonitor->Suspend();
}

bool CDialogBase::SetStorageMonitorMonitor( IStorageMonitor* pMonitor )
{	
	if( pMonitor )
	{
		m_spMonitor = NULL;
		m_spMonitor = pMonitor;
	}
	return true;
}

bool CDialogBase::SetDocument( CHLXXMLDocument* pDocument ,DocumentTypeEnum DocumentOpenType )
{
	if( m_spMonitor != NULL )
	{
		m_spMonitor->Stop();
		m_spMonitor = NULL;
	}
	if( m_pDocument != NULL )
	{		
		m_pDocument->close();
		m_pDocument->Release();
	}
	m_DocumentOpenType = hlxOpenNull;
	m_pDocument = NULL;

	if( pDocument != NULL )
	{
		m_DocumentOpenType=DocumentOpenType;
		m_pDocument = pDocument;
		m_pDocument->AddRef();
		return m_pDocument!=NULL;
	}
	return false;
}

CControls* CDialogBase::GetControlObject( LPCWSTR lpID )
{
	CXMLParse*	pParse;
	CControls*	pControl;
	POSITION	ps=m_namelist.GetHeadPosition();

	while( ps != NULL )
	{
		if( (pParse=m_namelist.GetNext(ps)) != NULL &&  (pControl = static_cast<CControls*>(pParse)) && 
			pControl->GetID() )
		{
			if( wcscmp(pControl->GetID(),lpID) == 0  )
				return pControl;
		}
	}
	return NULL;
}

bool CDialogBase::GetObject( LPCWSTR lpID ,IDispatch** pDispatch )
{
	CXMLElement* pElement;
	CControls*	pControl;

	if( (pControl=GetControlObject(lpID)) )
	{
		if( (pElement=pControl->GetElement()) && SUCCEEDED(pElement->QueryInterface(IID_IDispatch,(LPVOID*)pDispatch)) )
					return true;
	}
	return false;
}

bool CDialogBase::OnMouseEvent( UINT uMsg ,CControls* pControl ,POINT pt )
{
	if( m_pFocus == NULL && pControl == NULL )
		return false;

	if( uMsg == WM_LBUTTONUP )
	{
		if( (::GetTickCount()-m_dwMouseUpTick) < ::GetDoubleClickTime() &&m_pFocus == pControl )
		{
			RECT	rct;
			rct.left=m_ptMouseUpPoint.x-15;
			rct.right=m_ptMouseUpPoint.x+15;
			rct.top=m_ptMouseUpPoint.y-15;
			rct.bottom=m_ptMouseUpPoint.y+15;

			if( ::PtInRect(&rct,pt) )
				pControl->OnMouseDblclk(pt);
		}
		m_ptMouseUpPoint=pt;
		m_dwMouseUpTick=::GetTickCount();
		if( m_pFocus != NULL && m_pFocus != pControl )
			m_pFocus->OnFocusover(pt);
		if( pControl != NULL )
			pControl->OnFocusout(pt);

		m_pFocus = NULL;
		return true;
	}
	if( pControl != NULL && m_pFocus == pControl )
		return pControl->OnMousemove(pt);
	
	if( pControl != NULL  )		
	{
		if( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_MOUSEMOVE ) && pControl->OnFocusin(pt) == true )
		{
			if( m_pFocus != NULL )
				m_pFocus->OnFocusover(pt);
			m_pFocus = pControl;
			return true;
		}
		return false;
	}
	if( m_pFocus != NULL )
		m_pFocus->OnFocusover(pt);
	m_pFocus = NULL;
	return false;
}

HRESULT CDialogBase::OnTimeControls( void )
{
	CXMLParse*	pParse;
	CControls*	pControl;
	POSITION	ps=m_timerlist.GetHeadPosition();

	while( ps != NULL )
	{
		if( (pParse=m_timerlist.GetNext(ps)) != NULL )
		{
			if( (pControl=static_cast<CControls*>(pParse)) )
				pControl->IsTimeOut();
		}
	}
	return S_OK;
}


HRESULT CDialogBase::OnLoadControls( void )
{
	CXMLParse*	pParse;
	CControls*	pControl;
	POSITION	ps=m_list.GetHeadPosition();

	if( m_bstrLoad.Length() > 0 )
	{
		CComVariant	value;
		ExecCommandString(m_bstrLoad,value);
	}

	while( ps != NULL )
	{
		if( (pParse=m_list.GetNext(ps)) != NULL && pParse->IsControl() == true )
		{
			if( (pControl=static_cast<CControls*>(pParse)) && pControl->IsEnable() )
				pControl->OnControlLoad();				
		}
	}
	if( m_spMonitor != NULL )
		m_spMonitor->Start();
	return S_OK;
}

HRESULT CDialogBase::OnDrawControls(HDC hdcDraw ,LPCRECTL prcWBounds ,HRGN hRgn )
{
	LPRGNDATA	pRgnData;
	DWORD		i,dwSize;
	HBITMAP		hOldBmp,hBmp=NULL;
	HDC			hMemDC=NULL;
	CXMLParse*	pParse;
	CControls*	pControl;
	POSITION	ps=m_list.GetHeadPosition();

	if( prcWBounds == NULL || hdcDraw == NULL )
		return S_FALSE;
	
	if( (hBmp=::CreateCompatibleBitmap(hdcDraw,GetWidth(),GetHeight())) != NULL && (hMemDC=::CreateCompatibleDC(hdcDraw)) != NULL )
	{
		hOldBmp=(HBITMAP)::SelectObject(hMemDC,hBmp);
		if( m_spImage != NULL )
			DrawBackground(hMemDC,(LPRECT)prcWBounds);

		pRgnData = NULL;
		if( hRgn != NULL && (dwSize=GetRegionData(hRgn,0,NULL)) )
		{
			if( (pRgnData=(LPRGNDATA)new BYTE[dwSize]) != NULL )
				GetRegionData(hRgn,dwSize,pRgnData);
		}
		while( ps != NULL )
		{
			if( (pParse=m_list.GetNext(ps)) != NULL && pParse->IsControl() == true && (pControl=static_cast<CControls*>(pParse)) )
			{
					if( pRgnData == NULL )
					{
						if( pControl->HitTest(prcWBounds) )
							pControl->OnDraw(hMemDC,prcWBounds);
					}
					else
					{
						const RECTL * pRect = (const RECTL *)pRgnData->Buffer;
						for( i=0 ; i < pRgnData->rdh.nCount ; i++ )
						{
							if( pControl->HitTest(pRect+i) )
							{
								pControl->OnDraw(hMemDC,prcWBounds,pRgnData);
								break;
							}
						}						
					}
			}
		}
		::BitBlt(hdcDraw,prcWBounds->left,prcWBounds->top,prcWBounds->right-prcWBounds->left,prcWBounds->bottom-prcWBounds->top,hMemDC,prcWBounds->left,prcWBounds->top,SRCCOPY);
		::SelectObject(hMemDC,hOldBmp);
	}
	if( hMemDC != NULL )
		::DeleteDC(hMemDC);
	if( hBmp != NULL )
		::DeleteObject(hBmp);
	if( pRgnData != NULL )
		delete pRgnData;
	return S_OK;
}

LRESULT CDialogBase::OnButtonControl(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// TODO: Add your message handler code here and/or call default
	POINT		pt;
	CXMLParse*	pParse;
	CControls*	pControl;
	POSITION	ps=m_list.GetHeadPosition();

	bHandled = TRUE;

	if( abs(::GetTickCount()-m_dwDialogTick) < 500 )
		return 0;
	pt.x=GET_X_LPARAM(lParam); 
	pt.y=GET_Y_LPARAM(lParam); 
	while( ps != NULL )
	{
		if( (pParse=m_list.GetNext(ps)) != NULL && pParse->IsMouse() == true && pParse->IsControl() == true )
		{
			if( (pControl = static_cast<CControls*>(pParse)) && pControl->HitTest(pt) )
			{			
				OnMouseEvent(uMsg,pControl,pt);
				return S_OK;
			}
		}
	}
	OnMouseEvent(uMsg,NULL,pt);
	return 0;
}

void CDialogBase::OnAddControlID( CXMLParse* pParse )
{
	CControls*	pControl;

	if( pParse->IsControl() && (pControl = static_cast<CControls*>(pParse)) )
	{		
		if( pControl->GetID() != NULL )
			m_namelist.AddTail(pControl);
		if( pControl->IsTimerContol() )
			m_timerlist.AddTail(pControl);
	}
}

bool CDialogBase::OnAddControl( CXMLParse* pParse ,CComPtr<IXMLDOMNode>& pNode )
{
	CControls*	pControl;

	if( pParse->IsControl() && (pControl = static_cast<CControls*>(pParse)) && pControl->SetBaseDialog(this) )
	{		
		m_list.AddTail(pControl);
		return true;
	}
	return false;
}

int CDialogBase::DrawAnimation(HWND hWnd ,bool bCreate )
{
	LONG		stepHeight,stepWidth;
	HBITMAP		hOldBmp,hBmp=NULL;
	RECT	rect,rct=GetControlRect();
	HDC	hDC,hMemDC;

	if( m_bAnimation == false || (bCreate && m_bAnimationActiveOnly))
		return 0;

	if( (hDC=::GetDC(NULL)) )
	{
		stepHeight = 0;
		stepWidth = 0;
		hBmp=::CreateCompatibleBitmap(hDC,GetWidth(),GetHeight());
		hMemDC=::CreateCompatibleDC(hDC);
		hOldBmp=(HBITMAP)::SelectObject(hMemDC,hBmp);
		OnDrawControls(hMemDC,(LPCRECTL)&rct,NULL);
		if( m_rckeep.left )
			rct.left = m_rckeep.left;
		if( m_rckeep.top )
			rct.top = m_rckeep.top;
		if( m_rckeep.right )
			rct.right = m_rckeep.right;
		if( m_rckeep.bottom )
			rct.bottom = m_rckeep.bottom;		

		rect = rct;
		BLENDFUNCTION bm;
		bm.BlendOp=AC_SRC_OVER;
		bm.BlendFlags=0;	
		bm.AlphaFormat=0; 
		bm.SourceConstantAlpha=100;
		if( (m_dwAnimationEffectd&(ANIMATION_EFFECTS_UP|ANIMATION_EFFECTS_DOWN)) )
		{
			stepHeight=(abs(rct.bottom-rct.top)-ANIMATION_STEP*4)/ANIMATION_STEP;
			if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_UP) && (m_dwAnimationEffectd&ANIMATION_EFFECTS_DOWN) )
				stepHeight>>=1;
		}

		if( (m_dwAnimationEffectd&(ANIMATION_EFFECTS_LEFT|ANIMATION_EFFECTS_RIGHT)) )
		{
			stepWidth=(abs(rct.right-rct.left)-ANIMATION_STEP*4)/ANIMATION_STEP;
			if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_LEFT) && (m_dwAnimationEffectd&ANIMATION_EFFECTS_RIGHT) )
				stepWidth>>=1;
		}

		if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_UP) )
			rct.top = rect.bottom - stepHeight;
		if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_DOWN) )
			rct.bottom = rect.top + stepHeight;
		if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_UP) && (m_dwAnimationEffectd&ANIMATION_EFFECTS_DOWN) )
		{
			rct.top = (rect.top+rect.bottom)/2 - stepHeight;
			rct.bottom = (rect.top+rect.bottom)/2 + stepHeight;
		}


		if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_LEFT) )
			rct.left = rect.right - stepWidth;
		if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_RIGHT) )
			rct.right = rect.left + stepWidth;
		if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_LEFT) && (m_dwAnimationEffectd&ANIMATION_EFFECTS_RIGHT) )
		{
			rct.left = (rect.left+rect.right)/2 - stepWidth;
			rct.right= (rect.left+rect.right)/2 + stepWidth;
		}

		for( int i=0 ; i < ANIMATION_STEP ; i++ )
		{
			rect = rct;
			if( i == ANIMATION_STEP-1 )
				rect=GetControlRect();

			bm.SourceConstantAlpha-=50/ANIMATION_STEP;
#ifdef	_WIN32_WCE
		    if( i == ANIMATION_STEP-1)
				::BitBlt(hDC,rect.left,rect.top,GetWidth(),GetHeight(),hMemDC,0,0,SRCCOPY);
			else
				::AlphaBlend(hDC,m_rckeep.left+rct.left,m_rckeep.top+rct.top,abs(rct.right-rct.left),abs(rct.bottom-rct.top),hMemDC,m_rckeep.left+rect.left,m_rckeep.top+rect.top,abs(rct.right-rct.left),abs(rct.bottom-rct.top),bm); 
#endif
			if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_UP) )
				rct.top -= stepHeight;
			if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_DOWN) )
				rct.bottom += stepHeight;
			if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_LEFT) )
				rct.left -= stepWidth;
			if( (m_dwAnimationEffectd&ANIMATION_EFFECTS_RIGHT) )
				rct.right += stepWidth;
		}
		::SelectObject(hMemDC,hOldBmp);
		if( hMemDC != NULL )
			::DeleteDC(hMemDC);
		if( hBmp != NULL )
			::DeleteObject(hBmp);
		::ReleaseDC(hWnd,hDC);
	}
	return 0;
}

bool CDialogBase::ReleaseControl(void)
{
	CXMLParse*	pParse;
	POSITION	ps=m_list.GetHeadPosition();

	while( ps != NULL )
	{
		if( (pParse=m_list.GetNext(ps)) != NULL  )
		{
			pParse->Deconstruct();
		}
	}
	m_list.RemoveAll();
	m_namelist.RemoveAll();
	m_timerlist.RemoveAll();
	return true;
}


void CDialogBase::SetWindowActive(bool bStatus)
{
	m_bActive = bStatus;
}

LRESULT CDialogBase::OnEventMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// TODO: Add your implementation code here
	LONG	i;

	if( m_pMessageList != NULL )
	{
		for( i=0 ; i < m_lMessageCount ; i++ )
		{
	
			if( m_pMessageList[i].hMESSAGE == wParam && m_pMessageList[i].COMMAND[0] )
			{
				CComVariant	value;
				ExecCommandString(CComBSTR(m_pMessageList[i].COMMAND),value);
				return S_OK;
			}
		}
	}
	if( m_pDocument != NULL && m_pDocument->GetParentWindow() )
		return m_pDocument->GetParentWindow()->OnEventMessage(uMsg,wParam,lParam,bHandled);
	return S_FALSE;
}

bool CDialogBase::OnCreateMessage(LONG length ,MESSAGE_STRUCT* pEventList)
{
	if( m_pMessageList != NULL )
		delete m_pMessageList;
	m_lMessageCount = 0;
	if( (m_pMessageList = new MESSAGE_STRUCT[length]) )
	{
		m_lMessageCount = length;
		memcpy(m_pMessageList,pEventList,sizeof(MESSAGE_STRUCT)*length);
		return true;
	}
	return false;
}

bool CDialogBase::OnCreateEvent(LONG length ,EVENT_STRUCT* pEventList)
{
	LONG	i;
	HANDLE	hThread;
	DWORD	dwThreadID;

	m_dwThreadID=::GetCurrentThreadId();
	if( length > 0 && (m_pEventList= new EVENT_STRUCT[length]) && (m_hEventMessage=::RegisterWindowMessage(OLESTR("HOLUXEVENTMESSAGE"))) )
	{
		memcpy(m_pEventList,pEventList,sizeof(EVENT_STRUCT)*length);
		for( i=0 ; i < length ; i++ )
		{
			if( m_pEventList[i].PRIORITY > 50 && pEventList[i].NAME[0] )
			{
				m_pEventList[i].hEVENT = ::CreateEvent(NULL,FALSE,FALSE,m_pEventList[i].NAME);
				m_pEventList[i].hMESSAGE = ::RegisterWindowMessage(m_pEventList[i].NAME);
			}
		}
		m_lEventCount = length;
		if( (hThread=::CreateThread(NULL,0,ThreadProc,this,0,&dwThreadID)) )
		{
			::SetThreadPriority(hThread,THREAD_PRIORITY_ABOVE_NORMAL);
			::CloseHandle(hThread);
			return true;
		}
	}
	return false;
}

DWORD WINAPI CDialogBase::OnEventProc( void )
{
	LONG		i,count;
	HANDLE*		pEvent;
	UINT*		pMessage;
	UINT*		pStatus;
	DWORD		dwEventObject;

	for( i=0 ,count=0 ; i < m_lEventCount ; i++ )
	{
		if( m_pEventList[i].hEVENT && m_pEventList[i].hMESSAGE )
			count++;
	}
	if( count == 0 )
		return -1;

	pEvent = (HANDLE*)_alloca(sizeof(HANDLE)*count);
	pMessage = (UINT*)_alloca(sizeof(UINT)*count);
	pStatus = (UINT*)_alloca(sizeof(UINT)*count);

	if( pEvent == NULL || pMessage == NULL )
		return -2;

	for( i=0 ,count=0 ; i < m_lEventCount ; i++ )
	{
		if( m_pEventList[i].hEVENT && m_pEventList[i].hMESSAGE )
		{
			pEvent[i] = m_pEventList[i].hEVENT;
			pMessage[i] = m_pEventList[i].hMESSAGE;
			pStatus[i] = m_pEventList[i].STATUS;
			count++;
		}
	}
	while( (dwEventObject=::WaitForMultipleObjects(count,pEvent,FALSE,INFINITE)) != WAIT_FAILED )
	{
		if( dwEventObject == WAIT_TIMEOUT )
			break;

		if( m_hEventMessage != NULL && ( LONG(dwEventObject-WAIT_OBJECT_0) < count ) && pMessage[dwEventObject-WAIT_OBJECT_0] != NULL )
		{
			::PostMessage(GetMainWindow(),m_hEventMessage,pMessage[dwEventObject-WAIT_OBJECT_0],dwEventObject);
			if( (pStatus[dwEventObject-WAIT_OBJECT_0]&DLGMESSAGE_LOCAL_MASK) == DLGMESSAGE_LOCAL_PUBLIC )
				::PostMessage(HWND_BROADCAST,m_hEventMessage,pMessage[dwEventObject-WAIT_OBJECT_0],dwEventObject);
		}
	}
	return 0;
}

DWORD WINAPI CDialogBase::ThreadProc( LPVOID lpParameter )
{
	if( lpParameter != NULL )
		return ((CDialogBase*)lpParameter)->OnEventProc();
	return 0;
}

這個是整個 XML BASE UI 的 Dialog base class ,主司 Event 的分派 ,windows input message 的處理 ,controls 的繪製與控制


其中的 OnDrawControls 就是非動晝的繪圖部份 ,剛開始先分析本回合有那些要重繪的區域,只有座落在需要重繪區的 Control 才會被要求重繪 ,
這樣重繪動作才會有效率


而 OnTimeControls 是對有宣告 timer 的 control 的處理 ,Timer 類和 Animation 都是可以秀動晝的 2類別 ,不同在 Timer 是靠不停重繪來達到動晝效果,

本身和格式無關,而Animation 只能服務於有支持 IHLXAnimation 的 decoder 控件 ,一般都是指 GIF ,MNG 類的控制


不過需要說明的是 DrawAnimation 不是用來控制上面所說的 IHLXAnimation ,而是用來處理 ,Dialog 在 Active/Deactive 時過場特效

而特別在此說明 DrawAnimation  也是本 engine 少數幾個打破行數限制的方法之一,原因很單純,為了執行時期的效能不得不那麼多行,而不能再分解下去



而在開頭的宣告中

BEGIN_DATA_MAP( CDialogBase )
	PROP_DATA_STR( "animation",m_strAnimation );
	PROP_DATA_BOOL( "animation-active-only"	,m_bAnimationActiveOnly );
	PROP_DATA_LONG( "keep-left",m_rckeep.left );
	PROP_DATA_LONG( "keep-top",m_rckeep.top );
	PROP_DATA_LONG( "keep-right",m_rckeep.right );
	PROP_DATA_LONG( "keep-bottom",m_rckeep.bottom );
	PROP_DATA_STR( "onload",m_bstrLoad );
END_DATA_MAP()



這部份是我為了方便維護,XML tag 各元件的關連,特別為 XML標籤而開發出的XML 自動 PARSER 關連系統 ,XML 動態生成 V2.0 for ATL
大家就先當成和 MFC DDE 一般,可以自已依宣告好的關連的關係,放在正確的變數上 而 PARSER Engine Kernel XML 動態生成 V2.0 for ATL ,待到 PARSER Engine 的解說時候,會和大家解說的比較完整


而光只是用 CDialogBase 只能處理 Windows 的部份 ,在對 DOM 及 Automation 應用部份是連結不起來的,所以必需再封裝成 IDispatch 才能用在 Script 及 XML DOM 環境中

而下面的 template 正是配合 ATL 的 CDialogBase 封裝 ,因此所有的視窗訊息也是由此轉向交由CDialogBase 處理

#pragma once
#include <atlhost.h>
#include "..\Controls\DialogBase.h"
#include "..\Controls\Controls.h"
#include "XMLElement.h"

#ifdef	_WIN32_WCE
#include <pm.h>
#endif

#define	WM_USERSUSPEND	(WM_USER+5961)

class	CComHLXDialog :
	public CComObjectRootEx<CComSingleThreadModel>,	
	public CDialogBase,
	public IDispatchImpl<IHLXDialog, &IID_IHLXDialog, &LIBID_HLXDocvwLib, /* wMajor = */ 1, /* wMinor = */ 0>
{
	protected:
static	bool	m_bLowBat;
static	bool	m_bACOn;
static	bool	m_bFirstACOn;

};

template < class T1,class WinBase ,const CLSID* pclsid = &CLSID_NULL >
class ATL_NO_VTABLE HLXDialogImpl : 
	public WinBase,
	public CComCoClass<T1,pclsid>,
	public CComHLXDialog
{
public:
	typedef HLXDialogImpl< T1, WinBase ,pclsid>	thisClass;

	struct DialogElement
	{
		HWND				hWnd;
		OLECHAR				name[NAME_MAX];
		CComHLXDialog*		pDialog;
		CHLXXMLDocument*	pDocument;
	};

	HLXDialogImpl() : m_bDialogMode(false) ,m_hOldWnd(NULL) ,m_exitCode(0)
	{
#ifdef	_DEBUG
		m_dwParseKeyTickCount=0;
		m_dwParseTickCount = 0;
		m_dwImageTickCount = 0;
		m_dwObjectTickCount = 0;
		m_dwCreateImageTickCount=0;
		m_dwConstructTickCount=0;
#endif
	};

	class DialogTraits : public CElementTraits< DialogElement >
	{
		public:
		static bool CompareElements( const DialogElement& element1, const DialogElement& element2)
		{
			if( wcscmp(element1.name,element2.name)==0 )
				return true;
			return false;
		};
	};

	BEGIN_MSG_MAP(thisClass)
		MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST,WM_MOUSELAST,OnButtonControl)
		MESSAGE_HANDLER(WM_TIMER, OnTimer)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
		MESSAGE_HANDLER(WM_USERSUSPEND, OnSuspend )	
		MESSAGE_HANDLER(CDialogBase::m_hEventMessage, OnEventMessage)			
		CHAIN_MSG_MAP(WinBase)
	END_MSG_MAP()


//	typedef WinBase						baseWinClass;

	BEGIN_COM_MAP(thisClass)
		COM_INTERFACE_ENTRY(IHLXDialog)
		COM_INTERFACE_ENTRY2(IDispatch,IHLXDialog)
	END_COM_MAP()

	IDispatch* GetDispatch( void )
	{
		IDispatch*	pDispatch;

		if( SUCCEEDED(QueryInterface(IID_IDispatch,(LPVOID*)&pDispatch)) )
			return pDispatch;
		return NULL;
	}

// IHLXDialog Methods

	STDMETHOD(get_document)(IDispatch** pVal)
	{
		// TODO: Add your implementation code here
		if( pVal != NULL && GetDocumentDispatch(pVal) )		
			return S_OK;
		return S_FALSE;
	}

	STDMETHOD(GetControl)(BSTR Name ,IDispatch** pVal)
	{
		// TODO: Add your implementation code here
		CControls*			pControl;
		CComPtr<IDispatch>	spDispatch;

		if( pVal != NULL  && (pControl=GetControlObject(Name)) )
		{
			if( pControl->QueryControlObject(pVal) )
				return S_OK;
			if( GetObject(Name,pVal) )
				return S_OK;
		}
		return S_FALSE;
	}

	STDMETHOD(GetImage)(BSTR Name ,LONG lAlpha ,IDispatch** pVal)
	{
		// TODO: Add your implementation code here

		CComPtr<IHLXImage>	spImage;

		if( pVal != NULL && Name != NULL  && (spImage=CBackground::CreateImage(Name,lAlpha)) != NULL )
			return spImage->QueryInterface(IID_IDispatch,(LPVOID*)pVal);
		return S_FALSE;
	}

	STDMETHOD(GetString)(BSTR Name ,BSTR* pVal)
	{
		// TODO: Add your implementation code here
		if( pVal != NULL && Name != NULL && Name[0] == OLESTR('@') )
		{
			LONG		index;
			CComBSTR	bstrValue;

			index=_wtoi(Name+1);
			if( index > 0 )
			{
				if( GetLanguageString(index-1,bstrValue) )
				{
					bstrValue.CopyTo(pVal);
					return S_OK;
				}
			}
		}
		return S_FALSE;
	}


	STDMETHOD(Navigate)(BSTR xmlName, BSTR TargetName, LONG* RetValue)
	{
		// TODO: Add your implementation code here
		CComBSTR		strPath;
		DialogElement	Element;
		CComObject<CHLXXMLDocument>*	pDoc;
		POSITION	ps;

		if( wcscmp(OLESTR("system"),xmlName)==0 && wcscmp(OLESTR("interMessagebox"),TargetName) == 0 )
		{
			StartMouseFilter();
			return S_OK;
		}

		::ZeroMemory(&Element,sizeof(Element));
		wcscpy(Element.name,TargetName);
		if( (ps=m_client.Find(Element)) )
		{
			Element=m_client.GetAt(ps);
			if( Element.hWnd != GetTopWindow() )
			{
				Element.pDialog->DrawAnimation(NULL);
				Element.pDialog->BringWindowToTop();
			}
			return S_OK;
		}

		if( (pDoc=new CComObject<CHLXXMLDocument>) )
		{		
			if( SUCCEEDED(pDoc->FinalConstruct()) )
			{
				pDoc->SetParentWindow(this);			
				if( *xmlName != OLECHAR('.') )
				{
					strPath = m_strUrl;
					strPath.AppendBSTR(xmlName);
				}
				else
					strPath = m_pDocument->GetDocumentPath();
				if( FAILED(pDoc->load(strPath,TargetName,m_strUrl,hlxOpenWindow,RetValue)) )
				{
					delete pDoc;
					return S_FALSE;
				}
			}				
		}
		else
		{
			return S_FALSE;
		}

		Element.pDocument = pDoc;
		Element.pDialog=pDoc->GetSafeWindow();
		Element.hWnd=Element.pDialog->GetSafeHWND();
		m_client.AddHead(Element);
		return S_OK;
	}


	STDMETHOD(CloseWindow)(LONG exitCode)
	{
		// TODO: Add your implementation code here
		m_exitCode = exitCode;
		if( m_hOldWnd != NULL )
			SetMainWindow(m_hOldWnd);

		if( m_bDialogMode )
			EndDialog(exitCode);
		else
			PostMessage(WM_USER+1024,exitCode,NULL);
		return S_OK;
	}


	STDMETHOD(ShellCommand)(BSTR strCommand, LONG flage, VARIANT_BOOL* result)
	{
		// TODO: Add your implementation code here
		SHELLEXECUTEINFO	inf;

		*result = VARIANT_FALSE;
		if( strCommand != NULL )
		{
			::ZeroMemory(&inf,sizeof(inf));

			inf.cbSize = sizeof(inf);
			inf.lpFile = strCommand;
			inf.fMask = SEE_MASK_FLAG_NO_UI|SEE_MASK_NOCLOSEPROCESS;
			inf.nShow = SW_SHOWNA;
			if( ::ShellExecuteEx(&inf) )
			{
				*result = VARIANT_TRUE;
				if( flage == 2 )
				{
					::Sleep(1000);
					::CloseHandle(inf.hProcess);
					return S_OK;
				}
				WaitForSingleObject(inf.hProcess,INFINITE);
				return S_OK;
			}		
		}
		return S_FALSE;
	}

	STDMETHOD(MsgBox)(BSTR xmlName, BSTR TargetName, LONG* result)
	{
		// TODO: Add your implementation code here

		CComBSTR		strPath;
		CComObject<CHLXXMLDocument>*	pDoc;

		if( wcscmp(OLESTR("system"),xmlName)==0 && wcscmp(OLESTR("interMessagebox"),TargetName) == 0 )
		{
			StartMouseFilter();
			return S_OK;
		}

		if( (pDoc=new CComObject<CHLXXMLDocument>) )
		{		
			if( SUCCEEDED(pDoc->FinalConstruct()) )
			{
				pDoc->SetParentWindow(this);			
				if( *xmlName != OLECHAR('.') )
				{
					strPath = m_strUrl;
					strPath.AppendBSTR(xmlName);
				}
				else
					strPath = m_pDocument->GetDocumentPath();
				if( FAILED(pDoc->load(strPath,TargetName,m_strUrl,hlxOpenDialog,result)) )
				{
					pDoc->FinalRelease();
					delete pDoc;
					return S_FALSE;
				}
			}				
		}
		else
			return S_FALSE;
		StartMouseFilter();
		return S_OK;
	}

	STDMETHOD(GetExitCode)(LONG* exitCode)
	{
		// TODO: Add your implementation code here
		*exitCode=m_exitCode;
		return S_OK;
	}

	STDMETHOD(GetParentWindow)(IDispatch** pVal)
	{
		if( pVal && m_pDocument != NULL && m_pDocument->GetParentWindow() )
			return m_pDocument->GetParentWindow()->QueryInterface(IID_IDispatch,(LPVOID*)pVal);
		return S_FALSE;
	}
	
	STDMETHOD(GetHWnd)(LONG* pVal)
	{
		if( pVal )
		{
			*pVal = (LONG)m_hWnd;
			return S_OK;
		}
		return S_FALSE;
	}

protected:
	LONG		m_exitCode;
	HWND		m_hOldWnd;
	DWORD		m_dwTimeCount;
	bool		m_bDialogMode;
	CComBSTR	m_bstrUrl;
	CAtlList<DialogElement,DialogTraits>	m_client;

	HRESULT OnDraw(ATL_DRAWINFO& di)
	{
		// TODO: Add your specialized code here and/or call the base class
		OnDrawControls(di.hdcDraw,di.prcWBounds);
#ifdef	_DEBUG
		{
			WCHAR	buff[32];
			RECT	rct={0,0,200,30};
			::SetTextColor(di.hdcDraw,RGB(255,255,255));
			_itow(m_dwImageTickCount,buff,10);
			::DrawText(di.hdcDraw,buff,-1,&rct,DT_SINGLELINE );
		}
#endif
		return __super::OnDraw(di);
	}

	LRESULT OnSuspend(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		PumpMessage();
#ifdef	_WIN32_WCE
		::SetSystemPowerState( NULL, POWER_STATE_SUSPEND, POWER_FORCE);
#endif
		return 0;
	}

	LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		RECT	rct=GetControlRect();
		CAxDialogImpl<T1>::OnInitDialog(uMsg, wParam, lParam, bHandled);
		bHandled = TRUE;
		SetWindowPos(NULL,&rct,0);
		m_dwTimeCount = 450;
		SetTimer(1,100,NULL);
		m_pFocus = NULL;
		if( (m_DocumentOpenType&hlxOpenWindowRoot) || (m_DocumentOpenType&hlxOpenDialog) )
			m_hOldWnd=SetMainWindow(m_hWnd);
		SetSafeHWND(m_hWnd);
		OnLoadControls();
		if( m_pDocument != NULL && m_pDocument->GetParentWindow() )
			m_pDocument->GetParentWindow()->OnDialogDeActive();
		StartMouseFilter();
//		FireViewChange();
		return 1;  // Let the system set the focus
	}


	LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		// TODO: Add your message handler code here and/or call default
		PAINTSTRUCT	ps;
		INT ret;
		HRGN update_rgn = CreateRectRgn( 0, 0, 0, 0 );
		ret = 0;
		if( update_rgn )
			ret  = GetUpdateRgn( update_rgn, FALSE );
		BeginPaint(&ps);
		if (ret == COMPLEXREGION  )
			OnDrawControls(ps.hdc,(LPCRECTL)&ps.rcPaint,update_rgn);
		else
			OnDrawControls(ps.hdc,(LPCRECTL)&ps.rcPaint,NULL);
#ifdef	_DEBUG
		{
			WCHAR	buff[256];
			RECT	rct={0,250,480,270};
			::SetBkColor(ps.hdc,RGB(255,255,255));
			::SetTextColor(ps.hdc,RGB(0,0,0));
			::wsprintf(buff,TEXT("Navigate=%d,Object=%d,Parse=%d,Key=%d,Const=%d,LoImg=%d,CrImg=%d"),m_dwNavigateTickCount,m_dwObjectTickCount,m_dwParseTickCount,m_dwParseKeyTickCount,m_dwConstructTickCount,m_dwCreateImageTickCount,m_dwImageTickCount);
			::DrawText(ps.hdc,buff,-1,&rct,DT_SINGLELINE );
		}
#endif

		EndPaint(&ps);
		if( update_rgn != NULL )
			DeleteObject( update_rgn );

		return 0;
	}

	LRESULT OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		if( (m_DocumentOpenType&hlxOpenWindowRoot) )
		{
#ifdef	_WIN32_WCE

			SYSTEM_POWER_STATUS_EX	sp;

			if( GetSystemPowerStatusEx(&sp) )
			{
//				sp.ACLineStatus = AC_LINE_OFFLINE;
				if( sp.ACLineStatus == AC_LINE_OFFLINE  )
				{
					if( m_bACOn == true )
					{
						m_bACOn = false;
						m_bFirstACOn = false;
						::PostMessage(GetMainWindow(),m_hEventMessage ,::RegisterWindowMessage(OLESTR("SYSEVENT_ACOFF")),sp.BatteryLifePercent);
					}
				}
				else
				{
					if( m_bACOn == false  )
					{						
						m_bACOn = true;
						m_bLowBat = false;
						m_dwTimeCount = 0;
						if( m_bFirstACOn == false )
						{
							m_bFirstACOn = true;
							::PostMessage(GetMainWindow(),m_hEventMessage ,::RegisterWindowMessage(OLESTR("SYSEVENT_ACON")),sp.BatteryLifePercent);
						}
					}
				}
				if( sp.ACLineStatus == AC_LINE_OFFLINE && sp.BatteryLifePercent < 30 )
				{
					if( m_bLowBat == false )
					{
						m_bLowBat = true;
						m_dwTimeCount = ::GetTickCount();
						::PostMessage(GetMainWindow(),m_hEventMessage ,::RegisterWindowMessage(OLESTR("SYSEVENT_LOWBATTERY")),sp.BatteryLifePercent);
					}
					else
					{
						if( ::GetTickCount()-m_dwTimeCount > 30*60*1000 )
							m_bLowBat = false;
					}
				}
			}

#endif		
		}
		if( ::GetWindow(m_hWndBase,GW_CHILD) == NULL && ::GetWindow(m_hWndBase,GW_HWNDFIRST) == m_hWndBase )
			OnTimeControls();
		return 0;
	}

	LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		bHandled = TRUE;
		return 0;
	}

	bool CloseClientWindow(HWND hWnd)
	{	
		DialogElement	Element;

		if( hWnd != NULL )
		{
			POSITION	ps=m_client.GetHeadPosition();

			while( ps != NULL )
			{
				Element=m_client.GetAt(ps);
				if( Element.hWnd == hWnd )
				{
					m_client.RemoveAt(ps);
					StartMouseFilter();
					return true;
				}
				m_client.GetNext(ps);
			}
		}
		return false;
	}


};


到目前為此各位看到的是此系統對 window/dialog 的定義部份,可能很多人還不了解光是這樣,又是如何可以晝出各類元件,各類圖片?
在此再說明一下,前面也提過 這個 dialog OnDrawControls 中會找出需要重繪的 control ,在找到後呼叫 OnDraw 重繪,而這 control 的定義便如下所列



#pragma once
#include "DialogBase.h"
#include "..\common\FontObject.h"

class CControls :
	public CFontObject
{
	DECLARE_DATA_MAP()
public:
	CControls(void);
	~CControls(void);

	bool IsControl( void )
	{
		return true;
	}

	inline bool _fastcall IsFocus( void )
	{
		return (m_pDialog != NULL && m_pDialog->IsFocusControl(this));
	}

	bool _fastcall FireViewChange( void )
	{
		Refresh();
		return true;
	}

	bool DrawDialogBackground( HDC hdcDraw ,RECT& rct ,LONG x ,LONG y );
	inline bool HitTest( POINT pt )
	{
		if( m_rct.bottom == 0 && m_rct.top == 0 && m_rct.left == 0 && m_rct.right == 0 )
			return false;
		return ::PtInRect(&m_rct,pt)==TRUE;
	}

	inline bool _fastcall HitTest( LPCRECTL pRct ,LPRECT pDse=NULL )
	{
		RECT	rct;
		if( m_rct.bottom == 0 && m_rct.top == 0 && m_rct.left == 0 && m_rct.right == 0 )
			return false;
		if( ::IntersectRect(&rct,(LPCRECT)pRct,&m_rct) )
		{
			if( pDse )
				*pDse = rct;
			return true;

		}
		return false;
	}

	virtual void SetControlValue( VARIANT varValue);
	virtual bool GetControlValue(VARIANT* varValue);
	virtual bool OnControlLoad( void );
	virtual bool OnMouseDblclk( POINT pt );
	virtual bool OnMousemove( POINT pt );
	virtual bool OnFocusin( POINT pt );
	virtual bool OnFocusout( POINT pt );
	virtual bool OnFocusover( POINT pt );
	virtual bool OnControlExternCommand( BSTR bstrCommand ,VARIANT* value);
	virtual bool OnDeactive( void );
protected:
	CComBSTR	m_bstrLoad;

};

#include "StdAfx.h"
#include "Controls.h"

BEGIN_DATA_MAP( CControls )
	PROP_DATA_STR( "onload",m_bstrLoad );
END_DATA_MAP()

CControls::CControls() 
{
}

CControls::~CControls()
{
}

bool CControls::DrawDialogBackground( HDC hdcDraw ,RECT& rct ,LONG x ,LONG y )
{
	if( m_pDialog != NULL )
		return m_pDialog->DrawDialogBackground(hdcDraw,rct,x,y);
	return false;
}

bool CControls::OnMouseDblclk( POINT pt )
{
	return false;
}

bool CControls::OnMousemove( POINT pt )
{
	return false;
}

bool CControls::OnFocusin( POINT pt )
{
	return false;
}

bool CControls::OnFocusout( POINT pt )
{
	return false;
}

bool CControls::OnFocusover( POINT pt )
{
	return false;
}

void CControls::SetControlValue( VARIANT varValue)
{
}

bool CControls::GetControlValue(VARIANT* varValue)
{
	return false;
}

bool CControls::OnControlExternCommand( BSTR bstrCommand ,VARIANT* value)
{
	if( value )
		::VariantClear(value);
	return false;
}

bool CControls::OnControlLoad( void )
{
	if( m_bstrLoad.Length() > 0 )
	{
		CComVariant	value;
		ExecCommandString(m_bstrLoad,value);
	}
	return true;
}

bool CControls::OnDeactive( void )
{
	return true;
}



CControls 是所有 Control 的基礎類別 ,只要是控制元,不論是可見不可見都必需繼承,

而 CControls 向下方展除了在 code 中看到的 CFontObject (主管字型字體的控制) -> CColorObject (顏色,陰影控制)->CBackground(背景圖片控制)->CTimeEvent(時鐘元件事件控制)->CObejectRectangles(元件空間控制)->CBaseObject(元件基礎類別) 而最基礎的CBaseObject source code 如下

#pragma once
#include "..\common\xmlparse.h"

#ifdef	_WIN32_WCE
#import "progid:HLXDatabase.LanguageLib"  raw_interfaces_only auto_rename
#endif

#define	DISPATCHOFFSET	(0x40000000)
#define	FIELDOFFSET		(0x20000000)
class CDialogBase;
class CControls;

class CBaseObject :	
	public CXMLParse
{
	DECLARE_DATA_MAP()
public:
	CBaseObject(void);
	~CBaseObject(void);

	bool	SetBaseDialog( CDialogBase* pDialog );
	CDialogBase* GetBaseDialog( void );


	inline LPCWSTR _fastcall GetID( void )
	{
		if( m_bstrIdName.Length() > 0 )
			return m_bstrIdName;
		return NULL;
	}

	inline LONG _fastcall GetCID( void )
	{
		return m_lCID;
	}

	inline bool _fastcall IsEnable( void )
	{
		return m_bEnable;
	}

	bool ExecCommand(VARIANT& result)
	{
		return ExecCommandString(m_bstrCommand,result);
	}
	
	inline bool _stdcall QueryControlObject( IDispatch** pDispatch )
	{
		if( m_spDispatch != NULL )
			return SUCCEEDED(m_spDispatch->QueryInterface(IID_IDispatch,(LPVOID*)pDispatch));
		return false;
	}

	bool _fastcall SetControlEnable( bool bEnable );
	
	bool ExecClick( void );
	bool RefreshRect( RECT& rct ,bool bErase);
	bool UpdateWindow( void );
	void WaitMessage( void );
	void Deconstruct( void );
	virtual bool OnCommand( LPCWSTR lpCommand ,VARIANT& result );
	virtual bool OnScript( LPCWSTR lpCommand ,VARIANT& result );

	bool GetLanguageString( LONG index,CComBSTR& bstrText ,LONG* pStyle=NULL);
static	bool _fastcall CreateLanguage( LPCWSTR lpDirectroy );
static	bool _fastcall GetDefaultLanguageName( BSTR* name );
static	bool _fastcall SetDefaultLanguageName( BSTR name );

	bool ParseTargetCommand(IDispatch* pDispatch, LPCWSTR lpName ,LPCWSTR lpCommand ,VARIANT& result );
	bool ParseDispatchCommand(IDispatch* pDispatch, LPCWSTR lpCommand ,VARIANT& result );
	void InitVariants(VARIANT* pVar ,long count);
	void ClearVariants(VARIANT* pVar ,long count );

protected:
	CDialogBase*	m_pDialog;

	HWND GetSafeHWND( void );
	bool _fastcall GetControlObject( LPCWSTR lpCommand ,IDispatch** pDispatch );
	CControls* _fastcall GetControlObject( LPCWSTR lpCommand );
	bool GetProperty( LPCWSTR lpName ,VARIANT& value );
	bool PutProperty( LPCWSTR lpName ,LPCWSTR lpValue );

	bool ExecCommandString( CComBSTR& bstrCommand ,VARIANT& result )
	{
		::VariantClear(&result);
		if( bstrCommand.Length() > 0 )
		{
			if( bstrCommand[0] == OLECHAR('#') )
				return OnCommand( lTrim(bstrCommand+1) ,result );
			else
				return OnScript( lTrim(bstrCommand) ,result );
		}
		return false;
	}

	bool _fastcall OnControlObject( IDispatch* pDispatch );
	bool _fastcall OnControlObject( LPCWSTR lpTarget ,LPCWSTR lpCommand );	

	STDMETHODIMP InterGetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,LCID lcid, DISPID* rgdispid)
	{
		if( m_spDispatch != NULL )
		{
			if( SUCCEEDED(m_spDispatch->GetIDsOfNames(riid,rgszNames,cNames,lcid,rgdispid)) )
			{
				*rgdispid |= DISPATCHOFFSET;
				return S_OK;
			}
		}
		return S_FALSE;
	}

	STDMETHODIMP InterInvoke(DISPID dispidMember, REFIID riid,LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,EXCEPINFO* pexcepinfo, UINT* puArgErr)
	{
		if( m_spDispatch != NULL )
		{
			if( (dispidMember&DISPATCHOFFSET) )
				dispidMember &=~DISPATCHOFFSET;
			return m_spDispatch->Invoke(dispidMember,riid,lcid,wFlags,pdispparams,pvarResult,pexcepinfo,puArgErr);
		}
		return S_FALSE;
	}


private:
	LONG		m_lCID;
	bool		m_bEnable;
	CComBSTR	m_bstrIdName;
	CComBSTR	m_bstrCommand;	
	CComBSTR	m_bstrClick;
	CComBSTR	m_bstrDisableClick;
	CComPtr<IDispatch>	m_spDispatch;

#ifdef	_WIN32_WCE
	static	CComPtr<HLXDatabaseLib::ILanguageLib>	m_spLanguageLib;
#endif
	bool CopyString( LPWSTR lpBuff ,LPCWSTR lpCommand ,LPCWSTR lpEnd ,LONG Max );
	bool InterCommand( VARIANT& value ,VARIANT& result );
	bool InterCommand( LPCWSTR lpCommand ,VARIANT& result );
	bool ConvertVariants( LPWSTR lpParam ,VARIANT* pVar ,LONG count ,DWORD dwStatus ,bool bDefString=false);	
	long GetParamCount(LPWSTR lpBuff,LPWSTR& lpParam ,LPWSTR& lpNext ,DWORD& dwParseStatus );
	
};

#include "StdAfx.h"
#include "BaseObject.h"
#include "..\Controls\DialogBase.h"
#include "..\HLXDocvw\XMLElement.h"
#include "..\HLXDocvw\HLXXMLDocument.h"
#include "..\HLXDocvw\HLXDialog.h"

#ifdef	_WIN32_WCE
CComPtr<HLXDatabaseLib::ILanguageLib>	CBaseObject::m_spLanguageLib;
#endif

BEGIN_DATA_MAP( CBaseObject )
	PROP_DATA_STR( "id"		,m_bstrIdName );
	PROP_DATA_STR( "command",m_bstrCommand );
	PROP_DATA_STR( "onclick",m_bstrClick );	
	PROP_DATA_STR( "ondclick",m_bstrDisableClick );		
END_DATA_MAP()



bool CBaseObject::CreateLanguage( LPCWSTR lpDirectroy )
{
#ifdef	_WIN32_WCE
	VARIANT_BOOL	bResult;
	WCHAR	buff[MAX_PATH];

	if( m_spLanguageLib == NULL && lpDirectroy )
	{
		if( SUCCEEDED(m_spLanguageLib.CoCreateInstance(OLESTR("HLXDatabase.LanguageLib"))) )
		{
			wmemset(buff,0,MAX_PATH);
			wcscpy(buff,lpDirectroy);
			wcscat(buff,OLESTR("resource\\info\\"));
			if( SUCCEEDED(m_spLanguageLib->Open(buff,&bResult)) && bResult == VARIANT_TRUE )
			{
			}
		}
	}
#endif
	return true;
}

CBaseObject::CBaseObject(void) : m_bEnable(true) ,m_pDialog(NULL) ,m_lCID(0)
{
	m_spDispatch = NULL;
	m_bstrCommand.Empty();
	m_bstrIdName.Empty();
	m_bstrClick.Empty();
	m_bstrDisableClick.Empty();
}

void CBaseObject::Deconstruct( void )
{

	CComPtr<ILanguage>	pLanguage;
	if( m_spDispatch != NULL && SUCCEEDED(m_spDispatch.QueryInterface(&pLanguage)) )
			pLanguage->SetService(NULL);

	pLanguage = NULL;
	m_spDispatch = NULL;
	return __super::Deconstruct();
}

bool CBaseObject::SetControlEnable( bool bEnable )
{
	if( m_bEnable != bEnable )
	{
		m_bEnable = bEnable;
		return true;
	}
	return false;
}

CBaseObject::~CBaseObject(void)
{
}

bool CBaseObject::ExecClick( void )
{
	CComVariant result;
	if( IsEnable() )
		return ExecCommandString(m_bstrClick,result);
	return ExecCommandString(m_bstrDisableClick,result);
}

HWND CBaseObject::GetSafeHWND( void )
{
	if( m_pDialog != NULL )
		return m_pDialog->GetSafeHWND();
	return NULL;
}

bool CBaseObject::SetBaseDialog( CDialogBase* pDialog )
{
	if( m_pDialog == NULL )
	{
		m_pDialog = pDialog;
		m_lCID = pDialog->AddControl();
		return true;
	}
	return false;
}

CDialogBase* CBaseObject::GetBaseDialog( void )
{
	return m_pDialog;
}

void CBaseObject::WaitMessage( void )
{
	if( m_pDialog != NULL )
		m_pDialog->WaitMessage();
}

bool CBaseObject::UpdateWindow( void )
{
	if( m_pDialog != NULL )
		return m_pDialog->UpdateWindow();
	return false;
}

bool CBaseObject::RefreshRect( RECT& rct ,bool bErase )
{
	if( m_pDialog != NULL )
		return m_pDialog->InvalidateRect(rct,bErase);
	return false;
}

bool CBaseObject::OnScript( LPCWSTR lpCommand ,VARIANT& result )
{
	return false;
}

CControls* CBaseObject::GetControlObject( LPCWSTR lpCommand )
{
	if( lpCommand != NULL || m_pDialog != NULL )
		return m_pDialog->GetControlObject(lpCommand);
	return NULL;
}

bool CBaseObject::GetControlObject( LPCWSTR lpCommand ,IDispatch** pDispatch )
{
	LPWSTR lpControlName;

	if( pDispatch == NULL || lpCommand == NULL || m_pDialog == NULL )
		return false;

	lpControlName = (LPWSTR)lpCommand;

	if( wcscmp(lpControlName,OLESTR("document")) == 0 )
	{
		if( m_pDialog->GetDocumentDispatch(pDispatch) && *pDispatch != NULL )
			return true;
	}
	else if( wcscmp(lpControlName,OLESTR("window")) == 0 )
	{
		if( m_pDialog->GetDispatch(pDispatch) && *pDispatch != NULL )
			return true;
	}
	else if( wcscmp(lpControlName,OLESTR("parent")) == 0 )
	{
		if( m_pDialog->GetParentDispatch(pDispatch) && *pDispatch != NULL )
			return true;
	}
	else if( m_pDialog->GetObject(lpControlName,pDispatch) && *pDispatch != NULL )
	{
		return true;
	}
	return false;
}


bool CBaseObject::CopyString( LPWSTR lpBuff ,LPCWSTR lpCommand ,LPCWSTR lpEnd ,LONG Max )
{
	LONG	length;

	if( lpBuff == NULL || lpCommand == NULL || lpEnd == NULL )
		return false;

	length = lpEnd-lpCommand;
	if( length > Max-1 )
		length = length-1;

	memcpy((LPVOID)lpBuff,lpCommand,length*sizeof(OLECHAR));
	lpBuff[length]=OLECHAR('\0');
	return true;
}

bool CBaseObject::OnCommand( LPCWSTR lpCommand ,VARIANT& result)
{
	bool		bChar;
	LPCWSTR		lpObject,lpEnd;
	
	bChar = false;
	::VariantClear(&result);
	lpEnd=lpObject=lpCommand;
	while( lpEnd && *lpEnd )
	{
		if( *lpEnd == OLECHAR('\'') )
			bChar = !bChar;
		else if( bChar == false && *lpEnd == OLECHAR(';') )
		{
			InterCommand(lpObject,result);			
			lpEnd++;
			lpObject=lpEnd;
			continue;
		}
		lpEnd++;
	}
	if( lpObject != lpEnd )
		InterCommand(lpObject,result);
	return true;
}


bool CBaseObject::InterCommand( LPCWSTR lpCommand ,VARIANT& result)
{
	bool				bDigit,bAlpha,bObject;
	DWORD				dwStatus;
	LPCWSTR				lpObject;
	CComPtr<IDispatch>	spDispatch;
	LPOLESTR			lpName;
	OLECHAR				name[NAME_MAX];

	bDigit = false;
	bAlpha = false;
	bObject = false;
	lpName = name;
	lpObject = lpCommand;
	while( *lpObject != NULL  )
	{
		if( isalpha(*lpObject)  )
			bAlpha = true;		
		else if( isdigit(*lpObject) )
			bDigit = true;
		else if( *lpObject == OLESTR('_')  )
			bObject = true;
		else
			break;
		lpObject++;
	}

	if( lpObject == lpCommand )
		return false;


	if( CopyString(name,lpCommand,lpObject,NAME_MAX) == false )
		return false;

	if( bDigit && bAlpha == false )
	{
		::VariantClear(&result);
		result.vt = VT_I4;
		result.lVal = _wtoi(lpCommand);
		return true;
	}
	else if( name[0] == OLECHAR('i') && wcscmp(name,OLESTR("iif")) == 0 )
	{
		LONG		count;
		VARIANT*	pVariant;
		LPOLESTR	lpBuff,lpData,lpNext;

		if( (lpBuff=(LPOLESTR)_alloca(sizeof(OLECHAR)*(wcslen(lpCommand)+1))) )
		{
			wmemcpy(lpBuff,lpCommand,wcslen(lpCommand)+1);
			count=GetParamCount(lpBuff,lpData,lpNext,dwStatus);
			if( count > 1 && (pVariant=(VARIANT*)_alloca(sizeof(VARIANT)*count)) != NULL )
			{
				InitVariants(pVariant,count);
				if( ConvertVariants(lpData,pVariant,count,dwStatus,true) )
				{

					VARIANT	tmp;
					::VariantClear(&result);
					::VariantInit(&tmp);
					if( InterCommand(pVariant[count-1],tmp) && ((tmp.vt==VT_BOOL && tmp.boolVal==VARIANT_TRUE) || (tmp.vt==VT_I4 && tmp.lVal!=0)) )
						InterCommand(pVariant[count-2].bstrVal,tmp);
					else
					{
						if( count >2 )
							InterCommand(pVariant[count-3].bstrVal,tmp);
					}
					::VariantCopy(&result,&tmp);
					::VariantClear(&tmp);
					ClearVariants(pVariant,count);
					return true;
				}
			}

		}

	}
	else if( *lpObject == OLECHAR('(') )
	{
		HRESULT			hr;
		DISPID			pid;
		CXMLElement*	pElement;
		CComPtr<IDispatch>	spDispatch;

		hr = S_FALSE;
		if( (pElement=GetElement())  &&
			SUCCEEDED(hr=pElement->GetIDsOfNames(IID_NULL,(LPOLESTR*)&lpName,1,LOCALE_SYSTEM_DEFAULT,&pid)) && 
			SUCCEEDED(pElement->QueryInterface(IID_IDispatch,(LPVOID*)&spDispatch)) )
		{
				return ParseTargetCommand(spDispatch,lpName,lpObject,result);
		}

		if( hr!=S_OK && m_spDispatch != NULL )
		{
			hr=m_spDispatch->GetIDsOfNames(IID_NULL,(LPOLESTR*)&lpName,1,LOCALE_SYSTEM_DEFAULT,&pid);
			m_spDispatch->QueryInterface(&spDispatch);
		}

		if( hr==S_OK )
			return ParseDispatchCommand(spDispatch,lpObject,result);
	}
	else if( *lpObject == OLECHAR('=') && lpObject[1] == OLECHAR('=') )
	{
		CComVariant	v1,v2;

		::VariantClear(&result);
		result.vt = VT_BOOL;
		if( InterCommand(name,v1) && InterCommand(lpObject+2,v2) )
		{
			if( v1 == v2 )
				result.bVal = VARIANT_TRUE;
			else
				result.bVal = VARIANT_FALSE;
			return true;
		}
		return false;
	}
	else if( *lpObject == OLECHAR('!') && lpObject[1] == OLECHAR('=') )
	{
		CComVariant	v1,v2;

		::VariantClear(&result);
		result.vt = VT_BOOL;
		if( InterCommand(name,v1) && InterCommand(lpObject+2,v2) )
		{
			if( v1 == v2 )
				result.bVal = VARIANT_FALSE;
			else
				result.bVal = VARIANT_TRUE;
			return true;
		}
		return false;
	}
	else if( *lpObject == OLECHAR('.')  && GetControlObject(name,&spDispatch) && ParseDispatchCommand(spDispatch,lpObject+1,result) )
	{
		return true;
	}
	else
	{
		HRESULT			hr;
		DISPID			pid;
		CXMLElement*	pElement;
		CComPtr<IDispatch>	spDispatch;

		hr = S_FALSE;
		if( (pElement=GetElement())  )
		{
			if( SUCCEEDED(hr=pElement->GetIDsOfNames(IID_NULL,&lpName,1,LOCALE_SYSTEM_DEFAULT,&pid)) )
				pElement->QueryInterface(IID_IDispatch,(LPVOID*)&spDispatch);
		}

		if( hr!=S_OK && m_spDispatch != NULL )
		{
			if( SUCCEEDED(hr=m_spDispatch->GetIDsOfNames(IID_NULL,&lpName,1,LOCALE_SYSTEM_DEFAULT,&pid)) )
				m_spDispatch->QueryInterface(&spDispatch);
		}

		if( hr==S_OK && ParseTargetCommand(spDispatch,lpName,lpObject,result) )
		{
			return true;
		}

	}
	spDispatch = NULL;
	return false;
}

bool CBaseObject::OnControlObject( IDispatch* pDispatch )
{
	m_spDispatch = NULL;
	return (pDispatch != NULL && SUCCEEDED(pDispatch->QueryInterface(IID_IDispatch,(LPVOID*)&m_spDispatch)) );
}

bool CBaseObject::OnControlObject( LPCWSTR lpTarget ,LPCWSTR lpCommand )
{
	HRESULT	hr=S_FALSE;
	CLSID	clsid;

	m_spDispatch = NULL;
	if( wcscmp(OLESTR("clsid"),lpTarget) == 0 )
		hr=::CLSIDFromString((LPOLESTR)lpCommand,&clsid);
	else if( wcscmp(OLESTR("progid"),lpTarget) == 0 )
		hr=::CLSIDFromProgID((LPOLESTR)lpCommand,&clsid);
	if( SUCCEEDED(hr) )
	{
#ifdef	_WIN32_WCE
		CComPtr<ILanguage>	pLanguage;
		CComPtr<IStorageMonitor>	spMonitor;

		if( SUCCEEDED(m_spDispatch.CoCreateInstance(clsid)) && m_spDispatch != NULL )
		{
			if( SUCCEEDED(m_spDispatch.QueryInterface(&spMonitor)) )
			{
				m_pDialog->SetStorageMonitorMonitor(spMonitor );
				spMonitor = NULL;
			}
			if( m_spLanguageLib != NULL && SUCCEEDED(m_spDispatch.QueryInterface(&pLanguage)) )
				pLanguage->SetService(m_spLanguageLib);
		}
#endif
	}
	return true;
}

bool CBaseObject::GetProperty( LPCWSTR lpName ,VARIANT& value )
{
	if( m_spDispatch != NULL )
		return CCommonUtility::GetProperty(m_spDispatch,lpName,value);
	return false;
}

bool CBaseObject::PutProperty( LPCWSTR lpName ,LPCWSTR lpValue )
{
	CComVariant	varValue;

	if( m_spDispatch != NULL )
	{
		if( iswdigit(*lpValue) )
			varValue=_wtol(lpValue);
		else if( *lpValue == OLECHAR('\'') )
		{
			OLECHAR	value[MAX_PATH];

			wcscpy(value,lpValue+1);
			value[wcslen(value)-1]=OLECHAR('\0');
			varValue=value;
		}
		else
			varValue=lpValue;
			
		return CCommonUtility::PutProperty(m_spDispatch,lpName,varValue);
	}
	return false;
}


bool CBaseObject::GetLanguageString( LONG index,CComBSTR& bstrText ,LONG* pStyle )
{
	LONG	lStyle;
#ifdef	_WIN32_WCE
	if( m_spLanguageLib != NULL )
	{
		bstrText.Empty();
		if( SUCCEEDED(m_spLanguageLib->GetString(index,&lStyle,&bstrText)) )
		{
			if( pStyle != NULL )
				*pStyle = lStyle;
			return true;
		}
	}
#endif
	return false;
}

bool CBaseObject::SetDefaultLanguageName( BSTR name )
{
#ifdef	_WIN32_WCE
	if( m_spLanguageLib != NULL && m_spLanguageLib->SetDefaultLanguageName(name)==S_OK )
	{
		return true;
	}
#endif
	return false;
}

bool CBaseObject::GetDefaultLanguageName( BSTR* name )
{
#ifdef	_WIN32_WCE
	if( m_spLanguageLib != NULL )
	{
		m_spLanguageLib->GetName(name);
		return true;
	}
#endif
	return false;
}

void CBaseObject::InitVariants( VARIANT* pVar ,long count)
{
	for( long i=0 ; pVar != NULL && i < count ; i++ )
		::VariantInit(pVar+i);
}

void CBaseObject::ClearVariants( VARIANT* pVar ,long count)
{
	for( long i=0 ; pVar != NULL && i < count ; i++ )
		::VariantClear(pVar+i);
}

bool CBaseObject::ConvertVariants( LPWSTR lpParam ,VARIANT* pVars ,LONG count ,DWORD dwStatus ,bool bDefString )
{
	int		index;
	LONG	i;

	if( lpParam == NULL || pVars == NULL  )
		return false;

	if( count == 0 )
		return true;

	for( i=0 ; i < count ; i++ )
	{
		index = count-i-1;
		if( dwStatus&(0x03<<(index*2)) )
		{
			InterCommand(lpParam,pVars[index]);
		}
		else if( iswdigit(*lpParam) || (*lpParam == OLESTR('-') && iswdigit(lpParam[1]))  )
		{
			pVars[index].vt = VT_I4;
			pVars[index].lVal = _wtoi(lpParam);
		}
		else if( (*lpParam == OLECHAR('\'') && lpParam[wcslen(lpParam)-1] == OLECHAR('\'')) )
		{
			pVars[index].vt = VT_BSTR;
			pVars[index].bstrVal = ::SysAllocStringLen(lpParam+1,wcslen(lpParam)-2);
		}
		else
		{
			if( bDefString == false )
				InterCommand(lpParam,pVars[index]);
			else
			{
				pVars[index].vt = VT_BSTR;
				pVars[index].bstrVal = ::SysAllocString(lpParam);
			}
		}
		lpParam += wcslen(lpParam)+1;
	}
	return true;
}

bool CBaseObject::ParseTargetCommand(IDispatch* pDispatch, LPCWSTR lpName ,LPCWSTR lpCommand ,VARIANT& result )
{
	DWORD		dwStatus;
	LPOLESTR	lpBuff,lpData,lpNext;
	DISPID		idDisp;
	DISPPARAMS	dispParams;
	EXCEPINFO FAR *pExcepInfo = NULL;
	unsigned int FAR puArgErr = NULL;
	HRESULT		hr;

	if( pDispatch->GetIDsOfNames(IID_NULL,(LPOLESTR*)&lpName,1,LOCALE_SYSTEM_DEFAULT,&idDisp) == S_OK )
	{
		if( (lpBuff=(LPOLESTR)_alloca(sizeof(OLECHAR)*(wcslen(lpCommand)+1))) )
		{
			dispParams.cNamedArgs = NULL;
			dispParams.rgdispidNamedArgs = NULL;
			memcpy(lpBuff,lpCommand,sizeof(OLECHAR)*(wcslen(lpCommand)+1));
			dispParams.cArgs=GetParamCount(lpBuff,lpData,lpNext,dwStatus);
			if( (dispParams.rgvarg=(VARIANT*)_alloca(sizeof(VARIANT)*dispParams.cArgs)) != NULL )
			{
				InitVariants(dispParams.rgvarg,dispParams.cArgs);
				if( ConvertVariants(lpData,dispParams.rgvarg,dispParams.cArgs,dwStatus) )
				{
					::VariantClear(&result);
					hr=pDispatch->Invoke(idDisp,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD|DISPATCH_PROPERTYGET,&dispParams,&result,pExcepInfo,&puArgErr);
					ClearVariants(dispParams.rgvarg,dispParams.cArgs);
					return true;
				}
			}
		}
		return true;
	}
	return false;
}

bool CBaseObject::ParseDispatchCommand(IDispatch* pDispatch, LPCWSTR lpCommand ,VARIANT& result )
{
	LPCWSTR		lpParam;
	LPOLESTR	lpName;

	if( pDispatch == NULL || (lpParam=wcschr(lpCommand,OLECHAR('('))) == NULL || lpParam == lpCommand )
		return false;

	if( (lpName=(LPOLESTR)_alloca(sizeof(OLECHAR)*((lpParam-lpCommand)+1))) )
	{
		lpName[lpParam-lpCommand] = OLECHAR('\0');
		memcpy(lpName,lpCommand,sizeof(OLECHAR)*(lpParam-lpCommand));
		return ParseTargetCommand(pDispatch,lpName,lpParam,result);
	}	
	return false;
}

bool CBaseObject::InterCommand( VARIANT& value ,VARIANT& result )
{
	if( value.vt == VT_BSTR )
		return InterCommand( value.bstrVal ,result );
	::VariantClear(&result);
	::VariantCopy(&result,&value);
	return true;
}

long CBaseObject::GetParamCount( LPWSTR lpBuff ,LPWSTR& lpParam ,LPWSTR& lpNext ,DWORD& dwParseStatus )
{
	WCHAR	lastChar,curChar;
	bool bChar=false,bStr=false,bOperator=false;
	LONG lCount=0,lParamCount=0;
	LPWSTR lpData=lpBuff;

	dwParseStatus = 0;
	lastChar = NULL;
	while( lpData && *lpData )
	{
		curChar = *lpData;
		if( !iswspace(curChar) && !(bStr == false && (curChar==OLECHAR('(')||curChar==OLECHAR(')'))) )
			bChar = true;

		if( curChar == OLECHAR('\'') )
			bStr = !bStr;

		if( bStr == false )
		{
			if( (curChar == OLECHAR('=') || curChar == OLECHAR('>') || curChar == OLECHAR('<') ) )
				bOperator = true;

			if( curChar == OLECHAR('(') )
			{
				if( lCount == 0 )
					lpParam = lpData+1;
				lCount++;
			}
			else if( curChar == OLECHAR(')') )
			{
				if( --lCount == 0 )
				{
					if( bChar == true )
						lParamCount++;
					*lpData = OLECHAR('\0');
					break;
				}
			}
			else if( curChar == OLECHAR(';') )
			{
				if( bChar == false )
				{
					*lpData = OLECHAR('\0');
					break;
				}
			}
			else if( curChar == OLECHAR(',') && lCount  < 2 )
			{
				bChar = false;
				if( bOperator )
					dwParseStatus |= 0x1;
				dwParseStatus <<= 2;
				lParamCount++;
				*lpData = OLECHAR('\0');
				bOperator = false;
			}
		}
		lastChar = *lpData;
		lpData++;
	}
	if( bOperator )
		dwParseStatus |= 0x1;
	lpNext = lpData;
	return lParamCount;
}

這個基礎類別不只上至連接 控制元件,轉向dialog message ,向下還關連到 XML 分析及腳本處理部份 ,ExecCommandString 便是腳本引擎的入口,而InterCommand 便是腳本引擎核心之一,

XXXLanguage ,更是多國語言處理的門戶,不過這是後話,以後再解釋,由此可見此 class 的重要性

因為 CControls 是定義在抽象基礎類別,很多行為還要再向上看去,大家才能看到真正的繪圖動作,而這抽象的分解也正是C++ 的思想核心,往後所有的物件分解,和聚合也都以此思想核心進行 ,故先公開CBaseObject 以後有很多機會再回頭看到 CBaseObject ,而下一步再向上方展的部份待到下篇再解說



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值