一、今天开始写Win32 Application 程序
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // pointer to command line
int nCmdShow // show state of window
);
这是主函数,是基于Win32 的应用程序的默认入口函数。
参数:hInstance : 应用程序当前实例的句柄
hPrevInstance :应用程序上一个实例的句柄,对于基于Win32的程序,该参数为空。
如果需要检测是否有另外一个实例存在,调用CreatMutex函数创建一个独一无二的互斥命名,即使一个互斥命名已经存在,CreatMutex 也将会成功,但是GetLastError函数将会返回 ERROR_ALREADY_EXISTS,这就是说提示另外一个应用程序的实例已经存在,因为它先创建了一个互斥体。
lpCmdLine :在命令行程序中,指向一个以空来结尾的字符串,不包含程序名。检索整个命令行,使用GetCommandLine函数。
nCmdShow: :指定窗口如何显示,参数可以是下列值:
值 | 所代表的意义 |
SW_HIDE | 隐藏该窗口激活另外一个窗口 |
SW_MINIMIZE | 最小化指定得窗口,激活系统列表中得最上面的窗口 |
SW_RESTORE | 激活并显示窗口。如果窗口最小化或者最大化,把窗口恢复到初始大小和初始位置。 |
SW_SHOW | 以当前大小和位置激活窗口。 |
SW_SHOWMAXIMIZED |
|
。。。。。。 |
|
返回值:
如果函数成功,且当收到WM_PAINT消息时终止,它应该返回一个包含在消息的wParam参数中的exit值。如果函数在进入消息循环前终止,应该返回0。
备注:要使用Windows的消息机制。
二、创建一个应用程序的步骤
首先设计一个窗口类,接着注册该窗口类,再创建该窗口,最后显示及更新。
1. 设计一个窗口类;
2. 注册窗口类;
3. 创建窗口;
4. 显示及更新窗口。
设计窗口类的过程即定义一个WNDCLASS 对象,给该对象的属性赋值。如下:
WNDCLASS 的相关信息:
这是一个结构体,包含了窗口类的属性,这些属性可以使用RegisterClass函数来注册。
该结构体已经被WNDCLASSEX函数所取代,注册函数也被RegisterClassEx函数取代。区别在于,在不使用和窗口类相关的小图标时,可以继续使用WNDCLASS和RegisterClass。
结构体定义如下:
typedef struct _WNDCLASS {
UINT style; // 指定类的风格类型。可以使用|连接几个风格。
WNDPROC lpfnWndProc; //Windows 进程指针,必须使用CallWindowPro函数来调用window进程。
int cbClsExtra; // 指定该window类后面跟着的分配的额外的字节数
int cbWndExtra;// 指定window实例后面分配的额外的字节数。
HANDLE hInstance; //该类所在的window程序的实例句柄。
HICON hIcon; //该类的图标,需为图标资源句柄,如果为空,应用程序在用户最小化窗口时须画一个图标。
HCURSOR hCursor; // 光标
HBRUSH hbrBackground; // 背景句柄
LPCTSTR lpszMenuName; // 指向一个类的菜单的资源名的字符串的指针。
LPCTSTR lpszClassName; // 指向一个字符串或者一个原子的指针。
} WNDCLASS;
RegisterClass 注册一个窗口类
注册类函数注册一个窗口类,以便下一步在CreatWindow或者CreatWindowEx中使用,
注册类函数现在已经被RegisterClassEx函数取代,如果不必使用小图标时可以继续使用该函数。
ATOM RegisterClass(
CONST WNDCLASS *lpWndClass // address of structure with class data
);
参数:lpWndClass : WNDCLASS结构的指针。在传过来之前必须填写合适的属性。
返回值:如果函数成功,返回值为一个原子值,它唯一的标志注册的类。如果失败,返回0,。可以调用GetLastError值看错误信息。
ATOM 其实就是一个Word ,有一个Atom表,它指向一个该表中一个字符串的引用。
CreateWindow
创建一个窗口,返回值为一个窗口句柄。
HWND CreateWindow(
LPCTSTR lpClassName, // pointer to registered class name
LPCTSTR lpWindowName, // pointer to window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // handle to menu or child-window identifier
HANDLE hInstance, // handle to application instance
LPVOID lpParam // pointer to window-creation data
);
该函数创建一个overlapped 、弹出或子窗口。它指定窗口类,窗口的标题,风格,并且初始位置和大小(可选)。该函数也指定窗口的父窗口(如果有),和窗口的菜单。
hMenu:指向Menu的指针,或者指定一个子窗口标志的标志(根据window风格而定)
hInstance :和窗口相关的模块实例的句柄。
lpParam :在WM_CREAT消息中传递的参数,通过CREATSTRUCT结构传给窗口的值的指针。
返回值:如果成功,返回一个新窗口的句柄。如果失败,返回NULL。
备注:在返回之前,该函数发送一个WM_CREATE消息给window进程。
显示及刷新窗口 ShowWindow()
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
三、传递消息
在显示窗口以后,要对该窗口内的消息进行分发和处理
首先定义消息的对象。
MSG
消息MSG为一个结构体,包含了来自一个进程的消息队列中的消息。
typedef struct tagMSG { // msg
HWND hwnd; // 接收消息的串口句柄
UINT message; //消息的number
WPARAM wParam; // 指定消息的额外信息,精确的意思取决于message成员
LPARAM lParam; // 也是指定消息的额外信息,同上。
DWORD time; // 消息发出的时间。
POINT pt; // 指针位置,以屏幕为坐标系,
} MSG;
GetMessage()
得到消息
该函数从调用线程消息队列中读取消息,并把它放在指定的结构体中。它能够同时读取和指定窗口相关的消息,和通过PostThreadMessage函数传递的线程消息。该函数读取位于指定范围内的消息。它不会得到属于其他进程的消息。
BOOL GetMessage(
LPMSG lpMsg, // address of structure with message
HWND hWnd, // handle of window
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax // last message
);
lpMsg :从进程消息对列中获取消息,放在该指针指向的一个MSG结构体。
hWnd :窗口句柄,消息即是从该窗口中获取。其中NULL值有特殊意义,表示:函数从属于该进程的所有窗口中和通过调用PostThreadMessage传递给的进程中获取消息。
wMsgFilterMin : 最小的消息,整数
wMsgFilterMax:最大的消息,整数
返回值:如果函数得到一个非WM_PAINT 消息,返回值非0
如果是WM_PAINT ,返回0。
如果出错,返回-1;
TranslateMessage
翻译消息
BOOL TranslateMessage(
CONST MSG *lpMsg // address of structure with message
);
该函数把虚键值翻译成字符消息。字符消息被发送给调用进程的消息队列,当进程下一次调用GetMessage或者PeekMessage函数时被读出。
唯一的一个参数lpMsg 为一个MSG指针,
返回值: 如果消息被翻译(即字符消息被传给进程消息队列)返回非0;或者如果消息是 WM_KEYDOWN,WM_KEYUP,WM_SYSKEYDOWN,
WM_SYSKEYUP时,不管翻译情况,都返回非0;如果没有翻译,返回0。
DispatchMessage
分发消息
该函数把消息分发给窗口进程。典型的用于通过GetMessage函数获得的消息。
LONG DispatchMessage(
CONST MSG *lpmsg // pointer to structure with message
);
参数 lpmsg :指向MSG 结构的指针。
返回值:为窗口进程返回的值。经常被忽略。
备注:MSG结构必须包含合法的消息值。如果lpmsg 参数指向一个WM_TIMER消息,并且WM_TIMER的lParam参数不为NULL,lParam 指向一个调用的函数而非window 进程。
三、编写窗口处理函数WindowProc
WindowProc 函数是一个应用程序定义的函数,它处理发给窗口的消息。WNDPROC类型定义了一个调用返回函数的指针。WindowProc为应用程序定义函数名的占位符。
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
参数:
hwnd 窗口句柄
uMsg 指定消息
wParam 指定消息的额外信息。内容取决于uMsg 参数的值。
lParam
返回值 :返回值是消息处理的结果,取决于所发送的消息。
在处理消息的过程中,一定要在switch()的最后写上一个default 情况,(这也是所有switch()中应该注意的)。另外要有WM_DESTROY 消息,
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
这次在显示菜单的时候有些问题,
在设计窗口类时,很多地方用的是直接赋值,
wndclass.lpszMenuName = IDR_MENU1;
但是有的时候出问题,所以需要用下面的方式
wndcls.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);
MAKEINTRESOURCE():这是一个宏,参数为一个整型,把该整型对应的资源和一个32位应用程序的资源对应。
菜单命令消息属于WM_COMMAND里面的。即,处理菜单命令,需要在
Case WM_COMMAND : 中处理,判断是哪个菜单被点击,用lparam 参数,
case WM_COMMAND:
{
switch(wParam)
{
case IDM_EXIT:
if(IDYES== MessageBox(hwnd,"Really close","guanbi",MB_YESNO))
{
DestroyWindow(hwnd);
}
}
}
break;
所有的菜单命令处理都在这里面。
下面是在写该程序过程中出现的问题:
1。在关闭程序后,还不能彻底关闭该进程。
报的错误如下:
LINK : fatal error LNK1168: cannot open Debug/WinMain.exe for writing
Error executing link.exe.
这是因为在消息循环时的疏忽所致,代码可能如下:
while(GetMessage(&msg,hwnd,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
注意:GetMessage 的第二个参数说明如下
HWND hWnd, // 检索消息的窗口,如果为NULL,则是指所有的窗口。因此,如果没有设置成NULL,则关闭程序后仍旧检索该窗口的消息,所以县城仍然存在。此问题的解决办法即是把该参数设置为NULL。