Procedura: creare un componente COM classico mediante WRL
Puoi usare la libreria di modelli C++ di Windows Runtime (WRL) per creare componenti COM classici di base da usare nelle app desktop, oltre a usarlo per le app UWP (piattaforma UWP (Universal Windows Platform)). Per la creazione di componenti COM, la libreria di modelli C++ di Windows Runtime potrebbe richiedere meno codice rispetto ad ATL. Per informazioni sul subset di COM supportato dalla libreria di modelli C++ di Windows Runtime, vedere Libreria modelli C++ di Windows Runtime.For information about the subset of COM that the Windows Runtime C++ Template Library (WRL).
Questo documento illustra come usare la libreria di modelli C++ di Windows Runtime per creare un componente COM di base. Sebbene sia possibile usare il meccanismo di distribuzione che meglio si adatta alle proprie esigenze, questo documento illustra anche un metodo di base per registrare e utilizzare il componente COM da un'app desktop.
Per usare la libreria di modelli C++ di Windows Runtime per creare un componente COM classico di base
In Visual Studio creare un progetto soluzione vuota. Denominare il progetto, ad esempio .
WRLClassicCOM
Aggiungere un progetto Win32 alla soluzione. Denominare il progetto, ad esempio .
CalculatorComponent
Nella scheda Impostazioni applicazione selezionare DLL.Aggiungere un file Midl File (con estensione idl) al progetto. Denominare il file, ad esempio .
CalculatorComponent.idl
Aggiungere questo codice 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; } };
In CalculatorComponent.cpp definire la classe
CalculatorComponent
. LaCalculatorComponent
classe eredita da Microsoft::WRL::RuntimeClass. Microsoft::WRL::RuntimeClassFlags ClassicCom> specifica che la classe deriva da IUnknown e non IInspectable.< (IInspectable
è disponibile solo per i componenti dell'app Windows Runtime.CoCreatableClass
crea una factory per la classe che può essere usata con funzioni come 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);
Usare il codice seguente per sostituire il codice in
dllmain.cpp
. Questo file definisce le funzioni di esportazione DLL. Queste funzioni usano la classe Microsoft::WRL::Module per gestire le class factory per il modulo.#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; }
Aggiungere un file Module-Definition File (con estensione def) al progetto. Denominare il file, ad esempio .
CalculatorComponent.def
Questo file fornisce al linker i nomi delle funzioni da esportare. Aprire la finestra di dialogo Pagine delle proprietà per il progetto, quindi in Input linker>proprietà>di configurazione impostare la proprietà File di definizione del modulo sul file DEF.Aggiungere questo codice a CalculatorComponent.def:
LIBRARY EXPORTS DllGetActivationFactory PRIVATE DllGetClassObject PRIVATE DllCanUnloadNow PRIVATE
Aggiungere runtimeobject.lib alla riga del linker. Per informazioni su come, vedere
.Lib
File come input del linker.
Per utilizzare il componente COM da un'app desktop
Registrare il componente COM con il Registro di sistema di Windows. A tale scopo, creare un file di voci di registrazione, denominarlo
RegScript.reg
e aggiungere il testo seguente. Sostituire <dll-path> con il percorso della DLL,C:\temp\WRLClassicCOM\Debug\CalculatorComponent.dll
ad esempio .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"
Eseguire RegScript.reg o aggiungerlo all'evento post-compilazione del progetto. Per altre informazioni, vedere Finestra di dialogo Della riga di comando evento pre-compilazione/post-compilazione.
Aggiungere un progetto Applicazione console Win32 alla soluzione. Denominare il progetto, ad esempio .
Calculator
Usare questo codice per sostituire il contenuto di
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 */
Programmazione efficiente
Questo documento usa funzioni COM standard per dimostrare che è possibile usare la libreria di modelli C++ di Windows Runtime per creare un componente COM e renderlo disponibile per qualsiasi tecnologia abilitata per COM. Puoi anche usare i tipi di libreria modelli C++ di Windows Runtime, ad esempio Microsoft::WRL::ComPtr nell'app desktop per gestire la durata di COM e altri oggetti. Il codice seguente usa la libreria di modelli C++ di Windows Runtime per gestire la durata del ICalculatorComponent
puntatore. La classe CoInitializeWrapper
è un wrapper RAII che garantisce che la libreria COM venga liberata e che la sua durata sia superiore a quella dell'oggetto del puntatore intelligente ComPtr
.
#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;
}