2010年08月02日

Turbo C++ (というか、BCB というか、C++ Builder)で、DLL の「共有セグメント」を使う安直な方法

【結論】

・共有セグメントに置きたい変数は、グローバルレベルで、「初期化せずに」宣言
・以下の記述のみの .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 ----------------------------------
posted by 麻野なぎ at 12:28| Comment(1) | TrackBack(0) | Twitter と Bot の周辺
この記事へのコメント
この記事の内容、とても、参考になりました。私の場合は、WH_CBTというフックを掛けようとしています。
Posted by yakki at 2016年12月24日 19:33
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/39937377

この記事へのトラックバック