Vindicar
@Vindicar
RTFM!

Знает ли кто-то системную DLL, которая не фиксирует себя в памяти при загрузке?

Я пытаюсь составить простой пример использования динамических библиотек. Программа имеет примерно следующий вид (псевдокод):
вывести список загруженных библиотек;
HMODULE lib = LoadLibraryA("library.dll");
вывести список загруженных библиотек;
MyFunc func = GetProcAddress(lib, "имя функции");
func();
вывести список загруженных библиотек;
func = NULL;
FreeLibrary(lib);
вывести список загруженных библиотек;


Проблема в том, что я попробовал это на user32.dll и MessageBoxA(), так как это очень наглядная функция. Вот только либа не выгружается при вызове FreeLibrary(). Я читал про такое поведение, есть целый ряд методов, позволяющих библиотеке "зафиксировать" себя в памяти, начиная от GET_MODULE_HANDLE_EX_FLAG_PIN и до хуков. Ну ок, не проблема, обычно если приложение использует графический интерфейс, оно его использует в течении всего времени исполнения. Но мне-то нужен наглядный пример!

Кому-нибудь известна системная библиотека, которая а) наглядна в своём поведении и б) не клинит себя в памяти?
Или мне придётся писать свою DLL?

Тег Windows, так как вопрос Windows-специфичен, а тега WinAPI нет. =(

Полный код для экспериментов

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <Windows.h>
#include <Psapi.h>
using namespace std;

#pragma comment(lib, "psapi.lib")  //для MS VS 2010

void EnumerateModules(vector<HMODULE>& list)
{
	HANDLE me = GetCurrentProcess(); //дескриптор текущего процесса
	DWORD needed_size = 0; // требуемый размер массива, в байтах
	DWORD actual_size = 0; //текущий размер массива, в байтах
	do
	{
		actual_size = list.size() * sizeof(HMODULE);
		EnumProcessModules(//список модулей
			me, //в каком процессе ищем модули?
			list.data(), //куда поместить дескрипторы модулей
			actual_size,//размер массива
			&needed_size //требуемый размер массива
		);
		list.resize(needed_size / sizeof(HMODULE)); //корректируем размер массива
	} while (needed_size > actual_size); //повторяем, пока массив слишком мал
}

string GetModuleName(HMODULE module)
{
	HANDLE me = GetCurrentProcess();
	string buffer(FILENAME_MAX, 0); //буфер для размещения имени
	//получаем имя модуля (без пути к нему)
	DWORD real_length = GetModuleBaseNameA(
		me, //дескриптор процесса
		module, //какой модуль опрашиваем
		&buffer[0], //куда поместить имя модуля
		buffer.size() //размер буфера
	);
	if (real_length == 0) //в случае ошибки
		return ""; //возвращаем пустую строку
	return buffer.substr(0, real_length); //иначе возвращаем имя
}

void ListModules(vector<string>& list)
{
	vector<HMODULE> modules;
	EnumerateModules(modules);
	list.clear();
	for (size_t i = 0; i < modules.size(); i++)
		list.push_back(GetModuleName(modules[i]));
}

void OutputList(const vector<string>& list)
{
	for (size_t i = 0; i < list.size(); i++)
		cout << "    " << list[i].c_str() << "\n";
}

void FindExtra(
	vector<string> larger, //массив с большим числом элементов
	vector<string> smaller, //массив с меньшим числом элементов
	vector<string>& diff //элементы первого массива, отсутствующие во втором
)
{
	sort(larger.begin(), larger.end());
	sort(smaller.begin(), smaller.end());
	diff.clear();
	set_difference(
		larger.begin(), larger.end(),
		smaller.begin(), smaller.end(),
		back_inserter(diff)
	);
}

//указатель на функцию с заданной сигнатурой:
//int WINAPI MessageBoxA(HWND wnd, LPCSTR text, LPCSTR caption, UINT uType)
typedef int (WINAPI* MyFuncType)( //соглашение о вызове WINAPI, имя типа MyFuncType, возвращает int
	HWND wnd,
	LPCSTR text,
	LPCSTR caption,
	UINT uType);

int main()
{
	setlocale(0, "RU-ru");
	vector<string> start;
	ListModules(start);
	cout << "================ НАЧАЛО ================\n";
	OutputList(start);

	HMODULE lib = LoadLibraryA("User32.dll");
	if (lib == NULL)
		cout << "Не удалось загрузить библиотеку.\n";
	else
	{
		vector<string> after_import, diff_import;
		ListModules(after_import);
		FindExtra(after_import, start, diff_import);
		cout << "+++ Добавилось после импорта +++\n";
		OutputList(diff_import);
		//получаем адрес функции
		LPVOID addr = GetProcAddress(lib, "MessageBoxA");
		if (addr == NULL)
			cout << "Функция не найдена!\n";
		else
		{	//указываем тип функции
			MyFuncType func = (MyFuncType)addr;
			func( //вызываем функцию
				NULL,
				"Hello, world!",
				"A test",
				MB_OK | MB_ICONINFORMATION
			);
		}
		vector<string> after_call, diff_call;
		ListModules(after_call);
		FindExtra(after_call, after_import, diff_call);
		cout << "+++ Добавилось после вызова +++\n";
		OutputList(diff_call);

		vector<string> after_free, diff_free;
		FreeLibrary(lib);
		ListModules(after_free);
		FindExtra(after_call, after_free, diff_free);
		cout << "================ КОНЕЦ ================\n";
		OutputList(after_free);
		cout << "--- Исчезло " << diff_free.size() <<" библиотек ---\n";
		OutputList(diff_free);
	}
	/*
	MessageBoxA(
		NULL,
		"Hello, world!",
		"A test",
		MB_OK | MB_ICONINFORMATION
	);
	*/
	return 0;
}

  • Вопрос задан
  • 321 просмотр
Пригласить эксперта
Ответы на вопрос 4
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Вряд ли тут какие-то хитрые методы остаться в памяти тут используются. Просто библиотека приложением итак используется. LoadLibrary лишь увеличивает счетчик использований, FreeLibrary просто уменьшает его, и ничего не загружается/выгружается. Попробуйте найти какую-то dll-ку, которая не выводится в списке в начале.
Ответ написан
@Bwana
Напишите свою dll и с ней работайте.
Ответ написан
Комментировать
Vapaamies
@Vapaamies
Разработчик будущей ОС для ПК размером 250 МБ
Знаю, что есть ключ реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs, но не знаю, из-за него ли такое поведение.
Ответ написан
Комментировать
@vanyamba-electronics
DLL выгружается из RAM автоматически, когда нет ни одного процесса, который её использует.
user32.dll - это системная библиотека WIndows, которая загружается при загрузке Windows, и выгружается только после shutdown Windows.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы