2011-12-24 95 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的足够信息。