このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
DllCanUnloadNow に対応するには、
サーバ単位でインスタンスの参照を数えておく必要がある。
参照の確認には、AddRef と Release が使われるが、
これはインスタンス自身の生存期間の管理だけでなく、
それを含むサーバの生存期間の管理も必要となるのだ。
そのためには、サーバのロックカウントを用意し、
AddRef, Release で増減してやる必要がある。
ここでは、単純にグローバル変数としておこう。
例によって、global.hpp に宣言しておく。
========== global.hpp ==========
//(…前略…)
#include <ole2.h>
// グローバル変数
extern HMODULE g_moduleHandle;
extern ULONG g_serverLockCount;
#endif // !global_hpp_included
========== end of global.hpp ==========
実体は global.cpp に追加する。
========== global.cpp ==========
#include "global.hpp"
// グローバル変数の実体
HMODULE g_moduleHandle = NULL;
ULONG g_serverLockCount = 0;
========== end of global.cpp ==========
このロックカウント変数を使えば、
DllCanUnloadNow は以下のように実装できる。
========== library.cpp ==========
//(…前略…)
//(…DllMain…)
STDAPI DllCanUnloadNow() {
return (g_serverLockCount == 0) ? S_OK : S_FALSE;
}
========== end of library.cpp ==========
後は、適切なタイミングでロックカウントを増減することだ。
ロックカウントは、あらゆるインスタンスの
AddRef, Release の呼び出しに依存している。
従来の Object クラスの実装では、
サーバの生存期間の管理を考慮していなかったが、
ロックカウントを更新するように書き換えてみよう。
========== Object.cpp ==========
//(…前略…)
//(…Object::Object…)
//(…Object::~Object…)
//(…Object::QueryInterface…)
ULONG Object::AddRef() {
// サーバをロック
++g_serverLockCount;
// 参照カウンタを 1 加算
return ++referenceCount;
}
ULONG Object::Release() {
// 参照カウンタを 1 減算
ULONG ref = --referenceCount;
// カウンタが 0 なら自身を破棄
if (ref == 0) {
delete this;
}
// サーバをアンロック
--g_serverLockCount;
return ref;
}
========== end of Object.cpp ==========
こうしておくと、Object から派生する全クラスで、
自動的なサーバのロックが行われるようになる。
ロックはサーバの全インスタンスのカウンタとなるので、
インスタンスの利用頻度が高い場合、
相当な回数ロックされる可能性がある。
実質 4,294,967,295 まで数えられるので、
カウンタが溢れてしまう可能性はないと思うが、
心配な方は、最初の AddRef の時のみロックし、
最後の Release の時のみロック解除するようにすれば、
さらにカウンタを節約できるようになる。
明日は、クラスオブジェクトの作成を行おう。