程序思路是由外部的輸入輸出控制卡發出采集圖像信號,之后相機采集圖像得到圖像數據指針,接收圖像數據指針創建成圖像最后顯示到MFC對話框應用程序的Picture Control控件上,同時,為了標定相機位置,在主對話框類CMyDlg的OnPaint函數中有對Picture Control的繪圖操作(不改變圖像數據,進行畫線,畫矩形等操作)。
設計時考慮到I/O卡何時發出采集信號或者相機何時得到圖像數據指針是不確定的(不使用OnTime),同時考慮到I/O卡和相機的回調函數與主程序之間的數據交換會更加困難(不在回調函數里處理結果),所以創建多線程Dectect函數,I/O卡或者相機的回調函數僅負責向主程序發送全局的圖像數據指針,調用自定義事件的SetEvent函數通知Dectect線程工作。
Dectect線程獲得圖像數據指針之后無法直接調用CMyDlg的OnPaint函數,Invalidate和Updatedata等函數。
采用自定義消息的方式間接實現功能。將來在工作中肯定會遇到更多的此類情況。實現分為下列七個步驟。
第一步:在stdafx.h增加一個自定義消息宏
#define WM_USER_POSTINVALIDATE WM_USER+500
第二步:在MyDlg.h中聲明一個public類型的成員函數(聲明我們自己定義消息的處理函數)
afx_msg LRESULT MyMessage(WPARAM wParam, LPARAM lParam);
第三步:在CMyDlg類(MyDlg.cpp)的 BEGIN_MESSAGE_MAP(CEE8000Dlg, CDialog) 和 END_MESSAGE_MAP()之間(即類的消息映射表)中添加自定義消息的映射項
ON_MESSAGE(WM_USER_POSTINVALIDATE,MyMessage)
第四步:在CMyDlg類的實現文件MyDlg.cpp中添加自定義消息的處理函數
LRESULT CMyDlg::MyMessage(WPARAM wParam, LPARAM lParam)
{
}
第五步:之前操作增加的自定義消息函數的目的是為了可以在Dectect線程中調用PostMessage函數,PostMessage作用是將一個指定的消息寄送到指定窗口創建的線程(窗口句柄)的消息隊列中。消息已有,接下來需要在Dectect中獲得主對話框的窗口句柄。
1、得到主對話框的窗口句柄。常規問題,在CMyDlg的OnInitDialog函數中添加
CWnd *pMainWnd=AfxGetMainWnd();
HWND hMainWnd=pMainWnd->GetSafeHwnd();
2、將hMainWnd添加到Dectect。比較麻煩,初始嘗試把hMainWnd定義成全局變量,調試運行發現hMainWnd在OnInitDialog中正確賦值,運行到Dectect線程函數值就又變為NULL。還嘗試在Dectect函數中
CWnd *pMainWnd=AfxGetMainWnd(); //錯誤方法 HWND hMainWnd=pMainWnd->GetSafeHwnd(); //錯誤方法
調試結果運行到Dectect線程函數hMainWnd就又變為NULL。正確的方法又要回到Dectect線程的創建過程中去。
3、Dectect線程創建函數
HANDLE hThreadDectect=CreateThread(NULL,NULL,&Dectect,NULL,NULL,&dwThreadId1); //錯誤方法
修改后的Dectect線程創建函數
HANDLE hThreadDectect=CreateThread(NULL,NULL,&Dectect,hMainWnd,NULL,&dwThreadId1);//正確,第四個參數將hMain作為參數傳入回調函數
經過這樣3步就將主對話框的窗口句柄傳遞到Dectect線程中了。
第六步:Dectect線程圖像數據處理操作完成之后向主對話框線程寄送完成消息,我的程序中相當於通知主對話框進行重繪操作。Dectect線程函數的合適位置:
PostMessage((HWND)pParam,WM_USER_POSTINVALIDATE,0,0); //pParam就是CreateThread中傳遞到Dectect的窗口句柄
第七步:在第四步的函數實現部分中可以直接調用CMyDlg的OnPaint函數,Invalidate和Updatedata等函數了。
記錄的自我感覺很詳細,方便以后再查閱。同時歡迎各位大神多提寶貴意見。
參考文獻:MFC新線程控制進度條