Поделиться через


Разработка библиотек DLL

Область применения: Excel 2013 | Office 2013 | Visual Studio

Библиотека — это скомпилированный код, который обеспечивает функции исполняемого приложения и предоставляет ему данные. Библиотеки могут быть связаны статически и динамически, обычно у них расширение LIB и DLL соответственно. Статические библиотеки (например, библиотека времени выполнения C) связываются с приложением во время компиляции и становятся частью полученного исполняемого файла. Приложение загружает библиотеку DLL, когда она необходима (обычно при запуске). Одна библиотека DLL может загружать другую библиотеку DLL и динамически ссылаться на нее.

Преимущества библиотек DLL

Ниже приведены основные преимущества библиотек DLL.

  • Все приложения могут использовать одну копию на диске.
  • ����������� ����� ���������� �������� �������.
  • ����������� ��������� ������� �������. Разработчики приложений и библиотек DLL должны только согласовать интерфейс соответствующих частей. Этот интерфейс экспортируется в библиотеке DLL.
  • Разработчики DLL могут обновлять библиотеки DLL, чтобы повысить их эффективность или исправить ошибку, не обновляя все использующие их приложения, если экспортированный интерфейс библиотеки DLL не изменяется.

С помощью DLL можно добавлять функции и команды в Microsoft Excel.

Ресурсы для создания библиотек DLL

Вот что нужно, чтобы создать библиотеку DLL:

  • Редактор исходного кода.
  • Компилятор для преобразования исходного кода в объектный, совместимый с оборудованием.
  • Компоновщик для добавления кода из статических библиотек и создания исполняемого DLL-файла.

Современные интегрированные среды разработки ,такие как Microsoft Visual Studio, предоставляют все эти возможности. Они также предоставляют гораздо больше: интеллектуальные редакторы, средства для отладки кода, средства для управления несколькими проектами, мастеры новых проектов и многие другие важные инструменты.

�� ������ ��������� ���������� DLL �� ���������� ������, �������� C/C++, Pascal � Visual Basic. Так как исходный код API Excel — C и C++, в этой документации рассматриваются только эти два языка.

Экспорт функций и команд

При компиляции проекта DLL компилятор и компоновщик должны знать, какие функции экспортировать, чтобы предоставить к ним доступ в приложении. � ���� ������� ������� ��������� �������.

При компиляции исходного кода компиляторы, как правило, изменяют имена функций с момента их появления в исходном коде. Обычно это делается путем добавления в начало и (или) конец имени в процессе, известном как оформление имени. Необходимо убедиться, что функция экспортирована с именем, распознаваемым приложением, загружающим библиотеку DLL. Это может означать, что компоновщику нужно связать декорированное имя с более простым именем экспорта. Имя экспорта может быть именем, как оно первоначально отображалось в исходном коде, или что-то другое.

Способ оформления имени зависит от языка и от того, как компилятору показано, чтобы сделать функцию доступной, то есть от соглашения о вызове. Стандартное соглашение о межпроцессных вызовах для Windows, используемое библиотеками DLL, называется соглашением WinAPI. Он определяется в файлах заголовков Windows как WINAPI, который, в свою очередь, определяется с помощью __stdcall декларатора Win32.

�������, �������������� � DLL-���� ��� Excel (������� �����, �������, ������������� ����� ��������, ��� ���������������� �������) ������ ������ ������������ ���������� � ������� WINAPI / __stdcall. � ����������� ������� ���������� ���� �������� ��������� WINAPI, ��� ��� �� ��������� � ������������ Win32 ������������ ���������� � ������� __cdecl, ����� ������������ ��� WINAPIV.

Вы можете сообщить компоновщику о необходимости экспорта функции, а также ее внешнее имя несколькими способами:

  • Поместите функцию в DEF-файл после ключевого слова EXPORTS и добавьте ссылку на этот файл в параметр проекта DLL во время связывания.
  • Используйте декларатор __declspec(dllexport) в определении функции.
  • ����������� ��������� ������������� #pragma ��� �������� ��������� ������������.

В проекте можно использовать все три способа, они поддерживаются и компилятором, и компоновщиком, но не следует экспортировать одну функцию более чем одним способом. ��������, �����������, ��� ���������� DLL �������� ��� ������ ��������� ����, C � C++, ������� �������� ��� ������� ��� �������� � my_C_exportmy_Cpp_export ��������������. Для простоты предположим, что функции принимают один числовой аргумент двойной точности и возвращают данные того же типа. В следующих разделах описываются варианты экспорта функций с помощью каждого из этих методов.

