Professional Documents
Culture Documents
Лабораторна робота № 5
Лабораторна робота № 5
Лабораторна робота № 5
Функция DllMain
Більшість бібліотек DLL – це колекції практично незалежних одна
від одної функцій, що експортуються до застосунків і використовуються в
них. Крім функцій, призначених для експортування, у кожній бібліотеці
DLL є функція DllMain. Ця функція призначена для ініціалізації та
очищення DLL. Якщо Вашій DLL подібні дії не потрібні, Ви не зобов'язані
реалізовувати цю функцію. Приклад — DLL, що містить лише ресурси.
Структура найпростішої функції DllMain може виглядати, наприклад,
так:
BOOL WINAPI DllMain(HINSTANCE hinstDll,DWORD fdwReason,
PVOID fImpLoad)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
// DLL проектується на адресний простір процесу
break;
case DLL_THREAD_ATTACH:
// створюється потік
break;
case DLL_THREAD_DETACH:
// потік коректно завершується
break;
case DLL_PROCESS_DETACH
// DLL відключається від адресного простору процесу
break;
}
return(TRUE);
// використовується тільки для DLL_PROCESS_ATTACH
}
Функція DllMain викликається у кількох випадках. Причина її
виклику визначається параметром fdwReason, який може приймати одне з
наступних значень: DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
DLL_THREAD_ATTACH або DLL_THREAD_DETACH.
При першому завантаженні бібліотеки DLL процесом викликається
функція DllMain з fdwReason, що дорівнює DLL_PROCESS_ATTACH.
Щоразу під час створення процесом нового потоку DllMain викликається з
fdwReason, рівним DLL_THREAD_ATTACH (крім першого потоку, тому
що в цьому випадку fdwReason дорівнює DLL_PROCESS_ATTACH).
Після завершення процесу з DLL функція DllMain викликається з
параметром fdwReason, рівним DLL_PROCESS_DETACH. При знищенні
потоку (крім першого) fdwReason дорівнюватиме
DLL_THREAD_DETACH.
Параметр hinstDll містить описувач екземпляра DLL. Це значення —
віртуальна адреса проекції файлу DLL на адресний простір процесу.
Останній параметр, fImpLoad, відмінний від 0, якщо DLL завантажена
неявно, і рівний 0, якщо вона завантажена явно.
У разі успішного завершення, функція DllMain повинна повертати
TRUE. У разі помилки повертається FALSE, і подальші дії припиняються.
Експорт/імпорт функцій
Якщо перед змінною, прототипом функції або C++-классом DLL
стоїть модифікатор __declspec(dllexport), компілятор Microsoft С/c++
вбудовує в кінцевий OBJ-файл додаткову інформацію. Вона знадобиться
компонувальнику при збірці DLL з OBJ-файлів.
Виявивши таку інформацію, компонувальник створює LIB-файл із
списком ідентифікаторів, що експортуються з DLL. Цей LIB-файл
потрібний при збірці будь-якого EXE-модуля, що посилається на такі
ідентифікатори. Компонувальник також вставляє в кінцевий DLL-файл
таблицю ідентифікаторів, що експортуються, — розділ експорту, в якому
міститься список (в алфавітному порядку) ідентифікаторів функцій, що
експортуються, змінних і класів. Туди ж поміщається відносна віртуальна
адреса (relative virtual address, RVA) кожного ідентифікатора всередині
DLL-модуля.
Хай ми формуємо вихідний код EXE-модуля, який імпортує
ідентифікатори, що експортуються певною DLL, і посилається на них в
процесі виконання. Рекомендується користуватися ключовим словом
__declspec(dllimport) для функцій, що імпортуються, і ідентифікаторів
даних. Використовуючи посилання на ідентифікатори, що імпортуються,
компонувальник створює в кінцевому EXE-модулі розділ імпорту (imports
section). У ньому перераховуються DLL, необхідні цьому модулю, і
ідентифікатори, на які є посилання зі всіх використовуваних DLL.
Приклад створення
і неявного завантаження DLL по крокам
1. Створення DLL:
- створюємо застосунок, вказавши тип програми – DLL;
- у застосунку створюємо заголовний файл "MyDLL.h" з прототипами
функцій, які будуть експортуватися з DLL, використовуючи в якості
модифікатора extern "C" _declspec(dllexport);
extern "C" _declspec(dllexport) int fact(int)
- пишемо реалізацію експортованих функцій у файлі “MyDLL.cpp”:
extern "C" _declspec(dllexport) int fact(int n)
{
int rez(1);
for (int i=1;i<=n;i++) rez=rez*i;
return rez;
}
- збираємо DLL, в результаті чого з'являються фай “MyDLL.dll” і
“MyDLL.lib”
2. Підключення DLL:
- створюємо застосукнок, який буде використовувати функції з DLL;
вміст файлу “TestDLL.cpp”:
#include "stdafx.h"
#include "TestDLL.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int m; cin>>m;
cout<<m<<"!="<<fact(m)<<endl;
return 0;
}
- розміщуємо копію заголовного файлу "MyDLL.h" в папці з
заголовними файлами нового проекту і підключаємо його в файлі
"TestDLL.h":
#include "MyDLL.h"
- розміщуємо файли "MyDLL.dll" і "MyDLL.lib" в папці Debug нового
проекту;
- додаємо повне ім'я файлу бібліотеки “MyDLL.lib” до списку Project-
>Properties->Configuration Properties->Linker->Input->Additional
Dependencies
Контрольні запитання