Статична завантаження, Програми та розповсюдженний програм, C / C + +, статті

Створимо спершу проект (File / New / DLL). Буде створений проект, що містить
наступне:

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) {
return 1;
}

і довгий коментар застережливий вас про те, що для работо здібності
вашої DLL необхідно снеі забезпечити поствку деяких dll якщо ви використовуєте
екземпляри класу String.

Для експорту та імпорту з DLL необхідно використовувати моди фікатори __export
і __import відповідно. Але в C + + Builder можна використовувати нове ключове
слово __delspec () з параметрами dllexport і dllimport відповідно. Самі
розумієте, що для того щоб еспортіровать функції з бібліотеки еужен один
заголовний файл з описами _delspec (dllexport) для експортованих функцій,
для імпорту функцій у додаток вам необхідно буде поставити анологичних
заголовний файл але з _delspec (dllimport) описами, що досить незручно.
Ця проблема вирішується легко: додайте в заголовний файл бібліотеки наступне:

#if defined(BUILD_DLL)
# define DLL_EXP __declspec(dllexport)
#else
# if defined(BUILD_APP)
# define DLL_EXP __declspec(dllimport)
# else
# define DLL_EXP
# endif
#endif

у вихідному файлі DLL напишіть # define BUILD_DLL, а замість
__declspec (dllexport) пишіть DLL_EXP. При написанні програми додайте рядок
# Define BUILD_APP, і просто підключіть заголовний файл DLL.


Приклад DLL: файл P.cpp

//—————————————————————————
#define BUILD_DLL
#include
#include "p.h"
#pragma hdrstop

//—————————————————————————
// Important note about DLL memory management when your DLL uses the
// static version of the RunTime Library:
//
// If your DLL exports any functions that pass String objects (or structs/
// classes containing nested Strings) as parameter or function results,
// you will need to add the library MEMMGR.LIB to both the DLL project and
// any other projects that use the DLL. You will also need to use MEMMGR.LIB
// if any other projects which use the DLL will be perfomring new or delete
// operations on any non-TObject-derived classes which are exported from the
// DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
// EXE”s to use the BORLNDMM.DLL as their memory manager. In these cases,
// the file BORLNDMM.DLL should be deployed along with your DLL.
// To avoid using BORLNDMM.DLL, pass string information using "char *" or
// ShortString parameters.
//
// If your DLL uses the dynamic version of the RTL, you do not need to
// explicitly add MEMMGR.LIB as this will be done implicitly for you
//————————————————————————-
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) {
return 1;
}

//————————————————————————-

void Message(char *s) {
i=10;
Application->MessageBox(s,"From DLL",IDOK);
}


Файл P.h

#if defined(BUILD_DLL)
# define DLL_EXP __declspec(dllexport)
#else
# if defined(BUILD_APP)
# define DLL_EXP __declspec(dllimport)
# else
# define DLL_EXP
# endif
#endif

DLL_EXP void Message(char *s);
DLL_EXP int i;


Скомпілюйте проект.


Якщо ви натиснете Run то після завершення побудови буде видано повідомлення
що дана програма не можнт бути виконана (природно). Тепер напишемо
зухвалу програму. Втомже каталозі создайде новий проект (File / New
Application) в форму помістіть одну кнопку і створи обробник події OnClick.
Ваш виконуваний файл має бути собою слдующее:

//—————————————————————————
#include
#define BUILD_APP
#pragma hdrstop
#include "p.h"
#include "Unit1.h"
#include
//—————————————————————————
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//————————————————————————-
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
}

//————————————————————————-
void __fastcall TForm1::Button1Click(TObject *Sender) {
char c[10];
Message("roma");
for( ; i>0;i–) {
sprintf(c,"Example %d",i );
Application->MessageBox("Example of using DLL variable",(char*)c,IDOK);
}
}

//————————————————————————-


Не забудьте про об’яви на початку файлу. Зайдіть в менеджер проектов.Там
відкрийте свій проект і додайте. lib файл з Попереднє проект з DLL (правий
клік, пункт ADD). Запустіть проект.

Як бачите, для того, щоб вашу DLL можна було використовувати необхідно три
Файл: сама DLL, заголовний файл і бібліотечний файл. lib.

