Лабораторная работа
Создание и использование DLL в C++
Категория: | Лабораторная работа |
Дисциплина: | Системное программирование |
Город: | Беларусь, Минск |
Учебное заведение: | БНТУ, ФИТР |
Тег: | #Системное_программирование |
Стоимость работы: | 9 руб. |
Оценка: | 10 |
Объем страниц: | 11 |
Год сдачи: | 2022 |
Дата публикации: | 06.01.2022 |
* Кроме файла с работой, также есть архив с дополнительными файлами.
Описание дополнительных файлов:
Папка LW-3 — содержит исходный код программы на языке C++
Фрагменты для ознакомления
Лабораторная работа № 3
СОЗДАНИЕ И ИСПОЛЬЗОВАНИЕ DLL
Цель работы: рассмотреть ряд аспектов создания и использования динамических библиотек DLL в операционной среде Win32.
Изучаемые вопросы:
1. Функция DllMain. Последовательность вызовов в многопоточном приложении. Назначение и классификация диалоговых окон.
2. Экспорт/импорт функций.
3. Экспорт/импорт ресурсов.
4. Согласование интерфейсов.
5. Загрузка неявно подключаемой DLL.
6. Динамическая загрузка и выгрузка DLL.
7. Вызов функции по номеру.
8. Список динамических библиотек процесса.
Постановка задачи:
Разработать многопоточное Win32-приложение и двe DLL-библиотеки, одна из которых загружается явно, а вторая неявно. Первая динамическая библиотека содержит код обработки информации (например, код доступа к системной информации файловых систем FAT или NTFS), вторая – ресурсы типа диалог. Индивидуальное задание получить у преподавателя.
4.1. Функция DllMain. Последовательность вызовов в многопоточном приложении. Назначение и классификация диалоговых окон
Код библиотеки времени выполнения языка C++ вызывает функцию DllMain каждый раз, когда процесс или поток подключается к DLL или отключается от DLL (загрузке и выгрузке DLL‑библиотеки).
Примерный код данной функции может быть таким:
_declspec(dllexport) int counterCalledDLLMAin = 0; // экспортируемый счётчик вызовов
BOOL WINAPI DllMain(HMODULE hModule, // дескриптор модуля DLL
DWORD ul_reason_for_call, // причина вызова DllMain()
LPVOID lpvReserved) // указатель, зарезервированный для использования Windows
{
TCHAR szBuf[100] = { 0 };
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{//выполнить в процессе инициализацию, необходимую ее функциям
counterCalledDLLMAin++;
_stprintf_s(szBuf, TEXT("DLLInformationMemory - Информация(Counter=%i)"), counterCalledDLLMAin);
MessageBox(NULL, TEXT("Новый процесс пытается получить доступ к DLL. DLL спроецирована на адресное пространство процесса"), szBuf, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
break;
}
case DLL_THREAD_ATTACH:
{
counterCalledDLLMAin++;
_stprintf_s(szBuf, TEXT("DLLInformationMemory - Информация(Counter=%i)"), counterCalledDLLMAin);
MessageBox(NULL, TEXT("Новый поток существующего процесса пытается получить доступ к DLL"), szBuf, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
break;
}
case DLL_PROCESS_DETACH:
{ // очистку в данном процессе
counterCalledDLLMAin++;
_stprintf_s(szBuf, TEXT("DLLInformationMemory - Информация(Counter=%i)"), counterCalledDLLMAin);
MessageBox(NULL, TEXT("Последний поток процесса отсоединяется от DLL"), szBuf, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
break;
}
case DLL_THREAD_DETACH:
{
counterCalledDLLMAin++;
_stprintf_s(szBuf, TEXT("DLLInformationMemory - Информация(Counter=%i)"), counterCalledDLLMAin);
MessageBox(NULL, TEXT("Один из потоков процесса отсоединяется от DLL"), szBuf, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
break;
}
}
return TRUE; // корректно ли прошла инициализация DLL
}
Причины вызова DllMain определяется параметром ul_reason_for_call. При первой загрузке библиотеки DLL процессом вызывается функция DllMain с ul_reason_for_call, равным DLL_PROCESS_ATTACH. Каждый раз при создании процессом нового потока DllMain вызывается с ul_reason_for_call, равным DLL_THREAD_ATTACH.
По окончании работы процесса с DLL функция DllMain вызывается с параметром ul_reason_for_call, равным DLL_PROCESS_DETACH. При уничтожении потока (кроме первого) ul_reason_for_call будет равен DLL_THREAD_DETACH.
4.2. Экспорт/импорт функций
Есть два способа загрузки Dll-функции:
1. При неявном связывании DLL библиотеки:
Код функции из DLL библиотеки (откуда будет экспортирована функция):
#define DLLEXPORTM _declspec(dllexport)
DLLEXPORTM VOID CALLBACK getGlobalMemoryStatus(HWND hDlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
VOID CALLBACK getGlobalMemoryStatus(HWND hDlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Код импортирования из DLL библиотеки функции getGlobalMemoryStatus():
#define DLLIMPORTM __declspec(dllimport)
DLLIMPORTM VOID CALLBACK getGlobalMemoryStatus(HWND hDlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
IDTimer = SetTimer(hDlg, IDC_TIMER1, NELAPSE, (TIMERPROC)getGlobalMemoryStatus);
SendMessage(hDlg, WM_TIMER, NULL, NULL);
2. При явном связывании DLL библиотеки:
Содержимое файла Source.def из DLL библиотеки:
LIBRARY "NewDllexplicit"
EXPORTS
hIcon @2
gProtect @1
Загрузка функции может быть выполнена следующим образом:
typedef VOID (PFN)(DWORD protect, TCHAR(&szBuf)[100]);
static HMODULE hModule = NULL;
static PFN* function;
hModule = LoadLibrary(TEXT("NewDllexplicit"));
if (hModule)
{
function = (PFN*)GetProcAddress(hModule, (LPCSTR)MAKEINTRESOURCE(1));
if (function == NULL)
{
MessageBox(hDlg, _TEXT("Функция gProtect не найдена"), TEXT("LoadLibrary"), MB_OK | MB_ICONQUESTION);
DestroyWindow(hDlg);
return 0;
}
}
else
{
MessageBox(hDlg, _TEXT("Библиотека не найдена"), _TEXT("LoadLibrary"), MB_OK | MB_ICONQUESTION);
DestroyWindow(hDlg);
return 0;
}
FreeLibrary(hModule);
4.3. Экспорт/импорт ресурсов.
4.4. Согласование интерфейсов.
4.5. Загрузка неявно подключаемой DLL.
4.6. Динамическая загрузка и выгрузка DLL.
4.7. Вызов функции по номеру.
4.8. Список динамических библиотек процесса.
Результаты работы программного обеспечения:
