#include <Windows.h>
Int WINAPI WinMain(_In_ HINSTANCE hInstance,_In_opt HINSTANCE hPrevInstance,_In_ LPSTR lpCmdine,_In_ int nCmdShow){
MessageBox(NULL,L"你好,Visual Studio",L"消息窗口",0);
Return 0;
}

WINAPI 其实就是 _stdcall 有时候也会写作 CALLBACK 它和 WINAPI 等效
WinMain 是Windows程序的入口函数

WinMain的第一个参数:

HINSTANCE类型的hInstance,它表示该程序当前运行的实例句柄。
我们可以对这个类型HINSTANCE进行字面上的理解,h前缀表示这个参数的类型为handle(句柄),句柄的意思,而后面的Instance中文意思是实例,将两个意思结合起来,所以这个类型就是实例句柄。
hInstance其实就是一个数值。当一个程序在Windows下运行时,它唯一对应一个运行中的实例,也只有运行中的程序实例,才有资格分配到句柄。
一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄,并且通过hInstance参数传递给程序的入口点WinMain函数。

WinMain的第二个参数:

HINSTANCE类型的hPrevInstance,表示当前实例的前一个实例句柄。
​我们可以对这个参数进行字面上的理解,h表示参数类型为句柄,Prev代表先前的(Previous)意思,Instance依旧表示实例,那么组合起来就是先前的实例句柄,这样顾名思义,是不是很好记忆呢,对于这个参数用法,MSDN中明确表示在Win32环境下,该参数总是取NULL,这就是说在Win32环境下这个参数没有存在感,不起任何作用,只是在进行WinMain函数书写时需要将它专门做为一个参数表示出来而已。

WinMain的第三个参数:

LPSTR类型的lpCmdLine,它是一个以空终止的字符串,指定传递给运用程序的命令行参数。
依旧是进行参数肢解:lp前缀表示这个参数是一个指针,Cmd表示Command,命令的意思,与Line组合起来就表示命令行。
例如在Windows7操作系统下的E盘有一个叫ForTheDream.txt的文件,我们用鼠标双击这个文件时将启动记事本程序(notepad.exe)。
此时系统会将E:\ForTheDream.txt作为命令行的参数传递给记事本程序的WinMain函数,记事本程序会在得到这个文件的路径后,就会在窗口中正确显示这个文件的内容。

WinMain的第四个参数:

int类型的nCmdShow,指定程序窗口应该如何显示,是最大化,最小化,还是隐藏等等。
这个参数可有如下取值:

参数 意义
SW_HIDE 0 隐藏此窗口并激活另一个窗口
SW_MAXIMIZE 3 最大化指定的窗口
SW_MINIMIZE 6 最小化指定的窗口并激活当前Z次序中顶部的窗口
SW_RESTOPE 9 激活并显示此窗口,如果此窗口被最小化或者最大化了,系统会恢复它到原始尺寸的位置,一个应用程序应该在恢复最小化的窗口时指定此SW_RESTORE标识
SW_SHOW 5 以当前的尺寸和位置激活与显示指定窗口
SW_SHOWMAXIMIZED 3 最大化激活并显示这个窗口
SW_SHOWMINIMIZED 2 最小化激活并显示这个窗口
SW_SHOWMINNOACTIVE 7 最小化显示这个窗口,与SW_SHOWMINIMIZED唯一的区别是不会去激活指定的窗口
SW_SHOWNA 8 以当前的尺寸和位置激活与显示指定窗口,与SW_SHOW的唯一区别是不会去激活指定的窗口
SW_SHOWNOACTIVATE 4 显示一个窗口,若指定的窗口是最小化或者最大化的,系统会恢复其到原始尺寸和位置,与SW_SHOWNORMAL的唯一区别是不会去激活指定的窗口
SW_SHOWNORMAL 1 激活和显示一个窗口,若指定的窗口是最小化或者最大化的,系统会恢复其到原始尺寸和位置。一个应用程序应该在第一次显示窗口的时候指定这个标识

MessageBox函数

MessageBox函数,它用于显示一个消息框,可以通过一些参数来设置这个消息框的样式。在MSDN中查到这个函数有如下原型:

