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


Пошаговое руководство: Создание и использование собственной динамической библиотеки (C++)

В этом пошаговом руководстве объясняется, как использовать интегрированную среду разработки Visual Studio для создания собственной библиотеки динамической компоновки (DLL), написанной в Microsoft C++ (MSVC) и использования библиотеки DLL из другого приложения C++. Библиотеки DLL, также известные как общие библиотеки в операционных системах на основе UNIX, являются одним из наиболее полезных видов компонентов Windows. Их можно использовать для совместного использования кода и ресурсов, а также для уменьшения размера приложений. Библиотеки DLL могут упростить даже обслуживание и расширение ваших приложений.

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

В этом пошаговом руководстве рассматриваются следующие действия.

  • Создайте проект DLL в Visual Studio.
  • Добавьте экспортированные функции и переменные в библиотеку DLL.
  • Создайте проект консольного приложения в Visual Studio.
  • Используйте функции и переменные, импортированные из библиотеки DLL в консольном приложении.
  • Запустите готовое приложение.

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

В этом пошаговом руководстве создаются два решения Visual Studio: одно из них создает библиотеку DLL, а другое - клиентское приложение. Библиотека DLL использует соглашение вызова C. Его можно вызывать из приложений, написанных на других языках программирования, если соответствуют платформа, соглашения о вызовах и связывания. Клиентское приложение использует неявное связывание, где Windows связывает приложение с библиотекой DLL во время загрузки. Это связывание позволяет приложению вызывать предоставляемые библиотекой DLL функции так же, как функции в статической связанной библиотеке.

В этом пошаговом руководстве не рассматриваются некоторые распространенные ситуации. Код не показывает использование библиотек DLL C++ другими языками программирования. В нем не показано, как создать библиотеку DLL только для ресурсов или как использовать явную компоновку для загрузки библиотек DLL во время выполнения, а не во время загрузки. Убедитесь, что вы можете использовать MSVC и Visual Studio для выполнения всех этих действий.

Несмотря на то, что код библиотеки DLL написан на языке C++, мы используем интерфейсы в стиле C для экспортированных функций. Существует две основные причины: во-первых, многие другие языки поддерживают импорт функций в стиле C. Клиентское приложение не должно быть записано на языке C++. Во-вторых, это позволяет избежать некоторых распространенных ошибок, связанных с экспортируемыми классами и функциями-членами. При экспорте классов легко совершить труднодиагностируемые ошибки, поскольку все, что упоминается в объявлении класса, должно иметь экземпляр, который также экспортируется. Это ограничение применяется к библиотекам DLL, но не к статическим библиотекам. Если классы имеют обычный стиль данных, вы не должны столкнуться с этой проблемой.

Дополнительные сведения о библиотеках DLL см. в статье "Создание библиотек DLL C/C++" в Visual Studio. Дополнительные сведения о неявном связывании и явном связывании см. в разделе "Определение используемого метода связывания". Сведения о создании библиотек DLL C++ для использования с языками программирования, использующие соглашения о компоновке на языке C++, см. в статье "Экспорт функций C++ для использования в исполняемых файлах C-языка". Сведения о создании библиотек DLL для использования с языками .NET см. в статье "Вызов функций DLL из приложений Visual Basic".

Предпосылки

  • Microsoft Windows 7 или более поздней версии. Мы рекомендуем последнюю версию Windows для оптимальной разработки.
  • Визуальная студия. Сведения о том, как скачать и установить Visual Studio, см. в статье "Установка Visual Studio". При запуске установщика убедитесь, что установка разработки настольных приложений с C++ выбрана. Не волнуйтесь, если вы не установили эту рабочую нагрузку при установке Visual Studio. Вы можете снова запустить установщик и установить его сейчас.

    Снимок экрана установщика Visual Studio, рабочая нагрузка

  • Визуальная студия. Сведения о том, как скачать и установить Visual Studio 2015, см. в статье "Установка Visual Studio 2015". Используйте пользовательскую установку для установки компилятора И средств C++, так как они не устанавливаются по умолчанию.
  • Основные сведения об использовании интегрированной среды разработки Visual Studio. Если вы раньше использовали классические приложения Windows, возможно, вы сможете продолжать. Общие сведения см. в обзоре функций интегрированной среды разработки Visual Studio.

  • Некоторые знания о языке C++. Не беспокойтесь, мы не делаем ничего слишком сложного.

