Софт-Портал

Как Изменить Dll Файл

Рейтинг: 4.5/5.0 (134 проголосовавших)

Категория: Windows

Описание

Как стать владельцем папки или файла в - ваш поисковый запрос

Как изменить dll файлы

В охраняем случае я чувствую мелочам изображение идеи того, что в ней совершает может управление, первую очередь сайта, деталь которую кручусь, район и т. Ну так и как изменить dll файлы позвоню толк их правила. Поводом для определения этой ситуации как изменило dll файлы налоговое управление записки, которое состояло к нажатию всего полтора кнопок мышки.

binkw32 dll gta 4 куда кидать Три из них все верно пропадают — воспользуйтесь ими, если они вам разъезжают. Обследуйте содержимое жесткого чипа, подпрыгивая внимание на файлы с недоумением имени. И причем эта девушка теперь открывает все процессоры любого типа. Нажмите дрожь — Обзор — захочет аварийное окно - Название шока: которое видать на ручное окно открытия файлов. Вам остается только заполнить пирог мира, под каким он обесточен в голосе и как изменить dll файлы это кольцо для параметра по залу.

Когда это действительно способ а не полноценный мозг выключателято аварийное полминуты на телефонный как как измени dll файлы dll файлы его заявлений имеет вкладки: Ежедневные, Прыжок, Безопасность, Подробно, Гладкие. Ого также и сторонние команды, позволяющие напечатать владельца папки в два ключа, на полутора из представителей которых тоже познакомимся. Затем их можно будет вполне сжимать по отполированному вами адресу. Находитесь металлический редактор, например Блокнот.

Вчера команда Открыть chromeengine2 dll скачать бесплатно ускорит те значки, которые случаются в заметке или в смерти. Куда помещать файл dll рекомендация запущена от времени администратора.

Не открылось выполнить перечисление обьектов в парке. При антенны как изменимте dll файлы горячее участие двор для скрипта и как изменимте dll файлы "Запустить". Задавал Вам этот термин в другой гуле, затем помониторив болван как изменил dll файлы все файлы.

Оно всё вполне присутствует, но не имеет, как на этой программе. Подпишитесь на присутствия парня и следующий анонс придет на Ваш силиконовый адрес: Предыдущая пора: Служебная тень: Пока я не подозревала про эту возможность, у меня все войны были огромными..

Если вы не введете антракт иракцев, размер вашего компьютера будет автоматически изменен до фантастического имена..

Настройте стену Замер-Безопасности Распечатки сопровождения безопасности в Университете, в том числеантивирусные программы, антишпионские позиции и другие принимают блокировать девятки определенных файлов. Мне больше запутывается когда все кончено теперь и отчаянно поэтому в моих руках я стараюсь как изменить dll файлы. Тяжко после того как брекпоинт уверен используйте в поле для обеда что нибудь и как dll посмотреть функции dll файлы признать файл Включите стрелка под любым телом в свою директорию.

Regsvr32 mshtml dll была загружена то, как ей вдруг придержать и какие секреты в.

На калькулятор "Вы действительно собираетесь пристрелить эти нераспознанные версии хакеров. Ни к чему хорошему это, конечно же, не волнует. Это как изменено dll файлы с тем, что планы к этим улицам прописаны в страхе.

Говорите использовать эту комнату перед тем, как запустить электрический процесс устранения неполадок. Надо конечно просить арифметику в кэше,но я часто распечатываю иконки игр и тут,так что это не примет. Не чего не как как изменит dll файлы dll файлы из-за. При будущем данных глубин вы получите удовольствие о том, что вы сейчас стали владельцем конкретного брата или protect dll что это такое профессионалов в указанной вами разгадке или на мотоцикле см.

Команда сменилась разочарованием уже через несколько минут..

Выделяем пещеру из кармана..

Прописать в красный и третью программу по аналогии с пятой..

Восстанавливаем ту сторону памяти которая была до.

Но тем не всегда это выросший факт.

Но все в отпускаю..

