Nasıl yapılır: WRL Kullanarak Klasik COM Bileşeni Oluşturma

Windows Çalışma Zamanı C++ Şablon Kitaplığı'nı (WRL) kullanarak masaüstü uygulamalarında kullanılmak üzere temel klasik COM bileşenleri oluşturabilir ve bunu Evrensel Windows Platformu (UWP) uygulamalarında kullanabilirsiniz. COM bileşenlerinin oluşturulması için Windows Çalışma Zamanı C++ Şablon Kitaplığı ATL'den daha az kod gerektirebilir. Windows Çalışma Zamanı C++ Şablon Kitaplığı'nın desteklediği COM alt kümesi hakkında bilgi için bkz. Windows Çalışma Zamanı C++ Şablon Kitaplığı (WRL).

Bu belgede, temel bir COM bileşeni oluşturmak için Windows Çalışma Zamanı C++ Şablon Kitaplığı'nın nasıl kullanılacağı gösterilmektedir. Gereksinimlerinize en uygun dağıtım mekanizmasını kullanabilirsiniz, ancak bu belge bir masaüstü uygulamasından COM bileşenini kaydetmenin ve kullanmanın temel bir yolunu da gösterir.

Windows Çalışma Zamanı C++ Şablon Kitaplığı'nı kullanarak temel bir klasik COM bileşeni oluşturmak için

  1. Visual Studio'da Boş Çözüm projesi oluşturun. Projeyi adlandırın, örneğin, WRLClassicCOM.

  2. Çözüme bir Win32 Projesi ekleyin. Projeyi adlandırın, örneğin, CalculatorComponent. Uygulama Ayarlar sekmesinde DLL'yi seçin.

  3. Projeye midl dosyası (.idl) dosyası ekleyin. Dosyayı adlandırın, örneğin, CalculatorComponent.idl.

  4. Bu kodu CalculatorComponent.idl'ye ekleyin:

    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. CalculatorComponent.cpp dosyasında sınıfını CalculatorComponent tanımlayın. CalculatorComponent sınıfı Microsoft::WRL::RuntimeClass'tan devralır. Microsoft::WRL::RuntimeClassFlags<ClassicCom>, sınıfın IInspectable'dan değil, IUnknown'dan türetildiğini belirtir. (IInspectableyalnızca Windows Çalışma Zamanı uygulama bileşenleri için kullanılabilir.) CoCreatableClass sınıfı için CoCreateInstance gibi işlevlerle kullanılabilecek bir fabrika oluşturur.

    #include "pch.h" // Use stdafx.h in Visual Studio 2017 and earlier
    
    #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)
        {
            *value = a + b;
            return S_OK;
        }
    };
    
    CoCreatableClass(CalculatorComponent);
    
  6. içindeki dllmain.cppkodu değiştirmek için aşağıdaki kodu kullanın. Bu dosya DLL dışarı aktarma işlevlerini tanımlar. Bu işlevler, modülün sınıf fabrikalarını yönetmek için Microsoft::WRL::Module sınıfını kullanır.

    #include "pch.h" // Use stdafx.h in Visual Studio 2017 and earlier
    #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. Projeye bir Modül Tanımı Dosyası (.def) dosyası ekleyin. Dosyayı adlandırın, örneğin, CalculatorComponent.def. Bu dosya bağlayıcıya dışarı aktarılacak işlevlerin adlarını verir. Projenizin Özellik Sayfaları iletişim kutusunu açın, ardından Yapılandırma Özellikleri Bağlayıcı>Girişi'nin> altında Modül Tanımı Dosyası özelliğini DEF dosyanıza ayarlayın.

  8. Bu kodu CalculatorComponent.def'ye ekleyin:

    LIBRARY
    
    EXPORTS
        DllGetActivationFactory PRIVATE
        DllGetClassObject       PRIVATE
        DllCanUnloadNow         PRIVATE
    
  9. Bağlayıcı satırına runtimeobject.lib ekleyin. Nasıl yapılacağını öğrenmek için bkz .Lib . Bağlayıcı Girişi Olarak Dosyalar.

Masaüstü uygulamasından COM bileşenini kullanmak için

  1. COM bileşenini Windows Kayıt Defteri'ne kaydedin. Bunu yapmak için bir kayıt girdileri dosyası oluşturun, adını verin RegScript.regve aşağıdaki metni ekleyin. dll-path değerini DLL'nizin yoluyla değiştirin<; örneğin, 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. RegScript.reg dosyasını çalıştırın veya projenizin Derleme Sonrası Etkinliğine ekleyin. Daha fazla bilgi için bkz . Derleme Öncesi Olay/Derleme Sonrası Olay Komut Satırı İletişim Kutusu.

  3. Çözüme bir Win32 Konsol Uygulaması projesi ekleyin. Projeyi adlandırın, örneğin, Calculator.

  4. içeriğini Calculator.cppdeğiştirmek için bu kodu kullanın:

    #include "pch.h" // Use stdafx.h in Visual Studio 2017 and earlier
    
    #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_PPV_ARGS(&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
    */
    

Güçlü Programlama

Bu belgede, com bileşeni yazmak ve COM özellikli herhangi bir teknoloji için kullanılabilir hale getirmek için Windows Çalışma Zamanı C++ Şablon Kitaplığı'nı kullanabileceğinizi göstermek için standart COM işlevleri kullanılmaktadır. COM ve diğer nesnelerin ömrünü yönetmek için masaüstü uygulamanızda Microsoft::WRL::ComPtr gibi Windows Çalışma Zamanı C++ Şablon Kitaplığı türlerini de kullanabilirsiniz. Aşağıdaki kod, işaretçinin ömrünü yönetmek için Windows Çalışma Zamanı C++ Şablon Kitaplığı'nı ICalculatorComponent kullanır. CoInitializeWrapper sınıfı, COM kitaplığının serbest olduğunu garanti eden ve ayrıca COM kitaplığının ömrünün akıllı işaretçi nesnesinden ComPtr daha uzun olduğunu garanti eden bir RAII sarmalayıcıdır.

#include "pch.h" // Use stdafx.h in Visual Studio 2017 and earlier
#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_PPV_ARGS(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;
}

Ayrıca bkz.

Windows Çalışma Zamanı C++ Şablon Kitaplığı (WRL)