SlideShare a Scribd company logo
1 of 48
COM入門 
暁紫電 
@akatukisiden 
わんくま同盟東京勉強会#93
自己紹介 
• HN:暁紫電 
• Twitter: @akatukisiden 
• 本名:伊藤伸男 
• フリーランスプログラマー 
• 使用言語 
わんくま同盟東京勉強会#93 
–C++ 
–C# 
–C++/CLI
アジェンダ 
• コンポーネントによるアプリケーションについて 
• COMとは 
• インターフェイス 
• IUnknown 
• COMの登録 
• COMの使い方 
• COMの作り方(DLLサーバー) 
• まとめ 
わんくま同盟東京勉強会#93
モノリシックなアプリケーション 
• 一枚岩のバイナリで構成 
• 一度アプリケーションを生成すると 
再コンパイルして出荷するまで更新できない 
• 技術の進歩やソフトウェア業界の変化に対応 
できない 
わんくま同盟東京勉強会#93
コンポーネントによるアプリケーション 
• 独立した部品(コンポーネント)により構成 
• コンポーネントごとに更新が可能 
• 技術の進歩やソフトウェア業界の変化に柔軟 
に対応できる 
わんくま同盟東京勉強会#93
COM(Component Object Model)とは 
• コンポーネントを作成し、 
そのコンポーネントからアプリケーションを構 
築する方法を定義する仕様 
• 作成されたコンポーネントは 
実行可能コードでありWin32ダイナミックリンク 
ライブラリ(DLL)もしくは実行可能ファイル(EXE) 
として配布される 
わんくま同盟東京勉強会#93
何にCOMが使われているか 
• Office 
• Silverlight 
• WinRT(ストアアプリ) 
• 新しいネイティブAPI →基本的にCOMで提供 
– Sensor & Location 
– Media Foundation 
– DirectX 
– AnimationManager 
わんくま同盟東京勉強会#93
COMの特徴 
わんくま同盟東京勉強会#93 
• 言語から独立 
– 大半の言語で記述、使用が可能 
– C++,C,Ada,Java,Modula-3,Oberon,Pascal,etc… 
• バイナリ形式で出荷可能 
• ネットワーク上に等価的に配置、利用が可能 
– 同じプロセス(dll)、別のプロセス(exe),別のマシン上 
• 呼び出し元を編集することなく更新が可能 
• 実装を隠蔽し、更新を容易にするため 
コンポーネントをインターフェイスを通して扱う
COMインターフェイス 
• 関数の宣言のみで実装を持たない 
(≒純粋抽象基底クラス) 
• 多重継承可能(非仮想) 
• 同じインターフェイスを実装していれば異なる 
コンポーネントを同じように扱うことが出来る。 
• 一度公開したら変更してはいけない 
• 変更したい場合は新しいインターフェイスを追 
加する。 
わんくま同盟東京勉強会#93
IUnknown 
• 全てのCOMインターフェイスの共通の派生元 
• 全てのインターフェイスに知られてる 
唯一のインターフェイスなのにUnknown(未 
知) 
わんくま同盟東京勉強会#93 
#define interface struct 
interface IUnknown 
{ 
virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
const IID& riid, void** ppvObject) = 0; 
virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; 
virtual ULONG STDMETHODCALLTYPE Release(void) = 0; 
};
HRESULT __stdcall QueryInterface(const IID& riid, void **ppv) 
• コンポーネントがIIDで指定したインターフェイ 
スを実装しているかどうか調べ、実装してい 
ればそのインターフェイスへのポインタをppv 
に受け取る 
• 戻り値HRESULTは32bit 桁によって意味が 
異なるので実行の成否判定はマクロで行う 
SUCCEEDED(),FAILED() 
AddRef()/Release() 
• 参照カウントのインクリメント/デクリメント 
わんくま同盟東京勉強会#93
COMの登録 
• COMは基本的にレジストリに登録する必要が 
ある。 
• コンポーネントの一意なID(CLSID)とそのコン 
ポーネントを含むファイル(dll,exe)の配置場 
所を一緒に格納し、実行時にそれを暗黙的に 
参照することでコンポーネントがどのファイル 
(dll,exe)に含まれているか、そのファイルがど 
こにあるかを意識せずに開発を行うことが出 
来る。 
わんくま同盟東京勉強会#93
DllRegisterServer() /DllUnRegisterServer() 
• COM登録/登録解除用のコマンド 
regsvr32.exe “dll名” 
regsvr32.exe –u “dll名”で呼び出される 
• レジストリ関係のAPIを用いてレジストリに登 
録/解除するコードの記述する必要がある。 
• Dllのパスはdllmain関数の引数HMODULE 
hModule をGetModuleFileName関数に渡す 
ことで取得できる 
わんくま同盟東京勉強会#93
COMのレジストリ構成 
(DLLサーバーの場合) 
CLSID{CLSID値} 
InprocServer32 
ProgID 
VersionIndependentProgID 
<Program>.<Component>.<Version> 
CLSID 
CurVer 
<Program>.<Component> 
CLSID 
コンポーネント名 
DLLフルパス 
<Program>.<Component>.<Version> 
<Program>.<Component> 
コンポーネント名 
{CLSID値} 
<Program>.<Component>.<Version> 
コンポーネント名 
{CLSID値} 
わんくま同盟東京勉強会#93 
HKEY_CLASSES_ROOT 
キー 
値(既定値)
COMの使いかた 
• CoInitialize(NULL)でシステムを初期化 
• CoCreateInstance()関数で 
コンポーネントのインスタンスを指定したイン 
ターフェイスで取得して仕様 
• 必要に応じてQueryInterfaceで別のインター 
フェイスを取得 
• AddRef/Releaseで参照カウントを操作 
• 最後はCoUninitialize()を呼び出して終了。 
わんくま同盟東京勉強会#93
CoInitialize()/UnInitialize() 
• 初期化/初期化解除 
• スタートアップ時/クリーンアップ時に呼び出す 
• マルチスレッド時は各スレッドで呼び出す必要 
がある。 
わんくま同盟東京勉強会#93
HRESULT CoCreateInstance( 
const CLSID& rclsid, Iunknown* pUnkOuter, 
DWORD dwClsContext, const IID& riid,void**ppv ); 
CLSIDで指定したコンポーネント生成し、 
IIDで指定したインターフェイスとして受け取る 
• rclsid:作成するオブジェクトを指定 
• pUnkOuter:実装に集約という手法を用いる場合に用いる、 
使わない場合はNULL 
• dwClsContext:コンポーネントが実行される場所(インプロセ 
ス、アウトプロセス、リモートetc) 
• IID:どのインターフェイスで受け取るか 
• ppv:作成したコンポーネントを受け取るポインタ 
わんくま同盟東京勉強会#93
サンプル 
• 関数void FuncX()を持つインターフェイスIX 
• 関数void FuncY()を持つインターフェイスIY 
• の二つを実装したコンポーネント 
SessionComponentを使い 
• QueryInstanceでそれぞれのインターフェイス 
を取得、関数の呼び出しを行う。 
• ついでに実装していないインターフェイスIZの 
取得を試み、失敗することを確認する。 
わんくま同盟東京勉強会#93
サンプル 
• CLSID,IIDおよびインターフェイスは 
クライアントとサーバー両方で使うので 
今回スタティックライブラリとして両方にリンク 
させるようにした 
• 通常どのように公開されるかは不明 
わんくま同盟東京勉強会#93
インターフェイス及び各種ID 
interface IX:public IUnknown 
{ 
virtual void FuncX() =0; 
わんくま同盟東京勉強会#93 
}; 
interface IY :public IUnknown 
{ 
virtual void FuncY() =0; 
}; 
interface IZ :public IUnknown 
{ 
virtual void FuncZ() =0; 
};
インターフェイス及び各種ID 
extern "C" 
{ 
extern const CLSID CLSID_SessionComponent; 
extern const IID IID_IX; 
extern const IID IID_IY; 
extern const IID IID_IZ; 
} 
わんくま同盟東京勉強会#93
インターフェイス及び各種ID 
extern "C" 
{ 
extern const CLSID CLSID_SessionComponent = 
{ 0x3c4ec447, 0xa17, 0x4f0d, { 0xb7, 0x10, 0xc7, 0x3d, 0xde, 0xb0, 
0xbd, 0xcf } }; 
extern const IID IID_IX = 
{ 0x1772c7e7, 0x80d9, 0x49ac, { 0xbc, 0x25, 0xc6, 0x2, 0xf3, 0xe, 0xaf, 
0x72 } }; 
extern const IID IID_IY = 
{ 0x2b5cebed, 0xa19d, 0x4376, { 0xa2, 0xbb, 0x92, 0x38, 0x1e, 0x60, 
0x88, 0x60 } }; 
extern const IID IID_IZ = 
{ 0xf3b7ff4, 0xa5a6, 0x4296, { 0x98, 0x2c, 0x83, 0x18, 0x9e, 0x14, 
0x5d, 0x8b } }; 
} 
わんくま同盟東京勉強会#93
クライアント 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
わんくま同盟東京勉強会#93 
// COMの初期化 
CoInitialize(NULL); 
// CLSID_SessionComponentの指すコンポーネントのインスタンスを作成 
// インターフェイスIXで受け取る。 
IX *pIX = NULL; 
HRESULT hr = CoCreateInstance(CLSID_SessionComponent, 
NULL,CLSCTX_INPROC_SERVER,IID_IX, (void**) &pIX); 
//マクロで成否判定 
if (SUCCEEDED(hr)) 
{ 
// IXの関数を呼び出す。 
pIX->FuncX();
クライアント 
わんくま同盟東京勉強会#93 
pIX->FuncX(); 
//コンポーネントがIID_IYの差すインターフェイス(IY) 
//を実装しているか調べ、実装していれば受け取る 
IY* pIY = NULL; 
HRESULT hr = pIX->QueryInterface(IID_IY, (void**) &pIY); 
if (SUCCEEDED(hr)) 
{ 
//IY の関数を呼び出す。 
pIY->FuncY(); 
//インターフェイスを使い終わったので解放 
pIY->Release(); 
} 
else 
{ 
}
クライアント 
わんくま同盟東京勉強会#93 
else 
{ 
} 
// IZを実装しているかどうか調べる 
IZ* pIZ = NULL; 
HRESULT rZ = pIX->QueryInterface(IID_IZ, (void**) &pIZ); 
if (SUCCEEDED(rZ)) 
{ 
// 実装していれば関数を呼び出す。 
pIZ->FuncZ(); 
pIZ->Release(); 
} 
else 
{ 
//実装していなければメッセージを表示 
std::wcerr << L"Not Supportted IZ" << std::endl; 
}
クライアント 
std::wcerr << L"Not Supportted IZ" << std::endl; 
} 
// IXを使い終わったので解放 
pIX->Release(); 
わんくま同盟東京勉強会#93 
} 
// 終了 
CoUninitialize(); 
return 0; 
}
COMの作り方(必要なクラス・関数) 
• IUnknownまたはその派生インターフェイスから派生 
したコンポーネントクラス 
• 特定のコンポーネントのインスタンスを作成するため 
の関数CreateInstance()を持つ 
IClassFactoryから派生したクラスファクトリクラス 
• CLSIDを受け取り対応したクラスファクトリを生成す 
る関数。DllGetClassObject() 
• Dllをアンロードできる状態かどうかを返す。 
DllCanUnloadNow() 
わんくま同盟東京勉強会#93
クラスファクトリIClassFactory 
interface IClassFactory : public IUnknown 
{ 
public: 
virtual HRESULT __stdcall CreateInstance(IUnknown *pUnkOuter, 
const IID& riid, void **ppvObject) = 0; 
virtual HRESULT __stdcall LockServer(BOOL fLock) = 0; 
• 他のコンポーネントを作成するためのコンポーネント 
• 1つのクラスファクトリが1つのコンポーネントに対応 
• DllGetClassObject内でnewで作成 
• (クラスファクトリファクトリは不要) 
わんくま同盟東京勉強会#93 
};
STDAPI DllGetClassObject( 
const CLSID& clsid, 
const IID& iid,void **ppv) 
• CLSIDで指定したコンポーネント生成 
するためのクラスファクトリを、 
IIDで指定したインターフェイスとして受け取る 
• CoGetClassObject()から呼び出される。 
• コンポーネントを含むDLLに自分で実装する。 
わんくま同盟東京勉強会#93
HRESULT __stdcall 
CoGetClassObject( 
const clsid& rclsid, 
DWORD dwClsContext, void* pvReserved, 
const IID& riid, void** ppv 
); 
• CLSIDを受け取り、対応するDLLをロードし 
DllGetClassObject()を呼び出す。 
• CoCreateInstance()から呼び出される。 
• 同じコンポーネントのインスタンスを複数作成すると 
きなどは直接この関数を呼び出して、 
クラスファクトリを使いまわした方が効果的 
わんくま同盟東京勉強会#93
STDAPI DllCanUnloadNow() 
• 現在DLLをアンロードできる状態かどうかを調 
べる 
• DLL内のコンポーネントやクラスファクトリの 
使用中はS_FALSEを返すように自分で実装 
する必要がある(使っていないときはS_OK) 
• CoFreeUnusedLibraries()から呼び出される。 
わんくま同盟東京勉強会#93
void __stdcall CoFreeUnusedLibraries() 
• ロード済みライブラリのに対し 
DLLCanUnloadNowを呼び出し、解放できる 
場合は解放する。 
わんくま同盟東京勉強会#93
コンポーネント 
class SessionComponent:IX,IY 
{ 
わんくま同盟東京勉強会#93 
public: 
SessionComponent(); 
~SessionComponent(); 
// IUnknown 
virtual HRESULT __stdcall QueryInterface( 
const IID& riid,void **ppvObject); 
virtual ULONG __stdcall AddRef(void); 
virtual ULONG __stdcall Release(void); 
virtual void FuncX(); // IX 
virtual void FuncY(); // IY 
private: 
long cRef_; // 参照カウント 
};
コンポーネント(コンストラクタ・デストラクタ) 
SessionComponent::SessionComponent() :cRef_(1) 
{ 
// コンポーネントの使用を監視するグローバルなカウント 
// DllCanUnloadNow()で参照する。 
// コンポーネントのインスタンス生成時に+1 
InterlockedIncrement(&g_cComponents); 
わんくま同盟東京勉強会#93 
} 
SessionComponent::~SessionComponent() 
{ 
// コンポーネントの使用を監視するグローバルなカウント 
// コンポーネントの破棄時に-1 
InterlockedDecrement(&g_cComponents); 
}
コンポーネント(QueryInterface) 
HRESULT __stdcall SessionComponent::QueryInterface( 
const IID& riid, void **ppv) 
わんくま同盟東京勉強会#93 
{ 
// IIDに応じたインターフェイスを返す。 
if (riid == IID_IUnknown) // IUnknown 
{ 
// 常にIXインターフェースの規定IUnknownを返す。 
*ppv = static_cast<IX*>(this); 
} 
else if (riid == IID_IX) // IX 
{ 
*ppv = static_cast<IX*>(this); 
} 
else if (riid == IID_IY) // IY 
{ 
*ppv = static_cast<IY*>(this); 
} 
else // 対応していないインターフェイス
コンポーネント(QueryInterface) 
else // 対応していないインターフェイス 
{ 
// 指定したインターフェイスに対応していない 
*ppv = NULL; 
return E_NOINTERFACE; 
わんくま同盟東京勉強会#93 
} 
//新しい参照を返すので参照カウントを+1する。 
reinterpret_cast<IUnknown*>(*ppv)->AddRef(); 
return S_OK; 
}
コンポーネント(参照カウント) 
ULONG __stdcall SessionComponent::AddRef(void) 
{ 
// 参照カウントを+1 
return InterlockedIncrement(&cRef_); 
わんくま同盟東京勉強会#93 
} 
ULONG __stdcall SessionComponent::Release(void) 
{ 
// 参照カウントを-1して0になったら自己解放 
if (InterlockedDecrement(&cRef_) == 0) 
{ 
delete this; 
return 0; 
} 
return cRef_; 
}
コンポーネント(インターフェイスの実装) 
// IX 
void SessionComponent::FuncX() 
{ 
std::wcout << L"Call FuncX" << std::endl; 
わんくま同盟東京勉強会#93 
} 
// IY 
void SessionComponent::FuncY() 
{ 
std::wcout << L"Call FuncY_" << std::endl; 
}
クラスファクトリ 
class CSessionComponentFactory :public IClassFactory 
{ 
public: 
CSessionComponentFactory(); 
~CSessionComponentFactory(); 
// IUnknown 
virtual HRESULT __stdcall QueryInterface( 
const IID& riid,void **ppvObject); 
virtual ULONG __stdcall AddRef(void); 
virtual ULONG __stdcall Release(void); 
// IClassFactory 
virtual HRESULT __stdcall CreateInstance( 
IUnknown *pUnkOuter,const IID& riid,void **ppvObject); 
virtual HRESULT __stdcall LockServer(BOOL fLock); 
わんくま同盟東京勉強会#93 
private: 
long cRef_; 
};
クラスファクトリ 
CSessionComponentFactory::CSessionComponentFactory() :cRef_(1){} 
CSessionComponentFactory::~CSessionComponentFactory(){} 
ULONG __stdcall CSessionComponentFactory::AddRef(void) 
{ 
return InterlockedIncrement(&cRef_); 
わんくま同盟東京勉強会#93 
} 
ULONG __stdcall CSessionComponentFactory::Release(void) 
{ 
if (InterlockedDecrement(&cRef_) == 0) 
{ 
delete this; 
return 0; 
} 
return cRef_; 
}
クラスファクトリ(QueryInterface) 
HRESULT __stdcall CSessionComponentFactory::QueryInterface( 
const IID& riid,void * *ppv) 
{ 
// IIDに応じたインターフェイスを返す。 
if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) 
{ 
// IClassFactory 
*ppv = static_cast<IClassFactory*>(this); 
} 
else 
{ // 指定したインターフェイスに対応していない 
*ppv = NULL; 
return E_NOINTERFACE; 
} 
//新しい参照を返すので参照カウントを+1する。 
reinterpret_cast<IUnknown*>(*ppv)->AddRef(); 
return S_OK; 
わんくま同盟東京勉強会#93 
}
クラスファクトリ(CreateInstance) 
HRESULT STDMETHODCALLTYPE CSessionComponentFactory::CreateInstance( 
IUnknown *pUnkOuter,const IID& riid,void **ppvObject) 
{ 
if (pUnkOuter != NULL) 
{return CLASS_E_NOAGGREGATION;} 
else 
{ 
SessionComponent* pC = new SessionComponent(); 
if (pC == NULL){return E_OUTOFMEMORY;} 
else 
{ 
//指定されたインターフェイスを取得 
//内部で参照カウントが+1される 
HRESULT hr = pC->QueryInterface(riid, ppvObject); 
// この参照を使い終わったので参照カウントを-1する 
pC->Release(); 
return hr; 
わんくま同盟東京勉強会#93 
} 
} 
}
クラスファクトリ(CreateInstance) 
HRESULT STDMETHODCALLTYPE CSessionComponentFactory::LockServer( 
BOOL fLock) 
{ 
// Lock中はDll CanUnloadNow がfalseになる。 
if (fLock) 
{ 
InterlockedIncrement(&g_cServerLocks); 
わんくま同盟東京勉強会#93 
} 
else 
{ 
InterlockedDecrement(&g_cServerLocks); 
} 
return S_OK; 
}
Defファイル 
わんくま同盟東京勉強会#93 
LIBRARY COMSessionDLL 
EXPORTS 
DllGetClassObject PRIVATE 
DllRegisterServerPRIVATE 
DllUnregisterServerPRIVATE 
DllCanUnloadNow PRIVATE 
STDAPI DllRegisterServer() 
{ 
…省略… 
} 
STDAPI DllUnregisterServer() 
{ 
…省略… 
}
DllGetClassObject 
STDAPI DllGetClassObject(const CLSID& clsid,const IID& iid,void **ppv) 
{ 
if (clsid != CLSID_SessionComponent) 
{ return CLASS_E_CLASSNOTAVAILABLE; } 
else 
{ 
CSessionComponentFactory* factory 
= new CSessionComponentFactory(); 
if (factory == NULL) 
{ return E_OUTOFMEMORY; } 
else 
{ 
HRESULT hr = factory->QueryInterface(iid, ppv); 
factory->Release(); 
return hr; 
わんくま同盟東京勉強会#93 
} 
}
DllCanUnloadNow 
わんくま同盟東京勉強会#93 
STDAPI DllCanUnloadNow() 
{ 
//コンポーネントのインスタンスが存在するとき、 
// ClassFactoryのロック中はアンロードできない。 
if ((g_cComponents == 0) && (g_cServerLocks == 0)) 
{ 
return S_OK; 
} 
else 
{ 
return S_FALSE; 
} 
}
まとめ 
• 古い技術と思われがちだが、新しいネイティブAPIは 
基本的にCOMとして提供される他、WinRT、 
Silverlight等もCOMを基本とした技術でまだまだ現 
役 
• レジストリにCLSIDとファイルパスを登録することで、 
コンテキスト、所属ファイル、配置場所などを気にせ 
ずに扱うことが出来る。 
• インターフェイスを通して扱うことで 
実装を隠蔽し、呼び出し元を修正・再コンパイルする 
ことなく変更ができる 
わんくま同盟東京勉強会#93
これから勉強したいこと 
• 集約と包含 
• タイプライブラリ 
• アウトプロセスサーバー(EXEサーバー) 
• リモートサーバー 
• IDispatch 
• COM相互運用 
わんくま同盟東京勉強会#93

More Related Content

What's hot

3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~
3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~
3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~Fujio Kojima
 
C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26Yoshihisa Ozaki
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#信之 岩永
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~Akira Inoue
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~Akira Inoue
 
C#や.NET Frameworkがやっていること
C#や.NET FrameworkがやっていることC#や.NET Frameworkがやっていること
C#や.NET Frameworkがやっていること信之 岩永
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Akira Inoue
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!Shohei Okada
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~Fujio Kojima
 
今からでも遅くないC#開発
今からでも遅くないC#開発今からでも遅くないC#開発
今からでも遅くないC#開発Kazunori Hamamoto
 
Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3DKouji Hosoda
 
QtでC++開発環境構築
QtでC++開発環境構築QtでC++開発環境構築
QtでC++開発環境構築You&I
 
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京hecomi
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1信之 岩永
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 

What's hot (20)

3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~
3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~
3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~
 
Misrac20150523
Misrac20150523Misrac20150523
Misrac20150523
 
C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26
 
C#の書き方
C#の書き方C#の書き方
C#の書き方
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
 
C#や.NET Frameworkがやっていること
C#や.NET FrameworkがやっていることC#や.NET Frameworkがやっていること
C#や.NET Frameworkがやっていること
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~
 
qmake入門
qmake入門qmake入門
qmake入門
 
今からでも遅くないC#開発
今からでも遅くないC#開発今からでも遅くないC#開発
今からでも遅くないC#開発
 
Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3D
 
QtでC++開発環境構築
QtでC++開発環境構築QtでC++開発環境構築
QtでC++開発環境構築
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 

Similar to T93 com入門

Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Preferred Networks
 
ATLに見る魔術
ATLに見る魔術ATLに見る魔術
ATLに見る魔術egtra
 
cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携Tomoaki Shimizu
 
OpenCLに触れてみよう
OpenCLに触れてみようOpenCLに触れてみよう
OpenCLに触れてみようYou&I
 
コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)
コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)
コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)NTT DATA Technology & Innovation
 
