[英]How does a single wndproc let each window know its serial number?
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;
}
在上面的代碼中,當我創建多個 windows 並點擊它時,它應該會彈出“1”,“2”,“3”......但實際上都彈出“1”。
static int MeIs = 0;
case WM_CREATE:
{
MeIs = Num;
}
改成上面的代碼,會彈出最后一個window的序列號。 比如第四個window創建時,所有的windows都會彈出“4”
在實際應用中,每個 window 都有自己的設置,並存儲在向量中。 每個window根據自己的序列號找到自己的設置:
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].
例如,第一個window會將它們的坐標設置為UserData[1].x和UserData[1].y,關閉時也需要保存文件。 有什么想法嗎?謝謝!
有幾種方法可以使用 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;
}
做類似事情的另一種方法是在注冊 window class 時使用cbWndExtra
額外字段,如this answer中所述。
你可以:
SetProp
, SetWindowLong
+ GWL_USERDATA
, SetWindowLong
+ cbWndExtra
std::map
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.