С помощью DEF-файла

double WINAPI my_C_export(double x)
{
/* Modify x and return it. */
    return x * 2.0;
}
double WINAPI my_Cpp_export(double x)
{
// Modify x and return it.
    return x * 2.0;
}

DEF-файл должен содержать следующие строки.

EXPORTS my_C_export = _my_C_export@8 my_Cpp_export

���� �������� ����� ��������� ������, ��������� �� ���������� EXPORTS.

entryname[=internalname] [@ordinal[NONAME]] [DATA] [PRIVATE]

�������� ��������, ��� ������� C ������������, �� � DEF-����� ������������ ���� ���� �������� ������������� ��� �������, ��������� ��� �� ��������� ���� (� ������ �������). Компоновщик неявно экспортирует функцию C++, используя имя исходного кода, так что в DEF-файл необязательно включать расширенное имя.

Для 32-разрядных вызовов функций API Windows соглашение о оформлении функций, скомпилированных на C, выглядит следующим образом: function_name становится function_name@n , где n — число байтов, выраженных в виде десятичного числа, занятого всеми аргументами, при этом байты для каждого из них округляется до ближайшего, кратного четырем.

Примечание.

Размер всех указателей в Win32 — четыре байта. ��� ������������� �������� �� ������ �� ������������� �����.

Можно заставить компилятор C++ предоставлять некодированные имена для функций C++, заключив функцию и любые прототипы функций в extern "C" {...} block, как показано в этом примере. (Фигурные скобки здесь опущены {} , так как объявление относится только к блоку кода функции, который сразу после него).

extern "C"
double WINAPI my_undecorated_Cpp_export(double x)
{
// Modify x and return it.
    return x * 2.0;
}

При размещении прототипов функции C в файлах заголовков, которые могут быть включены в исходные файлы C или C++, необходимо включить следующую директиву препроцессора.

#ifdef __cplusplus
extern "C" {
#endif
double WINAPI my_C_export(double x);
double WINAPI my_Cdecorated_Cpp_export(double x);
#ifdef __cplusplus
}
#endif

С помощью декларатора __declspec(dllexport)

Ключевое слово __declspec(dllexport) можно использовать в объявлении функции указанным ниже образом.

__declspec(dllexport) double WINAPI my_C_export(double x)
{
/* Modify x and return it. */
    return x * 2.0;
}

�������� ����� __declspec(dllexport) ���������� �������� � ������� ����� ����� ����������. ������������ ����� �������: ������� �� ����� ��������� � DEF-�����, � ��������� �������� ����������� ������ � ������������.

Если вы не хотите декорировать имя функции C++, необходимо объявить функцию следующим образом.

extern "C"
__declspec(dllexport) double WINAPI my_undecorated_Cpp_export(double x)
{
// Modify x and return it.
    return x * 2.0;
}

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

С помощью директивы компоновщика препроцессора #pragma

��������� ������ Microsoft Visual Studio ������������ ��� ���������������� �������, ������� ��� ������������� � ���������� #pragma ��������� ������ �������� ������������ �������������� ������� ��������������� � ���� �������. ������� FUNCTIONFUNCDNAME (�������� �������� �� ��� ������� ������������� � ������ �������) ������������ � ����������������� � ��������������� ������� ������� ��������������.

Например, при использовании Microsoft Visual Studio эти строки можно включить в общий файл заголовка, как показано ниже.

#if _MSC_VER > 1200 // Later than Visual Studio 6.0
#define EXPORT comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
#else // Cannot use this way of exporting functions.
#define EXPORT
#endif // else need to use DEF file or __declspec(dllexport)

Если такой заголовок включен в исходные файлы, две функции, приведенные в качестве примера, можно экспортировать следующим образом.

Код C:

double WINAPI my_C_export(double x)
{
#pragma EXPORT
/* Modify x and return it. */
    return x * 2.0;
}

Код C++:

double WINAPI my_Cpp_export(double x)
{
#pragma EXPORT
// Modify x and return it.
    return x * 2.0;
}

Обратите внимание, что директива должна быть помещена в текст функции и развертывается только в том случае, если ни один из параметров компилятора /EP или /P не задан. Этот метод устраняет необходимость в DEF-файле или объявлении __declspec(dllexport) и сохраняет спецификацию состояния экспорта с кодом функции.

См. также