Page 1
Page 2
When the state machine engine receives a message dedicated to state machine applications, the state machine engine translates this message to an external event, and dispatch it to the destination application port if it is not null; otherwise dispatch it to all active applications which run in the same application thread context.
When the hooked window is destroyed, the window message hook is removed automatically.
/******************************************************************** DESCRIPTION: Just like SmeRun(), this function dispatches external event to applications.
* INPUT:
* OUTPUT: None.
* NOTE:
*******************************************************************/
struct SME_EVENT_T * GetEventFromQueue();
BOOL DispatchInternalEvents(SME_THREAD_CONTEXT_PT pThreadContext);
BOOL DispatchEventToApps(SME_THREAD_CONTEXT_PT pThreadContext,SME_EVENT_T *pEvent);
LRESULT CEgnSubclassWnd::OnExtEvent(MSG& WinMsg)
{
SME_APP_T *pApp;
SME_THREAD_CONTEXT_PT pThreadContext=NULL;
SME_EVENT_T *pEvent=TranslateEvent(&WinMsg);
if (pEvent==NULL)
return 0;
if (g_pfnGetThreadContext)
pThreadContext = (*g_pfnGetThreadContext)();
if (!pThreadContext) return 0;
pApp = pThreadContext->pActAppHdr;
/* Call hook function on an external event coming. */
if (pThreadContext->fnOnEventComeHook)
(*pThreadContext->fnOnEventComeHook)(SME_EVENT_ORIGIN_EXTERNAL, pEvent);
/* Dispatch it to active applications.*/
DispatchEventToApps(pThreadContext, pEvent);
DispatchInternalEvents(pThreadContext);
/* Free external event if necessary. */
if (pThreadContext->fnDelExtEvent && pEvent)
{
(*pThreadContext->fnDelExtEvent)(pEvent);
// Engine should delete this event, because translation of external event will create an internal event.
SmeDeleteEvent(pEvent);
}
return 0;
}
CEgnSubclassWnd EngSubclassWnd;
BOOL MfcHookWnd(HWND hWndHooked)
{
if (hWndHooked==NULL || !IsWindow(hWndHooked)) return FALSE;
CWnd *pWnd = CWnd::FromHandle(hWndHooked);
return EngSubclassWnd.HookWindow(pWnd);
}
BOOL MfcUnhookWnd(HWND hWndHooked)
{
if (hWndHooked==NULL || !IsWindow(hWndHooked)) return FALSE;
CWnd *pWnd = CWnd::FromHandle(hWndHooked);
return EngSubclassWnd.HookWindow(pWnd);
}
Sample
Suppose we have a simple player application whose state diagram is as follows:

Figure: Player State Machine Application
The following sample shows the way to hook dialog messages and dispatch external events to Player state machine application. Declare an application thread context. On dialog open, initializes the state machine engine in the thread context through SmeInitEngine(). In Windows edition of state machine engine, this function will automatically initialize the given thread context following informations implicitly:
1) SmeSetExtEventOprProc() to setup external event handling functions through Windows API GetMessage(), PostThreadMessage().
2) SmeSetMemOprProc() to setup dynamic memory management functions through new, delete operators.
3) SmeSetTlsProc() to setup thread local storage procedure functions through Windows API TlsGetValue(), TlsSetValue().
And then hooks the dialog messages. Activate the Player application in the application thread. If an external event triggers, calls MfcPostExtIntEventToWnd() function to post an external event to dialog. This function will post WM_EXT_EVNET_ID Windows message as below to the dialog.
#define WM_EXT_EVENT_ID (0xBFFF)
When the state machine engine receives this message, translates this message to an external event, and dispatch it to the destination application port if it is not null; otherwise dispatch it to all active applications which runs in the same application thread context.
// The application thread context.
SME_THREAD_CONTEXT_T g_AppThreadContext;
// Declare the Player state machine application variable.
SME_DEC_EXT_APP_VAR(Player);
BOOL CSamplePlayerMfcDlg::OnInitDialog()
{
CDialog::OnInitDialog();
....
// Initialize engine.
g_AppThreadContext.nAppThreadID = 0;
SmeInitEngine(&g_AppThreadContext);
// Hook dialog message.
MfcHookWnd(GetSafeHwnd());
SmeActivateApp(&SME_GET_APP_VAR(Player),NULL);
}
void CSamplePlayerMfcDlg::OnButtonPower()
{
MfcSendExtIntEventToWnd(EXT_EVENT_ID_POWER, 0, 0, NULL, GetSafeHwnd());
}
void CSamplePlayerMfcDlg::OnButtonPause()
{
// TODO: Add your control notification handler code here
MfcSendExtIntEventToWnd(EXT_EVENT_ID_PAUSE_RESUME, 0, 0, NULL, GetSafeHwnd());
}
Interested in this subject?
You may download more information at http://www.intelliwizard.com/ the official site the UML IntelliWizard open source project.[4]
References
[1] [Computer Networks, Andrew S.Tanenbaum].
[2] This entry is from Wikipedia, the leading user-contributed encyclopedia .
[3] Microsoft Systems Journal March 1997
[4] The U ML State Wizard project is hosted by Sourceforge.net
Previous Page