嗨,我有一個純粹的C++項目(DLL),我想轉換爲COM項目,例如,在頭文件中定義的所有公共接口現在將作爲COM接口(IDL等)公開。最終的產品應該是COM Dll。將C++(DLL)項目轉換爲COM DLL項目
我該如何開始?我如何定義任何高級指南?好文章?
嗨,我有一個純粹的C++項目(DLL),我想轉換爲COM項目,例如,在頭文件中定義的所有公共接口現在將作爲COM接口(IDL等)公開。最終的產品應該是COM Dll。將C++(DLL)項目轉換爲COM DLL項目
我該如何開始?我如何定義任何高級指南?好文章?
至少有兩個部分,這一問題:使用CoCreateInstance創建
首先,COM對象。 CoCreateInstance在內存中查找COM註冊(通過),在應用程序清單中作爲零註冊COM對象,最後在註冊表中註冊。
對於零註冊,創建一個描述您的dll的assembly manifest,以便您的對象的消費者可以添加一個dependantAssembly參考到他們的application manifest。
然後,COM DLL需要至少兩個入口點:DllGetClassObject和DllCanUnloadNow
您可以通過創建一個工廠對象的實例,實現DllGetClassObject
- 支持IClassFactory
- 可以用來做你的實際對象的實例。
因此,要總結 - 一種TDD驅動的方法來實現COM DLL:
CoCreateInstance
。假設的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引用與自己的界面。
Dale Rogenson的規範溫和的介紹是Inside COM。對於真正的深度,儘量Essential COM by Don Box
三大領域的擔心是:
該書的書還涵蓋了一些真討厭東西人d o與COM一樣 - 如免費線程編組器 - 如果您的庫已經線程安全並且您希望避免編組處罰,則可能適用該選項。
只是爲了確定。假設我有class X {foo(); bar();}如何更改類以便客戶端應用程序可以找到它的接口。定義IDL?將它包裝在一些ATL模板中?假設你可以改變這個類本身。 – Boris 2012-08-14 11:05:41
我非常感謝完整的答案 – Boris 2012-08-14 13:05:25