不久前,因为需要我必须开发一个继承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技术内幕等有关资料。