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;
}
In the above code, when I create multiple windows and click it, it should pop up "1", "2", "3"... But actually all pop up "1".
static int MeIs = 0;
case WM_CREATE:
{
MeIs = Num;
}
Change to the above code and the serial number of the last window will pop up. For example, when the fourth window is created, all windows will pop up "4"
In practical application, each window has its own settings and is stored in the vector. Each window finds its own settings according to its own serial number:
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].
For example,the first window will set their coordinates to UserData[1].x and UserData[1].y,also need to save the file when closing. Any idea?thank you!
CodePudding user response:
There are a couple of ways to maintain per-window data using the Win32 API.
The simplest is using the GWL_USERDATA
slot accessible via GetWindowLongPtr(...)
and SetWindowLongPtr(...)
. A typical way to initialize this user data value is to use the creation parameters passed to the WM_CREATE
message by the CreateWindow
call.
Code below:
#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;
}
Another way to do something similar is to use the cbWndExtra
extra field when registering the window class, as discussed in this answer.
CodePudding user response:
You can:
- Indeed store data in Window.
SetProp
,SetWindowLong
GWL_USERDATA
,SetWindowLong
cbWndExtra
- Map HWND to your data, like using c
std::map
- Use a thunk to have an associated object, like ATL, see ATL thunk header for available APIs (have to do it manually for older OSes)