2012年02月05日

exe と DLL の間で、グローバル変数を共有するには

DLL は、exe と同じプロセス空間にリンクすることができるので、ポインタを使って変数を共有することができるのですが、デフォルトでは、グローバル変数は共有していません。

sample.exe
 int g_MyGlobal;

sample.dll
 int g_MyGlobal;

上記は、g_MyGlobal という同じ名前のグローバル変数の宣言ですが、この2つの変数は、同じメモリの中にはありません。 たとえば、exe の中で、g_MyGlobal = 1 して、dll の中で g_MyGlobal = 2 して、exe の中で、g_MyGlobal に入っている値を参照したら、2 ではなく 1 になります。

しかし、同じメモリの中の変数にすることもできます。 exe のグローバル変数に、__declspec(dllimport) を、DLL のグローバル変数に、__declspec(dllexport) を記述します。

sample.exe
 #define dll_global __declspec(dllimport)
 dll_global int g_MyGlobal;

sample.dll
 #define dll_global __declspec(dllexport)
 dll_global int g_MyGlobal;

こうすれば、たとえば、exe の中で、g_MyGlobal = 1 して、dll の中で g_MyGlobal = 2 して、exe の中で、g_MyGlobal に入っている値を参照したら、2 になります。

ただし、Visual C++ 2008 では、exe の中の関数でブレークした場合、グローバル変数 g_MyGlobal などの値をウォッチすることができません。「シンボルが見つかりません」というエラーになります。

おそらく、__declspec(dllimport) した、グローバル変数は、別の名前のポインタ変数になっていて、デバッガがそれに対応していないことが原因でしょう。

つまり __declspec(dllimport) したところで、グローバル変数のメモリ領域は、相変わらず exe と dll で別々に用意されているのでしょう。 Windows は、まず、exe をロードした直後に exe 用のグローバル変数のメモリ領域を確保します。 この時点で、exe 用のグローバル変数のアドレスは確定します。 その直後、DLL をロードして用意される DLL 用のグローバル変数のメモリ領域を確保します。 DLL 用のグローバル変数のアドレスはこの段階で確定します。 変数の実体は DLL 側にあります。

DLL をロードしても、exe のグローバル変数のアドレスを変えることはできません。 なぜなら、グローバル変数を参照するときは、CPU は、グローバル・ポインタと呼ばれる CPU のレジスタの値に、コンパイル時にバイナリ・コードに埋め込まれる、グローバル・ポインタからのオフセットを足したアドレスのメモリを参照するからです。 exe の中の関数を実行しているときは、グローバル・ポインタは、exe 用のグローバル変数の領域を指し、DLL の中の関数を実行しているときは、グローバル・ポインタは、DLL 用のグローバル変数の領域を指しているので、exe の中から DLL 用のグローバル変数を直接参照することはできません。

では、exe にある __declspec(dllimport) の int 型のグローバル変数g_GlobalInt はどうなっているのかというと、実体は、int** 型(__imp__g_GlobalInt)になっています。 これは、ソースファイルを右クリックして [ 逆アセンブルを表示 ] すれば確認できます。 DLL をロードすると、DLL の関数のアドレスが計算されて決まるのですが、グローバル変数も同様に変数のアドレスが計算されて決まります。

よって、グローバル変数 g_MyGlobal の値をウォッチするときは、**(int**)__imp__g_GlobalInt と入力すれば、表示できます。


DLL のサンプル Visual C++ 2008 プロジェクトファイル:
  http://www.sage-p.com/b/dll_sample.zip

sage_p at 22:08│Comments(1)TrackBack(0) プログラミング 

トラックバックURL

この記事へのコメント

1. Posted by VCプログラマ   2017年04月13日 04:18
5 とても参考になりました。
ありがとうございました。

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