Поведение DebugBreak отличается между неуправляемым и смешанным (неуправляемым + управляемым) приложением? - PullRequest
1 голос
/ 02 сентября 2010

Возьмите следующий простой источник (назовите его test.cpp):

#include <windows.h>

void main()
{
DebugBreak();
}

Скомпилируйте и скомпонуйте его, используя следующие команды:

cl /MD /c test.cpp
link /debug test.obj

Если теперь запущен TEST.EXE(в 64-битной системе Windows 7) вы получите следующее диалоговое окно:

DebugBreak in unmanaged application

Теперь добавьте следующий исходный файл (назовите его 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).Вместо диалогового окна, показанного выше, вы получите следующее:

DebugBreak in mixed-mode application

Очевидно, что ссылки в среде .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 Ответ

2 голосов
/ 10 сентября 2010

Я нашел решение на следующей странице: http://www.codeproject.com/KB/debug/DebugBreakAnyway.aspx.

Вместо того, чтобы просто писать DebugBreak, вы должны встроить вызов DebugBreak между __try / __, кроме конструкции, например:

__try
   {
   DebugBreak();
   }
__except (UnhandledExceptionFilter(GetExceptionInformation()))
   {
   }

По-видимому, функция UnhandledExceptionFilter обрабатывает исключение DebugBreak по умолчанию, которое, по-видимому, отменяется в приложении в смешанном режиме.

Теперь вы снова получаете исходный диалог.

...