3

こんにちは、COM プロジェクトに変換したい純粋な C++ プロジェクト (DLL) があります。たとえば、ヘッダーで定義されたすべてのパブリック インターフェイスは、COM インターフェイス (IDL など) として公開されます。そして、最終的な製品は COM Dll になるはずです。

どうすれば始められますか? 高レベルのガイドラインを定義するにはどうすればよいですか? 良い記事?

4

2 に答える 2

3

この問題には少なくとも 2 つの部分があります。

まず、 CoCreateInstanceを使用して COM オブジェクトを作成します。CoCreateInstance は、( CoRegisterClassObjectを介して) メモリ内で COM 登録を検索し、ゼロ reg COM オブジェクトとしてアプリケーション マニフェスト内で検索し、最後にレジストリ内で検索します。

ゼロ reg の場合、 dll を記述するアセンブリ マニフェストを作成して、オブジェクトのコンシューマーがアプリケーション マニフェストに依存アセンブリ参照を追加できるようにします。

次に、COM dll には、 DllGetClassObjectDllCanUnloadNowの少なくとも 2 つのエントリ ポイントが必要です。

実際のオブジェクトのインスタンスを作成するために使用できる (DllGetClassObjectサポートする) ファクトリ オブジェクトのインスタンスを作成することによって実装します。IClassFactory

つまり、要約すると、COM dll を実装するための一種の TDD 駆動型アプローチです。

  1. 「DllGetClassObject」および「DllCanUnloadNow」エントリ ポイントを使用して DLL を作成します。
  2. オブジェクトを表す新しい GUID を作成し、dll (が) に含まれる COM オブジェクトを記述するアセンブリ マニフェストを作成します。
  3. CoCreateInstanceその GUIDで呼び出すテスト アプリケーションを作成します。
  4. CoCreateInstance を呼び出すと、DllGetClassObject 呼び出しに到達するはずです。クラス ファクトリ オブジェクトを実装します。
  5. CreateInstanceメソッドを実装して、C++ クラスの新しいインスタンスを作成します。すべてのインターフェイスが (少なくとも) IUnknown から派生していることを確認してください。新しく作成した独自のオブジェクトで QueryInterface を呼び出して、目的のインターフェイスを取得して返します。

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;
};

ClassFactory が実装されたのとほぼ同じ方法 (IUnknown メソッドに関して) で、cpp ファイルに IMyInterface を実装するクラスを実装します。独自のインターフェイスで IClassFactory への参照を交換します。

于 2012-08-14T09:51:13.187 に答える
1

標準的な穏やかな紹介は、Dale Rogenson によるInside COMです。真の深さについては、Don Box による Essential COM を試してください

心配すべき3つの大きな領域は次のとおりです。

  • ねじ切り
  • メモリ管理とメモリ所有権の規則]
  • COM インターフェイスの境界を越えて渡される型 - 特に STL を使用しない

ボックス ブックには、COM で人々が行う非常にやっかいなこと (無料のスレッド マーシャラーなど)含まれています。これは、ライブラリが既にスレッド セーフであり、マーシャリングのペナルティを回避したい場合に適用できる可能性があります。

于 2012-08-14T09:13:02.160 に答える