【发布时间】:2017-08-29 19:22:30
【问题描述】:
我正在使用 Windows API 试图了解它的行为方式,我意识到我可以完全删除 WNDPROC 并使用裸事件循环来处理事情,如下所示:
#include <Windows.h>
static struct {
HWND desktop;
HWND window;
} global;
int main(int argc, char **argv)
{
/* anonymous scope: register window class */
{
WNDCLASSEXW wcx;
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = DefWindowProc;
wcx.cbClsExtra = sizeof(void *);
wcx.cbWndExtra = sizeof(void *);
wcx.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = L"MyWindow";
wcx.hIconSm = wcx.hIcon;
RegisterClassExW(&wcx);
}
global.desktop = GetDesktopWindow();
global.window = CreateWindowExW (
0,
L"MyWindow",
NULL,
WS_POPUPWINDOW | WS_VISIBLE,
0,
0,
320,
200,
global.desktop,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL
);
/* anonymous scope, event loop */
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
if(msg.hwnd == global.window) {
if (msg.message == WM_PAINT) {
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(msg.hwnd, &ps);
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Rectangle(hdc, 0, 0, 320, 200);
EndPaint(msg.hwnd, &ps);
} else {
DispatchMessage(&msg);
}
} else {
DispatchMessage(&msg);
}
}
}
return 0;
}
我想更进一步,尝试使用this 技术使此窗口可移动,但我感到困惑,因为我无法以我习惯的方式从消息循环中“返回”(声明 @987654326 @) 在这种情况下没有意义。
我是这样开始的,然后感到困惑:
#include <Windows.h>
static struct {
HWND desktop;
HWND window;
} global;
int main(int argc, char **argv)
{
/* anonymous scope: register window class */
{
WNDCLASSEXW wcx;
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = DefWindowProc;
wcx.cbClsExtra = sizeof(void *);
wcx.cbWndExtra = sizeof(void *);
wcx.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = L"MyWindow";
wcx.hIconSm = wcx.hIcon;
RegisterClassExW(&wcx);
}
global.desktop = GetDesktopWindow();
global.window = CreateWindowExW (
0,
L"MyWindow",
NULL,
WS_POPUPWINDOW | WS_VISIBLE,
0,
0,
320,
200,
global.desktop,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL
);
/* anonymous scope, event loop */
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
if(msg.hwnd == global.window) {
if (msg.message == WM_PAINT) {
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(msg.hwnd, &ps);
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Rectangle(hdc, 0, 0, 320, 200);
EndPaint(msg.hwnd, &ps);
} else if (msg.message == WM_NCHITTEST) {
LRESULT hit = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
if (hit == HTCLIENT) {
hit = HTCAPTION;
}
// return hit; // makes no sense here
} else {
DispatchMessage(&msg);
}
} else {
DispatchMessage(&msg);
}
}
}
return 0;
}
如何模拟从 WM_NCHITTEST 条件返回的“命中”,以便它像这里的解决方案一样移动窗口:https://stackoverflow.com/a/7773941/2012715?
PS:我知道使用映射(如 std::unordered_map)而不是长 if/switch 以获得可伸缩性和可读性更好,但我想让示例更直接。
【问题讨论】:
-
致反对票的人:如果您反对票,您应该解释原因,否则毫无意义。这个问题是可以理解的,甚至有一个 MCVE,所以我真的看不出有理由投反对票。
-
@zett42:这个问题是问随机更改代码引起的问题,OP不明白。这对一般大众来说几乎没有用处,他们往往想要解决实际问题,而不是人为的问题。 OP 应该 提出的有用问题是:“DispatchMessage 的目的是什么?” 如所问,这个问题没有用。
-
随机更改代码我不懂?我对如何将 NCHITTEST 发送到窗口感到困惑。结果是window proc可以看到,但线程消息队列看不到;了解这是如何发生的很有用(线程消息队列可以看到 WM_PAINT 和 WM_MOUSEMOVE 等一些消息,而 NCHITTEST 则没有)。我不明白你的担心。
-
按理说,你不了解注册窗口过程的后果,因为你不了解Windows应用程序中的message routing。所有这些都记录在案并且随时可用。询问如何最好地对抗系统的问题通常没有用。
-
我了解注册窗口过程的后果。我不明白排队和非排队消息的概念。现在很有意义。