Есть моя программа (EXE) на C++/MFC, она установлена на 10050 компьютерах пользователей по всей Руси великой. Есть DLL сторонних разработчиков (программный интерфейс к устройству), кот. также используется на большом (сотни тысяч?) к-ве компьютеров. В процессе работы эта программа динамически загружает(LoadLibrary) эту DLL и вызывает из нее ф-цию int func(int param).
Идиётские разработчики DLL выпустили новую версию этой самой DLL, в которой та же (!) функция теперь описывается как int func(int param, char otherParam). Более того, выпустив новую версию DLL, эти альтернативно одаренные забыли (!) поменять в ней номер версии (VERSIONINFO) — их техподдержка признала эту ошибку. И теперь моя программа, соответственно, никак не может понять, какой набор параметров функции func() использовать. Реально программа сейчас использует старый интерфейс (int func(int param)), и если вдруг попадается пользователь с новой версией DLL, то программа тупо падает при попытке вызвать ф-цию func().
Вопрос: могу ли я как-то отловить это падение? Каким-нибудь try/catch? Если да, то каким именно?
(У меня нет у-ва, интерфейсом к которому служит DLL, и я тестировать на своем компьютере я не могу)
Здравствуйте, sushko, Вы писали:
S>Вопрос: могу ли я как-то отловить это падение? Каким-нибудь try/catch? Если да, то каким именно?
MFC вроде не поддерживает SEH.
Надо искать другой способ. Чем еще новая DLL отличается от старой? Например, может быть в новой версии появилась новая функция?
S>(У меня нет у-ва, интерфейсом к которому служит DLL, и я тестировать на своем компьютере я не могу)
Можно сделать фейковую DLL с пустыми телами методов, но которые будут возвращать какие-нибудь постоянные валидные значения.
Здравствуйте, sushko, Вы писали:
S>Есть моя программа (EXE) на C++/MFC, она установлена на 10050 компьютерах пользователей по всей Руси великой. Есть DLL сторонних разработчиков (программный интерфейс к устройству), кот. также используется на большом (сотни тысяч?) к-ве компьютеров. В процессе работы эта программа динамически загружает(LoadLibrary) эту DLL и вызывает из нее ф-цию int func(int param).
S>Идиётские разработчики DLL выпустили новую версию этой самой DLL, в которой та же (!) функция теперь описывается как int func(int param, char otherParam). Более того, выпустив новую версию DLL, эти альтернативно одаренные забыли (!) поменять в ней номер версии (VERSIONINFO) — их техподдержка признала эту ошибку. S>И теперь моя программа, соответственно, никак не может понять, какой набор параметров функции func() использовать.
Смотрите младшую часть адреса функции.
S>Реально программа сейчас использует старый интерфейс (int func(int param)), и если вдруг попадается пользователь с новой версией DLL, то программа тупо падает при попытке вызвать ф-цию func().
64bit dll ? S>Вопрос: могу ли я как-то отловить это падение? Каким-нибудь try/catch? Если да, то каким именно?
очень сильно зависит от конкретного случая.
S>(У меня нет у-ва, интерфейсом к которому служит DLL, и я тестировать на своем компьютере я не могу)
Используйте вспомогательную программу (процесс) и смотрите поведение. Если он падает dll новая, если нет старая, после чего делайте запись в конфиге какой интерфейс использовать
Здравствуйте, kov_serg, Вы писали:
S>>И теперь моя программа, соответственно, никак не может понять, какой набор параметров функции func() использовать. _>Смотрите младшую часть адреса функции.
А как на нее смотреть? Что я должен там увидеть и как мне использовать то, что я увижу?
S>>Реально программа сейчас использует старый интерфейс (int func(int param)), и если вдруг попадается пользователь с новой версией DLL, то программа тупо падает при попытке вызвать ф-цию func(). _>64bit dll ?
32bit
S>>(У меня нет у-ва, интерфейсом к которому служит DLL, и я тестировать на своем компьютере я не могу) _>Используйте вспомогательную программу (процесс) и смотрите поведение. Если он падает dll новая, если нет старая, после чего делайте запись в конфиге какой интерфейс использовать
Здравствуйте, sushko, Вы писали:
S>Здравствуйте, kov_serg, Вы писали:
S>>>И теперь моя программа, соответственно, никак не может понять, какой набор параметров функции func() использовать. _>>Смотрите младшую часть адреса функции. S>А как на нее смотреть? Что я должен там увидеть и как мне использовать то, что я увижу?
Смотрите версию, и если она та самая где такая хрень. Сравниваете смещение целевой функции. (она скорее всего разная для разных версий).
По ней и ориентируетесь.
S>>>Реально программа сейчас использует старый интерфейс (int func(int param)), и если вдруг попадается пользователь с новой версией DLL, то программа тупо падает при попытке вызвать ф-цию func(). _>>64bit dll ? S>32bit
Тогда вызов с корее всего __stdcall. Можно сделать такой костыль.
int __stdcall func_safe(int param, char otherParam);
Такой вариант будет работать с обеими версиями.
S>>>(У меня нет у-ва, интерфейсом к которому служит DLL, и я тестировать на своем компьютере я не могу) _>>Используйте вспомогательную программу (процесс) и смотрите поведение. Если он падает dll новая, если нет старая, после чего делайте запись в конфиге какой интерфейс использовать S>Не, это уже перебор
Почему же. Что вам мешает завести в конфигурационном файле, дополнительную опцию для лечения этого косяка?
Здравствуйте, sushko, Вы писали:
S>Есть моя программа (EXE) на C++/MFC, она установлена на 10050 компьютерах пользователей по всей Руси великой. Есть DLL сторонних разработчиков (программный интерфейс к устройству), кот. также используется на большом (сотни тысяч?) к-ве компьютеров. В процессе работы эта программа динамически загружает(LoadLibrary) эту DLL и вызывает из нее ф-цию int func(int param).
S>Идиётские разработчики DLL выпустили новую версию этой самой DLL, в которой та же (!) функция теперь описывается как int func(int param, char otherParam).
Обычно имя функции определяется по-разному, что-то типа _func@4 или _func@5, если только намеренно не приводится к непонятному _func.
Можно предложить вызывать с двумя параметрами и для старой версии. Я бы попробовал.
Здравствуйте, sushko, Вы писали:
_>>Смотрите младшую часть адреса функции. S>А как на нее смотреть? Что я должен там увидеть и как мне использовать то, что я увижу?
Если повезет, то пролог у новой функции будет отличаться от старой. Можно это использовать.
Здравствуйте, sushko, Вы писали:
S>Вопрос: могу ли я как-то отловить это падение? Каким-нибудь try/catch? Если да, то каким именно?
возникла следующая идея костыля.
нужно перед запуском основной программы протестировать DLL.
сделать это можно следующим образом: пишем программу, которая загружает DLL и вызывает в ней функцию определенным образом, а падение и успешное завершение работы программы различаем по её коду возврата.
в зависимости от этого выполнение основной программы делаем разным способом.
кроме того, если не хочется добавлять ещё один exe-файл к программе, это может делать и основной исполняемый файл, будучи запущенным второй раз с определенными параметрами командной строки.
Здравствуйте, LuciferSaratov, Вы писали:
LS>возникла следующая идея костыля. LS>нужно перед запуском основной программы протестировать DLL.
Хороший вариант, кторый уже предлагал kov_serg
,
но может не прокатить, так как DLL является интерфейсом к устройству, а устройству от такого теста может поплохеть так, что придется его физически перезапускать, а у ТС устройства нет и проверить он не может.
да, точно, невнимательно прочитал.
C>но может не прокатить, так как DLL является интерфейсом к устройству, а устройству от такого теста может поплохеть так, что придется его физически перезапускать, а у ТС устройства нет и проверить он не может.
можно попробовать изучить интерфейс и вызывать эту функцию заведомо так, чтобы устройство она не трогала.
например, пропустить любые этапы инициализации устройства в расчете на то, что при этом DLL просигнализирует об ошибке.
то есть сделать только такие действия: загрузить DLL, получить адрес функции, вызвать её с некими некорректными параметрами, при которых ожидается сигнализация о неверном использовании функции.
Здравствуйте, kov_serg, Вы писали:
_>Используйте вспомогательную программу (процесс) и смотрите поведение. Если он падает dll новая, если нет старая, после чего делайте запись в конфиге какой интерфейс использовать
Прога упадет, запись будет сделана "ага, новая версия". Пользователь подумает — "подложу старую версию, чет криво как-то запускается". Прога опять упадет, буте сделана новая запись. Пользователь "чет стало хуже" и так далее
Здравствуйте, sushko, Вы писали:
S>Вопрос: могу ли я как-то отловить это падение? Каким-нибудь try/catch? Если да, то каким именно?
Тебе действительно нужно именно отловить ? Зачем ? Ну отловишь, а дальше что ? Работать же все равно не будет.
Если я правильно понимаю, надо при новой DLL просто прекращать работу приложения, так как все равно ничего хорошего не будет. Или в приложении реализовать иной код на случай новой DLL.
Следовательно, надо просто на старте определить, какая именно версия DLL будет загружена
Если даже VERSIONINFO нет — всяких штампов хватает. Например, количество импортов/экспортов может не совпадать, размеры секций и т.п.
Так что можно просто просто просмотреть заголовок PE этой DLL и принять решение.
Здравствуйте, sushko, Вы писали:
Более того, выпустив новую версию DLL, эти альтернативно одаренные забыли (!) поменять в ней номер версии (VERSIONINFO) — их техподдержка признала эту ошибку.
Можно привязаться не к VERSIONINFO, а к размеру DLL, контрольной сумме, дате изменения.
Все это, конечно, костыль и не дает 100% гарантии, но практически может проблему решить.
Здравствуйте, RonWilson, Вы писали:
_>>Используйте вспомогательную программу (процесс) и смотрите поведение. Если он падает dll новая, если нет старая, после чего делайте запись в конфиге какой интерфейс использовать
RW>Прога упадет, запись будет сделана "ага, новая версия". Пользователь подумает — "подложу старую версию, чет криво как-то запускается". Прога опять упадет, буте сделана новая запись. Пользователь "чет стало хуже" и так далее
Вы не поняли. Библиотека запускает тестовый процесс, который или падает или нет. Пользователь ничего не видит.
Здравствуйте, cserg, Вы писали:
C>Надо искать другой способ. Чем еще новая DLL отличается от старой? Например, может быть в новой версии появилась новая функция?
Сергей, спасибо! Вы правы, и новая DLL отличается от старой, в частности, добавленными новыми функциями. Добавил проверку, отправил пользователю, он отрапортовал, что все работает.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Тебе действительно нужно именно отловить ? Зачем ? Ну отловишь, а дальше что ? Работать же все равно не будет.
Почему не будет? Будет. Просто я в старую DLL буду передавать один параметр, а в новую — два.
typedef int (__stdcall *func_old)(int param);
typedef int (__stdcall *func_new)(int param, char anotherParam);
func_old pfnOld = NULL;
func_new pfnNew = NULL;
if (IsOldDLL())
pfnOld = GetProcAddress();
else
pfnNew = GetProcAddress();
Мне надо было просто понять, old или new. И уважаемый форумчанин cserg, да будет имя его прославлено навеки, предложил проверить, а не добавились ли в новой DLL ф-ции, отсутствующие в старой, и по этому признаку определять, новая DLL или старая. Почему сам не догадался — Бог весть
Здравствуйте, sushko, Вы писали:
PD>>Тебе действительно нужно именно отловить ? Зачем ? Ну отловишь, а дальше что ? Работать же все равно не будет.
S>Почему не будет? Будет. Просто я в старую DLL буду передавать один параметр, а в новую — два.
Ну так я же и написал чуть дальше —
Или в приложении реализовать иной код на случай новой DLL.
Здравствуйте, sushko, Вы писали:
S>Идиётские разработчики DLL выпустили новую версию этой самой DLL, в которой та же (!) функция теперь описывается как int func(int param, char otherParam). Более того, выпустив новую версию DLL, эти альтернативно одаренные забыли (!) поменять в ней номер версии (VERSIONINFO)
Может быть, можно ориентироваться на размер DLL в байтах? Наверняка он отличается.
Здравствуйте, sushko, Вы писали:
S>Вопрос: могу ли я как-то отловить это падение? Каким-нибудь try/catch? Если да, то каким именно?
Даже если ты поймаешь это исключение, кто знает, сколько оно всего успеет поломать в адресном пространстве твоего процесса (хоть и не в твоем коде), прежде, чем долетит до тебя?
А нельзя как-то по вторичным половым признакам определить, с какой версией DLL ты имеешь дело? Ну, например, по наличию новых фукнций, которых раньше не было, по дате в подписи и т.п.?