0

Cスタイルの文字列OUTパラメータを介して結果を返すWinAPI関数を指定します。例:

int WINAPI GetWindowTextW(
   _In_   HWND hWnd,
   _Out_  LPTSTR lpString,
   _In_   int nMaxCount
);

以下で行っているよりも、関数を使用するためのより良い方法はありますか?

HWND handle; // Assume this is initialised to contain a real window handle
std::wstring title;
wchar_t buffer[512];
GetWindowTextW(handle, buffer, sizeof(buffer));
title = buffer;

上記のコードは機能しますが、次の問題があります。

  1. 関数が返す可能性のある文字列の長さを知る方法がないため、バッファサイズは完全に任意です。これは私にとって「間違っている」と感じます。私は常に、コードでマジックナンバーを避けようとしてきました。

  2. 関数がバッファよりも大きい文字列を返す場合、それは切り捨てられます-これは悪いことです!

  3. 関数がバッファよりも小さい文字列を返すときはいつでも、私はメモリを浪費します。これは(2)ほど悪くはありませんが、実際には数バイトしか必要としない可能性のあるもののために、メモリの大きなチャンク(たとえば、上記の例では1024バイト)を確保するというアイデアにはわくわくしません。

他に選択肢はありますか?

4

2 に答える 2

3

異なるサイズの一時バッファーを使用して、関数を複数回呼び出します。たとえば、8のバッファから始めます。バッファサイズを2倍にして、もう一度呼び出します。前回と同じカウントが返されるまで繰り返します。次に、正確なサイズのバッファを割り当てて、そこにあるものをコピーできます。同様の動作をするWin32関数がいくつかあります。

を使用することもできますGetWindowTextLength()が、競合状態がある場合はおそらくあまり役​​に立ちません(競合状態のためにテキストが切り捨てられる可能性があります)。

于 2013-02-05T20:07:15.880 に答える
2

使用している Windows API 関数に応じて、いくつかの異なるパターンがあります。場合によっては、別の関数 (GetWindowTextLengthW など) を呼び出して最初にクエリを実行できますが、通常はバッファーに NULL を渡します。クエリを実行した後、サイズを割り当てて再度呼び出し、実際の文字列データを取得します。

query-allocate-query を使用しても、競合状態が発生する可能性があるため、反復する必要がある場合があります。たとえば、GetWindowTextLengthW 呼び出しと GetWindowTextW 呼び出しの間でウィンドウ タイトルが変更された場合に何が起こるかを考えてみましょう。

2 番目のバッファーではなく文字列自体を使用することで、余分なコピーを回避することもできます。

std::wstring GetWindowTitle(HWND hwnd) {
    std::wstring title(16, L'X');
    int cch;
    do {
      title.resize(2 * title.size());
      cch = GetWindowTextW(hwnd, &title[0], title.size());
    } while (cch + 1 == title.size());
    title.resize(cch);
    return title;
}

厄介なことですが、これは実際には Windows API の設計上の問題ではありません。API は、C++ ではなく、C インターフェイスとして設計されています。C はオブジェクト指向ではないため、文字列の処理に関してはかなり制限があります。C++ コードの場合、この例で行ったように、この種のブックキーピングをラップできます。

于 2013-02-05T22:28:43.183 に答える