はじめてのCodeIgniter
はじめてのCodeIgniterはじめてのCodeIgniter
はじめてのCodeIgniterYuya Matsushima
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しようUnity Technologies Japan K.K.
 
HoloLensハンズオン:AirTap & SpatialMapping編
HoloLensハンズオン:AirTap & SpatialMapping編HoloLensハンズオン:AirTap & SpatialMapping編
HoloLensハンズオン:AirTap & SpatialMapping編Takashi Yoshinaga
 
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~Unity Technologies Japan K.K.
 
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compilerAdaptive optimization of JIT compiler
Adaptive optimization of JIT compilernothingcosmos
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overviewRyo Sakamoto
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門Yosuke Onoue
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)Iwana Chan
 
130329 04
130329 04130329 04
130329 04openrtm
 
20130329 rtm4
20130329 rtm420130329 rtm4
20130329 rtm4openrtm
 

Similar to T93 com入門 (20)

Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
Kubernete Meetup Tokyo #18 - Kubebuilder/controller-runtime 入門
 
ATLに見る魔術
ATLに見る魔術ATLに見る魔術
ATLに見る魔術
 
Embulk 20150411
Embulk 20150411Embulk 20150411
Embulk 20150411
 
cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携
 
OpenCLに触れてみよう
OpenCLに触れてみようOpenCLに触れてみよう
OpenCLに触れてみよう
 
コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)
コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)
コンテナを突き破れ!! ~コンテナセキュリティ入門基礎の基礎~(Kubernetes Novice Tokyo #11 発表資料)
 
SystemV IPC
SystemV IPCSystemV IPC
SystemV IPC
 
Hbstudy41 auto scaling
Hbstudy41 auto scalingHbstudy41 auto scaling
Hbstudy41 auto scaling
 
はじめてのCodeIgniter
はじめてのCodeIgniterはじめてのCodeIgniter
はじめてのCodeIgniter
 
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
 
HoloLensハンズオン:AirTap & SpatialMapping編
HoloLensハンズオン:AirTap & SpatialMapping編HoloLensハンズオン:AirTap & SpatialMapping編
HoloLensハンズオン:AirTap & SpatialMapping編
 
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~
 
Adaptive optimization of JIT compiler
Adaptive optimization of JIT compilerAdaptive optimization of JIT compiler
Adaptive optimization of JIT compiler
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overview
 
実践 NestJS
実践 NestJS実践 NestJS
実践 NestJS
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)
 
C#勉強会
C#勉強会C#勉強会
C#勉強会
 
130329 04
130329 04130329 04
130329 04
 
20130329 rtm4
20130329 rtm420130329 rtm4
20130329 rtm4
 