Динамічне завантаження


Динамічне завантаження горазда складніше. Однак для динамічного завантаження
потрібно тільки сама DLL (непотрібною ні. lib ні заголовний файл, хоча його
можна ісполбзовать для опису експортованих функцій для предполагемого
користувача).


Давайте розглянемо на прикладі, як здійснюється динамічне завантаження.
Створіть новий прокто DLL і внесіть до нього таке:

extern "C" void __export  Message(char *s)  {
Application->MessageBox(s,"From DLL",IDOK);
}

Cкомпіліруйте проект, в результаті чого буде створена DLL.

Тепер створіть проект програми анологичних проекту для використання
статичної завантаження (форма з кнопкою і обробником події кнопки OnClick)
нижче наведений код програми: (Unit11.cpp)

//—————————————————————————
#include
#pragma hdrstop
#include "Unit11.h"
#include
//—————————————————————————
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//—————————————————————————
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
}
//—————————————————————————

void __fastcall TForm1::Button1Click(TObject *Sender) {
void (__stdcall *Message)(char *s);
HINSTANCE dllp = LoadLibrary("p.dll");
if (dllp) {
Message= (void(__stdcall *) (char*))
GetProcAddress(dllp, "_Message");
if (Message) Message("Hi From Dinamic DLL");
}
FreeLibrary(dllp);
}
//—————————————————————————


запустіть цей проект, при натисканні на кнопку повинно видаватся сообшеніе.
Тепер розберемося, як це працює.



  • void (__stdcall *Message)(char *s);-Оголошення покажчика на функцію.
  • HINSTANCE dllp = LoadLibrary(“p.dll”);– Завантаження бібліотеки в пам’ять.

  • Message= (void(__stdcall *) (char*)) GetProcAddress(dllp,
    “_Message”);
    присвоєння вказівником адреси функції DLL.
  • Message(“Hi From Dinamic DLL”); робочий виклик фунції (власне те
    для чого все це і робиться).
  • FreeLibrary(dllp);– Вивантаження бібліотеки з пам’яті.

Зверніть увагу на те, що прізагрузке можна вказати точне местоположніе
бібліотеки (необезательно в тому ж каталозі де і додаток).


слід стежити щоб збігалися оголошення функції в *. dll і *. exe (зокрема
в цьому прикладі: __stdcall не збігаються, тому викидає External
exception)
привожу робочий приклад:
void __fastcall
TForm1::Button1Click(TObject *Sender) {
void (*Message)(char
*s);
HINSTANCE dllp = LoadLibrary(“p.dll”);
if (dllp) {
Message=
(void(*) (char*))
GetProcAddress(dllp, “_Message”);
if (Message)
Message(“Hi From Dinamic DLL”);
}
FreeLibrary(dllp);
}
dll-ку
залишаємо колишню

Вміст параграфа “Сутність
динамічного зв’язування “

Статична і
динамічна компоновка


Звичайна Windows-програма
являє собою виконуваний файл, який зазвичай створює одне або більше вікон,
а для отримання даних від користувача використовує цикл обробки
повідомлень.

·         Динамічно
бібліотеки (
DLL), Як правило, безпосередньо не
виконуються і зазвичай не отримують повідомлень. Вони представляють із себе окремі файли з функціями, які викликаються
програмами та іншими DLL для виконання певних завдань. DLL активізується тільки тоді, коли інший модуль
викликає одну з функцій, що знаходяться в
бібліотеці
.


Розглянемо сутність динамічного і
статичного зв’язування (або компонування)

·         Статичний зв’язування
(Static linking) має місце в процесі зв’язування програми
, Коли для створення виконуваного
exe-файла зв’язуються воєдино різні об’єктні
obj-модулі, lib-файли бібліотек і, як правило, скомпільовані
res-файли ресурсів.

·         Термін динамічне зв’язування (dynamic linking) відноситься до
процесам, які Windows використовує для того, щоб зв’язати виклик функції в
одному з модулів з реальною функцією з DLL. На відміну від
статичного зв’язування динамічне зв’язування
має місце під час виконання програми. У виконуваний файл
занесена тільки інформація про місцезнаходження
функцій DLL (цю інформацію додаток отримує з так званих
бібліотек імпорту).

