Приклад: з CBuilder в MFC

У цьому прикладі ми крок за кроком пройдемо весь процес завантаження форми CBuilder в додаток MFC – від початку до кінця Я покажу вам всі пастки, які виникнуть на шляху такого перетворення, а також навчу деяким прийомам, які полегшать вам життя

Перше, що треба зробити для того, щоб завантажити форму CBuilder в додаток MFC, – це створити в CBuilder DLL, що містить цю форму Чи не найскладніше завдання, чи не так Просто створіть новий додаток в CBuilder, вибравши команду меню File д New, і в якості типу створюваного додатка вкажіть DLL CBuilder автоматично згенерує повний скелет DLL, включаючи функцію для точки входу в DLL і файл збірки (Make-файл) Якщо ви звикли працювати в інших системах, вас це має приємно здивувати – система зробила за вас всю рутинну роботу

Після створення DLL вам треба створити форму, яку ви будете в ній використовувати У цьому теж немає нічого складного Вам не треба хвилюватися ні про порядок ініціалізації, ні про що підключаються бібліотеках, ні про яких подібних речах – все, що треба формам для створення, уже вбудовано в них Так що просто використовуйте команду меню File д New і виберіть Form з запропонованого списку

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

Рис 121 Форма CBuilder для програми MFC

Після створення форми вам треба визначити, яким чином форма буде створюватися в додатку MFC Тут починається другий етап нашого процесу – створення обгорткового функції (wrapper function) для доступу до форми з додатку MFC

Однією з проблем, що виникають при роботі в різних середовищах розробки, є проблема перетворення імен (name mangling) компілятором C + + Як і слід було очікувати, компілятори Microsoft Visual C + + і Borland C + + Builder після перетворення імен повертають різні імена для одних і тих же функцій, що сильно ускладнює їх обєднання На щастя, мова C + + надає спосіб, що дозволяє обійти цю проблему, – Можна скасувати перетворення імен функцій і обєктів, що визначаються в системі

Якщо ви помістіть блок коду всередину вираження extern &quotC&quot, Компілятор не буде виробляти перетворення імен в цьому блоці Дивлячись на синтаксис цього виразу, може здатися, що воно виключає можливість застосування коду C + + всередині блоку, але це не так У блоці, визначеному виразом extern &quotC&quot, Ви можете застосовувати будь синтаксис (навіть розширення CBuilder), і тим не менше все буде працювати належним чином

Розглянемо, наприклад, наступний блок коду: void CreateAForm (long nWhichForm)

Якщо ви пропустите цей код через компілятор Microsoft Visual C + +, швидше за все в результуючому обєктному файлі ви отримаєте імя типу _CreateAForm @ 4 Наскільки я розумію, подібне уявлення використовується для функцій, що мають аргумент типу long А ось навіщо компілятор додає символ подчеркива ня (_) в початок імені функції, я поняття не маю – схоже, це йде корінням в глибоке минуле

Якщо ви мислите приблизно так само, як і я, вас не повинно хвилювати, чому компілятор робить те, що він робить Все, що вам треба від компілятора, – це щоб він видавав працюючий код, який ви могли б включити в свій додаток Отже, проблема полягає в тому, щоб змусити два компілятора видавати коди в порівнянному один з одним форматі Для цієї мети і використовується вираз extern &quotC&quot.

Повернемося до нашої рядку і перепишемо її тепер наступним чином: extern C

{

void CreateAForm(long nWhichForm)

}

Тепер і після компіляції імя функції буде «CreateAForm» – без перетворень, повязаних з аргументами і символу підкреслення на початку імені Обидва компілятора знають, як працювати з таким синтаксисом, так що для них це ідеальний спосіб спілкування

Передбачаючи ваше запитання Не існує ніякої можливості напряму «спілкуватися» з обєктом

VCL CBuilder з програми на Microsoft Visual C + + Visual C + + не зможе переварити все

розширення синтаксису, використовувані в VCL для опису обєктів (__property,

__fastcall і

т п), так що безпосередньо звязати їх ніяк не вийде Відповідно, вам доведеться використовувати посередницьку функцію для виконання завдання

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

Нижче приведений код обгорткового функції, який треба додати в програму (майбутню DLL), тобто у файл project1cpp:

extern &quotC&quot void WINAPI __declspec(dllexport) ShowForm(void)

{

Form1 = new TForm1((TComponent *)NULL) Form1-&gtShow()

}

Перше, на що слід звернути увагу в цьому коді, – це на визначення функції Про розділ extern &quotC&quot ми тільки що поговорили Далі функція не вертає ніяких значень, про це говорить вжите тут вираз void Розділ WINAPI свідчить про те, що ми маємо справу зі звичайною функцією Windows

