Самовыгружающийся DLL-модуль

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

BBB Я же сразу сказал, что не знаю.

WinMain Что за привычка отвечать не на поставленный вопрос, а говорить что знаеш. Он не спрашивал как система работает с ресурсами, а просил показать как "выгрузиться из памяти". Это разные задачи: организация выполнения модулей, находяшихся в dll и выгрузка этих модулей из памяти.
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Во-первых, я действительно говорю то, что знаю...
Во-вторых, очитить оперативную память от ненужных ресурсов не так уж сложно: достаточно оставить компьютер в покое минут на 10-15 (попить чайку, покурить, сходить в туалет), а система сама выгрузит из памяти всё лишнее. Либо загрузить в память другие модули, которые вытеснят неиспользуемые образы.
Вопрос в другом: кого это волнует на уровне прикладных задач?
Главное, чтобы его плагины функционировали правильно. А управление внутренними ресурсами ядра операционной системы - это на столько узко-специализированная задача для системных программистов, что на этом форуме её даже обсуждать бесполезно.
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

Народ, давайте конструктивно, без флейма.
Скажем так: Побудить систему к выгрузке иначе как с помощью FreeLibrary можно?
Если нет, то тема как бы исчерпана.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Спасибо всем за участие, но вы как-то ушли от темы.
Меня, как сказал WinMain, интересует в первую очередь правильная работа моего плагина в многопоточном режиме, в данном случае нужно просто корректно освободить модуль после завершения потоковой процедуры. Мне нужна всего лишь грамотная реализация этой логической схемы.
О физической зачистке памяти здесь речь вообще не шла, а зачем понадобилось разводить эту дискуссию? Лично мне не понятно.
В общем так, я решил вместо CALLBACK-функции использовать указатель на интерфейс, в котором будет вызываться метод UnloadMe(). Класс CPluginManager должен будет имплементировать этот интерфейс и данный метод соответственно. Кроме этого мне нужно в классе CPluginManager сделать получение списка имеющихся плагинов и их функциональное назначение, т.е. краткое описание того, что каждый из них делает. Потому как в меню пользователя должны отображаться не имена файлов DLL-модулей, а набор тех действий, который они выполняют (например: "Загрузка данных по сети", "Печать Счёт-фактуры" и др.), и по выбору пользователем того или иного пункта меню, CPluginManager должен загрузить соответствующий плагин и запустить в нём нужную процедуру. А после завершения процедуры через передаваемый интерфейс будет вызываться метод UnloadMe(), который и будет выгружать (освобождать) этот модуль.
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

[off]
WinMain писал(а):Во-первых, я действительно говорю то, что знаю...
Это студеческая привычка. Отвечать не на поставленный вопрос, а говорить что знаеш.
Во-вторых, очитить оперативную память от ненужных ресурсов не так уж сложно: достаточно оставить компьютер в покое минут на 10-15 (попить чайку, покурить, сходить в туалет), а система сама выгрузит из памяти всё лишнее.

Да, только на это нужно время, которого может и не быть.
[/off]
Decoder писал(а):Т.е. загрузил плагин, создал поток, запустил процедуру на выполнение, а дальше по завершении процедуры модуль сам должен выгрузиться из памяти.
Выражаться надо точнее, а то мы тут устроили диспут, а выгрузка из памяти совсем не нужна.
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Ну хорошо, а что ты сам-то подразумеваешь под словом "выгрузка" из памяти, если не освобождение ранее занятого пространства или отказ от использования какого-то системного объекта? Как ты себе этот процесс по-другому представляешь?
Может я что-то ещё должен сделать с уже неиспользуемым системным ресурсом?
достаточно оставить компьютер в покое минут на 10-15 (попить чайку, покурить, сходить в туалет), а система сама выгрузит из памяти всё лишнее.
А это хорошая идея: периодически предлагать пользователю сделать технологический перерыв.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Информацию о плагине можно записать в ресурсы, а именно в секцию VERSIONINFO, параметр FileDescription. Тогда этот текст будет виден в Проводнике. Если не знаешь, как брать информацию из VERSIONINFO, то я об этом позже могу написать. Все планигы нужно поместить в отдельную папку, например PLUGINS и с помощью функций FindFirstFile, FindNextFile получить список имеющихся модулей. Ассоциативно связать в программе информацию о плагине с именем его файла можно с помощью контейнера std::map.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Спасибо, WinMain. Интересное решение.

