Programming Windows 第五版读书笔记 第一章 开始

Programming Windows 5th Edition - Chapter 1 Getting Started

1. 第一个windows程序,如下:

Code: Select all
/*------------------------------------------------------------
    HelloMsg.cpp -- Display "Hello, Windows!" in
                   a message box
   Eric Zhang 2007
--------------------------------------------------------------*/

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
               PSTR szCmdLine, int iCmdShow)
{
   MessageBox(NULL, TEXT("Hello, Windows!"), TEXT("HelloMsg"), 0);

   return 0;
}


在这个程序中,就有很多需要说明的东西。首先,include windows.h,windows.h是一个集大成的头文件,他里面include了很多必需的东西,最重要和最基本的有:

WINDEF.H 基本类型定义。
WINNT.H 支持Unicode的型态定义。
WINBASE.H Kernel函数。
WINUSER.H 使用者接口函数。
WINGDI.H 图形设备接口函数。

windows 自从发展开始以来,核心的东西一直没有变过,主要有三个:kernel,user,gdi,kernel(在windows很多地方这个kernel也叫 base,所以就有winbase.h这样的头文件)是windows的核心,负责内存管理,文件,进程等;user是使用者接口,比如键盘等;gdi是 图形设备接口。

再往下看代码,看到的是WinMain函数,这就相当于一个C程序的main函数。WinMain的原型定义在WINBASE.H中,如下:

Code: Select all
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nShowCmd);


这 里我们做了一些改动,首先是第三个参数,我们把类型改成了PSTR,PSTR其实就是char *,第二章中讲Unicode的时候会很详细清楚的讲windows中有关字符,字符串的数据类型系列,这里我们讲LPSTR改成了PSTR,其实效果一 样,带LP的指针表示long型指针,这是16位windows的遗留产物,在16位下,带L的指针表示占用4个字节,现在都是32位的windows 了,所以这个L加不加无所谓了,后面我们会看到很多16位windows下的数据类型和函数,这些都是遗留问题,事实上,windows从16位转成32 位的时候,API,数据类型膨胀的非常厉害,因为要兼容原来的16位程序,同时针对32位,又新加了大量的数据类型和函数。

其他就没什么变化了,只是我们将变量的名字改了一下,比如将lpCmdLine改成了szCmdLine,这是匈牙利变量的命名法,以前学过的,sz表示string terminaed with zero。

然后看到的就是WinMain申明中的WINAPI,这是给编译器看的一个编译参数,定义在WINDEF.h:

#define WINAPI __stdcall

__stdcall, __cdel, __fastcall这些都是指示编译器的指令,叫做呼叫约定(call convention),这些指令告诉编译器在编译function的时候,将function的名字如何命名(在真正二进制程序中,function的 name不是我们现在写的,需要做一些变化),函数的参数如何进栈和出栈(是将参数从右往左压入堆栈还是反之)...... 。有关这些东西我会在后面的文章中专门介绍,事实上,这些东西很重要,一旦写错会导致程序无法链接或执行期出现莫明其妙的错误,因为很多第三方的库,他的 Call Convention可能和我们的不一样,为了能调用他们,必须将我们的代码改成和他一致的,否则参数入栈出栈不同,会导致取出的参数不对;也有可能我们 将来的代码里面含有C++的代码,那么C++代码针对函数的呼叫约定又有不同;再有可能不同的编译器也不一样,情况很多,所以对呼叫约定还是需要透彻了解 的。

然后我们看到WinMain函数中的参数,第一个参数是我们这个程序实例(instance)的句柄,其实就是一个数字,用来标识我 们这个程序实例,第二个参数也是历史产物,在早期的windows中,如果我们将一个程序执行多次,那么,就会出现多个该程序的instance,此时, 我们的程序就可以通过check这个hPrevInstance来判定我们的程序是否已经被launch了,从而可以选择少做一些工作(比如一些只需要做 一次的工作)。不过这个参数目前已经被废弃了,所以目前的32位的windows,这个参数永远是NULL。

第三个参数是执行此程序时候的命令行,从中我们可以取到命令行选项和参数设定。第四个参数指定程序最初显示的方式,是最大化窗口,还是最小化窗口等等。

再 往下我们就看到MessageBox函数了,第一个参数是窗口句柄,将在第三章中介绍。第二个参数MessageBox对话框主体中显示的文字;第三个参 数是对话框标题栏上的文字,这两个参数我们都用TEXT宏将他们封装了起来,在第二章Unicode中,我们会详细介绍为什么要这么做和TEXT宏具体的 内容;第四个参数表示MessageBox的类型,用来指定MessageBox对话框中出现的按钮,定义在WINUSER.H中,通常有这么一些:

Code: Select all
#define MB_OK                       0x00000000L
#define MB_OKCANCEL                 0x00000001L
#define MB_ABORTRETRYIGNORE         0x00000002L
#define MB_YESNOCANCEL              0x00000003L
#define MB_YESNO                    0x00000004L
#define MB_RETRYCANCEL              0x00000005L


如果MessageBox中显示了多个按钮的话,我们可以将上面的常数和下面的常数做|运算,从而指定一个Default Button:

Code: Select all
#define MB_DEFBUTTON1               0x00000000L
#define MB_DEFBUTTON2               0x00000100L
#define MB_DEFBUTTON3               0x00000200L
#define MB_DEFBUTTON4               0x00000300L


我们还可以在这个参数中指定MessageBox对话框中出现的图标:

Code: Select all
#define MB_ICONHAND                 0x00000010L
#define MB_ICONQUESTION             0x00000020L
#define MB_ICONEXCLAMATION          0x00000030L
#define MB_ICONASTERISK             0x00000040L

#define MB_ICONWARNING              MB_ICONEXCLAMATION
#define MB_ICONERROR                MB_ICONHAND
#define MB_ICONINFORMATION          MB_ICONASTERISK
#define MB_ICONSTOP                 MB_ICONHAND


将这些常量互相 | 起来,就可以达到组合使用他们的目的。

至于MessageBox函数的返回值,在本程序中,MessageBox返回数值1,但更严格地说它返回IDOK,IDOK在 WINUSER.H中定义,等于1。根据在消息框中显示的其它按钮,MessageBox函数还可返回IDYES、IDNO、IDCANCEL、 IDABORT、 IDRETRY或IDIGNORE。

程序解释完了,最后在编译的时候,在Project Properties中,定义两个预编译条件变量(Preprocessor):UNICODE, _UNICODE,这两个东西打开了Unicode的支持,至于是如何实现的,第二章Unicode会详细讲述。 :idea: :idea: 8) :idea:
原文地址:https://www.cnblogs.com/super119/p/2011325.html