C ++吞咽错误

时间:2011-12-24 15:35:33

标签: c++ string file-io buffer wofstream

我正在编写一个应用程序,它通过Windows RPC机制与另一个进程中的托管接口进行通信。

编组是通过标准的内置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个字符(无论缓冲区中的内容 - 它是垃圾数据)并正确地进入最后一个I won't be written wcout指令。我想知道问题是否是控制台无法处理的不可读字符,这些字符可能会改变下一个字符的行为或控制台光标 - 这会使输出不可见,但是没有 - 我交换了输出流并设置了它是一个文件(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;
}

temp的值正确打印到67。

但是,为什么打印这些字符的wchar_t版本会阻止输出流接受任何内容?

2 个答案:

答案 0 :(得分:3)

您确定unicode_str包含有效的Unicode数据吗?

我对std::wcout(以及std::wostream s)的体验是,只要给出无效的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。我希望这可以帮助您解决问题。

答案 1 :(得分:2)

实际上,我很有信心,这是你的问题,我会把这个问题作为答案,而不是在评论中提出问题。

大多数情况下,当iostream表现得很神秘时,这是因为failbiteofbit(或有时badbit)被设置了。当处于这些错误状态之一时,I / O操作通常(总是?)立即返回而不做任何事情。

我认为错误的unicode数据会导致设置failbitbadbit

作为一般调试原则,当我看到iostream表现得很神秘时,我首先检查的是确保流仍然良好。几乎每一次,我发现这条流实际上并不好,完全解释了神秘的行为。

一旦你知道流是坏的,你可以决定采取一些行动。对于糟糕的unicode数据,也许只需将流的状态重置为一个好的状态 - 我对unicode I / O的了解还不够。