Поведение DebugBreak отличается между неуправляемым и смешанным (неуправляемым + управляемым) приложением?
Возьмите следующий простой источник (назовите его test.cpp):
#include <windows.h>
void main()
{
DebugBreak();
}
Скомпилируйте и скомпонуйте это, используя следующие команды:
cl /MD /c test.cpp
link /debug test.obj
Если сейчас запущен TEST.EXE (в 64-битной системе Windows 7), вы получите следующий диалог:
Теперь добавьте следующий исходный файл (назовите его test2.cpp):
void hello()
{
}
И скомпилируйте и свяжите это вместе с первым источником, например так:
cl /MD /c test.cpp
cl /MD /c /clr test2.cpp
link test.obj test2.obj
Обратите внимание, что мы даже не вызывали функцию hello, мы просто связали ее.
Теперь снова запустите TEST.EXE (в той же 64-битной системе Windows 7). Вместо диалогового окна, показанного выше, вы получите это:
Очевидно, что ссылки в среде.Net заставляют DebugBreak вести себя по-другому. Почему это? И как мне вернуть старое поведение DebugBreak обратно? Возможно, это Windows 7 или 64-разрядное поведение?
Дополнительное замечание, поясняющее, почему я хочу использовать DebugBreak: у нас есть специальная assert-framework (что-то вроде SuperAssert из книги отладочных приложений Windows Джона Роббина), и я использую функцию DebugBreak, чтобы разработчик мог перейти в отладчик (или откройте новый отладчик), если есть проблема. Теперь есть только простое всплывающее окно и больше нет возможности перейти к отладчику.
В качестве альтернативного решения я мог бы выполнить деление на ноль или запись в неправильный адрес, но я считаю это менее чистым решением.
РЕДАКТИРОВАТЬ: это стек вызовов во втором тесте (простой диалог):
ntdll.dll!_NtRaiseHardError@24() + 0x12 bytes
ntdll.dll!_NtRaiseHardError@24() + 0x12 bytes
clrjit.dll!Compiler::compCompile() + 0x5987 bytes
clr.dll!RaiseFailFastExceptionOnWin7() + 0x6b bytes
clr.dll!WatsonLastChance() + 0x1b8 bytes
clr.dll!InternalUnhandledExceptionFilter_Worker() + 0x29c bytes
clr.dll!InitGSCookie() + 0x70062 bytes
clr.dll!__CorExeMain@0() + 0x71111 bytes
msvcr100_clr0400.dll!@_EH4_CallFilterFunc@8() + 0x12 bytes
msvcr100_clr0400.dll!__except_handler4_common() + 0x7f bytes
clr.dll!__except_handler4() + 0x20 bytes
ntdll.dll!ExecuteHandler2@20() + 0x26 bytes
ntdll.dll!ExecuteHandler@20() + 0x24 bytes
ntdll.dll!_KiUserExceptionDispatcher@8() + 0xf bytes
KernelBase.dll!_DebugBreak@0() + 0x2 bytes
test_mixed.exe!01031009()
Это стек вызовов в первом тесте (диалог с вариантами "закрыть" и "отладка"):
ntdll.dll!_ZwWaitForMultipleObjects@20() + 0x15 bytes
ntdll.dll!_ZwWaitForMultipleObjects@20() + 0x15 bytes
kernel32.dll!_WaitForMultipleObjectsExImplementation@20() + 0x8e bytes
kernel32.dll!_WaitForMultipleObjects@16() + 0x18 bytes
kernel32.dll!_WerpReportFaultInternal@8() + 0x124 bytes
kernel32.dll!_WerpReportFault@8() + 0x49 bytes
kernel32.dll!_BasepReportFault@8() + 0x1f bytes
kernel32.dll!_UnhandledExceptionFilter@4() + 0xe0 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x369cc bytes
ntdll.dll!@_EH4_CallFilterFunc@8() + 0x12 bytes
ntdll.dll!ExecuteHandler2@20() + 0x26 bytes
ntdll.dll!ExecuteHandler@20() + 0x24 bytes
ntdll.dll!_KiUserExceptionDispatcher@8() + 0xf bytes
KernelBase.dll!_DebugBreak@0() + 0x2 bytes
test_native.exe!00af1009()
Разница начинается в ntdll.dll!Executehandler2@20. В не -.net приложении это вызывает ntdll.dll!@_EH4_CallFilterFunc
, В приложении.net есть звонки clr.dll!__except_handler4
,
1 ответ
Я нашел решение на следующей странице: http://www.codeproject.com/KB/debug/DebugBreakAnyway.aspx.
Вместо того, чтобы просто писать DebugBreak, вы должны встроить вызов DebugBreak между __try/__ кроме конструкции, например так:
__try
{
DebugBreak();
}
__except (UnhandledExceptionFilter(GetExceptionInformation()))
{
}
По-видимому, функция UnhandledExceptionFilter обрабатывает исключение DebugBreak по умолчанию, которое, по-видимому, отменяется в приложении в смешанном режиме.
Теперь вы снова получите оригинальный диалог.