释放IWICImagingFactory COM对象时程序关闭触发段错误求助
问题分析与解决方案
你的段错误根源是未正确初始化COM库,同时消息循环和资源释放的逻辑也存在问题,具体如下:
核心问题
- COM库未初始化:WIC(Windows Imaging Component)是基于COM的组件,调用
CoCreateInstance创建IWICImagingFactory前,必须先调用CoInitialize或CoInitializeEx初始化COM环境。未初始化的情况下,COM对象的创建和释放都会触发内存错误。 - 消息循环逻辑错误:当前代码中仅在
msg.message == WM_QUIT时才释放资源,但PeekMessage在无消息时msg的内容是未定义的,可能导致资源释放逻辑被跳过或错误触发。 - 资源释放顺序与时机错误:
CoUninitialize必须在所有COM对象释放完成后调用,否则会导致已释放的COM对象引用无效内存。
修正后的代码
#include <Windows.h> #include <d2d1.h> #include <wincodec.h> template <class Interface> void SafeRelease(Interface *&pInterfaceToRelease) { if (pInterfaceToRelease != nullptr) { pInterfaceToRelease->Release(); pInterfaceToRelease = nullptr; } } LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR pCmdLine, int nCmdShow) { // 初始化COM库(单线程公寓模型,适合Direct2D/WIC场景) HRESULT hr = CoInitialize(nullptr); if (FAILED(hr)) { return -1; } // Register Window Class WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInst; wc.lpszClassName = L"Class Name"; RegisterClass(&wc); // Create and Show Window HWND hWnd = CreateWindowEx(0, L"Class Name", L"Test Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); ShowWindow(hWnd, nCmdShow); // Create d2d factory and render target ID2D1Factory *pD2DFactory = nullptr; ID2D1HwndRenderTarget *pRT = nullptr; D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory); RECT rc; GetClientRect(hWnd, &rc); pD2DFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), &pRT); // Create Imaging Factory IWICImagingFactory *pWICFactory = nullptr; CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pWICFactory)); // Start loop MSG msg = {}; while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); // 渲染逻辑放在消息处理后,避免消息堆积 if (pRT != nullptr) { pRT->BeginDraw(); pRT->Clear(D2D1::ColorF(D2D1::ColorF::CornflowerBlue)); HRESULT drawHr = pRT->EndDraw(); // 处理渲染目标丢失的情况(比如窗口大小变化) if (drawHr == D2DERR_RECREATE_TARGET) { // 这里可以重新创建渲染目标,示例中简化处理 SafeRelease(pRT); GetClientRect(hWnd, &rc); pD2DFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), &pRT); } } } // 按依赖顺序释放资源:先释放依赖对象,再释放工厂 SafeRelease(pRT); SafeRelease(pD2DFactory); SafeRelease(pWICFactory); UnregisterClass(L"Class Name", hInst); // 所有COM对象释放完成后,关闭COM库 CoUninitialize(); return static_cast<int>(msg.wParam); }
关键修改点说明
- 添加COM初始化:在程序开头调用
CoInitialize(nullptr),使用单线程公寓(STA)模型,这是Direct2D和WIC推荐的线程模型。 - 修正消息循环:改用
GetMessage替代PeekMessage的循环方式,更符合Windows消息循环的标准写法,确保收到WM_QUIT后才退出循环。 - 调整资源释放顺序:先释放
ID2D1HwndRenderTarget(依赖ID2D1Factory),再释放ID2D1Factory和IWICImagingFactory,最后调用CoUninitialize。 - 添加渲染错误处理:处理
EndDraw返回的D2DERR_RECREATE_TARGET错误,避免窗口大小变化导致的渲染异常。
编译命令保持不变
g++ -fdiagnostics-color=always -g test.cpp -municode -mwindows -ld2d1 -lole32 -lwindowscodecs -o test.exe
内容的提问来源于stack exchange,提问作者SetupWizard
相关产品推荐
相关产品推荐

