・共有セグメントに置きたい変数は、グローバルレベルで、「初期化せずに」宣言
・以下の記述のみの .def ファイルを、プロジェクトに追加する。
----------------- from here ------------
SECTIONS
_BSS READ WRITE SHARED
----------------- to here ------------
さて、先日、突然一日のキーストローク数をカウントしてみたくなりました。
公開するわけでも、販売するわけでもない、そういう目的なので、まあ、なんとか動かせばいいか……というレベルでいろいろ情報を探すと、
・システムフックというのを使えばいいらしい。
・システムフックは、dll として作成する必要があるらしい。
・この場合、dll は、各スレッドごとに作成されるので、グローバル変数(たとえば、キーストロークの総数)は、共有セグメントに持たなければならい。
ということ。
そして、共有セグメントを使う方法としては、
#pragma data_seg("セグメント名")
ここで、変数を宣言+初期化
#pragma data_seg()
としたあと、.def ファイルで、このセグメントを共有指定すればOKという情報が。
以上の情報を頼りに、dll を作り始めましたが、#pragma data_seg が変?
あ、これ、Visual C++ の独自拡張なのですね。BCB ではそのままでは使えません。
ではどうすればいいのか?
「メモリマップトファイルを使用してください」
あ、確かに、とっても正しい回答であります。
といいつつも、さらに、メモリマップトファイルまで理解するのはちょっとおっくう。
そこで、「何が本質的なのか?」と自問。
別に、変数に「任意のセグメント名をつける」ことが必要なのではなく、「その変数が存在するセグメントを、共有セグメントとして定義する」ことが必要なのです。
そう、「その変数が存在するセグメント」さえわかれば、(さらに、副作用さえなければ)、そのセグメント名を共有セグメントとして指定すれば良いわけです。
そこで、とりあえず作成したキーフックするソースをアセンブルしてみると、問題の変数は、BSS というセグメントに存在している。あとは、BSS というセグメントを共有セグメントにすればいいわけで……
※冒頭で、「初期化せずに」と書いたのは、たまたまこの条件の変数が BSS に存在していたというだけです。
keyHookdef.def というファイルを作って、その中に、上記の
SECTIONS
_BSS READ WRITE SHARED
を書き込み。
これをプロジェクトに追加すると、どうやら、所定の動作をしてくれたようです。
めでたしめでたし。
ちなみに、ソース全体は以下のようになります。
---------------- keyHookUnit1.cpp ------------------------
#include
#include
#include
#pragma hdrstop
// この下にある、グローバル変数が、BSS に存在するようです。
HINSTANCE hInst;
HHOOK hHook;
int pressCount;
static void save()
{
std::ofstream otf("c:\\user\\keyCount_LL.txt");
otf << pressCount;
otf.close();
}
static void load()
{
std::ifstream inf("c:\\user\\keyCount_LL.txt");
if (inf)
{
inf >> pressCount;
inf.close();
}
else
pressCount = 0;
}
LRESULT CALLBACK HookProc(int nCode, WPARAM wp, LPARAM lp)
{
if ((nCode == HC_ACTION) && (wp == WM_KEYDOWN)) // キー押下時
{
pressCount++;
if ((pressCount % 1000) == 0) save();
}
return CallNextHookEx(hHook, nCode, wp, lp);
}
extern "C" __declspec(dllexport) void HookStart()
{
load();
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)HookProc, hInst, 0);
}
extern "C" __declspec(dllexport) void HookEnd()
{
UnhookWindowsHookEx(hHook);
save();
}
extern "C" __declspec(dllexport) int get()
{
return pressCount;
}
extern "C" __declspec(dllexport) void clear()
{
pressCount = 0;
save();
}
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
hInst = hinst;
return 1;
}
---------------- keyHook.h --------------------------------
#include
extern "C" __declspec(dllexport) void HookStart();
extern "C" __declspec(dllexport) void HookEnd();
extern "C" __declspec(dllexport) int get();
extern "C" __declspec(dllexport) void clear();
---------------- keyHookDef.def ---------------------------
SECTIONS
_BSS READ WRITE SHARED
---------------- to here ----------------------------------
