很多人都认为windows 程序设计很难,会有一种闻声丧胆的感觉,我个人认为那只不过是一种错觉,那是因为你没有深入的去了解windows 程序设计,只要你坚持了,深入了解了,你将发现windows 程序设计是很有意思的,也不是许多人所说的那般神秘,你会慢慢喜欢上她。
要创建一个windows 应用程序并不是那么困难,一般步骤如下:
一、创建一个windows 窗口类,并初始化要创建窗口的一些信息
设置要创建窗口的属性,定义在WNDCLASSEX结构中
typedef struct_WNDCLASSEX
{
UNIT cbSize; //WNDCLASSEX 结构的大小
UNIT style; //从这个窗口派生的窗口具有的风格
WNDPROC lpfnWndProc; //即 window procedure,窗口消息处理函数指针
int cbClsExtra; //指定紧跟在窗口类结构后的附加字节数
int cbWndExtra; //指定紧跟在窗口事例后的附加字节数
HANDLE hInstance; //本模块的实例句柄
HICON hIcon; //窗口左上角的句柄
HCURSOR hCursor; //光标的句柄
HBRUSH hbrBackground; //背景画刷的句柄
LPCTSTR lpszMenuName; //菜单名
LPCTSTR lpszClassName; //该窗口类的名称
HICON hIconSm; //小图标句柄
}WNDCLASSEX;
这一步就是根据所要创建的窗口,设置WNDCLASSEX 结构
事例如下:
WNDCLASSEX MyWindow;
MyWindow.cbSize = sizeof(MyWindow); //结构的大小
MyWindow.style = CS_HREDRAW|CS_VREDRAW; //指定如果窗口大小改变就重画
MyWindow.lpfnWndProc = MainWndProc; //窗口函数指针
MyWindow.cbClsExtra = 0; //没有额外的类内存
MyWindow.cbWndExtra = 0; //没有额外的窗口内存
MyWindow.hInstance = hInstance; //实例句柄
MyWindow.hIcon = ::LoadIcon(NULL,IDI_APPLICATION); //使用预定义的图标
MyWindow.hCursor = ::LoadCursor(NULL,IDC_ARROW); //使用预定义的光标
MyWindow.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); //使用白色背景画刷
MyWindow.lpszMenuName = NULL; //不指定菜单
MyWindow.lpszClassName = szClassName; //窗口类的名称
MyWindow.hIconSm = NULL; //没有类的小图标
其中有一个窗口函数指针,在程序前应该先声明该窗口的消息处理函数
LRESULT CALLBACK MainWndProc(HWND,UINT,WPARAM,LPARAM);
当然在程序中,还要实现消息处理函数,使其能够处理相应的消息
二、设置好要创建的窗口的属性后,就可以注册要创建的窗口了
注册窗口类用API 函数RegisterClassEx, 如果函数成功,返回值是唯一识别被注册类的一个原子;如果函数失败,返回值为0。
函数原型:ATON RegisterClassEX(CONST WNDCLASSEX * Ipwcx);
注册上面设置的窗口如下:
::RegisterClassEx(&MyWindow);
三、注册窗口后,接下来就是创建注册的窗口
创建窗口用API 函数CreateWindowEx,创建窗口成功的话,该函数返回创建窗口的句柄,否则返回false
函数原型:
HWND CreateWindowEx(
DWORD dwExStle, //指定窗口的扩展风格
LPCTSTR IpClassName, //指向一个空结束的字符串或整型数atom
LPCTSTR lpWindowName, //指向一个指定窗口名的空结束的字符串指针
DWORD dwStyle, //指定创建窗口的风格
int x, //初始化X坐标
int y, //初始化Y坐标
int nWidth, //初始化窗口宽度
int nHeight, //初始化窗口高度
HWND hWndParent, //指定父窗口句柄,没有的话,为NULL
HMENU hMenu, //菜单句柄,或依据窗口风格指明一个子窗口标识
HANDLE hlnstance, //与窗口相关联的模块事例的句柄
LPVOID lpParam //指向一个值的指针,该值传递给窗口 WM_CREATE消息
);
创建上面注册的窗口类如下:
HWND m_hWnd = ::CreateWindowEx(
0,
szClassName,
"My first Window",
WS_OVERLAPPEDWINDOW,
200,
100,
600,
450,
NULL,
NULL,
hInstance,
NULL);
四、创建窗口成功的话,创建的窗口还没有显示出来,这些需要调用ShowWindow函数把窗口显示出来并更新窗口
函数原型:BOOL ShowWindow(HWND hWnd,int nCmdShow);
函数原型:BOOL UpdateWindow(HWND hWnd);
显示上面创建的窗口:
::ShowWindow(m_hWnd,nCmdShow);
接下来则是更新窗口
::UpdateWindow(m_hWnd);
至此,一个简单的window 应用程序窗口已经呈现在你的面前了
五、接下来就是让窗口可对不同的消息才去不同的操作
达到这个目的,即让窗口进入无限的消息循环:
MSG msg;
while(::GetMessage(&msg,nCmdShow))
{
//转化键盘消息
::TranslateMessage(&msg);
//将消息发送相应的窗口函数
::DispatchMessage(&msg);
}
Windows 为每个线程维护了一个消息队列,每当有一个输入发生,Windows 就把用户的输入翻译成消息放在消息队列中。利用GetMessage函数可以从调用线程的消息队列中取出一个消息来填充MSG结构。
::GetMessae(&msg,NULL,0,0);
如果消息队列中没有消息(既没有用户输入),这个函数会一直等待下去,直到有消息进入消息队列为止。如果从消息队列中取得消息不是WM_QUIT,则返回 非零值,一个WM_QUIT消息会促使GetMessage函数返回0,从而结束消息循环。
msg是MSG结构类型的一个变量,这个结构定义了消息的所有属性。
typedef struct tagMSG
{
HWND hwnd; //消息要发送的窗口句柄
UINT message; //消息标示符,一WM_开头的预定义值(意为window message)
WPARAM wParam; //消息的参数之一
LPARAM lParam; //消息的参数之二
DWORD time; //消息放入消息队列的时间
POINT pt; //这是一个POINT结构,表示消息放入消息队列是的鼠标位置
}MSG,*PMSG;
windows 应用程序简单窗口的创建实现代码
#include "stdafx.h"
// 窗口函数的消息处理函数原形声明
LRESULT CALLBACK MainWProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
char szClassName[] = "MainWClass";
WNDCLASSEX wndclass;
// 用描述主窗口的参数填充WNDCLASSEX结构
wndclass.cbSize = sizeof(wndclass); // 结构的大小
wndclass.style = CS_HREDRAW|CS_VREDRAW; // 指定如果大小改变就重画
wndclass.lpfnWndProc = MainWProc; // 窗口函数指针
wndclass.cbClsExtra = 0; // 没有额外的类内存
wndclass.cbWndExtra = 0; // 没有额外的窗口内存
wndclass.hInstance = hInstance; // 实例句柄
wndclass.hIcon = ::LoadIcon(NULL,IDI_APPLICATION); // 使用预定义图标
wndclass.hCursor = ::LoadCursor(NULL,(LPSTR)IDC_ARROW); // 使用预定义的光标
wndclass.hbrBackground = (HBRUSH)
::GetStockObject(WHITE_BRUSH); // 使用白色背景画刷
wndclass.lpszMenuName = NULL; // 不指定菜单
wndclass.lpszClassName = szClassName ; // 窗口类的名称
wndclass.hIconSm = NULL; // 没有类的小图标
// 注册这个窗口类
::RegisterClassEx(&wndclass);
// 创建主窗口
HWND hwnd = ::CreateWindowEx(
0, // dwExStyle,扩展样式
szClassName, // lpClassName,类名
"贴心小闹钟", // lpWindowName,标题
WS_OVERLAPPEDWINDOW, // dwStyle,窗口风格
200, // X,初始 X 坐标
100, // Y,初始 Y 坐标
600, // nWidth,宽度
450, // nHeight,高度
NULL, // hWndParent,父窗口句柄
NULL, // hMenu,菜单句柄
hInstance, // hlnstance,程序实例句柄
NULL) ; // lpParam,用户数据
if(hwnd == NULL)
{
::MessageBox(NULL, "创建窗口出错!", "error", MB_OK);
return -1;
}
// 显示窗口,刷新窗口客户区
::ShowWindow(hwnd, nCmdShow);
::UpdateWindow(hwnd);
// 从消息堆中取出消息
MSG msg;
while(::GetMessage(&msg, NULL, 0, 0))
{
// 转化键盘消息
::TranslateMessage(&msg);
// 将消息发送到相应的窗口函数
::DispatchMessage(&msg);
}
// 当GetMessage返回0时程序结束
return msg.wParam;
}
LRESULT CALLBACK MainWProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
char szText[] = "贴心小闹钟";
switch (message)
{
case WM_PAINT: // 窗口客户区需要重画
{
HDC hdc;
PAINTSTRUCT ps;
// 使无效的客户区变的有效,并取得设备环境句柄
hdc = ::BeginPaint (hwnd, &ps) ;
// 显示文字
::TextOut(hdc, 250, 10, szText, strlen(szText));
::EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY: // 正在销毁窗口
// 向消息队列投递一个WM_QUIT消息,促使GetMessage函数返回0,结束消息循环
::PostQuitMessage(0) ;
return 0 ;
}
// 将我们不处理的消息交给系统做默认处理
return ::DefWindowProc(hwnd, message, wParam, lParam);
}