Замечание

В этом пошаговом руководстве предполагается, что вы используете Visual Studio 2017 версии 15.9 или более поздней. Некоторые более ранние версии Visual Studio 2017 имели дефекты в шаблонах кода или использовали различные диалоговые окна пользовательского интерфейса. Чтобы избежать проблем, используйте установщик Visual Studio для обновления Visual Studio 2017 до версии 15.9 или более поздней.

Создание проекта DLL

В следующем наборе задач вы создадите проект для библиотеки DLL, добавьте код и создадите его. Чтобы начать, запустите интегрированную среду разработки Visual Studio и войдите, если вам нужно. Инструкции немного различаются в зависимости от используемой версии Visual Studio. Чтобы просмотреть шаги для предпочтительной версии Visual Studio, используйте селектор версий , расположенный в верхней части оглавлений на этой странице.

Создание проекта DLL в Visual Studio

  1. В строке меню выберите Файл>Создать>Проект, чтобы открыть диалоговое окно Создание проекта.

    Снимок экрана диалогового окна

  2. В верхней части диалогового окна задайте Язык на C++, установите Платформу на Windows, и установите Тип проекта на Библиотека.

  3. В отфильтрованном списке типов проектов выберите библиотеку динамических ссылок (DLL) и нажмите кнопку "Далее".

  4. На странице "Настройка нового проекта " введите MathLibrary в поле "Имя проекта", чтобы указать имя проекта. Оставьте значения имен расположения и решения по умолчанию. Установите Solution на Create new solution. Снимите флажок "Разместить решение и проект в том же каталоге", если он установлен.

  5. Нажмите кнопку Создать, чтобы создать проект.

При создании решения можно просмотреть созданные проекты и исходные файлы в окне обозревателя решений в Visual Studio.

Снимок экрана: окно обозревателя решений с выделенным проектом MathLibrary.

Создание проекта DLL в Visual Studio 2017

  1. В строке меню последовательно выберите пункты Файл>Создать>Проект, чтобы открыть диалоговое окно Новый проект.

  2. В левой области диалогового окна "Новый проект" выберите "Установленные компоненты Visual C++ Windows Desktop". В центральной области выберите Dynamic-Link Library (DLL). Введите MathLibrary в поле "Имя ", чтобы указать имя проекта. Оставьте значения имен расположения и решения по умолчанию. Установите Solution на Create new solution. Проверьте, установлен ли флажок "Создать каталог для решения", если нет.

    Снимок экрана: диалоговое окно

  3. Нажмите кнопку "ОК ", чтобы создать проект.

При создании решения можно просмотреть созданные проекты и исходные файлы в окне обозревателя решений в Visual Studio.

Снимок экрана: окно обозревателя решений в Visual Studio 2017 с выделенной библиотекой математики.

Создание проекта DLL в Visual Studio 2015 и более ранних версиях

  1. В строке меню выберите Файл >Создать >Проект.

  2. В левой области диалогового окна "Новый проект" разверните установленные>шаблоны и выберите Visual C++, а затем в центральной области выберите консольное приложение Win32. Введите MathLibrary в поле " Имя ", чтобы указать имя проекта. Оставьте значения имен расположения и решения по умолчанию. Установите Solution на Create new solution. Проверьте, установлен ли флажок "Создать каталог для решения", если нет.

    Скриншот диалогового окна

  3. Нажмите кнопку "ОК ", чтобы закрыть диалоговое окно "Новый проект" и запустить мастер приложений Win32.

    Снимок экрана страницы обзора мастера приложений Win32.

  4. Нажмите кнопку Далее. На странице "Параметры приложения" в разделе "Тип приложения" выберите библиотеку DLL.

    Снимок экрана: страница параметров приложения мастера приложений Win32.

  5. Нажмите кнопку "Готово ", чтобы создать проект.

Когда мастер завершит решение, вы увидите созданные проекты и исходные файлы в окне обозревателя решений в Visual Studio.

Снимок экрана: окно обозревателя решений в Visual Studio 2015 с выделенным элементом MathLibrary.

Прямо сейчас эта DLL не выполняет много функций. Затем вы создадите файл заголовка для объявления функций, экспортируемых библиотекой DLL, а затем добавьте определения функций в библиотеку DLL, чтобы сделать его более полезным.

