こんにちは、COM プロジェクトに変換したい純粋な C++ プロジェクト (DLL) があります。たとえば、ヘッダーで定義されたすべてのパブリック インターフェイスは、COM インターフェイス (IDL など) として公開されます。そして、最終的な製品は COM Dll になるはずです。
どうすれば始められますか? 高レベルのガイドラインを定義するにはどうすればよいですか? 良い記事?
こんにちは、COM プロジェクトに変換したい純粋な C++ プロジェクト (DLL) があります。たとえば、ヘッダーで定義されたすべてのパブリック インターフェイスは、COM インターフェイス (IDL など) として公開されます。そして、最終的な製品は COM Dll になるはずです。
どうすれば始められますか? 高レベルのガイドラインを定義するにはどうすればよいですか? 良い記事?
この問題には少なくとも 2 つの部分があります。
まず、 CoCreateInstanceを使用して COM オブジェクトを作成します。CoCreateInstance は、( CoRegisterClassObjectを介して) メモリ内で COM 登録を検索し、ゼロ reg COM オブジェクトとしてアプリケーション マニフェスト内で検索し、最後にレジストリ内で検索します。
ゼロ reg の場合、 dll を記述するアセンブリ マニフェストを作成して、オブジェクトのコンシューマーがアプリケーション マニフェストに依存アセンブリ参照を追加できるようにします。
次に、COM dll には、 DllGetClassObjectとDllCanUnloadNowの少なくとも 2 つのエントリ ポイントが必要です。
実際のオブジェクトのインスタンスを作成するために使用できる (DllGetClassObject
サポートする) ファクトリ オブジェクトのインスタンスを作成することによって実装します。IClassFactory
つまり、要約すると、COM dll を実装するための一種の TDD 駆動型アプローチです。
CoCreateInstance
その GUIDで呼び出すテスト アプリケーションを作成します。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 への参照を交換します。
標準的な穏やかな紹介は、Dale Rogenson によるInside COMです。真の深さについては、Don Box による Essential COM を試してください
心配すべき3つの大きな領域は次のとおりです。
ボックス ブックには、COM で人々が行う非常にやっかいなこと (無料のスレッド マーシャラーなど)も含まれています。これは、ライブラリが既にスレッド セーフであり、マーシャリングのペナルティを回避したい場合に適用できる可能性があります。