Compartir a través de


Cómo: Crear un componente COM clásico mediante WRL

Puede utilizar Biblioteca de plantillas de Windows Runtime C++ (WRL) para crear componentes COM clásicos básicos para su uso en aplicaciones de escritorio, además de utilizarlo para las aplicaciones de Tienda Windows.Para la creación de componentes COM, WRL puede requerir menos código que el ATL.Para obtener información sobre el subconjunto de COM que WRL admite, vea Biblioteca de plantillas de Windows Runtime C++ (WRL).

En este documento se muestra cómo utilizar WRL para crear un componente COM básico.Aunque puede utilizar el mecanismo de distribución que mejor se adapte a necesidades, este documento también muestra una forma básica de registrar y de utilizar el componente COM de una aplicación de escritorio.

Para utilizar WRL para crear un componente COM clásico básico

  1. En Visual Studio, cree un proyecto Solución en blanco.Denomine el proyecto, por ejemplo, WRLClassicCOM.

  2. Agregue Proyecto Win32 a la solución.Denomine el proyecto, por ejemplo, CalculatorComponent.En la pestaña Configuración de la aplicación, seleccione dll.

  3. Agregue un archivo Archivo MIDL (.idl) al proyecto.Asigne al archivo, por ejemplo, CalculatorComponent.idl.

  4. Agregue este código a CalculatorComponent.idl:

    import "ocidl.idl";
    
    [uuid(0DBABB94-CE99-42F7-ACBD-E698B2332C60), version(1.0)] 
    interface ICalculatorComponent : IUnknown
    {
        HRESULT Add([in] int a, [in] int b, [out, retval] int* value);
    }
    
    [uuid(9D3E6826-CB8E-4D86-8B14-89F0D7EFCD01), version(1.0)]
    library CalculatorComponentLib
    {
        [uuid(E68F5EDD-6257-4E72-A10B-4067ED8E85F2), version(1.0)]
        coclass CalculatorComponent
        {
            [default] interface ICalculatorComponent;
        }
    };
    
  5. En CalculatorComponent.cpp, defina la clase de CalculatorComponent.La clase de CalculatorComponent hereda de Microsoft::WRL::RuntimeClass.Microsoft::WRL::RuntimeClassFlags<ClassicCom> especifica que la clase deriva de IUnknown y no IInspectable.(IInspectable solo está disponible para los componentes de aplicación de Tienda .) CoCreatableClass crea un generador para la clase como CoCreateInstance la que se puede utilizar con funciones.

    #include "stdafx.h"
    
    #include "CalculatorComponent_h.h"
    #include <wrl.h>
    
    using namespace Microsoft::WRL;
    
    class CalculatorComponent: public RuntimeClass<RuntimeClassFlags<ClassicCom>, ICalculatorComponent>
    {
    public:
        CalculatorComponent()
        {
        }
    
        STDMETHODIMP Add(_In_ int a, _In_ int b, _Out_ int* value)
        {
            if (value == nullptr)
            {
                return E_POINTER;
            }
            *value = a + b;
            return S_OK;
        }
    };
    
    CoCreatableClass(CalculatorComponent);
    
  6. Utilice el código siguiente para reemplazar el código en dllmain.cpp.Este archivo define las funciones de exportación del archivo DLL.Estas funciones utilizan la clase de Microsoft::WRL::Module para administrar los generadores de clases para el módulo.

    #include "stdafx.h"
    #include <wrl\module.h>
    
    using namespace Microsoft::WRL;
    
    #if !defined(__WRL_CLASSIC_COM__)
    STDAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _COM_Outptr_ IActivationFactory** factory)
    {
        return Module<InProc>::GetModule().GetActivationFactory(activatibleClassId, factory);
    }
    #endif
    
    #if !defined(__WRL_WINRT_STRICT__)
    STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv)
    {
        return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
    }
    #endif
    
    STDAPI DllCanUnloadNow()
    {
        return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
    }
    
    STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
    {
        if (reason == DLL_PROCESS_ATTACH)
        {
            DisableThreadLibraryCalls(hinst);
        }
        return TRUE;
    }
    
  7. Agregue un archivo Archivo de definición de módulo (.def) al proyecto.Asigne al archivo, por ejemplo, CalculatorComponent.def.Este archivo proporciona al vinculador los nombres de las funciones que se exportarán.

  8. Agregue este código a CalculatorComponent.def:

    LIBRARY
    
    EXPORTS
        DllGetActivationFactory PRIVATE
        DllGetClassObject       PRIVATE
        DllCanUnloadNow         PRIVATE
    
  9. Agregue runtimeobject.lib a la línea del vinculador.Para obtener información sobre cómo, vea archivos .Lib como entrada del vinculador.

