DLL内でのグローバル変数 – プログラミング – Home

DLL内でのグローバル変数
 
通知
すべてクリア

[解決済] DLL内でのグローバル変数

固定ページ 1 / 2

hirocco
 hirocco
(@hirocco)
ゲスト
結合: 13年前
投稿: 138
Topic starter  

DLL内で定義されたグローバル変数があるとします
そして,そのDLLを利用するDLLが2つ以上あるとします
そして,そのDLLを利用する2つ以上あるDLLを1つのアプリケーション上で
利用するとします

そのときの根元のDLL内で定義されたグローバル変数は同じ値として使うことができるの
でしょうか?
実際動くことは動くのですけど,それは安全といえるのでしょうか?

いろいろすみません
よろしくお願いします


引用未解決
トピックタグ
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 4年前
投稿: 828
 

Win32に限定します。
まず実行ファイルは「プロセス」として起動されます。
プロセスには、それ専用の「仮想アドレス」を持った「メモリー空間」が
割り当てられます。これらはPCに実装されている物理メモリの物理アドレス
とは直接の関係はありません(あるけど、任意のポインタが物理アドレスのどこに
あるかは、意識する必要がないことを意味します。もちろんポインタの値
(アドレス)は仮想的(=なんちゃって)なものです)。

従って、EXEは他にだれもいないメモリー空間に、単独で実行されている
という状態だといえます。これはGetModuleHandl( NULL)の結果が
いかなるEXEであっても常に0x00400000をとることで、確認できます。
この値はEXEのインスタンスハンドルとして利用されています。

そのEXEがDLLをロードするということは、自分のメモリー空間にマッピング
されることを意味します。

さて、何らかのOSのシステム固定値がそのDLL内にあったとき、
対応する関数でそれを取得するときに、呼び出しもとに関係なく
同じ値が戻してもらえます。user32.dllやkernel32.dllに実装されている
関数は、それをやってくれまよね。

もちろん、これらのシステムDLLも例外ではなく
「このEXEのメモリー空間にマッピング」されているわけです。


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 4年前
投稿: 828
 

きれちゃったorz。
んで、さっきのは、リンクした場合の話し、
では、LoadLibraly()でロードしたものはどうなるのかというと、
そのDLLの参照カウントがアップします。カウントアップは重要な
ことで、これにより再マップされることになります。従って、
最初のLoadLibraly()でロードされたDLLと、次のLoadLibraly()で
ロードされたものは別の位置(アドレス)にマップされているはずです。
その内部のデータは言わずもがなですよね。


返信引用
hirocco
 hirocco
(@hirocco)
ゲスト
結合: 13年前
投稿: 138
Topic starter  

libでのリンク時は
DLL内のグローバル変数は同一のEXE内では共通だけど
別のEXEでは別のものとなるということで,

LoadLibraly()でロードされると同一のEXE内でも
グローバル変数は別物となってしまうということですか?

えっと読み違えてますか?


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

まず、1つのプロセス内に話を限るものとする。

LoadLibrary() で明示ロードしようが
import_library 経由で暗黙ロードしようが
・同一 DLL は当該プロセスのメモリ空間中に1回だけロードされる。
・ロードのたびに参照カウンタが上昇する。
・アンロードのたびに参照カウンタが減少する。
・参照カウンタが0になったらメモリ空間から除去される
LoadLibrary http://msdn.microsoft.com/ja-jp/library/cc429241.aspx
FreeLibrary http://msdn.microsoft.com/ja-jp/library/cc429103.aspx
つまり、同一 DLL であればコードもデータも共有される。

foo.exe --+-- foo.dll
+-- bar.dll -- foo.dll
+-- baz.dll -- foo.dll
のように foo.dll が使われるとき、その foo.dll がすべて同一のものであれば
コード領域、データ領域はとも、1個づつしかない=共有される。

1個目の foo.dll は、実は c:\workspace\foodll\debug\foo.dll
2個目の foo.dll は、実は c:\workspace\foodll\release\foo.dll
とかなっていると、これは別ものなのでコードもデータも共有されない。
LoadLibrary(_T(foo.dll)) と、パス明示指定しない場合に、まれにはまる。


返信引用
hirocco
 hirocco
(@hirocco)
ゲスト
結合: 13年前
投稿: 138
Topic starter  

仲澤@失業者さん,tetrapodさん
ありがとうございます

実際に動かしてみました

・DLL(1)内でグローバルでchar配列(260バイト分)を定義してみました
・そのDLL(1)を2つの異なったのDLL(2)(3)内でリンクさせました
・2つの異なったのDLL(2)(3)内でそれぞれリンクした元々のDLL(1)内で
 グローバル定義されているchar配列にアクセス(設定/取得)できるようにしました
