Exception в SHGetFileInfo. Вопрос к специалистам WINAPI.
От: bespalovdn  
Дата: 14.10.09 07:54
Оценка:
Всем привет!
У меня проблема с использованием вышеназванной функции в моей программе, и я никак не могу найти хоть сколько -нибудь похожую проблему и её решение в интернете. Суть в следующем. Для получения иконки файла я использую функцию SHGetFileInfo вот таким образом:

SHFILEINFO fi = {0};
::SHGetFileInfo( fileName.c_str(), // Здесь полное имя файла, включая путь к нему
   fileAttributes, // Здесь атрибуты файла полученные с WIN32_FIND_DATA.dwFileAttributes
   &fi, sizeof(SHFILEINFO), 
   SHGFI_ICON | SHGFI_SMALLICON | SHGFI_ADDOVERLAYS | SHGFI_USEFILEATTRIBUTES );


"Особенность" состоит в том, что функция вызывается в отдельном от основного окна потоке. А проблема моя в том, что при каждом вызове этой функции внутри неё происходит исключение, которое в моём output-окне в отладчике выглядит следующим образом:
First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: GCError @ 0x0171ef98.
First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: [rethrow] @ 0x00000000.
Исключение видимо успешно ловится внутри самой функции, и стэк не разворачивается за её пределами, то есть мой код после её вызова идёт дальше нормально, и можно было бы закрыть глаза на этот косяк и забить. Но это исключение каким-то образом влияет на очередь асинхронных сообщений в основном потоке, и я их попросту теряю.
В ходе экспериментов с передаваемыми в неё флагами, удалось выяснить, что исключение не генерится, если убрать флаг SHGFI_ADDOVERLAYS.
Но это еще не всё. Проблема с исключением в этой функции проявляется на моей рабочей 2-х ядерной машине, однако дома на одноядерной тачке всё замечательно, ни каких исключений в SHGetFileInfo, никаких потерь асинхронных сообщений в основном потоке.

Буду очень признателен всем откликнувшимся.
Здесь вы можете разместить вашу рекламу.
Re: Exception в SHGetFileInfo. Вопрос к специалистам WINAPI.
От: Юрий Жмеренецкий ICQ 380412032
Дата: 14.10.09 08:49
Оценка: +2
Здравствуйте, bespalovdn, Вы писали:

[...]

B>В ходе экспериментов с передаваемыми в неё флагами, удалось выяснить, что исключение не генерится, если убрать флаг SHGFI_ADDOVERLAYS.

B>Но это еще не всё. Проблема с исключением в этой функции проявляется на моей рабочей 2-х ядерной машине, однако дома на одноядерной тачке всё замечательно, ни каких исключений в SHGetFileInfo, никаких потерь асинхронных сообщений в основном потоке.

С вероятностью 90% это связано с чужим расширением (как например Tortoise SVN). См. список загруженных модулей до/после вызова SHGetFileInfo. + Нужно проверить на "чистой" ОС.
Re[2]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: DmitryCPP  
Дата: 14.10.09 09:53
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>С вероятностью 90% это связано с чужим расширением (как например Tortoise SVN). См. список загруженных модулей до/после вызова SHGetFileInfo. + Нужно проверить на "чистой" ОС.

Да, у меня действительно стоит Tortoise SVN. Причём на обоих компах. Однако на однопроцессорном компе всё пучком. Кстати, что на самом деле может сделать тортила (или подобная прога, которая прописывает оверлеи к иконкам, как я понимаю проблема в этом?) с SHGetFileInfo такого чтобы та стала кидаться исключениями?
Здесь вы можете разместить вашу рекламу.
Re[3]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: De-Bugger  
Дата: 14.10.09 10:56
Оценка:
Здравствуйте, DmitryCPP, Вы писали:

DCP>что на самом деле может сделать тортила (или подобная прога, которая прописывает оверлеи к иконкам, как я понимаю проблема в этом?) с SHGetFileInfo такого чтобы та стала кидаться исключениями?


Ну к примеру, коряво реализовать IShellIconOverlay в одном из своих расширений. Уж поверьте мне, с недели 3 назад чуть с ума не сошел пытаясь решить вот эту
Автор: De-Bugger
Дата: 23.09.09
проблему, а дело оказалось в чужом кривом расширении.
Re[4]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: DmitryCPP  
Дата: 14.10.09 11:08
Оценка:
Здравствуйте, De-Bugger, Вы писали:

DB>Ну к примеру, коряво реализовать IShellIconOverlay в одном из своих расширений. Уж поверьте мне, с недели 3 назад чуть с ума не сошел пытаясь решить вот эту
Автор: De-Bugger
Дата: 23.09.09
проблему, а дело оказалось в чужом кривом расширении.


