45828 (665172), страница 3

Файл №665172 45828 (Создание в среде Borland C++ Builder dll, совместимой с Visual C++) 3 страница45828 (665172) страница 32016-07-31СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 3)

Использование директивы препроцессора #define

Теперь рассмотрим способ, позволяющий добиться одинаковых названий функций в заголовочном и объектном (.lib) файлах с помощью директивы #define. Перепишем заголовочный файл нашей BCB-библиотеки следующим образом

Листинг 4 - Компилятор Borland C++ Builder 5

ImplicitLinking_cdecl.h

#ifndef _IMPLICITDLL_

#define _IMPLICITDLL_

#ifdef _DLLEXPORT_

#define _DECLARATOR_ __declspec(dllexport)

#else

#define _DECLARATOR_ __declspec(dllimport)

#endif

extern "C"

{

// при компиляции в VC к оригинальным наименованиям

// функций добавятся символы подчеркивания, таким образом

// имена объявляемых функций совпадут с их именами в таблице

// экспорта DLL и, следовательно, .lib-файле

#ifdef _MSC_VER

#define SumFunc _SumFunc

#define ViewStringGridWnd _ViewStringGridWnd

#endif

int _DECLARATOR_ __cdecl SumFunc(int a, int b);

HWND _DECLARATOR_ __cdecl ViewStringGridWnd(int Count, double* Values);

}

#endif

При компиляции клиентского VC-приложения в подключенном к проекту заголовочном файле dll (ImplicitLinking_cdecl.h) к наименованию каждой функции с помощью директив #define добавляется символ подчеркивания (макрос _MSC_VER определяется компилятором VC по умолчанию). Поскольку из BCB dll __cdecl-функции экспортируются таким же образом, то есть с добавлением символа подчеркивания, то устанавливается соответствие имен экспортируемых и объявленных функций. Макросы #define распространяют свое влияние и на весь последующий код приложения, что позволяет в тексте программы при вызове импортируемой функции пользоваться ее оригинальным именем, которое при компиляции будет дополнено необходимым магическим символом подчеркивания. Таким образом, мы идем на поводу у фирмы Borland и в клиентском приложении завуалированно используем для вызова функций из нашей dll имена, измененные компилятором BCB. Именно необходимость использования измененных имен (пусть и не в открытую благодаря define-трюку), на мой взгляд, является существенным недостатком этого способа, так как, например, при желании явно (см. раздел “Алгоритм с явной загрузкой dll”) использовать dll придется оперировать измененными именами функций. Не развивая дальше эту тему, скажу, что если BCB dll создается с четким намерением использовать ее в VC-приложениях, то лучше добавлять к проекту библиотеки .def-файл с удобными для пользователей именами-псевдонимами функций.

К достоинствам данного способа (define-трюка) можно отнести его простоту и, как бы это ни противоречило сказанному в предыдущем абзаце, отсутствие необходимости добавлять к таблице экспорта dll псевдонимы функций. Несмотря на все удобства использования псевдонимов, таблица экспорта (а следовательно, и сама dll) при этом увеличивается в размерах. Да и создание .def-файла псевдонимов при большом количестве функций не добавляет приятных эмоций.

После компиляции dll с помощью impdef.exe получаем .def-файл экспорта, из которого утилитой lib.exe создаем объектный .lib-файл и добавляем его к клиентскому VC-проекту.

Листинг клиентского приложения, код которого в данном случае не зависит от способа решения проблемы несоответствия наименований функций в заголовочном и объектном файлах библиотеки, представлен ниже. Как и в предыдущем разделе, это диалоговое окно с двумя кнопками. Интересующий нас код сосредоточен в обработчиках событий нажатия кнопок диалога.

Листинг 5 - Компилятор Visual C++ 6.0

UsingImplicitLinking_cdeclDlg.cpp

// код, генерируемый средой разработки

// хэндл окна с VCL-компонентом StringGrid

HWND hGrid = NULL;

// подключаем заголовочный файл библиотеки

#include "ImplicitLinking_cdecl.h"

// код, генерируемый средой разработки

void CUsingImplicitLinkng_cdeclDlg::OnSumFunc()

{

// вызываем функцию SumFunc из dll

int res = SumFunc(5, 9);

// выводим результат в заголовок диалогового окна

char str[10];

this->SetWindowText(itoa(res, str ,10));

}

