您好我有一个纯C ++项目(DLL),我想将其转换为COM项目,例如标头中定义的所有公共接口现在将作为COM接口公开(IDL等...)。最终的产品应该是COM Dll。
我该如何开始?如何定义任何高级指南?好文章?
答案 0 :(得分:3)
这个问题至少有两个部分:
首先,使用CoCreateInstance创建COM对象。 CoCreateInstance在内存中查找COM注册(通过CoRegisterClassObject),在应用程序清单中查找零注册COM对象,最后在注册表中查找。
对于零注册,请创建一个描述您的dll的assembly manifest,以便您的对象的使用者可以向他们的application manifest添加dependantAssembly引用。
然后,COM dll至少需要两个入口点:DllGetClassObject和DllCanUnloadNow
通过创建支持DllGetClassObject
的工厂对象实例来实现IClassFactory
- 可以用来创建实际对象的实例。
总而言之 - 一种实现COM dll的TDD驱动方法:
CoCreateInstance
。假设Visual Studio(Express没问题)是你的构建环境:
创建一个测试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:
<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:DllGetClassObject=_DllGetClassObject@12,PRIVATE")
#pragma comment(linker,"/export:DllCanUnloadNow=_DllCanUnloadNow@0,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;
};
在cpp文件中实现实现IMyInterface的类,与实现ClassFactory的方式非常相似(根据IUnknown方法) - 使用您自己的接口交换对IClassFactory的引用。
答案 1 :(得分:1)
需要担心的三大方面是:
Box书中还介绍了人们使用COM做的一些非常讨厌的事情 - 比如 free threaded marshaller - 如果您的库已经是线程,那么您可能会适用它安全,你想避免编组惩罚。