А от розділ __delspec (dllexport) – Це вельми важливе додавання, яке вам доведеться використовувати у всіх функціях, які ви збираєтеся викликати з будь-якої зовнішньої програми Це вираз означає, що функція повинна бути автоматично експортована з DLL і доступна для будь викликає програми Якщо ви не визначите свою функцію як експортовану, жодна з викликають програм не буде її бачити, а отже, і додаток MFC не зможе її викликати

Можливо, ви памятаєте, що при розмові про DLL в CBuilder ми зупиняли свою увагу на програмі implib, яка використовується для створення бібліотек імпорту (import libraries) для DLL Коли ці бібліотеки імпорту приєднані до програми, функції з DLL поводяться так само, як якби вони були просто частиною вихідного файлу цієї програми При динамічної

завантаженні ви спочатку завантажуєте DLL, потім знаходите функцію в DLL і вже після цього викликаєте функцію непрямим викликом (як ми це робили в попередньому розділі) При статичній завантаженні процес виглядає поіншому Коли ви статично завантажуєте DLL за допомогою бібліотеки імпорту, Windows сама виконує роботу по знаходженню DLL, завантаженні її в память і перетворенню ваших звернень до функцій в непрямі виклики функцій Бібліотеки імпорту – це менш гнучке освіту, ніж статичні бібліотеки Одного разу приєднавши бібліотеку імпорту, ви вже привязуєтесь до конкретного втілення функції і вже нічого не можете зробити з нею під час виконання З іншого боку, бібліотеки імпорту чудово підходять для оновлення версій Ви можете поставляти користувачам оновлені версії DLL, і якщо ви нічого не міняли в описах функцій, то користувач зможе використовувати більш нові версії, нічого не змінюючи в своїх програмах

Ознайомившись з настільки радісним описом бібліотек імпорту, ви, можливо, вирішите, що наша робота в основному виконана і все, що нам залишилося зробити, – це за допомогою програми implib створити бібліотеку імпорту для нашої DLL, завантажити її в додаток на Visual C + + з MFC і викликати функцію Ви, безумовно, не праві У мене складається враження, що у творців компіляторів є свій таємний кодекс честі, і створення компілятора, що дозволяє програмісту зробити що-небудь настільки просто, в корені суперечить самому духу цього кодексу Так що тепер нам треба виконати якусь досить прямолінійну, але проте малозрозумілу процедуру, для того щоб наша DLL запрацювала з MFC

Ви не можете використовувати програму implib, оскільки бібліотеки, створювані цією програмою, не сумісні з Visual C + + Незважаючи на те що, як я вже згадував, DLL – вона і в Африці DLL, бібліотека – це все ж набір обєктних файлів Для того щоб код був сумісний, формати обєктних файлів також повинні бути сумісні Чи треба говорити, що формати обєктних файлів CBuilder і Microsoft Visual C + + сильно розрізняються, так що бібліотека імпорту не зможе бути коректно завантажена Що нам треба зробити, так це створити бібліотеку імпорту в Visual C + +, яка була б сумісна з цією системою

«Немає проблем, – скажете ви, – просто запускаємо версію implib для Visual C + + – і ключик у нас у кишені» Вибачте, але не все так просто Фірма Microsoft з якихось причин перестала поставляти програму implib зі своїми засобами розробки Вона все ж надає в наше розпорядження метод для створення бібліотеки імпорту, але він вимагає декілька великих зусиль Давайте розглянемо кроки, які нам необхідно вжити для того, щоб виконати цю роботу

Перше, що знадобиться вам для створення бібліотеки імпорту, – це файл опису модуля (DEF) Як вам відразу б сказав будь-який програміст, попрацювавши ший з Windows декілька років, цей файл являє собою опис DLL, яке включає в себе список експортованих функцій Замість того щоб змушувати вас розбиратися в синтаксисі файлу DEF (а він дуже схожий на древнескандінав ські руни), я надам у ваше розпорядження шаблон файлу DEF, який ви зможете без праці заповнити своїми даними Цей шаблон (з описами того, що слід замінити), виглядає наступним чином:

; project1def: Описує параметри модуля для DLL LIBRARY $ $ ProjectName $ $

CODE SHARED EXECUTE READ DATA READ WRITE

DESCRIPTION  $Description$ EXPORTS

; Тут розташовуються експортовані імена

$FunctionName$  @$FunctionNumber$

У цьому описі вам слід зробити деякі заміни, спираючись на те, що:

·&nbsp&nbsp&nbsp $ProjectName$ – Імя проекту Як правило, це буде те ж саме імя, під яким ви зберігали проект в CBuilder

·&nbsp&nbsp&nbsp $Description$ – Написане на нормальному людській мові опис проекту, з якого можна дізнатися, чому була створена дана DLL і для чого вона використовується

·&nbsp&nbsp&nbsp $FunctionName$ – Імя функції, яку ви хочете експортувати Існує одне місце в шаблоні для кожної функції, яку ви хочете описати як експортовану в DLL

·&nbsp&nbsp&nbsp $FunctionNumber$ – Простий порядковий номер (від 1 до кількості функцій в DLL) Цей номер використовується для того, щоб прискорити завантаження функції з DLL під час виконання

Нам для нашої програми треба знати список експортованих функцій в DLL Як правило, ви знайомі з цим списком, оскільки самі ж і створювали цю DLL, але іноді може виникнути ситуація, коли вам доведеться працювати з DLL, написаною не вами, в якій не будуть визначені експортовані функції Також може виникнути момент, коли ви захочете дізнатися, які ж ще функції, крім зазначених у документації, експортує DLL (треба сказати, що подібне бажання приходить вельми часто) Для того щоб здійснити задумане, вам доведеться використовувати ще одну поставлену з Visual C + + програму – dumpbin

Щоб отримати список експортованих функцій в DLL, використовуйте наступний синтаксис запуску програми dumpbin:

dumpbin /EXPORTS filenamedll

Я сподіваюся, ви вже здогадалися, що тут filenamedll – це імя тієї DLL, для якої ви хочете дізнатися список експортованих функцій Якщо ми запустимо програму dumpbin для файлу project1dll, створеного нами в CBuilder, то побачимо наступне:

dumpbin /EXPORTS project1dll

Microsoft (r) COFF Binary File Dumper Version 4206164 Copyright (c) Microsoft Corp 1992-1996 All rights reserved Dump of file project1dll

File type: DLL

Section contains the following Exports for D:\matt\CBDLL\Project1dll

0 characteristics

0 time date stamp Wed Dec 31 19:00:00 1969

000 version

1 ordinal base

3 number of functions 3 number of names

ordinal hint name

1 0 ShowForm (0000119C)

2 1 _ DebugHook (000313FC)

3 2 _ Exception Class (000347E0)

Summary 9000 data

1000 edata

2000 idata

4000 reloc

5000 rsrc F000 text 1000 tls

У даній роздруківці результатів роботи програми dumpbin міститься досить багато цікавої інформації, але нас дійсно хвилюють тільки деякі значення Найбільш важливий для нас блок, виділений підсвічуванням, в якому показані експортовані функції з номерами, які нам треба внести в файл DEF Функції _DebugHook і _ExceptionClass нас не хвилюють – вони використовуються самою системою CBuilder А ось створена нами в DLL функція ShowForm нас якраз цікавить Тепер, використовуючи отриману інформацію, ми можемо доопределить файл DEF для нашої DLL:

; project1def: Описує параметри модуля для DLL LIBRARY PROJECT1

CODE SHARED EXECUTE READ

DATA READ WRITE

DESCRIPTION DLL для використання BCB в MFC EXPORTS

; Тут розташовуються експортовані імена

ShowForm @1

Ми почали розмову з роботи з бібліотеками імпорту, так що ви можете здивуватися, чому нам довелося спочатку створювати цей незрозумілий файл DEF Все насправді просто – для того щоб створити бібліотеку імпорту, яку можна було б використовувати в Visual C + +, треба спочатку визначити файл DEF, що містить інформацію про DLL

Це може здатися трохи дивним, але як тільки ви усвідомлюєте, що ж насправді являє собою бібліотека імпорту, все відразу ж стане на свої місця Бібліотека імпорту

– Це такий собі різновид бібліотеки, що містить в собі «адреси» функцій DLL і якийсь код, який повідомляє Windows, що

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

Для того щоб створити бібліотеку імпорту для DLL, маючи файл DEF, слід скористатися програмою lib, що поставляється з Visual C + + У порівнянні з програмою tlib, що поставляється з CBuilder, програма lib набагато більш складна Як ви, можливо, памятаєте, програма tlib просто створює якийсь архів обєктних файлів, який можна підключити до додатка, а програма lib вміє робити набагато більше речей

Перейдіть в каталог, що містить файл DEF для нашої DLL, і запустите програму lib з наступними параметрами (це дозволить вам створити бібліотеку імпорту для DLL):

lib /DEF:project1dll