void CUsingImplicitLinkng_cdeclDlg::OnViewStringGridWnd()

{

// инициализация аргументов

const int count = 5;

double Values[count] = {2.14, 3.56, 6.8, 8, 5.6564};

// закрываем ранее созданное окно, чтобы они не «плодились»

if( hGrid != NULL )

::SendMessage(hGrid, WM_CLOSE, 0, 0);

// вызываем функцию ViewStringGridWnd из dll

hGrid = ViewStringGridWnd(count, Values);

}

void CUsingImplicitLinkng_cdeclDlg::OnDestroy()

{

CDialog::OnDestroy();

// закрываем окно с компонентом StringGrid, если оно было создано

if( hGrid != NULL )

::SendMessage(hGrid, WM_CLOSE, 0,0);

}

Основным преимуществом неявной загрузки dll является именно неявность использования dll со стороны клиентского приложения. Другими словами, приложение, вызывая функции, не подозревает, что они могут находиться где-то во внешнем модуле. Результатом является упрощение кода программы. К недостаткам следует отнести тот факт, что dll находится в памяти в течение всей работы программы, неявно ее использующей. Загрузка dll осуществляется при загрузке приложения – загрузчик PE-файлов, просматривая каждую запись в таблице импорта приложения, загружает соответствующую этой записи dll. Следовательно, если используемых библиотек много, загрузка основной программы может затянуться. В случае отсутствия неявно используемой dll приложение вообще не запустится.

Итоговый алгоритм с неявным связыванием для экспорта (импорта) __cdecl-функций состоит из следующей последовательности действий (см. также Демонстрационный проект):

1. Объявить экспортируемые функции как __cdecl.

2. Поместить объявления функций в блок extern ”С”, при этом не экспортировать классы и функции-члены классов.

3. В заголовочный файл для возможности его дальнейшего использования на клиентской стороне вставить:

#ifdef _DLLEXPORT_

#define _DECLARATOR_ __declspec(dllexport)

#else

#define _DECLARATOR_ __declspec(dllimport)

#endif

и добавить макрос _DECLARATOR_ к объявлению каждой функции, например,

int _DECLARATOR_ __cdecl SumFunc( int a, int b );

4. Далее либо создать и добавить к проекту .def-файл с псевдонимами для каждой функции, либо добавить в заголовочный файл библиотеки следующее:

#ifdef _MSC_VER

#define FuncName1 _FuncName1

#define FuncName2 _FuncName2

#define FuncNameN _FuncNameN

#endif

Если использовался #define-трюк, то пункт 7 нужно будет пропустить.

5. Скомпилировать BCB dll.

6. С помощью impdef.exe создать .def-файл с наименованиями экспортируемых функций.

7. Если в пункте 4 воспользовались псевдонимами, удалить из .def-файла экспорта неиспользуемые наименования функций, оставив только псевдонимы.

8. Создать клиентский VC-проект.

9. Из .def-файла экспорта библиотеки при помощи утилиты lib.exe создать объектный .lib-файл формата COFF и добавить его к клиентскому VC-приложению.

10. Скопировать BCB dll и ее заголовочный файл в папку с клиентским VC-проектом.

11. В клиентском приложении подключить заголовочный файл dll.

12. Вызвать в теле программы необходимые функции, не задумываясь над тем, что они расположены во внешней dll.

Алгоритм с неявным связыванием для экспорта (импорта) __stdcall-функций

Как уже упоминалось выше, утилита lib.exe может создавать библиотеку импорта только из .def-файла экспорта, при чем lib.exe при этом никак не взаимодействует с самой dll. Однако .def-файл не содержит никакой информации, касаемой соглашений о вызове, которых придерживаются экспортируемые функции. Следовательно, и lib.exe, работая исключительно с .def-файлом, не сможет уловить, что имеет дело с __stdcall-функциями, и, как результат, не сможет в .lib-файле отобразить функции согласно Microsoft-соглашению о наименовании для __stdcall-функций. Таким образом, учитывая из предыдущего раздела, что для __cdecl-функций lib.exe генерирует вполне работоспособный .lib-файл, приходим к следующему выводу: утилита lib.exe не способна генерировать библиотеки импорта для dll, экспортирующих __stdcall-функции. Людям, пожелавшим или вынужденным (а после прочтения этого раздела думаю только вынужденным) использовать BCB dll с __stdcall-функциями в VC, этот раздел посвящается.

Исходный код BCB dll остался таким же, как в предыдущем разделе (см. Листинг 3), только ключевое слово __cdecl везде необходимо заменить ключевым словом __stdcall.

Известно, что при создании VC dll вместе с ней среда генерирует .lib-файл (библиотеку импорта), который представлен, естественно, в нужном нам формате COFF, и в котором корректно будут отображаться __stdcall-функции. Поэтому создадим (File -> New… -> Win32 Dynamic-Link Library -> OK -> An empty DLL project -> Finish) ложную (dummy) VC dll, которая будет экспортировать тот же набор функций, что и BCB dll. Реализация функций в ложной dll абсолютно не важна, важны исключительно их наименования. Помимо одинаковых наименований экспортируемых функций у ложной и исходной библиотек должны совпадать имена, поскольку .lib-файлы содержат наименования dll. Можно воспользоваться исходными текстами BCBdll, скопировав .h- и .cpp-файлы в директорию к ложной dll, затем добавив их к проекту (Project -> Add To Project -> Files…) и удалив тела всех функций. Если функция возвращает значение, то оставляем оператор return и возвращаем в соответствии с типом все, что угодно (можно 0, NULL и т.д.). Поскольку тела функций будут пустыми, большую часть директив #include с подключаемыми заголовочными файлами также можно удалить. В итоге получим согласно нашему примеру следующий код ложной dll:

Листинг 6 - Компилятор Visual C++ 6.0

ImplicitLinking_stdcallDummy.h

#ifdef _DLLEXPORT_

#define _DECLARATOR_ __declspec(dllexport)

#else

#define _DECLARATOR_ __declspec(dllimport)

#endif

extern "C"

{

int _DECLARATOR_ __stdcall SumFunc(int a, int b);

HWND _DECLARATOR_ __stdcall ViewStringGridWnd(int Count, double* Values);

}

ImplicitLinking_stdcallDummy.cpp

#define _DLLEXPORT_

#include

#include "ImplicitLinking_stdcallDummy.h"

int __stdcall SumFunc(int a, int b)

{

return 0;

}

HWND __stdcall ViewStringGridWnd(int Count, double* Values)

{

return NULL;

}

Согласно таблице 1, VC экспортирует __stdcall-функции, добавляя к их наименованию информацию о списке аргументов и символ подчеркивания. Следовательно, в объектном .lib-файле будут имена, отличные от оригинальных имен функций, объявленных в заголовочном файле, и тем более отличные от наименований функций, экспортируемых из BCB dll, так как __stdcall-функции компилятор BCB экспортирует без изменений. Избавляться от этого несоответствия будем снова посредством .def-файла. Для нашего примера он будет следующим:

DummyDef.def

libRARY ImplicitLinking_stdcall.dll

EXPORTS

SumFunc

ViewStringGridWnd

Строка с именем библиотеки (LIBRARY) в .def-файле не обязательна, но если она есть, то имя, указанное в ней, в точности должно совпадать с именами ложной и исходной dll. Добавляем .def-файл к VC-проекту, перекомпилируем и получаем ложную dll и необходимую нам библиотеку импорта, содержащую корректное описание экспортируемых __stdcall-функций. .lib-файл, доставшийся в наследство от ложной dll, должен добавляться (прилинковываться) к любому VC-проекту, который собирается использовать нашу исходную BCB dll.

Пример VC-приложения, импортирующего __stdcall-функции, такой же, как и в предыдущем разделе (см. Листинг 5). Не забудьте в примере подключить (#include) нужный заголовочный файл BCB dll и добавить к проекту нужную библиотеку импорта.

Алгоритм с неявным связыванием для экспорта (импорта) __stdcall-функций (см. также Демонстрационный проект, ImplicitLinkingDll_stdcall.zip):

Характеристики

Тип файла
Документ
Размер
167,04 Kb
Тип материала
Учебное заведение
Неизвестно

Список файлов реферата

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6508
Авторов
на СтудИзбе
302
Средний доход
с одного платного файла
Обучение Подробнее