У момент виконання програми
завантажується вся бібліотека цілком.
Завдяки цьому різні процеси можуть користуватися
спільно бібліотеками, що знаходяться в пам’яті. Такий підхід дозволяє
скоротити обсяг пам’яті, необхідний для декількох додатків, що використовують
багато спільних бібліотек, а також контролювати розміри
exe-файлів.



  • Деякі спільні
    бібліотеки (наприклад, файли шрифтів) містять
    тільки ресурси. У них містяться лише дані (зазвичай у вигляді
    ресурсів), і практично немає програмного коду.

Таким чином, одній цілей існування динамічно підключаються бібліотек
є забезпечення програм функціями і ресурсами, які можна
використовувати в багатьох, зовсім різних програмах.


Хоча модуль динамічно підключається
бібліотеки може мати будь-яке розширення (. exe або. fon), стандартним розширенням, прийнятим у Windows,
є. dll.



  • Тільки ті DLL, які мають
    розширення. dll, Windows завантажить
    автоматично. Якщо файл має інше розширення, то додаток повинен завантажити модуль бібліотеки
    явно. Для цього використовується функція LoadLibrary або LoadLibraryEx.

Як правило, найбільший сенс DLL набувають у контексті великого
проекту (або пакета програм). Зазвичай в таких програмах
використовуються деякі загальні підпрограми.

·         Ці підпрограми можна помістити у звичайну об’єктну бібліотеку
(Файл з розширенням. Lib) і додати її до кожного програмного модулю при
компонуванні. Але такий підхід надмірний,
оскільки в цьому випадку в кожній програмі буде знаходитися однаковий код
підпрограм, що виконують одні й ті ж завдання.

·         Більше того, при зміні однієї
з підпрограм в бібліотеці, необхідно
перекомпоновувати всі програми, до складу яких входить ця
підпрограма.

·         Однак якщо помістити всі ці общеіспользуемие підпрограми в динамічно підключається бібліотеку, то обидві
проблеми будуть вирішені. Тільки в одному бібліотечному модулі потрібно
містити необхідні всім додаткам підпрограми, і можна змінити
бібліотечний модуль без перекомпонування додатків.

Три значення одного
слова “бібліотека”


У попередньому викладі
слово “бібліотека” зустрічається в різних контекстах. Крім динамічно
бібліотек, що підключаються воно згадується в поєднаннях “об’єктна бібліотек” та
“Бібліотека імпорту”. Розберемося в цих поняттях.

Об’єктна
Бібліотека
– Це
файл з розширенням. lib, в якому міститься код,
додається до коду програми, що знаходиться у файлі c розширенням. exe, коли
йде компонування програми
.

·         Наприклад, в Microsoft Visual C + +
звичайна об’єктна бібліотека, яка при компонуванні
приєднується до програми, називається libc.lib.

Бібліотека імпорту
являє собою особливу форму файлу об’єктної бібліотеки
. Так само як об’єктні бібліотеки,
Бібліотека імпорту має розширення. lib і використовується компоновщиком для
дозволу посилань на функції в початковому тексті програми. Проте в бібліотеках імпорту програмного коду
немає. Замість них в бібліотеках імпорту
знаходиться інформація, необхідна компонувальнику для установки таблиці посилань
всередині exe-файлу, призначеної для динамічного
зв’язування.

Об’єктні бібліотеки та бібліотеки
імпорту (створювані одночасно з модулем DLL) використовуються тільки на етапі
розробки програми. Динамічно підключаються
бібліотеки використовуються під час виконання програми. Динамічно
бібліотека повинна знаходиться на диску,
коли виконується програма, яка використовує цю
бібліотеку
.



  • Якщо операційної
    системі Windows потрібно самостійно завантажити модуль динамічно
    підключається бібліотеки
    , То файл DLL-бібліотеки повинен
    зберігатися в тому ж каталозі, що і exe-файл програми, або в поточному каталозі,
    або в системному каталозі Windows, або в каталозі, доступному з змінної PATH
    оточення DOS. Саме в такому порядку відбувається
    пошук
    .

Приклад простий
DLL


