Как выгрузить dll из памяти
Динамическое связывание происходит намного сложнее статического, причем динамическое связывание в Lazarus несколько отличается от такого же связывания в Delphi, поэтому примеры Delphi тут работать не будут.
Итак, начнем с того, что процедуру динамического связывания можно разбить на четыре этапа:
- Загрузка динамической библиотеки функцией LoadLibrary и получение её дескриптора - числового идентификатора библиотеки в системе. Такой идентификатор представляет собой целое число. Если загрузка библиотеки была неудачной, то в дескриптор запишется ноль.
- Получение адреса нужной функции (или функций) с помощью GetProcAddress .
- Непосредственно работа с нужной функцией из DLL.
- Выгрузка DLL из памяти.
Причем вы можете выполнять все действия по загрузке библиотеки в память и её выгрузке как для вызова каждой процедуры или функции отдельно, так и для вызова группы подпрограмм. Например, пользователь захотел выполнить некую операцию. Для этой операции требуется вызвать, скажем, десять подпрограмм (процедур и функций) из DLL . Будет глупо открывать и закрывать DLL отдельно для каждой подпрограммы, правильней будет открыть DLL , выполнить все эти десять подпрограмм, а затем закрыть DLL .
Но в нашем примере для наглядности мы будем загружать и выгружать DLL отдельно для каждой операции .
Для этого приложения нам потребуются точно такие же компоненты на форме, как и у предыдущего. Если вам не лень, то можно вернуться назад, и подготовить форму таким же образом, как и у проекта Proba. Однако можно сделать проще. Загрузите в Lazarus проект Proba из папки 26-02, для этого вам нужно загрузить файл Proba.lpi или Proba.lpr. Далее выведите на передний план Редактор формы. Щелкните правой кнопкой мыши по свободному месту формы и выберите команду "Выделить всё". При этом окажутся выделенными все компоненты формы. Затем выберите команду главного меню "Правка -> Копировать".
Теперь начнем новый проект. Выберите команду "Файл -> Создать -> Приложение", и у вас откроется новый проект с пустой формой. Растяните форму по ширине и высоте, чтобы на ней легко уместились все компоненты, позже размеры формы можно будет подкорректировать. Теперь выберите команду главного меню "Правка -> Вставить". При этом все нужные компоненты появятся на форме на том же самом месте. Кроме того, они сохранят свои имена и прочие настройки. Подкорректируйте размер формы. Теперь переименуйте форму в fMain, в Caption напишите " Динамическое связывание DLL ", в BorderStyle выберите bsDialog , а в Position - poDesktopCenter . Сохраните проект в папку 26-03 под именем Proba2, модулю формы дайте имя Main . Не забудьте скопировать файл MyFirstDLL.dll и в эту папку.
Теперь нам потребуется некоторая подготовка перед тем, как мы начнем динамически связывать нашу DLL . Прежде всего, в раздел uses добавьте еще один модуль - Dynlibs . Именно в нём описаны необходимые инструменты для динамического подключения библиотек.
Далее, перед глобальным разделом var нам нужно описать типы наших подключаемых функций, а в самом разделе var добавить переменную- дескриптор библиотеки, а также по переменной на каждую функцию:
Обратите внимание, как мы описываем тип функций:
Тип мы назвали TCode , вы можете дать другое имя, но для типов и классов традиционно принято начинать имя с большой буквы "T". В этом типе мы указали, что создается функция с такими то параметрами (как в DLL ), которая возвращает тип PChar , и будет использовать соглашение stdcall . При этом имени самой функции мы не указываем. Таким же образом мы создаем еще три типа.
Далее, в глобальном разделе var мы добавляем такую переменную:
Это - дескриптор . Когда мы загрузим DLL в память , в эту переменную попадет идентификатор нашей библиотеки. Ведь в памяти всё время загружено множество самых разных DLL , используемых системой, и Windows как-то нужно различать, к которой из них вы обращаетесь. По умолчанию сразу же выставляем нулевое значение . Если попытка считать DLL в память будет неудачной, например, эта DLL отсутствует, то дескриптор также будет нулевым.
Далее мы создаем по переменной для каждой вызываемой из DLL функции. Например, для функции Code мы создаем переменную
Тип TCode мы описали выше, здесь просто используем его же. В принципе, эти переменные необязательно делать глобальными, можно было описать их в разделе var той процедуры, откуда будем вызывать. Но в больших проектах одну и ту же DLL -функцию обычно вызывают из множества различных процедур, поэтому удобней описывать переменные, как глобальные.
Описав дескриптор и переменные для функций, мы сделали всю подготовительную работу.
Переходим ко второму этапу - динамической загрузке DLL , использовании нужной функции и выгрузке DLL из памяти.
Сгенерируйте событие OnClick для кнопки bBeforeBirthday. Код события отличается от прошлого проекта, он более сложный:
Давайте подробно разбирать весь этот код. Для начала, как и в прошлом проекте, мы сделали проверку - есть ли что-то в строке DE1 , и если нет, то выходим, так как в дальнейших действиях смысла нет. Если текст есть ( пользователь вписал или выбрал дату рождения), то выполняется дальнейший код. Прежде всего, мы загружаем в память библиотеку, сразу же получая дескриптор на неё:
Функция LoadLibrary описана в модуле Dynlibs , который мы подключили в разделе uses , и пытается открыть указанную в параметре библиотеку. Если имя библиотечного файла указано без адреса, как в нашем случае, то файл библиотеки ищется в той же папке, откуда запущена программа . Если его там нет, то библиотека ищется в текущей папке (она может отличаться от папки с программой), затем в системных каталогах Windows и, наконец, в папках, указанных в системной переменной Path . Поэтому DLL лучше устанавливать в папку с программой, или в системную папку Windows , если эту DLL будут использовать несколько приложений. Такой папкой может быть, например,
C:\Windows\system32
Далее, мы получаем адрес в памяти, где находится нужная нам процедура:
Для этого мы указываем имя типа этой функции и используем функцию GetProcAddress . Эта функция работает так. В качестве параметров она получает дескриптор нужной библиотеки и название функции (процедуры), которую нам требуется оттуда вызвать. Затем она возвращает адрес этой функции в памяти, который попадает в нашу переменную BeforeBirthday . Кстати, необязательно давать этим переменным такие же имена, как и у функций, просто так удобней.
Если по какой то причине адрес функции получить не удалось, например, в памяти находится устаревшая версия DLL , где эта функция отсутствует, то GetProcAddress вернет значение nil , то есть, ничего. Именно поэтому мы делаем ещё одну проверку:
Поскольку переменная BeforeBirthday является, на самом деле, указателем, то в ней находится не функция из DLL с аналогичным именем, а адрес этой функции в памяти. Чтобы посмотреть, указывает ли на что-то этот указатель , мы используем оператор получения адреса @ , указанный перед именем указателя:
Иначе функция недоступна, о чем мы и сообщаем пользователю, не обращаясь при этом к функции:
В принципе, в нашем небольшом проекте можно было бы обойтись и без всех этих многочисленных проверок, но я хотел показать, каким образом динамически подключаются DLL в реальных проектах. Это на первый взгляд весь этот код кажется сложным, а когда разберетесь и опробуйте его, он станет достаточно понятным. Под конец мы выгружаем DLL из памяти:
После этого, обращаться к её функциям уже будет нельзя. Код обращения к остальным функциям мы так подробно разбирать не будем, поскольку он аналогичен рассмотренному выше коду. Код события OnClick кнопки bArToRom следующий:
Java взаимодействует с операционной системой через методы, помеченные ключевым словом native, при помощи системных библиотек, загружаемых процедурой System.loadLibrary().
Загрузить системную библиотеку очень просто, а вот чтобы ее выгрузить, как оказалось, нужно приложить немало усилий. Как именно выгружаются системные библиотеки, и зачем это нужно я постараюсь рассказать.
Предположим, мы хотим сделать небольшую утилиту, которую будут запускать пользователи на своих компьютерах в локальной сети. Нам бы хотелось избавить пользователей от проблем с установкой и настройкой программы, но нет ресурсов на развертывание и поддержку централизованной инфраструктуры. В таких случаях обычно собирают программу вместе со всеми зависимостями в единый jar-файл. Это легко сделать при помощи maven-assembly-plugin или просто экспортировать из IDE Runnable jar. Запуск программы будет осуществляться командой:
К сожалению, это не работает, если одна из библиотек требует для своей работы системную динамическую библиотеку, проще говоря dll. Обычно в одном из классов такой библиотеки в статическом инициализаторе делается вызов System.loadLibrary(). Чтобы dll загрузилась, нужно положить ее в каталог, доступный через системное свойство JVM java.library.path. Как это ограничение можно обойти?
Запакуем dll внутрь jar-файла. Перед началом использования классов, требующих подгрузки dll, создадим временный каталог, извлечем библиотеку туда и добавим каталог в java.library.path. Выглядеть это будет примерно так:
К сожалению, приходится химичить с reflection, потому что стандартных методов расширить java.library.path Java не предоставляет.
Теперь загрузка библиотеки проходит для пользователя прозрачно, и он не должен беспокоиться о копировании файлов или настройке переменных окружения. Для работы по-прежнему достаточно просто запустить обычный скрипт. Однако после каждого запуска программы остается временный каталог с файлами. Это не очень хорошо, поэтому на выходе надо выполнить очистку.
Но на Windows это не работает. Загруженная в JVM библиотека блокирует dll-файл и каталог, в котором он лежит. Таким образом, чтобы решить задачу аккуратного завершения программы, надо выгрузить из JVM системную динамическую библиотеку.
Попытка решения
Прежде всего разумно добавить в код диагностику. Если файлы удалось удалить, например. когда библиотека не использовалась, то и делать ничего не надо, а если файлы заблокированы, тогда предпринять дополнительные меры.
Как быстрое, но не самое красивое решение, я использовал планировщик. На выходе создаю xml-файл с заданием на выполнение через 1 минуту команды «cmd /c rd /s /q temp-dir» и загружаю задание в планировщик командой «schtasks -create taskName -xml taskFile.xml». К моменту выполнения задания программа уже завершена, и файлы никто не держит.
Самое же верное решение — это обеспечить выгрузку библиотеки средствами Java-машины. Документация говорит о том, что системная библиотека будет выгружена при удалении класса, а класс удаляется сборщиком мусора вместе с класслоадером, когда не осталось ни одного экземпляра из его классов. На мой взгляд, лучше всегда писать такой код, который полностью очищает после себя всю память и другие ресурсы. Потому что если код делает что-то полезное, рано или поздно захочется его переиспользовать и задеплоить на какой-нибудь сервер, где установлены и другие компоненты. Поэтому я решил потратить время на то, чтобы разобраться, как корректно программно выгрузить dll.
Использование класслоадера
В моей программе проблемы исходили из JDBC-драйвера, поэтому дальше я буду рассматривать пример с JDBC. Но и с другими библиотеками можно работать аналогичным образом.
Если dll загружена из системного загрузчика классов, то выгрузить ее уже не получится, поэтому необходимо создать свой класслоадер таким образом, чтобы класс, подтягивающий библиотеку, был загружен из него. Новый класслоадер должен быть связан с системным класслоадером через свойство parent, иначе в нем не будут доступны классы String, Object и другие необходимые в хозяйстве в вещи.
Не работает. При загрузке класса сначала производится попытка поднять его из родительского загрузчика, поэтому наш драйвер загрузился не так, как нам нужно. Для использования нового класслоадера, нужно JDBC-драйвер из jar-файла программы удалить, чтобы он не был доступен системному загрузчику. Значит, запаковываем библиотеку в виде вложенного jar-файла, а перед использованием разворачиваем его во временном каталоге (в том же, где и dll у нас лежит).
Мы получили объект, загруженный из нашего нового загрузчика, по окончании работы нам надо позакрывать все, что мы открывали, почистить все наши переменные, и, видимо, вызвать System.gc(), после чего уже пытаться чистить файлы. В этом месте имеет смысл инкапсулировать всю логику работы с загрузчиками классов в отдельном классе с явными методами инициализации.
Эксперименты со сборщиком мусора
Не работает. Каталог заблокирован процессом java. С этого момента я использовал такую технику:
- Ставлю на выходе System.in.read()
- Когда программа останавливается в этом месте, делаю дамп памяти из jvisualvm
- Смотрю дамп при помощи Eclipse Memory Analysis Tool или jhat
- Ищу экземпляры объектов, классы которых были загружены мои загрузчиком
- Локальные переменные
- DriverManager
- ResourceBundle
- ThreadLocals
- Исключения
Локальные переменные
Оказалось, что сборщик мусора не считает локальную переменную недостижимой, пока не будет завершена функция, содержащая эту переменную, даже если переменная вышла из области видимости.
Поэтому для решения задачи выгрузки класслоадера необходимо перед вызовом gc выйти из всех функций, которые используют выгружаемые классы.
DriverManager
JDBC-драйверы при загрузке их класса регистрируются в классе DriverManager методом registerDriver(). Судя по всему, перед выгрузкой надо вызвать метод deregisterDriver(). Пробуем.
Не работает. Heapdump не изменился. Смотрим в исходники класса DriverManager и обнаруживаем, что в методе deregisterDriver() стоит проверка на то, что вызов должен быть из класса, который принадлежит тому же класслоадеру, что и класс, вызвавший ранее registerDriver(). А registerDriver() вызван самим драйвером из статического инициализатора. Неожиданный поворот.
Получается, мы не можем напрямую разрегистрировать драйвер. Вместо этого мы должны попросить какой-нибудь класс из нового класслоадера, чтобы он сделал это от своего имени. Выход заключается в создании специального класса DriverManagerProxy, точнее даже двух, класса и интерфейса.
Интерфейс будет находиться в основном classpath-е, а релизация будет загружена новым загрузчиком из вспомогательного jar-файла вместе с JDBC-драйвером. Теоретически без интерфейса можно было бы обойтись, но тогда для вызова функции пришлось бы применять reflection. Используется прокси следующим образом:
ResourceBundle
Следующая зацепка на класслоадер, который я пытался выгрузить, обнаружилась в недрах класса ResourceBundle. К счастью, в отличие от DriverManager, ResourceBundle предоставляет специальную функцию clearCache(), которой класслоадер передается в качестве параметра.
Надо заметить, что, судя по исходникам, в ResourceBundle используются слабые ссылки, которые не должны препятствовать сборке мусора. Возможно, если очистить все остальные ссылки на наши объекты, то чистить этот кэш нет необходимости.
ThreadLocals
Последнее место, где обнаружились хвосты неиспользуемого драйвера, оказалось ThreadLocals. После истории с DriverManager-ом, очистка локальных поточных переменных кажется парой пустяков. Хотя тут не удалось обойтись без reflection.
Исключения
Мы рассчитываем на то, что код очистки можно поместить в блоке finally. На входе в этот блок у нас уже должно быть все закрыто автоматически при помощи механизма try-with-resources. Однако наш класслоадер по-прежнему не будет в этом месте удален из памяти, если из блока try выброшено исключение, класс которого загружен этим класслоадером.
Чтобы удалить из памяти нежелательный exception, его надо поймать и обработать, а если нужно ошибку все-таки выбросить наверх, то скопировать exception в другой класс. Вот как это сделал я в своей программе:
Java наносит ответный удар
После очистки всех обнаруженных ссылок на выгружаемые классы получилась немного парадоксальная ситуация. Никаких объектов в памяти нет, судя по дампу памяти, количество экземпляров во всех классах равно 0. Но сами классы и их загрузчик никуда не делись, и соответственно не удалилась нативная библиотека.
Устранить проблему получилось вот таким приемом:
Наверное, в Java 1.7, которую я использовал, была какая-то особенность очистки объектов, которые лежат в PermGen. С настройками сборки мусора я не экспериментировал, потому что старался написать код, который будет одинаково работать в различном окружении, в том числе в серверах приложений.
После указанного приема код заработал как следует, библиотека выгружалась, каталоги удалялись. Однако после перехода на Java 8 проблема вернулась. Разобраться, в чем дело, не было времени, но судя по всему, изменилось что-то в поведении сборщика мусора.
Поэтому пришлось применить тяжелую артиллерию, а именно JMX:
Через HotSpotDiagnosticMXBean вызываем сохранение дампа памяти. В качестве имени файла указываем nul, что в Windows означает то же самое, что и /dev/null в Unix. Второй параметр указывает на то, что в дамп должны быть выгружены только живые объекты. Именно этот параметр заставляет JVM выполнить полную сборку мусора.
Вот после этого лайфхака проблема удаления библиотеки из временного каталога больше не возникала. Итоговый код очистки файлов выглядит так:
Проверка при помощи OSGI
Для проверки качества кода я написал свой JDBC-драйвер, который полностью убирает за собой. Он работает как обертка вокруг любого другого драйвера, подгружаемого из отдельного classpath.
Этот драйвер я вставил в сервис OSGI на Apache Felix.
При старте модуля через системную консоль Apache Felix, запущенную на Java 1.8.0_102, появляется временный каталог с dll-файлом. Файл заблокирован процессом java. Как только модуль останавливается, каталог удаляется автоматически. Если же вместо UnloadableDriver использовать DriverManager и обычную библиотеку из Embedded-Artifacts, то после обновления модуля возникает ошибка java.lang.UnsatisfiedLinkError: Native Library already loaded in another classloader.
Выводы
Универсального способа выгрузить системную динамическую библиотеку из Java-машины не существует, но задача эта решаема.
В Java существует немало мест, в которых можно случайно оставить ссылки на свои классы, и это является предпосылкой к утечкам памяти.
Даже если ваш код делает все корректно, утечка может быть привнесена какой-нибудь библиотекой, которую вы используете.
Особое внимание следует обратить на случаи, когда программа что-то загружает при помощи создаваемого во время выполнения нового загрузчика классов. Если останется хотя бы одна ссылка на один из загруженных классов, то класслоадер и все его классы останутся в памяти.
Чтобы обнаружить утечку памяти, надо сделать дамп и проанализировать при помощи специальных инструментов, таких как Eclipse MAT.
При обнаружении утечки памяти в сторонней библиотеке можно попробовать устранить ее при помощи одного из описанных в статье рецептов.
Современный пользователь во время рабочего дня пользуется десятком программ, которые запускает и выключает по мере необходимости. Все программы подгружают во время запуска в оперативную память свои библиотеки, но при закрытии программ эти библиотеки продолжают висеть в памяти, тормозя систему и иногда внося в неё небольшие сбои.
В Windows XP в реестре был ключ, способный автоматически выгружать неиспользуемые библиотеки (dll) из оперативной памяти (хотя он и был выключен по умолчанию). В Windows Vista и 7 этого ключа нет, его придётся создавать самостоятельно. Наверно, разработчики решили, что при выросшем размере оперативной памяти этот ключ будет лишним или просто о нём забыли. Довольно большое упущение. Если пользователь работает с одной-двумя программами в день, не запуская никаких дополнительных приложений (музыка, видео, скайпы, почты, аськи), то может он и не заметит подтормаживание системы к концу дня. А вот если Вам необходимо перескакивать между десятком программ, да ещё в автозагрузке столько же грузится, то к середине дня срабатывание окон может замедлиться, что-то может начать взвисать и может возникнуть необходимость перезагрузки. Впрочем, даже когда Вы не пользуетесь разнообразием программ, кто Вам сказал, что Ваша операционка не нагрузила в память лишних библиотек приложений при запуске, которые там висят и не используются?
Варианта добавки - два. Для пытливых и для ленивых.
1. Заходим в реестр. Пуск- пункт «Выполнить»- набираем команду «regedit» и жмём «ОК». В появившемся окне реестра слева идём
HKEY_LOCAL_MACHINE – Software – Microsoft – Windows – CurrentVersion – Explorer
Справа становимся в пустом месте – нажимаем правую клавишу мыши и в появившемся меню жмём пункт «Создать параметр DWORD 32 bit». В появившемся окне вводим название «AlwaysUnloadDLL» и присваиваем ему значение 1.
Жмём «ОК» и перезагружаемся.
2. Просто скачиваете файлик архива (скачать бесплатно), распаковываете и запускаете. Перезагрузка.
С помощью реестра можно включить автоматическую выгрузку DLL-файлов. Ее целесообразность обусловлена тем, что интервал времени, через который оболочка Windows выгружает неиспользуемые DLL-файлы, может быть достаточно большим (например, при отладке программ).
Примечание
Система не выгружает DLL-файлы приложения специально после его завершения. Она оставляет их в памяти, чтобы, если вы опять запустите данное приложение, не тратить время на повторную загрузку одних и тех же DLL-файлов. Если DLL-файлы не будут выгружены, то для повторной загрузки программы будет потрачено меньше времени.
Чтобы включить режим автоматической выгрузки DLL-файлов, необходимо в разделе реестра HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionExplorer создать строковый параметр AlwaysUnloadDLL и присвоить ему значение 1. Соответствующий REG-файл будет выглядеть следующим образом (расположение на компакт-диске – Файлы реестраРежимыAlwaysUnloadDLL.reg):
Windows Registry Editor Version 5.00
После внесения в реестр указанных изменений и последующей перезагрузки компьютера будет включен режим автоматической выгрузки всех DLL-файлов (в том числе и неиспользуемых).
Данный текст является ознакомительным фрагментом.
Продолжение на ЛитРес
9.3. Автоматическая нумерация и списки
9.3. Автоматическая нумерация и списки В CSS существует два свойства для управления нумерацией: counter-increment и counter-reset. Счетчики, которые определены данными свойствами, используются функциями counter() и counters() свойства content. Рассмотрим подробно свойства для управления
11.4. Автоматическая установка Windows Vista
11.4. Автоматическая установка Windows Vista Пакет Windows AIKЕсли вам приходилось устанавливать одну и ту же операционную систему на несколько компьютеров, то вам, вероятно, надоедало постоянно отвечать на одни и те же вопросы. Windows Vista имеет специальные средства для установки
OID, их автоматическая генерация и перезагрузки
OID, их автоматическая генерация и перезагрузки При создании конфигурационного файла, и при добавлении юнитов вручную oid можно не указывать. При этом значение oid генерируется автоматически, так что если набрать show config, значения oid выставятся каким–то случайным образом.
9.1.2 Выгрузка процессов
9.1.2 Выгрузка процессов Ядро выгружает процесс, если испытывает потребность в свободной памяти, которая может возникнуть в следующих случаях:1. Произведено обращение к системной функции fork, которая должна выделить место в памяти для процесса-потомка.2. Произведено
9.1.2.1 Выгрузка при выполнении системной функции fork
9.1.2.1 Выгрузка при выполнении системной функции fork В описании системной функции fork (раздел 7.1) предполагалось, что процесс-родитель получил в свое распоряжение память, достаточную для создания контекста потомка. Если это условие не выполняется, ядро выгружает процесс из
9.1.2.2 Выгрузка с расширением
9.1.2.2 Выгрузка с расширением Если процесс испытывает потребность в дополнительной физической памяти, либо в результате расширения стека, либо в результате запуска функции brk, и если эта потребность превышает доступные резервы памяти, ядро выполняет операцию выгрузки
Автоматическая дефрагментация
Автоматическая дефрагментация Одним из нововведений Windows XP является автоматическая дефрагментация файловой системы при простое компьютера в течение определенного промежутка времени (10-30 минут). При этом по умолчанию также выполняется дефрагментация загрузочного
Выгрузка библиотек при выходе из программы
Выгрузка библиотек при выходе из программы По умолчанию система при завершении работы программы оставляет в памяти ее библиотеки на случай, если через некоторое время она снова будет запущена. С одной стороны, плюс этого метода очевиден — следующий запуск будет
Загрузка и выгрузка файлов посредством FTP
Загрузка и выгрузка файлов посредством FTP Поговорим о том, как можно выгрузить свои файлы на удаленный сервер Интернета, чтобы их потом могли загружать другие, а также рассмотрим еще один способ загрузки файлов на свой компьютер, не связанный с использованием браузеров и
Автоматическая проверка
Автоматическая проверка При автоматическом контроле орфографии и грамматики Word проверяет в тексте ошибки непосредственно при наборе. В таком случае сразу после того, как слово или предложение набрано, видно, допущена ошибка или нет: программа подчеркивает слова,
Программная выгрузка доменов приложения
II. Автоматическая корректировка текста
II. Автоматическая корректировка текста Для корректировки текста можно использовать либо интерактивные инструменты (см. ниже), либо – автоматические. Рассмотрим их подробнее.
2.3.6. Динамическая загрузка и выгрузка
2.3.6. Динамическая загрузка и выгрузка Иногда на этапе выполнения программы требуется загрузить некоторый код без явной компоновки. Рассмотрим приложение, поддерживающее подключаемые модули: Web-броузер. Архитектура броузера позволяет сторонним разработчикам создавать
Автоматическая смена обоев
Автоматическая смена обоев Украсить Рабочий стол, не устанавливая специальные программы для визуализации интерфейса, можно стандартными обоями. Используя для этого высококачественные изображения, можно фактически каждый день изменять внешний вид своего Рабочего
Загрузка и выгрузка фильмов Shockwave/Flash и изображений в формате JPEG
Загрузка и выгрузка фильмов Shockwave/Flash и изображений в формате JPEG Проще всего загрузить в основной фильм, воспроизводящийся в окне проигрывателя Flash, другой фильм Shockwave/Flash или изображение в формате JPEG из внешнего файла (загружаемого фильма). Такое часто делается, особенно
Перед физическим удалением/переносом надо сделать uninstall библиотеки ил реестра функцией DllUnregisterServer. О ней пишут:
The DllUnregisterServer function removes entries associated with a Cluster Administrator extension DLL from the system registry.
FreeLibrary уменьшает счётчик использования DLL вызывающим процессом и выгружает библиотеку при достижении счётчика нуля. Если после вызова FreeLibrary ваша библиотека всё ещё не выгружена, значит для неё несколько раз вызывалась LoadLibrary, соответственно счётчик больше единицы. Такое бывает, если библиотека загружена по ходу инициализации процесса, поскольку зависимость была задана при компоновке, а потом ещё и вручную грузится.Ещё проверьте легальность передаваемого FreeLibrary аргумента.
Перед физическим удалением/переносом надо сделать uninstall библиотеки ил реестра функцией DllUnregisterServer. О ней пишут:
The DllUnregisterServer function removes entries associated with a Cluster Administrator extension DLL from the system registry.
я задавал цикл до 100000 раз, оно все равно не выгружает.
Есть еще идеи?
FreeLibrary уменьшает счётчик использования DLL вызывающим процессом и выгружает библиотеку при достижении счётчика нуля. Если после вызова FreeLibrary ваша библиотека всё ещё не выгружена, значит для неё несколько раз вызывалась LoadLibrary, соответственно счётчик больше единицы. Такое бывает, если библиотека загружена по ходу инициализации процесса, поскольку зависимость была задана при компоновке, а потом ещё и вручную грузится.
Ещё проверьте легальность передаваемого FreeLibrary аргумента.
я задавал цикл до 100000 раз, оно все равно не выгружает.
Есть еще идеи?
А кстати, какое значение возвращает FreeLibrary? Originally posted by fellow
Тот факт, что библиотека может быть загружена каким-либо процессом, кроме вашего, FreeLibrary не опознаёт и не диагностирует. Таким образом, если ещё кто бы то ни было загрузил DLL и не выгрузил, то ни переместить, ни перезаписать её не удастся.
А кстати, какое значение возвращает FreeLibrary?
Что значит легальность FreeLibrary?
И как узнать какое значение возвращает FreeLibrary?
Что значит легальность FreeLibrary?
И как узнать какое значение возвращает FreeLibrary?
Легальность [COLOR=orangered]передаваемого FreeLibrary аргумента[/COLOR]
Убедитесь, что аргумент, который вы передаёте функции FreeLibrary, является действительным хендлом загруженного модуля библиотеки, HMODULE.
Узнать же возвращаемое значение легко, обратитесь к справке по Win32 SDK, там сказано, что функция FreeLibrary в случае неудачи возвращает 0.
Легальность [COLOR=orangered]передаваемого FreeLibrary аргумента[/COLOR]
Убедитесь, что аргумент, который вы передаёте функции FreeLibrary, является действительным хендлом загруженного модуля библиотеки, HMODULE.
Не понял я абсолютно этой фразы. я использую HINSTANCE. обьясните пожалуйста. Или, есть ли у вас аська, или что-то в этом духе, где можно в реальном времени пообщатся с вами?
Значение действительно у меня возвращает 0. почему?
ВЫ поняли что мне нужно сделать? мне нужно каким-то мокаром переместить DLL которое загружена виндой в память. Получается мне надо ее выгрузить, а потом переместить, и опять загрузить. Может есть возможность убрать с реестра какие-то данные связанные с этой ДЛЛ?
Скажите пожалуйста как мне заставить чтобы винда забыла про этот файл?! должно же быть команда которая вырубает все проги которые используют этот ДЛЛ, и выгружает его из памяти!
Да кстати, я пишу на С++ Builder.
Читайте также: