TN033: DLL Версія MFC

Цієї записці описується, як можна використовувати в MFCxx.DLL та MFCxxD.DLL (де x є номером версії MFC) спільні бібліотеки динамічного компонування MFC програм та розширенням DLL. Щоб отримати додаткові відомості про регулярні DLL перегляньте Використання MFC як частину DLL.

Ця технічна Примітка охоплює три аспекти DLL. Останні два є для більш досвідчених користувачів:

Якщо ви зацікавлені у створенні DLL, що використання MFC, які можуть бути використані з додатками не MFC (це називається регулярні DLL), зверніться до технічної Примітка 11.

Огляд MFCxx.DLL підтримка: термінології та файли

Регулярні DLL: ви використовуєте регулярно DLL побудувати автономний DLL, що використання деяких MFC класів. Інтерфейси через App/DLL межі є інтерфейси "С", і клієнтський застосунок не має бути MFC програми.

Це версія DLL підтримки у MFC 1.0. Це описано в технічних Примітка 11 і MFC передові концепції зразок DLLTRACE.

Примітка   Станом на Visual C++ версії 4.0, термін USRDLL є застарілою і було замінено на регулярній DLL, яка статично MFC. Ви будуєте регулярні DLL, яка динамічно MFC.

MFC 3.0 (і вище) підтримує регулярні DLL з нової функціональності, у тому числі класи OLE і бази даних.

AFXDLL: це також називають Версія MFC бібліотек. Це нова DLL підтримки додав у MFC 2.0. Самої бібліотеки MFC є в ряді бібліотек (див. нижче), і клієнтський застосунок або DLL динамічно посилання DLL, що вона потребує. Інтерфейси через застосування/DLL межі є C + + / MFC клас інтерфейсів. Клієнтський застосунок має бути MFC програми. Це підтримує всі функції MFC 3.0 (excption: ЮНІКОД не підтримується для класів бази даних).

Примітка   Станом на Visual c + + версії 4.0 цей тип DLL називають "Розширенням DLL."

Ця Примітка буде використовувати MFCxx.DLL для посилання на весь MFC DLL набір, який включає в себе:

Примітка   На MFCSxx [U] [D].LIB бібліотеки що використовуються в поєднанні з MFC спільні бібліотеки DLL. Ці бібліотеки містять код, що повинна бути статично пов'язана програми або DLL.

До застосування посилання на відповідні імпортувати бібліотеки:

В "MFC розширенням DLL" є DLL, побудований на MFCxx.DLL (та/або інші MFC спільні бібліотеки DLL). Тут в ногу MFC архітектурі компонентів. Якщо отримати корисні клас з MFC-клас, або створити інший інструментарій MFC, як, ви можете розмістити в DLL. Що DLL використовує MFCxx.DLL, як це робить у кінцева клієнтського застосунку. Це дозволяє багаторазові листя класи, багаторазові базових класів і класи багаторазовий перегляд документа.

Приміткаnbsp;  Це не є необхідним, щоб зв'язок з MFCOxx [U] D, D MFCDxx [U] або [U] MFC&Nxx D налагодження бібліотеки, якщо ваш застосування використовує MFC/OLE, бази даних або мережі класи відповідно.

Плюси і мінуси

Чому ви повинні використовувати Версія MFC?

Чому ви не повинні використовувати Версія MFC:

Як написати MFC розширення DLL

У MFC розширенням DLL є DLL, що містять класи та функції, написана, щоб прикрасити функціональність MFC класів. Підтримка OLE і бази даних налагодження DLL (MFCOxxD.DLL та MFCDxxD.DLL) є прикладами MFC розширенням DLL, в тому, що вони використовують MFCxxD.DLL. У MFC розширенням DLL використовує спільні бібліотеки DLL MFC таким же чином, що програма використовує його, з деякими додатковими зауваженнями:

Ці міркування описані більш докладно нижче. Ви повинні також послатися на зразок MFC передові концепції DLLHUSK , оскільки вона ілюструє

Клієнтський застосунок і будь-який розширенням DLL повинні використовувати ту ж версію MFCxx.DLL. Ви повинні слідувати конвенції MFC DLL і забезпечити як налагодження та роздрібна (/ звільнити) Версія вашого розширення DLL. Це дозволяє клієнтські програми побудувати налагодження і роздрібні версії свої програми і пов'язати їх з відповідної налагодження або роздрібної версії всіх DLL.

Примітка   Завдяки C++ ім'я mangling і експорт питання Експорт списку з розширенням DLL можуть відрізнятися від налагодження і роздрібні версії бібліотеці DLL до бібліотек для різних платформ. Роздрібна торгівля MFCxx.DLL має близько 2000 експортовані точки входу; налагодження MFCxxD.DLL має близько 3000 експортовані точки входу.

Швидкий відомості про керування пам'яттю

Розділі під назвою "Керування пам'яттю," в кінці цього технічну записку, описано виконання на MFCxx.DLL з Версія MFC. Нижче описано інформацію, вам необхідно знати для здійснення просто розширенням DLL.

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

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

Аналогічним чином інші "Глобальний" MFC держави, як поточний виконуваний файл для завантаження ресурсів, також спільних клієнтського застосунку та всі MFC розширенням DLL а також MFCxx.DLL, сам.

Створення розширень DLL

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

Якщо перетворення існуючого проекту MFC розширення DLL, почати з стандартні правила для побудови програму за допомогою Версія MFC, а потім виконайте такі дії:

Зміна заголовні файли

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

Для цього необхідно переконатися, що кожен член функцій буде позначено як імпортувати або експортувати як відповідні. Це вимагає спеціальних декларації: __declspec(dllexport) і __declspec(dllimport). Коли ваші класи використовуються на клієнтських застосунків, ви хочете бути визнано __declspec(dllimport). Коли це будується розширенням DLL, сама по собі, вони повинні бути оголошені як __declspec(dllexport). Крім того, функції повинні бути фактично експортувала, так що клієнтські програми приєднується до них на час завантаження.

Щоб експортувати весь клас, використання AFX_EXT_CLASS у визначенні класу. Цей макрос визначається рамках як __declspec(dllexport) при _AFXDLL і _AFXEXT визначено, але визначається як __declspec(dllimport) , якщо _AFXEXT не визначено. _AFXEXT як описано вище, тільки визначається при побудові вашого розширення DLL. Наприклад:

клас AFX_EXT_CLASS CExampleExport: Громадська CObject
{... клас визначення...}

Не експортувати весь клас

Іноді може знадобитися експортувати тільки окремі необхідні членів вашого класу. Наприклад, якщо експортуєте CDialog-отриманих клас, тільки потрібно експортувати Конструктор і DoModal дзвінка. Ви можете експортувати ці члени використання в DLL.DEF файл, але ви також можете використовувати AFX_EXT_CLASS багато так само, як на окремих членів, які потрібно експортувати.

Наприклад:

 клас CExampleDialog: Громадська CDialog
{
готелю:
   AFX_EXT_CLASS CExampleDialog();
   AFX_EXT_CLASS int DoModal();
   / / відпочинок класу визначення
   .
   .
   .
}

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

Наприклад, DECLARE_DYNAMIC макрос визначається таким чином при створенні розширенням DLL:

# визначити DECLARE_DY&NAMIC(class_name) \
Охоронювані: \
 nbsp; статичний CRuntimeClass * ПАСКАЛЬ _GetBaseClass(); \
   Громадська: \
   статичного класу AFX_DATA CRuntimeClass # # class_name; \
   Віртуальний CRuntimeClass * GetRuntimeClass() константа; \

Рядок, що починається з "статичними AFX_DATA" декларує статичний об'єкт всередині, з вашого класу. Щоб експортувати цей клас правильно і доступ до виконання даних від клієнта.EXE, потрібно експортувати цей статичний об'єкт. Оскільки статичний об'єкт оголошується з службову AFX_DATA, потрібно тільки визначити AFX_DATA бути __declspec(dllexport) при побудові вашого DLL і визначити його як __declspec(dllimport) при побудові вашого клієнта виконуваний.

Як зазначено вище, AFX_EXT_CLASS вже визначено таким чином. Так вам просто потрібно повторно визначити AFX_DATA буде так само, як AFX_EXT_CLASS навколо вашого класу визначення.

Наприклад:

nbsp;  #undef AFX_DATA
   # визначити AFX_DATA AFX_EXT_CLASS
   клас CExampleView: Громадська CView
   {
     DECLARE_DY&NAMIC()
     / /... клас визначення...
   };
   #undef AFX_DATA
   # визначити AFX_DATA

MFC завжди використовує символ AFX_DATA елементів даних визначає в межах його макроси, так що цей метод буде працювати для всіх таких сценаріїв. Наприклад, він буде працювати для DECLARE_MESSAGE_MAP.

Примітка   Якщо ви експортуєте весь клас, а не виділеного членів класу, статичні дані членів буде автоматично експортовано.

Можна використовувати ту ж техніку, автоматично експортувати CArchive видобутку оператора для класів, що макроси DECLARE_SERIAL і IMPLEMENT_SERIAL . Експорт оператора архіву на брекетинга визначення класів (-одна з місцевих громад, що розташована в регіоні.H-файл) з наступний код:

#undef AFX_API
# визначити AFX_API AFX_EXT_CLASS

lt; визначення класів тут >

#undef AFX_API
# визначити AFX_API

Обмеження _AFXEXT

AFXEXT _ pre-processor символ можна використовувати для вашого розширення DLL до тих пір, поки ви не маєте декілька шарів розширенням DLL. У вас є розширенням DLL, яка зателефонувати або отримати з класів у власні розширення DLL, яка потім отримати з MFC класи, потрібно використовувати ваш власний препроцесора символ уникнути двозначності.

Проблема в тому, що в Win32, ви повинні чітко заявити будь-які дані як __declspec(dllexport) якщо це експортуватися з DLL і __declspec(dllimport) , якщо він буде імпортовано з DLL. Коли ви визначаєте _AFXEXT, заголовки MFC переконайтеся, що визначено AFX_EXT_CLASS.

Коли у вас є декілька шарів, один символ, наприклад, AFX_EXT_CLASS недостатньо, оскільки розширенням DLL можуть бути експорт нові класи як Імпорт інші класи з іншим розширенням DLL. Для вирішення цієї проблеми, використовують pre-processor спеціальний символ, який означає, що ви будуєте DLL, сама проти використання DLL. Наприклад, припустімо, що два розширення DLL, A.DLL і B.DLL. Кожен з них експортувати деякі класи в A.H та B.H, відповідно. B.DLL використовує класи з A.DLL. Заголовні файли буде виглядати приблизно так:

/ / A.H
#IFDEF A_IMPL
   # визначити CLASS_DECL_A __declspec(dllexport)
# інше
   # визначити CLASS_DECL_A __declspec(dllimport)
#endif

клас CLASS_DECL_A CExampleA: Громадська CObject
{... клас визначення...};

/ / B.H
#IFDEF B_IMPL
   # визначити CLASS_DECL_B __declspec(dllexport)
# інше
   # визначити CLASS_DECL_B __declspec(dllimport)
#endif

клас CLASS_DECL_B CExampleB: Громадська CExampleA
{... клас визначення...}

Під побудований A.DLL, вона побудована з /D A_IMPL і під побудований B.DLL, вона побудована з параметр B_IMPL. За допомогою окремі символи для кожного DLL, експортується CExampleB і CExampleA буде імпортовано при створенні B.DLL. CExampleA експорту, коли будівля A.DLL і імпортовано під час використання B.DLL (або деякі інші клієнт).

Цей тип розшарування не може бути зроблено під час використання вбудованих AFX_EXT_CLASS і _AFXEXT pre-processor символів. Методика, описана вище вирішує цю проблему таким чином, не на відміну від механізм MFC, сама використовує при створенні її OLE, бази даних і мережі розширення DLL.

Не експортувати весь клас

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

Наприклад:

/ / A.H
#IFDEF A_IMPL
 nbsp; # визначити CLASS_DECL_A _declspec(dllexport)
# інше
   # визначити CLASS_DECL_A _declspec(dllimport)
   #endif

#undef AFX_DATA
# визначити AFX_DATA CLASS_DECL_A

клас CExampleA: Громадська CObject
{
   DECLARE_DY&NAMIC()
   CLASS_DECL_A int SomeFunction();
   //Class. визначення.
   .
   .
};

#undef AFX_DATA
# визначити AFX_DATA

DllMain

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

# включити "afxdllx.h"

статичний AFX_EXTE&NSION_MODULE extensionDLL;

зовнішній "С" int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
 nbsp; Якщо (dwReason = = DLL_PROCESS_ATTACH)
   {
      / / Розширення DLL одноразова ініціалізації якщо (!AfxInitExtensionModule (
             extensionDLL, hInstance))
         повертає 0;

/ / TODO: інших завдань ініціалізації тут
   }
   Якщо інше (dwReason = = DLL_PROCESS_DETACH)
   {
      / / Розширення DLL в процесі припинення
      AfxTermExtensionModule(extensionDLL);

/ / TODO: інших завдань очищення тут
   }
   повернення 1;   / / ok
}

