上次我们分析到函数的前向声明,如果你们遗忘了可以去看我的第一篇解析https://blog.csdn.net/hlz_12345/article/details/100529847
然后这一篇我们继续分析。
首先我们看到wWinMain函数
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
在函数名称前有个修饰符叫APIENTRY,实质上它是跟CALLBACK一样的东西,main函数也需要回调?是的,因为程序的启动也是由用户的操作触发的。比如说双击某个程序图标,程序就开始运行了,在这个过程中,双击是个操作,windows系统采用消息驱动机制所以这个操作会被封装成消息进入到消息队列里,当消息被取出时肯定调用了底层的API然后这个API再CALL BACK winmain函数。当然我是新手我个人觉得大概流程是这样的,如果有什么不对,欢迎大佬们来讨论。
然后关于函数参数里的_In_,_In_opt_这些都是sal里的内容,我们可以理解为一种注释。_In_表示的是输入的参数只可读,In_opt_是参数可选。这种东西了解就好。
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
这两行都用了同一个宏函数UNREFER什么的,意思就是说告诉编译器这个参数我用过了不要报警告。
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_HELLOWINDOWS, szWindowClass, MAX_LOADSTRING);
函数LoadString声明如下:
WINUSERAPI int WINAPI LoadStringA(
__in_opt HINSTANCE hInstance,
__in UINT uID,
__out_ecount(cchBufferMax) LPSTR lpBuffer,
__in int nBufferMax);
参数1: hInstance是应用程序实例句柄。
参数2: uID是资源中的字符串编号。
参数3: lpBuffer是接收从资源里拷贝字符串出来的缓冲区。
参数4: nBufferMax是指明缓冲的大小。
作用是从 资源 里加载字符串资源到CString对象里。
MyRegisterClass(hInstance); 注册窗口类,注意这个hInstance是从winmain函数参数里传进来的。
if (!InitInstance (hInstance, nCmdShow)) 顾名思义,创建实例。
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HELLOWINDOWS));
这个作用是加载资源里的快捷键,我们了解下即可。
MSG msg;
// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
这里的内容就是消息循环,有一点要讲的是,我不知道大家有没有思考过这个GetMessage函数是怎么接收外面的MSG的?
这确实比较令人费解,但我们现在需要知道的是这个函数其实也是一个CALLBACK函数。
具体内容在第二篇https://blog.csdn.net/hlz_12345/article/details/100536183在此不再赘述
return (int) msg.wParam;
退出while循环意味着已经接收到了WM_QUIT,此时的msg封装的应该是有关quit的信息,虽然我也不知道wParam里面是什么不过无所谓。
主函数里的内容分析到这里就结束了,我们可以概括下就是:
加载资源字符串-->注册窗口类-->创建窗口-->创建消息循环