问题描述
我想在新线程中创建一个新的 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 方式处理的 - 当所有者不复存在时,获得的对象也不复存在。