Выходит что обходного пути, или решения данной проблемы кроме как отказаться от использования SHGetFileInfo вообще не существует? Если я стану использовать вместо этой функции IShellFolder + IExtractIcon, не застряну ли я с той же самой проблемой? Может быть существуют другие способы получения иконок с оверлеями? Explorer же справляется как-то с этой задачей, даже в условиях наличия установленных коряво реализующих IShellIconOverlay программ.
Здесь вы можете разместить вашу рекламу.
Re[3]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: Pavel Dvorkin Россия  
Дата: 14.10.09 11:54
Оценка:
Здравствуйте, DmitryCPP, Вы писали:


DCP>Да, у меня действительно стоит Tortoise SVN. Причём на обоих компах. Однако на однопроцессорном компе всё пучком.


Не аргумент. Баги в многопоточности очень легко сделать, причем на одном ядре они могут не проявляться, так как истинной многопоточности там все же нет.

>Кстати, что на самом деле может сделать тортила (или подобная прога, которая прописывает оверлеи к иконкам, как я понимаю проблема в этом?) с SHGetFileInfo такого чтобы та стала кидаться исключениями?


Что угодно. Она встроила тебе в процесс свою(свои) DLL. Они теперь часть твоего процесса. Срабатывает хук, управление в твоем процессе, но код от тортилы. Все шишки на твою голову, хотя ты и не виноват. Проклятие хуков.
With best regards
Pavel Dvorkin
Re: Exception в SHGetFileInfo. Вопрос к специалистам WINAPI.
От: Pavel Dvorkin Россия  
Дата: 14.10.09 12:05
Оценка:
Здравствуйте, bespalovdn, Вы писали:

B>First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: GCError @ 0x0171ef98.

B>First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: [rethrow] @ 0x00000000.
B>Исключение видимо успешно ловится внутри самой функции, и стэк не разворачивается за её пределами, то есть мой код после её вызова идёт дальше нормально, и можно было бы закрыть глаза на этот косяк и забить. Но это исключение каким-то образом влияет на очередь асинхронных сообщений в основном потоке, и я их попросту теряю.

First-chance exception означает вот что. Исключение произошло. И в данном случае это программно сгенерированное исключение (Microsoft C++ exception), то есть вызвано оно throw из C++, который в конечном счете вызывает RaiseException. Любое исключение передается твоему отладчику, может, это его дело ? (например, исключение в точке из-за того, что он в код брекпойнт вставил). Но отладчик ответил — нет, это не мое дело. Тогда исключение идет обратно в программу — ей дается шанс его обработать, catch (или __except, в зависимости от того, что используется). Вот она и обработала. То есть имело место

try {//..
}
catch(что-то)
{ // и сюда попали
}

И вот этот обработчик исключения написан не вполне верно. Из-за этого и не работает очередь асинхронных событий. А программа не падает — формально все в порядке.
Если же исключение программа не обработала, то его вновь передают отладчику (второе предупреждение), и тут он уже выведет известное окно с сообщением об исключении.

Рекомендация. Убедиться еще раз, что виной тортила. Может быть, даже пойти на дезактивацию ее. Понимаю, что такой совет дать легче, чем выполнить, но если это важно. Либо поставить свежую инсталляцию ОС и попробовать там. В общем, первым делом надо найти виновного. А потом — увы. трудно сказать. Вполне возможно, что и не лечится. Но по крайней мере будешь знать, что ты не виноват.
With best regards
Pavel Dvorkin
Re[2]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: DmitryCPP  
Дата: 14.10.09 13:04
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, bespalovdn, Вы писали:


B>>First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: GCError @ 0x0171ef98.

B>>First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: [rethrow] @ 0x00000000.
B>>Исключение видимо успешно ловится внутри самой функции, и стэк не разворачивается за её пределами, то есть мой код после её вызова идёт дальше нормально, и можно было бы закрыть глаза на этот косяк и забить. Но это исключение каким-то образом влияет на очередь асинхронных сообщений в основном потоке, и я их попросту теряю.

PD>First-chance exception означает вот что. Исключение произошло. И в данном случае это программно сгенерированное исключение (Microsoft C++ exception), то есть вызвано оно throw из C++, который в конечном счете вызывает RaiseException. Любое исключение передается твоему отладчику, может, это его дело ? (например, исключение в точке из-за того, что он в код брекпойнт вставил). Но отладчик ответил — нет, это не мое дело. Тогда исключение идет обратно в программу — ей дается шанс его обработать, catch (или __except, в зависимости от того, что используется). Вот она и обработала. То есть имело место


PD>try {//..

PD>}
PD>catch(что-то)
PD>{ // и сюда попали
PD>}

PD>И вот этот обработчик исключения написан не вполне верно. Из-за этого и не работает очередь асинхронных событий. А программа не падает — формально все в порядке.

PD>Если же исключение программа не обработала, то его вновь передают отладчику (второе предупреждение), и тут он уже выведет известное окно с сообщением об исключении.

PD>Рекомендация. Убедиться еще раз, что виной тортила. Может быть, даже пойти на дезактивацию ее. Понимаю, что такой совет дать легче, чем выполнить, но если это важно. Либо поставить свежую инсталляцию ОС и попробовать там. В общем, первым делом надо найти виновного. А потом — увы. трудно сказать. Вполне возможно, что и не лечится. Но по крайней мере будешь знать, что ты не виноват.