Microsoft (r) 32-Bit Library Manager Version 4206164 Copyright (c) Microsoft Corp 1992-1996 All rights reserved

LIB: warning LNK4068: /MACHINE not specified defaulting to IX86 project1dll : warning LNK4017: MZP statement not supported for the target platform ignored

Creating library project1lib and object project1exp

Ви нічого не втратите, проігнорувавши попередження програми про те, що вираз MZP

Не підтримується даною платформою Це повідомлення зявилося через те, що ми не визначили значення MACHINE для нашої бібліотеки За замовчуванням програма lib встановлює архітектуру машин Intel, так що, оскільки поки CBuilder працює тільки під Windows на платформі Intel, нас це цілком влаштовує

По закінченні роботи lib (а працює вона всього лише одну-дві секунди) знайдіть в своєму каталозі файл з імям, що збігається з імям файлу DEF і розширенням LIB Це і є наша горезвісна бібліотека імпорту для DLL

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

Отже, тепер у нас є DLL і є бібліотека імпорту, яку ми можемо використовувати у програмах на Visual C + + Так що тепер нам треба створити додаток MFC і викликати функцію Давайте цим і займемося

Я сподіваюся, що ви вже вмієте створювати додатки в Visual C + + за допомогою Майстра додатків Якщо ні, почитайте щось по цій системі – ця книга про CBuilder, а не про Visual C + +

Отже, за допомогою Майстра додатків створіть новий додаток, назвіть його MFCToBCB і призначте йому однодокументний (SDI) тип інтерфейсу Останні значення, задаються за умовчанням, нас не цікавлять – Нам вони не знадобляться

Якщо ви використовуєте версію Visual C + + 4x, виберіть команду Project д Insert Files Into the Project і знайдіть щойно створену нами бібліотеку імпорту Додайте її в проект і натисніть кнопку OK Тепер при складанні проекту Visual C + + підключить в нього бібліотеку імпорту для нашої DLL Треба сказати, що даний приклад не буде працювати у версіях Visual C + + нижче четвертої, оскільки ви не можете підключити 32-розрядну бібліотеку до 16-розрядному додатком

Наступне, що нам треба зробити, – це викликати функцію Для початку додайте в головне меню вашого застосування новий пункт із заголовком Особливо, а в нього включите підпункт Викликати форму C + + Builder Повна структура меню програми показана на рис 122

Рис 122 Структура меню програми MFCToBCB

Визначивши новий пункт меню, викличте Майстер класів і визначте обробник для цього пункту в класі CMainFrame Дайте новому методу імя OnBuilderForm – Цей метод буде використовуватися додатком для відображення форми CBuilder

Відкрийте клас CMainFrame на редагування в редакторі IDE Visual C + +

На початок вихідного файлу mainfrmcpp додайте рядки коду, що представляють прототип нашої функції, – цей прототип буде потрібно компілятору для того, щоб згенерувати код, здатний викликати функцію з DLL: extern C

{

void __declspec(dllexport) ShowForm(void)

}

Не забудьте, що і тут нам треба укласти опис прототипу функції всередину вираження

extern &quotC&quot, В іншому випадку компонувальник видасть нам повідомлення про помилку

Ще один цікавий аспект наведеного вище опису – використання модифікатора

__declspec(dllexport) Коли цей модифікатор використовується в DLL, він означає, що функція DLL повинна бути експортованої А коли цей модифікатор застосовується в додатку, він автоматично перетвориться в вираз, означаю

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

Останній етап нашого процесу – виклик функції Додайте в код методу OnBuilderForm

наступні рядки:

void  CMainFrame::OnBuilderForm()

{

ShowForm()

}

От і все, що треба зробити для того, щоб викликати метод і відобразити форму на екрані Тепер компілятор скомпілює весь код, а компонувальник приєднає бібліотеку імпорту для DLL таким чином, додаток буде зібрано воєдино

При запуску програми Windows автоматично завантажить DLL для форми CBuilder Коли ви викличете метод DLL ShowForm, Бібліотека імпорту здійснить непрямий виклик функції DLL, і форма буде відображена на екрані

Якщо ви мені не вірите, спробуйте самі: створіть додаток Visual C + + і, попередньо переконавшись у тому, що потрібна нам DLL знаходиться в тому ж каталозі, що і виконуваний файл програми, запустіть програму Виберіть пункт меню Викликати форму C + + Builder і переконайтеся, що форма дійсно відображає ся на екрані Отже, нам вдалося приєднати форму CBuilder до додатка MFC

Джерело: Теллес М – Borland C + + Builder Бібліотека програміста – 1998

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


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

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

Ваш отзыв

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

*

*