・そして2つのDLL(2)(3)を1つのアプリケーション上にリンク/ロードさせてみました
・ボタンを押すとDLL(1)内のグローバルなchar配列に適当な文字列を代入させます
・DLL(2)(3)で取得したDLL(1)内のグローバルなchar配列の内容はタイトルバーに
 常時ONで表示させます

同一アプリケーション上からはそれぞれのグローバルのchar配列は
どちらのDLL(2)or(3)から変更させても同じ値に変わりました

そのアプリケーションを2重起動させてみました
プロセスが変わるようで2重に起動したそれぞれのアプリでのグローバルのchar配列は
影響しませんでした

なるほどな結果です


返信引用
hirocco
 hirocco
(@hirocco)
ゲスト
結合: 13年前
投稿: 138
Topic starter  

複数の異なるアプリケーション間でのDLL内の内容を一致させる場合というのは
簡単にはいかないものなんでしょうか?

レアなケースなので簡単じゃなければ,簡単にあきらめますけど...

あ,でも,知りたかった事は学べましたので解決にします

どうもありがとうございました


返信引用
hirocco
 hirocco
(@hirocco)
ゲスト
結合: 13年前
投稿: 138
Topic starter  

解決にしますって言っておいてチェックしてないかったです...


返信引用
subaru
 subaru
(@subaru)
ゲスト
結合: 18年前
投稿: 381
 

>複数の異なるアプリケーション間でのDLL内の内容を一致させる場合というのは
>簡単にはいかないものなんでしょうか?
DLL内のグローバル変数をアプリケーション間で共有することは可能です。
http://support.microsoft.com/kb/89817/ja
http://msdn.microsoft.com/ja-jp/library/h90dkhs0%28v=vs.90%29.aspx

ただし共有のグローバル変数がポインタの場合は
VirtualAllocEx,ReadProcessMemory,WriteProcessMemoryあたりを使う必要もあったかと。


返信引用
hirocco
 hirocco
(@hirocco)
ゲスト
結合: 13年前
投稿: 138
Topic starter  

客先で客先の人がちょこっとだけ変更したりできるように
して欲しい的な要求もたまにあって,どうしたものかと,
インタプリタ的なものを実装させてそこをイジッテもらうか
なんてのも考えたんですけど
メンドイし...
そんなにお金貰ってないので,別exeを呼び出しますって,
必要だったらそのexeと同名のexeを作ってくれればいいですから
なんて事にしたこともありまして,
で,このDLLを使ってください
そうすれば必要なデータは共有できるますから
なんて使い方できたらいいですね,という発想からでした
客先の人が作るって言っても,きっと浅い知識で偏った先入観どっぷりの
オカシナ事をするんだろうねぇと思うので(あ,毒出てます?)
できるだけ簡単に安全にできるといいですねって思いました

subaruさん,どうもありがとうございます
参考にしてみます


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

解決済みですが

> グローバル変数
これって、import/exportされた変数という意味でつかってますか、
それとも、単なる外部リンケージの変数のことですか。

単なる外部リンケージならば、
C言語の場合だと、ヘッダにextern無しで、int MyGlobal;とか書くと、
このヘッダをincludeしたexe,dllごとにMyGlobalが作られると思うのですが。

あと、
> いかなるEXEであっても常に0x00400000をとることで、確認できます。
XPのnotepad.exeは0x01000000になっています。


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

この話題の主体は [DLL を使う側] だと思っていたが、
勝手に [DLL を実装する側] に話すりかえちゃだめだよ。

DLL を実装する側からみれば 単なる外部結合の変数は1個だけになる。
DLL を使う側としては、その DLL を複数回ロードしたらどうなるのか?
って、話題としてはぜんぜん違う内容。


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

tetrapodさん、感謝します
テーマを完全に読み違えてました。


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 4年前
投稿: 828
 

複数のEXEから、DLL内の変数の値を共用するには、関数と同じく
「変数をエクスポート」します。
が、単にお客にいじらせる、かつ、固定値であるという条件なら
*.iniを含む外部ファイルにしときますけど。自分の場合は。

>XPのnotepad.exeは0x01000000になっています。
おおっそですかっ。
GetModuleHandl(notepad.exe);とかの値じゃないですよねぇ。
自分のメモリ空間にマップされたnotepad.exeじゃ
ぜんぜん意味違いますし(笑い)。


返信引用
subaru
 subaru
(@subaru)
ゲスト
結合: 18年前
投稿: 381
 

>>XPのnotepad.exeは0x01000000になっています。
>おおっそですかっ。
>GetModuleHandl(notepad.exe);とかの値じゃないですよねぇ。
一応ベースアドレスはコンパイラの設定でも変更できるので
必ず0x00400000というわけでもなさそうです。
Process Hackerというツールで確認してみると
確かにnotepad.exeは0x01000000になってます。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました