C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

■96403 / 1階層)  SendMessageの使用法
□投稿者/ 魔界の仮面弁士 (2920回)-(2020/11/19(Thu) 20:09:14)
2020/11/19(Thu) 20:33:52 編集(投稿者)

No96397 (初心者 さん) に返信
> ネットでは SendMessageの使用法として、
> ウィンドウに関連付けられたテキスト(ウィンドウタイトルやコントロールの内容など)を指定されたバッファにコピーします。
上記は WM_GETTEXT メッセージの話でしょうか?


> 何故か、ウィンドウタイトルが取得されます、
指定しているウィンドウハンドルは、そのコントロールの HWND になっていますか?

ウィンドウレスコントロールが対象の場合には、SendMessage では受け取れないので、
UI オートメーションなどを使って値を取得する必要があるかもしれません。


> 内容を取得するにはどのように記述したら良いのでしょうか。
フォームのタイトルを受け取るのであれば、確かに WM_GETTEXT メッセージを送出すれば OK です。
また、16bit 版 Windows 時代の名残で、TextBox コントロール等は WM_GETTEXT で受け取れるます。

しかしほとんどのコントロールは、それぞれのコントールごとの専用メッセージを使うようになっています。
RichTextBox なら EM_GETTEXTEX メッセージ、ListBox なら LB_GETTEXT メッセージ、ListView なら LVM_GETITEMTEXT メッセージなど。


> Textboxのコントロールだと思っているのですが。
Microsoft Spy++ 等で確認済みですか?


> 使い分けはどの様したらよいのでしょうか。

構文自体は VB.NET のものになっていますが、API の呼び出し方が明らかに間違っています。
特にデータ型。VB.NET の API 宣言で As Long が登場することは稀です。

もしかして、VB.NET 向けのサンプルではなく、32bit 版 VBA 向けのソースコードを真似ていませんか?
たとえば Lib "SendMessageA" とか書いてありそうな予感が…。
オーバーロードを使わずに別名関数として API を宣言している点も、.NET っぽくないですし。


> Dim strResult As String ' 文字列を受け取るバッファ
一定の条件を満たせば、文字列バッファとして As String で受けられなくもないですが、
WM_GETTEXT であれば、普通は As StringBuilder を渡すようにします。


> Public Function S1_GetTextMessage(ByVal hWin As Long, ByRef mes As String) As Long

VB.NET の Long 型は、64bitの整数型です。

ウィンドウハンドルは、実行環境によって 32bit だったり 64bit だったりするため、
As Long ではなく、As HandleRef もしくは As IntPtr にするのが一般的です。


> lenResult = SendMessage(hWin, WM_GETTEXTLENGTH, 0, 0&)

第3第4引数が 0, 0& になっていますが、これは前者が Int32 型で、後者が Int64 型という
組合せになっています。明らかに不自然な呼び出し方です。

ソースコードの先頭に「Option Explicit On」宣言を指定して、データ型チェックを厳密化しておいてください。
その上で、現在の API 宣言も提示頂けないでしょうか。



SendMessage の宣言方法は色々ありますが、汎用的な宣言ですと、
たとえば下記のように書くことができます。

Private Declare Auto Function SendMessage Lib "user32" (hWnd As IntPtr, wMsg As UInteger, wParam As IntPtr, lParam As IntPtr) As IntPtr

第2引数を As Integer にすることも多いですし、第1引数を As HandleRef にすることもあります。
Declare ステートメントを使う代わりに、DllImport 属性による定義を用いる事もあります。
また、使用するメッセージによっては、第3引数や第4引数を
ByRef As Integer や ByVal As StringBuilder などにすることもあります。


たとえば WM_GETTEXT の場合であれば、これでどうでしょう。

Private Const WM_GETTEXTLENGTH As UInteger = &HE
Private Const WM_GETTEXT As UInteger = &HD
Private Declare Unicode Function SendMessage Lib "user32" Alias "SendMessageW" (hWnd As IntPtr, wMsg As UInteger, wParam As IntPtr, lParam As IntPtr) As IntPtr
Private Declare Unicode Function SendMessage Lib "user32" Alias "SendMessageW" (hWnd As IntPtr, wMsg As UInteger, wParam As IntPtr, lParam As System.Text.StringBuilder) As IntPtr

Public Shared Function GetText(hWin As IntPtr) As String
  Dim length = SendMessage(hWin, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero)
  If length = IntPtr.Zero Then
    Return Nothing
  Else
    Dim buffer As New System.Text.StringBuilder(length.ToInt32() + 1)
    SendMessage(hWin, WM_GETTEXT, New IntPtr(buffer.Capacity), buffer)
    Return buffer.ToString()
  End If
End Function
編集キー/

前の記事(元になった記事) 次の記事(この記事の返信)
←SendMessageの使用法 /初心者 →Re[2]: SendMessageの使用法 /初心者
 
上記関連ツリー

SendMessageの使用法 / 初心者 (20/11/19(Thu) 18:50) #96397
Re[1]: SendMessageの使用法 / Hongliang (20/11/19(Thu) 20:03) #96400
SendMessageの使用法 / 魔界の仮面弁士 (20/11/19(Thu) 20:09) #96403 ←Now
  └ Re[2]: SendMessageの使用法 / 初心者 (20/11/20(Fri) 12:35) #96407
    └ Re[3]: SendMessageの使用法 / 魔界の仮面弁士 (20/11/20(Fri) 16:28) #96409
      └ Re[4]: SendMessageの使用法 / 初心者 (20/11/21(Sat) 11:39) #96414
        └ Re[5]: SendMessageの使用法 / Azulean (20/11/21(Sat) 17:57) #96415
          └ Re[6]: SendMessageの使用法 / 初心者 (20/11/23(Mon) 15:02) #96442

上記ツリーを一括表示 / 上記ツリーをトピック表示
 
上記の記事へ返信