Search code examples
c++comwic

CoCreateInstance dont work


I tried to make a Bitmap with direct2d. The problem is the function CoCreateInstance(...) it wont work

 HRESULT Renderer::InitImagingFactory()
{
    if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) return E_FAIL;


    if (FAILED(CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWICImagingFactory,
        reinterpret_cast<void **>(&m_imagingfactory)))) return E_FAIL;

    return S_OK;
}

Solution

  • There's two main reasons you could be hitting this.

    (1) You need to initialize COM before calling this function. For classic Win32 desktop apps, you'd do this with CoInitialize or CoInitializeEx. For Windows Runtime platforms you'd use Windows::Foundation::Initialize.

    HRESULT hr = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);
    if (FAILED(hr))
        // error
    

    (2) You need to make sure you have _WIN32_WINNT set correctly for your target platform--see Using the Windows Headers.

    For a classic Win32 desktop app, you probably want to use the following which initializes WIC2 on platforms that support it or WIC1 otherwise--code found in DirectXTex and DirectXTK's WICTextureLoader.

    #include <wincodec.h>
    
    namespace
    {
        bool g_WIC2 = false;
    }
    
    bool IsWIC2()
    {
        return g_WIC2;
    }
    
    IWICImagingFactory* GetWIC()
    {
        static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;
    
        IWICImagingFactory* factory = nullptr;
        InitOnceExecuteOnce(&s_initOnce,
            [](PINIT_ONCE, PVOID, PVOID *factory) -> BOOL
            {
            #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)
                HRESULT hr = CoCreateInstance(
                    CLSID_WICImagingFactory2,
                    nullptr,
                    CLSCTX_INPROC_SERVER,
                    __uuidof(IWICImagingFactory2),
                    factory
                    );
    
                if ( SUCCEEDED(hr) )
                {
                    // WIC2 is available on Windows 10, Windows 8.x, and Windows 7 SP1 with KB 2670838 installed
                    g_WIC2 = true;
                    return TRUE;
                }
                else
                {
                    hr = CoCreateInstance(
                        CLSID_WICImagingFactory1,
                        nullptr,
                        CLSCTX_INPROC_SERVER,
                        __uuidof(IWICImagingFactory),
                        factory
                        );
                    return SUCCEEDED(hr) ? TRUE : FALSE;
                }
            #else
                return SUCCEEDED( CoCreateInstance(
                    CLSID_WICImagingFactory,
                    nullptr,
                    CLSCTX_INPROC_SERVER,
                    __uuidof(IWICImagingFactory),
                    factory) ) ? TRUE : FALSE;
            #endif
            }, nullptr, reinterpret_cast<LPVOID*>(&factory));
    
        return factory;
    }
    

    This uses InitOnceExecuteOnce to ensure it's thread-safe. This ensures that the WIC factory is created exactly once no matter which thread calls GetWIC first. I'm using a C++11 lambda a.k.a. an anonymous function for the callback. The actual pointer to the WIC factory is stored inside the INIT_ONCE structure. See Using One-Time Initialization

    This code is designed to cover all the possible platform settings.

    • When building for Windows Store, Universal Windows Platform (UWP) apps, or Xbox then the _WIN32_WINNT variable will be set for Windows 8 or later. This would also apply to a classic Win32 desktop application that only supports Windows 8.0 or later.

    • When building for Windows 7 _WIN32_WINNT will be set to something below Windows 8. The Windows 8.x SDK and Windows 10 SDK WIC header supports both WIC and WIC version 2, but the WIC version 2 defines are not normally defined for Windows 7 or below builds. Therefore, you also use the _WIN7_PLATFORM_UPDATE preprocessor symbol in the build settings to get the wincodec.h header to define the WIC2 types even with _WIN32_WINNT is set to 0x0601 (Windows 7) or 0x0600 (Windows Vista). In this case, you need to handle cases where WIC2 support is not actually installed on the operating system and fallback to use the original WIC factory.

    • Otherwise, it just defaults to the default WIC factory which is going to be WIC version 1. This codepath would also build with older Windows SDK than the Windows 8.0 SDK which is the first one with the WIC2 types in wincodec.h.

    I have the IsWIC2 function because there are a few places where you need to know if the factory was in fact a WIC2 factory, in particular if you are trying to use the GUID_WICPixelFormat96bppRGBFloat, GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat64bppRGB, or GUID_WICPixelFormat64bppPRGBAHalf pixel formats. If you aren't using WIC2, then you'll need to use other formats instead.

    For details on what's different in WIC vs. WIC2, see MSDN as well as this blog post.