簡體   English   中英

單個 wndproc 如何讓每個 window 知道它的序列號?

[英]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中所述

你可以:

  • 確實將數據存儲在 Window 中。 SetProp , SetWindowLong + GWL_USERDATA , SetWindowLong + cbWndExtra
  • Map HWND 到您的數據,例如使用 c++ std::map
  • 使用 thunk 獲得關聯的 object,如 ATL,請參閱ATL thunk header以獲取可用的 API(對於較舊的操作系統,必須手動執行)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM