单个 wndproc 如何让每个窗口知道它的序列号?
Posted
技术标签:
【中文标题】单个 wndproc 如何让每个窗口知道它的序列号?【英文标题】:How does a single wndproc let each window know its serial number? 【发布时间】:2022-01-05 15:08:19 【问题描述】:int Num = 0;
LRESULT CALLBACK TestWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
RECT rc;
GetClientRect(hWnd, &rc);
RECT Winrc;
GetWindowRect(hWnd, &Winrc);
SYSTEMTIME time;
GetLocalTime(&time);
static const wchar_t* BoxTxt = L"";
static int MeIs = Num;
switch (message)
case WM_CREATE:
SetWindowLong(hWnd, GWL_EXSTYLE,
GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 220, LWA_ALPHA);
//GhWnd = hWnd;
break;
case WM_LBUTTONUP:
wchar_t meChar[20] = L"";
_itow(MeIs, meChar, 10);
MessageBox(0, meChar, meChar, 0);
case WM_SIZE:
InvalidateRect(hWnd, &rc, 1);
break;
case WM_NCLBUTTONDBLCLK:
break;
case WM_COMMAND:
int wmId = LOWORD(wParam);
switch (wmId)
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_CLOSE:
Num -= 1;
DestroyWindow(hWnd);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
int CreateTestWindow()
//Call testwndproc. To reduce the length of the problem description, omit these codes
Num+=1;
return 0;
在上面的代码中,当我创建多个窗口并点击它时,应该会弹出“1”、“2”、“3”……但实际上都是弹出“1”。
static int MeIs = 0;
case WM_CREATE:
MeIs = Num;
改成上面的代码,会弹出最后一个窗口的序列号。比如第四个窗口创建时,所有窗口都会弹出“4”
在实际应用中,每个窗口都有自己的设置,并存储在向量中。每个窗口根据自己的序列号找到自己的设置:
struct Data
int x;
int y;
int width;
int height;
const wchar_t* text;
std::vector<data>UserData(32);//Max:32
//then read them from file,But the window must know which window it is:UserData[i].
例如,第一个窗口会将它们的坐标设置为UserData[1].x和UserData[1].y,关闭时也需要保存文件。 有什么想法吗?谢谢!
【问题讨论】:
static int MeIs
- 你在程序中只得到其中一个,而不是每个窗口一个。如果您想要每个窗口的数据,您可以在注册窗口类时添加存储空间。
但是如何增加存储空间呢?我希望每个窗口数据是独立的,但是WndProc只有一个。
你应该阅读 Petzold 的书。像这样学习真的不会有成效。
cbWndExtra
.
hwnd
不是已经表示窗口了吗?
【参考方案1】:
有几种方法可以使用 Win32 API 维护每个窗口的数据。
最简单的方法是使用可通过GetWindowLongPtr(...)
和SetWindowLongPtr(...)
访问的GWL_USERDATA
插槽。初始化此用户数据值的典型方法是使用通过CreateWindow
调用传递给WM_CREATE
消息的创建参数。
代码如下:
#include <windows.h>
#include <string>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
struct SomeData
int n;
std::wstring str;
;
int RegisterWindow(HINSTANCE hInstance, const wchar_t* wnd_class)
MSG msg = 0 ;
WNDCLASS wc = 0 ;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(WHITE_BRUSH);
wc.lpszClassName = wnd_class;
if (!RegisterClass(&wc))
return 1;
return 0;
int CreateWindowWithUserData(HINSTANCE hInstance, const wchar_t* wnd_class, int n, const std::wstring& str)
auto* data_ptr = new SomeData n, str ;
if (!CreateWindow(wnd_class, L"Window text", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, data_ptr))
return 2;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
const auto* wnd_class = L"foobar";
RegisterWindow(hInstance, wnd_class);
for (int i = 1; i <= 5; i++)
CreateWindowWithUserData(hInstance, wnd_class, i, L"blah");
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
TranslateMessage(&msg);
DispatchMessage(&msg);
return 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
switch (message)
case WM_CREATE:
CREATESTRUCT* create_struct = reinterpret_cast<CREATESTRUCT*>(lParam);
SomeData* user_data = reinterpret_cast<SomeData*>(create_struct->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG>(user_data));
return 0;
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_PAINT:
SomeData* user_data = reinterpret_cast<SomeData*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT r = 20, 20, 300, 35 ;
auto msg = user_data->str + L" " + std::to_wstring(user_data->n);
DrawText(hdc, msg.c_str(), -1, &r, DT_SINGLELINE);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
SomeData* user_data = reinterpret_cast<SomeData*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
delete user_data;
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
做类似事情的另一种方法是在注册窗口类时使用cbWndExtra
额外字段as discussed in this answer。
【讨论】:
谢谢,但还有一个问题。如果窗口关闭,我如何通知程序重新排序所有窗口?比如我关闭第二个窗口(假设一共有五个),第三个窗口会被排序为“2”,以此类推 我不确定你的意思。它们是独立的窗口。用户可以按照用户想要的任何顺序放置它们。但它们仍会显示创建时使用的正确的每个窗口数据。 对不起,我没有说清楚。表示一共创建了序号为1,2,3,4,5的窗口,但是例如如果序号为3的窗口关闭了,则使用后面的窗口序号补充关闭的窗口,像4变成3,5变成4。有没有办法实现呢?感谢您的辛勤工作。【参考方案2】:你可以:
确实在Window中存储数据。SetProp
, SetWindowLong
+GWL_USERDATA
, SetWindowLong
+cbWndExtra
将 HWND 映射到您的数据,例如使用 c++ std::map
使用 thunk 来获得关联对象,例如 ATL,请参阅 ATL thunk header 了解可用 API(对于较旧的操作系统,必须手动完成)
【讨论】:
以上是关于单个 wndproc 如何让每个窗口知道它的序列号?的主要内容,如果未能解决你的问题,请参考以下文章