2012-08-14 84 views
3

嗨,我有一個純粹的C++項目(DLL),我想轉換爲COM項目,例如,在頭文件中定義的所有公共接口現在將作爲COM接口(IDL等)公開。最終的產品應該是COM Dll。將C++(DLL)項目轉換爲COM DLL項目

我該如何開始?我如何定義任何高級指南?好文章?

回答

3

至少有兩個部分,這一問題:使用CoCreateInstance創建

首先,COM對象。 CoCreateInstance在內存中查找COM註冊(通過),在應用程序清單中作爲零註冊COM對象,最後在註冊表中註冊。

對於零註冊,創建一個描述您的dll的assembly manifest,以便您的對象的消費者可以添加一個dependantAssembly參考到他們的application manifest

然後,COM DLL需要至少兩個入口點:DllGetClassObjectDllCanUnloadNow

您可以通過創建一個工廠對象的實例,實現DllGetClassObject - 支持IClassFactory - 可以用來做你的實際對象的實例。

因此,要總結 - 一種TDD驅動的方法來實現COM DLL:

  1. 用 '的DllGetClassObject' 和 'DllCanUnloadNow' 入口點創建一個DLL。
  2. 創建一個新的GUID來表示您的對象,並創建一個描述您的dll(將)包含的COM對象的程序集清單。
  3. 創建一個測試應用程序,該應用程序使用該GUID調用CoCreateInstance
  4. 調用CoCreateInstance現在應該着陸在您的DllGetClassObject調用中。實現類工廠對象。
  5. 實現CreateInstance方法來創建一個新的C++類實例。確保所有接口都來自(至少)IUnknown。在你自己新創建的對象上調用QueryInterface來獲取並返回所需的接口。

假設的Visual Studio(Express是OK)是你構建環境:

創建一個測試EXE:

// main.cpp 
#include <windows.h> 
#include <objbase.h> 
#include <initguid.h> 
DEFINE_GUID(CLSID_RegFreeOcx,0x00000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); 
#if defined _MSC_VER 
#if !defined _WINDLL && !defined (_CONSOLE) 
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") 
#endif 
#endif 
#pragma comment(linker, "/manifestDependency:\"name='acme.RegFreeOcx' processorArchitecture='*' version='1.0.0.0' type='win32' \"") 
int main(){ 
    CoInitialize(NULL); 
    IUnknown* pUnk; 
    CoCreateInstance(CLSID_RegFreeOcx,NULL,CLSCTX_ALL,IID_IUnknown,(void**)&pUnk); 
    if(pUnk) 
    pUnk->Release(); 
} 

的COM DLL的REG免費激活創建清單:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity name="Acme.RegFreeOcx" processorArchitecture="x86" version="1.0.0.0" type="win32" /> 
    <file name = "RegFreeOcx.dll"> 
    <comClass clsid="{00000000-0000-0000-0000-000000000000}" threadingModel="Apartment" /> 
    </file> 
</assembly> 

創建一個dll項目

// dllmain.cpp 
#include <windows.h> 
#pragma comment(linker,"/export:[email protected],PRIVATE") 
#pragma comment(linker,"/export:[email protected],PRIVATE") 
#include <objbase.h> 
#include <initguid.h> 
DEFINE_GUID(CLSID_RegFreeOcx,0x00000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); 
#include "MyClassFactory.hpp" 

STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid,void** ppvObj) 
{ 
    if(CLSID_RegFreeOcx == clsid){ 
    MyClassFactory* pFactory = new MyClassFactory(); 
    HRESULT result = pFactory->QueryInterface(riid,ppvObj); 
    pFactory->Release(); 
    return result; 
    } 
return E_FAIL; 
} 
STDAPI DllCanUnloadNow() 
{ 
    return E_FAIL; 
} 

//MyClassFactory.hpp 
#include <MyClass.hpp> 
class MyClassFactory : public IClassFactory { 
    volatile ULONG _cRef; 
public: 
    MyClassFactory():_cRef(1){} 
    virtual ~MyClassFactory(){} 
public: // IUnknown 
    STDMETHODIMP_(ULONG)AddRef(){ 
    return InterlockedIncrement(&_cRef); 
    } 
    STDMETHODIMP_(ULONG)Release(){ 
    ULONG result = InterlockedDecrement(&_cRef); 
    if(!result) delete this; 
    return result; 
    } 
    STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj){ 
    if(riid == IID_IUnknown || riid == IID_IClassFactory) 
     *ppvObj = (IClassFactory*)this; 
    else { 
     *ppvObj=0; 
     return E_NOINTERFACE; 
    } 
    AddRef(); 
    return S_OK; 
    } 
public: // IClassFactory 
    STDMETHODIMP CreateInstance(IUnknown* pUnkOuter,REFIID riid,void** ppvObj){ 
    if(pUnkOuter) 
     return E_INVALIDARG; 
    MyClass* pClass = new MyClass(); 
    HRESULT result = pClass->QueryInterface(riid,ppvObj); 
    pClass->Release(); 
    return result; 
    } 
    STDMETHODIMP LockServer(BOOL fLock){ 
    return E_NOTIMPL; 
    } 
}; 

最後,定義你自己的類。您可以使用IDL來做到這一點,但對於其他cpp使用者,您可以將其定義在頭文件中。

// IMyClass.h 
#include <objbase.h> 
DEFINE_GUID(IID_MyInterface,0x00000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); 
interface IMyInterface : IUnknown { 
    STDMETHOD(MyMethod)(void)PURE; 
}; 

實現實現IMyInterface的一個CPP文件中幾乎相同的方式將是的ClassFactory實施(在IUnknown方法計算)類 - 交換出去的IClassFactory引用與自己的界面。

+0

只是爲了確定。假設我有class X {foo(); bar();}如何更改類以便客戶端應用程序可以找到它的接口。定義IDL?將它包裝在一些ATL模板中?假設你可以改變這個類本身。 – Boris 2012-08-14 11:05:41

+0

我非常感謝完整的答案 – Boris 2012-08-14 13:05:25

1

Dale Rogenson的規範溫和的介紹是Inside COM。對於真正的深度,儘量Essential COM by Don Box

三大領域的擔心是:

  • 線程跨越COM接口邊界傳遞
  • 內存管理和內存所有權公約]
  • 類型 - 尤其是沒有使用STL

該書的書還涵蓋了一些真討厭東西人d o與COM一樣 - 如免費線程編組器 - 如果您的庫已經線程安全並且您希望避免編組處罰,則可能適用該選項。