質問: SendMessage(hwnd,WM_GETTEXT,length *10 +1,sb); Console.WriteLine("before length:"+ length); /*何らかの処理、ただし、hwndのテキストはコード側ではいじらない*/ } ```
回答: `WM_GETTEXTLENGTH`.aspx)に説明されています。 > > Under certain conditions, the DefWindowProc function returns a value that is larger than the actual length of the text. This occurs with certain mixtures of ANSI and Unicode, and is due to the system allowing for the possible existence of double-byte character set (DBCS) characters within the text. The return value, however, will always be at least as large as the actual length of the text; you can thus always use it to guide buffer allocation. This behavior can occur when an application uses both ANSI functions and common dialogs, which use Unicode. > > > WindowsアプリケーションはUnicodeとANSIの2種類が存在し、APIとしてもUnicodeとANSIの2バージョンが用意されています。アプリケーションの動作モードと`SendMessage`とが異なる場合、実際の文字数ではなく文字列を格納可能な大きめのバッファサイズを返すそうです。 > > sbには実際の文字列が途切れて格納されていました。 > > SendMessageは[DllImport("user32.dll", CharSet = CharSet.Auto)]としています > > > `WM_GETTEXTLENGTH`はANSIバージョンが呼び出された場合、当然ながらANSI文字列のバイト数を返しますし、`WM_GETTEXT`が`WPARAM`で要求するバッファサイズも呼び出したバージョンに依存します。ところが`StringBuilder`が保持するバッファのサイズは常にUnicodeの文字数です。質問文に挙げられているコードはバッファサイズの単位が一致しておらず非常に不安定です。 Unicodeに統一すると共に、`WM_GETTEXT`呼び出し前に`StringBuilder`のバッファサイズを確保すべきです。なお、`StringBuilder`の既定のバッファサイズは16文字ですのでたいていの場合にあふれています。 ``` [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wparam, StringBuilder lparam); while(true){ //<=実際には何かしらの条件 /*何らかの処理、ただし、hwndのテキストはコード側ではいじらない*/ //hwnd<-対象のハンドル var length = SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero); Console.WriteLine("before length:"+ length); var sb = new StringBuilder(length); /* length分のバッファサイズを確保 */ length = SendMessage(hwnd, WM_GETTEXT, new IntPtr(length+1), sb); Console.WriteLine("before length:"+ length); /*何らかの処理、ただし、hwndのテキストはコード側ではいじらない*/ } ```