现在我们要学的是Windows32的编程,与DOS不同的是,实现的目标是一个具有你所需要的功能的“窗口”。这个“窗口”时时刻刻都在与操作系统之间,通过一个称之为“消息队列”的东西传送数据。因此处理好各种消息便成了Win32编程的核心。

SDK编程是相对于MFC来说的,也就是用C和C++来调用WindowsAPI,这API是操作系统的东西,其他语言(如VB)也可以调用。因此,以前也有人将这种编程称为API编程。当然,这儿对C或C++进行了一些扩展,所谓扩展,就是增加了许多宏定义、模板,让你看了之后大吃一惊,真不知“何方神圣”倒底有何神通。

如果你C或C++还不会的话,请先学习C语言和C++语言,否则,你再刻苦也等于看电影,也许你看懂了但你肯定不会演电影。学习窗口编程之前,你要知道几个概念。
[list]
[*]实例(instance): 这是C++的内容,“类”相当于结构体的数据类型,用“类”这种类型去定义一个变量(如果是指针,则假定已经得到了空间),这个变量就是那个“类”的“实例”。它和C语言中的变量是一回事,不过只有用“类”定义的变量才称为“实例”。
[*]句柄(handle):这是C语言的内容,和文件句柄一样,它实际上是一个整数,用来标识是哪一个实例,也就是实例的标识符。通过句柄可以操作这个实例。
[*]回调(CALLBACK):这其实是C语言中的函数指针,函数指针一般在大项目搭框架时常常使用。也就是你设计好要得到什么,把接口定义好,具体怎么实现完全交给别人,别人只要把函数名传给你就OK。这个函数名就是地址,不过取这种地址的指针在定义上与普通指针有些不同。小雅在《C语言教程》的“函数指针”中有详细解说和例子。
[/list]

[b]一、WinMain()函数[/b]
WinMain()函数是窗口程序的入口函数,在这个函数中你就可以调用各种API函数来完成你的目标。①一般是先调用RegisterClassEx()函数用当前窗口句柄去向操作系统申请(或称登录)将要创建一个什么样的窗口,申请成功后,②再调用CreateWindowEx()函数创建一个窗口对象,这仅仅是一个外观,③还要调用ShowWindow()函数设置初期表示,即最大或最小或普通等。④最后还要调用UpdateWindow()函数向窗口传送WM_PAINT消息来画出窗口里面的内容。

窗口创建完后,这是一个“静止”的窗口,⑤因此还要在WinMain()函数的最后添加消息循环,最后才return。WinMain()函数完了之后,⑥还要再编写一个“窗口消息处理”函数。上面讲了一大堆API函数的调用也许有点昏头,但那些全是固定的,基本上不要编程。在你理解之后,只要修改少量参数便可,真正要编程的是这个“窗口消息处理”函数。

下面我们从简单入手,先不创建窗口,而只是调用一下通用对话框。主要是了解WinMain()函数。

#include <windows.h>

int APIENTRY WinMain(HINSTANCE hInstance, //当前窗口实例句柄
HINSTANCE hPrevInstance, //前一个实例句柄,Win32下为NULL
LPSTR lpCmdLine, //命令行参数字符
int nCmdShow //窗口的显示方式
)
{
MessageBox(NULL,"丸博欢迎您!", "http://www.quanxue.cn/", MB_OK); //通用对话框

return 0; //函数返回值
}


初学者不明白的地方还很多,但大都可以就这样先用,以后慢慢理解,小雅当初问了很多“高手”,答案却让我更不明白,只好“慢慢理解”。这样拖了几年,现在小雅就一一解说,如有不对,上论坛指摘2句。



[list]


[*]APIENTRY不是返回类型,这是为编译器准备的一个宏定义,告诉编译器将当前函数编译成64位机也能用的长调用。为什么要这样一个开关呢?VisualC++要兼容C语言、C++语言、16位的Windows版本等,同时还要为将来扩展为64位机作准备。虽然它和CALLBACK是同一宏定义,但编译时还是略有区别。


[*]WinMain()函数在.Net上变成了_tWinMain(),这也是为了兼容而定义的宏定义。


[*]HINSTANCE是实例句柄,象这样用H或h开头的东西(如HDC)都是句柄,其值是整数。如果你硬写成int型,编译器会分不清,因此出编译错误。


[*]LPSTR是UNICODE型的字符串指针。


[*]hInstance是当前窗口的实例句柄,hPrevInstance是16位机上用于识别当前窗口是否重复打开,当hPrevInstance不为NULL时为前一个窗口实例句柄,在32位机上hPrevInstance恒为NULL。


[*]lpCmdLine是命令行传来的参数。


[*]nCmdShow是初始显示方式,最大/最小/正常/隐藏等等。


[*]MessageBox()函数是Win32的API函数,调用通用对话框。这不是我们要学习的窗口编程。


[/list]



[b]二、基本Win32程序[/b]



下面是生成一个窗口的最基本的程序,也是后面要介绍的内容,大家看了之后能找到上面讲的①-⑥,那就OK了。


#include <windows.h>

TCHAR szTitle[32]="丸博"; //窗口的标题
TCHAR szWindowClass[32]="Simple"; //窗口的名称

ATOM MyRegisterClass(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;

MyRegisterClass(hInstance); //注册窗口类

if (!InitInstance (hInstance, nCmdShow)) //初始化窗口
{
return FALSE;
}

while (GetMessage(&msg, NULL, 0, 0)) //消息循环
{
TranslateMessage(&msg); //消息解释
DispatchMessage(&msg); //消息发送
}

//注意:不能用“return 0;”,因为有非正常退出的可能性
return (int)msg.wParam;
}

//注册窗口类
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wc; //定义一个窗口类,其实是一个结构体

wc.cbSize = sizeof(WNDCLASSEX); //结构体的字节长度
wc.style = CS_HREDRAW | CS_VREDRAW; //窗口式样
wc.lpfnWndProc = (WNDPROC)WndProc; //窗口处理函数
wc.cbClsExtra = 0; //分配给窗口类结构之后的额外字节数,一般为0
wc.cbWndExtra = 0; //分配给窗口实例之后的额外字节数,一般为0
wc.hInstance = hInstance; //实例句柄
wc.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW); //光标
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); //背景
wc.lpszMenuName = NULL; //菜单
wc.lpszClassName = szWindowClass; //窗口名
wc.hIconSm = LoadIcon(wc.hInstance, (LPCTSTR)IDI_APPLICATION);

return RegisterClassEx(&wc);
}

//初始化窗口
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

//创建窗口
hWnd = CreateWindow( szWindowClass, //窗口名
szTitle, //窗口标题
WS_OVERLAPPEDWINDOW, //窗口式样
CW_USEDEFAULT, //窗口左上角的x坐标/CW_USEDEFAULT
CW_USEDEFAULT, //窗口左上角的y坐标/CW_USEDEFAULT
CW_USEDEFAULT, //窗口的宽度/CW_USEDEFAULT
CW_USEDEFAULT, //窗口的高度/CW_USEDEFAULT
NULL, //父窗口句柄
NULL, //菜单句柄
hInstance, //实例句柄
NULL); //创建参数
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow); //显示窗口
UpdateWindow(hWnd); //立即显示

return TRUE;
}

//窗口消息处理
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY: //关闭窗口
PostQuitMessage(0); //发送关闭消息
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam); //缺省窗口处理函数
}
return 0;
}