Добавление файла заголовка в библиотеку DLL

  1. Чтобы создать файл заголовка для функций, в строке меню выберите "Добавить новый элемент>".

  2. В диалоговом окне "Добавление нового элемента" в левой области выберите Visual C++. В центральной области выберите файл заголовка (.h). Укажите MathLibrary.h имя файла заголовка.

    Снимок экрана: диалоговое окно

  3. Нажмите кнопку "Добавить ", чтобы создать пустой файл заголовка, который отображается в новом окне редактора.

    Снимок экрана: пустой файл MathLibrary.h в редакторе.

  4. Замените содержимое файла заголовка следующим кодом:

    // MathLibrary.h - Contains declarations of math functions
    #pragma once
    
    #ifdef MATHLIBRARY_EXPORTS
    #define MATHLIBRARY_API __declspec(dllexport)
    #else
    #define MATHLIBRARY_API __declspec(dllimport)
    #endif
    
    // The Fibonacci recurrence relation describes a sequence F
    // where F(n) is { n = 0, a
    //               { n = 1, b
    //               { n > 1, F(n-2) + F(n-1)
    // for some initial integral values a and b.
    // If the sequence is initialized F(0) = 1, F(1) = 1,
    // then this relation produces the well-known Fibonacci
    // sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    extern "C" MATHLIBRARY_API void fibonacci_init(
        const unsigned long long a, const unsigned long long b);
    
    // Produce the next value in the sequence.
    // Returns true on success and updates current value and index;
    // false on overflow, leaves current value and index unchanged.
    extern "C" MATHLIBRARY_API bool fibonacci_next();
    
    // Get the current value in the sequence.
    extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();
    
    // Get the position of the current value in the sequence.
    extern "C" MATHLIBRARY_API unsigned fibonacci_index();
    

Этот файл заголовка объявляет некоторые функции для создания обобщенной последовательности Fibonacci, учитывая два начальных значения. Вызов fibonacci_init(1, 1) генерирует знакомую последовательность чисел Фибоначчи.

Обратите внимание на инструкции препроцессора в верхней части файла. Новый шаблон проекта для библиотеки DLL добавляет <PROJECTNAME>_EXPORTS к определённым макросам препроцессора. В этом примере Visual Studio определяет MATHLIBRARY_EXPORTS , когда создается проект DLL MathLibrary.

Когда определен макрос MATHLIBRARY_EXPORTS, макрос MATHLIBRARY_API задает __declspec(dllexport) модификатор для объявлений функций. Этот модификатор сообщает компилятору и компоновщику экспортировать функцию или переменную из библиотеки DLL для использования другими приложениями. Если MATHLIBRARY_EXPORTS не определено, например, если файл заголовка MATHLIBRARY_EXPORTS включен клиентским приложением, MATHLIBRARY_API применяет модификатор __declspec(dllimport) к объявлениям. Этот модификатор оптимизирует импорт функции или переменной в приложении. Дополнительные сведения см. в статье dllexport, dllimport.