Зауваження.
Зробимо
попередні зауваження для C + +-програмістів про
угоді мови С + + про імена функцій. Це зауваження необхідно
тому, що дуже багато бібліотек написані за допомогою різних компіляторів без
використання мови C + +, в зв’язку з чим в процесі створення cpp-проекту при
роботі з функціями цих бібліотек можуть бути проблеми.



  • Перекладачі мови С + + до
    вихідного імені функції, визначеної в тексті програми, додають символи,
    позначають типи аргументів і тип значення
    (Імена функцій розширюються). Хоча
    всі інші правила виклику функції в C ідентичні правилам виклику функцій в
    C + +, в бібліотеках C імена функцій не розширюються. До них тільки додається
    символ підкреслення.

Тому,



  • Якщо необхідно
    підключити бібліотеку на C до додатка на C + +
    , всі функції з цієї бібліотеки
    доведеться оголосити як зовнішні у форматі C. Це робиться так:
 
        extern “C” int Function(int Param);
 


  • Якщо всі функції
    бібліотеки оголошені під включається файлі MyLib.h,
    то модифікатор extern можна
    застосувати до цілого блоку, до якого за допомогою директиви # include підключений файл
    заголовків С-функцій з DLL:
 
        extern “C” 
        {
               #include “MyLib.h”
        }
 

Розглянемо тепер процес створення та використання DLL в найлегшому
варіанті
.

Наведемо вихідний код найпростішої бібліотеки динамічного
компонування, яка називається MyDLL і містить одну функцію
MyFunction, яка просто виводить повідомлення

MyDLL.h
        #define EXPORT extern “C” __declspec (dllexport)
        EXPORT int CALLBACK MyFunction(char *str);
 
MyDLL.c
        #include <windows.h>
        #include “MyDLL.h”
 
        int WINAPI DllMain(HINSTANCE hInstance, DWORD fdReason, PVOID pvReserved)
        {
               return TRUE;
        }
 
        EXPORT int CALLBACK MyFunction(char *str)
        {
               MessageBox(NULL,str,”Function from DLL”,MB_OK);
               return 1;
        }

 



  • Після трансляції та
    компонування
    цих файлів з’являються два файли –
    MyDLL.dll ( сама динамічно підключається
    Бібліотека) і MyDLL.lib ( її бібліотека
    імпорту
    ).

Звернемо увагу на те, що спочатку в заголовному файлі визначається макроконстанта
EXPORT. Вона використовується потім при оголошенні функцій DLL, які
будуть доступні додаткам, завантажити цю DLL.



  • Використання
    макроконстанти EXPORT
    (Обумовленої в заголовному файлі
    бібліотеки) при визначенні деякої функції динамічно підключається
    бібліотеці дозволяє повідомити компонувальнику, що ця
    функція доступна для використання іншими програмами, в результаті чого він
    заносить її в бібліотеку імпорту. Крім цього, така функція, точно
    так само, як і віконна процедура, повинна
    визначатися за допомогою константи CALLBACK
    .

Файл бібліотеки також
дещо відрізняється від звичайних файлів на мові C для Windows
. У файлі бібліотеки замість функції
WinMain є функція DllMain. Ця функція використовується для виконання ініціалізації, про що
буде розказано пізніше. Для того щоб бібліотека
залишилася після її завантаження в пам’яті, і можна було викликати її
функції, необхідно, щоб повертається значенням функції DllMain було
TRUE.

Перейдемо до обговорення процесу використання створеної
DLL-бібліотеки
.

Наведемо тепер вихідний код простого застосування, яке використовує функцію
MyFunction
з
бібліотеки
MyDLL.dll:

 
MyApp.c
        #include <windows.h>
        #include “MyDLL.h”
 
        int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
        {
               int iCode=MyFunction(“Hello”);
               return 0;
        }
 


  • Ця програма виглядає як звичайна
    програм для Windows, чим вона по суті і є. Проте, слід
    звернути увагу, що у вихідний текст програми
    крім виклику функції MyFunction з DLL-бібліотеки включений і заголовний файл
    цієї бібліотеки MyDLL.h.
    Також необхідно на етапі компоновки програми підключити до нього бібліотеку
    імпорту MyDLL.lib (процес неявного
    підключення DLL до виконуваного модулю).

Надзвичайно важливо розуміти, що
сам код функції MyFunction не включається в файл
MyApp.exe. Замість цього там просто є посилання на файл MyDLL.dll і посилання на функцію
MyFunction, яка знаходиться в цьому файлі. Файл MyApp.exe вимагає запуску файлу
MyDLL.dll
.

·         Заголовний файл MyDLL.h включений в
файл з вихідним текстом програми MyApp.c точно так
ж, як туди включений файл windows.h. Включення бібліотеки імпорту
MyDLL.lib для компонування аналогічно
включенню туди всіх бібліотек імпорту Windows.

·         Коли програма MyApp.exe працює,
вона підключається до бібліотеки MyDLL.dll точно так
само, як до всіх стандартних динамічно підключається бібліотекам

Windows.

Зробимо ще кілька зауважень про
властивості DLL.



  • Оскільки код модулів додатків і
    динамічно підключаються бібліотек захищений про записи, один і той же код DLL може використовуватися різними
    процесами. Однак дані, з якими
    працює DLL – для кожного процесу свої. Кожен процес має
    власний адресний простір для всіх даних, які використовує DLL.
    Поділ пам’яті між процесами вимагає, як буде
    видно далі, додаткових зусиль.


  • DLL – це не тільки розширення
    Windows, це ще й доповнення додатка, що її використовує. Все, що робить Колективна бібліотека,
    робиться від імені програми
    .
    Наприклад, власником всієї виділеної бібліотекою
    пам’яті є додаток. Власником всіх створюваних бібліотекою вікон є додаток. Власником всіх відкритих бібліотекою файлів є
    додаток.


  • Кілька програм можуть
    використовувати одну й ту ж динамічно підключається бібліотеку. Однак якщо написати спільні бібліотеки з
    функціями, які можуть викликатися з декількох потоків програми
    ,
    компілювати бібліотеку слід з такими ж опціями, як і багатопотокове додаток.

Вміст параграфа “Способи
зв’язування програми з DLL “

Розглянемо різні
способи зв’язування програми з
бібліотекою динамічної компоновки
.

Зв’язування
з DLL при завантаженні програми (неявне
підключення)

Якщо
при створенні програми, що викликає
функції DLL, використовується бібліотека
імпорту DLL

(Як зроблено в наведеному вище прикладі –
см. вихідний текст додатку MyApp), то цей спосіб
підключення DLL називається неявним
підключенням DLL. Інформація з
бібліотеки імпорту необхідна
компонувальнику для
установки таблиці посилань усередині exe-файлу,
призначеної для динамічного
зв’язуванняя.

Windows
при завантаженні програми намагається знайти
всі файли DLL, неявно підключені до
додатком
,
і помістити їх в область оперативної
пам’яті, займану даним процесом. Пошук
файлів DLL операційною системою здійснюється
в такій послідовності
:

  1. Каталог,
    в якому знаходиться EXE-файл.

  2. Поточний
    каталог процесу.

  3. Системний
    каталог Windows.

Якщо
Бібліотека DLL не виявлено,

додаток виводить діалогове вікно з
повідомленням про її відсутність і шляхи, по
яким здійснювався пошук, потім
процес припиняє свою роботу
. Якщо
Бібліотека знайдена,
вона міститься в
оперативну пам’ять процесу, де і
залишається до його закінчення. Тепер додаток
може звертатися до функцій, що містяться
в DLL
.

Динамічна
завантаження DLL в процесі роботи програми

Замість
того щоб Windows виконувала динамічне
зв’язування з DLL при першому завантаженні
програми в оперативну пам’ять,
можна зв’язати програму з модулем
бібліотеки під час виконання програми

(При такому способі в процесі створення
програми не потрібно
використовувати бібліотеку імпорту
).

·        
В
Зокрема, можна
визначити, яка з бібліотек DLL доступна
користувачеві, або дозволити користувачеві
вибрати, яка з бібліотек буде
завантажуватися. Таким чином, можна
використовувати різні DLL, в яких
реалізовані одні й ті ж функції,
виконують різні дії. Наприклад,
додаток, призначений для
незалежної передачі даних, зможе в ході
виконання прийняти рішення, завантажувати чи
DLL для протоколу TCP / IP або для іншого
протоколу.

Перше,
що необхідно зробити при динамічній
завантаженні DLL, – це помістити модуль
бібліотеки в пам’ять процесу
.
Дана операція виконується за допомогою
функції LoadLibrary,
має єдиний аргумент – ім’я
завантажуваного модуля. Відповідний
фрагмент програми повинен виглядати так:

 

        HINSTANCE hMyDll;
        . . .
        if((hMyDll=LoadLibrary(“MyDLL”))==NULL) 
        { 
                 / * не вдалося завантажити DLL * / 

        }
        else 
        { 
                 / * програма має право користуватися функціями DLL через hMyDll * / 

        }
 

  • Якщо
    файл виявлений, і бібліотека успішно
    завантажилася, функція LoadLibrary
    повертає її дескриптор,
    який використовується для доступу до
    функцій бібліотеки
    .

Розглянемо процес
пошуку файлу бібліотеки DLL операційної
системою
.

·        
Стандартним
розширенням файлу бібліотеки Windows вважає
.dll,
якщо
не вказати інше розширення. Якщо
в імені файлу вказаний і шлях, то
тільки він буде використовуватися для пошуку
файлу. В іншому випадку
Windows буде шукати файл за тією ж схемою
,
що й у випадку неявно підключених DLL,
починаючи з каталогу, з якого
завантажується exe-файл, і продовжуючи в
відповідно до значення PATH.

·        
Коли
Windows виявить файл
,
його повний
шлях буде порівняний з шляхом бібліотек DLL,
вже завантажених даним процесом. Якщо
виявиться тотожність, замість завантаження
копії програми повертається дескриптор
вже підключеної бібліотеки
.

Перейдемо
тепер рішенням проблеми
виклику функції бібліотеки, завантаженої
таким способом. Перед тим, як
використовувати функції бібліотеки, необхідно
отримати їх адресу.

Для
отримання адреси функції
спочатку
слід скористатися директивою typedef
для визначення типу функцій і визначити
змінну цього типу, наприклад:

 

        typedef int (WINAPI *PFN_MyFunction)(char *);
        . . . 
        PFN_MyFunction pfnMyFunction; 
 

Потім
слід отримати
дескриптор бібліотеки, за допомогою
якого і визначити
адреси функцій, який використовується в
Надалі для виклику функції бібліотеки:

 

        hMyDll=LoadLibrary(“MyDLL”); / / Отримання дескриптора бібліотеки
        pfnMyFunction=(PFN_MyFunction)GetProcAddress(hMyDll,”MyFunction”);
        . . .
        int iCode=(*pfnMyFunction)(“Hello”); // виклик  функції  бібліотеки  по  адресою
        . . .
 

  • Адреса
    функції
    визначається
    за допомогою функції GetProcAddress,
    їй слід передати ім’я бібліотеки і ім’я
    функції. Останнє
    має передаватися в тому вигляді, в
    якому експортується з DLL
    .

Можна
також послатися на функцію за порядковим
номером, за яким вона експортується

(При цьому для створення бібліотеки повинен
використовуватися def-файл):

 

        pfnMyFunction=(PFN_MyFunction)GetProcAddress(hMyDll, MAKEINTRESOURCE(1));

 

Коли
додаток припиняє працювати з
функціями бібліотеки, її слід видалити
з пам’яті процесу. Бібліотеку
динамічного компонування (вірніше її дані)
можна вивантажити з пам’яті процесу з
допомогою функції FreeLibrary
:

 

        FreeLibrary(hMyDll);
 

На закінчення
зазначимо таке:

З
допомогою функції LoadLibrary також можна
завантажувати в пам’ять виконувані файли (не
запускати їх на виконання!).

Дескриптор виконуваного модуля може
потім використовуватися при зверненні до
функцій FindResource і LoadResource
для пошуку і завантаження ресурсів
програми
. Вивантажують модулі з
пам’яті також за допомогою функції FreeLibrary.

Вміст параграфа “Деякі
важливі аспекти створення DLL “

 

 

Познайомившись
з принципами роботи DLL в додатках,
розглянемо докладніше деякі аспекти їх
створення.

