WTL编程--运行框架

来源:互联网 发布:男朋友礼物学生知乎 编辑:程序博客网 时间:2024/05/16 17:28

              WTL的历史和渊源就不介绍了。如果要谈论一门编程语言,基础的内容却必不可少--总得有些东西把所有的一切都串起来才行。

      我从接触WTL到今天,大概有7-8年了。6年前,我决定放弃了使用多年的MFC彻底转向WTL,做这个决定的一个基本的原因就是自由,当你使用WTL编码,你可以感受到操作系统的律动,你会觉得自己在跟操作系统协作。你知道自己在做什么,也能够预计即将发生什么,这感觉相当好。

     那么WTL都能做什么呢?答案是--任何事情。如果你觉得某样事情还不能做,那基本上只是表示你还有东西需要学,仅此而已。

            我目前使用的库是WTL8.1,由于我必须使用window 2003 server版的操作系统,有些东西我甚至还没有去尝试。 好吧,我们还是进入正题,看看WTL究竟是怎么回事,他是怎么开始的,如何工作?

             在开始之前,希望你已经了解Win32 windows编程,起码你知道,向windows注册一个窗口,消息循环,消息处理诸如此类的事情。如果你使用的是VS2008或者更高版本的开发环境,你可以生成一个win32程序看看。

             WTL实际上必须完成那些基础工作,我们现在来看看她是怎么做的。


CAppModule _Module;int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT){CMessageLoop theLoop;_Module.AddMessageLoop(&theLoop);CMainFrame wndMain;if(wndMain.CreateEx() == 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);// If you are running on NT 4.0 or higher you can use the following call instead to // make the EXE free threaded. This means that calls come in on a random RPC thread.//HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);ATLASSERT(SUCCEEDED(hRes));// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used::DefWindowProc(NULL, 0, 0, 0L);AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);// add flags to support other controlshRes = _Module.Init(NULL, hInstance);ATLASSERT(SUCCEEDED(hRes));int nRet = Run(lpstrCmdLine, nCmdShow);_Module.Term();::CoUninitialize();return nRet;}


         当你用WTL向导建立一个SDI程序,你会看到向导产生了这样的代码。开始的时候,你大概知道也许就可以了,但是总究有一天你会想去弄明白这些代码的意义。这个程序框架所带来的效果,就是你只需要专注去处理   CMainFrame 这个类就行了。就算你不管上面这些代码,程序也会运行的很好。

          将目光放在_tWinMain ,因为这里是整个程序的入口点。

        1. CoInitializeEx是Windows提供的API函数,为当前线程初始化COM库并设置并发模式。应用程序调用com库中的函数(除CoGetMalloc内存分配函数)之前必须初始化com库。在应用程序中使用COM库,至少要调用一次CoInitializeEx函数(通常也就调用一次)。如果传入参数的并发标志相同,单个线程也可以多次调用该函数,但后来有效的调用将返回 S_FALSE。在正常关闭COM库情况下,每一个CoInitialize 或者CoInitializeEx的成功的调用(也包含返回S_FALSE的调用),都必须用通Uninitialize函数来结束。

       使用函数 CoInitializeEx的代码的前面需要包含于处理标志 #define _WIN32_DCOM

     基于线程的并发模式一旦设置,将不能再改变。一个线程上调用CoInitializeEx如果与原来调用设置的并发模式不一致,将会失败并返回RPC_E_CHANGED_MODE。

     2.  注册通用控件(AtlInitCommonControls):

       InitCommonControlsex

 

         InitCommonControlsex
         函数原形:BOOL WINAPI InitCommonControlsEx(LPINITCOMMONCONTROLSEX lpInitCtrls);
               pInitCtrls参数指向一个INITCOMMONCONTROLSEX结构:
typedef struct tagINITCOMMONCONTROLSEX {
DWORD dwSize; // size of this structure结构长度
DWORD dwICC; // flags indicating which classes to be initialized需要初始化的类
} INITCOMMONCONTROLSEX, *LPINITCOMMONCONTROLSEX;
结构中的dwICC字段指定了需要注册的扩展通用控件类,与InitCommonControls注册所有它支持的通用控件类不同,InitCommonControlsEx函数只注册dwICC字段指明的扩展通用控件类,字段可以是下面取值的组合:
● ICC_BAR_CLASSES——注册工具栏、状态栏、Trackbar和Tooltip类。
● ICC_COOL_CLASSES——注册Rebar类。
● ICC_DATE_CLASSES——注册Date and Time Picker类。
● ICC_HOTKEY_CLASS——注册Hot Key类。
● ICC_INTERNET_CLASSES——注册IP Address Picker类。
● ICC_LISTVIEW_CLASSES——注册ListView和Header类。
● ICC_PAGESCROLLER_CLASS——注册Pager类。
● ICC_PROGRESS_CLASS——注册Progress Bar类。
● ICC_TAB_CLASSES——注册Tab和Tooltip类。
● ICC_TREEVIEW_CLASSES——注册TreeView和Tooltip类。
● ICC_UPDOWN_CLASS——注册Up-Down类。
● ICC_USEREX_CLASSES——注册ComboBoxEx类。

● ICC_WIN95_CLASSES——注册InitCommonControls函数注册的所有类。
InitCommonControlsEx函数是InitCommonControls函数的扩充


消息循环类:CMessageLoop

        观察一下第一个函数Run,它在 _tWinMain 中被调用, 这个地方用来处理命令行和初始化问题,例如建立特定的窗口并设置窗口的状态。这个Run函数内部,首先建立一个一个消息循环对象,把它附加给实体全局变量,由于实体全局变量已经初始化, 也就是线程已经运行, 这时候定义 CMainFrame wndMain, 并且建立这个窗口,然后显示他,最后开启消息循环函数的Run,观察一下 CMessageLoop 分类里面的Run函数,对比win32程序,看上几遍,你应该就已经理解这里发生了什么事情了。


全局变量 CAppModule _Module

       因为目前还不需要深究深层的运行的机制。这里就简单的说一下,能理解就可以了。所谓实体,其实就是一个进程,也就是指一个运行的程序。在windows下,它有自己的运行环境,有自己的独立内存空间,有自己的消息循环。大致看一下CAppModule 这个类就知道了。他有消息循环,系统设置改变通知,空闲处理,模块也有个初始化和释放的功能要调用,大致可以理解为创建线程和销毁线程的作用。而在这两者之间,就是消息循环了,我们编写应用的全部工作就在这个阶段。


0 0
原创粉丝点击