Добавление реализации в библиотеку DLL

  1. В обозревателе решений щелкните правой кнопкой мыши узел "Исходные файлы" и выберите "Добавить>новый элемент". Создайте новый файл с именем .cpp, таким же образом, как вы добавили новый файл заголовка MathLibrary.cpp на предыдущем шаге.

  2. В окне редактора выберите вкладку MathLibrary.cpp , если она уже открыта. Если нет, в обозревателе решений дважды щелкните MathLibrary.cpp папку "Исходные файлы" проекта MathLibrary , чтобы открыть его.

  3. В редакторе замените содержимое MathLibrary.cpp файла следующим кодом:

    // MathLibrary.cpp : Defines the exported functions for the DLL.
    #include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
    #include <utility>
    #include <limits.h>
    #include "MathLibrary.h"
    
    // DLL internal state variables:
    static unsigned long long previous_;  // Previous value, if any
    static unsigned long long current_;   // Current sequence value
    static unsigned index_;               // Current seq. position
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    void fibonacci_init(
        const unsigned long long a,
        const unsigned long long b)
    {
        index_ = 0;
        current_ = a;
        previous_ = b; // see special case when initialized
    }
    
    // Produce the next value in the sequence.
    // Returns true on success, false on overflow.
    bool fibonacci_next()
    {
        // check to see if we'd overflow result or position
        if ((ULLONG_MAX - previous_ < current_) ||
            (UINT_MAX == index_))
        {
            return false;
        }
    
        // Special case when index == 0, just return b value
        if (index_ > 0)
        {
            // otherwise, calculate next sequence value
            previous_ += current_;
        }
        std::swap(current_, previous_);
        ++index_;
        return true;
    }
    
    // Get the current value in the sequence.
    unsigned long long fibonacci_current()
    {
        return current_;
    }
    
    // Get the current index position in the sequence.
    unsigned fibonacci_index()
    {
        return index_;
    }
    
  1. В окне редактора выберите вкладку для MathLibrary.cpp , если она уже открыта. Если нет, в обозревателе решений дважды щелкните MathLibrary.cpp в папке "Исходные файлы " проекта MathLibrary , чтобы открыть его.

  2. В редакторе замените содержимое MathLibrary.cpp файла следующим кодом:

    // MathLibrary.cpp : Defines the exported functions for the DLL.
    #include "stdafx.h" // use pch.h in Visual Studio 2019 and later
    #include <utility>
    #include <limits.h>
    #include "MathLibrary.h"
    
    // DLL internal state variables:
    static unsigned long long previous_;  // Previous value, if any
    static unsigned long long current_;   // Current sequence value
    static unsigned index_;               // Current seq. position
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    void fibonacci_init(
        const unsigned long long a,
        const unsigned long long b)
    {
        index_ = 0;
        current_ = a;
        previous_ = b; // see special case when initialized
    }
    
    // Produce the next value in the sequence.
    // Returns true on success, false on overflow.
    bool fibonacci_next()
    {
        // check to see if we'd overflow result or position
        if ((ULLONG_MAX - previous_ < current_) ||
            (UINT_MAX == index_))
        {
            return false;
        }
    
        // Special case when index == 0, just return b value
        if (index_ > 0)
        {
            // otherwise, calculate next sequence value
            previous_ += current_;
        }
        std::swap(current_, previous_);
        ++index_;
        return true;
    }
    
    // Get the current value in the sequence.
    unsigned long long fibonacci_current()
    {
        return current_;
    }
    
    // Get the current index position in the sequence.
    unsigned fibonacci_index()
    {
        return index_;
    }
    

Чтобы убедиться, что все работает до сих пор, скомпилируйте библиотеку DLL. Чтобы скомпилировать, выберите Сборка>Сборка решения на строке меню. Выходные данные DLL и связанного компилятора помещаются в папку, которая называется Debug непосредственно под папкой решения. При создании сборки Release выходные данные помещаются в папку с именем Release. Вывод должен выглядеть примерно так:

1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>stdafx.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>MathLibrary.cpp
1>dllmain.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.pdb (Partial PDB)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Поздравляем, вы создали библиотеку DLL с помощью Visual Studio! Затем вы создадите клиентское приложение, использующее функции, экспортированные библиотекой DLL.

Создание клиентского приложения, использующего библиотеку DLL

При создании библиотеки DLL думайте о том, как клиентские приложения могут использовать его. Чтобы вызвать функции или получить доступ к данным, экспортируемым библиотекой DLL, исходный код клиента должен иметь объявления, доступные во время компиляции. Во время компоновки компоновщику требуется информация для разрешения вызовов функций или доступа к данным. Библиотека DLL предоставляет эти сведения в библиотеке импорта, файл, содержащий сведения о том, как найти функции и данные вместо фактического кода. В момент выполнения библиотека DLL должна быть доступна клиенту в месте, доступном для операционной системы.

Независимо от того, является ли ваша DLL собственным решением или разработкой третьей стороны, проект клиентского приложения должен содержать несколько видов информации для её использования. Ему нужно найти заголовки, объявляющие экспорт DLL, файлы библиотек импорта для компоновщика и сам файл DLL. Одним из решений является копирование всех этих файлов в клиентский проект. Для сторонних библиотек DLL, которые вряд ли изменятся во время разработки клиента, этот метод может быть лучшим способом их использования. Однако при сборке библиотеки DLL лучше избежать дублирования. Если вы делаете локальную копию DLL-файлов, которые находятся в процессе разработки, вы можете случайно изменить файл заголовка в одной копии, но не другое, или использовать устаревшую библиотеку.

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

