2011-12-24 166 views
0

我正在編寫一個應用程序,通過Windows RPC機制與另一個進程中的託管接口進行通信。C++吞嚥錯誤

通過標準的內置NDR處理封送處理。該接口公開了幾個函數,其中一個函數通過參數返回一個字符串(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個字符(不管緩衝器中的內容 - 它是垃圾數據),並且正確地步入最後的012cwcout指令。我想知道如果問題是控制檯無法處理的無法讀取的字符,並且這些字符可能會改變下一個字符的行爲或控制檯光標 - 並且會使輸出不可見,但是不會 - 我已交換輸出流並設置它到一個文件(wofstream)並且文件的大小是47個字節 - 這與寫入到控制檯流的數量完全相同。

我沒有得到任何訪問衝突,任何異常,任何日誌條目,什麼都沒有。即使調試器(VS2010)在選擇中斷每種可能類型的異常之後也沒有注意到任何異常 - 更令人驚訝的是,使用調試器逐步執行代碼並觀察當地人產生期望值(我從0 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 2011-12-24 16:56:13

回答

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 s爲此目的。我希望這可以幫助你解決你的問題。

+0

不,unicode_str包含無效的unicode數據 - 我在問題中提到它正在保存垃圾數據。 – 2011-12-24 20:04:11

2

實際上,我確信你的問題是我要做出答案而不是在評論中提出問題。

大多數時候,當iostream被mystifyingly表現,這是因爲failbiteofbit(或有時badbit)被設定。當處於這些不良狀態之一時,I/O操作通常會(總是)立即返回而不做任何事情。

我認爲不好的Unicode數據將導致failbitbadbit被設置。

作爲一般的調試原理,當我看到一個iostream表現神祕時,我首先檢查的是確保流仍然很好。幾乎每一次,我發現這個流事實上並不好,完全解釋了這個神祕的行爲。

一旦你知道流是壞的,你可以決定採取一些行動。對於錯誤的unicode數據,也許只需將流的狀態重新設置爲一個好的狀態就足夠了 - 我無法確定unicode I/O的足夠信息。