Призначення
функції DllMain

·        
Більшість
бібліотек DLL – це просто колекції
практично незалежних один від одного
функцій, що експортуються в додатки і
використовуваних в них. Крім функцій,
призначених для експортування, можуть
бути і прості, звичайні функції. Вони
відрізняються від експортованих функцій тим,
що програма не може їх
викликати, вони для нього “невидимі”
.

Крім
цих двох типів функцій, в
кожній бібліотеці DLL є функція DllMain. Ця
функція призначена для ініціалізації і
для очищення DLL – вона обов’язково
викликається при першому запуску бібліотеки
і при завершенні її роботи. Структура
найпростішої функції DllMain може
виглядати, наприклад, так:

 

        BOOL WINAPI DllMain(HINSTANCE hDLL,DWORD dwReason,LPVOID lpReserved)
        {       
                switch(dwReason)
                {
                       case DLL_PROCESS_ATTACH:        / / ініціалізація процесу
                               break;
                       case DLL_THREAD_ATTACH:         / / ініціалізація потоку
                               break;
                        case DLL_ THREAD _DETACH:       / / очищення структур потоку
                               break;
                       case DLL_PROCESS_DETACH:        / / очищення структур процесу
                               break;
                }
                return TRUE;
}
 

·        
Першим
параметром функції DllMain
є дескриптор
модуля бібліотеки, для якого
викликається ця функція. Цей дескриптор
можна зберегти в глобальної змінної і
потім використовувати для доступу до ресурсів
модуля бібліотеки. Останній параметр
резервується системою. Параметр dwReason
може приймати одне з чотирьох значень,
що ідентифікує причину
виклику функції DllMain
операційною системою.

Зауваження.
Перед
продовженням викладу матеріалу слід
зазначити, що одна і та ж програма (додаток)
може бути завантажена кілька разів,

і її екземпляри працюють як окремі
процес.

Значення DLL_PROCESS_ATTACH
параметра dwReason означає, що динамічно
бібліотека відображена в
адресному просторі процесу. Це
сигнал бібліотеці виконати якісь
завдання по ініціалізації, які
потрібні для обслуговування наступних
запитів від процесу. Функція
DllMain динамічно підключається бібліотеки
викликається з параметром DLL_PROCESS_ATTACH тільки
один раз, при завантаженні бібліотеки в
адресний простір процесу (додатки).

·        
Будь
інший процес, що використовує ту ж
динамічно підключається бібліотеку
,
теж призводить до нового викликом
функції DllMain з параметром DLL_PROCESS_ATTACH
,
але це відбувається від імені нового процесу.

Якщо
ініціалізація проходить вдало,
повертаним значенням функції DllMain
повинно бути ненульове значення. Нульове
повертається значення призводить до того, що
Windows не завантажить бібліотеку в пам’ять.

Якщо параметр
dwReason дорівнює значенню DLL_PROCESS_DETACH,
то це означає, що динамічно
бібліотека більше процесу
не потрібна. Це дає можливість
бібліотеці звільнити займані ресурси
системи.

Аналогічно,
якщо функція DllMain
викликається з параметром DLL_THREAD_ATTACH,
це означає, що пов’язаний
з бібліотекою процес створив новий потік
.
Коли потік завершується, Windows викликає
функцію DllMain
з
параметром
DLL_THREAD_DETACH.

·        
 

Зауваження.
Слід
зазначити, що існує ймовірність того,
що виклик функції DllMain з параметром DLL_THREAD_DETACH
відбудеться без
попереднього її виклику с
параметром DLL_THREAD_ATTACH.
Це можливо в тому випадку, якщо бібліотека
була завантажена після створення
потоку.

·        
Коли
функція DllMain
викликається з параметром DLL_THREAD_DETACH,
потік ще існує. Динамічно
бібліотека може навіть
посилати повідомлення потоку в цей момент.
Але при цьому не можна
використовувати функцію PostMessage
,
оскільки потік, ймовірно, закінчиться
ще до того, як повідомлення, надіслане цієї
функцією, буде оброблено.

Отже,

Всі
операції з ініціалізації та очищення
процесів і потоків
,
яких потребує DLL, необхідно
виконувати на підставі

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*