ПЕРЕЛІК ДИСЦИПЛІН:
  • Адміністративне право
  • Арбітражний процес
  • Архітектура
  • Астрологія
  • Астрономія
  • Банківська справа
  • Безпека життєдіяльності
  • Біографії
  • Біологія
  • Біологія і хімія
  • Ботаніка та сільське гос-во
  • Бухгалтерський облік і аудит
  • Валютні відносини
  • Ветеринарія
  • Військова кафедра
  • Географія
  • Геодезія
  • Геологія
  • Етика
  • Держава і право
  • Цивільне право і процес
  • Діловодство
  • Гроші та кредит
  • Природничі науки
  • Журналістика
  • Екологія
  • Видавнича справа та поліграфія
  • Інвестиції
  • Іноземна мова
  • Інформатика
  • Інформатика, програмування
  • Юрист по наследству
  • Історичні особистості
  • Історія
  • Історія техніки
  • Кибернетика
  • Комунікації і зв'язок
  • Комп'ютерні науки
  • Косметологія
  • Короткий зміст творів
  • Криміналістика
  • Кримінологія
  • Криптология
  • Кулінарія
  • Культура і мистецтво
  • Культурологія
  • Російська література
  • Література і російська мова
  • Логіка
  • Логістика
  • Маркетинг
  • Математика
  • Медицина, здоров'я
  • Медичні науки
  • Міжнародне публічне право
  • Міжнародне приватне право
  • Міжнародні відносини
  • Менеджмент
  • Металургія
  • Москвоведение
  • Мовознавство
  • Музика
  • Муніципальне право
  • Податки, оподаткування
  •  
    Бесплатные рефераты
     

     

     

     

     

     

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

     

    Інформатика, програмування

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

    Андрій Уваров

    З самого народження (або трохи пізніше) операційна система Windows використовувала бібліотеки динамічного компонування DLL (Dynamic Link Library), в яких містилися реалізації найбільш часто вживаних функцій. Спадкоємці Windows - NT і Windows 95, а також OS/2 - теж залежать від бібліотек DLL в плані забезпечення значної частини їх функціональних можливостей.

    Розглянемо ряд аспектів створення і використання бібліотек DLL:

    як статично підключати бібліотеки DLL;

    як динамічно завантажувати бібліотеки DLL;

    як створювати бібліотеки DLL;

    як створювати розширення МFC бібліотек DLL.

    Використання DLL

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

    Взагалі кажучи, DLL - це просто набори функцій, зібрані в бібліотеки. Однак, на відміну від своїх статичних родичів (файлів. lib), бібліотеки DLL не приєднають безпосередньо до виконуваних файлів за допомогою редактора зв'язків. У виконуваний файл занесена тільки інформація про їхнє місцезнаходження. У момент виконання програми завантажується вся бібліотека цілком. Завдяки цьому різні процеси можуть користуватися спільно одними і тими ж бібліотеками, що знаходяться в пам'яті. Такий підхід дозволяє скоротити обсяг пам'яті, необхідний для декількох додатків, що використовують багато спільних бібліотек, а також контролювати розміри ЕХЕ-файлів.

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

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

    Бібліотеки імпортування

    При статичному підключенні DLL ім'я. lib-файлу визначається серед інших параметрів редактора зв'язків у командному рядку або на вкладці "Link" діалогового вікна "Project Settings" середовища Developer Studio. Однак. Lib-файл, що використовується при підключенні неявному DLL, -- це не звичайна статична бібліотека. Такі. Lib-файли називаються бібліотеками імпортування (import libraries). У них міститься не сам код бібліотеки, а тільки посилання на всі функції, що експортуються з файлу DLL, в якому все і зберігається. У результаті бібліотеки імпортування, як правило, мають менший розмір, ніж DLL-файли. До способів їх створення повернемося пізніше. А зараз розглянемо інші питання, що стосуються неявного підключення динамічних бібліотек.

    Узгодження інтерфейсів

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

    Якби світ був досконалий, то програмістом не довелося б турбуватися про узгодження інтерфейсів функцій при підключенні бібліотек - всі вони були б однаковими. Проте світ далекий від досконалості, і багато великі програми написані за допомогою різних бібліотек без C ++.

    За умовчанням в Visual C + + інтерфейси функцій узгоджуються за правилами C + +. Це означає, що параметри заносяться в стек справа наліво, що викликає програма відповідає за їх видалення з стека при виході з функції і розширення її імені. Розширення імен (name mangling) дозволяє редактору зв'язків розрізняти перевантажені функції, тобто функції з однаковими іменами, але різними списками аргументів. Однак у старій бібліотеці З функції з розширеними іменами відсутні.

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

    Якщо необхідно підключити бібліотеку на С до додатка на C + +, всі функції з цієї бібліотеки доведеться оголосити як зовнішні у форматі С:

    extern "З" int MyOldCFunction (int myParam);

    Оголошення функцій бібліотеки зазвичай містяться в фото заголовка цієї бібліотеки, хоча заголовки більшості бібліотек С не розраховані на застосування в проектах на C + +. У цьому випадку необхідно створити копію файлу заголовка і включити в неї модифікатор extern "C" до оголошенню всіх використовуваних функцій бібліотеки. Модифікатор extern "C" можна застосувати і до цілого блоку, до якого за допомогою директиви # tinclude приєднаний файл старого заголовка С. Таким чином, замість модифікації кожної функції окремо можна обійтися всього трьома рядками:

    extern "З"

    (

    # include "MyCLib.h"

    )

    У програмах для старих версій Windows використовувалися також угоди про виклик функцій мови PASCAL для функцій Windows API. У нових програмах слід використовувати модифікатор winapi, перетворений в _stdcall. Хоча це й не стандартний інтерфейс функцій С або C + +, але саме він використовується для звернень до функцій Windows API. Проте зазвичай все це вже враховано в стандартних заголовках Windows.

    Завантаження неявно підключається DLL

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

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

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

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

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

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

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

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

    Завантаження звичайній DLL

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

    HINSTANCE hMyDll;

    ::

    if ((hMyDll =:: LoadLibrary ( "MyDLL "))== NULL) (/ * не вдалося завантажити DLL * /)

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

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

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

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

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

    // тип PFN_MyFunction буде оголошувати покажчик на функцію,

    // приймаючу покажчик на символьний буфер і видає значення типу int

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

    ::

    PFN_MyFunction pfnMyFunction;

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

    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);

    Завантаження MFC-розширень динамічних бібліотек

    При завантаженні MFC-розширень для DLL (докладно про яких розповідається далі) замість функцій LoadLibraryі FreeLibrary використовуються функції AfxLoadLibrary і AfxFreeLibrary. Останні майже ідентичні функцій Win32 API. Вони лише гарантують додатково, що структури MFC, початкові розширенням DLL, не були запорчени іншими потоками.

    Ресурси DLL

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

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

    Приклад звичайної DLL і способів завантаження

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

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

    MyDLL.h

    # define EXPORT extern "C" __declspec (dllexport)

    EXPORT int CALLBACK MyFunction (char * str);

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

    MyDLL.c

    # include

    # 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 (її бібліотека імпорту).

    Приклад неявного підключення DLL додатком

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

    # include

    # 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 додатком

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

    # include

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

    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

    LPSTR lpCmdLine, int nCmdShow)

    (

    HINSTANCE hMyDll;

    if ((hMyDll = LoadLibrary ( "MyDLL "))== NULL) return 1;

    PFN_MyFunction pfnMyFunction;

    pfnMyFunction = (PFN_MyFunction) GetProcAddress (hMyDll, "MyFunction ");

    int iCode = (* pfnMyFunction) ( "Hello ");

    FreeLibrary (hMyDll);

    return 0;

    )

    Створення DLL

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

    Найпростіше створити новий проект DLL за допомогою майстра AppWizard, який автоматично виконує багато операцій. Для простих DLL, таких як розглянуті в цьому розділі, необхідно вибрати тип проекту Win32 Dynamic-Link Library. Нового проекту будуть присвоєні всі необхідні параметри для створення бібліотеки DLL. Файли вихідних текстів доведеться додавати до проекту вручну.

    Якщо ж планується повною мірою використовувати функціональні можливості MFC, такі як документи та подання, або мають намір створити сервер автоматизації OLE, краще вибрати тип проекту MFC AppWizard (dll). У цьому випадку, крім присвоєння проекту параметрів для підключення динамічних бібліотек, майстер виконає деяку додаткову роботу. У проект будуть додані необхідні посилання на бібліотеки MFC та файли вихідних текстів, що містять опис і реалізацію в бібліотеці DLL об'єкта класу програми, похідного від CWinApp.

    Іноді зручно спочатку створити проект типу MFC AppWizard (dll) в якості тестового програми, а потім - бібліотеку DLL в вигляді його складової частини. У результаті DLL у разі необхідності буде створюватися автоматично.

    Функція DllMain

    Більшість бібліотек DLL - просто колекції практично незалежних один від одного функцій, що експортуються до програми та що використовуються в них. Окрім функцій, призначених для експортування, кожній бібліотеці DLL є функція DllMain. Ця функція призначена для ініціалізації та очищення DLL. Вона прийшла на зміну функцій LibMain і WEP, що застосовувався в попередніх версіях Windows. Структура найпростішої функції DllMain може виглядати, наприклад, так:

    BOOL WINAPI DllMain (HANDLE hInst, DWORD dwReason, LPVOID IpReserved)

    (

    BOOL bAllWentWell = TRUE;

    switch (dwReason)

    (

    case DLL_PROCESS_ATTACH:// Ініціалізація процесу.

    break;

    case DLL_THREAD_ATTACH:// Ініціалізація потоку.

    break;

    case DLL_THREAD_DETACH:// Очищення структур потоку.

    break;

    case DLL_PROCESS_DETACH:// Очищення структур процесу.

    break;

    )

    if (bAllWentWell) return TRUE;

    else return FALSE;

    )

    Функція DllMain викликається в кількох випадках. Причина її виклику визначається параметром dwReason, який може приймати одне з наступних значень.

    При першому завантаженні бібліотеки DLL процесом викликається функція DllMain з dwReason, рівним DLL_PROCESS_ATTACH. Кожного разу при створенні процесом нового потоку DllMainO викликається з dwReason, рівним DLL_THREAD_ATTACH (крім першого потоку, тому що в цьому слу?? ае dwReason дорівнює DLL_PROCESS_ATTACH).

    По закінченні роботи процесу з DLL функція DllMain викликається з параметром dwReason, рівним DLL_PROCESS_DETACH. При знищенні потоку (крім першого) dwReason буде дорівнює DLL_THREAD_DETACH.

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

    До складу DLL можуть входити ресурси, які не належать що викликає цю бібліотеку з додатком. Якщо функції DLL працюють з ресурсами DLL, було б, очевидно, корисно зберегти де-небудь в затишному місці дескриптор hInst і використовувати його при завантаженні ресурсів з DLL. Покажчик IpReserved зарезервований для внутрішнього використання Windows. Отже, програма не має претендувати на нього. Можна лише перевірити його значення. Якщо бібліотека DLL була завантажена динамічно, воно буде дорівнює NULL. При статичної завантаженні цей покажчик буде ненульовим.

    У разі успішного завершення функція DllMain повинна повертати TRUE. У разі виникнення помилки повертається FALSE, і подальші дії припиняються.

    Зауваження. Якщо не написати власної функції DllMain (), компілятор підключить стандартну версію, яка просто повертає TRUE.

    Експорт функцій з DLL

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

    Метод __declspec (dllexport)

    Можна експортувати функцію з DLL, поставивши на початку її опису модифікатор __declspec (dllexport). Крім того, до складу MFC входить кілька макросів, що визначають __declspec (dllexport), у тому числі AFX_CLASS_EXPORT, AFX_DATA_EXPORT і AFX_API_EXPORT.

    Метод __declspec застосовується не так часто, як друга метод, який працює з файлами визначення модуля (. def), і дозволяє краще керувати процесом експортування.

    Файли визначення модуля

    Синтаксис файлів з розширенням. def в Visual C + + досить прямолінійний, головним чином тому, що складні параметри, що використовувалися в попередніх версіях Windows, в Win32 більше не застосовуються. Як стане зрозуміло з такого простого прикладу,. def-файл містить назву та опис бібліотеки, а також список експортованих функцій:

    MyDLL.def

    LIBRARY "MyDLL"

    DESCRIPTION 'MyDLL - приклад DLL-бібліотеки'

    EXPORTS

    MyFunction @ 1

    У рядку експорту функції можна вказати її порядковий номер, поставивши перед ним символ @. Цей номер буде потім використовуватися при зверненні до GetProcAddress (). Насправді компілятор присвоює порядкові номери всім експортним об'єктам. Однак спосіб, яким він це робить, почасти непередбачуваний, якщо не привласнити ці номери явно.

    У рядку експорту можна використовувати параметр NONAME. Він забороняє компілятору включати ім'я функції в таблицю експортування DLL:

    MyFunction @ 1 NONAME

    Іноді це дозволяє заощадити багато місця у файлі DLL. Програми, що використовують бібліотеку імпортування для неявного підключення DLL, не "помітять" різниці, оскільки при неявному підключенні порядкові номери використовуються автоматично. Додатків, файли бібліотеки DLL динамічно, буде потрібно передавати в GetProcAddress порядковий номер, а не ім'я функції.

    При використанні вищенаведеного def-файл опису експортованих функцій DLL-бібліотеки може бути, наприклад, не таким:

    # define EXPORT extern "C" __declspec (dllexport)

    EXPORT int CALLBACK MyFunction (char * str);

    a таким:

    extern "C" int CALLBACK MyFunction (char * str);

    Експорт класів

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

    Якщо поглянути на реалізований в класі файл розподілу пам'яті, в ньому можна помітити деякі досить незвичайні функції. Виявляється, тут є неявні конструктори і деструктори, функції, оголошені в макросах MFC, зокрема _DECLARE_MESSAGE_MAP, а також функції, які написані програмістом.

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

    Пам'ять DLL

    На відміну від статичних бібліотек, які, на суті, стають частиною коду програми, бібліотеки динамічного компонування в 16-розрядних версіях Windows працювали з пам'яттю трохи інакше. Під управлінням Win 16 пам'ять DLL розміщувалася поза адресного простору завдання. Розміщення динамічних бібліотек у глобальній пам'яті забезпечувало можливість спільного використання їх різними завданнями.

    У Win32 бібліотека DLL розташовується в області пам'яті завантажують її процесу. Кожному процесу надається окрема копія "глобальної" пам'яті DLL, яка реініціалізіруется кожного разу, коли її завантажує новий процес. Це означає, що динамічна бібліотека не може використовуватися спільно, в загальній пам'яті, як це було в Winl6.

    І все ж, виконавши ряд хитромудрих маніпуляцій над сегментом даних DLL, можна створити загальну область пам'яті для всіх процесів, що використовують дану бібліотеку.

    Припустимо, є масив цілих чисел, який повинен використовуватися всіма процесами, які завантажили дану DLL. Це можна запрограмувати таким чином:

    # pragma data_seg ( ". myseg")

    int sharedlnts [10];

    // інші змінні загального користування

    # pragma data_seg ()

    # pragma comment (lib, "msvcrt" "-SECTION:. Myseg, rws ");

    Всі змінні, оголошені між директивами # pragma data_seg (), розміщуються в сегменті. myseg. Директива # pragma comment () - не звичайний коментар. Вона дає вказівку бібліотеці виконує системи С позначити новий розділ як дозволений для читання, запису і спільного доступу.

    Повна компіляція DLL

    Якщо проект динамічної бібліотеки створений за допомогою AppWizard і. Def-файл модифікований відповідним чином - цього достатньо. Якщо ж файли проекту створюються вручну або іншими способами без допомоги AppWizard, в командний рядок редактора зв'язків слід включити параметр/DLL. У результаті замість автономного виконуваного файлу буде створена бібліотека DLL.

    Якщо в. def-файлі є рядок LIBRART, вказувати явно параметр/DLL в командному рядку редактора зв'язків не потрібно.

    Для MFC передбачено низку особливих режимів, що стосуються використання динамічної бібліотекою бібліотек MFC. Цьому питанню присвячений наступний розділ.

    DLL і MFC

    Програміст не зобов'язаний використовувати MFC при створенні динамічних бібліотек. Проте використання MFC відкриває ряд дуже важливих можливостей.

    Є два рівня використання структури MFC в DLL. Перший з них - це звичайна динамічна бібліотека на основі MFC, MFC DLL (regular MFC DLL). Вона може використовувати MFC, але не може передавати покажчики на об'єкти MFC між DLL і додатками. Другий рівень реалізований в динамічних розширеннях MFC (MFC extensions DLL). Використання цього виду динамічних бібліотек вимагає деяких додаткових зусиль по настройці, але дозволяє вільно обмінюватися покажчиками на об'єкти MFC між DLL і додатком.

    Звичайні MFC DLL

    Звичайні MFC DLL дозволяють застосовувати MFC в динамічних бібліотеках. При цьому додатки, які звертаються до таких бібліотекам, не обов'язково повинні бути побудовані на основі MFC. У звичайних DLL можна використовувати MFC будь-яким способом, у тому числі створюючи в DLL нові класи на базі класів MFC та їх експортом в додатки.

    Однак звичайні DLL не можуть обмінюватися з додатками покажчиками на класи, похідні від MFC.

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

    Архітектура звичайних DLL розрахована на використання іншими середовищами програмування, такими як Visual Basic і PowerBuilder.

    При створенні звичайної бібліотеки MFC DLL за допомогою AppWizard вибирається новий проект типу MFC AppWizard (dll). У першому діалоговому вікні майстра додатків необхідно вибрати один з режимів для звичайних динамічних бібліотек: "Regular DLL with MFC statistically linked" або "Regular DLL using shared MFC DLL". Перший передбачає статичне, а другий - динамічне підключення бібліотек MFC. Згодом режим підключення до MFC DLL можна буде змінити за допомогою комбінованого списку на вкладці "General" діалогового вікна "Project settings ".

    Управління інформацією про стан MFC

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

    AFX_MANAGE_STATE (AfxGetStaticModuleState ());

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

    Динамічні розширення MFC

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

    Щоб забезпечити можливість вільного обміну покажчиками на об'єкти MFC між програмою і DLL, потрібно створити динамічне розширення MFC. DLL цього типу підключаються до динамічних бібліотек MFC так само, як і будь-які додатки, що використовують динамічне розширення MFC.

    Щоб створити нове динамічне розширення MFC, простіше за все, скориставшись майстром додатку, привласнити проекту тип MFC AppWizard (dll) і на кроці 1 включити режим "MFC Extension DLL". У результаті новому проекту будуть присвоєні всі необхідні атрибути динамічного розширення MFC. Крім того, буде створена функція DllMain для DLL, що виконує ряд специфічних операцій з ініціалізації розширення DLL. Слід звернути увагу, що динамічні бібліотеки даного типу не містять і не повинні містити об'єктів, похідних від CWinApp.

    Ініціалізація динамічних розширень

    Щоб "вписатися" в структуру MFC, динамічні розширення MFC вимагають додаткової початкової настройки. Відповідні операції виконуються функцією DllMain. Розглянемо приклад цієї функції, створений майстром AppWizard.

    static AFX_EXTENSION_MODULE MyExtDLL = (NULL, NULL);

    extern "C" int APIENTRY

    DllMain (HINSTANCE hinstance, DWORD dwReason, LPVOID IpReserved)

    (

    if (dwReason == DLL_PROCESS_ATTACH)

    (

    TRACED ( "MYEXT.DLL Initializing! N ");

    // Extension DLL one-time initialization

    AfxInitExtensionModule (MyExtDLL, hinstance);

    // Insert this DLL into the resource chain

    new CDynLinkLibrary (MyExtDLL);

    )

    else if (dwReason == DLL_PROCESS_DETACH)

    (

    TRACED ( "MYEXT.DLL Terminating! N ");

    )

    return 1; //Ok

    )

    Найважливішою частиною цієї функції є виклик AfxInitExtensionModule. Це ініціалізація динамічної бібліотеки, що дозволяє їй коректно працювати у складі структури MFC. Аргументами даної функції є передається в DllMain дескриптор бібліотеки DLL і структура AFX_EXTENSION_MODULE, що містить інформацію про підключається до MFC динамічної бібліотеці.

    Немає необхідності ініціалізувати структуру AFX_EXTENSION_MODULE явно. Однак оголосити її треба обов'язково. Ініціалізацією ж займеться конструктор CDynLinkLibrary. У DLL необхідно створити клас CDynLinkLibrary. Його конструктор не тільки буде ініціалізувати структуру AFX_EXTENSION_MODULE, але і додасть нову бібліотеку в список DLL, з якими може працювати MFC.

    Завантаження динамічних розширень MFC

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

    if (dwReason == DLL_PROCESS_DETACH)

    (

    AfxTermExtensionModule (MyExtDLL);

    )

    Крім того, слід пам'ятати, що нова бібліотека DLL є динамічним розширенням і повинна завантажуватися і розвантажуватися динамічно, за допомогою функцій AfxLoadLibrary і AfxFreeLibrary, а не LoadLibrary і FreeLibrary.

    Експорт функцій з динамічних розширень

    Розглянемо тепер, як здійснюється експортування в додаток функцій і класів з динамічного розширення. Хоча додати DEF-файл всі додаткові імена можна і вручну, краще використовувати модифікатори для оголошень експортованих класів і функцій, такі як AFX_EXT_CLASS і AFX_EXT_API, наприклад:

    class AFX_EXT_CLASS CMyClass: public CObject

    (

    // Your class declaration

    )

    void AFX_EXT_API MyFunc ();

    Список літератури

    Для підготовки даної роботи були використані матеріали з сайту http://www.realcoding.net/

         
     
         
    Реферат Банк
     
    Рефераты
     
    Бесплатные рефераты
     

     

     

     

     

     

     

     
     
     
      Все права защищены. Reff.net.ua - українські реферати ! DMCA.com Protection Status