DLL 内のデータをアプリケーションまたはほかの DLL と共有する方法

更新 : 2007 年 11 月

Win32 DLL は、呼び出し側プロセスのアドレス空間に割り当てられます。既定では、DLL を使用するプロセスごとに、すべての DLL のグローバル変数および静的変数のインスタンスが作成されます。DLL のデータをほかのアプリケーションによって読み込まれたほかの DLL インスタンスと共有する必要がある場合は、次のいずれかの方法を使います。

  • data_seg プラグマを使って名前付きデータ セクションを作成する。

  • メモリ マップト ファイルを使用する。MSDN Lib の「Managing Memory-Mapped Files in Win32」ドキュメントを参照してください。

data_seg プラグマの使用例を次に示します。

#pragma data_seg (".myseg")
   int i = 0; 
   char a[32]n = "hello world";
#pragma data_seg()

data_seg を使って、新規の名前付きセクションを作成できます。この例では、.myseg を作成します。最も一般的な方法では、わかりやすいようにデータ セグメントを .shared と呼びます。この場合、新規の名前付きデータ セクションの共有属性を .def ファイルまたは /SECTION:.MYSEC,RWS リンカ オプションで正しく指定する必要があります。

共有データ セグメントを使用する前に考慮する必要のある制限事項は以下のとおりです。

  • 共有データ セグメント内の変数は、静的に初期化する必要があります。上の例で、i は 0 に初期化され、a は 32 文字で hello world に初期化されます。

  • すべての共有変数は、コンパイル済み DLL の指定されたデータ セグメントに配置されます。配列が大きすぎると、極度に大きな DLL が生じることがあります。これは初期化されるすべてのグローバル変数についても該当します。

  • プロセス固有の情報は、共有データ セグメントに格納しないでください。ハンドルなどの Win32 のほとんどのデータ構造体やデータ値は、実際には単一プロセスのコンテキスト内だけで有効です。

  • 各プロセスは、独自のアドレス空間を取得します。ポインタは共有データ セグメント内の変数に格納されないことに注意する必要があります。ポインタは、あるアプリケーション内で完全に有効であっても、別のアプリケーションでは有効でない場合があります。

  • 各プロセスの仮想アドレス空間では、DLL 自体が異なるアドレスで読み込みまれる可能性があります。DLL 内の関数へのポインタやほかの共有変数へのポインタを持つのは安全ではありません。

これらのうち最後の 3 点は、メモリ マップト ファイルと共有データ セグメントが対象であることに注意してください。

メモリ マップト ファイルは、ファイルの先頭がわかっているという点で、共有データ セクションよりも有利です。開発者は、共有メモリ内にあるすべてのデータで "共有メモリ セクションの先頭からのオフセット" を使ってポインタと同様の動作を実装できます。高速で簡単な方法として、__based ポインタの使用をお勧めします。ただし、ベース (またはメモリ マップト ファイルの先頭) はプロセスごとに異なる可能性があるため、__based ポインタのベースを格納する変数は共有メモリ内に置くことができないことに注意してください。

以下の制限事項は、C++ クラスに対して重要な意味を持ちます。

  • 仮想関数を持つクラスには、常に関数ポインタが含まれます。仮想関数を持つクラスは、共有データ セグメントにもメモリ マップト ファイルにも格納しないでください。これは特に MFC クラスや MFC を継承するクラスにとって重要です。

  • 静的データ メンバは、グローバル変数と同等に実装されます。つまり、各プロセスでは、クラスの静的データ メンバのコピーを独自に所有することになります。静的データ メンバを持つクラスは共有しないでください。

  • 共有データ セグメントの初期化要件により、C++ クラスに特定の問題が発生します。共有データ セグメントに CTest Counter(0); のような記述があると、DLL の読み込み時に各プロセスで Counter オブジェクトが初期化され、そのたびにオブジェクトのデータがゼロに設定される可能性があります。これは DLL の作成時にリンカによって初期化される組み込みのデータ型とは大きく異なります。

これらの制限があるため、Microsoft ではプロセス間での C++ オブジェクトの共有をお勧めできません。通常、C++ を使ってプロセス間でデータを共有する場合は、メモリ マップト ファイルを内部的に使ってデータを共有するクラスを作成しますが、クラス インスタンス自体は共有しないでください。内部的にデータを共有するクラスの開発には特別な注意が必要ですが、アプリケーション開発者はデータ共有の副作用を完全に制御できます。

名前付きデータ セクションの作成の詳細については、http://support.microsoft.com で、以下のサポート技術情報の文書を参照してください。

  • 「Share Data Between Different Mappings of a DLL (Q125677)」

  • 「HOWTO: Specify Shared and Nonshared Data in a DLL (Q100634)」

  • 「HOWTO: Share All Data in a DLL (Q109619)」

  • 「共有コード セクションのメモリが Terminal Server セッション間で共有されない (JP251045)」

参照

概念

DLL に関してよく寄せられる質問