1

別のプロセスでホストされたインターフェイスと Windows RPC メカニズムを介して通信するアプリケーションを作成しています。

マーシャリングは、標準の組み込み NDR によって処理されます。インターフェイスはいくつかの関数を公開しますが、そのうちの 1 つUNICODE_STRINGはパラメーターを介して文字列 ( ) を返します。

この関数は、成功した場合は 0 を返し、それ以外の場合はエラー コードを返します。RPC 関数を呼び出すと、成功し、UNICODE_STRING パラメータが設定されます。

問題は、C++ またはランタイムのいずれかが、関数によって返された文字列を読み取ろうとしているときに発生するエラーを飲み込むことです。多くのコードを読む手間を省くために、私のコードの簡略版を次に示します。

void func()
{
    UNICODE_STRING unicode_str;

    HMODULE hLib = LoadLibrary(L"Ntdll.dll");
    RtlInitUnicodeStringFn fn;

    fn = (RtlInitUnicodeStringFn) GetProcAddress(hLib, "RtlInitUnicodeString");
    fn(&unicode_str, NULL);

    std::cout << "Before calling RPC the buffer was pointing at: " << std::hex << unicode_str.Buffer << std::endl;

    if(call(binding.get_binding_handle(), &unicode_str))
    {
        std::cout << "len: " << unicode_str.Length << " maxlen: " << unicode_str.MaximumLength << std::endl;
        std::cout << "After calling RPC the buffer is pointing at: " << std::hex << unicode_str.Buffer << std::endl;
        try
        {
            for(int i = 0; i < unicode_str.Length; i++)
                std::wcout << i << ": " << unicode_str.Buffer[i] << std::endl;
        }
        catch(...)
        {
            std::cout << "Caught an exception";
        }
        std::wcout << "I won't be written" << std::endl;
    }
}

bool call(void* handle, PUNICODE_STRING str)
{
    __try
    {
        std::cout << "RPC call returned: " << RpcInterfaceFunction(handle, str) << std::endl;
        return true;
    }
    __except(1)
    {
        std::cout << "Error: " << std::dec << GetExceptionCode() << std::endl;
        return false;
    }
}

このコードを実行すると、出力は次のようになります。

Before calling RPC the buffer is pointing at : 000000000
RPC call returned: 0
len:68, maxlen: 70
After calling RPC the buffer is pointing at: 00746168
0: #
1: t
2: 

そして戻ります。私はこの関数をデバッガーでステップ実行しましたが、68 文字全体を正しく処理し (バッファーの内容に関係なく、ガベージ データです)、最後のI won't be writtenwcout 命令に正しくステップインします。コンソールが処理できない判読不能な文字に問題があり、これらの文字が次の文字の動作またはコンソールカーソルを変更する可能性があるかどうか疑問に思いました-それは出力を非表示にしますが、いいえ-出力ストリームを交換して設定しましたファイル (wofstream) に出力し、ファイルのサイズは 47 バイトでした。これは、コンソール ストリームに書き込まれるサイズとまったく同じです。

アクセス違反、例外、ログ エントリなどはありません。デバッガー (VS2010) でさえ、考えられるすべての種類の例外で中断することを選択した後、例外に注意しません。さらに驚くべきことは、デバッガーでコードをステップ実行し、そこでローカルを監視すると、期待値が得られることです (私は 0 から68 に変更され、バッファー内の現在の wchar_t には値 (ガベージ Unicode char) があります。

誰でもこの動作を説明できますか?

編集:

印刷ループを次のように交換します。

for(int i = 0; i < unicode_str.Length; i++)
{
    std::wcout << "I'm writing the " << i << "th character" << std::endl;
    unsigned short temp = unicode_str.Buffer[i];
    std::wcout << i << ": " << temp << std::endl;
}

67 までの値をtemp正しく出力します。

それでも、これらの文字の wchar_t バージョンを出力すると、出力ストリームが何も受け入れなくなるのはなぜでしょうか?

4

2 に答える 2

3

unicode_strに有効な Unicode データが含まれていますか?

std::wcout(および一般的な s)に関する私の経験でstd::wostreamは、無効な Unicode データが与えられるたびに、それらは悪い状態になるということです。デフォルトでは、これが発生しても例外をスローしません。内部の failbit または badbit を設定して、動作を停止するだけです。std::wcout.fail()またはを呼び出して、ストリームが不良な状態にあるかどうかを確認できます。また、 を呼び出しstd::wcout.bad()て、エラー状態フラグをクリアできますstd::wcout.clear()

また、failbit または badbit が設定されたときに例外をスローしたい場合は、 を呼び出すことができますstd::wcout.exceptions(std::wostream::failbit | std::wostream::badbit)

std::wostream要するに、この目的で s を使用しないことをお勧めします。これが問題の解決に役立つことを願っています。

于 2011-12-24T16:49:25.803 に答える
2

実際、コメントで質問するのではなく、これを回答にするのはあなたの問題であると確信しています。

iostreamほとんどの場合、が不可解な振る舞いをしているとき、それはfailbitor eofbit(または場合によってbadbitは ) が設定されているためです。これらの悪い状態の 1 つである場合、I/O 操作は通常 (常に?) 何もせずにすぐに戻ります。

不良なユニコードデータが原因であるfailbitbadbit、設定されると思います。

一般的なデバッグの原則として、iostream不可解な動作を目にした場合、最初に確認することは、ストリームがまだ良好であることを確認することです。そして、ほぼ毎回、ストリームが実際には良くないことを発見し、不可解な動作を完全に説明しています.

ストリームが悪いことがわかったら、実行するアクションを決定できます。Unicode データが悪い場合は、ストリームの状態を良い状態にリセットするだけで十分かもしれません。

于 2011-12-24T17:06:36.823 に答える