How to: Instantiate WRL Components Directly

Learn how to use the Windows Runtime C++ Template Library (WRL)Microsoft::WRL::Make and Microsoft::WRL::Details::MakeAndInitialize functions to instantiate a component from the module that defines it.

By instantiating components directly, you can reduce overhead when you don't need class factories or other mechanisms. You can instantiate a component directly in both Universal Windows Platform apps and in desktop apps.

To learn how to use Windows Runtime C++ Template Library to create a classic COM component and instantiate it from an external desktop app, see How to: Create a Classic COM Component.

This document shows two examples. The first example uses the Make function to instantiate a component. The second example uses the MakeAndInitialize function to instantiate a component that can fail during construction. (Because COM typically uses HRESULT values, instead of exceptions, to indicate errors, a COM type typically does not throw from its constructor. MakeAndInitialize enables a component to validate its construction arguments through the RuntimeClassInitialize method.) Both examples define a basic logger interface and implement that interface by defining a class that writes messages to the console.

Important

You can't use the new operator to instantiate Windows Runtime C++ Template Library components. Therefore, we recommend that you always use Make or MakeAndInitialize to instantiate a component directly.

To create and instantiate a basic logger component

  1. In Visual Studio, create a Win32 Console Application project. Name the project, for example, WRLLogger.

  2. Add a Midl File (.idl) file to the project, name the file ILogger.idl, and then add this code:

    import "ocidl.idl";
    
    // Prints text to the console.
    [uuid(AFDB9683-F18A-4B85-90D1-B6158DAFA46C)]
    interface ILogger : IUnknown
    {
        HRESULT Log([in] LPCWSTR text);
    }
    
  3. Use the following code to replace the contents of WRLLogger.cpp.

    #include "pch.h" // Use stdafx.h in Visual Studio 2017 and earlier
    #include <wrl\implements.h>
    #include <comutil.h>
    
    #include "ILogger_h.h"
    
    using namespace Microsoft::WRL;
    
    // Writes logging messages to the console.
    class CConsoleWriter : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ILogger>
    {
    public:
        STDMETHODIMP Log(_In_ PCWSTR text)
        {
            wprintf_s(L"%s\n", text);
            return S_OK;
        }
    
    private:
        // Make destroyable only through Release.
        ~CConsoleWriter()
        {
        }
    };
    
    int wmain()
    {
        ComPtr<CConsoleWriter> writer = Make<CConsoleWriter>();
        HRESULT hr = writer->Log(L"Logger ready.");
        return hr;
    }
    
    /* Output:
    Logger ready.
    */
    

To handle construction failure for the basic logger component

  1. Use the following code to replace the definition of the CConsoleWriter class. This version holds a private string member variable and overrides the RuntimeClass::RuntimeClassInitialize method. RuntimeClassInitialize fails if the call to SHStrDup fails.

    // Writes logging messages to the console.
    class CConsoleWriter : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ILogger>
    {
    public:
        // Initializes the CConsoleWriter object.
        // Failure here causes your object to fail construction with the HRESULT you choose.
        HRESULT RuntimeClassInitialize(_In_ PCWSTR category)
        {
            return SHStrDup(category, &m_category);
        }
    
        STDMETHODIMP Log(_In_ PCWSTR text)
        {
            wprintf_s(L"%s: %s\n", m_category, text);
            return S_OK;
        }
    
    private:
        PWSTR m_category;
    
        // Make destroyable only through Release.
        ~CConsoleWriter()
        {
            CoTaskMemFree(m_category);
        }
    };
    
  2. Use the following code to replace the definition of wmain. This version uses MakeAndInitialize to instantiate the CConsoleWriter object and checks the HRESULT result.

    int wmain()
    {
        ComPtr<CConsoleWriter> writer;
        HRESULT hr = MakeAndInitialize<CConsoleWriter>(&writer, L"INFO");
        if (FAILED(hr))
        {
            wprintf_s(L"Object creation failed. Result = 0x%x", hr);
            return hr;
        }
        hr = writer->Log(L"Logger ready.");
        return hr;
    }
    
    /* Output:
    INFO: Logger ready.
    */
    

See also

Windows Runtime C++ Template Library (WRL)
Microsoft::WRL::Make
Microsoft::WRL::Details::MakeAndInitialize