微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在单独的线程中创建一个新窗口?

如何解决如何在单独的线程中创建一个新窗口?

我想在新线程中创建一个新的 POPUP 样式窗口。这是我到目前为止的代码

#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);
}

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,190,110,myStruct.hWnd,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!",MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    SetwindowLong(hwnd_child,GWL_EXSTYLE,getwindowlong(hwnd_child,GWL_EXSTYLE) | WS_EX_layered);
    SetlayeredWindowAttributes(hwnd_child,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,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,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,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!",MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

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

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

    SetwindowLong(hwnd,getwindowlong(hwnd,GWL_EXSTYLE) | WS_EX_layered);
    SetlayeredWindowAttributes(hwnd,LWA_ALPHA);
    ShowWindow(hwnd,nCmdshow);
    UpdateWindow(hwnd);

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

    return Msg.wParam;
}

问题在于,当我调试时,子窗口确实创建了,但在 WndProcChild 返回时会自动/神奇地销毁。

如何更正代码以使其按预期运行(子窗口保持打开状态,直到主窗口没有被销毁)?

解决方法

线程拥有它创建的窗口和它的消息队列,因此必须提供一个事件循环。它被销毁是因为在 Win API 中所有权是以 RAII 方式处理的 - 当所有者不复存在时,获得的对象也不复存在。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。