Click here to Skip to main content
15,895,011 members
Articles / Programming Languages / Objective C

Running State Machine Based Win32/WinCE Programs

Rate me:
Please Sign up or sign in to vote.
4.37/5 (9 votes)
17 May 20065 min read 70.9K   1.3K   35  
This article describes how to run state machine application framework based Win32/WinCE programs using the window message hooking technology. (Open source project)
// SimulatorDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Simulator.h"
#include "SimulatorDlg.h"
#include "AppThread.h"
#include "AppChildThread.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define SIMULATOR_SUPPORT_COLOR_NUM		256
#define SIMULATOR_BIT_PER_PIXEL			8
#define SIMULATOR_ADJUST_NUMBER			SIMULATOR_SUPPORT_COLOR_NUM-1

#define DISPLAY_BACKGROUND_COLOR		DEFAULT_BACKGROUND_COLOR
#define DISPLAY_FORGROUND_COLOR			0x000000

#define ID_TIMER_ALLOCATOR				100
#define ID_TIMER_CUSTOMER				101

extern SME_THREAD_CONTEXT_T g_AppThreadContext;
extern SME_THREAD_CONTEXT_T g_AppChildThreadContext;
HWND g_hwndDLg=NULL;

HANDLE g_hAppThread=NULL;
HANDLE g_hAppChildThread=NULL;

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSimulatorDlg dialog

CSimulatorDlg::CSimulatorDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSimulatorDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CSimulatorDlg)
	m_sMemSize = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_bTurnOn = FALSE;
}

void CSimulatorDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSimulatorDlg)
	DDX_Control(pDX, IDC_TRACE, m_trace);
	DDX_Control(pDX, IDC_STATIC_DISPLAY, m_Display);
	DDX_Text(pDX, IDC_STATIC_SIZE, m_sMemSize);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CSimulatorDlg, CDialog)
	//{{AFX_MSG_MAP(CSimulatorDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_POWER, OnButtonOnOff)
	ON_MESSAGE(WM_SRV_CALL_ID, OnSrvCall)
	ON_MESSAGE(WM_DEBUG_STR_ID,OnDebugStr)
	ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
	ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
	ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
	ON_BN_CLICKED(IDC_BUTTON4, OnButton4)
	ON_BN_CLICKED(IDC_BUTTON5, OnButton5)
	ON_BN_CLICKED(IDC_BUTTON6, OnButton6)
	ON_BN_CLICKED(IDC_BUTTON7, OnButton7)
	ON_BN_CLICKED(IDC_BUTTON8, OnButton8)
	ON_BN_CLICKED(IDC_BUTTON9, OnButton9)
	ON_BN_CLICKED(IDC_BUTTON11, OnButton11)
	ON_BN_CLICKED(IDC_BUTTON_LEFTSOFT, OnButtonLeftSoft)
	ON_BN_CLICKED(IDC_BUTTON_RIGHTSOFT, OnButtonRightSoft)
	ON_BN_CLICKED(IDC_BUTTON_UP, OnButtonUp)
	ON_BN_CLICKED(IDC_BUTTON_DOWN, OnButtonDown)
	ON_WM_TIMER()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSimulatorDlg message handlers

BOOL CSimulatorDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_event_id=0;
	m_event_str=_T("");
	m_trace.ModifyStyle(LVS_TYPEMASK,LVS_REPORT);
	m_trace.InsertColumn(0,_T("Time"),LVCFMT_LEFT,150);
	m_trace.InsertColumn(1,_T("Log"),LVCFMT_LEFT,265);
	m_nMemSize=0;
	m_sMemSize.Format(_T("%d Byte(s)"),m_nMemSize);
	UpdateData(FALSE);

	g_hwndDLg = m_hWnd;
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CSimulatorDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CSimulatorDlg::OnPaint() 
{

	if (IsIconic())
	{
		TRACE(_T("Iconic OnPaint \n"));

		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
		CDialog::OnPaint();
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CSimulatorDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CSimulatorDlg::OnButtonOnOff() 
{
	// TODO: Add your control notification handler code here
	MSG_KEY_PRESS_T KeyPressMsg;
	if (m_bTurnOn==FALSE && g_hAppChildThread==NULL && g_hAppThread==NULL)
	{
		// Power has turned off, and application threads are not running. 
		m_bTurnOn = TRUE;
		SME_SET_TRACER(MyOutputDbgStrProc);
		CWinThread* pAppThreadObj = AfxBeginThread(RUNTIME_CLASS(CAppThread));
		g_hAppThread = (HANDLE)pAppThreadObj; 

		CWinThread* pAppChildThreadObj = AfxBeginThread(RUNTIME_CLASS(CAppChildThread));
		g_hAppChildThread = (HANDLE)pAppChildThreadObj; 
	}
	else if (m_bTurnOn==TRUE && g_hAppChildThread!=NULL && g_hAppThread!=NULL)
	{
		// Post a message to App thread requested to end thread.
		m_bTurnOn = FALSE;
		KeyPressMsg.nKeyCode = KEY_CODE_POWER;
		AgtPostExtEvent(EXT_EVENT_ID_KEY_PRESS, &KeyPressMsg, sizeof(MSG_KEY_PRESS_T), NULL, &g_AppThreadContext);
		//SME_ASCII_TRACE("EXT_EVENT_ID_KEY_PRESS:%d", KEY_CODE_POWER);
	}
}

void CSimulatorDlg::OnButtonKeyPress(int nKeyCode) 
{
	// TODO: Add your control notification handler code here
	if (m_bTurnOn== FALSE) return;

	MSG_KEY_PRESS_T KeyPressMsg;
	KeyPressMsg.nKeyCode = nKeyCode;

	AgtPostExtEvent(EXT_EVENT_ID_KEY_PRESS, &KeyPressMsg, sizeof(MSG_KEY_PRESS_T), NULL,&g_AppThreadContext);
	//SME_ASCII_TRACE("EXT_EVENT_ID_KEY_PRESS:%d", nKeyCode);
}

void CSimulatorDlg::OnButton1() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_1);	
}

void CSimulatorDlg::OnButton2() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_2);	
	
}

void CSimulatorDlg::OnButton3() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_3);	
	
}

void CSimulatorDlg::OnButton4() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_4);	
	
}

void CSimulatorDlg::OnButton5() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_5);	
	
}

void CSimulatorDlg::OnButton6() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_6);	
	
}

void CSimulatorDlg::OnButton7() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_7);	
	
}

void CSimulatorDlg::OnButton8() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_8);	
	
}

void CSimulatorDlg::OnButton9() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_9);	
	
}

void CSimulatorDlg::OnButton11() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_0);	

}

void CSimulatorDlg::OnButtonLeftSoft() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_LEFTSOFT);	
}

void CSimulatorDlg::OnButtonRightSoft() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_RIGHTSOFT);	
}

void CSimulatorDlg::OnButtonUp() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_UP);	
}

void CSimulatorDlg::OnButtonDown() 
{
	// TODO: Add your control notification handler code here
	OnButtonKeyPress(KEY_CODE_DOWN);
}

LRESULT CSimulatorDlg::OnSrvCall(WPARAM wParam, LPARAM lParam)
{
	SME_SRV_CALL_DATA_HDR_T *pHdr = (SME_SRV_CALL_DATA_HDR_T *)wParam;
	long nSrvCallId = pHdr->nSrvCallId;
	void *pCallData = SME_HDR2CALLDATA(pHdr);
	int nDataSize = pHdr->nDataLen;
	SRV_SET_TIMER_T *pSetTimer;
	SRV_GET_TIME_T *pGetTime;
	SRV_KILL_TIMER_T *pKillTimer;

	switch (nSrvCallId)
	{
	case SRV_ID_POWER_CONTROL:
		PowerControl();
		break;
	case SRV_ID_CLEAR_DISPLAY:
		ClearDisplay();
		break;
	case SRV_ID_UPDATE_DISPLAY:
		UpdateDisplay(pCallData,nDataSize);
		break;
	case SRV_ID_TURN_OFF_DISPLAY:
		TurnOffDisplay();
		break;
	case SRV_ID_MEMORY_STATISTIC:
		UpdateMemSize(pCallData);
		break;
	case SRV_ID_SET_TIMER:
		pSetTimer = (SRV_SET_TIMER_T*)(pCallData);
		(*pSetTimer->pTimerID) = myClk.SetTimer(pSetTimer->nElapse,pSetTimer->pDestPort,&m_clk_id);
		break;
	case SRV_ID_KILL_TIMER:
		pKillTimer = (SRV_KILL_TIMER_T*)(pCallData);
		::KillTimer(0, pKillTimer->nTimerID);
		break;
	case SRV_ID_GET_TIME:
		pGetTime = (SRV_GET_TIME_T*)(pCallData);
		myClk.GetTime(pGetTime->pHour, pGetTime->pMinute, pGetTime->pSecond);
		break;
	}; // end of switch

	AgtEndServiceCall(pHdr);
	return TRUE;
}

// The following call back function will be invoked at application thread.
int OnThreadEnd(void* pParam )
{
	AfxEndThread(0);
	return 0;
}

BOOL CSimulatorDlg::PowerControl(){
	if (m_bTurnOn==TRUE)
		AgtPostExtEvent(EVENT_POWER_UP,NULL,0,NULL,&g_AppThreadContext);
	else{
		TurnOffDisplay();
		// Post a request to end application thread.
		AgtEndAppThread(&g_AppChildThreadContext,OnThreadEnd);
		WaitForSingleObject(g_hAppChildThread,INFINITE);

		AgtEndAppThread(&g_AppThreadContext,OnThreadEnd);
		WaitForSingleObject(g_hAppThread,INFINITE);

		// Ensure all application threads ended.
		Sleep(1000);
		AgtFreeAppDll();
		g_hAppChildThread=NULL;
		g_hAppThread = NULL;
	}
	return TRUE;
}

BOOL CSimulatorDlg::ClearDisplay()
{
	CDC *pDC = m_Display.GetDC();
	for (int x=0; x<DISP_WIDTH; x++)
		for (int y=0; y<DISP_HEIGHT; y++)
		{
			pDC->SetPixel(x,y,DISPLAY_BACKGROUND_COLOR);
			m_Display.m_DispBuf[x+y*DISP_WIDTH]= DISPLAY_BACKGROUND_COLOR;
		}
	m_Display.UpdateWindow();
	return TRUE;
}

BOOL CSimulatorDlg::TurnOffDisplay()
{
	CDC *pDC = m_Display.GetDC();
	for (int x=0; x<DISP_WIDTH; x++)
		for (int y=0; y<DISP_HEIGHT; y++)
		{
			pDC->SetPixel(x,y,DISPLAY_FORGROUND_COLOR);
			m_Display.m_DispBuf[x+y*DISP_WIDTH]= DISPLAY_FORGROUND_COLOR;
		}
	m_Display.UpdateWindow();
	return TRUE;
}

BOOL CSimulatorDlg::UpdateDisplay(void *pCallData, int nSize)
{
	CDC *pDC = m_Display.GetDC();

	SRV_CALL_UPDATE_DISPLAY_T *pData = (SRV_CALL_UPDATE_DISPLAY_T *)pCallData;
	int nLeft, nTop, nWidth, nHeight;
	unsigned short pixel_per_byte=8/SIMULATOR_BIT_PER_PIXEL,color;
	unsigned char *pBuffer = pData->pData;
	
	if(pCallData){
		nLeft = pData->nLeft;
		nTop = pData->nTop;
		nHeight = pData->nHeight;
		nWidth = pData->nWidth;
		
		for (int y=0;y<nTop;y++)
			for(int i=0;i<DISP_WIDTH/pixel_per_byte;i++)
				pBuffer++;

		for (y=nTop; y<nTop+nHeight; y++){

			for (int x=0;x<nLeft;x++)
				if (x % pixel_per_byte==pixel_per_byte-1)
					pBuffer++;

			for (x=nLeft; x<nLeft+nWidth; x++)
			{
				color=(*pBuffer>>(8-(x%pixel_per_byte+1)*SIMULATOR_BIT_PER_PIXEL)) & SIMULATOR_ADJUST_NUMBER;
				pDC->SetPixel(x,y,ColorPalette(color).GetColorRef());
				m_Display.m_DispBuf[x+y*DISP_WIDTH]=ColorPalette(color).GetColorRef();
				if (x % pixel_per_byte==pixel_per_byte-1)
					pBuffer++;
			}

			for(x=nLeft+nWidth;x<DISP_WIDTH;x++)
				if (x % pixel_per_byte==pixel_per_byte-1)
					pBuffer++;
		}

		m_Display.UpdateWindow();
		return TRUE;
	}
	else
		return FALSE;
}

BOOL CSimulatorDlg::UpdateMemSize(void *pCallData){
	if(pCallData){
		m_nMemSize=*((unsigned int*)pCallData);
		return TRUE;
	}
	else
		return FALSE;
}

CStringList g_DbgStrList;

void MyOutputDbgStrProc(const SME_CHAR * sDebugStr)
{
	g_DbgStrList.AddTail(sDebugStr);

	if (g_hwndDLg)
		::PostMessage(g_hwndDLg, WM_DEBUG_STR_ID,(WPARAM)(LPCTSTR)(g_DbgStrList.GetTail()),0);

}

LRESULT CSimulatorDlg::OnDebugStr(WPARAM wParam, LPARAM lParam)
{
	CString time_str;
	int hour,minute,second;

	myClk.GetTime(&hour,&minute,&second);
	time_str.Format(_T("%d:%d:%d"),hour,minute,second);

	CString sDbgStr = g_DbgStrList.RemoveHead();

	int nAddItem = m_trace.InsertItem(999999, time_str);
	m_trace.SetItemText(nAddItem,1,sDbgStr);
	m_trace.EnsureVisible(nAddItem,TRUE);
	m_event_id++;
	m_event_str=(SME_CHAR*)wParam;
	return TRUE;
}

void CSimulatorDlg::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	// Refresh dynamic memory statistics.
	if(nIDEvent==ID_TIMER_ALLOCATOR){
		m_sMemSize.Format(_T("%d Byte(s)"),m_nMemSize);
		UpdateData(FALSE);
		CDialog::OnTimer(nIDEvent);
	}
	//else if(nIDEvent==ID_TIMER_CUSTOMER){
	//}
}


int CSimulatorDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
	// TODO: Add your specialized creation code here
	m_timer_id=SetTimer (ID_TIMER_ALLOCATOR, 2000, NULL);
	return 0;
}

BOOL CSimulatorDlg::DestroyWindow() 
{
	// TODO: Add your specialized code here and/or call the base class
	::KillTimer(0, m_timer_id);
	if (m_bTurnOn==TRUE && g_hAppChildThread!=NULL && g_hAppThread!=NULL)
	{
		// Turn off power and terminate application threads.
		m_bTurnOn = FALSE;
		PowerControl();
	}
	return CDialog::DestroyWindow();
}

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.


Written By
Web Developer
China China
Jerome. (Free to speak, free to use.)

Comments and Discussions