Создание клиентского приложения в Visual Studio

  1. В строке меню выберите "Файл> новогопроекта>, чтобы открыть диалоговое окно "Создать проект".

  2. В верхней части диалогового окна задайте для параметра Язык значение C++, для параметра Платформа значение Windows, а для Типа проекта — Консоль.

  3. В отфильтрованном списке типов проектов щелкните Консольное приложение, а затем нажмите кнопку Далее.

  4. На странице "Настройка нового проекта " введите MathClient в поле "Имя проекта", чтобы указать имя проекта. Оставьте значения имен расположения и решения по умолчанию. Установите Solution на Создать новое решение. Снимите флажок "Разместить решение и проект в том же каталоге", если он установлен.

    Снимок экрана: диалоговое окно

  5. Нажмите кнопку Создать, чтобы создать клиентский проект.

Для вас создается минимальный проект консольного приложения. Имя основного исходного файла совпадает с именем проекта, введенным ранее. В этом примере оно называется MathClient.cpp. Его можно создать, но он еще не использует библиотеку DLL.

Создание клиентского приложения в Visual Studio 2017

  1. Чтобы создать приложение C++, использующее созданную библиотеку DLL, в строке меню выберите "Файл>нового>проекта".

  2. В левой области диалогового окна "Создать проект " выберите "Рабочий стол Windows " в разделе "Установленный>Visual C++". В центральной области выберите консольное приложение Windows. Укажите имя проекта , MathClient, в поле " Имя ". Оставьте значения имен расположения и решения по умолчанию. Установите Solution на Создать новое решение. Поставьте флажок "Создать каталог для решения", если он не отмечен.

    Снимок экрана: диалоговое окно

  3. Нажмите кнопку "ОК ", чтобы создать проект клиентского приложения.

Для вас создается минимальный проект консольного приложения. Имя основного исходного файла совпадает с именем проекта, введенным ранее. В этом примере оно называется MathClient.cpp. Его можно создать, но он еще не использует библиотеку DLL.

Создание клиентского приложения в Visual Studio 2015

  1. Чтобы создать приложение C++, использующее созданную библиотеку DLL, в строке меню выберите "Файл>нового>проекта".

  2. В левой области диалогового окна "Создать проект " выберите Win32 в разделе "Установленные>шаблоны>Visual C++". В центральной области выберите консольное приложение Win32. Укажите имя проекта , MathClient, в поле " Имя ". Оставьте значения имен расположения и решения по умолчанию. Установите Solution на Create new solution. Проверьте, установлен ли флажок "Создать каталог для решения", если нет.

    Снимок экрана диалогового окна

  3. Нажмите кнопку "ОК ", чтобы закрыть диалоговое окно "Новый проект" и запустить мастер приложений Win32. На странице "Обзор " диалогового окна мастера приложений Win32 нажмите кнопку "Далее ".

  4. На странице "Параметры приложения " в разделе "Тип приложения" выберите консольное приложение , если оно еще не выбрано.

  5. Нажмите кнопку "Готово ", чтобы создать проект.

После завершения работы мастера создается проект консольного приложения минимальной конфигурации. Имя основного исходного файла совпадает с именем проекта, введенным ранее. В этом примере оно называется MathClient.cpp. Его можно создать, но он еще не использует библиотеку DLL.

Затем, чтобы использовать функции MathLibrary в вашем исходном коде, ваш проект должен содержать файл MathLibrary.h. Этот файл заголовка можно скопировать в проект клиентского приложения, а затем добавить его в проект в качестве существующего элемента. Этот метод может быть хорошим выбором для сторонних библиотек. Однако если вы работаете над кодом для библиотеки DLL и клиента одновременно, файлы заголовков могут выйти из синхронизации. Чтобы избежать этой проблемы, задайте в проекте путь "Дополнительные каталоги включения" , чтобы включить путь к исходному заголовку.

