SendMessageのWM_GETTEXTとWM_GETTEXTLENGTHで大幅に文字数が異なる

[code]

    while(true){ //<=実際には何かしらの条件
        /*何らかの処理、ただし、hwndのテキストはコード側ではいじらない*/
        //hwnd<-対象のハンドル
        var sb = new StruingBuilder();
        var length = SendMessage(hwnd,WM_GETTEXTLENGTH,0,0);
        sb.Capacity = length+1; //追記2
        Console.WriteLine("before length:"+ length);
        Thread.Sleep(200);  //無くても同じ
        length = SendMessage(hwnd,WM_GETTEXT,length+1,sb);
        Console.WriteLine("before length:"+ length);
        /*何らかの処理、ただし、hwndのテキストはコード側ではいじらない*/
    }
    
[/code]

上記プログラムを実行すると

[code]

    before length:212
    after length:91
    
[/code]

と何度もなってしまいます。  
また、ターゲットのアプリケーションの最新版ではどの状況でも文字数が一致するのですが、古いバージョンでは上記のように一致する時としない時とあります。  
どういった原因が考えられるでしょうか。以上、よろしくお願いいたします。

追記:  
sbには実際の文字列が途切れて格納されていました。

追記2:  
sbのCapacityは設定しておりましたが、転記ミスで抜けていました。せっかくご回答いただいたのに大変失礼いたしました。申し訳ございません。

追記3:  
下記のように、試しに取得する長さを変更(length * 10)しましたが、得られる文字列はやはり途切れておりました。

[code]

    while(true){ //<=実際には何かしらの条件
        /*何らかの処理、ただし、hwndのテキストはコード側ではいじらない*/
        //hwnd<-対象のハンドル
        var sb = new StruingBuilder();
        var length = SendMessage(hwnd,WM_GETTEXTLENGTH,0,0);
        sb.Capacity = length *10 +1;
        Console.WriteLine("before length:"+ length);
        Thread.Sleep(200);  //無くても同じ
        length = SendMessage(hwnd,WM_GETTEXT,length *10 +1,sb);
        Console.WriteLine("before length:"+ length);
        /*何らかの処理、ただし、hwndのテキストはコード側ではいじらない*/
    }
    
[/code]




[`WM_GETTEXTLENGTH`](https://msdn.microsoft.com/en-
us/library/ms632628\(v=vs.85\).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の２種類が存在し、APIとしてもUnicodeとANSIの２バージョンが用意されています。アプリケーションの動作モードと`SendMessage`とが異なる場合、実際の文字数ではなく文字列を格納可能な大きめのバッファサイズを返すそうです。

* * *

> sbには実際の文字列が途切れて格納されていました。  
>  SendMessageは[DllImport("user32.dll", CharSet = CharSet.Auto)]としています

`WM_GETTEXTLENGTH`はANSIバージョンが呼び出された場合、当然ながらANSI文字列のバイト数を返しますし、`WM_GETTEXT`が`WPARAM`で要求するバッファサイズも呼び出したバージョンに依存します。ところが`StringBuilder`が保持するバッファのサイズは常にUnicodeの文字数です。質問文に挙げられているコードはバッファサイズの単位が一致しておらず非常に不安定です。

Unicodeに統一すると共に、`WM_GETTEXT`呼び出し前に`StringBuilder`のバッファサイズを確保すべきです。なお、`StringBuilder`の既定のバッファサイズは16文字ですのでたいていの場合にあふれています。

[code]

    [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のテキストはコード側ではいじらない*/
    }
    
[/code]

