さて今回は毎度おなじみ@ITの会議室より、タスクバーのタスクボタンの情報を取得したいスレッドをネタに話を進めましょう。
私も以前タスクバーから特定アプリのタスクボタンを隠したいとか思って色々調べてみたことがあります。で、まず初めに知ったのがWindows XPからはタスクバーで使用されるコモンコントロールが変更され、もともとTabControlが使われていたのが代わりにToolBarを使われるようになったこと。この変更の波及は大きく、2000までだったらTabControlにTCM_GETITEMをTCIF_PARAMつきで投げてやれば、そのタブが扱うアプリのウィンドウハンドルが手に入ったんですが、XPではToolBarにTB_BUTTONINFOをTBIF_LPARAMつきで投げても良く分からない値しか取得できなくなったんです。おかげでウィンドウタイトルからFindWindowするハメになると言う……。
ま、そんな益体もない話はおいておいて、今回の話に入りましょう。
今まで、SendMessage関数をごく何気なく使っていました。構造体でもref(ByRef)やMarshal.StructureToPtrで普通に参照(アドレス)を渡していました。自分のプロセスのことならメモリアドレスは一意ですから何も問題はなかったんですね。しかし、他のプロセスということになると話は変わってきます。仮想アドレス空間はプロセスごとに用意され、これにプログラムはそれぞれ関数や変数を割り当てて、そのアドレスを使用します。Marshal.AllocCoTaskMemなどで返される値もこの仮想アドレス空間におけるアドレスです。
仮想アドレス空間はプロセスごとと言いました。つまりプロセスが異なれば、同じアドレスを違うものが指していることになるわけです。もちろんそんなの認めるわけにはいきませんから(あっさり暴走しちゃいます)、OSはあるプロセスが扱う仮想アドレス空間には他のプロセスからはアクセスできないようにしています。
ですから、例えば他のプロセスのあるタブコントロールにTCM_GETITEM送信したい場合、単純にTCITEMへの参照を渡すわけにはいきません。こちらのプロセスで作成した構造体の参照(アドレス)は、当然こちらのプロセスの仮想アドレス空間上のアドレスを指すわけで、それをSendMessageで送信してもあちらのプロセスはそのアドレスを処理できません。なんとかあちらのプロセスの仮想アドレス空間を扱う必要があります。
そこで登場するのが、今回のVirtualAllocEx、WriteProcessMemory、ReadProcessMemoryの各Win32API関数です。VirtualAllocExは、指定したプロセスの仮想アドレス空間にメモリ領域を確保する関数。Write/ReadProcessMemoryがその確保した領域とこちらのプロセスの間でデータをコピーする関数です。
大雑把な流れはこうです。
- 対象のプロセスのハンドルを、OpenProcess関数などで取得。
- VirtualAllocExで、対象のプロセスの仮想アドレス空間に構造体のメモリ領域を確保。
- TCM_GETITEMでTCIF_TEXTを使用する場合、その文字列分も確保する必要がある。
- WriteProcessMemoryで、VirtualAllocExで確保した領域に必要な構造体をコピー。
- SendMessageで目的のコントロールに送信。
- 勿論この際構造体アドレスに使用するのはVirtualAllocExで確保したアドレス。
- ReadProcessMemoryで結果をこちらのプロセスのメモリ空間にコピー。
これだけ分かれば後は細々としたプログラミング技術の話になるでしょう。
今回は元スレッドに乗っかってVB.NETオンリーの記事です。尤も下調べはC#でしたのですが。
ところでこれ、元スレッドのそのまま答えというかそのままコードなんですが、こういうのいつもポストバックするかどうか悩むんですよねー。そのままコードは余り質問の答えにはしたくないので。とは言えまあこんな記事書いてる時点で結局書いたのを見せたいという願望があるのは事実ですが。
- 追記(2005/10/13)
- フォロー記事を書きましたので、そちらも参照してください。
ではコードを。
posted by Hongliang at 23:11|
Comment(55)
|
TrackBack(0)
|
VB.NET
|

|