2011-12-24 4 views
0

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

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

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

問題は、関数によって返された文字列を読み込もうとしているときにエラーが発生する可能性があることです。

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 written wcout命令を正しく実行します。私は問題がコンソールでは処理できない文字に問題があるのか​​、これらの文字が次のキャラクタの動作やコンソールカーソルを変更する可能性があるのか​​と疑問に思っていました。出力が見えなくなりましたが、出力ストリームを入れ替えてそれはファイル(wofstream)になり、ファイルのサイズは47バイトでした。これはコンソールストリームに書き込まれたものとまったく同じです。

アクセス違反、例外、ログエントリ、何も取得できません。デバッガ(VS2010)でも例外の可能性のあるすべての型を壊すことを選択した後に例外を書き留めません - さらに驚くべきことは、デバッガでコードをステップ実行し、そこで地元の人たちが期待値を得ていることです68と、バッファ内の現在のwchar_tに値(ゴミのUnicode文字を)持っている

は誰、この動作を説明してもらえ

編集:。?

で印刷ループを交換する:

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; 
} 

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

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

+0

ストリームのエラーをチェックしてみましたか?私はあなたが何かを無効にすることを試みていると確信して、フェイルビットが設定されています。 – Hurkyl

答えて

3

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

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

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

したがって、この目的でstd::wostreamを使用しないことをお勧めします。私はこれがあなたの問題に役立つことを願っています。

+0

いいえ、unicode_strには無効なユニコードデータが含まれています。質問にはガベージデータが含まれています。 –

2

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

iostreamがmystifyingly動作しているときfailbitまたはeofbit(または時々badbit)が設定されますので、ほとんどの時間は、それはです。これらの悪い状態のいずれかにある場合、I/O操作は一般的に(常に?)何もせずにすぐに戻ります。

ユニコードデータが正しくないと仮定すると、failbitまたはbadbitが設定されます。

一般的なデバッグの原則として、私がiostreamが不思議なふるまいをするのを見たとき、私がチェックする最初のことはストリームがまだ良好であることを確認することです。そして、ほとんど毎回、私はストリームが実際には良くないことを発見し、不思議な振る舞いを完全に説明しています。

ストリームが不良であることがわかったら、実行するアクションを決めることができます。悪いユニコードデータの場合は、ストリームの状態を良い状態に戻すだけで十分でしょう - 確かめるためには、私は十分にユニコードI/Oについて知りません。

関連する問題