• 締切済み

VBAでコントロールのハンドルを取得したい

Excel2000のVBAでFormに配置したコントロールのハンドルを取得するにはどうしたらよいのでしょうか? 目的は、Winsock API(ws2_32.dll)の WSAAsyncSelect関数の2番目の引数にセットする値を取得することです。USER32.dll の GetDlgItem が使用できそうなことがわかったのですが、こちらもその2番目の引数にセットするIDがわかりません。

みんなの回答

noname#50176
noname#50176
回答No.4

すみません、説明がVBベースでした・・・。 メッセージのキャッチ目的なら、KenKen_SPさんの 仰るとおりで完璧だと思います。 もしUserFormをサブクラスせず別オブジェクトに専属させたいのであれば、 RegisterClass,CreateWindow API関数で別の親ウインドウを作成して クラスモジュールでメッセージハンドラ用プロシージャを 用意して当てればモジュールがすっきりします。 スモールアイコン、拡張スタイルは無関係なので Ex いらずです。 互換プログラミングスタイルで私はVB、VBAでも極力APIで埋め込みますが、 小規模ならKenKen_SPさんのやり方を適用するべきです。

Gana_Gana
質問者

お礼

ありがとうございました。 別ウインドウを作成する方法もやってみます。

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.3

> ウインドウメッセージを捕らえたいのではなく、(特殊な方法で) > ウインドウメッセージを送りたいのです。 WinSock から通知されてくるメッセージ、例えば FD_READ を捕らえ たら、recv() をコール...するといった処理をさせるわけではない.. ということですね? ダミーで良いなら、通知先は Userform で良いのでは? #2 のコードで得られたハンドルで良いと思います。 Frame などは下記のようなコードで取れるは取れるのですけど、確実に 「この Frame のハンドル」とは取れないのです。 例えば、Form 内に Frame が 2つ配置されていたり、ListBox も配置 されていたら、その内のどれかのハンドル...といった具合です。 したがって、「取れる・取れない」というレベルでは、「取れる」なの ですが、実用に使えるものではありません。  # これが Excel VBA の仕様なのでどうしようもないんです... Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" ( _     ByVal lpClassName As String, _     ByVal lpWindowName As String) As Long Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" ( _     ByVal hWnd1 As Long, _     ByVal hWnd2 As Long, _     ByVal lpsz1 As String, _     ByVal lpsz2 As String) As Long Private Sub CommandButton1_Click()      Dim hWnd As Long   hWnd = FindWindow("ThunderDFrame", Me.Caption)   hWnd = FindWindowEx(hWnd, 0&, "F3 Server 60000000", vbNullString)   hWnd = FindWindowEx(hWnd, 0&, "F3 Server 60000000", vbNullString)   MsgBox hWnd End Sub 興味本位で恐縮ですが、メッセージを受け取らないのに、なぜ通知先 が必要なんでしょう? だとしたら、WSAAsyncSelect の意図がよく 分かりません。 あまりご期待に沿う回答ができず、すみません。

Gana_Gana
質問者

お礼

ご丁寧に教えていただきありがとうございました。

Gana_Gana
質問者

補足

> WinSock から通知されてくるメッセージ、例えば FD_READ を捕らえ > たら、recv() をコール...するといった処理をさせるわけではない.. > ということですね? そういう処理をしたいのですが、そういう処理をダミーとして配置したコントロールのイベントとして記述しようとしているのです。 > 興味本位で恐縮ですが、メッセージを受け取らないのに、なぜ通知先 > が必要なんでしょう? だとしたら、WSAAsyncSelect の意図がよく > 分かりません。 メッセージは受け取りたいのです。メッセージを受けるコントロールがダミーなだけで、メッセージを受けても処理しないわけではありません。 考えていた方法では困難そうですので、 方向転換して、UserFormをサブクラス化する方向で少し検討してみませす。 ありがとうございました。

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.2

VBA の標準コントロール(Microsoft Forms2 Object Library)は、 一部( ListBox や Frame )を除いてウインドウハンドルを取得 できません。SPY++ で調べるとわかります(^^;  # テキストボックスなどはハンドルが無いので、FindWindowEx  # を使っても取得できません。   これは、VB6.0 との差別化のための仕様だと思いますが... WSAAsyncSelect について詳しくはありませんが、ウインドウ メッセージを捕らえるなら、別にコントロールでなくとも Userform のウインドウハンドルが取得できれば良いのでは ありませんか? Userform のハンドル取得方法は FindWindow API を使用します。 注意点としては、Excel97 と Excel2000以降のバージョンで クラス名が変更になっている点です。   クラス名: "ThunderXFrame" ' Excel 97   クラス名: "ThunderDFrame" ' Excel 2000 Later もし Excel97 での動作も視野に入れるなら下記のようなコード で条件分岐させれば良いでしょう。   sClass = IIf(Val(Application.Version) <= 9, _        "ThunderXFrame", _        "ThunderDFrame")   hWnd = FindWindow(sClass, UserForm1.Caption) あとはこのハンドルを使って、Userform をサブクラス化すれば メッセージをフックできると思います。

Gana_Gana
質問者

補足

丁寧な回答ありがとうございます。 ListBox や Frameのハンドルが取得できるのであれば、目的は達成できるのですが、これはどのようにすれば取得できるのでしょうか? > WSAAsyncSelect について詳しくはありませんが、ウインドウ > メッセージを捕らえるなら、別にコントロールでなくとも > Userform のウインドウハンドルが取得できれば良いのでは > ありませんか? ウインドウメッセージを捕らえたいのではなく、 (特殊な方法で)ウインドウメッセージを送りたいのです。(実際に送るのはシステム?がします) そのために、送り先のコントロールのハンドルが必要になっています。 WSAAsyncSelectは、その為の設定をします。 [使用イメージ] WSAAsyncSelect(ソケット, 送り先のハンドル, 送信メッセージ, イベント) as エラーコード メッセージを受けるコントロールはダミーなので、ListBox でも問題ありません。

noname#50176
noname#50176
回答No.1

コントロールハンドルでしたらやはり  ≫コントロール名.hwnd(Button1.hwnd のように) で取得できますが取得実体がなければ、  1.EnumChildWindows 関数で列挙  2.GetClassName 関数でクラス名を照合させて洗い出す 後者は動的コントロール作成でも使えます。 (VBプログラマはほとんど使わないですけど・・・)

Gana_Gana
質問者

補足

早速の回答ありがとうございます。 しかし、、、 Button1.hWnd のようにしてみましたが、「コンパイルエラー メソッド又はデータメンバーが見つかりません」となります。(入力補完でもでてきませんが、なぜか"w"は自動的に大文字になります。Button1.hWnd()ともしてみましたが、同じでした) > 1.EnumChildWindows 関数で列挙 > 2.GetClassName 関数でクラス名を照合させて洗い出す これについては、使用方法がわかりませんが、もう少し調べてみます。 ありがとうございました。

関連するQ&A