======================================
То, что не моя вина, это я знаю 100%. Проверяется просто: брэйк-поинт перед ::SHGetFileInfo, и еще один сразу после неё. Попадаем на первый бряк — смотрим в output — всё ок; едем дальше — попадаем во второй бряк — после вызова злополучной функции, смотрим output — едрён батон!
Вариант с удалением тортилы, и продолжением работы для меня конечно может и сработает. Но для других потенциальных пользователей проги проблема останется.
Насчёт возможных проблем с работой проги из-под дебаггера: пробовал запускать одтельно без аттача, результат — асинхронные сообщения теряются, следовательно дебаггер тут не причём.
Здесь вы можете разместить вашу рекламу.
Re[3]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: Юрий Жмеренецкий ICQ 380412032
Дата: 14.10.09 13:21
Оценка:
Здравствуйте, DmitryCPP, Вы писали:

DCP>Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>>С вероятностью 90% это связано с чужим расширением (как например Tortoise SVN). См. список загруженных модулей до/после вызова SHGetFileInfo. + Нужно проверить на "чистой" ОС.

DCP>Да, у меня действительно стоит Tortoise SVN. Причём на обоих компах. Однако на однопроцессорном компе всё пучком. Кстати, что на самом деле может сделать тортила (или подобная прога, которая прописывает оверлеи к иконкам, как я понимаю проблема в этом?) с SHGetFileInfo такого чтобы та стала кидаться исключениями?


SHGetFileInfo косвенно приводит к выполнению кода из соответствующих расширений. А сделать она она может что угодно. Например, в версии 1.3.5 (кажется) в специфических условиях вызвала VirtualFree для блока памяти, полученного через CoTaskMemAlloc.

1) Что возвращает SHGetFileInfo в случае наличия исключения?
2) Ты говорил про отдельный поток, там COM инициализируется? попробуй CoInitializeEx + COINIT_MULTITHREADED.
3) Исходники Tortoise доступны (*) — можно там поискать в каких случаях генерируется такое исключение (если это вообще SVN).

* Head revision username — guest, без пароля
Re[4]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: DmitryCPP  
Дата: 14.10.09 13:57
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>SHGetFileInfo косвенно приводит к выполнению кода из соответствующих расширений. А сделать она она может что угодно. Например, в версии 1.3.5 (кажется) в специфических условиях вызвала VirtualFree для блока памяти, полученного через CoTaskMemAlloc.


ЮЖ>1) Что возвращает SHGetFileInfo в случае наличия исключения?

ЮЖ>2) Ты говорил про отдельный поток, там COM инициализируется? попробуй CoInitializeEx + COINIT_MULTITHREADED.
ЮЖ>3) Исходники Tortoise доступны (*) — можно там поискать в каких случаях генерируется такое исключение (если это вообще SVN).

ЮЖ>* Head revision username — guest, без пароля


Я забыл про инициализацию CoInitialize в отдельном потоке! Исключения валиться перестали. SHGetFileInfo раньше и сейчас возвращала 1, и хэндлы иконок всегда валидные.
Однако с асинхронными сообщениями всё равно что-то не то. Приводить здесь весь код участвующий во всей этой обработке не представляется возможным, поэтому попробую сам разобраться с деталями. В любом случае, спасибо за ценные советы!
Здесь вы можете разместить вашу рекламу.
Re[3]: Exception в SHGetFileInfo. Вопрос к специалистам WINA
От: Pavel Dvorkin Россия  
Дата: 15.10.09 02:34
Оценка:
Здравствуйте, DmitryCPP, Вы писали:

B>>>First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: GCError @ 0x0171ef98.

B>>>First-chance exception at 0x7c812a5b in FM.exe: Microsoft C++ exception: [rethrow] @ 0x00000000.

DCP>То, что не моя вина, это я знаю 100%. Проверяется просто: брэйк-поинт перед ::SHGetFileInfo, и еще один сразу после неё. Попадаем на первый бряк — смотрим в output — всё ок; едем дальше — попадаем во второй бряк — после вызова злополучной функции, смотрим output — едрён батон!

DCP>Вариант с удалением тортилы, и продолжением работы для меня конечно может и сработает. Но для других потенциальных пользователей проги проблема останется.

Кстати, можешь легко узнать, где произошло исключение. Поставь брекпойнт в какое-нибудь место , так, чтобы он сработал после выдачи этих сообщений о
first-chance exception. Далее посмотри Debug-Modules и найди, в пределах которого лежит адрес 0x7c812a5b


DCP>Насчёт возможных проблем с работой проги из-под дебаггера: пробовал запускать одтельно без аттача, результат — асинхронные сообщения теряются, следовательно дебаггер тут не причём.


Конечно, ни при чем. При его отсутствии схема обработки исключения примерно та же, только все, что написано про дебаггер, надо опустить, а в случае необработанного исключения вместо окна дебаггера об исключении получишь всем хорошо известное окно
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.