IClassFactory
COM公式ドキュメント
IClassFactory インターフェイスは、オブジェクトのクラスの作成を可能にします。
メソッド 2
vtbl = vtable インデックス(0始まり)。HSP等からCOMメソッドをインデックス指定で呼ぶ際に使用します。0〜2 は IUnknown。
初期化されていないオブジェクトを作成します。
| pUnkOuter | IUnknown* | inoptional | オブジェクトが集約(アグリゲーション)の一部として作成される場合は、集約を制御する IUnknown インターフェイスへのポインターを指定します。それ以外の場合、このパラメーターは NULL でなければなりません。 |
| riid | GUID* | in | 新しく作成されたオブジェクトとの通信に使用するインターフェイスの識別子への参照。pUnkOuter が NULL の場合、このパラメーターは通常、初期化用インターフェイスの IID です。pUnkOuter が非 NULL の場合、riid は IID_IUnknown でなければなりません。 |
| ppvObject | void** | out | riid で要求されたインターフェイスポインターを受け取るポインター変数のアドレス。正常に戻ると、*ppvObject には要求されたインターフェイスポインターが格納されます。オブジェクトが riid で指定されたインターフェイスをサポートしていない場合、実装は *ppvObject を NULL に設定しなければなりません。 |
戻り値
このメソッドは、標準の戻り値 E_INVALIDARG、E_OUTOFMEMORY、E_UNEXPECTED のほか、以下の値を返すことがあります。
| 戻り値 | 説明 |
|---|---|
| 指定されたオブジェクトが作成されました。 | |
| pUnkOuter パラメーターが非 NULL でしたが、オブジェクトが集約をサポートしていません。 | |
| ppvObject が指すオブジェクトが、riid で識別されるインターフェイスをサポートしていません。 |
解説(Remarks)
COM サーバーの CreateInstance の実装は、そのサーバーの DCOM リゾルバーに属するアパートメントに含まれるオブジェクトへの参照を返さなければなりません。リモートアパートメントに含まれるオブジェクトへの参照を返してはなりません。
IClassFactory インターフェイスは常にクラスオブジェクト上にあります。CreateInstance メソッドは、指定された CLSID で識別されるクラスの、初期化されていないオブジェクトを作成します。この方法でオブジェクトを作成する場合、CLSID は CoRegisterClassObject 関数によってシステムレジストリに登録されていなければなりません。
pUnkOuter パラメーターは、オブジェクトが集約の一部として作成されるかどうかを示します。オブジェクト定義は集約をサポートする必要はありません。集約をサポートするには、そのために特別に設計され実装されていなければなりません。
riid パラメーターは、新しいオブジェクトとの通信に使用するインターフェイスの IID(インターフェイス識別子)を指定します。pUnkOuter が非 NULL(集約を示す)の場合、riid パラメーターの値は IID_IUnknown でなければなりません。オブジェクトが集約の一部でない場合、riid はオブジェクトの初期化に使用するインターフェイスを指定することがよくあります。
OLE 埋め込みの場合、初期化用インターフェイスは IPersistStorage ですが、その他の状況では別のインターフェイスが使用されます。オブジェクトを初期化するには、その後で初期化用インターフェイスの適切なメソッドを呼び出す必要があります。一般的な初期化関数には、IPersistStorage::InitNew(新規で空の埋め込み可能コンポーネント用)、IPersistStorage::Load(再読み込みされる埋め込み可能コンポーネント用)、IPersistStream::Load(ストリームオブジェクトに格納されたオブジェクト用)、IPersistFile::Load(ファイルに格納されたオブジェクト用)などがあります。
一般に、アプリケーションが 1 つのクラスのオブジェクトのみをサポートし、そのクラスオブジェクトが単一使用(single use)として登録されている場合、作成できるオブジェクトは 1 つだけです。アプリケーションは他のオブジェクトを作成してはならず、作成の要求に対しては IClassFactory::CreateInstance からエラーを返す必要があります。複数のクラスをサポートし、それぞれのクラスオブジェクトが単一使用として登録されているアプリケーションについても同様です。あるクラスに対する CreateInstance の呼び出しに続いて、いずれかのクラスに対する CreateInstance を呼び出すと、エラーが返されます。
エラーを返さないようにするため、単一使用のクラスオブジェクトを持つ複数のクラスをサポートするアプリケーションは、2 つ目のインスタンス化要求を受け取ったときに、CoRevokeClassObject を呼び出して 1 つ目のクラスの登録済みクラスオブジェクトを取り消すことができます。たとえば、A と B という 2 つのクラスがあるとします。クラス A に対して CreateInstance が呼び出されたときは、B のクラスオブジェクトを取り消します。B が作成されたときは、A のクラスオブジェクトを取り消します。この解決策では、いずれかのクラスオブジェクトが既に取り消されている可能性がある(かつ 2 回取り消すことはできない)ため、シャットダウンが複雑になります。
IClassFactory::LockServer メソッドは、オブジェクトアプリケーションをメモリ内で開いたままロックします。これにより、インスタンスをより高速に作成できるようになります。
| fLock | BOOL | in | TRUE の場合はロックカウントをインクリメントし、FALSE の場合はロックカウントをデクリメントします。 |
戻り値
このメソッドは、標準の戻り値 E_OUTOFMEMORY、E_UNEXPECTED、E_FAIL、および S_OK を返すことがあります。
解説(Remarks)
IClassFactory::LockServer は、オブジェクトのサーバーをメモリ内に保持するかどうかを制御します。アプリケーションをメモリ内で生存させておくことで、インスタンスをより高速に作成できるようになります。
呼び出し側への注意
ほとんどのクライアントは、このメソッドを呼び出す必要はありません。このメソッドは、オブジェクトの複数のインスタンスを作成する際に特別なパフォーマンスを必要とするクライアントのためだけに提供されています。実装者への注意
ロックカウントが 0 で、使用中のオブジェクトがこれ以上なく、アプリケーションがユーザーの制御下にない場合は、サーバーを閉じることができます。LockServer を実装する方法の 1 つは、CoLockObjectExternal 関数を呼び出すことです。オブジェクトアプリケーションをロックしたプロセスは、そのロックを解除する責任があります。クラスオブジェクトが解放された後は、後で同じクラスへの呼び出し側の接続を保証するメカニズムはありません(クラスオブジェクトが単一使用として登録されている場合など)。LockServer への呼び出しは、最後の呼び出しだけでなくすべての呼び出しをカウントすることが重要です。クラスオブジェクトの IClassFactory インターフェイスへのポインターを解放しようとする前に呼び出しの数が釣り合っていなければ、エラーになるためです。fLock を TRUE に設定した LockServer の呼び出しごとに、fLock を FALSE に設定した LockServer の呼び出しが必要です。ロックカウントとクラスオブジェクトの参照カウントの両方が 0 になったとき、クラスオブジェクトを解放できます。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
HSP用 COM定義
#usecom / #comfunc によるHSPのCOM呼び出し定義。数字は vtbl インデックス(0始まり)。クラスIDが無い場合 #usecom の末尾は "{}"、ある場合は "{CLSID}"。
#define global IID_IClassFactory "{00000001-0000-0000-C000-000000000046}" #usecom global IClassFactory IID_IClassFactory "{}" #comfunc global IClassFactory_CreateInstance 3 sptr,var,sptr #comfunc global IClassFactory_LockServer 4 int ; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。 ; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。 ; ※出力/バッファ引数は var(変数直渡し)。varptr 方式にも切替可。 ; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。#define global IID_IClassFactory "{00000001-0000-0000-C000-000000000046}" #usecom global IClassFactory IID_IClassFactory "{}" #comfunc global IClassFactory_CreateInstance 3 sptr,sptr,sptr #comfunc global IClassFactory_LockServer 4 int ; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。 ; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。 ; ※出力/バッファ引数はポインタ方式(token=sptr / 呼び出しは varptr(変数))。 ; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。