インテル® Fortran コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
このトピックは、Windows* にのみ適用されます。
このセクションでは、Fortran COM サーバーに関する次のトピックについて説明します。
DLL (インプロセス) COM サーバーと EXE (アウトオブプロセス) COM サーバーを選択する際の基本的なトレードオフは、パフォーマンスと安定性です。
DLL サーバーは、EXE サーバーと比べてパフォーマンスに優れています。DLL サーバーはクライアントのアドレス空間にロードされるため、メソッドの呼び出しにおけるオーバーヘッドが少なくて済みます。クライアント・コードとサーバー・オブジェクトが同じ COM 集合内にある場合、メソッドの呼び出しは DLL ルーチンの呼び出しと同じように効率的です。
EXE サーバーは、DLL サーバーと比べて安定性に優れています。サーバー・オブジェクトは別のアドレス空間にあるため、クライアントのメモリー処理に問題があっても影響を受けません。また、その逆についても同じことがいえます。サーバーがクラッシュしても、クライアントですべてのメソッドの呼び出し結果を確認して、問題のあったオブジェクトから回復するための処置を行っていれば、クライアントは必ずしもクラッシュするとは限りません。
パフォーマンスと安定性のトレードオフに加えて、次の点も考慮する必要があります。
EXE サーバーでは、クライアントからオブジェクトを別のセキュリティー・コンテキストで実行することができます。DLL サーバーでは、オブジェクトのメソッドのコードは、クライアントのアクセストークンを使用して実行されます。
EXE サーバーは、COM 分散オブジェクトを使用して、リモートマシンから実行することができます。
DLL サーバーを代理サーバーにロードして、EXE サーバーのメリットを利用することができます。詳細は、次のセクションで説明します。
インプロセス DLL サーバーは、代理サーバーを使用して、別のプロセスで実行することができます。代理サーバーは別のプロセスとして実行され、DLL サーバーをロードして、DLL サーバーがローカルサーバーとして動作するために必要なすべてのメカニズムを提供します。Windows* では、DLLHOST.EXE という名前の標準の代理サーバーが提供されています。代理サーバーを使用する最大のメリットは、障害を分離できることです。つまり、サーバーがクラッシュしても、クライアントはクラッシュしません。また、その逆についても同じことがいえます。ただし、パフォーマンスに影響を与えます。別のアプリケーションでのメソッドの実行は、DLL と比べると、著しいパフォーマンスのオーバーヘッドが発生します。
DLL サーバーは、システム・レジストリーの項目 (AppID) に関連付けることで、代理サーバーと関連付けられます。AppID は GUID です。標準の代理サーバーを使用する場合は、DLL クラスの CLSID を AppID として使用するか、または新しく生成した GUID を使用することができます。新しい GUID を生成する場合は、Developer Studio Tools サブディレクトリーにある GUIDGEN.EXE を使用します。
クラスの HKEY_CLASSES_ROOT\CLSID\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx} キーに、CLSID の値を使用して AppID を追加します。サンプル・プロジェクトの AddingMachine クラスでは、レジストリー・キーは HKEY_CLASSES_ROOT\CLSID\{904245FC-DD6D-11D3-9835-0000F875E193} となり、AppID の値は {904245FC-DD6D-11D3-9835-0000F875E193} となります。
HKEY_CLASSES_ROOT\AppID キーに、AppID を使用して新しいキーを追加します。サンプル・プロジェクトの AddingMachine クラスでは、レジストリー・キーは HKEY_CLASSES_ROOT\AppID\{904245FC-DD6D-11D3-9835-0000F875E193} となります。キーのデフォルト値をクラス名として使用します (例: AddingMachine Class)。値に、空の文字列を持つ DllSurrogate 項目を追加します。
クライアントは、インプロセス DLL サーバーをロードせずに代理サーバーを使用するために、CLSCTX_INPROC_SERVER ではなく、CLSCTX_LOCAL_SERVER を要求する必要があります。メソッドが別々のプロセスから呼び出されるため、代理サーバーを使用するには、DLL サーバーのプロキシー/スタブを登録する必要があります。プロキシー/スタブについての情報は、「マーシャリング、プロキシー、およびスタブ」を参照してください。
カスタム代理サーバーを作成することもできます。詳細は、Windows* Platform SDK のドキュメントを参照してください。
COM サーバーウィザードは、templates という名前のプロジェクト・サブディレクトリーにあるファイルから、プロジェクトのコードを生成します。project-name.hie ファイルには、非公開のテキスト言語で記述された COM サーバーの定義が含まれています。project-name.hie ファイルは手動で編集しないでください。ウィザードによって編集されます。
templates ディレクトリーにあるその他のファイルのほとんどは、プロジェクト用に生成されたソースファイルのテンプレートです。これらのテンプレートには、生成されるソースに "そのまま" コピーされるソースコードと、定義する COM サーバー固有のコードを生成する際に、ウィザードが使用する埋め込みディレクティブが含まれています。ディレクティブは project-name.hie ファイルの情報を使用します。ディレクティブは、非公開で、変更されることがあります。
新しい Fortran COM サーバー・プロジェクトを作成する場合、ウィザードは templates ディレクトリーを作成して、Fortran COM サーバーのテンプレート・ディレクトリー (...\Intel Fortran\Templates\COMServer) からテンプレートをコピーします。
Fortran COM サーバーのテンプレート・ディレクトリー内のファイルは、バージョンによって異なりますが、プロジェクトの templates ディレクトリー内のファイルは自動的に更新されません。例えば、インテル® Visual Fortran コンパイラー 13.0 を使用して COM サーバーを作成した場合、次のリリース (バージョン 13.1) に更新されたテンプレートが含まれていても、COM サーバー・プロジェクトのテンプレートは、新しい 13.1 のテンプレートに更新されません。サーバーの定義を変更しても、プロジェクトはそのサーバーの作成時に作成されたテンプレートを使用し続けます。これは、開発およびテスト済みのプロジェクトに新しく別のコードを追加しなくても良いというメリットがあります。
ただし、次のように、プロジェクトで使用するテンプレートを変更したほうが良い場合もあります。
新しいバージョンのインテル® Fortran コンパイラーに、COM サーバー・プロジェクトで使用可能な追加機能が含まれている場合。一部の新機能では、新しいテンプレートが必要な場合があります。この場合、templates ディレクトリーのテンプレートを更新しない限り、以前のバージョンで作成した既存のプロジェクトでこれらの機能を利用することはできません。テンプレートを更新するには、Fortran COM サーバーのテンプレート・ディレクトリー (...\Intel Fortran\Templates\COMServer) にあるすべてのファイルを templates ディレクトリーにコピーして、既存のファイルはすべて上書きします。次回、サーバーの定義が変更され、プロジェクト・ソースが再生成されると、プロジェクトは新しいテンプレートを使用するようになります。
ウィザードによって生成されたコードを変更する場合。templates ディレクトリーにあるテンプレートを編集することができます。"そのまま" コピーされたコードを編集するのは簡単です。埋め込みディレクティブの変更はサポートされていません。埋め込みディレクティブを変更したテンプレートを使用すると、ウィザードは失敗することがあります。埋め込みディレクティブは、@ (アットマーク) で始まり、その次の文字はディレクティブの種類を決定します。多くのディレクティブは @ とそのディレクティブの種類の最終文字で終わっています。例えば、ディレクティブの種類の 1 つは @[ で始まり、@] で終わります。
テンプレートを変更するメリットは、ウィザードによって生成されたコードをカスタマイズできることです。しかし、次の点に注意してください。
テンプレートを変更したことにより、ウィザードが不正なコードを生成したり、失敗しないように細心の注意が必要です。
新しいバージョンのインテル® Fortran コンパイラーのテンプレートを使用して、プロジェクトのテンプレートを更新するには、新しいテンプレートに変更を再度適用する必要があります。
ウィザードは、DLL COM サーバーで作成するクラスにおいて Apartment (集合) と Single (単一) の 2 つの COM スレッド化モデルをサポートしています。デフォルトでは、Apartment (集合) スレッド化モデル (STA: Single Threaded Apartment) を使用します。Apartment (集合) スレッド化モデルの基本的な規則は次のとおりです。
同じ STA スレッドで A と B という 2 つのオブジェクトが作成され、A でメソッドの呼び出しを処理している場合、A が終了するまで、ほかのクライアントは A または B を呼び出すことができません。
B が A とは別のスレッドによって作成された場合は、A が処理中であっても B のメソッドを呼び出すことができます。また、その逆についても同じことがいえます。
クラスのオブジェクト間でグローバルデータを共有している場合、スレッド同期プリミティブを使用して、そのグローバルデータへのアクセスを保護する必要があります。これは、クラスの 2 つのインスタンスが別々のスレッドで実行される可能性があるためです。クラスの派生型フィールドである per-object インスタンス・データは、COM メカニズムによって同時アクセスから保護されています。ただし、オブジェクトが自身の再入可能な呼び出しを引き起こす別のオブジェクトを呼び出す場合は除きます。
Single (単一) スレッド化モデルを使用するクラスでは、クラスのグローバルデータおよび per-object データへの同時アクセスについて考慮する必要はありません。すべてのオブジェクトは、単一のスレッドで作成されるため、同時に 1 つのオブジェクトのみ実行することができます。
ウィザードによって生成される EXE COM サーバーは単一スレッドです。すべてのメソッドの呼び出しは、サーバーのメッセージキューによって順次実行されます。このため、EXE サーバーでは、クラスのグローバルデータおよび per-object データへの同時アクセスについて考慮する必要はありません。
COM スレッド化モデルの詳細については、Windows* Platform SDK のドキュメントを参照してください。
COM は、(EXE サーバーまたは DLL 代用サーバーで) 別のプロセスでのオブジェクトの使用をサポートしています。また、マーシャリング、プロキシー、およびスタブを使用する上記のスレッド化モデルの使用もサポートしています。このセクションでは、マーシャリング、プロキシー、およびスタブの概要について説明します。
マーシャリングとは、メソッドの呼び出しに必要な引数を読み出し、別の実行コンテキスト (スレッド、プロセス、マシンなど) へ転送するために準備する処理です。マーシャリングはプロキシーによって行われます。クライアント側からは、プロキシーとオブジェクトのインターフェイスは同じに見えます。プロキシーの役割は、オブジェクトがクライアントと同じ実行コンテキスト内にあるかのように見せることです。
プロキシーにより、クライアント・コードで実際のオブジェクトの場所を考慮する必要がなくなります。プロキシーはメソッド引数をマーシャリングして、サーバー内のオブジェクトに関連付けられたスタブへ転送します。スタブは引数をアンマーシャリングして、サーバーでメソッドを呼び出します。サーバー側からは、同一の実行コンテキスト内のクライアントから呼び出された場合と同じように見えます。インプロセス DLL サーバー以外のサーバーでは、常にプロキシー/スタブのペアが必要です。インプロセス DLL サーバーでは、クライアントとオブジェクトが別の集合にある場合、プロキシー/スタブのペアが必要になります。
サーバーにプロキシー/スタブのペアを割り当てる方法は 3 つあります。
タイプ・ライブラリー・マーシャリング: |
メソッドおよびプロパティーでオートメーション互換データ型のみを使用する場合、COM は自動的に Universal Marshaller をサーバーのプロキシー/スタブとして使用します。Universal Marshaller はタイプ・ライブラリーにあるサーバーの記述を使用して、引数をマーシャリングする方法を決定します。この方法をタイプ・ライブラリー・マーシャリングと言います。タイプ・ライブラリー・マーシャリングを使用するには、サーバーをオートメーション互換データ型に制限するだけです。 |
MIDL ベース・マーシャリング: |
プロジェクトは、MIDL コンパイラーを使用して、サーバーの IDL 記述をタイプ・ライブラリーにコンパイルします。同時に、MIDL コンパイラーは、サーバーのプロキシー/スタブ DLL をビルドするのに必要な C ソースコードも生成します。MIDL によって生成されたコードからプロキシー/スタブ DLL をビルドするには、C コンパイラーが必要です。プロキシー/スタブ DLL は、それ自身がインプロセス DLL サーバーであり、システムに登録する必要があります。サーバーでオートメーション互換データ型以外を使用し、クライアントが異なる実行コンテキストでサーバーを使用する場合は、MIDL ベース・マーシャリングを使用する必要があります。 |
カスタム・マーシャリング: |
サーバーは IMarshall インターフェイスを実装することで、独自のマーシャリングを実装することができます。この方法は、一般的に多くの作業を必要とし、パフォーマンス上の理由で使用されます。 |
このセクションでは、ウィザードによって Do Not Edit ソースファイルとして生成される COM サーバー機能の概要について説明します。
ファイル名 |
説明 |
---|---|
server.idl |
サーバーの IDL 記述。サーバーのタイプ・ライブラリーを生成するために MIDL コンパイラーによりコンパイルされます。 |
servernameglobal.f90 |
サーバーのグローバルデータおよび関数。 |
dllmain.f90 (DLL サーバー) |
すべての COM サーバー DLL で必要なエクスポートされた関数。DllMain、DLLRegisterServer、DLLUnregisterServer、DllGetClassObject、および DllCanUnloadNow が含まれます。 |
exemain.f90 (EXE サーバー) |
EXE サーバーのメイン・エントリー・ポイント。コマンドライン引数も処理します。 |
serverhelper.f90 |
サーバーのヘルパー関数。 |
clsfactty.f90 |
サーバーによって定義されたクラスのインスタンスを作成する IClassFactory インターフェイスの定義。 |
clsfact.f90 |
サーバーによって定義されたクラスのインスタンスを作成する IClassFactory インターフェイスのメソッド。 |
classnameTY.f90 |
クラスの実装で使用される引数および型の定義を含むモジュールの定義。クラスの IUnknown メソッドの実装も含まれます。サーバーで定義されている各クラスに対して、このファイルの個別のインスタンスが生成されます。 |
interfacename.f90 |
インターフェイスのメソッドの Fortran インターフェイスを含むモジュールの定義。クラスの VTBL から直接呼び出され、ユーザーによって実装されたメソッドを呼び出す Fortran ラッパーの実装も含まれます。クラスで定義されている各インターフェイスに対して、このファイルの個別のインスタンスが生成されます。 |