c++ Win32 Api 线程内的 GetMessage 关闭程序
c++ Win32 Api GetMessage closing program inside thread
我正在使用 win32 api 构建一个界面,我想在另一个 class 中用一个线程来管理所有的东西,以继续在 main 中工作。
我有这个代码:
WindowManager.h
class UIManager::WindowManager {
private:
//Class data
HINSTANCE hInstance;
WNDCLASSEX winClass; /* Data structure for the windowclass */
MSG msg;
HWND hwnd;
//Window Data
LPCSTR wiName;
int startX = 250;
int startY = 150;
int endX = 544;
int endY = 375;
//Private managers
void makeWindow();
public:
WindowManager(HINSTANCE & hInstance, std::string wiName = "Window Name");
void show();
};
WindowManager.c(我使用 bind 是因为我在命名空间中有 class,这是我发现线程允许我编译的唯一方法而不是抛出错误)
#include "WindowManager.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//Private
//
void UIManager::WindowManager::makeWindow()
{
int ms = GetMessage(&msg, 0, 0, 0); //I do this to see if it gets to
while (GetMessage(&msg, NULL, 0, 0)) { //this part, but never happens
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//Public
//
UIManager::WindowManager::WindowManager(HINSTANCE & hInstance, std::string wiName)
{
this->wiName = wiName.c_str();
this->hInstance = hInstance;
winClass.cbSize = sizeof(winClass);
winClass.hInstance = hInstance;
winClass.lpszClassName = this->wiName;
winClass.lpfnWndProc = WndProc; //Execution callback
//Load default editable ellements
winClass.hCursor = LoadCursor(0, IDC_ARROW); /*Default*/
winClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); /*Default*/ //Alt+Tab Dialog
winClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
winClass.lpszMenuName = NULL; /* No menu */
RegisterClassEx(&winClass);
//Create Window
hwnd = CreateWindowEx(
0,
this->wiName, /* Title Class */
this->wiName, /* Title Text */
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
startX, /* X Start */
startY, /* Y Start */
endX, /* The programs width */
endY, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hInstance, /* Program Instance handler */
NULL
);
SetWindowPos(hwnd, 0, 0, 0, 20, 20, 0);
}
void UIManager::WindowManager::show()
{
std::thread listener(std::bind(&WindowManager::makeWindow, this));
listener.detach();
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{ //This part is executed
//...blablabla
break;
}
case WM_COMMAND:
{//This part is never executed
//...blablabla
break;
}
case WM_DESTROY:
{//This part is never executed
//...blabla
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
window 执行和显示正确,甚至执行 WM_CREATE,但是当 "GetMessage" 执行时它立即结束程序而没有抛出任何错误或类似的东西。
我用 GetMessage 的值添加了一个 int 以查看它是否在调试模式下到达 "while" 但它确实发生了。
有没有办法查看可能抛出的错误或阻止它关闭程序?还是我在线程内部调用 "GetMessage" 时做错了?
您的代码有几个问题:
- 您在一个线程中创建 window,但尝试在另一个线程中 运行 消息循环。
GetMessage
仅处理属于调用线程的 windows 的消息。
- 您永远不会等待后台线程处理消息,而是与其分离并继续在可能结束应用程序的主线程中执行。
- 您不检查
GetMessage
返回的值并将其用作布尔值。
如果您想创建后台 ui 线程,您需要将所有 window 创建代码移到那里并在线程上调用 join
。消息循环应该是这样的:
::MSG msg;
for(;;)
{
auto const res{::GetMessage(&msg, NULL, 0, 0))};
if(0 < res)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else if(0 == res)
{ // PostQuitMessage was called...
break;
}
else
{ // an error occurred...
break;
}
}
我正在使用 win32 api 构建一个界面,我想在另一个 class 中用一个线程来管理所有的东西,以继续在 main 中工作。 我有这个代码:
WindowManager.h
class UIManager::WindowManager {
private:
//Class data
HINSTANCE hInstance;
WNDCLASSEX winClass; /* Data structure for the windowclass */
MSG msg;
HWND hwnd;
//Window Data
LPCSTR wiName;
int startX = 250;
int startY = 150;
int endX = 544;
int endY = 375;
//Private managers
void makeWindow();
public:
WindowManager(HINSTANCE & hInstance, std::string wiName = "Window Name");
void show();
};
WindowManager.c(我使用 bind 是因为我在命名空间中有 class,这是我发现线程允许我编译的唯一方法而不是抛出错误)
#include "WindowManager.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//Private
//
void UIManager::WindowManager::makeWindow()
{
int ms = GetMessage(&msg, 0, 0, 0); //I do this to see if it gets to
while (GetMessage(&msg, NULL, 0, 0)) { //this part, but never happens
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//Public
//
UIManager::WindowManager::WindowManager(HINSTANCE & hInstance, std::string wiName)
{
this->wiName = wiName.c_str();
this->hInstance = hInstance;
winClass.cbSize = sizeof(winClass);
winClass.hInstance = hInstance;
winClass.lpszClassName = this->wiName;
winClass.lpfnWndProc = WndProc; //Execution callback
//Load default editable ellements
winClass.hCursor = LoadCursor(0, IDC_ARROW); /*Default*/
winClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); /*Default*/ //Alt+Tab Dialog
winClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
winClass.lpszMenuName = NULL; /* No menu */
RegisterClassEx(&winClass);
//Create Window
hwnd = CreateWindowEx(
0,
this->wiName, /* Title Class */
this->wiName, /* Title Text */
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
startX, /* X Start */
startY, /* Y Start */
endX, /* The programs width */
endY, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hInstance, /* Program Instance handler */
NULL
);
SetWindowPos(hwnd, 0, 0, 0, 20, 20, 0);
}
void UIManager::WindowManager::show()
{
std::thread listener(std::bind(&WindowManager::makeWindow, this));
listener.detach();
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{ //This part is executed
//...blablabla
break;
}
case WM_COMMAND:
{//This part is never executed
//...blablabla
break;
}
case WM_DESTROY:
{//This part is never executed
//...blabla
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
window 执行和显示正确,甚至执行 WM_CREATE,但是当 "GetMessage" 执行时它立即结束程序而没有抛出任何错误或类似的东西。
我用 GetMessage 的值添加了一个 int 以查看它是否在调试模式下到达 "while" 但它确实发生了。 有没有办法查看可能抛出的错误或阻止它关闭程序?还是我在线程内部调用 "GetMessage" 时做错了?
您的代码有几个问题:
- 您在一个线程中创建 window,但尝试在另一个线程中 运行 消息循环。
GetMessage
仅处理属于调用线程的 windows 的消息。 - 您永远不会等待后台线程处理消息,而是与其分离并继续在可能结束应用程序的主线程中执行。
- 您不检查
GetMessage
返回的值并将其用作布尔值。
如果您想创建后台 ui 线程,您需要将所有 window 创建代码移到那里并在线程上调用 join
。消息循环应该是这样的:
::MSG msg;
for(;;)
{
auto const res{::GetMessage(&msg, NULL, 0, 0))};
if(0 < res)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else if(0 == res)
{ // PostQuitMessage was called...
break;
}
else
{ // an error occurred...
break;
}
}