将 Win32/WinAPI 应用程序移植到 wxWidgets

Port Win32/WinAPI application to wxWidgets

本文关键字:wxWidgets 应用程序 Win32 WinAPI      更新时间:2023-10-16

我目前正在使用Windows 10,MSVC v142(VS2019(和wxWidgets 3.1.3。我有一个旧的Windows C++应用程序,它使用WinAPI作为其GUI功能,即Windows消息循环,使用"CreateWindow",并且必须"手动"创建所有窗口过程和事件处理。

我想通过使用 wxWidgets 逐步替换 UI 来改进此应用程序,这样我就不必从头开始。我会在wxWidgets中实现新的,独立的UI功能(例如特定的对话框(,然后回到过去,用wxWidgets实现替换所有旧的UI代码,而不必在此过程中破坏应用程序。

以下是我的应用当前设置方式的框架:

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)    
{
// Handling window messages, e.g menus, buttons, etc.
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* lpCmdLine, int nCmdShow)
{
// Initialize resources, register main window class using MainWndProc, etc.
// ...
HWND mainwnd = CreateWindow(/* CreateWindow args... */);

do
{
MSG msg = {};
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Per-frame application logic
// ...
} while (msg.message != WM_QUIT);

// Clean up resources
// ...
return 0;
}

我需要如何修改它,以便所有 WinAPI 对象继续运行,但现在我也可以使用 wxWidgets 创建窗口?我之前尝试通过从wxApp派生的自定义类初始化 wxWidgets 来替换上面的消息循环,但我的应用程序在清理代码期间不断崩溃(有时甚至无法达到(。

编辑:我设法让它工作,更新的骨架可以在下面找到。

// Main WinAPI window procedure
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)    
{
switch (uMsg)
{
// Code to handle other messages
// ...
case WM_CLOSE:
// Closing this window should shut down the app
PostQuitMessage(0);
break;
}

return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit() override
{
if(!Old_Init())
{
// Perform cleanup in case something goes wrong
Old_Exit();
return false;
}

// Wrap the WinAPI window in a dummy wxWindow
m_dummyMainWindow = new wxWindow();
m_dummyMainWindow->SetHWND(m_mainWnd);

return true;
}

int OnExit() override
{
// Unset the dummy window HWND and delete it (is this necessary?)
m_dummyMainWindow->SetHWND(NULL);
delete m_dummyMainWindow;

// Clean up everything else
return Old_Exit();
}

private:
bool Old_Init()
{
// Perform the old initialization
// ...
m_mainWnd = CreateWindow(/* CreateWindow args... */);

if(m_mainWnd)
{   
return true;
}
else
{
return false;
}
}

int Old_Exit()
{
// Perform the old cleanup (previously done after exiting the Windows message loop)
// ...
return 0;
}

HWND m_mainWnd;
wxWindow* m_dummyMainWindow;
};
wxIMPLEMENT_APP_NO_MAIN(MyApp);
// App entrypoint
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* lpCmdLine, int nCmdShow)
{
if (wxEntry())
{
// Exit if something goes wrong (this might not be the correct way to do it?)
wxExit();
}

return 0;
}

这似乎确实有效,所有旧的 UI 元素都像以前一样工作,但我不能 100% 确定这是一个稳定的解决方案。我的调试器警告我有关内存泄漏的信息,当我激活 UI 元素(例如打开和关闭对话框(时,内存泄漏的数量似乎会增加。我怀疑 WinAPI 资源可能无法正确清理。我错过了什么吗?

EDIT2:我做了更多的调试,我的原始应用程序中的代码(即没有wxWidgets(也会导致这些"内存泄漏",我无法在最小的工作示例中复制它,所以我怀疑这个问题与wxWidgets完全无关。因此,我相信上述方法应该可以解决我的问题,但我不介意第二种意见。

我建议查看 MFC 示例,以查看接近您想要执行的操作的工作示例。 当然,MFC 与 Win32 API 并不完全相同,但它仍然应该是一个很好的起点。

值得注意的是,它显示了当您运行自己的消息时如何将消息传递给wx事件循环(这部分在include/wx/msw/mfc.hwxMFCApp类中(。当然,如果可以切换到运行wx事件循环,那就更简单了。

您可能还会发现,您可以使用AssociateHandle()将您创建HWND包装到wxWindow中,并通过覆盖MSWHandleMessage()甚至仅直接使用wxNativeWindow来处理其消息,这很有帮助。

祝你好运!