Int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpTest,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);

这里的_In_opt 类似于之前提到过的_in,只不过是后面多了一个_opt,表示可选的(Optional),两个词组合在一起就表示”可选的输入参数”了。就是说这个参数我们可以自己填内容,不填具体内容的话直接填NULL也行得通,选择权在于我们。

MessageBox函数第一个参数:

HWND类型的hWnd,表示我们显示的消息框所属的窗口的句柄。在进行Windows编程中,我们常常要和句柄打交道,后面我们会具体阐述什么是句柄,在我们的Visual Studio程序中,这个参数设为了NULL,表示消息框是从属于桌面。

MessageBox函数的第二个参数:

LPCTSTR类型的lpText,它是一个以NULL结尾的字符串,表示所要显示的消息的内容。

MessageBox函数的第三个参数:

LPCTSTR类型的lpCaption,它也是一个以NULL结尾的字符串,在其中填我们要显示的消息框的标题的内容。

MessageBox函数的第四个参数:

UINT类型的uType,表示我们消息窗口需要什么样的样式。微软已经为我们定义好了很多可供选择的样式和消息对应的图标,一些常用的样式列表如下:

标识名(Flags) 含有精析
MB_ABORTRETRYIGNORE 消息框带有三个按钮:Abort、Retry和Ignore
MB_OK 消息框带有唯一一个按钮:OK。需要注意的是,MB_OK 是系统默认的MessageBox函数样式
MB_OKCANCEL 消息框带有两个按钮:OK和Cancel
MB_RETRYCANCEL 消息框带有两个按钮:Retry和Cancel
MB_YESNO 消息框带有两个按钮:YES和NO
MB_YESNOCANCEL 消息框带有三个按钮:YES、NO和Cancel

常见的图标我们也是通过一些标识名来指定,如以下几种:

标识名(Flags) 含义精析
MB_ICONWARNING “警告”图标
MB_ICONASTERISK “风险”图标
MB_ICONSTOP “停止”图标

这里只列出了一些常用的标识,完整版可以自行查阅MSDN。
想要多个标识一起使用的话,我们可以采用逻辑或(Logical OR)把不同的标识连接起来,具体的符号是键盘上Enter键上方的那条竖杠”|”。比如要创建一个具有YES和NO的按钮并带有”问号”图标的消息框,我们就把uType填成这样:MB_YESNO|MB_ICONQUESTION,非常直观。后面我们也会经常碰到类似的、需要多个标识符同时使用的场合,用一下这条竖杠”|”连接一下就好了。
和大多数Win32函数一样,MessageBox函数也有返回值。在Visual Studio示例程序中,这个返回值可以忽略。而如果我们创建了具有对应按钮的消息框,就涉及到按下具体的按键,就需要给出按键的返回值,这样我们就需要判断哪个键被按下了,再对应作出相应的响应。返回值的列表如下:

返回值类型 精析
IDABORT 按下Abort后的返回值
IDCANCEL 按下Cancel后的返回值
IDIGNORE 按下Ignore后的返回值
IDNO 按下NO之后的返回值
IDOK 按下OK之后的返回值
IDRETRY 按下Retry之后的返回值
IDYES 按下Yes之后的返回值

这个短小的函数MessageBox我们算是讲完了。它虽然很简单,但是非常好用,可谓麻雀虽小五脏俱全,特别是在需要向玩家显示出错误消息的时候,比如我们写了一个函数,在程序执行出错的时候我们要知道出错的地方,就可以这样来写:

if(error){
MessageBox(NULL,L"在这里填写出错的信息",L"在这里填报错信息标题",0);
}

用MessageBox来显示错误消息的这个方法会贯穿我们游戏编程的始终,如果想让我们的游戏程序遇到问题可以更加智能,就要在我们的游戏程序源代码中多加一些这样的”错误处理”代码。值得一提的是,在运行游戏程序时经常会弹出一个提示框,提示缺失某某D3D的DLL或者MSVR的DLL,程序想要重新安装云云,就是这个MessageBox函数的杰作。