Para utilizar el componente COM de una aplicación de escritorio

  1. Registre el componente COM con el Registro de Windows.Para ello, cree un archivo de entradas de registro, llamar RegScript.reg, y agregar el texto siguiente.Reemplace <dll-path> con la ruta de DLL- para el ejemplo, C: \\temp\\WRLClassicCOM\\Debug\\CalculatorComponent .dll.

    Windows Registry Editor Version 5.00
    
    [HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{E68F5EDD-6257-4E72-A10B-4067ED8E85F2}]
    @="CalculatorComponent Class"
    
    [HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{E68F5EDD-6257-4E72-A10B-4067ED8E85F2}\InprocServer32]
    @="<dll-path>"
    "ThreadingModel"="Apartment"
    
    [HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{E68F5EDD-6257-4E72-A10B-4067ED8E85F2}\Programmable]
    
    [HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{E68F5EDD-6257-4E72-A10B-4067ED8E85F2}\TypeLib]
    @="{9D3E6826-CB8E-4D86-8B14-89F0D7EFCD01}"
    
    [HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{E68F5EDD-6257-4E72-A10B-4067ED8E85F2}\Version]
    @="1.0"
    
  2. Ejecute RegScript.reg o agréguelo a Evento posterior a la compilación del proyecto.Para obtener más información, vea Línea de comandos del evento anterior/posterior a la compilación (Cuadro de diálogo).

  3. Agregue un proyecto Aplicación de consola Win32 a la solución.Denomine el proyecto, por ejemplo, Calculadora.

  4. Utilice este código para reemplazar el contenido de Calculator.cpp:

    #include "stdafx.h"
    
    #include "..\CalculatorComponent\CalculatorComponent_h.h"
    
    const IID IID_ICalculatorComponent = {0x0DBABB94,0xCE99,0x42F7,0xAC,0xBD,0xE6,0x98,0xB2,0x33,0x2C,0x60};
    const CLSID CLSID_CalculatorComponent = {0xE68F5EDD,0x6257,0x4E72,0xA1,0x0B,0x40,0x67,0xED,0x8E,0x85,0xF2};
    
    // Prints an error string for the provided source code line and HRESULT
    // value and returns the HRESULT value as an int.
    int PrintError(unsigned int line, HRESULT hr)
    {
        wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr);
        return hr;
    }
    
    int wmain()
    {
        HRESULT hr;
    
        // Initialize the COM library.
        hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
        if (FAILED(hr))
        {
            return PrintError(__LINE__, hr);
        }
    
        ICalculatorComponent* calc = nullptr; // Interface to COM component.
    
        // Create the CalculatorComponent object.
        hr = CoCreateInstance(CLSID_CalculatorComponent, nullptr, CLSCTX_INPROC_SERVER, IID_ICalculatorComponent, reinterpret_cast<void**>(&calc));
        if (SUCCEEDED(hr))
        {
            // Test the component by adding two numbers.
            int result;
            hr = calc->Add(4, 5, &result);
            if (FAILED(hr))
            {
                PrintError(__LINE__, hr);
            }
            else
            {
                wprintf_s(L"result = %d\n", result);
            }
    
            // Free the CalculatorComponent object.
            calc->Release();
        }
        else
        {
            // Object creation failed. Print a message.
            PrintError(__LINE__, hr);
        }
    
        // Free the COM library.
        CoUninitialize();
    
        return hr;
    }
    /* Output:
    result = 9
    */
    

Programación eficaz

Este documento utiliza funciones COM estándar para mostrar que puede utilizar WRL para crear un componente COM y para ponerla a disposición de las tecnologías COM- habilitada.También puede utilizar los tipos de WRL como Microsoft::WRL::ComPtr en la aplicación de escritorio para administrar la duración de COM y otros objetos.El código siguiente utiliza WRL para administrar la duración del puntero de ICalculatorComponent.La clase de CoInitializeWrapper es un contenedor RAII que garantiza que la biblioteca COM se liberará y también las garantías que la duración de la biblioteca COM sobrevive al objeto de puntero inteligente de ComPtr.

#include "stdafx.h"
#include <wrl.h>

#include "..\CalculatorComponent\CalculatorComponent_h.h"

using namespace Microsoft::WRL;

const IID IID_ICalculatorComponent = {0x0DBABB94,0xCE99,0x42F7,0xAC,0xBD,0xE6,0x98,0xB2,0x33,0x2C,0x60};
const CLSID CLSID_CalculatorComponent = {0xE68F5EDD,0x6257,0x4E72,0xA1,0x0B,0x40,0x67,0xED,0x8E,0x85,0xF2};

// Prints an error string for the provided source code line and HRESULT
// value and returns the HRESULT value as an int.
int PrintError(unsigned int line, HRESULT hr)
{
    wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr);
    return hr;
}

int wmain()
{
    HRESULT hr;

    // RAII wrapper for managing the lifetime of the COM library.
    class CoInitializeWrapper
    {
        HRESULT _hr;
    public:
        CoInitializeWrapper(DWORD flags)
        {
            _hr = CoInitializeEx(nullptr, flags);
        }
        ~CoInitializeWrapper()
        {
            if (SUCCEEDED(_hr))
            {
                CoUninitialize();
            }
        }
        operator HRESULT()
        {
            return _hr;
        }

    };

    // Initialize the COM library.
    CoInitializeWrapper initialize(COINIT_APARTMENTTHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }

    ComPtr<ICalculatorComponent> calc; // Interface to COM component.

    // Create the CalculatorComponent object.
    hr = CoCreateInstance(CLSID_CalculatorComponent, nullptr, CLSCTX_INPROC_SERVER, IID_ICalculatorComponent, reinterpret_cast<void**>(calc.GetAddressOf()));
    if (SUCCEEDED(hr))
    {
        // Test the component by adding two numbers.
        int result;
        hr = calc->Add(4, 5, &result);
        if (FAILED(hr))
        {
            return PrintError(__LINE__, hr);
        }
        wprintf_s(L"result = %d\n", result);
    }
    else
    {
        // Object creation failed. Print a message.
        return PrintError(__LINE__, hr);
    }

    return 0;
}

Vea también

Conceptos

Biblioteca de plantillas de Windows Runtime C++ (WRL)