说明:只供学习交流,转载请注明出处
windows编程基础
(1):API与SDK
我们在编写标准C程序的时候,经常会调用各种库函数来辅助完成某些功能:初学者使用得最多的库函数就是printf了,这些库函数是由你所使用的编译器厂商所提供的。在Windows平台下,也有类似的函数可供调用。不同的是,这些函数是由Windows操作系统本身提供的。Windows操作系统提供了各种各样的函数,以方便我们开发Windows应用程序。这些函数是Windows操作系统提供给应用程序编程的接口(ApplicationProgrammingInterface),简称为API函数。我们在编写Windows程序时所说的API函数,就是指系统提供的函数,所有主要的Windows函数都在Windows.h头文件中进行了说明。
我们经常听到Win32SDK开发、QtSDK开发等等说法。那么什么是SDK呢?SDK的全称是Software Development Kit,中文译为软件开发包。比如我们现在要开发与短信猫相关的通信程序,在购买短信猫的同时,厂商会提供短信猫的SDK开发包,以方便我们对短信猫的编程操作。这个开发包通常都会包括短信猫的API函数库、帮助文档、使用手册、辅助工具等资源。也就是说,SDK实际上就是开发所需资源的一个集合。
需要明确的是,API和SDK是一种广泛使用的专业术语,并没有专指某一种特定的API和SDK。Windows操作系统提供了1000多种API函数,作为开发人员,要全部记住这些函数调用的语法几乎是不可能的。那么我们如何才能更好的去使用和掌握这些函数呢?答案是熟练使用MSDN。
(2):窗口
窗口是Windows应用程序中一个非常重要的元素,一个Windows应用程序至少要有一个窗口,称为主窗口。窗口是指屏幕上的一块矩形区域,是Windows应用程序与用户进行
交互的接口。利用窗口,可以接收用户的输入以及显示输出。
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,有的还有滚动条。
窗口可以分为客户区和非客户区,客户区是窗口的一部分,应用程序通常在客户区中显示文字或者绘制图形。标题栏、菜单栏、系统菜单、最小化框和最大化框、可调边框统称
为窗口的非客户区,它们由Windows系统来管理,而应用程序则主要管理客户区的外观及操作。
窗口可以有一个父窗口,有父窗口的窗口称为子窗口。
对话框和消息框也是一种窗口。在对话框上通常还包含许多子窗口,这些子窗口的形式有按钮、单选按钮、复选框、组框、文本编辑框等。此外,我们在启动Windows系统后,看到的桌面也是一个窗口,称为桌面窗口,是位于最上层的窗口,由Windows系统创建和管理。
(3):句柄
Windows具有很强的面向对象特性。Windows对象有很多,譬如桌面、读取所使用的程序等等。那么,如何区分这些东西呢?答案是使用句柄。句柄是引用不同Windows对象的方式。可以使用Windows的句柄、文件的句柄、分配内存的
句柄、图像的句柄等等。系统在创建这些资源时会为它们分配内存,并返回标识这些资源的标识号,这就是句柄。实际上我们也可以将这些句柄看作指针。在使用句柄之前,必须先创建它们,当不再使用时,应当及时销毁它们。如果不销毁它们,最终将导致资源泄露(resourceleak),资源泄露有可能导致系统崩溃,所以,务必确保在适当的时候销毁不再使用的句柄。在windows应用程序中,窗口是通过窗口句柄(HWND)来标识的。我们要对某个窗口进行操作,首先就要得到这个窗口的句柄,这就是窗口和句柄的联系。
(4):消息与消息队列
Windows程序设计是一种基于消息的事件驱动方式的设计模式,完全不同于传统的DOS方式的程序设计方法。在Windows中,编程的骨架都是响应和发送消息。例如,当用户在窗口中画图的时候,按下鼠标左键,此时操作系统会感知这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并响应。在这个处理过程中,操作系统也会给应用程序“发送消息”。所谓“发送消息”,实际上是操作系统调用程序中一个专门处理消息的函数,称为“窗口过程”。
在windows程序中,消息是由MSG结构体来表示的。MSG结构体的定义如下:
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG;
该结构体中各成员变量的含义如下:
hwnd表示消息所属的窗口。我们开发的程序都是窗口应用程序,消息一般都是与某个窗口相关联的。在Windows程序中,用HWND类型的变量来标识窗口。
message变量指定了消息的标识符。在Windows中,消息是由一个数值来表示的,不同的消息对应不同的数值。但是由于数值不便于记忆,所以Windows将消息对应的数值定义
为WM_XXX宏(WM是Window Message的缩写)的形式,XXX对应某种消息的英文拼写的大写形式。例如,鼠标左键按下的消息是WM_LBUTTONDOWN,键盘按下消息是WM_KEYDOWN,字符消息是WM_CHAR等等。在程序中,我们通常都是用WM_XXX宏的形式来使用消息的。此外,我们可以定义自己的消息,并给窗口发送这些消息,您完全不用担心如何使这些消息与代码联系起来,因为这是应用程序框架的事情。但是另一方面,这也在一定程度上固定了程序设计上的一些结构。
wParam和lParam用于指定消息的其他附加信息。比如,当我们收到一个字符消息的时候,message成员变量的值就是WM_CHAR,但用户输入的是那些字符,就由wParam和
lParam来说明。wParam、lParam表示的信息随消息的不同而有变化。
time和pt分别表示消息投递到消息队列的时间和鼠标的当前位置。
消息队列:
每一个Windows应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。Windows将产生的消息依次放入消息队列中,而
应用程序则通过消息循环不断从队列中取出消息,进行响应。这种消息机制,就是Windows程序运行的基本机制。
(5):窗口句柄和消息
现在我们将消息与句柄联系起来。假如有一个窗口,且拥有该窗口的一个句柄(称作一个HWND),我们命名该句柄为your_HWND。假设因为其他的窗口刚刚从该窗口上移走,那
么操作系统希望重绘这个窗口。Windows将传递如下所示消息:
PostMessage(your_HWND,WM_PAINT,0,0);
这个函数通过句柄your_HWND给窗口发送了一条绘制消息。最后两个参数用作消息的额外信息,暂时可以不必深究它们的具体细节。
现在,应用程序中有一个函数用一个庞大的case语句来处理所有信息。例如:
Void HandleTheMessage()
{
switch(Message)
{
Case WM_PAINT:
DrawWindow();
break;
case WM_KEYDOWN:
break;
......
}
}
以上就是Windows中的消息和句柄的大致工作过程。了解这些后原理后,下面就可以学习一下有关主程序以及窗口创建的知识。
(6):主程序-WinMain函数
在windows操作系统下,用C或者C++来编写MS-DOS应用程序时,最起码要有一个main函数。当用户运行该应用程序时,操作系统会自动调用main。但当编写Windows应用程序时,就一定要有WinMain函数,因为当用户运行该程序时,操作系统首先调用程序中的WinMain函数。该函数一般用来完成某些特殊的任务,其中最重要的任务就是要创建该应用程序的“主窗口”。许多Windows集成开发环境,包括使用Microsoft MFC类库的VisualC++,都通过隐藏WinMain函数及构造消息-控制机制来简化编程。虽然使用MFC编程不再需要过多关注WinMain函数,但是弄清楚操作系统与程序之间的这种关系是最基本的要求。
(7):创建窗口
Windows窗口在创建之前,其属性必须设定好,所谓属性包括类的名字、图标、光标及窗口过程处理函数等属性。为了设定这些属性,Windows要求注册窗口类,一经注册,就可
以创建更多的同类窗口,无需再次注册。窗口类仅仅定义了窗口的特征,所有创建窗口的对象都用窗口类来创建窗口。程序必须在产生窗口前先利用API函数RegisterClass设定属
性,这一个过程就是注册窗口类。
窗口注册完之后,就可以创建相应的窗口。注册窗口时,必须给函数传递一个指针,这个指针指向一个包含窗口属性的结构。该结构有2个版本,WNDCLASS和WNDCLASSEX,前者本来用于Windows早期版本,但现在仍可沿用;后者用于32位Windows,该结构包含1个cbSize成员和1个指向小图标的句柄,其它两者相同。
WNDCLASSEX定义如下:
typedef struct_WNDCLASSEX
{
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
}WNDCLASSEX;
ATOM RegisterClassEx
(
CONST WNDCLASSEX *lpwcx
);
调用过程如下:
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW| CS_VREDRAW; //窗口风格
wcex.lpfnWndproc = (WNDPROC)WndProc; //窗口过程,处理消息响应
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance; //程序实例
wcex.hIcon = 0; //图标
wcex.hCursor = LoadCursor(NULL,IDC_ARROW);//光标
wcex.hbrBackground =(HBRUSH)(COLOR_WINDOW+1); //背景色
wcex.lpszMenuName = NULL; //菜单资源
wcex.lpszClassName =“YourClassName”; //窗口类名
wcex.hIconSm = NULL; //小图标
RegisterClassEx(&wcex); //注册窗口类
在此之后,就可以使用函数CreateWindow创建窗口了。不过,这个函数还有11个参数,第1个参数就是:
wcex.lpszClassName = “YourClassName”;
只有用注册过的窗口类名才可以创建窗体。不过,用户一般情况下不用担心这些事情,因为,MFC已经做了其中的大部分事情。如:
⑴在3个应用程序框架里,主要的窗口都已经被创建了,可以直接使用C++对象;
⑵在资源编辑器里,控件窗口也被设计好了,您可以用ClassWizard为控件窗口连接C++对象。
⑶如果是动态创建控件,您只需要用Create等函数来创建窗口,这一过程中,MFC提供了方法来判断窗口类是否注册。若未注册,则先注册,再创建窗口(您完全可以不了解这
些内容)。
(8):环境变量
和类Unix系统一样,Windows系统也有环境变量,分为系统环境变量和用户环境变量两种。
一般来说,系统环境变量影响所有的用户和程序,但更改系统环境变量后,对已经启动的服务程序并不起作用,因为此服务程序并不知道环境变量已发生改变,需要重新启动操
作系统。
在命令提示符下,运行set可以看到当前所有的环境变量。同时,set也可以更改环境变量的值,但仅对当前的命令提示符下启动的程序起作用。
Windows也提供GUI工具来修改环境变量,做法是单击【开始】菜单,或者在【我的电脑】图标上单击鼠标右键,在弹出的菜单中选择【属性】命令,弹出【系统属性】对话框。
切换到【高级】选项页,单击下方的【环境变量】按钮,弹出【环境变量】对话框,可以查看或修改增加环境变量。
环境变量PATH的功能和Unix下的PATH加上LD_LIBRARY_PATH是一样的,同时影响可执行文件和动态链接库。执行命令时,Windows会根据是否含路径,是否是cmd内部命令,当前路径下是否有可执行扩展名的文件,然后再在PATH环境变量(先系统的再到用户的)路径里查找有无可执行扩展名的文件。如果匹配,则执行。对于动态链接库,则是查找是否包含路径,系统的system32(32位OS情况下)路径,然后是PATH环境变量(先系统的再到用户的)路径里查找动态链接库的文件。
其他需要传递的信息对C/C++程序员影响比较小,因为传递信息的方式已经被存取注册表这种方式取代。
(9):注册表
注册表可以看作是一个系统的数据库,大量系统及用户的数据在此存放,尤其是配置数据及运行状态数据。这些数据有字符、数字及二进制数组等类型。通过以Reg开头的一系列函数,可以存取注册表数据。
需要注意的是,注册表中的数据是透明的,其他程序及regedit、regedt32等系统工具,也可以存取这些数据,这些数据并不是被某个用户所独占的。
(10)使用MSDN
SDN是MicrosoftSoftwareDeveloperNetwork的简称,是微软针对开发者的帮助网络,可以在http://msdn.microsoft.com看到有关的详细介绍。MSDN可以单独购买订阅,也可以在购买VisualStudio套件时得到。
MSDN的安装比较简单,只需要按照向导提示安装即可完成。安装完毕后,可以在Windows的开始菜单里找到【MicrosoftDeveloperNetwork】→【MSDN
LibraryforVisualStudio2005】这一项(因为笔者安装的是这个版本,你的可能会有所不同),通过这个菜单就可以打开MSDN了,也可以在VisualStudio中按下F1键打开MSDN。