gpt4 book ai didi

c - 如何在裸事件循环中处理 WM_NCHITTEST?

转载 作者:太空宇宙 更新时间:2023-11-04 06:15:48 30 4
gpt4 key购买 nike

我正在玩 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 使这个窗口可移动技术,并感到困惑,因为我无法按照我习惯的方式从消息循环中“返回”(语句 return hit;)在这种情况下没有意义。

以下是我的开始和困惑:

#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 以实现可伸缩性和可读性,但我想让示例更直接。

最佳答案

你不能。

您显示的代码将永远无法工作,因为 (Get|Peek)Message() 仅返回 QUEUED消息。您无法回复排队的消息,因为发件人没有等待回复,而是将消息放入队列并继续处理其他事情。只有NON-QUEUED可以回复使用 SendMessage...() 系列函数发送的消息。 (Get|Peek)Message() 永远不会返回已发送的消息,但会在内部将其分派(dispatch)给目标窗口的消息过程(只会分派(dispatch)从另一个线程发送的消息,通过拥有该窗口的同一个线程将完全绕过消息队列。

WM_PAINT 是一条排队消息,因此您的事件循环可以看到它。但是 WM_NCHITTEST 没有排队,所以你的消息循环永远不会直接看到它,它只能在消息过程中看到。

您展示的不是处理 Windows UI 消息循环的正确方法。由于您正在创建一个 UI 窗口,因此您必须为其提供消息过程(如果不是通过 RegisterClass/Ex(),则通过 SetWindowLong/Ptr(GWL_WNDPROC)SetWindowSubclass())。但是,如果您需要手动处理消息,请不要在该过程中使用 DefWindowProc()。提供您自己的调用 DefWindowProc() 的消息过程(或 CallWindowProc()GWL_WNDPROC 的情况下,或 DefSubclassProc()SetWindowSubclass() 的情况下用于任何未处理的消息,例如:

LRESULT WINAPI MyWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Rectangle(hdc, 0, 0, 320, 200);

EndPaint(hwnd, &ps);
return 0;
}

case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hwnd, uMsg, wParam, lParam);
if (hit == HTCLIENT) {
hit = HTCAPTION;
}
return hit;
}
}

return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

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 = MyWndProc; // <--
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);
DispatchMessage(&msg);
}
}

return 0;
}

关于c - 如何在裸事件循环中处理 WM_NCHITTEST?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45946865/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com