В общем так, чтобы никто мне больше не морочил голову с загрузкой/выгрузкой DLL-модуля и чтобы окончательно закрыть этот вопрос, я провёл следующий эксперимент:
Создал DLL-модуль, в котором объявил глобальный объект в виде класса, у которого в конструкторе на консоль отправляется текст "Глобальный конструктор", а из деструктора отправляется текст "Глобальный деструктор".
В коде так выглядит:

Код: Выделить всё

// FreeLib.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <tchar.h>

BOOL PrintText(LPCTSTR szText)
{
	static HANDLE hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
	//
	DWORD dw(0);
	return ::WriteConsole(hConsole, szText, ::lstrlen(szText), &dw, NULL);
}

class Global
{
public:
	Global()
	{
		PrintText(_T("Глобальный конструктор...\r\n"));
	}
	~Global()
	{
		PrintText(_T("Глобальный деструктор...\r\n"));
	}
} _global;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved)
{
    return TRUE;
}
Далее создал приложение, которое загружает этот модуль и тут же его освобождает.
Вот как оно выглядит в коде:

Код: Выделить всё

#include "stdafx.h"
#include "conio.h"

int _tmain(int argc, _TCHAR* argv[])
{
	HMODULE hModule = ::LoadLibrary(_T("FreeLib.dll"));
	if (hModule != NULL)
	{
		::FreeLibrary(hModule);
	}
	_getch();
	return 0;
}
После запуска приложения на экране появились строки
Глобальный конструктор...
Глобальный деструктор...
Само приложение при этом не завершает работу, поскольку этому препятствует функция _getch, ожидающая ввод символа с клавиатуры.
Таким образом можно сделать вывод, что если вызывается деструктор класса, то значит этот объект каким-то образом удаляется из памяти.
А это значит, что модуль всё-таки выгружается из памяти, иначе как ещё это можно было бы объяснить?
Продолжим эксперимент дальше. Пусть функция LoadLibrary() вызывается дважды, а FreeLibrary() только один раз.

Код: Выделить всё

#include "stdafx.h"
#include "conio.h"

int _tmain(int argc, _TCHAR* argv[])
{
	::LoadLibrary(_T("FreeLib.dll"));
	HMODULE hModule = ::LoadLibrary(_T("FreeLib.dll"));
	if (hModule != NULL)
	{
		::FreeLibrary(hModule);
	}
	_getch();
	return 0;
}
В этом случае на экране появилось только одна надпись:
Глобальный конструктор...
В итоге окончательный вывод таков: если количество вывовов FreeLibrary равняется количеству ранее вызванных LoadLibrary, то модуль просто выгружается из памяти и всё.
Остальные утверждения про невозможность выгрузить DLL из памяти - это не более чем домыслы.
Аватара пользователя
Airhand
Сообщения: 239
Зарегистрирован: 06 окт 2005, 16:21
Откуда: Dnepropetrovsk

Decoder писал(а):Таким образом можно сделать вывод, что если вызывается деструктор класса, то значит этот объект каким-то образом удаляется из памяти.
А это значит, что модуль всё-таки выгружается из памяти, иначе как ещё это можно было бы объяснить?
Уже неверный вывод. Если вызывается деструктор класса, то работа с этим экземпляром завершена. Больше ничего от сюда не следует. С чего ты решил, что объект был выгружен из памяти ?
Как-то винда выгружает библиотеки. Кто знает способ это сделать ?
Оптимизация по скорости:
#define while if
Оптимизация по размеру:
#define struct union
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

А каким ещё образом можно завершить работу с глобальным объектом, кроме как выгрузкой модуля или завершением работы всего приложения?
Можешь назвать какой-нибудь другой способ?
Ответить