Bagikan melalui


Cara: Membuat Komponen COM Klasik Menggunakan WRL

Anda dapat menggunakan Windows Runtime C++ Template Library (WRL) untuk membuat komponen COM klasik dasar untuk digunakan di aplikasi desktop, selain menggunakannya untuk aplikasi Platform Windows Universal (UWP). Untuk pembuatan komponen COM, Pustaka Templat C++ Runtime Windows mungkin memerlukan lebih sedikit kode daripada ATL. Untuk informasi tentang subset COM yang didukung Pustaka Templat C++ Runtime Windows, lihat Windows Runtime C++ Template Library (WRL).

Dokumen ini memperlihatkan cara menggunakan Pustaka Templat Windows Runtime C++ untuk membuat komponen COM dasar. Meskipun Anda dapat menggunakan mekanisme penyebaran yang paling sesuai dengan kebutuhan Anda, dokumen ini juga menunjukkan cara dasar untuk mendaftar dan menggunakan komponen COM dari aplikasi desktop.

Untuk menggunakan Pustaka Templat C++ Windows Runtime untuk membuat komponen COM klasik dasar

  1. Di Visual Studio, buat proyek Solusi Kosong. Beri nama proyek, misalnya, WRLClassicCOM.

  2. Tambahkan Proyek Win32 ke solusi. Beri nama proyek, misalnya, CalculatorComponent. Pada tab Pengaturan Aplikasi, pilih DLL.

  3. Tambahkan file Midl File (.idl) ke proyek. Beri nama file, misalnya, CalculatorComponent.idl.

  4. Tambahkan kode ini ke 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. Di CalculatorComponent.cpp, tentukan CalculatorComponent kelas . Kelas CalculatorComponent mewarisi dari Microsoft::WRL::RuntimeClass. Microsoft::WRL::RuntimeClassFlags<ClassicCom> menentukan bahwa kelas berasal dari IUnknown dan bukan IInspectable. (IInspectable hanya tersedia untuk komponen aplikasi Windows Runtime.) CoCreatableClass membuat pabrik untuk kelas yang dapat digunakan dengan fungsi seperti CoCreateInstance.

    #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. Gunakan kode berikut untuk mengganti kode di dllmain.cpp. File ini mendefinisikan fungsi ekspor DLL. Fungsi-fungsi ini menggunakan kelas Microsoft::WRL::Module untuk mengelola pabrik kelas untuk modul.

    #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. Tambahkan file Module-Definition File (.def) ke proyek. Beri nama file, misalnya, CalculatorComponent.def. File ini memberi linker nama fungsi yang akan diekspor. Buka dialog Halaman Properti untuk proyek Anda, lalu di bawah Input Penghubung>Properti>Konfigurasi, atur properti File Definisi Modul ke file DEF Anda.

  8. Tambahkan kode ini ke CalculatorComponent.def:

    LIBRARY
    
    EXPORTS
        DllGetActivationFactory PRIVATE
        DllGetClassObject       PRIVATE
        DllCanUnloadNow         PRIVATE
    
  9. Tambahkan runtimeobject.lib ke baris linker. Untuk mempelajari caranya, lihat .Lib File sebagai Input Linker.

Untuk menggunakan komponen COM dari aplikasi desktop

  1. Daftarkan komponen COM dengan Windows Registry. Untuk melakukannya, buat file entri pendaftaran, beri nama RegScript.reg, dan tambahkan teks berikut. Ganti <dll-path> dengan jalur DLL Anda—misalnya, 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. Jalankan RegScript.reg atau tambahkan ke Peristiwa Post-Build proyek Anda. Untuk informasi selengkapnya, lihat Kotak Dialog Baris Perintah Peristiwa Pra-build/Pasca-build.

  3. Tambahkan proyek Aplikasi Konsol Win32 ke solusi. Beri nama proyek, misalnya, Calculator.

  4. Gunakan kode ini untuk menggantikan konten Calculator.cpp:

    #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
    */
    

Pemrograman yang Kuat

Dokumen ini menggunakan fungsi COM standar untuk menunjukkan bahwa Anda dapat menggunakan Pustaka Templat C++ Runtime Windows untuk menulis komponen COM dan membuatnya tersedia untuk teknologi berkemampuan COM. Anda juga dapat menggunakan jenis Pustaka Templat C++ Windows Runtime seperti Microsoft::WRL::ComPtr di aplikasi desktop Anda untuk mengelola masa pakai COM dan objek lainnya. Kode berikut menggunakan Pustaka Templat C++ Runtime Windows untuk mengelola masa ICalculatorComponent pakai pointer. Kelas CoInitializeWrapper ini adalah pembungkus RAII yang menjamin bahwa pustaka COM dibeberkan dan juga menjamin bahwa masa pakai pustaka COM mengungguli ComPtr objek penunjuk pintar.

#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;
}

Baca juga

Pustaka Templat Windows Runtime C++ (WRL)