wtl这个开发框架在开发win32程序方面有很多应用 ,现在chrome和金山等都是用的这个库,所以我要好好学习一下,故写此博客,以推动自己学习。
开始
我从都开始建立一个win32的窗口程序,然后一步一步的添加wtl中的模块,以求达到熟悉win32中的各个api和wtl中类的目的。
首先,包含一下atlapp.h这个头文件。这个头文件中包含了CMessageLoop,这个类主要是用来管理win32的消息循环的(具体的以后再仔细分析吧);CAppModule这个类封装了一个程序中的所有的线程消息循环 。
class CAppModule : public ATL::CComModule
{
public:
DWORD m_dwMainThreadID;
ATL::CSimpleMap<DWORD, CMessageLoop*>* m_pMsgLoopMap;
ATL::CSimpleArray<HWND>* m_pSettingChangeNotify;
。。。。。。。。。。。
}
其中,m_dwMainThreadID是程序主线程的线程ID,m_pMsgLoopMap中维护着所有线程,m_pSettingChangeNotify我还不清楚,在看吧。
在项目中添加一个类CmfMainFrame,然后继承自CWindowImpl<CmfMainFrame>, CWindowImpl是WTL中所有的窗口封装类的一个实现模板里,封装了基本的窗口相关的api调用。如果要从CWindowImpl类继承,我们必须要定义如下两个宏:
BEGIN_MSG_MAP(CmfMainFrame)
END_MSG_MAP()
其中BEGIN_MSG_MAP的定义如下,封装了一个ProcessWindowMessage函数,这个函数是CWindowImpl中的一个虚函数,我们通过在子类中实现出这个函数,才能够实例化它。
#define BEGIN_MSG_MAP(theClass) \
public: \
BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \
{ \
BOOL bHandled = TRUE; \
(hWnd); \
(uMsg); \
(wParam); \
(lParam); \
(lResult); \
(bHandled); \
switch(dwMsgMapID) \
{ \
case 0:
由win32中的编程知识可知,我们要创建一个窗口,必选在定义然后注册这个窗口,然后创建显示,开始程序中的消息循环。CwindowImpl中封装了定义和注册窗口,还有创建和显示。我的CmfMainFrame类得代码如下:
class CmfMainFrame:
public CWindowImpl<CmfMainFrame>
{
public:
BEGIN_MSG_MAP(CmfMainFrame)
END_MSG_MAP()
};
然后主程序的代码如下:
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CmfMainFrame wndMain;
if(wndMain.Create(NULL, CWindow::rcDefault, L"KO", WS_OVERLAPPEDWINDOW) == NULL)
{
ATLTRACE(_T("Main window creation failed!\n"));
return 0;
}
wndMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
return nRet;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
ATLASSERT(SUCCEEDED(hRes));
AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES);
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
AtlAxWinInit();
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
return nRet;
}
此时,运行程序就可以显示一个窗口了。我们要是点击窗口的X关闭按钮后,不能够结束程序,只是窗口消失了。问题在于我们没有处理WM_DESTROY消息。我们在BEGIN_MSG_MAP中添加一个MESSAGE_HANDLER代码如下:
BEGIN_MSG_MAP(CmfMainFrame)
MESSAGE_HANDLER(WM_DESTROY, onDestroy)
END_MSG_MAP()
LRESULT onDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
PostQuitMessage(0);
return 0;
}
此时我们点击窗口的关闭按钮后,我们就可以退出程序了。
至此一个简单的窗体就显示出来了。