简体   繁体   中英

How to create a new window in a speparate thread?

I'd like to create a new POPUP style window in a new thread. Here is the code I have so far.

#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
#include <tchar.h>
#include <thread>
#include <string>

#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;
using namespace std;

const wchar_t g_szClassName[] = L"Skeleton";
const wchar_t g_szChildClassName[] = L"Child";

wchar_t msgbuf[100];
char msgbuf_ansi[100];
WNDCLASSEX wc;

struct MyStruct
{
    WNDCLASSEX wc;
    HWND hWnd;
    HINSTANCE hInst;
    int nCmdShow;
};

MyStruct g_myStruct;
LRESULT CALLBACK WndProcChild(HWND, UINT, WPARAM, LPARAM);

void Example_DrawImage9(HDC hdc) {
    Graphics graphics(hdc);
    Image image(L"C:/Users/Darek/Fallout2_older/data/art/iface/armor_info.bmp");
    graphics.DrawImage(&image, 0, 0);
}

int task1(MyStruct myStruct)
{
    sprintf_s(msgbuf_ansi, ("thread\n"));
    OutputDebugStringA(msgbuf_ansi);

    HWND hwnd_child;

    myStruct.wc.lpfnWndProc = WndProcChild;
    myStruct.wc.lpszClassName = g_szChildClassName;

    if (!RegisterClassEx(&myStruct.wc)) {
        MessageBox(NULL, L"thread - Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd_child = CreateWindowEx(0, g_szChildClassName, L"Child", WS_POPUP | WS_BORDER, 200, 0, 190, 110, myStruct.hWnd, 0, myStruct.hInst, 0);

    swprintf_s(msgbuf, _T("THREAD - CHILD -  hwnd: %02X\n"), (int)hwnd_child);
    OutputDebugString(msgbuf);

    if (hwnd_child == NULL) {
        MessageBox(NULL, L"thread - Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    SetWindowLong(hwnd_child, GWL_EXSTYLE, GetWindowLong(hwnd_child, GWL_EXSTYLE) | WS_EX_LAYERED);
    SetLayeredWindowAttributes(hwnd_child, 0, 128, LWA_ALPHA);
    ShowWindow(hwnd_child, myStruct.nCmdShow);
    UpdateWindow(hwnd_child);
}
thread t1;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {

        //case WM_KEYDOWN:

    case WM_CLOSE:
        swprintf_s(msgbuf, _T("WM_CLOSE - PARENT \n"));
        OutputDebugString(msgbuf);
        if (MessageBox(hwnd, L"Really quit?", L"My application", MB_OKCANCEL) == IDOK)
        {
            DestroyWindow(hwnd);
        }
        return 0;

    case WM_DESTROY:
        swprintf_s(msgbuf, _T("WM_DESTROY - PARENT \n"));
        OutputDebugString(msgbuf);
        PostQuitMessage(0);
        return 0;

    case WM_CREATE: {
        swprintf_s(msgbuf, _T("WM_CREATE - PARENT \n"));
        OutputDebugString(msgbuf);
        thread t1(task1, g_myStruct);
        t1.join();
        return 0;
    }

    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
int g_fMouseTracking = FALSE;
LRESULT CALLBACK WndProcChild(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {
    case WM_PAINT:
        HDC hdc;
        PAINTSTRUCT ps;

        swprintf_s(msgbuf, _T("WM_PAINT - CHILD -  hwnd: %02X\n"), (int)hwnd);
        OutputDebugString(msgbuf);

        hdc = BeginPaint(hwnd, &ps);
        Example_DrawImage9(hdc);
        EndPaint(hwnd, &ps);

        return 0;

        //case WM_KEYDOWN:

    case WM_CREATE: {
        swprintf_s(msgbuf, _T("WM_CREATE - CHILD \n"));
        OutputDebugString(msgbuf);
        return 0;
    }

    case WM_MOUSEMOVE:
        swprintf_s(msgbuf, _T("WM_MOUSEMOVE - CHILD -  hwnd: %02X\n"), (int)hwnd);
        OutputDebugString(msgbuf);

        if (!g_fMouseTracking)
        {
            // start tracking if we aren't already
            TRACKMOUSEEVENT tme = {};
            tme.cbSize = sizeof(TRACKMOUSEEVENT);
            tme.dwFlags = TME_HOVER | TME_LEAVE;
            tme.hwndTrack = hwnd;
            tme.dwHoverTime = HOVER_DEFAULT;

            g_fMouseTracking = TrackMouseEvent(&tme);
        }

        return 0;

    case WM_MOUSELEAVE:
        swprintf_s(msgbuf, _T("WM_MOUSELEAVE  - CHILD -  hwnd: %02X\n"), (int)hwnd);
        OutputDebugString(msgbuf);

        g_fMouseTracking = FALSE; // tracking now canceled

        return 0;

    case WM_CLOSE:
        swprintf_s(msgbuf, _T("WM_CLOSE - CHILD \n"));
        OutputDebugString(msgbuf);
        /*if (MessageBox(hwnd, L"Really quit?", L"My application", MB_OKCANCEL) == IDOK)
        {
            DestroyWindow(hwnd);
        }*/
        return 0;

    case WM_DESTROY:
        swprintf_s(msgbuf, _T("WM_DESTROY - CHILD \n"));
        OutputDebugString(msgbuf);
        PostQuitMessage(0);
        return 0;

    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    //WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    ULONG_PTR token;
    GdiplusStartupInput input = { 0 };
    input.GdiplusVersion = 1;
    GdiplusStartup(&token, &input, NULL);

    //Step 1: Registering the Window Class
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    g_myStruct.wc = wc;
    
    g_myStruct.hInst = hInstance;
    g_myStruct.nCmdShow = nCmdShow;

    if (!RegisterClassEx(&wc)) {
        MessageBox(NULL, L"Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowEx(0, g_szClassName, L"Skeleton", WS_BORDER, 0, 0, 190, 110, 0, 0, hInstance, 0);
    g_myStruct.hWnd = hwnd;
    if (hwnd == NULL) {
        MessageBox(NULL, L"Parent Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    swprintf_s(msgbuf, _T("MAIN - PARENT -  hwnd: %02X\n"), (int)hwnd);
    OutputDebugString(msgbuf);

    SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
    SetLayeredWindowAttributes(hwnd, 0, 128, LWA_ALPHA);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&Msg, NULL, 0, 0) > 0) {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    return Msg.wParam;
}

The problems is that as I've debugged the child window is indeed created but automatically/magically destroyed when the WndProcChild returns.

How to correct the code to have it run as expected (the child window stays open until the main is't destroyed)?

The thread own the window it had created and its message queue and therefore must provide an event loop. It's destroyed because in Win API ownership is treated in RAII way - when owner ceases to exist, so do the acquired objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM