我有超级简单的WinApi程序。关闭按钮不会破坏程序的进程。应该添加什么?
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hINSTANCE;
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpstr,
int nCmdShow) {
// VARIABLES
TCHAR className[] = _T("win32api");
TCHAR windowName[] = _T("Protected Window");
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = className;
wcex.hIconSm = LoadIcon(NULL, IDI_SHIELD);
if (!RegisterClassEx(&wcex)) {
MessageBox(NULL, _T("Cannot register window"), _T("Error"), MB_OK | MB_ICONERROR);
return 0;
}
HWND hWnd = CreateWindow(className,
windowName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
300,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd) {
MessageBox(hWnd, _T("Call to register windows isn't working"), _T("Error"), NULL);
return 1;
}
hINSTANCE = hInstance;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, hWnd, 0, 0) != 0 || GetMessage(&msg, hWnd, 0, 0) != -1) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.lParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uInt, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
switch (uInt) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 10, 20, _T("Text sample right here boyz."), _tcsclen(_T("Text sample right here boyz.")));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uInt, wParam, lParam);
break;
}
return 0;
}
如果我再添加一个案例
case WM_CLOSE:
PostQuitMessage(0);
break;
它根本没有关闭(按下关闭按钮没有做任何事情)。非常感谢任何其他提示。
答案 0 :(得分:4)
您的消息循环错误,原因有两个:
您正在拨打GetMessage()
两次。不要那样做!想想如果你这样做会发生什么。如果GetMessage()
左侧的||
调用要检测WM_QUIT
(它不能,请参见下文),则会返回0.这会导致{||
1}}调用右侧的GetMessage()
,忽略前一次调用的WM_QUIT
并阻止循环,直到稍后有新消息到达。您应该在每次循环迭代时只调用GetMessage()
一次,然后根据需要对返回值执行操作:
BOOL bRet;
do
{
bRet = GetMessage(&msg, hWnd, 0, 0);
if (bRet == 0) break;
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
while (1);
但是,您还要按HWND
(don't do that!)过滤邮件,因此它只会通过{{1}返回发布到指定HWND
的邮件}。 PostMessage()
将PostQuitMessage()
消息发布到调用线程本身的输入队列,而不是WM_QUIT
。因此,过滤永远不会看到HWND
消息。为了让WM_QUIT
打破循环,您需要完全停止WM_QUIT
过滤,或者至少定期进行未过滤的调用。
您的消息循环应该是这样的。这是标准消息循环:
HWND
答案 1 :(得分:0)
要关闭应用程序,您需要销毁窗口。通常,这是通过以下两种方式之一完成的:
WM_CLOSE
处理程序调用{{1}}。DestroyWindow
处理完您所做的事后的消息。你的DefWindowProc
有点不同寻常。我通常把它们写成:
WndProc
有关{
switch(msg)
{
case WM_CLOSE:
// prompt user, clean stuff up, etc.
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
// Other cases here. Most will fall out of the switch so that
// DefWindowProc can handle them (for other system notifications).
// Only return from the case if you really don't want anybody else
// to handle the message.
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
的详细信息,请参阅https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx,其中明确说明您必须致电WM_CLOSE
或让DestroyWindow
执行此操作。