Добавьте заголовок DLL в путь включения

  1. Щелкните правой кнопкой мыши узел MathClient в обозревателе решений , чтобы открыть диалоговое окно "Страницы свойств ".

  2. В раскрывающемся списке "Конфигурация" выберите все конфигурации , если он еще не выбран.

  3. В левой области выберите "Свойства> конфигурации" C/C++>General.

  4. В области свойств выберите раскрывающийся список рядом с полем редактирования дополнительных каталогов включения , а затем нажмите кнопку "Изменить".

    Снимок экрана диалогового окна

  5. Дважды щелкните в верхней панели диалогового окна "Дополнительные каталоги включения", чтобы включить режим редактирования. Или щелкните значок папки, чтобы создать новую запись.

  6. В элементе управления редактирования укажите путь к расположению файла заголовка MathLibrary.h . Вы можете выбрать элемент управления с многоточием (...), чтобы перейти к правильной папке.

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

    ..\..\MathLibrary\MathLibrary

    Если проекты DLL и клиентские проекты входят в одно решение, относительный путь может выглядеть следующим образом:

    ..\MathLibrary

    Когда клиентские проекты и библиотеки DLL находятся в других папках, измените относительный путь, чтобы он соответствовал. Или используйте элемент управления с многоточием для поиска папки.

    Скриншот диалогового окна

  7. После ввода пути к файлу заголовка в диалоговом окне "Дополнительные каталоги включения", нажмите кнопку "ОК". В диалоговом окне "Страницы свойств" нажмите кнопку "ОК ", чтобы сохранить изменения.

Теперь вы можете подключить файл MathLibrary.h и использовать функции, объявленные в вашем клиентском приложении. Замените содержимое MathClient.cpp с помощью этого кода:

// MathClient.cpp : Client app for MathLibrary DLL.
// #include "pch.h" Uncomment for Visual Studio 2017 and earlier
#include <iostream>
#include "MathLibrary.h"

int main()
{
    // Initialize a Fibonacci relation sequence.
    fibonacci_init(1, 1);
    // Write out the sequence values until overflow.
    do {
        std::cout << fibonacci_index() << ": "
            << fibonacci_current() << std::endl;
    } while (fibonacci_next());
    // Report count of values written before overflow.
    std::cout << fibonacci_index() + 1 <<
        " Fibonacci sequence values fit in an " <<
        "unsigned 64-bit integer." << std::endl;
}

Этот код можно скомпилировать, но не связать. Если вы создаете клиентское приложение сейчас, список ошибок отображает несколько LNK2019 ошибок. Это связано с отсутствием некоторых сведений о проекте: вы еще не указали, что у вашего проекта есть зависимость от библиотеки MathLibrary.lib . Вы не сказали системе компоновки, как найти файл MathLibrary.lib.

Чтобы устранить эту проблему, можно скопировать файл библиотеки непосредственно в проект клиентского приложения. Компоновщик будет находить и использовать его автоматически. Однако если библиотека и клиентское приложение находятся в процессе разработки, это может привести к изменениям в одной копии, которая не отображается в другой. Чтобы избежать этой проблемы, можно задать свойство Дополнительные зависимости, чтобы сообщить системе сборки, что ваш проект зависит от MathLibrary.lib. Кроме того, можно задать в проекте путь к дополнительным каталогам библиотеки , чтобы включить путь к исходной библиотеке при связывании.

Добавление библиотеки импорта DLL в проект

  1. Щелкните правой кнопкой мыши узел MathClient в обозревателе решений и выберите "Свойства ", чтобы открыть диалоговое окно "Страницы свойств ".

  2. В раскрывающемся списке "Конфигурация" выберите все конфигурации , если он еще не выбран. Это гарантирует, что любые изменения свойств применяются как к сборкам отладки, так и к релизным сборкам.

  3. В левой области выберите Свойства конфигурации>Компоновщик>Входные данные. В области свойств выберите раскрывающийся список рядом с полем редактирования дополнительных зависимостей и нажмите кнопку "Изменить".

    Снимок экрана: диалоговое окно

  4. В диалоговом окне "Дополнительные зависимости" добавьте MathLibrary.lib в список в верхнем элементе управления редактирования.

    Снимок экрана: диалоговое окно

  5. Нажмите кнопку "ОК ", чтобы вернуться в диалоговое окно "Страницы свойств ".

  6. В левой области выберите Свойства конфигурации>Компоновщик>Общие. В области свойств выберите раскрывающийся список рядом с полем " Дополнительные каталоги библиотеки " и нажмите кнопку "Изменить".

    Снимок экрана: диалоговое окно

  7. Дважды щелкните в верхней области диалогового окна "Дополнительные каталоги библиотеки" , чтобы включить элемент управления редактированием. В элементе управления редактирования укажите путь к расположению MathLibrary.lib файла. По умолчанию она находится в папке "Отладка " непосредственно в папке решения DLL. При создании релизной сборки файл помещается в папку с именем Release. Вы можете использовать $(IntDir) макрос, чтобы компоновщик смог найти библиотеку DLL, какую бы сборку вы ни создавали. Если вы выполнили инструкции, чтобы поместить клиентский проект в отдельное решение от проекта DLL, относительный путь должен выглядеть следующим образом:

    ..\..\MathLibrary\$(IntDir)

    Если ваши проекты DLL и клиентские проекты находятся в других местах, скорректируйте относительный путь для их соответствия.

    Снимок экрана: диалоговое окно

  8. После ввода пути к файлу библиотеки в диалоговом окне "Дополнительные каталоги библиотеки " нажмите кнопку "ОК ", чтобы вернуться в диалоговое окно "Страницы свойств ". Нажмите кнопку "ОК ", чтобы сохранить изменения свойств.

