在MFC应用框架下运行状态机

本文描述了使用钩子技术在基于Windows程序的MFC应用框架下直接运行状态机应用程序的方法。

一个典型的状态自动机线程如下运作:

 

SmeRun()

{

            do {

                        等待被传递到该运行的线程的一个外部事件;               

if (事件有效)

                        {

                                    分发这个事件给活动的应用程序并触发状态转换。                   

} else break;

            } while(1);

}

 

这种运行模式的缺点是我们必须为状态自动机创建一个单独的线程。为了直接用基于程序的MFC应用框架 运行 状态自动机应用程序,状态向导允许你使用 函数MfcHookWnd().将一个应用线程与一个窗口相连。MFC程序可以将一个外部事件传递 或发送到运行在一个线程上的被钩住的窗口,然后引擎 将它分发到活动的状态机应用程序。

MfcHookWnd()通过在Windows下把一个HWND对象作为子类钩住这个HWND对象,即通过在所有当前的程序前面插入它自己的窗口进程,通常是AfxWndProc。可以参考Microsoft Systems Journal March 1997)获得更详细的信息。

 

LRESULT CEgnSubclassWnd::WindowProc(HWND hwnd, UINT msg, WPARAM wp,LPARAM lp)

{

            struct SME_EVENT_T* pExtEvent=NULL;

            MSG WinMsg;

            WinMsg.hwnd = hwnd;

            WinMsg.message =msg;

            WinMsg.wParam = wp;

            WinMsg.lParam = lp;

 

            LRESULT ret = 0;

            switch (msg)

            {

            case WM_EXT_EVENT_ID:

                        // External event is triggered. App go to running state.

                        OnExtEvent(WinMsg);

                        break;

 

            default:

                        break;

            }

 

            ret = CSubclassWnd::WindowProc(hwnd,msg,wp,lp);

            return ret;

}

 

CEgnSubclassWnd EngSubclassWnd;

 

BOOL MfcHookWnd(HWND hWndHooked)

{

            if (hWndHooked==NULL || !IsWindow(hWndHooked)) return FALSE;

 

            CWnd *pWnd = CWnd::FromHandle(hWndHooked);

            return EngSubclassWnd.HookWindow(pWnd);           

}

 

 

通常,所有的状态机程序只运行在一个线程上。然而,状态自动机允许将程序分成一些组,每组的程序同时在单独的线程上运行。如下图:用MFC运行状态机说明一组程序可在每组各自的线程上运行。在每个线程上,状态自动机钩住在线程上运行的窗口。

 

: MFC 运行状态自动机

 

下面的例子说明了钩住对话框消息和分发外部事件给Player 状态机应用程序的方法。声明一个应用线程上下文。在对话框打开时,通过SmeInitEngine()初始化状态自动机的线程上下文。在Windows系统下,这个函数将自动的隐式的初始化所给线程上下文的以下信息:

1) SmeSetExtEventOprProc()   通过Windows API GetMessage(), PostThreadMessage() 创建外部事件处理函数

2) SmeSetMemOprProc()         通过new, delete操作来创建动态内存管理函数。

3) SmeSetTlsProc()                   通过Windows API TlsGetValue(), TlsSetValue()创建线程局部存储器程序函数。

然后钩住对话框消息。激活Player应用程序的应用线程。如果有外部事件触发,调用MfcPostExtIntEventToWnd()函数发送一个外部事件给对话框。这个函数将发送如下的WM_EXT_EVNET_ID窗口消息给对话框

#define WM_EXT_EVENT_ID                       (0xBFFF)

 

当状态自动机接收到这个消息,将信息转化为一个外部事件,如果它不是空的就 将它分发到目的应用程序端口;否则将它分发到所有在应用线程上下文上的活动应用程序。

 

: Player 应用程序

 

 

// 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());

}

 

被钩住的窗口毁灭时,窗口消息钩子被自动 的移除。

 

下面的函数对Windows应用程序的发展起了很大作用。

·   MfcHookWnd() : 这个 API 函数钩住特定的窗口。

·   MfcPostExtPtrEventToWnd() : 这个 API 函数传递一个带有数据块的外部事件给特定的窗口,然后引擎分发它给在线程上下文的活动状态自动机应用程序。MfcPostExtIntEventToWnd() : 这个 API函数发送一个带有数据块的外部事件给特定的窗口,然后引擎分发它给在线程上下文的活动状态自动机应用程序。

·   MfcSendExtPtrEventToWnd() :这个API函数传递一个带有两个整型参数的外部事件给特定的窗口,然后引擎分发它给在线程上下文的活动状态自动机应用 程序。

·   MfcSendExtIntEventToWnd() : 这个API函数发送一个带有两个整型参数的外部 事件给特定的窗口,然后引擎分发它给在线程上下文的活动状态自动机应用程序。

 

www.intelliwizard.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值