ATL的GUI程序设计(1)
from:http://blog.titilima.com/atlgui-1.html
第一章 不能免俗的“Hello, World!”
在这一章里,就像所有的入门级教程一样,我也将不能免俗地以一个“Hello, World!”程序开始我的教程。然后,我将逐步深入,向你介绍这个ATL版本程序中所有必要的信息。此外,我还将介绍一些Win32中你可能不知道的东西,包括WinMain的_t兼容以及如何在MessageBox中加入自己的图标等等。
接近,接近,再接近……
可以说,所有“Hello, World!”程序的内容不外乎都是以十分有限的几行代码向当前的目标屏幕环境上输出一个字符串“Hello, World!”。这个程序通常具有以下几个特点:
- 排除印刷错误的可能性,几乎所有的初学者都可以照葫芦画瓢地独立书写、编译并运行这个程序。
- 这个程序可以体现出当前语言环境的典型配置方式。
- 这个程序中具有当前语言特定的程序入口点。
- 这个程序中含有一条当前环境典型的输出语句(通常也是最简单、最常用的),由这条语句来输出“Hello, World!”字符串。
- 从这个程序可以很清楚的了解当前语言环境下程序运行的典型流程。
- 这个程序可能还会表现当前语言的一些其它特点。
那么,首先让我以最简单的C语言版“Hello, World!”开始吧:
- #include <stdio.h>
- int main()
- {
- printf( "Hello, World! " );
- return 0;
- }
虽然是不到10行的代码,但它仍然五脏俱全。现在,就由我将它和上述的特点对号入座吧。也就是说,这个程序能体现出C程序设计的以下特点:
- C语言的程序以main函数作为程序入口点。
- printf是C中用来输出字符串的代码。
- 函数是C语言程序的基本单位,它通常由返回值、函数名、参数列表、函数体、return组成。
- 调用函数的时候要include相应的头文件。
- 是C语言中的转义字符,代表换行符。
接下来,我们来看一看Win32版的“Hello, World!”:
- #include <windows.h>
- int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
- {
- MessageBox( NULL, TEXT("Hello, World!"), TEXT("Hello"), 0 );
- return 0;
- }
这个程序告诉你了以下几件事:
- 所有Win32下的C程序都需要包含windows.h头文件。
- Win32下的程序是以WinMain作为程序入口点的,而不是main。
- Win32下最常用输出信息的方法是MessageBox。
- WINAPI是Win32 API函数的调用约定,也就是__stdcall。
- HINSTANCE、LPSTR都是Win32自定义的数据类型,分别表示应用程序实例句柄和以空字符结尾的ANSI字符串指针。
- TEXT宏用于在源代码一级保证ANSI/Unicode字符串的兼容。
如果你对以上的几个知识点仍然有些许迷茫,请参考Charles Petzold的《Programming Windows》(中译《Windows程序设计》)的第一章。这段代码就是几乎原封不动地搬过来的。不过,我在编写这段代码的时候,通常会这么写:
- #include <windows.h>
- #include <tchar.h>
- int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
- {
- MessageBox( NULL, _T("Hello, World!"), _T("Hello"), 0 );
- return 0;
- }
是的,有几个地方有些不一样,我对它们的解释是:
- tchar.h中包含了对C runtime library中ANSI/Unicode字符串的源代码级兼容。
- _tWinMain提供了对命令行参数lpCmdLine的ANSI/Unicode源码级兼容。
- _T宏亦包含在tchar.h之中,它的作用和TEXT宏一样,但它比TEXT宏更加短小,因此可以节省编码的时间。
现在我可以告诉你,随着我们的步步接近,接下来ATL版的“Hello, World!”程序就要出现在我们的眼前了。那么,就让我们来看看这个犹抱琵琶半遮面的家伙吧。(请注意,虽然这是一个ATL版本的程序,但是你仍然需要建立一个Win32 Application的工程,而不是用ATL/COM Wizard。)
- //////////////////////////////////////////////////////////////////////////
- // ATL的GUI程序设计配套源代码
- // 第一章 不能免俗的“Hello, World!”
- // 工程名称:HelloWorld
- // 作者:李马
- // http://www.titilima.cn
- //////////////////////////////////////////////////////////////////////////
- #include <atlbase.h>
- CComModule _Module;
- int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
- {
- _Module.Init( NULL, hInstance );
- MessageBox( NULL, _T("Hello, World!"), _T("Hello"), 0 );
- _Module.Term();
- return 0;
- }
也许有些陌生了,不过所幸它并无太多的变化——毕竟整个代码段就没有多长。好了,这一节的内容就到这里,希望李马的这种渐近的方法没让大家觉得一切来得太突然。大家可以喝口水先,然后做个深呼吸再,因为接下来我们就要开始接触真正的ATL程序了。
“不过如此”
说句题外话先。许是我太狂妄,又许是我太幼稚,总之我在上大学以来,越来越喜欢说“不过如此”这句话。譬如上了大学以后,没过俩月我就觉得大学“不过如此”;学会喝酒之后,就又会觉得喝酒“不过如此”;到了北京以后,又觉得北京“不过如此”;参观了某著名软件公司之后,又觉得它“不过如此”……书归正传话归正题,不知道你第一眼看过ATL版本的“Hello, World!”之后会不会同样有这样一种感觉?——自然,我希望是这样的。
那么,在了解ATL之前,就让我们先来目测一下这个“Hello, World!”吧。也许,你会从上面的代码猜到以下内容:
- atlbase.h大概其应该是ATL程序需要包含的头文件。
- CComModule,从类名称看应该是一个模块类。_Module是这个模块类的实例。
- WinMain没变。
- CComModule::Init应该是对模块进行初始化,这个方法应该是在程序初始化的时候调用。
- CComModule::Term应该是对模块进行结束处理,这个方法应该是在程序结束之前调用。
- WinMain的最后仍然是以return结尾。
好,是不是“不过如此”呢?没错!
大抵如此
到此为止,希望你的猜想能够让你对ATL的恐惧感(如果有的话)一扫而光。那么,现在李马来为你补充上几点:
atlbase.h在用ATL进行GUI程序设计的时候,就如同SDK中的windows.h一样重要。对于GUI程序设计的部分,这个文件中主要有这么几个值得关注的地方:
- Win32程序设计必备的头文件,诸如windows.h、tchar.h等。
- CComModule的定义。对于GUI程序设计,我们可以将它简单地看作对HINSTANCE的一个封装。
- 一些简单的工具类。(请原谅我不能在这里提供给你它们具体的名字,因为ATL 3.0和ATL 7.0是不一样的。VC 6.0附带的是ATL 3.0,它的atlbase.h中主要提供了一些COM的智能指针和字符串,如CComPtr、CComBSTR等;而VS2003中的ATL 7.0中则附带了一些更有趣的类,比如CRegKey、CHandle等。)
下面接着说CComModule。相信你可以从它的类名称中看出来,这个类主要用来管理COM的各种信息。如果你深入到ATL的源代码之中,你可能会为它的众多成员与方法感觉到迷惑。其实在进行GUI程序设计的时候,你只需要关心以下这些内容:
- HRESULT CComModule::Init( _ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid = NULL );
进行模块的初始化,第一个参数取NULL,第二个参数取应用程序的实例句柄,也就是WinMain中传入的hInstance。 - void CComModule::Term();
进行模块的卸载,在程序结束时调用。 - HINSTANCE CComModule::GetModuleInstance();
获取应用程序实例句柄CComModule::m_hInst。 - HINSTANCE CComModule::GetResourceInstance();
获取资源模块句柄CComModule::m_hInstResource,这个值在默认情况下是和CComModule::m_hInst一致的。如果你程序的所有资源位于一个DLL之中,那么你可以在初始化应用程序中将CComModule::m_hInstResource成员赋值为这个DLL的模块句柄。
接着说CComModule的实例_Module。可以说,这个全局变量贯穿于ATL整个框架的始终,无论你是使用它编写COM组件还是GUI程序。譬如,你可能不止一次地需要使用模块的实例句柄(LoadIcon、LoadCursor),那么你只需要这样调用:
- extern CComModule _Module;
- HICON hIcon = ::LoadIcon( _Module.GetResourceInstance(), MAKEINTRESOURCE( IDI_YOURICON ) );
好了,那么现在我们可以充分展示一下这个模块类的具体使用了。在此,我仅仅将我先前的“Hello, World!”作了一番扩展,如下:
- //////////////////////////////////////////////////////////////////////////
- // ATL的GUI程序设计配套源代码
- // 第一章 不能免俗的“Hello, World!”
- // 工程名称:HelloWorldEx
- // 作者:李马
- // http://www.titilima.cn
- //////////////////////////////////////////////////////////////////////////
- #include <atlbase.h>
- CComModule _Module;
- int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
- {
- _Module.Init( NULL, hInstance );
- _Module.m_hInstResource = LoadLibrary( _T("shell32.dll") );
- MSGBOXPARAMS mbp;
- ZeroMemory( &mbp, sizeof( mbp ) );
- mbp.cbSize = sizeof( mbp );
- mbp.dwLanguageId = GetSystemDefaultLangID();
- mbp.dwStyle = MB_USERICON;
- mbp.hInstance = _Module.GetResourceInstance();
- mbp.lpszCaption = _T("Hello");
- mbp.lpszIcon = MAKEINTRESOURCE( 44 );
- mbp.lpszText = _T("Hello, World!");
- MessageBoxIndirect( &mbp );
- FreeLibrary( _Module.m_hInstResource );
- _Module.m_hInstResource = NULL;
- _Module.Term();
- return 0;
- }
这个程序运行起来是这个样子:
如你所见,在这里我使用了来自应用程序之外的资源,也就是对CComModule::GetModuleInstance进行了特殊处理。WTL就是对CComModule这个类进行了继承处理而派生出了CAppModule类,使之成为了更适合应用程序使用的模块类。有兴趣的朋友可以参看WTL附带的atlapp.h文件,我这里就不多说了。
“貌合神离”
字典上对这个词的解释是:“表面上很亲密而实际上怀有二心”。在此,我将它用在ATL 3.0与7.0上,用来表示它们俩“用法兼容而实现迥异”的既有事实。不过,对于GUI程序设计而言,你并不需要深入了解这方面的内容。因此我这里列举的,也只是与GUI有关的部分。
- ATL 3.0之中,CComModule直接继承自_ATL_MODULE;而ATL 7.0之中,CComModule则经历了一串的继承链。
- 相比之下,ATL 7.0中的CComModule更有COM的味道,譬如它的ModuleInstance、ResourceInstance都可以作为COM组件的property,使用get、put来处理。
当然,ATL毕竟是一个为开发COM组件而构建的Framework,所以ATL 7.0中的atlbase.h之中还包含了更多有关COM开发的工具类。这些内容与本书无关,而且李马也自认现在尚无能力来解说这些内容,所以一并从略了就。
附件:atlgui01.zip
ATL的GUI程序设计(1)的更多相关文章
- ATL的GUI程序设计(4)
第四章 对话框和控件 对于Win32 GUI的程序设计来说,其实大部分的情况下我们都不需要自己进行窗口类的设计,而是可以使用Win32中与用户交互的标准方式--对话框(Dialog Box).我们可以 ...
- ATL的GUI程序设计(3)
第三章 ATL的窗口类 CWindowImpl.CWindow.CWinTraits,ATL窗口类的奥秘尽在此三者之中.在本章里,李马将为你详细解说它们的使用方法.另外,本章的内容也可以算是本书的核心 ...
- ATL的GUI程序设计(2)
from:http://blog.titilima.com/atlgui-2.html 第二章 一个最简单窗口程序的转型 我知道,可能会有很多朋友对上一章的"Hello, World!&qu ...
- ATL的GUI程序设计(前言)
前言 也许,你是一个顽固的SDK簇拥者: 也许,你对MFC抱着无比排斥的态度,甚至像我一样对它几乎一无所知: 也许,你符合上面两条,而且正在寻求着一种出路: 也许,你找到了一条出路--WTL,但是仍然 ...
- Java GUI程序设计
在实际应用中,我们见到的许多应用界面都属于GUI图形型用户界面.如:我们点击QQ图标,就会弹出一个QQ登陆界面的对话框.这个QQ图标就可以被称作图形化的用户界面. 其实,用户界面的类型分为两类:Com ...
- GUI程序设计2
8. 按钮(JButton)使用示例 例14. 按钮使用示例. package GUI; import java.awt.BorderLayout; import java.awt.Container ...
- GUI程序设计
1. 对话框(JDialog)使用示例 例1. JDialog简单使用示例. import javax.swing.JLabel; public class demoJDialog { JFrame ...
- Matlab GUI程序设计入门——信号发生器+时域分析
背景:学习matlab gui编程入门,完成一个基于GUIDE的图形化界面程序,结合信号生成及分析等. 操作步骤: 1.新建程序 新建一个GUIDE程序 这里选择第一个选项,即创建一个空白的GUIDE ...
- MATLAB GUI程序设计中ListBox控件在运行期间消失的原因及解决方法
在运行期间,ListBox控件突然消失,同时给出如下错误提示: Warning: single-selection listbox control requires that Value be an ...
随机推荐
- elasticsearch定时删除索引第二版
该版本对于上一个版本做了升级.兼容性更好了. #!/bin/bash ####################################################### # $Name: ...
- GraphicsLab Project之Diffuse Irradiance Environment Map
作者:i_dovelemon 日期:2020-01-04 主题:Rendering Equation,Irradiance Environment Map,Spherical Harmonic 引言 ...
- nodejs-websocket+ssl证书
1.nodejs配置微信小程序本地服务器(二):利用ws模块创建基于ssl证书的WebSocket服务器:https://segmentfault.com/a/1190000013956534 2.n ...
- Python基础(二):操作基本数据类型
Python是一门解释型语言,它的优势在于代码简洁,易于理解,可以通过大量已封装好的内建方法和第三方模块方法完成日常所需的操作. 字符串 索引 起始下标为0 (从前往后数),末尾下标为-1(从后往前数 ...
- Snipaste - 可以提高你工作效率的截图软件
使用Snipaste提高您的工作效率 Snipaste是一个简单但功能强大的剪切工具,还允许您将屏幕截图固定在屏幕上.下载并启动应用程序,按F1开始剪切,然后按F3将其粘贴为浮动窗口.而已! 您还可以 ...
- linux下安装OpenCV-2.4
OpenCV(Open Source Computer Vision Library),是一个跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法. OpenCV由一系列 C 函数和少量 ...
- 浏览器从输入url 到页面展示完成响应过程
用户从输入 url 到浏览器响应,呈现给用户的具体过程 1.用户在输入栏输入地址 (1) 如果有 beforeunload 事件会先执行判断继续还是跳出操作 (2) 浏览器进程识别是 地址还是关键字检 ...
- vim添加多行注释的几种方式
最近需要在阿里云上部署项目,不可避免地会遇到vim这个工具,查了一些资料,总结了一下使用vim多行注释的方法 块操作 多行注释: 首先按esc进入命令行模式下,按下Ctrl + v,进入列(也叫区块) ...
- 【LC_Lesson5】---求最长的公共前缀
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...
- 《企业IT架构转型之道:阿里巴巴中台战略思想与架构实战》-总结
一.什么是业务中台 概念来自于阿里,介于前台和后台(此后台指的是云计算.数据库.消息队列.缓存等基础服务) 采用共享式架构设计解决以往烟囱式架构设计的资源浪费.重复造轮.试错成本高的问题 阿里的中 ...