Клиентское приложение теперь можно успешно скомпилировать и скомпоновать, но оно по-прежнему не имеет всего необходимого для запуска. Когда операционная система загружает приложение, она ищет библиотеку DLL MathLibrary. Если не удается найти библиотеку DLL в определенных системных каталогах, переменной окружения PATH или в локальном каталоге приложения, загрузка терпит неудачу. В зависимости от операционной системы вы увидите следующее сообщение об ошибке:

Снимок экрана: диалоговое окно ошибки, библиотека DLL MathLibrary не найдена.

Один из способов избежать этой проблемы заключается в копировании библиотеки DLL в каталог, содержащий исполняемый файл клиента в рамках процесса сборки. Вы можете добавить событие после сборки в проект, чтобы добавить команду, которая копирует библиотеку DLL в выходной каталог сборки. Указанная здесь команда копирует библиотеку DLL, только если она отсутствует или изменена. В нем используются макросы для копирования в директории Debug или Release, которые зависят от настройки сборки.

Копирование библиотеки DLL в событии после сборки

  1. Щелкните правой кнопкой мыши узел MathClient в обозревателе решений и выберите "Свойства ", чтобы открыть диалоговое окно "Страницы свойств ".

  2. В раскрывающемся списке "Конфигурация" выберите "Все конфигурации ", если он еще не выбран.

  3. В левой панели выберите Свойства конфигурации>События сборки>Событие после сборки.

  4. В области свойств выберите элемент управления для редактирования в поле командной строки. Если вы выполнили инструкции, чтобы поместить клиентский проект в отдельное решение из проекта DLL, введите следующую команду:

    xcopy /y /d "..\..\MathLibrary\$(IntDir)MathLibrary.dll" "$(OutDir)"

    Если библиотеки DLL и клиентские проекты находятся в других каталогах, измените относительный путь к библиотеке DLL на соответствие.

    Снимок экрана: диалоговое окно

  5. Нажмите кнопку "ОК ", чтобы сохранить изменения в свойствах проекта.

Теперь клиентское приложение имеет все необходимое для сборки и запуска. Создайте приложение, выбрав "Сборка>" в строке меню. Окно вывода в Visual Studio должно иметь примерно следующий пример в зависимости от версии Visual Studio:

1>------ Build started: Project: MathClient, Configuration: Debug Win32 ------
1>MathClient.cpp
1>MathClient.vcxproj -> C:\Users\username\Source\Repos\MathClient\Debug\MathClient.exe
1>1 File(s) copied
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Поздравляем, вы создали приложение, которое вызывает функции в библиотеке DLL. Теперь запустите приложение, чтобы узнать, что он делает. В строке меню выберите "Начать отладку>без отладки". Visual Studio открывает командное окно для запуска программы. Последняя часть выходных данных должна выглядеть следующим образом:

Снимок экрана: выходные данные окна команд при запуске клиентского приложения без отладки.

Нажмите любую клавишу, чтобы закрыть окно командной строки.

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

При развертывании приложения необходимо также развернуть используемые им библиотеки DLL. Самый простой способ сделать библиотеки DLL, которые вы создаете, или получаете от третьих сторон, доступными — поместить их в каталог с приложением. Это называется локальным развертыванием приложений. Дополнительные сведения о развертывании см. в разделе "Развертывание" в Microsoft C++.

См. также