| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: WinAPI и системное программирование > Выгрузить чужую DLL |
| Автор: Domoffou 26.6.2008, 00:07 |
| Здравствуйте. Каким образом можно выгрузить из памяти чужую DLL? Моя DLL работает самостоятельно =) При скачивании более новой версии, моя программа (updater) должна заменять старый длл на новый, а вот как это сделать без выгрузки - не знаю, возможно обмен данными между "чужим" процессом (апдейтером) и местной длл, и выгрузка в последствии из самой себя? (если такое вообще возможно). |
| Автор: Domoffou 26.6.2008, 09:00 | ||
Ну вообще свою Но, получается, выгрузка своей библиотеки, запущенной от своей же (но другой) программы, которая уже не работает Библиотека загружается посредством Loadlibrary в одной программе, далее программы выходит БЕЗ FeeeLibrary. DLL остается в памяти. Мне необходимо заменить длл, находящийся на диске, но, соответственно, изменить его не могу, пока не будет перезагружен комп, а его перезагружать не желательно. FreeLibraryAndExitThread - не помогает :( Подскажите любой способ, я думаю подойдет тут выгрузка длл другой программой (как я понимаю, нужно уменьшить каким-то образом число глобальных счетчиков использования библиотеки) либо послать сообщение ДЛЛ, а она в свою очередь сама самостоятельно отсоединится от всех процессов и завершит работу и с файлом можно будет делать все что угодно. |
| Автор: CodeMonkey 26.6.2008, 10:07 | ||
Эту фичу стоило бы назвать: "случайным образом обрушь программы, использующие мою DLL". Вы представляете, что будет, если приложение попробует воспользоваться DLL после того, как вы её выгрузили? |
| Автор: Riply 26.6.2008, 10:15 | ||||
Вот это сформулировал - так сформулировал ! Я поняла так: 1. есть твоя библиотека, которую загрузил некий процесс. 2. у тебя есть возможность общения с ней (библиотекой) Ну и отлично: сообщаем ей, что пора выгружаться и она делает это, например, при помощи FreeLibraryAndExitThread. P.S. Сама использовать эту ф-ю не пробовала ( в те поры не знала о ее существовании). Выгружалась "вручную": сообщала библиотеке, что пора закругляться, и создавала нить, в которой вызывала FreeLibrary. Добавлено через 4 минуты и 17 секунд
Так перед выгрузкой надо пресечь данные, совершенно наглые попытки в корне Иными словами вежливо попросить целевой процесс самостоятельно выгрузить нас |
| Автор: CodeMonkey 26.6.2008, 10:34 | ||
Совершенно верно. Но я сказал это только для того, чтобы уточнить, понимает ли это автор вопроса. P.S. А то с некоторых станется и вызвать в бесконечном цикле FreeLibraryAndExitThread из главного потока. |
| Автор: Domoffou 26.6.2008, 11:06 |
| Как я понимаю, DLL фактически работает со всеми процессами в системе? Т.е. при Loadlibrary он присоединяется ко всем процессам (в DLL висит хук). Пробовал ставить DLL_PROCESS_DETACH, но эта функция запускается каждый раз при закрытии какого-либо приложения (жаль, что ей нельзя воспользоваться глобально) :( Riply, я попробовал функцию, которую Вы мне предложили. Программа, вызывающая эту функцию, попросту закрывается, а DLL продолжает работать и записывать тестовый лог. Возможно, я не очень понимаю, но мне нужно вызвать FreeLibraryAndExitThread столько раз, сколько процессов в системе? Вся проблема в том, что программа, загружающая длл и программа, которая должна ее выгружать - это д.б. разные процессы, причем работа второго должна производиться без деятельности первого (1 процесс закрыт, ДЛЛ висит в памяти). Если я правильно понимаю - целевой процесс, это программа, загрузившая ДЛЛ? Ну дык она уже и не работает |
| Автор: Domoffou 26.6.2008, 11:43 |
| Сделал выводы из умной литературы Первый раз, при загрузке DLL она помещается в память, выполняются действия при инициализации ДЛЛ, глобальный счетчик юзания этой длл становится 1. Программа закрывается, длл висит в памяти. Счетчик по-прежнему 1. Запускается другая программа, подсоединяется к моей ДЛЛ, счетчик становится 2, хотя действия при инициализации не выполняются, т.к. длл уже в памяти. Делаю из 2 программы FREELIBRARY, длл отсоединяется от 2 процесса, счетчик становится 1. А выгрузка производится при длл равной 0. Правильно ли я понимаю? И что делать, как говорится, в такой ситуации. P.S. FreeLibraryAndExitThread д.б. в библиотеке? |
| Автор: Riply 26.6.2008, 12:03 |
Надо бы тебе еще почитать "умной литературы" Я поступала так (это не руководство к действию, а просто рассказ 1. Делаем невозможной продгрузку Dll-ки новыми процессами (зависит от способа, которым ты подгружал) 2. Сообщаем уже подгруженным, что пора закругляться. (Они должны подчистить за собой все, что напакостили в процессе) 3. Опять зависит от способа загрузки, но попробуй так: Каждая Dll-ка (подчистив за собой) создает нить, в которой вызывается FreeLibraryAndExitThread (эта нить не должна использовать ничего из DLL) По поводу: не уверена, что это возможно (ну, скажем так: лего реализуемо) |
| Автор: CodeMonkey 26.6.2008, 12:08 | ||
Вы что-то не то нам говорите. Если вы закрыли все приложения, использующие вашу DLL, то она не может "ещё работать". Ей просто негде это делать. Значит, у вас есть ещё процессы, использующие вашу DLL.
Вот с этого и надо было начинать. Вы, кстати, ловушку перед выходом снимаете? http://www.delphikingdom.ru/asp/answer.asp?IDAnswer=62697 http://www.delphikingdom.ru/asp/answer.asp?IDAnswer=58060 Да, правильно. |
| Автор: Domoffou 26.6.2008, 13:19 | ||
Перед выходом чего? ДЛЛ остается в памяти. Я то как раз и пытаюсь сделать выход. Несколько вопросов: 1. Хук в длл "присоединяется" к памяти всех процессов, с кем работает юзер? Т.е. чтобы выгрузить библиотеку, нужно заставить каждую прогу снять с нее хук или попросту закрыть? 2. При первой загрузке ДЛЛ происходит инициализация. При второй - происходит или нет? Моя программа работает полностью в длл (мож, кто знает) т.е. загружает ее другой проц (LoadLibrary) и выходит. в ДЛЛ при инициализации стоит SetHook. При закрытии каждой программы (например блокнота) вызывается DLL_PROCESS_DETACH В идеале я бы сделал по этому событию UnHook, но в таком случае придется закрывать все окна, к которым присоединился хук фактически, а это нереально.
хук, как я понимаю, подгружается автоматически хмм... это как? |
| Автор: bartram 26.6.2008, 14:34 | ||
Делай Unhook при выгрузке какого-нибудь системного процесса например Explorer.exe. Если Explorer выгрузился, значит винда завершает работу, а значит снимаем хук |
| Автор: Riply 26.6.2008, 14:55 | ||||||
А зачем закрывать все окна ? Ты что там (в процессах) дополнительно делаешь что-то необратимое ? Если так, то меняй идеологию.
Ты же сам сказал:
а теперь спрашиваешь "как" ? |
| Автор: Domoffou 26.6.2008, 15:05 | ||||||||||
| Приведу код. DLL:
Программа, загружающая длл:
Хорошая идея, будет полезна при сохранении данных при перезагрузке или выключении ПК. Каким образом следить? Пробегать по списку процессов?
Нет, процедура хука простая - принимает клавишу и записываем его в файл (для теста). Ну совсем не догоняю как это реализовать пробовал так в программе (уже другой):
программа завершается а логи продолжаются делать. P.S. Секцию DLLProc пока не подключал. Нужно ли? |
| Автор: bartram 26.6.2008, 16:07 | ||
Нет, в событии DLL_PROCESS_DETACH смотрим к какому процессу прицеплены, если это Explorer то снимаем хук. |
| Автор: Domoffou 26.6.2008, 16:44 |
| не жмотьте, дайте коду поесть ну чуточку хотя-бы, я встрял совсем :( |
| Автор: CodeMonkey 26.6.2008, 16:45 | ||||||||||||||
Если не критично, что апдейт применяется не сразу, то можно библиотеку переименовать (например, добавить '_' в конец имени). А апдейт положить на нужное место. При перезагрузке подцепится апдейт. До перезагрузки будет работать старый вариант. При запуске удалять старый файл с '_' в имени.
Почти ко всем. Хук может не присоединиться к процессу, если не хватает прав. И не сразу библиотека грузится, а с задержкой. После удаления хука библиотека выгружается из всех процессов, но, опять таки, с задержкой.
Нет.
Так делать нельзя:
Ваше приложение должно жить на протяжении всей работы хука и снять его до выхода. Вообще мне казалось, что система подчистит за вами, но, возможно, я ошибаюсь. Этот вопрос требует дальнейшего исследования.
Чёрта с два вы его сделаете. Какой дескриптор вы собираетесь передать в UnhookWindowsHookEx? У вас его нет. Процесс, в котором этот дескриптор имел смысл уже завершился.
А вы вообще понимаете, что вы делаете? Как ваш процесс связан с остальными процессами системы? Правильный ответ - никак. |
| Автор: Domoffou 26.6.2008, 17:29 | ||
| CodeMonkey, спасибо за пояснения. Я написал программу для небольшого наблюдения за юзером и вывода статистики определенной. По идее все работает, но я задался целью - запихнуть все в DLL, и грузить при входе юзера (от explorer.exe). Согласен, это сложно, но я все же хочу это реализовать, и прошу Вас помочь мне с этим! Естественно, explorer при старте делает только Loadlibrary и все, соответственно дальше мне нужно работать самому. И при выходе юзера библиотеку винда закроет автоматически, как я понимаю, вместе с закрытием explorer. Но вот, действительно, захочу я поставить апдейт. И никак. Переименовать старую ДЛЛ не получится, ибо она юзается системой. Удалить, соответственно, тоже нельзя. Мне нужно каким-то образом (даже в случае продолжения работы эксплорера) передать программе, мол "апдейт пришел - останавливай хук и выгружайся, дальше я все сделаю". Допустим, реализовать при закрытом приложении уже никак, то бишь нужно ждать перезагрузки. Тогда подскажите идеи в этом направлении. :( Добавлено через 2 минуты и 56 секунд
Как я понимаю, в дельфе к DLLMain не передается хэндл окна? |
| Автор: CodeMonkey 26.6.2008, 17:51 | ||
Извините, но по-моему, вы врёте. Вы это проверяли? Обычно, если DLL загружена, то это не мешает её переименовывать. Попробуйте сами: запустите любую программу. А теперь переименуйте exe. Удалить его вам не дадут, а вот переименовать - запросто. Аналогичная ситуация и с DLL. На этом и был основан мой совет по апдейту в предыдущем посте. Переименовываем старую DLL-ку, чтобы не мешалась, а на её место укладываем новую.
Давайте подробнее, а то я уже ничего не понимаю. То у вас ваше приложение делает LoadLibrary и выходит, то теперь Explorer. Вы уж давайте, пишите как есть. И пишите что хотите получить. Это не сложно, но пока совершенно непонятно, что у вас там происходит. Соответственно, нельзя дать совет, подходящий к ситуации, т.к. ситуация не ясна. Можно палить наобум - вам уже так штуки три минимум способов сказали. |
| Автор: Domoffou 26.6.2008, 18:01 | ||
Решил, что если удалить нельзя, то переименовать не получится тем более. Приношу свои извинения, но не стоит так негативно реагировать
Мое приложение - это лишь пример, тест загрузки ДЛЛ в память. Есть такая замечательная штука, как загрузка динамических библиотек при старте Windows. Для нее даже не потребуется программы, т.к. длл будет запускать SHELL, и делать он это будет через Loadlibrary, поэтому никакой особой разницы с моим приложением нет. Допустим апдейт сделаю с перезагрузкой, это Вы мне сказали. Тогда как быть с открытием административной панели для просмотра отчетов? В моей DLL еще и форма, которую нужно открыть в определенный момент, и, естественно, на время просмотра отчетов все хуки нужно останавливать. Подойдет UnHook при открытии формы из длл или этого буит мало? |
| Автор: bartram 26.6.2008, 21:31 |
Не знаю, откуда такая инфа? Что далеко ходить, можете проверить.... |
| Автор: CodeMonkey 27.6.2008, 09:36 |
| >>> Есть такая замечательная штука, как загрузка динамических библиотек при старте Windows. Вы AppInit_DLLs имеете ввиду? |
| Автор: Domoffou 27.6.2008, 10:22 |
Угу, вроде, хотя я пробовал над ShellServiceObjectDelayLoad. Есть еще секция ShellExecuteHooks в эксплорере. |
| Автор: CodeMonkey 27.6.2008, 11:03 |
| Мда, у вас поразительная способность использовать инструменты не по назначению Если вам нужен глобальный системный хук, то создайте обычное приложение, которое будет устанавливать и снимать ловушку. Не надо извращаться и создавать себе сложности. |
| Автор: Domoffou 27.6.2008, 14:32 | ||
В этом то и весь интерес =) Обычное приложение уже создано и прекрасно функционирует. Вопрос в невидимости и в оптимизации системы, поэтому переписываю программу в DLL, стараясь юзать как можно меньше стандартных компонентов, занимающих кучу лишних килобайт. P.S. Вопрос в догонку так сказать, в DLL будет форма программы, которая займет, я полагаю, в общей сумме около 1 Мб. FormCreate будет выполняться только после нажатия спец клавиш. Ну так вот вопрос - насколько замедлит функционирование 1Мб длл в памяти. Я полгагаю, что не особо, ведь ресурсы формы будут играть роль только в случае ее создания? Спасибо. |
| Автор: CodeMonkey 27.6.2008, 15:03 | ||||
Тогда я пас. Я люблю, чтобы всё работало красиво и правильно. А красиво и правильно - это отдельный процесс, управляющий хуком. И если я правильно понял идеологию, то ещё одна отдельная DLL или EXE, которая отвечает за GUI.
Да. Но я бы разделил эти вещи. Нет смысла пихать GUI в туже библиотеку, что и функционал.
Вам, что, делать нечего? Это ничего не даёт. Да и формы вы собираетесь пихать прямо в эту же DLL. Вам не кажется, что вас разрывают противоречивые порывы? P.S. Линк по теме http://www.osnews.com/images/comics/wtfm.jpg - good code vs bad code. |
| Автор: Riply 27.6.2008, 15:51 | ||
А зачем нужна "невидимость" ? Насчет "оптимизации системы", то сильно сомневаюсь, что ее работа будет более оптимальной от загрузки в каждый процесс Dll-и, да еще и с формой, и чтоб совсем жизнь медом не казалась, с хуками |
| Автор: Virtuals 29.6.2008, 21:30 | ||
по метру в длл да с хуками, да в каждое приложение,... батенька да вы маньяк, по попыткам сожрать ресурсы всемилюбимомуМ$ до вас далеко. а по теме: если у пользователя есть права админа, то поверьте ему будет побоку ваша длл, как вы ее не прячте (любой антивирус на нее сразу ткнет пальцем, неговоря уже о любимом AVZ) если прав нет, то все проще всю реализацию в сервис, а гуи в отдельный модуль, запускаемый по желанию |
| Автор: Domoffou 30.6.2008, 16:27 |
| Хм... спасибо, пожалуй так и сделаю - буду хранить интерфейс в отдельной DLL. Вопрос еще один, имеет ли смысл пускать обработку хуков в отдельную DLL? Ведь, как я понимаю, DLL с хуком внедряется в процессы, поэтому я заинтересован в том, чтобы библиотека была как можно меньше. Поэтому при получении, например, клавиши или клика мыши я вызываю процедуру из другой DLL (которая без хуков), она в свою очередь уже будет все обрабатывать. 1. Насколько уменьшится время обработки клавиш (потеряю ли я в этом что-то), т.е. если обработку хуков вызывать в другой подключаемой библиотеке? 2. Будет ли вторая библиотека работать со всеми процессами, или только с моим (я заинтересован во втором варианте, т.е. будет подгружаться только к моей ДЛЛ). P.S. Наверняка возникнет вопрос - а почему бы не передавать клавиши в exe приложение, которое уже будет обрабатывать входящие сообщения? Ответ - нельзя, ибо пишу свою мечту - программу для учета рабочего времени ПК, а невидимость - основная задача, решаемая спомощью ДЛЛ. P.P.S. DLLку я не прячу от админа, а от юзера. Спасибо. |
| Автор: Rennigth 30.6.2008, 18:44 |
| Domoffou, Если первоначально загрузочная dll будет подгружена екслореру, то вам не кажеться что опытный юзер догадается просто перезапустить его п.с. или я может конечно идеи недогнал, многа букаф и все чет очень запутано. п.с.с. имхо сервис тут самое оно. |
| Автор: Domoffou 30.6.2008, 21:34 | ||
Ну я полагаю, что с перезапуском Эксплорера библиотека будет подгружена заново. Проблема в том, что я не умею прятать сервис от глаз юзера - в этом то и косяк, литературы много прочитал но решения так и не нашел :( Поэтому приходится так изворачиваться) |
| Автор: CodeMonkey 30.6.2008, 22:44 |
Обычно сочетание сервиса и чего-то, что работает в сессии пользователя, - плохая идея по многим причинам. |
| Автор: Virtuals 1.7.2008, 09:05 |
| CodeMonkey, Обычно сочетание сервиса и чего-то, что работает в сессии пользователя, - идеальная идея по всем причинам! сервис.ехе общается с гуи.ехе!!! а вот если сервис создает свои окошки то да!, это очень плохо Domoffou, а зачем прятать? пусть видят что большой брат недремлет! помогает намного лучше, а вот тот кто сможет среди списка процессов выделить именно ваш сервисный и понять что он делает, тот влегкую его снесет со станции |
| Автор: Domoffou 1.7.2008, 09:08 | ||
Сейчас программа работает по такому принципу, но цель для меня поставлена - поэтому приходится реализовывать. |
| Автор: CodeMonkey 1.7.2008, 09:34 |
В таком случае это решается административными мерами? Т.е. нужно запускать свой процесс от имени администратора. Тогда пользователь не будет иметь прав, чтобы его завершить. Да, я имел ввиду, что сервис сам взаимодействует с сеансом пользователя. |
| Автор: Domoffou 1.7.2008, 16:05 | ||
Довольно часто юзеры ограничены другими сторонними утилитами, хотя учетная запись в группе Администраторы. Тем более "админ", в моем случае, это человек не наделенный какими-либо привилегиями по правам, а устанавливающий программу. |