Недавно наткнулся на непонятную проблему. В небольших консольных прогах я использую маленькую dll собственного написания которая среди всего прочего ставит обработчик исключений вызывая SetUnhandledExceptionFilter (я это делал и в Dllmain, если код запроса =DLL_PROCESS_ATTACH и в отдельной экспортируемой функции вызывая её из главного модуля — на результат это не влияет). Обработчик выводил в консоль с помощью WriteConsole сообщение и завершал процесс. Однако когда я попробовал использовать свою dll в более сложной программе, где кроме главного модуля и библиотеки с обработчиком есть ещё одна dll, в которой и генерируется исключение, я обнаружил, что WriteConsole возвращается с ошибкой, а последующий вызов GetLastError даёт ERROR_INVALID_HANDLE, хотя хэндл, который я получал в dllmain или в специальной функции инициализации вызывая GetStdHandle был вполне валидным, по крайней мере до исключения.
Во вложении приведены два тестовых примера на ассемблере (код и бинарники), синтаксис fasm (sorry, на С я писать не умею)
После долгих экспериментов я выяснил, что проблему удаётся решить вызывая AllocConsole и GetStdHandle непосредственно в обработчике исключения (одного только GetStdHandle недостаточно). Однако это очень не удобно для консольных приложений.
Кто-нибудь сталкивался с пободной проблемой? Возможно, есть какие-нибудь предположения, почему исключение "портит" стандартный вывод (не просто хэндл, а весь канал), в тестовом примере я генерирую его обычным
xor eax,eax
mov [eax],eax
и проблем оно вызывать не должно. И почему портит его только исключение в дополнительной dll, но не портит исключение в главном модуле?
Здравствуйте, MescalitoPeyot, Вы писали:
MP>Недавно наткнулся на непонятную проблему. В небольших консольных прогах я использую маленькую dll собственного написания которая среди всего прочего ставит обработчик исключений вызывая SetUnhandledExceptionFilter (я это делал и в Dllmain, если код запроса =DLL_PROCESS_ATTACH и в отдельной экспортируемой функции вызывая её из главного модуля — на результат это не влияет). Обработчик выводил в консоль с помощью WriteConsole сообщение и завершал процесс. Однако когда я попробовал использовать свою dll в более сложной программе, где кроме главного модуля и библиотеки с обработчиком есть ещё одна dll, в которой и генерируется исключение, я обнаружил, что WriteConsole возвращается с ошибкой, а последующий вызов GetLastError даёт ERROR_INVALID_HANDLE, хотя хэндл, который я получал в dllmain или в специальной функции
1. все dll/exe консольные?
2. мб консоль не иниц до вызова exe, а искл происходит в dllmain
3. мб установлен другой фильтр, который снимает консоль и вызывает твой
4. у меня в SetUnhandledExceptionFilter сначала пытается вывести в консоль по WriteConsole, если неудача, то WriteFile туда же, если снова не удача, то выдается диалог.
СМ>1. все dll/exe консольные? СМ>2. мб консоль не иниц до вызова exe, а искл происходит в dllmain СМ>3. мб установлен другой фильтр, который снимает консоль и вызывает твой СМ>4. у меня в SetUnhandledExceptionFilter сначала пытается вывести в консоль по WriteConsole, если неудача, то WriteFile туда же, если снова не удача, то выдается диалог.
1. Да. Хотя в gui наблюдается тоже самое
2. Нет. Эксперементируя я сам генерировал исключение
3. Фильтр в программе один
4. Т. е. такие траблы наблюдаются? А часто бывает так, что WriteConsole не срабатывает, а WriteFile — работает?
Блин, что-то у меня проблемы с вложением, выложу код тестовых примеров здесь (заранее прошу прощения за большой пост):
seh.dll — с обработчиком
format PE Dll
entry start
include'%FASM%\include\win32a.inc'section'.data'data readable writeable
nStCon dd 0
hOut dd 0
hello db'Hello world',0
section'.code'code readable executable
FinalSEH:
xor eax,eax
push eax
push nStCon
push 11
push hello
push [hOut]
call [WriteConsole]
xor eax,eax
inc eax
ret 4
outit:
push [hOut]
call [CloseHandle]
jmp endstart
start:
mov eax,[esp+8]
test eax,eax
jz outit
dec eax
jz init
mov eax,esp
endstart:
ret 12
init:
push FinalSEH
call [SetUnhandledExceptionFilter]
push STD_OUTPUT_HANDLE
call [GetStdHandle]
mov [hOut],eax
jmp endstart
Init:
ret
section'.idata'import data readable writeable
library kernel32,'KERNEL32.DLL'import kernel32,\
WriteConsole,'WriteConsoleA',\
AllocConsole,'AllocConsole',\
GetStdHandle,'GetStdHandle',\
SetUnhandledExceptionFilter,'SetUnhandledExceptionFilter',\
ExitProcess,'ExitProcess',\
CloseHandle,'CloseHandle'section'.edata'export data readable
export'SEH.DLL',\
Init,'Init'section'.reloc' fixups data discardable
layer.dll — дополнительная библиотека, в которой генерируется исключение
format PE Dll
entry start
include'%FASM%\include\win32a.inc'section'.code' readable executable
start:
mov eax,esp
ret 12
Start:
xor ebx,ebx
mov [ebx],ebx
push ebx
call [ExitProcess]
section'.idata'import data readable writeable
library kernel32,'KERNEL32.DLL',\
seh,'SEH.DLL'import kernel32,\
ExitProcess,'ExitProcess'import seh,\
Init,'Init'section'.edata'export data readable
export'LAYER.DLL',\
Start,'Start'section'.reloc' fixups data discardable
test1.asm — первый пример, главный модуль + seh.dll, WriteConsole работает
format PE at 400000h
entry start
include'%FASM%\include\win32a.inc'section'.code'code readable executable
start:
call [Init]
xor eax,eax
mov [eax],eax
section'.idata'import data readable writeable
library kernel32,'KERNEL32.DLL',\
seh,'SEH.DLL'import kernel32,\
ExitProcess,'ExitProcess'import seh,\
Init,'Init'
test2.asm — второй пример, главный модуль + seh.dll + layer.dll в которой генерируется исключение, WriteConsole не работает
format PE GUI 4.0 at 400000h
entry start
include'%FASM%\include\win32a.inc'section'.code' readable executable
start:
xor ebx,ebx
call [Init]
call [Start]
push ebx
call [ExitProcess]
section'.idata'import data readable writeable
library kernel32,'KERNEL32.DLL',\
layer,'LAYER.DLL',\
seh,'SEH.DLL'import kernel32,\
ExitProcess,'ExitProcess'import layer,\
Start,'Start'import seh,\
Init,'Init'
Наличие вызова AllocConsole в seh.dll, размещение SetUnhandledExceptionFilter и GetStdHandle в dllmain или в специальной процедуре инициализации библиотеки, дополнительный GetStdHandle в обработчике исключений проблемы не решают — установлено опытным путём
СМ>>4. у меня в SetUnhandledExceptionFilter сначала пытается вывести в консоль по WriteConsole, если неудача, то WriteFile туда же, если снова не удача, то выдается диалог.
MP>4. Т. е. такие траблы наблюдаются? А часто бывает так, что WriteConsole не срабатывает, а WriteFile — работает?
Если вывод переназначен, я не знаю, будет ли работать WriteConsole.