将c ++(DLL)项目转换为COM DLL项目

时间:2012-08-14 07:43:48

标签: c++ windows visual-studio com

您好我有一个纯C ++项目(DLL),我想将其转换为COM项目,例如标头中定义的所有公共接口现在将作为COM接口公开(IDL等...)。最终的产品应该是COM Dll。

我该如何开始?如何定义任何高级指南?好文章?

2 个答案:

答案 0 :(得分:3)

这个问题至少有两个部分:

首先,使用CoCreateInstance创建COM对象。 CoCreateInstance在内存中查找COM注册(通过CoRegisterClassObject),在应用程序清单中查找零注册COM对象,最后在注册表中查找。

对于零注册,请创建一个描述您的dll的assembly manifest,以便您的对象的使用者可以向他们的application manifest添加dependantAssembly引用。

然后,COM dll至少需要两个入口点:DllGetClassObjectDllCanUnloadNow

通过创建支持DllGetClassObject的工厂对象实例来实现IClassFactory - 可以用来创建实际对象的实例。

总而言之 - 一种实现COM dll的TDD驱动方法:

  1. 使用'DllGetClassObject'和'DllCanUnloadNow'入口点创建DLL。
  2. 创建一个新的GUID来表示您的对象,并创建一个描述您的dll(将)包含的COM对象的程序集清单。
  3. 创建一个测试应用程序,使用该GUID调用CoCreateInstance
  4. 调用CoCreateInstance现在应该在DllGetClassObject调用中登陆。实现类工厂对象。
  5. 实现CreateInstance方法以创建c ++类的新实例。确保所有接口都来自(至少)IUnknown。在您自己新创建的对象上调用QueryInterface以获取并返回所需的接口。

  6. 假设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)

Dale Rogenson Inside COM的规范温和介绍。要获得真实深度,请尝试Essential COM by Don Box

需要担心的三大方面是:

  • 线程
  • 内存管理和内存所有权约定]
  • 跨COM接口边界传递的类型 - 特别是不使用STL

Box书中还介绍了人们使用COM做的一些非常讨厌的事情 - 比如 free threaded marshaller - 如果您的库已经是线程,那么您可能会适用它安全,你想避免编组惩罚。