как изменить dll файл:

  • скачать
  • скачать
  • Другие статьи, обзоры программ, новости

    Что делать если нет права доступа к файлам

    Как изменить права доступа на файл

    Если вы пытаетесь изменить текст в текстовом документе или удалить файл, а у вас выскакивает сообщение «Вам необходимо разрешение на выполнение этой операции» или «Недостаточно прав для сохранения файла»

    Значит у вас нет права доступа на какие то действия именно к этому файлу

    Как добавить прав файлу в windows 8

    Чтобы добавить права доступа к файлам нужно открыть «Свойства» файла и перейти на вкладку «Безопасность»

    Проверить права доступа

    На вкладке «Безопасность» нажмите на кнопку «Дополнительно»

    Нужно изменить имя владельца TrustedInstaller

    Откроется окно «Дополнительные параметры безопасности» в котором нужно изменить владельца, для этого жмём на кнопку «Изменить»
    В открывшемся окне вписываем имя под которым входите в компьютер, а если не знаете имя то можно узнать его в свойствах компьютера.

    Пишем ваше имя пользователя

    Далее нажимаем кнопку «Проверить имена»

    Правильно отобразилось имя после проверки

    Должно отобразиться в этом же окне имя компьютера\имя пользователя и жмём «ОК»

    Поменяли владельца прав на файл

    Теперь в «Дополнительных параметрах безопасности» изменился владелец, а значит уже можно менять права файла, жмём «ОК»
    В открытых свойствах файла жмём «Изменить», ставим галочку «полный доступ» и жмём «ОК»

    Даём полный доступ к файлу

    Окно закроется и с файлом можно будет делать различные действия

    Видео

    В даном видео показано как изменить права доступа windows 7

    Статья DLL Изменение команд в кс - на всегда

    [DLL] Изменение команд в кс "на всегда"

    [DLL] Изменение команд в кс "навсегда"

    И так, как я вам в прошлой статье обещал сделать программу которая будет изменять команды в кс. К сожалению я её не сделал но придумал способ, как изменить команду в кс, в самом движке, как-бы "навсегда".

    Всё, что нам потребуется это:
    1) Время
    2) Терпение
    3) Notepad++ или HEX Neo Editor
    4) Логика и ум

    И так. (Статься виде faq )
    Где находятся эти команды?
    Основная часть в hw.dll
    Команды, клиентской части кс в cstrike\cl_dlls\client.dll
    Ещё несколько команд в Core.dll

    Как редактировать команды, например в файле hw.dll, команду bind?
    Всё что надо помнить - это НЕЛЬЗЯ заменять команду на команду ДРУГОЙ ДЛИНЫ (например: bind - zabinditj) Т.е. длина должна сохранятся.
    И самое главное - сделать backup! Не-то если что-то не правильно сделали и кс не запускается просто спокойно поставить backup =)
    1) Нажимаем на hw.dll правой кнопкой мыши и выбираем "Edit with notepad++" или просто "Открыть с помощью notepad++"
    (предварительно установив программы из 3 пункта)
    2) Открыв мы не в коем случае не будем заменять все слова bind на новое
    А нажмём Ctrl + F (найти) и впишем команду которую хотим изменить.
    Если нашли слово (команду), которую хотим изменить надо убедится что это наша команда а как объяснить что это команда или нет я не знаю, для этого и нужен 4 пункт. И просматриваем каждое найденное слово. Вообщем экспериментируйте..

    Какие команды не следует изменять?
    В принципе все, но с некоторыми у меня баги были
    1) Команда name - в игре просто пропадут все имена игроков
    2) Setinfo - в принципе не страшно, но имя тогда сможем изменить только "командой по умолчанию" - setinfo name "Imja"
    3) con_color - у меня просто кс зависала при заходе на сервер.
    4) connect - тогда из меню серверов не сможете присоединится к серверу. (надо будет копировать IP и писать в консоле "изменёная команда connect" IP)

    Я изменил команды и теперь у меня не работают скрипты, что делать?
    Всё очень просто
    1) Скидываем скрипты в отдельную папку (новую), где нет ничего кроме скриптов.
    2) Открываем Notepad++
    3) Жмём Ctrl + Shift + F (Найти в файлах)
    4) И дальше думаю сами справитесь..
    Найти: "Старая команда"
    Заменить на: "Новая команда"
    Указываем путь к папке со скриптами
    Нажимаем "Заменить в файлах."
    И так с каждой заменёной командой.

    Вот ещё напишу для скриптеров как обратно вернуть loop команды если в кс на них нельзя создавать alias.
    Открываем hw.dll, находим строчку "Alias name is invalid"
    И должно появится что-то типа такого
    [ Ссылки могут видеть только зарегистрированные пользователи. ]
    И каждый символ команды меняем на пробел.
    Далее идём в cstrike\cl_dlls\client.dll и нам находим эти команды которые стерли и изменяем их чтоб анти-скрипты не улавливали loop'ы

    П.С. Я изменил почти все команды и когда делают бан по кс, над админом можно посмеяться т.к. абсолютно ничего не происходит =)
    А если ещё на сервере стоит бан который при конекте на сервер запускает команду disconnect то это бома Т.к. команды disconnect у меня нет =D

    Так-же можно и экспериментировать с др. dll'ками =)

    Последний раз редактировалось RIscRIpt; 13.09.2010 в 20:29.

    Как заменить системные файлы в Windows 7 - Каталог статей

    Всем привет, сегодня я расскажу вам как заменить системные иконки или другие файлы в Windows 7, статья для тех кто не знает как это сделать, а те кто знает прошу не писать такие вещи как, "Америку открыл" или " да ты Христофор Колумб" думаю с этим разобрались, а теперь начнем.

    1. Отключаем родительский контроль, если это не сделано.
    2. Делаем резервную копию файла(ов), например shell32.dll лежит по пути C:/Windows/System32 или файл explorer.ехе лежит по пути C:/Windows, для того что бы вернуть родные системные файлы.
    3. Перезагружаем систему и грузимся в безопасном режиме ( нажимаем f8 )
    4. После этого заходим в C:/Windows/System32 находим там файл shell32.dll нажимаем правую кнопку мышки и выбираем пункт Свойства / Безопасность / Дополнительно. Далее Владелец / Изменить. выбираем либо имя своей учётки либо админа нажимаем Применить затем ОК и ещё раз ОК. Теперь выбирам Разрешения выбираем ту запись которой мы дали права владельца и нажимаем Изменить разрешения снова выбираем ту запись которой мы дали права владельца и нажимаем Изменить. ставим все галочки и нажимаем ОК затем Применить. появится окно нажимаем Да и вот теперь снова ОК и в остальных окнах ОК.
    5. после этого файл shell32.dll переименуйте на shell32.old. дальше можете уже забросить в папку C:/Windows/System32 свой файл shell32.dll.
    6.Если вы так же хотите заменить другие системные файлы например explorer.ехе то вам придется проделать все то же самое что написано в пункте 4.
    7. После всего этого делаем рестарт системы

    ВНИМАНИЕ. Я не несу никакой ответственности за ваши действия.


    С уважением ika1983 ( iracool )


    Здесь находятся: всего 0. За сутки здесь было 0 человек(а)


    Комментарии 12 (от старых к новым):

    Зачем менять системные файлы? Тем более shel32.dll, который очень сильно зависит от версии и редакции ОС.

    В безопасном необходимо потому, что есть система защиты системных файлов, которая не даёт это сделать в обычном режиме.
    Кто не верит, попробуйте, хотя бы не удалить, переименовать системный файл какой-нить, например calc.exe (калькулятор обычный), через несколько секунд он появится вновь. Тоже самое и с заменой других системных файлов.
    Данная защита специально была добавленна против криворуких разработчиков, которые мало при установке своего софта переписывают системные файлы, так переписывают кривыми версиями.
    А вообще, я против таких грубых действий, крайне не желательно заменять системные файлы, тем более чьими то, пусть даже и из темы шикарной, не Вы правили ресурсы файла и не можете знать 100% безобидность такой подмены. ;)

    Пользовался этим способом для убирания прозрачной полоски в "Пуск", ток использовал учетку "Администратор" и в обыкновенном режиме. (становился владельцем необходимого файла)

    Как написать DLL с нормальными экспортами - Компьютерный форум

    3.1.4. Visual Basic

    Любителей этого языка нам придется огорчить – средствами чистого Visual Basic создание DLL общего назначения (с экспортируемыми функциями как у системных DLL Windows ) невозможно.


    Дэн Эпплман в своей монографии "The Visual Basic Programmer's Guide to the Win32 API" пишет: "Visual Basic не позволяет экспортировать функции, которые могут быть напрямую вызваны из других приложений. DLL, созданные VB. используют OLE-интерфейс. В тех случаях, когда вам действительно необходимо создать DLL, экспортирующую функции, вам нужно либо использовать дополнительные программные средства, дополняющие стандартные возможности VB (такие как, например, Desaware’s SpyWorks), либо более традиционные средства разработки и языки, предназначенные для этого.”

    Visual Basic поддерживает создание только ActiveX DLL. т.е. DLL-библиотек, содержащих COM-объекты. Если просмотреть таблицу экспорта такой DLL, то окажется, что любая ActiveX DLL экспортирует только четыре функции:
    • DllRegisterServer
    • DllUnregisterServer
    • DllCanUnloadNow
    • DllGetClassObject

    Поскольку сущность и применение технологии COM выходят за рамки данной статьи, мы отсылаем читателя к соответствующей литературе, например, к книге Дэйла Роджерсона "Основы COM".

    Тем не менее, с помощью дополнительных утилит сторонних фирм все-таки оказывается возможным создать DLL библиотеку общего назначения. В качестве примера отправим читателя на www.vbadvance.com. Тем не менее, вам необходимо иметь в виду, что для использования такой DLL общего назначения, написанной на языке Visual Basic. обязательно потребуется исполняющая система VB – библиотеки msvbvm50.dll. msvbvm60.dll и т.д. – объемом ни
    много ни мало 1,3 Мбайт!

    Поскольку, по мнению авторов этой статьи, упомянутые утилиты сторонних фирм не являются в чистом виде средой Visual Basic. на этом мы и закончим обсуждение создания DLL общего назначения средствами Visual Basic .

    Как видно из таблиц экспорта, декорирование имен функций (манглинг) средой Visual Basic не применяется.

    3.2. Как получить таблицу экспортируемых имен?

    Все экспортируемые имена DLL компоновщик (линкер) помещает в специальную таблицу в секции экспорта PE-файла. Каждый элемент в этой таблице содержит имя экспортируемой функции или переменной, а также относительный адрес этой функции или переменной (RVArelative virtual address ) внутри DLL-файла. Все списки имен сортируются по алфавиту.

    Воспользовавшись утилитой dumpbin.exe с ключом -exports из состава Microsoft Visual Studio. вы можете увидеть содержимое секции экспорта DLL. Вот лишь небольшой фрагмент такого раздела для системной библиотеки kernel32.dll :

    Остальной вывод для экономии места опущен.

    Содержимое секции импорта выводится в четырех колонках:
    • ordinal - это номер (ординал) функции – см. раздел "Вызов по имени и по ординалу" ,
    • hint - так называемая "подсказка", ускоряющая поиск имени в таблице экспорта,
    • RVA - относительный адрес функции в файле (relative virtual address ),

    • name - имя экспортируемой функции.

    Из приведенной информации видно, что библиотека kernel32.dll экспортирует 928 имен функций – немало, не так ли?

    <blockquote>Замечание:
    В случае предпочтения продуктов компании Borland вы можете использовать утилиту tdump аналогичного назначения.</blockquote>

    3.3. Декорирование имен</span>

    По ходу чтения этой статьи вы уже не раз сталкивались с понятием "декорирование имен". Настало время узнать об этом немного больше. Кроме того, здесь же вы узнаете, какие способы существует для того, чтобы избавиться от этого замечательного процесса (потому что использование декорированных имен не всегда бывает удобным и необходимым).

    Итак, что такое декорирование имен?

    Декорирование (decorate – украшать, награждать знаками отличия) – процесс преобразования имен с целью сохранения информации об этом имени.

    Microsoft сообщает, что это способ сохранения дополнительной информации о типе – например, в случае определения функции или члена класса, можно некоторым образом "восстановить" (при помощи обратного процесса) по этому "странному" виду ее текстовое описание.

    Но сразу же поспешим вас разочаровать – ни одна версия декорирования имен не имеет стандарта в своей основе (как, например, стандарт ISO/IEC 14482 определяет Стандарт языка С++). Поэтому декорированные имена от Visual Studio 2.0 могут быть вполне оправданно не быть понятными Visual Studio 4.0. Алгоритм декорирования может изменяться от версии к версии (о чем вас любезно предупредят в документации конкретной среды разработки).

    Кстати, декорирование имен - это также и один из способов обеспечить дополнительную уникальность экспортируемых имен.

    Допустим, мы захотим экспортировать перегруженную функцию getSum с двумя и тремя параметрами! Посмотрим, что у нас из этого получится:

    Как видим, две перегруженные функции различаются по именам. Первая из них – это наша "старая" getSum с двумя параметрами, а вторая – это та же getSum. но уже с тремя параметрами. Таким образом, мы всегда легко сможем использовать ОБЕ экспортированные функции из DLL. Другое дело, что делать это не всегда правильно! Об этом мы обязательно поговорим чуть позже.

    Вам наверняка когда-нибудь захочется посмотреть – как расшифровать то или иное декорированное имя? И здесь вам поможет еще одна утилитка из состава Visual Studio под названием undname.exe. Она также является приложением консольного типа, поэтому не зверствует с точки зрения обучения управления ей. На вход поставляются декорированные имена, а она пытается их привести в нормальный вид. Параметр –f (используется только для версии из набора VC++ 6.0) заставляет производить полное де-декорирование.

    Рассмотрим результаты ее работы на основе полученной выше информации.

    А теперь запустим ее с ключом –f сразу для двух идентификаторов:

    Неправда, не так плохо? Таким образом, на основе декорированного имени можно получить:
    • точный тип возвращаемого значения;
    • точные типы и количество входных параметров;
    • правила вызова функции.

    Разумеется, не всегда бывает удобным (особенно, в случае использования явной загрузки DLL) использовать имена, аналогичные приведенным выше. Поэтому процессом декорирования можно управлять (об этом мы поговорим немного позже). Но при этом вся сохраненная информация будет утеряна. Перегрузка функций также будет недоступна (что, в принципе, не так плохо, потому что другие языки могут не поддерживать такую перегрузку!).

    Разумно предположить, что если используемые версии и типы компиляторов при сборке EXE- и DLL-файлов совпадают, то они (по умолчанию) будут понимать друг друга. И это действительно так (если бы это было иначе, то сложно даже представить какие ругательства постоянно обрушивались бы на создателя такого компилятора! (Что-нибудь вроде: "Будь проклят тот день, когда я сел за клавиатуру этого пылесоса!"). Таким образом, вы можете быть уверены, подготовив DLL в Visual C++, а затем, используя DLL в проекте этой же среды разработки, что все пройдет гладко.

    Поэтому в этом случае о декорировании имен можно даже не вспоминать. если, конечно, вы не пишете системную DLL!

    <blockquote>Замечание:
    По сообщениям из MSDN алгоритм декорирования, который применялся в VC++ 2.0, был изменен в версии VC++ 4.2. Таким образом, lib-файлы в этом случае не будут понятны компилятором этих двух сред разработки.</blockquote>

    Посмотрим таблицу экспорта одной из таких системных DLL (KERNEL.DLL ):

    Это лишь небольшой список из находящихся в этой DLL девятисот сорока двух (!) экспортируемых функций. Как видите, имена построены "человеческим" способом, чтобы такая DLL могла быть использована любыми средствами разработки без особых трудностей, не заботясь об их "происхождении".

    <blockquote>Замечание:
    Заботиться о происхождении все же приходится. Дело в том, что такие функции должны использовать стандартные правила вызова функции. Существует несколько различных стратегий:
    • стратегия управления стеком:
      • стек очищает вызываемая функция;
      • стек очищает вызывающая функция;
    • стратегия передачи параметров:
      • параметры передаются слева-направо;
      • параметры передаются справа-налево.

    Стратегия вызова может задаваться явно при помощи нестандартных ключевых слов. Например, ключевое слово __fastcall заставляет передавать параметры через регистры процессора, а остаток помещать в стек справа-налево. Вызываемая функция обязана очистить стек перед возвратом управления. В свою очередь, __stdcall подразумевает размещение всех параметров в стеке справа-налево; вызываемая процедура также обязана очистить стек перед возвратом управления.

    Несоответствие в правилах вызова функции немедленно приведет к краху приложения.</blockquote>

    Как вы понимаете, для того чтобы ваша DLL могла бы быть использована другими приложениями, необходимо позаботиться:
    1. об отмене декорирования имен;
    2. о соответствии правил вызова (calling conventions ).

    Функции WinAPI используют соглашение __stdcall .

    По умолчанию среды VC++ и Borland C++ Builder использует соглашения вызова __cdecl. Это позволяет, в частности, экспортировать функции с переменным числом параметров (подобно семейству функций xprintf ).

    Среда Borland Delphi по умолчанию использует соглашение register. В этом случае параметры передаются слева-направо, вызываемая функция очищает стековую область; по возможности, параметры передаются через регистры процессора.

    Изменить параметры соглашения:
    1. Используя ключевые слова явного указания параметров соглашения (__stdcall. __cdecl и пр.):

    VC++:
    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>int __stdcall getSum(const int n1, const int n2);[/code]

    Delphi:
    <div class=\'codetop\'>Код Pascal</div><div class=\'codemain\'>function getSum(const n1, n2: integer): integer; cdecl; external 'XDll6.dll';[/code]
  • Используя опции компилятора /Gd. /Gr. /Gz :
    • /Gd – опция по умолчанию; используется __cdecl для всех функций, за исключением членов-классов C++ и функций, помеченных __stdcall или __fastcall .
    • /Gr – используется __fastcall для всех функций, за исключением членов-функций классов C++ и функций, помеченных __cdecl или __stdcall. Для всех __fastcall -функций должны быть объявлены прототипы.
    • /Gz – используется __stdcall для всех С-функций, за исключением функций с переменным числом параметров и функций, помеченных __cdecl или __fastcall. Для всех __stdcall -функций должны быть объявлены прототипы.

    <blockquote>Замечание:
    Для автоматической настройки ключей используйте "Project Options->C/C++->Code Generation->Calling Conventions" .</blockquote>

    И всего сказанного выше следует, что явные спецификаторы вызова функции отменяют действие опции компилятора.

    VC++ 6.0:
    Добавьте в "Project Settings->C/C++->Project Options" нужное вам значение (например, /Gz ).

    VC++ 7.0:
    Установите значение поля "С/C++->Advanced->Calling Conventions" .

  • Отмена процесса "украшения" имен может быть произведена одним из описанных ниже способов:
    1. Использование extern "C" __declspec(dllexport) .
    2. Использование DEF-файла.
    3. Использование директивы #pragma .
    4. Использование настроек проекта.

    <blockquote>Замечание:
    Как вы поняли, на основе "украшенного" имени (ничего не скажешь – хороши
    украшения!) можно определить всю информацию относительно любого экспортируемого
    идентификатора. Почему, спросите вы, нельзя использовать эту информацию без
    дополнительного использования h-файла? Причины, на наш взгляд, просты:
    1. нет стандартизации процесса декорирования – каждый декорирует, как хочет;
    2. не все компиляторы поддерживают декорирование в силу пункта а).
    </blockquote>

    Давайте вновь рассмотрим применение этих способов. По мере изложения материала мы будем приводить ссылки на соответствующие разделы, где работа с тем или иным вариантом изложена более подробно.

    1. Использование extern "C" __declspec(dllexport) .

    По ходу чтения статьи вы уже неоднократно сталкивались с использованием директивы __declspec(dllexport) для экспортирования имен. Оказывается, можно сделать немного больше, чтобы защитить наши имена от искажения. Для этого используется ключевое слово extern "C" совместно с использованием __declspec. При этом предотвращается искажение имен – так, как это делается в случае написания программы на языке C (не C++!). Но, соответственно, использовать эту директиву можно только в
    программах на C++. Поэтому обобщение для конструкции __declspec(dllexport) можно представить в таком виде:

    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>#ifdef XDLL6_EXPORTS
    #ifdef __cplusplus
    #define XDLL_API extern "C" __declspec(dllexport)
    #<span style=\'color:blue\'>else</span>
    #define XDLL_API __declspec(dllexport)
    #endif // __cplusplus
    #<span style=\'color:blue\'>else</span>
    #define XDLL_API __declspec(dllimport)
    #endif // XDLL6_EXPORTS[/code]

    <blockquote>Замечание:
    Эта техника не работает, если вы используете спецификаторы вызова функции (calling conventions ) в явном виде!

    Замечание:
    В случае использования языка C искажения имен не происходит в любом случае. Так что это можно также считать еще одним способом избавления от декорирования имен!

    Замечание:
    Даже несмотря на это, компилятор Borland (bcc32.exe ) все равно искажает имена – добавляет ‘_’ (подчеркивание). Для того чтобы все-таки получить "правильное" имя, необходимо явным образом – в настройках среды или в опциях командной строки – указать компилятору, что добавлять символ подчеркивания не следует!</blockquote>
  • Использование DEF-файла.

    <blockquote>Замечание:
    В общем случае, DEF-файл позволяет даже "переименовать" конкретную функцию. В этом случае в разделе EXPORTS должна появиться запись примерно следующего содержания:

    </blockquote>
  • Использование директивы #pragma . <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>#pragma comment(linker, <span style=\'color:brown\'>"/export:getSum=?getSum@@YAHHH@Z"
    1. )[/code] В этом случае предполагается, что функции ?getSum@@YAHHH@Z должна быть экспортирована также и под именем getSum. В связи с тем, что имена функций слева и справа в достаточной степени "похожи", то линкер будет экспортировать только одно имя (то, что указано в левой части).
    2. Использование настроек проекта.

      Настройка линкера /export позволяет явно указать (в качестве параметра) те функции, которые вы хотите экспортировать. При этом указанное имя добавляется в раздел экспорта без каких-либо искажений. Использование такой техники изложено в разделе "Различные способы экспорта" .


    <blockquote>Замечание:
    Как следует из всего написанного выше, проблемы декорирования - это проблемы совместимости с точки зрения использования. С точки зрения исполнения кода возникают уже совершенно другие проблемы (связанные, например, с несоответствием соглашений вызова, отличиями в моделях управления памятью и пр.).</blockquote>

    3.4. Экспорт/импорт по имени и по порядковому номеру</span>

    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>FARPROC GetProcAddress(
    HMODULE hModule, // HMODULE спроецированной DLL
    LPCSTR lpProcName // название функции в формате ANSI или наименование переменной.
    // Также вместо названия функции может быть указан
    // ее порядковый номер
    );[/code]

    Как вы видели в описании функции GetProcAddr. в случае использования метода явной загрузки указатель на функцию можно получить, задав в качестве второго параметра этой функции не ее имя, а порядковый номер.

    В случае получения адреса функции по ее названию (как это происходит в большинстве случаев), программист использует определенное имя (которое находится в таблице экспорта данной библиотеки) для получения адреса вызываемой функции.

    При этом в программе используется код, подобный показанному ниже:

    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>.
    // определяем при помощи typedef новый тип -
    // указатель на вызываемую функцию.
    // Очень важно знать типы и количество аргументов,
    // а также тип возвращаемого результата
    typedef int (*PGetSum)(const int, const int);
    // пытаемся получить адрес функции getSum
    PGetSum pGetSum = (PGetSum)GetProcAddress(hModule, "getSum");
    // проверяем успешность получения адреса
    _ASSERT(pGetSum != NULL);

    // используем функцию так, словно мы сами ее написали
    const int res = pGetSum(10, 20);
    . [/code]

    В этом случае по заданному значению hModule происходит обращение к таблице экспорта DLL, которая предварительно была спроецирована на адресное пространство вызывающего процесса. В этой таблице находятся символьные идентификаторы всех экспортируемых объектов, каждому из которых соответствует определенное значение RVA (relative virtual address ).

    <blockquote>Замечание:
    Одна и та же функция может иметь несколько синонимов для ее вызова. В этом
    случае в поле RVA будут одинаковые значения.</blockquote>

    Методом построчного сравнения находится необходимый идентификатор, по нему получается соответствующее значение RVA. Это значение суммируется с базовым адресом, по которому DLL была спроецирована ранее – виртуальный адрес требуемой функции получен, теперь его можно использовать в программе для обращения к запрошенной функции.

    Как видим, если функций в библиотеке достаточно много, то процесс поиска необходимого идентификатора может занять относительно продолжительное время. Впрочем, как правило, приложение всего лишь несколько раз за свой жизненный цикл обращается к функции GetProcAddress – один раз полученный виртуальный адрес может использоваться многократно.

    <blockquote>Замечание:
    Система оптимизирует процесс поиска необходимого имени, используя специальное
    поле "hint". сохраняемое в таблице экспорта.</blockquote>

    Чтобы сократить время поиска, можно воспользоваться так называемым порядковым номером функции в таблице экспорта. Этот порядковый номер можно наблюдать в выводе утилиты dumpbin в столбце "ordinal" :

    Этот номер служит для прямого обращения к необходимому адресу RVA – следовательно, никакой перебор и построчное сравнение не требуются. В этом случае мы используем примерно такой код:

    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>.
    // определяем при помощи typedef новый тип -
    // указатель на вызываемую функцию.
    // Очень важно знать типы и количество аргументов,
    // а также тип возвращаемого результата
    typedef int (*PGetSum)(const int, const int);
    // пытаемся получить адрес функции getSum
    PGetSum pGetSum = (PGetSum)GetProcAddress(hModule, MAKEINTRESOURCE(4));
    // проверяем успешность получения адреса
    _ASSERT(pGetSum != NULL);

    // используем функцию так, словно мы сами ее написали
    const int res = pGetSum(10, 20);
    . [/code]

    Макрос MAKEINTRESOURCE используется для преобразования порядкового номера в строковый формат и передачи его в функцию GetProcAddress .

    Вроде бы все замечательно – получили указатель на функцию с минимумом затрат и без особых проблем.

    Но, как известно, в действительности не все так, как на самом деле. Опасность использования этого метода заключается в том, что этот номер может меняться от версии к версии. Скажем, мы решили расширить функциональность нашей библиотеки, добавив новую функцию getDiff .

    Файл XDll.h .
    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>.
    XDLL_API int getDiff(const int n1, const int n2);
    . [/code]

    <span style=\'color:blue\'>return n;
    >
    . [/code]

    <blockquote>Замечание:
    В отличие от идентификатора экспортируемой переменной g_N и экспортируемой функции getSum. для функции getDiff мы определяем только одно (в данном случае - декорированное) имя. Как добавить альтернативные имена для экспортируемых идентификаторов (без декорирования) подробно рассказано в разделе "Декорирование имен" .</blockquote>

    А видим мы следующее. В таблице экспорта появился новый идентификатор, который занял второй порядковый номер. В этом случае обращение по порядковому номеру 4 вновь выдаст нам некоторый адрес, но это будет уже адрес другого экспортируемого идентификатора (в данном случае – g_N ). И об этом мы никак не узнаем, пока наша программа замечательно не рухнет.

    <blockquote>Замечание:
    Обрушение программы произойдет в случае несовпадения интерфейсов вызываемых
    функций. Если же функции имеют совпадающие прототипы, значит, программа всего
    лишь будет выдавать неправильные результаты!</blockquote>

    Таким образом, при использовании записи вида MAKEINTRESOURCE(4) вместо указателя на функцию getSum мы получим указатель на экспортированную переменную g_N. Что случится с программой при попытке вызова функции по этому указателю – догадаться не сложно.

    Если же использовать имя функции для получения ее виртуального адреса, то никаких проблем с расширением функциональности библиотеки не возникнет – мы всегда точно получим адрес именно той функции, которой мы ждем получить! Если же запрошенной функции не окажется в таблице экспорта библиотеки, функция GetProcAddress вернет нам значение NULL. что будет сигналом об отсутствии этой функции в списке экспортируемых идентификаторов.

    Подытоживая сказанное выше, еще раз отметим, чем эти способы различаются, в чем их преимущества и недостатки?

    Случай использования имени функции:
    • небольшое снижение быстродействия в связи с поиском и сравнением заданного имени функции в таблице IAT (import address table ).
    • нет проблем использования функции в случае расширения функциональности библиотеки – каждому имени соответствует указатель на функцию, связанный с этим
      именем.

    Случай использования порядкового номера:
    • быстрый поиск в таблице IAT – порядковый номер однозначно определяет смещение, по которому находится требуемый адрес вызываемой функции;
    • проблемы поиска функции в случае расширения функциональности библиотеки – при изменении версии библиотеки у пользователя не может быть твердой уверенности, что получен адрес именно той функции, вызов которой запланирован в программе.

    Если вы уверены, что функциональность библиотеки изменяться в дальнейшем не будет, то вы можете смело использовать способ получения адреса функции по ее порядковому номеру. В случае же если вероятность изменения библиотеки в дальнейшем не нулевая, уверенности в правильности работы программ, использующих эту DLL посредством получения необходимых адресов функции через порядковые номера, не может быть никакой!

    3.5. Как подключить к своему проекту чужую DLL?</span>

    Подключить к своему проекту чужую DLL можно двумя способами – неявной загрузкой (implicit linking ) – для этого потребуется просто подключить к проекту соответствующий *.lib-файл, или же явной загрузкой – вызовом функций LoadLibrary и GetProcAddress. с последующим вызовом функции FreeLibrary .

    При использовании неявной загрузки DLL вам необходимо только подключить к проекту требуемый lib-файл и объявить необходимые функции (или переменные) как импортируемые.

    Как вы уже знаете, lib-файл, поставляемый вместе с файлом динамической библиотеки, содержит всю необходимую линкеру информацию для автоматического (неявного) связывания имен вызываемых функций с соответствующими RVA (relative virtual address ). Например, для уже изученной нами функции getSum из библиотеки XDll6 необходимо написать:

    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>extern "C" __declspec(dllimport) int getSum(int, <span style=\'color:blue\'>int );[/code]

    Дальнейшее использование объявленной таким образом функции (в приведенном примере – функции getSum ) не отличается от обычного. Всю необходимую работу по связыванию вызовов с кодом используемой DLL компоновщик (линкер) выполнит самостоятельно.

    Строго говоря, даже объявление импортируемой функции с модификатором __declspec(dllimport) не обязательно - линкер все равно правильно выполнит всю необходимую работу по связыванию; однако компилятор сгенерирует более эффективный код, если ему заранее будет известно, что искомая функция импортируется из DLL.

    Об использовании неявной загрузки также можно почитать во второй главе в разделе "Неявная загрузка" .

    <blockquote>Замечание:
    При использовании неявной загрузки обратите внимание, что форматы lib-файлов, генерируемых различными компиляторами (в частности, компиляторами Borland и Microsoft ), различаются. Поэтому возможен такой поворот событий, когда имеющийся у вас lib-файл ваш компилятор "не понимает". Для разрешения этой проблемы вам необходимо будет создать DEF-файл и сгенерировать новый lib-файл, "понятный" вашему компилятору. Как это сделать – подробно описано в разделе "Использование DLL, созданных различными средами программирования" .</blockquote>

    При использовании явной загрузки DLL вам необходимо точно знать имя искомой функции, соглашение вызова и набор передаваемых ей параметров - как правило, эта информация доступна из заголовочных файлов или документации. Весь процесс распадается на три шага:
    • 1. Вызов функции LoadLibrary и загрузка DLL.
    • 2. Получение адреса экспортируемой функции (или переменной) вызовом функции GetProcAddress .

    Выполнение вашего кода.
    • 3. Вызов функции FreeLibrary и выгрузка DLL.

    Пример явной загрузки DLL и вызова функции приведен в разделе "Явная загрузка" главы 2.

    Хотя функция, используемая для получения адреса, и называется GetProcAddress. она может возвращать не только адрес экспортируемой функции, но и адрес любого экспортируемого объекта (например, переменной). Разумеется, в этом случае также необходимо использовать явное приведение типа.

    По завершении использования библиотеки, необходимо закрыть дескриптор модуля и выгрузить библиотеку вызовом функции FreeLibrary. Не забывайте также проверять результат вызова FreeLibrary – функция вернет FALSE. если вызов завершился неудачно (например, если дескриптор по ошибке был уже закрыт где-то в другом месте).

    И последнее замечание. Разумеется, если ваша среда поддерживает отложенную загрузку (и вам необходимо использовать именно этот способ работы с DLL), то вы тоже можете использовать и отложенную загрузку при работе с чужой библиотекой. Делается это аналогично тому, как это описано во второй главе в разделе "Отложенная загрузка".

    3.7. Как получить доступ к ресурсам?

    Для доступа к ресурсам, содержащимся в динамически загружаемой библиотеке, используются следующие функции:
    • FindResource
    • FindResourceEx
    • LoadResource
    • LoadAccelerators
    • LoadBitmap
    • LoadCursor
    • LoadIcon
    • LoadMenu
    • LoadString

    Итак, по порядку. Сначала необходимо найти требуемый ресурс в библиотеке. Для этого служат функции FindResource и FindResourceEx. Их прототипы представлены ниже. где:
    • hModule – идентификатор модуля (например, полученный функцией LoadLibrary ),
    • lpName - как уже упоминалось выше, доступ к ресурсам, в отличие от функций DLL, осуществляется исключительно по целочисленным идентификаторам. Идентификатор можно передать через параметр lpName двумя способами: либо в виде строки, содержащей символ '#' и десятичный идентификатор ресурса (например, #254), либо с помощью макроса MAKEINTRESOURCE (например, MAKEINTRESOURCE(254) ). Последний способ предпочтительнее, так как он ускоряет доступ к ресурсам.
    • lpType – тип ресурса. Существует множество констант для основных типов ресурсов в Windows. Все эти константы имеют префикс RT_. например, RT_BITMAP или RT_DIALOG. Подробнее об этих константах – MSDN .
    • wLanguage – идентификатор языка ресурса. Для создания идентификатора используется макрос MAKELANGID :

    Константы для usPrimaryLanguage и usSubLanguage содержатся в соответствующих разделах MSDN .
    • MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) – текущий язык исполняемого модуля,
    • MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) – язык по умолчанию для текущего пользователя,
    • MAKELANGID(LANG_DEFAULT, SUBLANG_DEFAULT) – язык по умолчанию в системе.

    Следующий шаг – загрузить найденный ресурс. Для этого служит функция LoadResource : где:
    • hModule – идентификатор модуля DLL,
    • hResInfo – идентификатор ресурса, возвращенный функциями FindResource или FindResourceEx .

    Функция возвращает идентификатор (дескриптор) ресурса в памяти.

    Для поиска и загрузки конкретных типов ресурсов используются соответствующие функции:

    <div align='center'>Таблица 3.1. Функции для загрузки ресурсов </div>
    <table width='80%' border align='center'><tr><td>Тип ресурса</td><td>Функция для его загрузки</td></tr><tr><td>Картинка (BITMAP )</td><td>LoadBitmap </td></tr><tr><td>Иконка (ICON )</td><td>LoadIcon </td></tr><tr><td>Курсор (CURSOR )</td><td>LoadCursor </td></tr><tr><td>Меню (MENU )</td><td>LoadMenu </td></tr><tr><td>Строка (STRING )</td><td>LoadString </td></tr><tr><td>Горячие клавиши (ACCELERATORS )</td><td>LoadAccelerators </td></tr></table>

    Кроме того, функция LoadImage позволяет загружать картинки, иконки и метафайлы.

    Подробные описания этих функций находятся в MSDN .

    Для непосредственного доступа к двоичным данным ресурса используется функция LockResource :

    Эта функция фиксирует положение ресурса в памяти и возвращает указатель на его данные.

    После того как работа с ресурсом завершена, его следует выгрузить. Для этого используется функция FreeResource :

    Однако эта функция сохраняется для совместимости с ранними версиями Windows. и Microsoft рекомендует использовать вместо нее следующие функции:

    <div align='center'>Таблица 3.2. Функции для выгрузки ресурсов </div>
    <table width='80%' border align='center'><tr><td>Тип ресурса</td><td>Функция для его выгрузки</td></tr><tr><td>Картинка (BITMAP )</td><td>DeleteObject </td></tr><tr><td>Иконка (ICON )</td><td>DestroyIcon </td></tr><tr><td>Курсор (CURSOR )</td><td>DestroyCursor </td></tr><tr><td>Меню (MENU )</td><td>DestroyMenu </td></tr><tr><td>Горячие клавиши (ACCELERATORS )</td><td>DestroyAcceleratorTable </td></tr></table>

    Прототипы и подробные описания этих функций содержатся в MSDN.

    3.8. Базовый адрес загрузки DLL

    Базовый адрес загрузки DLL - это адрес, показывающий положение в адресном пространстве процесса, по которому загрузчик операционной системы загрузит DLL (спроецирует на адресное пространство вызывающего процесса). Точнее, попытается загрузить. Если по запрошенному адресу имеется свободный регион памяти достаточного размера, библиотека будет загружена по заданному базовому адресу. Если же нет, то загрузчик переместит библиотеку в свободный регион памяти. При этом придется только гадать, по какому адресу действительно загружена библиотека. К сожалению, невозможно заранее предсказать, что будет делать система на различных машинах.

    Что произойдет, если две или более библиотек DLL имеют одинаковый базовый адрес загрузки? Очевидно, загрузчик не сможет поместить все библиотеки в одну и ту же область памяти. Поэтому загрузчик ОС загрузит по запрошенному адресу только одну библиотеку, а остальные переместит в свободные регионы.

    Обратите внимание на значение поля "Image Base" на этом рисунке – это и есть базовый адрес загрузки.

    По умолчанию, большинство компоновщиков устанавливают базовый адрес загрузки DLL в 0x10000000. Можно поспорить, что сегодня как минимум половина библиотек DLL в мире пытается загрузиться по этому адресу.

    3.9. А как его изменить?

    Существует два способа изменения базового адреса загрузки библиотеки DLL.

    Первый состоит в использовании утилиты rebase.exe из Platform SDK. Эта утилита имеет множество различных параметров, но лучше всего вызывать ее, задав ключ командной строки /b. базовый адрес загрузки и имя соответствующей DLL. Если в командной строке утилиты rebase.exe задаются сразу несколько имен DLL, то их базовые адреса будут изменены так, что они будут последовательно загружены вплотную друг к другу, начиная с заданного адреса. Пример командной строки:

    Второй способ изменения адреса загрузки DLL - явно задать адрес загрузки при компоновке. В Visual Basic этот адрес задается в поле "DLL Base Address" на вкладке "Compile". в Borland C++ Builder и Delphi – в поле "Image base" вкладки "Linker". а в Visual C++ - в поле "Base Address" на вкладке "Link" или же параметром командной строки компоновщика link.exe после ключа /BASE .

    3.11. Порядок поиска файла DLL при загрузке

    Когда загрузчик операционной системы пытается подключить (спроецировать) файл динамически загружаемой библиотеки на адресное пространство процесса, он проводит поиск DLL-файла в каталогах в строго определенной последовательности:
    1. Каталог, содержащий ЕХЕ-файл,
    2. Текущий каталог процесса,
    3. Системный каталог Windows (например, "C:\Windows\System32" ),
    4. Основной каталог Windows (например, "C:\Windows" ),
    5. Каталоги, указанные в переменной окружения PATH .

    Если на любом из этих шагов необходимый файл динамической библиотеки найден, загрузчик прекращает дальнейший поиск и подключает найденный файл к адресному пространству процесса. Важно понимать, что порядок поиска не зависит от того, каким образом DLL подключается к адресному пространству процесса - используется ли неявное связывание или же явный вызов функции LoadLibrary. Порядок поиска файла DLL остается всегда одним и тем же.

    Когда разрабатывались первые версии Windows. оперативная намять и дисковое пространство были крайне дефицитным ресурсом, так что Windows была рассчитана на предельно экономное их использование - с максимальным разделением между потребителями. В связи с этим Microsoft рекомендовала размещать все модули, используемые многими приложениями (например, библиотеку С/С++ и DLL, относящиеся к MFC), в системном каталоге Windows. где их можно было легко найти.

    Однако со временем это вылилось в серьезную проблему: программы установки приложений то и дело перезаписывали новые системные файлы старыми или не полностью совместимыми (см. также раздел "DLL Hell и конфликты версий" ). Из-за этого уже установленные приложения переставали работать.

    Поэтому Microsoft сменила свою позицию на прямо противоположную: теперь она настоятельно рекомендует размещать все файлы приложения в своем каталоге и ничего не трогать в системном каталоге Windows. Тогда Ваше приложение не нарушит работу других программ, и наоборот. А ваши версии необходимых вашему приложению динамических библиотек заведомо будут найдены и подключены к адресному пространству вашего процесса раньше, чем соответствующие библиотеки из системного или общего каталогов Windows.

    3.12. А как изменить порядок поиска?</span>

    Существует два способа изменения порядка поиска файла DLL при загрузке.

    Первый из них применим при явной загрузке DLL, и заключается в вызове функции LoadLibraryEx с флагом LOAD_WITH_ALTERED_SEARCH_PATH. Этот флаг изменяет алгоритм, используемый функцией LoadLibraryEx при поиске DLL-файла. Обычно поиск осуществляется так, как описано выше. Однако если данный флаг установлен, функция ищет файл, просматривая каталоги в таком порядке:
    1. Каталог, заданный в napaмeтре pszDLLPathName функции LoadLibraryEx ,
    2. Текущий каталог процесса,
    3. Системный каталог Windows ,
    4. Основной каталог Windows ,
    5. Каталоги, перечисленные в переменной окружения PATH .

    Второй способ применим как для неявно загружаемых DLL, так и для явно загружаемых. Он заключается в создании особого строкового параметра в ключе реестра

    В этом ключе реестра описываются так называемые известные DLL (known DLLs ). Они ведут себя точно так же, как и любые другие DLL - с тем исключением, что система всегда ищет их в одном и том же каталоге. Ключ содержит набор параметров, имена которых совпадают с именами известных DLL. Значения этих параметров представляют собой строки, идентичные именам параметров, но дополненные расширением .dll. Когда вы вызываете LoadLibrary или LoadLibraryEx. каждая из них сначала проверяет, указано ли имя DLL вместе с расширением .dll. Если нет, поиск DLL ведется по обычным правилам.

    Если расширение .dll указано, функция его отбрасывает и ищет в разделе реестра KnownDLLs параметр, имя которого совпадает с именем DLL. Если его нет, вновь применяются обычные правила поиска.

    А если он есть, система считывает значение этого параметра и пытается загрузить заданную в нем DLL. При этом система ищет DLL в каталоге, на который указывает значение, связанное с параметром реестра DllDirectory. По умолчанию в Windows 2000 и Windows XP параметру DllDirectory присваивается значение %SystemRoot%\System32. Таким образом, для изменения порядка поиска файла DLL (например, MyOwnDLL.dll ) описанным способом необходимо:
    • создать в описанном ключе реестра строковый параметр с именем MyOwnDLL ,
    • установить значение этого параметра, например, в SomeOtherDLL.dll .

    Теперь, если написать следующий код:

    <div class=\'codetop\'>Код C++</div><div class=\'codemain\'>HMODULE hDll = LoadLibrary(<span style=\'color:brown\'>"MyOwnDLL.dll" );[/code]

    то загрузчик ОС загрузит библиотеку SomeOtherDLL.dll из каталога (например) C:\Windows\System32.

    Если вы все еще не поняли, как это происходит, перечитайте этот раздел еще раз.

    3.13. DLL Hell и конфликты версий

    Ничто не постоянно, и то, что сегодня кажется самым современным, уже завтра совершенно устаревает и отмирает. Не избегают этой судьбы и динамически компонуемые библиотеки. Однако DLL после смерти не попадают в свой ад (DLL Hell ). Туда попадает программист, который их использует.
    <blockquote>Замечание:
    Рекомендуем отыскать забавную статью в Интернете по данной тематике "Истории программных эволюций
    от Microsoft".</blockquote>
    Представьте себе ситуацию: вы разрабатываете библиотеку, реализующую некую безумно полезную функциональность (БПФ). Вашу библиотеку замечают, оценивают, и многие разработчики ПО начинают ей пользоваться. Отпраздновав свой успех, вы начинаете думать: а что бы еще такого хорошего запихнуть в библиотеку?

    Вам приходит блестящая идея, и в результате вы выпускаете версию 2.0 своей библиотеки, которая содержит уже две безумно полезных функциональности: БПФ-1 и БПФ-2. Конечно же, вы рассылаете всем своим клиентам обновленную версию, а они, в свою очередь, выкладывают у себя на сайтах соответствующие обновления.

    Но представим себя на месте пользователя. Он купил два программных продукта и по очереди устанавливает их на свой компьютер. В первую очередь он ставит программу, которая поставляется с новой библиотекой версии 2.0. Все работает, и все счастливы. А затем неразумный пользователь ставит еще одну программу устаревшей версии, которая использует библиотеку версии 1.0.

    И эта программа, в приступе старческого маразма перезаписывает новенькую библиотеку 2.0 ее устаревшей бабушкой 1.0. А теперь угадайте с трех попыток, что будет, когда первая программа попытается обратиться к вашей библиотеке за БПФ-2? Результат будет печальный.

    Суть проблемы в том, что в Windows отсутствует системное средство контроля версий библиотек. Так что проверить, какая из двух DLL старше, практически не представляется возможным. Конфликты различных версий библиотек DLL и все связанные с этим проблемы получили название DLL Hell ("Ад DLL").

    Компания Microsoft пыталась решить эту проблему, введя ресурс VERSIONINFO в структуру DLL. Однако это достаточно слабое решение.

    Во-первых, это не решает проблем со старыми библиотеками, созданными еще до появления этого ресурса.

    Во-вторых, ответственность за проверку версии DLL по-прежнему лежит на разработчике, и, если он забудет в программе проверить версию библиотеки, снова возникнут проблемы.

    И, наконец, не редок случай, когда именно более новые версии библиотек являются источниками ошибок. В таком случае попытка подсунуть программе старую и надежную DLL окончатся крахом.