Заклик до AfxInitExtensionModule захоплює модулі runtime класи (CRuntimeClass структури) а також заводах об'єкт (COleObjectFactory об'єктів) для подальшого використання, коли створюється об'єкт CDynLinkLibrary . (Необов'язково) виклик AfxTermExtensionModule дозволяє MFC очищення розширенням DLL коли відокремлює кожен процес, (який буває, коли процес виходів, або DLL вивантажений з FreeLibrary дзвінка) з розширенням. DLL. Оскільки більшість розширенням DLL не динамічно завантажуються (як правило, вони пов'язані через їх Імпорт бібліотеки), дзвінок на AfxTermExtensionModule як правило не є необхідним.

Якщо ваша заявка навантажень і звільняє розширенням DLL динамічно, обов'язково викличте AfxTermExte&nsionModule , як показано на малюнку above.nbsp; Крім того, не забудьте використовувати AfxLoadLibrary і AfxFreeLibrary (замість Win32 функції, LoadLibrary і FreeLibrary) Якщо ваше додаток використовує декілька потоків. За допомогою AfxLoadLibrary і AfxFreeLibrary гарантує, що запуск і завершення код, який виконує коли розширення DLL завантаження або відключення не корумповані глобального MFC держави.

Заголовний файл AFXDLLX.H містить спеціальні defintions для структури, що використовуються в розширення DLL, наприклад, визначення для AFX_EXTENSION_MODULE і CDynLinkLibrary.

Глобальна extensionDLL має бути оголошено, як показано на малюнку. На відміну від 16-розрядна версія MFC ви можете виділити пам'ять і викликати MFC функції протягом цього часу, оскільки коли ваш DllMain називається повністю ініціалізується на MFCxx.DLL.

Спільний доступ до ресурсів і класи

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

Експорт ресурсів зробили це за допомогою списку ресурсів. У кожної програми це окремо зв'язаного списку об'єктів, CDynLinkLibrary . При пошуку ресурсів, більшість стандартних MFC реалізацій, що навантаження ресурсів, подивіться спочатку у поточному модуль ресурсів (AfxGetResourceHandle) і якщо не знайдено Прогулянка список CDynLinkLibrary об'єктів, спроба завантаження запитаного ресурсу.

Аналогічна динамічного створення об'єктів C++, дав ім'я класу C++. MFC об'єкт deserialization механізм повинен мати всі CRuntimeClass об'єкти, зареєстровані, так що він може відновити динамічно створюючи C++ об'єкт необхідні типу, засновані на те, що зберігалася раніше.

Якщо ви хочете, щоб до клієнтського застосунку для використання класів у ваше розширення DLL, які DECLARE_SERIAL, то вам буде потрібно експортувати ваші класи, щоб бути видно до клієнтського додатка. Це робиться ходьба список CDynLinkLibrary.

У випадку з MFC передові концепції зразок DLLHUSK, список виглядає приблизно так

голова - >   DLLHUSK.EXE - або - DLLHUSK.EXE
               |                      |
          TESTDLL2.БІБЛІОТЕКА DLL TESTDLL2.БІБЛІОТЕКА DLL
               |                      |
          TESTDLL1.БІБЛІОТЕКА DLL TESTDLL1.БІБЛІОТЕКА DLL
               |                      |
           MFCO42D.DLL                |
               |                      |
           MFCD42D.DLL                |
               |                      |
            MFC42D.БІБЛІОТЕКА DLL MFC42.БІБЛІОТЕКА DLL

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

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

Ініціалізація DLL

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

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

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

зовнішній "С" зовнішній втрати WI&NAPI InitXxxDLL()
{
 nbsp; нові CDynLinkLibrary(extensionDLL);
}

Звичайні ім'я, InitXxxDLL в цьому прикладі може бути все що завгодно. Вона не повинна бути extern “C” , але робити так робить простіше підтримувати список експорту.

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

Експорт записи

Простий спосіб експорту ваших класах є використання __declspec(dllimport) і __declspec(dllexport) на кожного класу та глобальні функції для експорту. Це робить його набагато легше, але менш ефективним, ніж іменування кожну точку входу (див. нижче), оскільки у вас менше контролю за те, що функції експортується і не можна експортувати функції на порядковий. Це метод, який TESTDLL1 і TESTDLL2 за допомогою експортувати свої записи.

Більш ефективний спосіб (і метод, який використовується на MFCxx.DLL), щоб експортувати кожен запис вручну отримують імена кожного запису в.DEF файл. Оскільки ми експортування Вибірковий експорту з наших DLL (тобто, не все), ми повинні будемо вирішувати яких зокрема інтерфейсів, ми хочемо, щоб експортувати. Це складно, оскільки необхідно вказати спотворюються імена, щоб компонувальник у вигляді записів у регіоні.DEF файл. Не експортувати будь-класів C++, якщо ви дійсно повинні мати символічне посилання для нього.

Якщо ви експорт C++ класів з є.DEF файлу перш ніж ви можете розробити інструмент, щоб створити цей список автоматично. Це можна зробити за допомогою двох етапів посилання. Посилання ваші DLL з не експорту, і дозволити компонувальник генерувати на.Файл карти. В.Файл карти можуть бути використані для генерує список функцій, які потрібно експортувати, тому з деякими munging, він може бути використаний для створення ЕКСПОРТ записи для вашого.DEF файл. Експорт списку для MFCxx.DLL і OLE і бази даних розширенням DLL, кілька тисяч номера, створено на цьому процесі (хоча це не повністю Автоматична і вимагає деяких руки тюнинг кожен раз в той час).

CWinApp-CDynLinkLibrary

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

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

Використання ресурсів у вашій реалізації DLL

Як уже згадувалося вище, навантаження ресурс за промовчанням буде ходити список CDynLinkLibrary об'єктів, шукає перший EXE або DLL, який має потрібний ресурс. Всі MFC API, а також внутрішній код використовує AfxFindResourceHandle ходити списку ресурсів, щоб знайти будь-який ресурс, незалежно від того, де він може бути.

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

Ходьба списку має недоліки, що це трохи повільніше і вимагає керування діапазонами Ідентифікатор ресурсу. Це має ту перевагу, що клієнтський застосунок, що посилання на декілька розширенням DLL можуть використовувати будь-які умови для DLL ресурсу без необхідності вказування дескриптор екземпляра DLL. AfxFindResourceHandle є API використовується для ходьби ресурс список дивитися на даний матч. Він приймає ім'я та тип ресурс і повертає дескриптор ресурс, де було вперше знайдено (або NULL).

Написання застосунок, який використовує версію DLL

Вимоги до додатків

Програма, яка використовує Версія MFC повинні дотримуватися кількох простих правил:

Будинок з середовище розробки

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

Наступний крок припускає, що ви маєте правильного функціонування MFC програма, пов'язана з NAFXCWD.Бібліотека (для налагодження) і NAFXCW.Бібліотека (для роздрібної торгівлі) і ви хочете, щоб перетворити його на використання Версія MFC бібліотеки. Ви працюєте в середовищі Visual C++ і внутрішній проект-файлом.

  1. Виберіть параметри в меню побудувати. На сторінці настройки проекту встановити Microsoft Базисні класи для використання MFC у спільних DLL (MFCxx(d).dll).

Будинок з NMAKE

Якщо ви використовуєте функцію зовнішніх makefile Visual c++, або використовують NMAKE безпосередньо, ви повинні змінити ваші makefile для підтримки компілятор та компонувальник параметри

Необхідні компілятор прапори:

/ D_AFXDLL /MD

/ D_AFXDLL

Стандартний MFC заголовки повинні цей символ, щоб визначити:

/MD

Застосування повинні використовувати DLL версії C-виконавча бібліотека

Всі інші прапори компілятор виконайте MFC за замовчуванням (наприклад, _DEBUG для налагодження).

Редагування списку компонувальник бібліотек. Змінити NAFXCWD.LIB MFCxxD.LIB і змінити NAFXCW.LIB MFCxx.LIB. Додати MFCOxx[U]D.LIB, MFCDxx[U]D.LIB та MFCNxx[U]D.LIB відповідно (необхідні для використання MFC/OLE, бази даних або мережі класи). Замінити LIBC.LIB з MSVCRT.LIB. Як будь-які інші бібліотеки MFC є важливим, що MFCxxD.LIB розміщені, перш ніж будь-який C-виконавчі бібліотеки.

Можна також додати /D_AFXDLL ваш роздрібної торгівлі і налагодження ресурс компілятор параметри (той, який фактично компілює ресурси з /R). Це робить ваш остаточний виконуваний файл менших за розподіл ресурсів, які присутні у MFC DLL.

Повне відновлення є після цих змін.

Створення зразків

Більша частина MFC приклади програм можуть бути побудовані з Visual c + + або спільного NMAKE-сумісні MAKEFILE з командного рядка.

Щоб перетворити будь-який з цих зразків для використання MFCxx.DLL, ви можете завантажити з.MAK файлів в Visual C++ і встановіть параметри проекту, як описано вище. Якщо ви використовуєте NMAKE побудувати, можна вказати "AFXDLL = 1" на на NMAKE командного рядка і що буде побудувати зразки, використовуючи загальні бібліотеки MFC.

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

Упаковка нотатки

Роздрібна Версія DLL (MFCxx [U].Бібліотека DLL) є вільно вторинного розповсюдження. Налагоджування версії DLL не вільно вторинного розповсюдження і повинні бути використані тільки при розробці вашого застосування.

Налагодження DLL надаються з налагоджувальної інформації. За допомогою налагоджувача Visual C++, можуть простежити виконання вашого застосування, а також DLL. Реліз DLL (MFCxx [U].Бібліотека DLL) не містять налагоджувальної інформації.

Настроювання або відновити DLL, тоді ви повинні називати їх щось інше, ніж "MFCxx" The MFC SRC файл MFCDLL.MAK описано параметри побудувати і містить логіку для перейменування DLL. Це правило також стосується MFC/OLE, бази даних і мережа DLL, яка побудована MFCOLE.МАК, MFCDB.Мак і MFCNET.Мак, відповідно. Перейменування файлів є необхідним, оскільки ці DLL потенційно поділяють багато MFC додатків. Маючи ваш власний Версія MFC DLL замінити ті, установлений у системі може розірвати іншим додатком MFC за допомогою спільних MFC DLL.

Відновлення MFC DLL не рекомендується.

Як здійснюється на MFCxx.DLL

Наступний розділ описує, як виконані MFC DLL (MFCxx.DLL і MFCxxD.DLL). Розуміння подробиці тут, також не важливо, якщо все, що ви хочете зробити є використання MFC DLL з вашої програми. Подробиці тут не є необхідними для розуміння того, як створити MFC розширення DLL, але розуміння цієї реалізації може допомогти вам створити свій власний DLL.

Впровадження огляд

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

Win32 робить велику частину роботи

16-Розрядна версія MFC необхідні ряд спеціальних методів, включаючи дані за app в сегменті стек, спеціальні сегменти, створена 80 x 86 Асамблеї код, на процес-винятку контекстах і інші методи. Win32 безпосередньо підтримує за процес дані в бібліотеку DLL, яка є те, що ви хочете, щоб більшу частину часу. В більшості, MFCxx.DLL є просто NAFXCW.LIB упаковані в DLL. Якщо ви подивитеся на MFC вихідний код, ви знайдете дуже мало #ifdef _AFXDLL, оскільки існує дуже мало особливих випадках, які повинні бути зроблені. Особливих випадках, які є спеціально для боротьби з Win32 на Windows 3.1 (інакше відома як Win32s). Win32s чи не підтримки за процес DLL даних безпосередньо так MFC DLL необхідно використовувати до локального сховища ниті (TLS) API для Win32 отримати процес локальні дані.

Вплив на бібліотеку джерел, додаткові файли

Вплив на нормальний MFC клас бібліотеки джерел і заголовки, версія _AFXDLL є відносно незначними. Існує спеціальна версія файлу (AFXV_DLL.H) а також додаткові заголовка файлу (AFXDLL_.H) включено на основні AFXWIN.H заголовка. AFXDLL_.H заголовок містить CDynLinkLibrary класу та інших деталей реалізації програми _AFXDLL і MFC розширенням DLL. AFXDLLX.H заголовок надається для побудови MFC розширенням DLL (див. вище подробиці).

Регулярні джерел MFC SRC, бібліотеку MFC є деякі додаткові умовного код під _AFXDLL #ifdef. Файл додаткове джерело (DLLINIT.CPP) містить додаткові DLL ініціалізації коду та інші клей для Версія MFC.

Для того, щоб побудувати Версія MFC, надаються додаткові файли. (Докладніше див нижче про те, як побудувати DLL.)

Будівництво MFC DLL

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

MFCDLL.Мак файл буде побудувати налагодження DLL з CodeView інформація:

NMAKE mfcdll.mak /f НАЛАГОДЖЕННЯ = 1 LIBNAME = MYMFC

MFCDLL.Мак файл буде побудувати реліз DLL без інформація CodeView:

NMAKE mfcdll.mak /f НАЛАГОДЖЕННЯ = 0 LIBNAME = MYMFC

(Аналогічно, використовувати MFCOLE.МАК, MFCDB.Мак і MFCNET.MAK побудувати, MFCOxxD.DLL, MFCDxxD.DLL і MFCNxxD.DLL - DLL, яка містить MFC/OLE, бази даних і мережа класи)

Це буде побудувати приватних Версія MFC DLL в MFC SRC каталогу з стандартні імена MFCxx.DLL і MFCxxD.DLL. Вам буде потрібно скопіювати їх на відповідні місця на вашому шляху до використання нового DLL. MFCDLL.MAK makefile також відновити Імпорт бібліотеки (MFCxx.LIB і MFCxxD.LIB) і розмістити їх в стандартний каталог MFC LIB. Це призведе до заміни готові MFCxx.LIB та MFCxxD.LIB бібліотеки, тому будь ласка, будьте обережні.

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

Можна змінювати бібліотеки та розповсюджувати роздрібною (/ звільнити) змінений медіатеки, тільки якщо ви Перейменуйте його на щось інше, ніж MFCxx.DLL. Ви не можуть поширювати налагоджування версії або вбудованих або власний вбудований налагодження DLL.

Ці обмеження перерозподілу в основному, щоб уникнути розповсюдження нестандартні і потенційно вірус, що містять DLL. в ідеалі ви не повинні відновити DLL, і якщо ви перерозподілу вашого застосування з готові MFCxx.DLL, забезпечені продукт Visual C++, дозволить уникнути багато проблем для себе і ваших користувачів.

Управління пам'яттю

Додаток, що використовує MFCxx.DLL використовує загальні розподільника пам'яті надаються MSVCRTxx.DLL, спільні C-виконавчі DLL. Як додаток, будь-який розширенням DLL, а також MFC DLL, самі, використовувати цей розподільника спільної пам'яті. За допомогою спільних DLL для виділення пам'яті, DLL MFC можна виділити пам'ять, згодом звільнений застосунком або навпаки. Тому, що застосування і DLL необхідно використовувати той же розподільника, повинні не скасовує C++ глобальної оператор новий або Видалити оператора. Ті ж правила застосовуються до інших процедур розподіл пам'яті C-виконавчі файли (наприклад, malloc, realloc, безкоштовно, тощо.).

Порядкові числа і клас __declspec(dllexport) і DLL іменування

Ми не використовуємо в class __declspec(dllexport) функціональність компілятором C++. Замість цього, список експорту входить до складу клас бібліотеки джерел (MFCxx.DEF і MFCxxD.DEF). Експортуються лише ці набір точок входу (функції і дані). Інші символи, такі як MFC приватних реалізації функцій або класи, не експортуються всі експорту зробили порядкові без імені рядка в резиденти або резидента ім'я таблиці .

За допомогою class __declspec(dllexport) може бути життєздатною альтернативою для створення невеликих DLL, але у випадку з великими DLL як MFC, за замовчуванням, експорт механізм має ефективність і потенціал межі .

Що все це значить є що ми можна запакувати велику кількість функцій у випуску MFCxx.DLL, який є лише близько 800 КБ у більшу сторону без шкоди для багато виконання або швидкість завантаження. MFCxx.DLL було б 100K більше, цей метод не був використаний.Це також дає змогу додавати додаткові точки входу в кінці на.DEF файл дозволяє просте керування версіями без шкоди для швидкість і розміри ефективність експорт порядкові. Основної версії зміни в бібліотеці MFC клас буде змінити ім'я бібліотеки. Тобто, MFC30.Бібліотека DLL є вторинного розповсюдження DLL, що містить версію 3.0 MFC бібліотеки класів. Оновлення цієї DLL сказати, в гіпотетичний MFC 3.1, DLL б їм MFC31.Бібліотека DLL замість. Знову Якщо змінюється вихідний код MFC виробляти свої власні версії MFC DLL, використайте інше ім'я (і бажано один без "MFC") в ім'я.

Технічні примітки за номером |nbsp; Технічні примітки за категоріями

Index