#define WIN32_LEAN_AND_MEAN //预编译指令 指示编译器不要包含MFC的内容
#include
#include
//我们创建的窗口和其他应用程序窗口都会产生事件和消息,所有消息都进入一个队列,并且我们的窗口消息发送到我们的窗口专用队列中,
//然后,主事件循环检索这些消息,并且把他们我们的窗口WindowProc中处理
/*
hwnd:窗口句柄,当我们使用同一个类建立多个窗口时才会用到,hwnd是表明消息来自哪个窗口的唯一途径
*/
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
static int cnt = 2;
switch (msg) {
case WM_ACTIVATE: {//当窗口第一次创建
return 0;
}break;
case WM_PAINT: {//当窗口需要重画
hdc = BeginPaint(hwnd, &ps); //BeginPaint()EndPaint()这一对调用将激活窗口,并使用存储在Windows类中变量hbrBackground填充背景
EndPaint(hwnd, &ps);
return 0;
}break;
case WM_DESTROY: {//用户关闭窗口时调用,而不是应用程序,应用程序继续运行
cnt--;
if (cnt == 0) {
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()中使用
MessageBox(NULL,
"Hello",//多字节编码 https://blog.csdn.net/luoweifu/article/details/49382969
"My First Windows Program",
MB_OK | MB_ICONEXCLAMATION);
MessageBeep(MB_OK);//点击按钮后有声音
/*
函数返回一个值通知我们发生了什么事,比如IDABORT, IDCANCEL
int MessageBox(
_In_opt_ HWND hWnd, 窗口句柄,设置为null,Windows桌面被用作父窗口
_In_opt_ LPCSTR lpText, 包含显示文本的空值终止字符串
_In_opt_ LPCSTR lpCaption, 包含显示文本框标题的空值终止字符串
_In_ UINT uType); 决定显示的是哪种信息框
*/
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(wc);
wc.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WINCLASS1";//每个window类代表我们的应用程序所创建的不同的窗口类型,windows需要一些途径跟踪识别它们,lpszClassName就是用于此目的,
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {//注册一个拓展的窗口类,将新类通知给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,//假如存在父窗口,指向父窗口句柄
NULL,//指向附属该窗口菜单的句柄
hinstance,//应用程序实例
NULL))
) {
return 0;
}
//----------------创建第二个窗口
wc.lpszClassName = "WINCLASS2";
if (!RegisterClassEx(&wc)) {//注册一个拓展的窗口类,将新类通知给windows
return 0;
};
HWND hwnd2;
//返回新建窗口句柄,失败了返回null
if (!(hwnd2 = CreateWindowEx(NULL, "WINCLASS2", "My First Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,//WS_VISIBLE 自动显示的类型标识符
200, 200,//窗口左上角位置
400, 400,
NULL,//假如存在父窗口,指向父窗口句柄
NULL,//指向附属该窗口菜单的句柄
hinstance,//应用程序实例
NULL))
) {
return 0;
}
//---------------第二个窗口创建完成
ShowWindow(hwnd, ncmdshow);//如果没有添加WS_VISIBLE标识符,手动显示
UpdateWindow(hwnd);//更新窗口内容,并且产生一个WM_PAINT信息
ShowWindow(hwnd2, ncmdshow);
UpdateWindow(hwnd2);
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;
}
为了实现,两个窗口都关闭才推出程序,因此我们添加了一个计数器 static int cnt = 2;
当两个窗口都关闭时,cnt=0,这时再发送WM_QUIT消息。
参考:
https://bbs.csdn.net/topics/270046351