不久前,因?yàn)樾枰冶仨氶_發(fā)一個(gè)繼承MFC中CWnd類別的控件。這個(gè)控件將會(huì)放在一個(gè)DLL中來讓使用者來調(diào)用,這樣就可以在每次的復(fù)用時(shí)不要停留在批量的拷文件的過程。我不是說批量拷文件到新的工程中的做法不好,但是經(jīng)過幾個(gè)項(xiàng)目的批量拷文件的做法很有可能會(huì)讓原來簡(jiǎn)單的幾個(gè)文件變成一大堆耦合很強(qiáng)的文件,這將給再次復(fù)用帶來不便。但是文件直接包含在使用者處也會(huì)帶來些好處,如調(diào)試要來得方便一些,要修改一些特性也是很容易。所以有人說做事是一個(gè)決策的過程,我認(rèn)為不假。如果其中沒有決策,那只能說明一件事,我們忽略了某些東西。這往往也是很危險(xiǎn)的。
在這個(gè)開發(fā)的過程中,我自認(rèn)為對(duì)整個(gè)過程是清晰的,明了的。但是在開發(fā)的過程中卻因一個(gè)細(xì)節(jié)問題而迫使我花了整整一個(gè)上午的時(shí)間來調(diào)試,最后得以發(fā)現(xiàn)這個(gè)問題。這里我就簡(jiǎn)單地回顧這個(gè)開發(fā)過程。
1:利用向?qū)Мa(chǎn)生MFC Regular DLL 框架。
2:在app文件中加入一個(gè)導(dǎo)出的啞函數(shù)(就是什么事也不做的函數(shù))來讓這個(gè)DLL支持隱式的加載.
如 extern “C” __declspec(dllimport) DummyExport() {}
3: 添加一個(gè)自CWnd派生的類,就叫MyCWnd好了。
4:為這個(gè)MyApp映射消息。如映射一個(gè)OnLButtonDown。并在這個(gè)消息中向父控件發(fā)
出自己的消息(當(dāng)然實(shí)際項(xiàng)目中可不會(huì)是這樣簡(jiǎn)單,這里只是讓控件的框架
先能跑起來證明與外界的消息是暢通的)
GetParent()->SendMessage(WM_COMMAND, GetCtrlID(), GetSafeHwnd());
5: 自定義一個(gè)消息 #define WM_MYWNDLAUGH (WM_USER + 106)并完成相應(yīng)的映射。
6:為了注冊(cè)這自己的這個(gè)窗體類別,我們必須有一個(gè)靜態(tài)的注冊(cè)函數(shù),
以便在CWinApp::InitInstance時(shí)注冊(cè)窗體類。
這里就是關(guān)鍵了
1 WNDCLASS wc;
2 wc.style = CS_GLOBALCLASS ;//這里曾讓我花了數(shù)小時(shí)來找這個(gè)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中調(diào)用注冊(cè)函數(shù)。
8: 在使用者界面中添加自定義控件,控件的類別就是上面的wc.lpszClassName對(duì)應(yīng)的名稱。
9: 在使用者類中映射子控件消息
10:在早期就調(diào)用上述的啞函數(shù)。
11:向自定義控件發(fā)送消息。這樣就搭起了一個(gè)自定義控件的框架,在上面的這些步聚中就是
第6步要細(xì)心。余下的就是加特性的工作了。上述參考了MFC技術(shù)內(nèi)幕等有關(guān)資料。