0

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;
}
IInspectable
  • 46,945
  • 8
  • 85
  • 181
A. Boz
  • 132
  • 1
  • 8
  • 4
    Define won't work. Won't compile? Won't do what you expect? Lies on the couch all day drinking beer and watching talk shows? – user4581301 Nov 01 '16 at 00:05
  • What version of Visual Studio do you use? Try `CLSID_WICImagingFactory1` or `CLSID_WICImagingFactory2` instead. Also show the rest of initialization. – Barmak Shemirani Nov 01 '16 at 00:11
  • 3
    Are you experiencing a compiler error, or a runtime error? If the latter, what `HRESULT` value does `CoCreateInstance()` actually return? That will tell you why it is failing. – Remy Lebeau Nov 01 '16 at 00:55
  • You could output the return value of `CoCreateInstance`, which will be a HRESULT that gives a clue as to why the creation failed – M.M Nov 01 '16 at 06:02
  • 1
    Do fix your coding style, you are returning "it did not work" error codes. Which is why you could not diagnose the problem. If a COM function fails then return its failure code. Automatically makes it debuggable, you've got an HRESULT to look at. – Hans Passant Nov 01 '16 at 10:11

1 Answers1

2

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.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • Thank you it works now. But this piece of code looks really unreadable and I realy dont understand what you did there :D – A. Boz Nov 01 '16 at 09:55
  • Fair enough. I've updated the answer with more explanation and references. The code snippet represents years worth of code review from lots of folks at Microsoft, so it really is trying to be 'best of breed'. – Chuck Walbourn Nov 01 '16 at 19:10