仕事でハマってしまった。また忘れてハマリそうなのでメモ。
Windowsのあるアプリケーションがウィンドウメッセージをブロードキャストしていて、それを受け取って処理する別アプリをVBで書こうととした場合うまく処理できない。
単純にFormをサブクラス化してメッセージを受け取ればできるだろうと高を括っていたのだが、うまくいかない。ブロードキャストするメッセージを登録するのにRegisterWindowMessage APIを使っているが、もしやそれがうまくいっていないのかと思ったがそうでもない。
よくよく調べてみると、VBの場合はちょっと工夫がいるのだということが分かった。
SendMessage(HWND_BROADCAST…)でブロードキャストしたメッセージは、トップレベルウィンドウにしか送られない、とMSDNには書いてある。
VB(確認したのはVB6)では、単純なFormを表示するアプリケーションを作成して動かした場合でも、裏でいくつかのトップレベルウィンドウが生成されているようだ。SPYでウィンドウクラス名を調べてみると、フォームは”Form1″ ThunderRT6FormDCなどとなっているが、それ以外に”Project1″ ThunderRT6Mainというクラスをウィンドウを確認できる。(RT6という部分は多分VBのバージョンによって変わるんだろう)
Form1のウィンドウプロシージャをフックしてサブクラス化しても、このメッセージを受け取ることはできないようなので、試しにThunderRT6Main側をSPYしてみると・・・ビンゴ。
で、このウィンドウのハンドルを取得するには、GetWindow(Form1.hWnd, GW_OWNER)とすればよい。
というわけでやっと解決。悩むこと約数時間。お疲れ様でした<自分
これって、ひょっとするとVB使いさん達の間では常識なんでしょうか・・・?
しかし今回の件でよく分からないのは、以下のような挙動。
A、B、C、Dというアプリがある。AはVCで作成したアプリで、B,CはVB、DはDelphiでそれぞれ作成したものとする。
B,C,Dでは、同じ登録メッセージ(仮にX) を受け取って処理する。また、A,B,CはメッセージXをブロードキャストする。
VBで作成したB,Cは、上で書いた解決策を使わずにForm1のサブクラス化によってブロードキャストメッセージを受け取るようにコーディングしてあるものとする。
すると、BあるいはCからブロードキャストしたメッセージは、B,C,D共に受け取ることができる。
しかし、AからブロードキャストされたメッセージはDしか受け取れない。
これってどういうことなんだろう・・・。