T93 com入門

  • 1. COM入門 暁紫電 @akatukisiden わんくま同盟東京勉強会#93
  • 2. 自己紹介 • HN:暁紫電 • Twitter: @akatukisiden • 本名:伊藤伸男 • フリーランスプログラマー • 使用言語 わんくま同盟東京勉強会#93 –C++ –C# –C++/CLI
  • 3. アジェンダ • コンポーネントによるアプリケーションについて • COMとは • インターフェイス • IUnknown • COMの登録 • COMの使い方 • COMの作り方(DLLサーバー) • まとめ わんくま同盟東京勉強会#93
  • 4. モノリシックなアプリケーション • 一枚岩のバイナリで構成 • 一度アプリケーションを生成すると 再コンパイルして出荷するまで更新できない • 技術の進歩やソフトウェア業界の変化に対応 できない わんくま同盟東京勉強会#93
  • 5. コンポーネントによるアプリケーション • 独立した部品(コンポーネント)により構成 • コンポーネントごとに更新が可能 • 技術の進歩やソフトウェア業界の変化に柔軟 に対応できる わんくま同盟東京勉強会#93
  • 6. COM(Component Object Model)とは • コンポーネントを作成し、 そのコンポーネントからアプリケーションを構 築する方法を定義する仕様 • 作成されたコンポーネントは 実行可能コードでありWin32ダイナミックリンク ライブラリ(DLL)もしくは実行可能ファイル(EXE) として配布される わんくま同盟東京勉強会#93
  • 7. 何にCOMが使われているか • Office • Silverlight • WinRT(ストアアプリ) • 新しいネイティブAPI →基本的にCOMで提供 – Sensor & Location – Media Foundation – DirectX – AnimationManager わんくま同盟東京勉強会#93
  • 8. COMの特徴 わんくま同盟東京勉強会#93 • 言語から独立 – 大半の言語で記述、使用が可能 – C++,C,Ada,Java,Modula-3,Oberon,Pascal,etc… • バイナリ形式で出荷可能 • ネットワーク上に等価的に配置、利用が可能 – 同じプロセス(dll)、別のプロセス(exe),別のマシン上 • 呼び出し元を編集することなく更新が可能 • 実装を隠蔽し、更新を容易にするため コンポーネントをインターフェイスを通して扱う
  • 9. COMインターフェイス • 関数の宣言のみで実装を持たない (≒純粋抽象基底クラス) • 多重継承可能(非仮想) • 同じインターフェイスを実装していれば異なる コンポーネントを同じように扱うことが出来る。 • 一度公開したら変更してはいけない • 変更したい場合は新しいインターフェイスを追 加する。 わんくま同盟東京勉強会#93
  • 10. IUnknown • 全てのCOMインターフェイスの共通の派生元 • 全てのインターフェイスに知られてる 唯一のインターフェイスなのにUnknown(未 知) わんくま同盟東京勉強会#93 #define interface struct interface IUnknown { virtual HRESULT STDMETHODCALLTYPE QueryInterface( const IID& riid, void** ppvObject) = 0; virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; virtual ULONG STDMETHODCALLTYPE Release(void) = 0; };
  • 11. HRESULT __stdcall QueryInterface(const IID& riid, void **ppv) • コンポーネントがIIDで指定したインターフェイ スを実装しているかどうか調べ、実装してい ればそのインターフェイスへのポインタをppv に受け取る • 戻り値HRESULTは32bit 桁によって意味が 異なるので実行の成否判定はマクロで行う SUCCEEDED(),FAILED() AddRef()/Release() • 参照カウントのインクリメント/デクリメント わんくま同盟東京勉強会#93
  • 12. COMの登録 • COMは基本的にレジストリに登録する必要が ある。 • コンポーネントの一意なID(CLSID)とそのコン ポーネントを含むファイル(dll,exe)の配置場 所を一緒に格納し、実行時にそれを暗黙的に 参照することでコンポーネントがどのファイル (dll,exe)に含まれているか、そのファイルがど こにあるかを意識せずに開発を行うことが出 来る。 わんくま同盟東京勉強会#93
  • 13. DllRegisterServer() /DllUnRegisterServer() • COM登録/登録解除用のコマンド regsvr32.exe “dll名” regsvr32.exe –u “dll名”で呼び出される • レジストリ関係のAPIを用いてレジストリに登 録/解除するコードの記述する必要がある。 • Dllのパスはdllmain関数の引数HMODULE hModule をGetModuleFileName関数に渡す ことで取得できる わんくま同盟東京勉強会#93
  • 14. COMのレジストリ構成 (DLLサーバーの場合) CLSID{CLSID値} InprocServer32 ProgID VersionIndependentProgID <Program>.<Component>.<Version> CLSID CurVer <Program>.<Component> CLSID コンポーネント名 DLLフルパス <Program>.<Component>.<Version> <Program>.<Component> コンポーネント名 {CLSID値} <Program>.<Component>.<Version> コンポーネント名 {CLSID値} わんくま同盟東京勉強会#93 HKEY_CLASSES_ROOT キー 値(既定値)
  • 15. COMの使いかた • CoInitialize(NULL)でシステムを初期化 • CoCreateInstance()関数で コンポーネントのインスタンスを指定したイン ターフェイスで取得して仕様 • 必要に応じてQueryInterfaceで別のインター フェイスを取得 • AddRef/Releaseで参照カウントを操作 • 最後はCoUninitialize()を呼び出して終了。 わんくま同盟東京勉強会#93
  • 16. CoInitialize()/UnInitialize() • 初期化/初期化解除 • スタートアップ時/クリーンアップ時に呼び出す • マルチスレッド時は各スレッドで呼び出す必要 がある。 わんくま同盟東京勉強会#93
  • 17. HRESULT CoCreateInstance( const CLSID& rclsid, Iunknown* pUnkOuter, DWORD dwClsContext, const IID& riid,void**ppv ); CLSIDで指定したコンポーネント生成し、 IIDで指定したインターフェイスとして受け取る • rclsid:作成するオブジェクトを指定 • pUnkOuter:実装に集約という手法を用いる場合に用いる、 使わない場合はNULL • dwClsContext:コンポーネントが実行される場所(インプロセ ス、アウトプロセス、リモートetc) • IID:どのインターフェイスで受け取るか • ppv:作成したコンポーネントを受け取るポインタ わんくま同盟東京勉強会#93
  • 18. サンプル • 関数void FuncX()を持つインターフェイスIX • 関数void FuncY()を持つインターフェイスIY • の二つを実装したコンポーネント SessionComponentを使い • QueryInstanceでそれぞれのインターフェイス を取得、関数の呼び出しを行う。 • ついでに実装していないインターフェイスIZの 取得を試み、失敗することを確認する。 わんくま同盟東京勉強会#93
  • 19. サンプル • CLSID,IIDおよびインターフェイスは クライアントとサーバー両方で使うので 今回スタティックライブラリとして両方にリンク させるようにした • 通常どのように公開されるかは不明 わんくま同盟東京勉強会#93
  • 20. インターフェイス及び各種ID interface IX:public IUnknown { virtual void FuncX() =0; わんくま同盟東京勉強会#93 }; interface IY :public IUnknown { virtual void FuncY() =0; }; interface IZ :public IUnknown { virtual void FuncZ() =0; };
  • 21. インターフェイス及び各種ID extern "C" { extern const CLSID CLSID_SessionComponent; extern const IID IID_IX; extern const IID IID_IY; extern const IID IID_IZ; } わんくま同盟東京勉強会#93
  • 22. インターフェイス及び各種ID extern "C" { extern const CLSID CLSID_SessionComponent = { 0x3c4ec447, 0xa17, 0x4f0d, { 0xb7, 0x10, 0xc7, 0x3d, 0xde, 0xb0, 0xbd, 0xcf } }; extern const IID IID_IX = { 0x1772c7e7, 0x80d9, 0x49ac, { 0xbc, 0x25, 0xc6, 0x2, 0xf3, 0xe, 0xaf, 0x72 } }; extern const IID IID_IY = { 0x2b5cebed, 0xa19d, 0x4376, { 0xa2, 0xbb, 0x92, 0x38, 0x1e, 0x60, 0x88, 0x60 } }; extern const IID IID_IZ = { 0xf3b7ff4, 0xa5a6, 0x4296, { 0x98, 0x2c, 0x83, 0x18, 0x9e, 0x14, 0x5d, 0x8b } }; } わんくま同盟東京勉強会#93
  • 23. クライアント int _tmain(int argc, _TCHAR* argv[]) { わんくま同盟東京勉強会#93 // COMの初期化 CoInitialize(NULL); // CLSID_SessionComponentの指すコンポーネントのインスタンスを作成 // インターフェイスIXで受け取る。 IX *pIX = NULL; HRESULT hr = CoCreateInstance(CLSID_SessionComponent, NULL,CLSCTX_INPROC_SERVER,IID_IX, (void**) &pIX); //マクロで成否判定 if (SUCCEEDED(hr)) { // IXの関数を呼び出す。 pIX->FuncX();
  • 24. クライアント わんくま同盟東京勉強会#93 pIX->FuncX(); //コンポーネントがIID_IYの差すインターフェイス(IY) //を実装しているか調べ、実装していれば受け取る IY* pIY = NULL; HRESULT hr = pIX->QueryInterface(IID_IY, (void**) &pIY); if (SUCCEEDED(hr)) { //IY の関数を呼び出す。 pIY->FuncY(); //インターフェイスを使い終わったので解放 pIY->Release(); } else { }
  • 25. クライアント わんくま同盟東京勉強会#93 else { } // IZを実装しているかどうか調べる IZ* pIZ = NULL; HRESULT rZ = pIX->QueryInterface(IID_IZ, (void**) &pIZ); if (SUCCEEDED(rZ)) { // 実装していれば関数を呼び出す。 pIZ->FuncZ(); pIZ->Release(); } else { //実装していなければメッセージを表示 std::wcerr << L"Not Supportted IZ" << std::endl; }
  • 26. クライアント std::wcerr << L"Not Supportted IZ" << std::endl; } // IXを使い終わったので解放 pIX->Release(); わんくま同盟東京勉強会#93 } // 終了 CoUninitialize(); return 0; }
  • 27. COMの作り方(必要なクラス・関数) • IUnknownまたはその派生インターフェイスから派生 したコンポーネントクラス • 特定のコンポーネントのインスタンスを作成するため の関数CreateInstance()を持つ IClassFactoryから派生したクラスファクトリクラス • CLSIDを受け取り対応したクラスファクトリを生成す る関数。DllGetClassObject() • Dllをアンロードできる状態かどうかを返す。 DllCanUnloadNow() わんくま同盟東京勉強会#93
  • 28. クラスファクトリIClassFactory interface IClassFactory : public IUnknown { public: virtual HRESULT __stdcall CreateInstance(IUnknown *pUnkOuter, const IID& riid, void **ppvObject) = 0; virtual HRESULT __stdcall LockServer(BOOL fLock) = 0; • 他のコンポーネントを作成するためのコンポーネント • 1つのクラスファクトリが1つのコンポーネントに対応 • DllGetClassObject内でnewで作成 • (クラスファクトリファクトリは不要) わんくま同盟東京勉強会#93 };
  • 29. STDAPI DllGetClassObject( const CLSID& clsid, const IID& iid,void **ppv) • CLSIDで指定したコンポーネント生成 するためのクラスファクトリを、 IIDで指定したインターフェイスとして受け取る • CoGetClassObject()から呼び出される。 • コンポーネントを含むDLLに自分で実装する。 わんくま同盟東京勉強会#93
  • 30. HRESULT __stdcall CoGetClassObject( const clsid& rclsid, DWORD dwClsContext, void* pvReserved, const IID& riid, void** ppv ); • CLSIDを受け取り、対応するDLLをロードし DllGetClassObject()を呼び出す。 • CoCreateInstance()から呼び出される。 • 同じコンポーネントのインスタンスを複数作成すると きなどは直接この関数を呼び出して、 クラスファクトリを使いまわした方が効果的 わんくま同盟東京勉強会#93
  • 31. STDAPI DllCanUnloadNow() • 現在DLLをアンロードできる状態かどうかを調 べる • DLL内のコンポーネントやクラスファクトリの 使用中はS_FALSEを返すように自分で実装 する必要がある(使っていないときはS_OK) • CoFreeUnusedLibraries()から呼び出される。 わんくま同盟東京勉強会#93
  • 32. void __stdcall CoFreeUnusedLibraries() • ロード済みライブラリのに対し DLLCanUnloadNowを呼び出し、解放できる 場合は解放する。 わんくま同盟東京勉強会#93
  • 33. コンポーネント class SessionComponent:IX,IY { わんくま同盟東京勉強会#93 public: SessionComponent(); ~SessionComponent(); // IUnknown virtual HRESULT __stdcall QueryInterface( const IID& riid,void **ppvObject); virtual ULONG __stdcall AddRef(void); virtual ULONG __stdcall Release(void); virtual void FuncX(); // IX virtual void FuncY(); // IY private: long cRef_; // 参照カウント };
  • 34. コンポーネント(コンストラクタ・デストラクタ) SessionComponent::SessionComponent() :cRef_(1) { // コンポーネントの使用を監視するグローバルなカウント // DllCanUnloadNow()で参照する。 // コンポーネントのインスタンス生成時に+1 InterlockedIncrement(&g_cComponents); わんくま同盟東京勉強会#93 } SessionComponent::~SessionComponent() { // コンポーネントの使用を監視するグローバルなカウント // コンポーネントの破棄時に-1 InterlockedDecrement(&g_cComponents); }
  • 35. コンポーネント(QueryInterface) HRESULT __stdcall SessionComponent::QueryInterface( const IID& riid, void **ppv) わんくま同盟東京勉強会#93 { // IIDに応じたインターフェイスを返す。 if (riid == IID_IUnknown) // IUnknown { // 常にIXインターフェースの規定IUnknownを返す。 *ppv = static_cast<IX*>(this); } else if (riid == IID_IX) // IX { *ppv = static_cast<IX*>(this); } else if (riid == IID_IY) // IY { *ppv = static_cast<IY*>(this); } else // 対応していないインターフェイス
  • 36. コンポーネント(QueryInterface) else // 対応していないインターフェイス { // 指定したインターフェイスに対応していない *ppv = NULL; return E_NOINTERFACE; わんくま同盟東京勉強会#93 } //新しい参照を返すので参照カウントを+1する。 reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; }
  • 37. コンポーネント(参照カウント) ULONG __stdcall SessionComponent::AddRef(void) { // 参照カウントを+1 return InterlockedIncrement(&cRef_); わんくま同盟東京勉強会#93 } ULONG __stdcall SessionComponent::Release(void) { // 参照カウントを-1して0になったら自己解放 if (InterlockedDecrement(&cRef_) == 0) { delete this; return 0; } return cRef_; }
  • 38. コンポーネント(インターフェイスの実装) // IX void SessionComponent::FuncX() { std::wcout << L"Call FuncX" << std::endl; わんくま同盟東京勉強会#93 } // IY void SessionComponent::FuncY() { std::wcout << L"Call FuncY_" << std::endl; }
  • 39. クラスファクトリ class CSessionComponentFactory :public IClassFactory { public: CSessionComponentFactory(); ~CSessionComponentFactory(); // IUnknown virtual HRESULT __stdcall QueryInterface( const IID& riid,void **ppvObject); virtual ULONG __stdcall AddRef(void); virtual ULONG __stdcall Release(void); // IClassFactory virtual HRESULT __stdcall CreateInstance( IUnknown *pUnkOuter,const IID& riid,void **ppvObject); virtual HRESULT __stdcall LockServer(BOOL fLock); わんくま同盟東京勉強会#93 private: long cRef_; };
  • 40. クラスファクトリ CSessionComponentFactory::CSessionComponentFactory() :cRef_(1){} CSessionComponentFactory::~CSessionComponentFactory(){} ULONG __stdcall CSessionComponentFactory::AddRef(void) { return InterlockedIncrement(&cRef_); わんくま同盟東京勉強会#93 } ULONG __stdcall CSessionComponentFactory::Release(void) { if (InterlockedDecrement(&cRef_) == 0) { delete this; return 0; } return cRef_; }
  • 41. クラスファクトリ(QueryInterface) HRESULT __stdcall CSessionComponentFactory::QueryInterface( const IID& riid,void * *ppv) { // IIDに応じたインターフェイスを返す。 if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { // IClassFactory *ppv = static_cast<IClassFactory*>(this); } else { // 指定したインターフェイスに対応していない *ppv = NULL; return E_NOINTERFACE; } //新しい参照を返すので参照カウントを+1する。 reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; わんくま同盟東京勉強会#93 }
  • 42. クラスファクトリ(CreateInstance) HRESULT STDMETHODCALLTYPE CSessionComponentFactory::CreateInstance( IUnknown *pUnkOuter,const IID& riid,void **ppvObject) { if (pUnkOuter != NULL) {return CLASS_E_NOAGGREGATION;} else { SessionComponent* pC = new SessionComponent(); if (pC == NULL){return E_OUTOFMEMORY;} else { //指定されたインターフェイスを取得 //内部で参照カウントが+1される HRESULT hr = pC->QueryInterface(riid, ppvObject); // この参照を使い終わったので参照カウントを-1する pC->Release(); return hr; わんくま同盟東京勉強会#93 } } }
  • 43. クラスファクトリ(CreateInstance) HRESULT STDMETHODCALLTYPE CSessionComponentFactory::LockServer( BOOL fLock) { // Lock中はDll CanUnloadNow がfalseになる。 if (fLock) { InterlockedIncrement(&g_cServerLocks); わんくま同盟東京勉強会#93 } else { InterlockedDecrement(&g_cServerLocks); } return S_OK; }
  • 44. Defファイル わんくま同盟東京勉強会#93 LIBRARY COMSessionDLL EXPORTS DllGetClassObject PRIVATE DllRegisterServerPRIVATE DllUnregisterServerPRIVATE DllCanUnloadNow PRIVATE STDAPI DllRegisterServer() { …省略… } STDAPI DllUnregisterServer() { …省略… }
  • 45. DllGetClassObject STDAPI DllGetClassObject(const CLSID& clsid,const IID& iid,void **ppv) { if (clsid != CLSID_SessionComponent) { return CLASS_E_CLASSNOTAVAILABLE; } else { CSessionComponentFactory* factory = new CSessionComponentFactory(); if (factory == NULL) { return E_OUTOFMEMORY; } else { HRESULT hr = factory->QueryInterface(iid, ppv); factory->Release(); return hr; わんくま同盟東京勉強会#93 } }
  • 46. DllCanUnloadNow わんくま同盟東京勉強会#93 STDAPI DllCanUnloadNow() { //コンポーネントのインスタンスが存在するとき、 // ClassFactoryのロック中はアンロードできない。 if ((g_cComponents == 0) && (g_cServerLocks == 0)) { return S_OK; } else { return S_FALSE; } }
  • 47. まとめ • 古い技術と思われがちだが、新しいネイティブAPIは 基本的にCOMとして提供される他、WinRT、 Silverlight等もCOMを基本とした技術でまだまだ現 役 • レジストリにCLSIDとファイルパスを登録することで、 コンテキスト、所属ファイル、配置場所などを気にせ ずに扱うことが出来る。 • インターフェイスを通して扱うことで 実装を隠蔽し、呼び出し元を修正・再コンパイルする ことなく変更ができる わんくま同盟東京勉強会#93
  • 48. これから勉強したいこと • 集約と包含 • タイプライブラリ • アウトプロセスサーバー(EXEサーバー) • リモートサーバー • IDispatch • COM相互運用 わんくま同盟東京勉強会#93