ところで、dll内のグローバル変数とかstaticな変数はどうなるのでしょうか。
たとえば、あるアプリケーションから呼ばれてある値をdll内のstaticな
変数に格納したとします。別なアプリケーションがdllを呼び出したとき
この変数の値はどうなるのでしょうか?
ま、いろいろ考えてもわからんので、実験してみましょう。 次のようなプログラムを作ってください。
VC++の人はプロジェクトを「Win32 Dynamic-Link」にします。プロジェクト名 は「dll03」にします。そして、 プロジェクトに上のdll03.cppを参加させます。// dll03.cpp #include <windows.h> #include "dll03.h" int WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, PVOID pvReserved) { return TRUE; } EXPORT int CALLBACK CountClick() { static int nCount = 0; nCount++; return nCount; } // dll03.h #define EXPORT extern "C" __declspec(dllexport) EXPORT int CALLBACK CountClick(void);
これをビルドすればdll03.dllとdll03.libができあがります。
さて、このdllは何をしているかというとCountClick関数が呼ばれるたびに nCountの数を1ずつ増やしてその値を返すという単純なものです。
では呼び出し側のプログラムを作ってみましょう。
dll03.hは先ほどdllを作ったときのものです。これは普通のウィンドウズ プログラムなのでプロジェクトは「Win32 Application」です。また、 プロジェクトに参加するファイルはこのdll3test.cppとdllを作ったときに できたdll03.libです。このへんを間違えるとなかなか面倒なことになります。// dll3test.cpp #define STRICT #include <windows.h> #include "dll03.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "dll3test"; //ウィンドウクラス int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }
このへんはいつもと同じです。//ウィンドウ・クラスの登録 BOOL InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるdll",//タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW,//ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL,//親ウィンドウのハンドル、親を作るときはNULL NULL,//メニューハンドル、クラスメニューを使うときはNULL hInst,//インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
WM_LBUTTONDOWNメッセージが来たらdll内のCountClick関数を呼び出して クリック数をクライアント領域に表示します。簡単のためにここで 表示を行っているので再描画が起こったときは(画面サイズの変更、他のウィンドウに 隠されて再度出てきたときなど)は表示が消えてしまいます。 気にくわない人は消えないようにプログラムを直してください。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, nCount; HDC hdc; char str[64]; char *str_org = "%3d回左クリックされました"; switch (msg) { case WM_LBUTTONDOWN: nCount = CountClick(); hdc = GetDC(hWnd); wsprintf(str, str_org, nCount); TextOut(hdc, 0, 0, (LPCTSTR)str, strlen(str)); ReleaseDC(hWnd, hdc); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }
さて、プログラムができたら実行してください。最初に作ったdllが このプログラムと同じディレクトリにあるか、システムのディレクトリにあるか もしくはパスの通ったディレクトリにある必要があります。
クライアント領域を左クリックして正しくクリック回数が表示されるか 確認してください。
うまく動けば、同じプラグラムをもう一つ起動してください。 そして、左クリックしてください。
二つのプログラムはクリック回数を別々に表示します。Windowsはプロセスの アドレス空間が他のプロセスから見られないように分割管理をしています。 従ってあるプログラムから呼ばれてdll内の変数に値を格納しても、 他のプログラムから呼ばれてもこの値は使われません。(あまり正しい表現では ないですが、雰囲気的にはわかりますね)しかし、場合によっては 他のアプリケーションと共有したい場合もあると思います。これは、また いつか解説します。
Update Apr/27/1998 By Y.Kumei