windows游戏编程大师技巧第二版也是很老的书了,内容有些变化。
使用vs2019创建菜单资源:
资源名称修改为MainMenu.rc,
查看菜单ID:
方法一:
双击进入:
菜单ID为IDR_MENU1
双击打开resource.h文件
这里的ID_FILE_OPEN,ID_FILE_CLOSE就是菜单栏按钮的id,后面代码中还需要使用。
代码记得#include "resource.h"
#define WIN32_LEAN_AND_MEAN //预编译指令 指示编译器不要包含MFC的内容
#include
#include
#include "resource.h"
//我们创建的窗口和其他应用程序窗口都会产生事件和消息,所有消息都进入一个队列,并且我们的窗口消息发送到我们的窗口专用队列中,
//然后,主事件循环检索这些消息,并且把他们我们的窗口WindowProc中处理
/*
hwnd:窗口句柄,当我们使用同一个类建立多个窗口时才会用到,hwnd是表明消息来自哪个窗口的唯一途径
*/
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
switch (msg) {
case WM_ACTIVATE: //当窗口第一次创建
return 0;
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_FILE_OPEN:
break;
case ID_FILE_CLOSE:
break;
case ID_FILE_SAVE:
break;
case ID_FILE_EXIT:
break;
case ID_HELP_ABOUT:
break;
default:
break;
}
break;
case WM_PAINT: {//当窗口需要重画
hdc = BeginPaint(hwnd, &ps); //BeginPaint()EndPaint()这一对调用将激活窗口,并使用存储在Windows类中变量hbrBackground填充背景
EndPaint(hwnd, &ps);
return 0;
} break;
case WM_DESTROY: {//用户关闭窗口时调用,而不是应用程序,应用程序继续运行
PostQuitMessage(0);//通知windows终止应用程序
return 0;
} break;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
/*
#define WINAPI __stdcall
#define CALLBACK __stdcall
__stdcall: 函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。
__cdecl: C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。
WINAPI声明符: 一般用于修饰动态链接库中导出函数 3. CALLBACK仅用于修饰回调函数
*/
int WINAPI WinMain(HINSTANCE hinstance, /*windows为应用程序生成的实例句柄。实例是一个指针或一个数。 本例中hinstance用来跟踪应用程序*/
HINSTANCE hprevinstance,/*用来跟踪应用程序以前的实例,目前不再使用,微软要去除它*/
LPSTR lpcmdline,//空值终止字符串
int ncmdshow) {//启动过程中被传递给应用程序,带有如何打开主应用程序窗口的信息。这样用户可以有些控制程序如何启动的能力,可以在函数ShowWindow()中使用
WNDCLASSEX winclass = { 0 };
winclass.cbSize = sizeof(winclass);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursorA(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = "WINCLASS1";//每个window类代表我们的应用程序所创建的不同的窗口类型,windows需要一些途径跟踪识别它们,lpszClassName就是用于此目的,
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&winclass)) {//注册一个拓展的窗口类,将新类通知给windows
return 0;
};
HWND hwnd;
//返回新建窗口句柄,失败了返回null
if (!(hwnd = CreateWindowEx(NULL, "WINCLASS1", "My First Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,//WS_VISIBLE 自动显示的类型标识符
0, 0,//窗口左上角位置
400, 400,
NULL,//假如存在父窗口,指向父窗口句柄
LoadMenu(hinstance, MAKEINTRESOURCE(IDR_MENU1)),//指向附属该窗口菜单的句柄
hinstance,//应用程序实例
NULL))
) {
return 0;
}
ShowWindow(hwnd, ncmdshow);//如果没有添加WS_VISIBLE标识符,手动显示
UpdateWindow(hwnd);//更新窗口内容,并且产生一个WM_PAINT信息
MSG msg;
//while (GetMessage(&msg, NULL, 0, 0)) {
// TranslateMessage(&msg);
// DispatchMessage(&msg);//指出所有操作发生的位置,调用WinProc进一步处理
//}
while (TRUE) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);//消息发送给Window Procedure
}
}
return 0;
}
参考:https://blog.csdn.net/nullccc/article/details/81352470