Я пишу приложение, которое взаимодействует через механизм 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).
Может ли кто-нибудь объяснить это поведение?
Edit:
замена цикла печати на:
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 мешает выходному потоку принимать что-либо?