不久前,因為需要我必須開發一個繼承MFC中CWnd類別的控件。這個控件將會放在一個DLL中來讓使用者來調用,這樣就可以在每次的復用時不要停留在批量的拷文件的過程。我不是說批量拷文件到新的工程中的做法不好,但是經過幾個項目的批量拷文件的做法很有可能會讓原來簡單的幾個文件變成一大堆耦合很強的文件,這將給再次復用帶來不便。但是文件直接包含在使用者處也會帶來些好處,如調試要來得方便一些,要修改一些特性也是很容易。所以有人說做事是一個決策的過程,我認為不假。如果其中沒有決策,那只能說明一件事,我們忽略了某些東西。這往往也是很危險的。
在這個開發的過程中,我自認為對整個過程是清晰的,明了的。但是在開發的過程中卻因一個細節問題而迫使我花了整整一個上午的時間來調試,最后得以發現這個問題。這里我就簡單地回顧這個開發過程。
1:利用向導產生MFC Regular DLL 框架。
2:在app文件中加入一個導出的啞函數(就是什么事也不做的函數)來讓這個DLL支持隱式的加載.
如 extern “C” __declspec(dllimport) DummyExport() {}
3: 添加一個自CWnd派生的類,就叫MyCWnd好了。
4:為這個MyApp映射消息。如映射一個OnLButtonDown。并在這個消息中向父控件發
出自己的消息(當然實際項目中可不會是這樣簡單,這里只是讓控件的框架
先能跑起來證明與外界的消息是暢通的)
GetParent()->SendMessage(WM_COMMAND, GetCtrlID(), GetSafeHwnd());
5: 自定義一個消息 #define WM_MYWNDLAUGH (WM_USER + 106)并完成相應的映射。
6:為了注冊這自己的這個窗體類別,我們必須有一個靜態的注冊函數,
以便在CWinApp::InitInstance時注冊窗體類。
這里就是關鍵了
1 WNDCLASS wc;
2 wc.style = CS_GLOBALCLASS ;//這里曾讓我花了數小時來找這個bug.
3 wc.lpfnWndProc = myFunc;
4
5
6 LRESULT CALLBACK AFX_EXPORT myFunc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
7 {
8 AFX_MANAGE_STATE(AfxGetStaticModuleState());
9 CWnd *pWnd;
10 pWnd =CWnd::FromHandlePermanent(hWnd);
11 if(pWnd == NULL)
12 { pWnd = new MyWnd(); pWnd->attach(hwnd); }
13 return AfxCallWndProc(pWnd, hWnd, message, wParam, lParam);
14 }
15
7: 在CWinApp::InitInstance中調用注冊函數。
8: 在使用者界面中添加自定義控件,控件的類別就是上面的wc.lpszClassName對應的名稱。
9: 在使用者類中映射子控件消息
10:在早期就調用上述的啞函數。
11:向自定義控件發送消息。這樣就搭起了一個自定義控件的框架,在上面的這些步聚中就是
第6步要細心。余下的就是加特性的工作了。上述參考了MFC技術內幕等有關資料。