Создание и использование DLL

При разработке программ часто оказывается, что разным программным приложениям требуются одни и те же объекты, их свойства методы, процедуры и функции. Например, почти все программы выводят информацию на экран и пользуются стандартными объектами интерфейса Windows (окна, кнопки, меню…) Было бы в высшей степени неразумно запихивать код отрисовки каждого такого элемента во все программы.

Таким образом, возникает задача разделения большой программы на отдельные независимые модули, каждый из которых содержит определенный набор процедур и функций. Процедуры и функции такого модуля может вызывать любая другая программа. Подобные модули получили название динамически подключаемых библиотек (DLL – dynamically linked library). Слово "динамический" указывает на то, что подключение библиотеки происходит не на этапе компиляции, а уже после запуска программы.

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

Создание повторно используемого кода

С помощью Visual C++ можно создавать библиотеки трех следующих типов:
• библиотеки динамической компоновки (DLL);
• статические библиотеки;
• управляемые сборки.

Как правило, если необходимо создать библиотеку, которая могла бы использоваться машинным кодом C++, то следует предпочесть библиотеку динамической компоновки или статическую библиотеку. Если необходимо создать библиотеку, которая могла бы использоваться кодом на языках C++/CLI или на любом ином языке .NET, например C# или Visual Basic, то следует предпочесть управляемую сборку.

Создание и использование библиотеки DLL (C++)

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

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

Создание проекта библиотеки динамической компоновки (DLL)
1. В меню Файл выберите пункт Создать и затем пункт Проект....
2. В узле Visual C++ области Типы проектов выберите Win32.
3. В области Шаблоны выберите Консольное приложение Win32.
4. Выберите имя проекта, например MathFuncsDll, и введите его в поле Имя. Выберите имя решения, например DynamicLibrary, и введите его в поле Имя решения.
5. Для запуска мастера приложений Win32 нажмите кнопку ОК. На странице Общие сведения диалогового окна Мастер приложений Win32 нажмите кнопку Далее.
6. На странице Параметры приложения диалогового окна Мастер приложений Win32, в поле Тип приложения, выберите пункт DLL, если он доступен, либо пункт Консольное приложение в противном случае. В некоторых версиях Visual Studio создание проектов DLL с помощью мастеров не поддерживается. Необходимые изменения можно внести позднее для компиляции проекта в библиотеку DLL.
7. На странице Параметры приложения диалогового окна Мастер приложений Win32 в поле Дополнительные параметры выберите пункт Пустой проект.
8. Чтобы создать проект, нажмите кнопку Готово.

Добавление класса в библиотеку динамической компоновки
1. Чтобы создать файл заголовка для нового класса, в меню Проект выберите команду Добавить новый элемент.... Откроется диалоговое окно Добавление нового элемента. В узле Visual C++ области Категории выберите пункт Код. В области Шаблоны выберите пункт Заголовочный файл (.h). Выберите имя заголовочного файла, например MathFuncsDll.h, и нажмите кнопку Добавить. Отобразится пустой файл.
2. Добавьте простой класс с именем MyMathFuncs, осуществляющий обычные арифметические операции, такие как сложение, вычитание, умножение и деление. Код должен выглядеть примерно следующим образом:

// MathFuncsDll.h
namespace MathFuncs
{
 class MyMathFuncs
 {
 public:
 // Returns a + b
 static __declspec(dllexport) double Add(double a, double b);
 // Returns a - b
 static __declspec(dllexport) double Subtract(double a, double b);
 // Returns a * b
 static __declspec(dllexport) double Multiply(double a, double b);
 // Returns a / b
 // Throws DivideByZeroException if b is 0
 static __declspec(dllexport) double Divide(double a, double b);
 };
}

3. Обратите внимание на модификатор __declspec(dllexport) в объявлениях методов в этом коде. Этот модификатор разрешает экспорт метода библиотекой DLL для использования его другими приложениями. Дополнительные сведения см. в разделе dllexport, dllimport.
4. Чтобы создать исходный файл для нового класса, в меню Проект выберите команду Добавить новый элемент.... Откроется диалоговое окно Добавление нового элемента. В узле Visual C++ области Категории выберите пункт Код. В области Шаблоны выберите пункт Файл C++ (.cpp). Выберите имя исходного файла, например MathFuncsDll.cpp, и нажмите кнопку Добавить. Отобразится пустой файл.
5. Реализуйте функциональность класса MyMathFuncs в исходном файле. Код должен выглядеть примерно следующим образом:

// MathFuncsDll.cpp
// compile with: /EHsc /LD
#include "MathFuncsDll.h"
#include <stdexcept>
using namespace std;
namespace MathFuncs
{
 double MyMathFuncs::Add(double a, double b)
 {
 return a + b;
 }
 double MyMathFuncs::Subtract(double a, double b)
 {
 return a - b;
 }
 double MyMathFuncs::Multiply(double a, double b)
 {
 return a * b;
 }
 double MyMathFuncs::Divide(double a, double b)
 {
 if (b == 0)
 {
 throw new invalid_argument("b cannot be zero!");
 }
 return a / b;
 }
}

6. Чтобы построить библиотеку DLL проекта, в меню Проект выберите СвойстваMathFuncsDll. В левой области в поле Свойства конфигурации выберите Общие. В правой области в поле Тип конфигурации выберите Динамическая библиотека (.dll). Нажмите кнопку ОК для сохранения изменений.
7. Скомпилируйте библиотеку динамической компоновки, выбрав команду Построить решение в меню Построение. В результате будет создана библиотека DLL, которая может использоваться другими программами.

Создание приложения, ссылающегося на библиотеку динамической компоновки
1. Чтобы создать приложение, которое будет ссылаться и использовать созданную ранее библиотеку динамической компоновки, в меню Файл выберите пункт Создать и затем пункт Проект....
2. В узле Visual C++ области Типы проектов выберите Win32.
3. В области Шаблоны выберите Консольное приложение Win32.
4. Выберите имя проекта, например MyExecRefsDll, и введите его в поле Имя. В раскрывающемся списке рядом с полем Решение выберите пункт Добавить в решение. После этого новый проект будет добавлен в то же решение, что и библиотека динамической компоновки.
5. Для запуска мастера приложений Win32 нажмите кнопку ОК. На странице Общие сведения диалогового окна Мастер приложений Win32 нажмите кнопку Далее.
6. На странице Параметры приложения диалогового окна Мастер приложений Win32 в поле Тип приложения выберите пункт Консольное приложение.
7. На странице Параметры приложения диалогового окна Мастер приложений Win32 в поле Дополнительные параметры снимите флажок Предкомпилированный заголовок.
8. Чтобы создать проект, нажмите кнопку Готово.


Использование функциональных возможностей библиотеки классов в консольном приложении
1. По завершении создания консольного приложения будет создана пустая программа. Имя исходного файла будет совпадать с именем, выбранным ранее для проекта. В этом примере он имеет имя MyExecRefsDll.cpp.
2. Для использования математических процедур из библиотеки динамической компоновки необходимо сослаться на эту библиотеку. Для этого в меню Проект(Project) выберите пункт Ссылки....(Reference…) В диалоговом окне Окна свойств(Properties) разверните узел Общие свойства (Common Properties), выберите пункт Ссылки, а затем нажмите кнопку Добавить новую ссылку.... (Add New Rewference…).
3. Появится диалоговое окно Добавить ссылку. В этом диалоговом окне отображается список всех библиотек, на которые можно ссылаться. На вкладке Проект перечисляются все проекты текущего решения и включенные в них библиотеки. На вкладке Проекты выберите MathFuncsDll. Затем нажмите кнопку ОК.
4. Для создания ссылки на заголовочные файлы библиотеки динамической компоновки необходимо изменить путь к каталогам включения. Для этого в диалоговом окне Окна свойств (Properties) последовательно разверните узлы Свойства конфигурации (Configuration Properties), C/C++, а затем выберите Общие (General). Рядом с полем Дополнительные каталоги включения (Additional Include Directories) введите путь к месту размещения заголовочного файла MathFuncsDll.h.
5. Исполняемый файл не загружает библиотеки динамической компоновки во время выполнения. Необходимо указать системе место для поиска библиотеки MathFuncsDll.dll. Это можно сделать с помощью переменной среды PATH. Для этого в диалоговом окне Окна свойств (Properties) разверните узел Свойства конфигурации (Configuration Properties), а затем выберите Отладка(Debugging). В поле Среда(Environment) введите следующую строку: PATH=<путь к файлу MathFuncsDll.dll>, где вместо <путь к файлу MathFuncsDll.dll> необходимо подставить фактическое местоположение библиотеки MathFuncsDll.dll. Нажмите кнопку ОК для сохранения всех изменений.
6. Теперь класс MyMathFuncs можно использовать в приложении. Замените код в файле MyExecRefsDll.cpp следующим кодом:

// MyExecRefsDll.cpp
// compile with: /EHsc /link MathFuncsDll.lib
#include <iostream>
#include "MathFuncsDll.h"
using namespace std;
int main()
{
 double a = 7.4;
 int b = 99;
 cout << "a + b = " <<
 MathFuncs::MyMathFuncs::Add(a, b) << endl;
 cout << "a - b = " <<
 MathFuncs::MyMathFuncs::Subtract(a, b) << endl;
 cout << "a * b = " <<
 MathFuncs::MyMathFuncs::Multiply(a, b) << endl;
 cout << "a / b = " <<
 MathFuncs::MyMathFuncs::Divide(a, b) << endl;
 return 0;
}

7. Постройте исполняемый файл, выбрав команду Построить решение в меню Построение.

Запуск приложения

1. Убедитесь, что проект MyExecRefsDll выбран в качестве проекта по умолчанию. В Обозревателе решений выберите проект MyExecRefsDll и затем в меню Проект выберите команду Назначить запускаемым проектом.
2. Чтобы запустить проект, в меню Отладка выберите команду Запуск без отладки. Результат выполнения должен выглядеть примерно следующим образом:

a + b = 106.4
a - b = -91.6
a * b = 732.6
a / b = 0.0747475


Создание и использование статической библиотеки (C++)

Следующим типом библиотеки, которую мы создадим, является статическая библиотека (LIB). Статические библиотеки являются хорошим способом повторного использования кода. Вместо того чтобы каждый раз реализовывать одни и те же подпрограммы в каждом создаваемом приложении, их можно создать единожды и затем вызывать из приложений для обеспечения соответствующей функциональности.

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

Создание проекта статической библиотеки

1. В меню Файл выберите пункт Создать и затем пункт Проект....
2. В узле Visual C++ области Типы проектов выберите Win32.
3. В области Шаблоны выберите Консольное приложение Win32.
4. Выберите имя проекта, например MathFuncsLib, и введите его в поле Имя. Выберите имя решения, например StaticLibrary, и введите его в поле Имя решения.
5. Для запуска мастера приложений Win32 нажмите кнопку ОК. На странице Общие сведения диалогового окна Мастер приложений Win32 нажмите кнопку Далее.
6. На странице Параметры приложения диалогового окна Мастер приложений Win32 в поле Тип приложения выберите пункт Статическая библиотека.
7. На странице Параметры приложения диалогового окна Мастер приложений Win32 в поле Дополнительные параметры снимите флажок Предкомпилированный заголовок.
8. Чтобы создать проект, нажмите кнопку Готово.

Добавление класса в статическую библиотеку

1. Чтобы создать файл заголовка для нового класса, в меню Проект выберите команду Добавить новый элемент.... Откроется диалоговое окно Добавление нового элемента. В узле Visual C++ области Категории выберите пункт Код. В области Шаблоны выберите пункт Заголовочный файл (.h). Выберите имя заголовочного файла, например MathFuncsLib.h, и нажмите Добавить. Отобразится пустой файл.
2. Добавьте простой класс с именем MyMathFuncs, осуществляющий обычные арифметические операции, такие как сложение, вычитание, умножение и деление. Код должен выглядеть примерно следующим образом:

// MathFuncsLib.h
namespace MathFuncs
{
 class MyMathFuncs
 {
 public:
 // Returns a + b
 static double Add(double a, double b);
 // Returns a - b
 static double Subtract(double a, double b);
 // Returns a * b
 static double Multiply(double a, double b);
 // Returns a / b
 // Throws DivideByZeroException if b is 0
 static double Divide(double a, double b);
 };
}

3. Чтобы создать исходный файл для нового класса, в меню Проект выберите команду Добавить новый элемент.... Откроется диалоговое окно Добавление нового элемента. В узле Visual C++ области Категории выберите пункт Код. В области Шаблоны выберите пункт Файл C++ (.cpp). Выберите имя исходного файла, например MathFuncsLib.cpp, и нажмите Добавить. Отобразится пустой файл.
4. Реализуйте функциональность класса MyMathFuncs в исходном файле. Код должен выглядеть примерно следующим образом:

// MathFuncsLib.cpp
// compile with: /c /EHsc
// post-build command: lib MathFuncsLib.obj
#include "MathFuncsLib.h"
#include <stdexcept>
using namespace std;
namespace MathFuncs
{
 double MyMathFuncs::Add(double a, double b)
 {
 return a + b;
 }
 double MyMathFuncs::Subtract(double a, double b)
 {
 return a - b;
 }
 double MyMathFuncs::Multiply(double a, double b)
 {
 return a * b;
 }
 double MyMathFuncs::Divide(double a, double b)
 {
 if (b == 0)
 {
 throw new invalid_argument("b cannot be zero!");
 }
 return a / b;
 }
}

5. Чтобы построить статическую библиотеку проекта, в меню Проект выберите СвойстваMathFuncsLib. В левой области в поле Свойства конфигурации выберите Общие. В правой области в поле Тип конфигурации выберите Статическая библиотека (.lib). Нажмите кнопку ОК для сохранения изменений.
6. Скомпилируйте статическую библиотеку, выбрав команду Построить решение в меню Построение. В результате будет создана статическая библиотека, которая может использоваться другими программами.

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

1. Чтобы создать приложение, которое будет ссылаться и использовать созданную ранее статическую библиотеку, в меню Файл выберите пункт Создать и затем пункт Проект....
2. В узле Visual C++ области Типы проектов выберите Win32.
3. В области Шаблоны выберите Консольное приложение Win32.
4. Выберите имя проекта, например MyExecRefsLib, и введите его в поле Имя. В раскрывающемся списке рядом с полем Решение выберите пункт Добавить в решение. После этого новый проект будет добавлен в то же решение, что и статическая библиотека.
5. Для запуска мастера приложений Win32 нажмите кнопку ОК. На странице Общие сведения диалогового окна Мастер приложений Win32 нажмите кнопку Далее.
6. На странице Параметры приложения диалогового окна Мастер приложений Win32 в поле Тип приложения выберите пункт Консольное приложение.
7. На странице Параметры приложения диалогового окна Мастер приложений Win32 в поле Дополнительные параметры снимите флажок Предкомпилированный заголовок.
8. Чтобы создать проект, нажмите кнопку Готово.

Использование функциональных возможностей статической библиотеки в консольном приложении

1. По завершении создания консольного приложения мастер создаст пустую программу. Имя исходного файла будет совпадать с именем, выбранным ранее для проекта. В этом примере он имеет имя MyExecRefsLib.cpp.
2. Для использования математических процедур из статической библиотеки необходимо сослаться на эту библиотеку. Для этого в меню Проект выберите пункт Ссылки.... В диалоговом окне Окна свойств разверните узел Общие свойства и выберите пункт Ссылки. Затем нажмите кнопку Добавить новую ссылку….
3. Появится диалоговое окно Добавить ссылку. В этом диалоговом окне отображается список всех библиотек, на которые можно ссылаться. На вкладке Проект перечисляются все проекты текущего решения и включенные в них библиотеки. На вкладке Проекты выберите MathFuncsLib. Затем нажмите кнопку ОК.
4. Для создания ссылки на заголовочные файлы статической библиотеки необходимо изменить путь к каталогам включения. Для этого в диалоговом окне Окна свойств последовательно разверните узлы Свойства конфигурации, C/C++, а затем выберите Общие. Рядом с полем Дополнительные каталоги включения введите путь к месту размещения заголовочного файла MathFuncsLib.h.
5. Теперь класс MyMathFuncs можно использовать в приложении. Замените код в файле MyExecRefsLib.cpp следующим кодом:

// MyExecRefsLib.cpp
// compile with: /EHsc /link MathFuncsLib.lib
#include <iostream>
#include "MathFuncsLib.h"
using namespace std;
int main()
{
 double a = 7.4;
 int b = 99;
 cout << "a + b = " <<
 MathFuncs::MyMathFuncs::Add(a, b) << endl;
 cout << "a - b = " <<
 MathFuncs::MyMathFuncs::Subtract(a, b) << endl;
 cout << "a * b = " <<
 MathFuncs::MyMathFuncs::Multiply(a, b) << endl;
 cout << "a / b = " <<
 MathFuncs::MyMathFuncs::Divide(a, b) << endl;
 return 0;
}

6. Постройте исполняемый файл, выбрав команду Построить решение в меню Построение.

Запуск приложения

1. Убедитесь, что проект MyExecRefsLib выбран в качестве проекта по умолчанию. В Обозревателе решений выберите проект MyExecRefsLib и затем в меню Проект выберите команду Назначить запускаемым проектом.
2. Чтобы запустить проект, в меню Отладка выберите команду Запуск без отладки. Результат выполнения должен выглядеть примерно следующим образом:

a + b = 106.4
a - b = -91.6
a * b = 732.6
a / b = 0.0747475

Создание и использование управляемой сборки (C++)

Следующим типом библиотеки, которую мы создадим, является управляемая сборка. Управляемые сборки являются хорошим способом повторного использования кода. Вместо того чтобы каждый раз реализовывать одни и те же подпрограммы в каждом создаваемом приложении, их можно создать единожды и затем вызывать из приложений для обеспечения соответствующей функциональности.
В этом пошаговом руководстве рассматриваются следующие действия:
• создание нового проекта библиотеки классов;
• добавление класса в библиотеку классов;
• создание приложения, ссылающегося на библиотеку классов;
• использование функциональных возможностей библиотеки классов в консольном приложении;
• запуск приложения.

Создание нового проекта библиотеки классов

1. В меню Файл выберите пункт Создать и затем пункт Проект....
2. В узле Visual C++ области Типы проектов выберите CLR. При этом будет создан проект, предназначенный для среды CLR.
3. В области Шаблоны выберите пункт Библиотека классов.
4. Выберите имя проекта, например MathFuncsAssembly, и введите его в поле Имя. Выберите имя решения, например ManagedAssemblies, и введите его в поле Имя решения.
5. Нажмите ОК, чтобы создать проект.
6. По умолчанию создаваемые проекты настраиваются на использование предкомпилированных заголовков. Чтобы отключить предкомпилированные заголовки, в меню Проект выберите Свойства. Последовательно разверните узлы Свойства конфигурации, C/C++, а затем выберите пункт Предварительно скомпилированные заголовки. В раскрывающемся списке рядом с полем Создавать или использовать предварительно скомпилированный заголовочный файл выберите пункт Не использовать предкомпилированный заголовок. Нажмите кнопку ОК для сохранения этих изменений.

Добавление класса в библиотеку классов

1. По завершении создания библиотеки классов CLR мастер создаст простейший класс. Имена файла заголовка и файла исходного кода будет совпадать с именем, выбранным ранее для проекта. В этом примере они имеют имена MathFuncsAssembly.h и MathFuncsAssembly.cpp.
2. Замените код в файле MathFuncsAssembly.h простейшим классом MyMathFuncsAssembly, осуществляющим обычные арифметические операции, такие как сложение, вычитание, умножение и деление. Код должен выглядеть примерно следующим образом:

// MathFuncsAssembly.h
using namespace System;
namespace MathFuncs
{
 public ref class MyMathFuncs
 {
 public:
 // Returns a + b
 static double Add(double a, double b);
 // Returns a - b
 static double Subtract(double a, double b);
 // Returns a * b
 static double Multiply(double a, double b);
 // Returns a / b
 // Throws DivideByZeroException if b is 0
 static double Divide(double a, double b);
 };

3. Реализуйте функциональность класса MyMathFuncs в исходном файле. Код должен выглядеть примерно следующим образом:

// MathFuncsAssembly.cpp
// compile with: /clr /LD
#include "MathFuncsAssembly.h"
namespace MathFuncs
{
 double MyMathFuncs::Add(double a, double b)
 {
 return a + b;
 }
 double MyMathFuncs::Subtract(double a, double b)
 {
 return a - b;
 }
 double MyMathFuncs::Multiply(double a, double b)
 {
 return a * b;
 }
 double MyMathFuncs::Divide(double a, double b)
 {
 if (b == 0)
 {
 throw gcnew DivideByZeroException("b cannot be zero!");
 }
 return a / b;
 }
}

4. Скомпилируйте библиотеку классов, выбрав команду Построить решение в меню Построение. В результате будет создана библиотека динамической компоновки (DLL), которая может использоваться другими программами.

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

1. Чтобы создать приложение, которое будет ссылаться и использовать созданную ранее библиотеку классов, в меню Файл выберите пункт Создать и затем пункт Проект....
2. В узле Visual C++ области Типы проектов выберите CLR. При этом будет создан проект, предназначенный для среды CLR.
3. В области Шаблоны выберите Консольное приложение CLR.
4. Выберите имя проекта, например MyExecRefsAssembly, и введите его в поле Имя. В раскрывающемся списке рядом с полем Решение выберите пункт Добавить в решение. После этого новый проект будет добавлен в то же решение, что и библиотека классов.
5. Нажмите ОК, чтобы создать проект.
6. По умолчанию создаваемые проекты настраиваются на использование предкомпилированных заголовков. Чтобы отключить предкомпилированные заголовки, в меню Проект выберите Свойства. Последовательно разверните узлы Свойства конфигурации, C/C++, а затем выберите пункт Предварительно скомпилированные заголовки. В раскрывающемся списке рядом с полем Создавать или использовать предварительно скомпилированный заголовочный файл выберите пункт Не использовать предкомпилированный заголовок. Нажмите кнопку ОК для сохранения этих изменений. Дополнительные сведения о предкомпилированных заголовках см. в разделе Создание файлов предкомпилированных заголовков.

Использование функциональных возможностей библиотеки классов в консольном приложении

1. По завершении создания консольного приложения CLR будет создана программа, выводящая на консоль приветствие "Hello World". Имя исходного файла будет совпадать с именем, выбранным ранее для проекта. В этом примере он имеет имя MyExecRefsAssembly.cpp.
2. Для использования математических процедур из библиотеки классов необходимо сослаться на эту библиотеку. Для этого в меню Проект выберите пункт Ссылки.... В диалоговом окне Окна свойств разверните узел Общие свойства, выберите пункт Ссылки, а затем нажмите кнопку Добавить новую ссылку....
3. Появится диалоговое окно Добавить ссылку. В этом диалоговом окне отображается список всех библиотек, на которые можно ссылаться. На вкладке .NET перечислены библиотеки, включенные в .NET Framework. На вкладке COM перечислены все COM-компоненты, установленные на компьютере. На вкладке Проект перечисляются все проекты текущего решения и включенные в них библиотеки. На вкладке Проекты выберите MathFuncsAssembly, после чего нажмите кнопку ОК.
4. Теперь класс MyMathFuncs можно использовать в приложении. Замените содержимое функции в файле MyExecRefsAssembly.cpp следующим кодом:

// MyExecRefsAssembly.cpp
// compile with: /clr /FUMathFuncsAssembly.dll
using namespace System;
int main(array<System::String ^> ^args)
{
 double a = 7.4;
 int b = 99;
 Console::WriteLine("a + b = {0}",
 MathFuncs::MyMathFuncs::Add(a, b));
 Console::WriteLine("a - b = {0}",
 MathFuncs::MyMathFuncs::Subtract(a, b));
 Console::WriteLine("a * b = {0}",
 MathFuncs::MyMathFuncs::Multiply(a, b));
 Console::WriteLine("a / b = {0}",
 MathFuncs::MyMathFuncs::Divide(a, b));
 return 0;
}

5. Постройте исполняемый файл, выбрав команду Построить решение в меню Построение.

Запуск приложения

1. Убедитесь, что проект MyExecRefsAssembly выбран в качестве проекта по умолчанию. В Обозревателе решений выберите проект MyExecRefsAssembly и затем в меню Проект выберите команду Назначить запускаемым проектом.
2. Чтобы запустить проект, в меню Отладка выберите команду Запуск без отладки. Результат должен выглядеть следующим образом:

a + b = 106.4
a - b = -91.6
a * b = 732.6
a / b = 0.0747474747474748

Создание DLL

Ничего особенного здесь нет. Как обычно, вы просто пишите функции, как в обычной программе. Если вы используете MSVC, создайте новый проект и укажите, что вы создаете Win32 Dynamic-Link Library, в опциях указать Пустой проект(Empty project). После компиляции вы получите DLL, библиотеку импорта (.lib) и библиотеку экспорта (.exp). Далее показан примерный код вашей DLL:

Заголовочный файл (DLLTEST.H)

#ifndef _DLLTEST_H_
#define _DLLTEST_H_ 

#include <iostream>
#include <stdio.h>
#include <windows.h> 

using namespace std;
extern "C" __declspec(dllexport) void NumberList();
extern "C" __declspec(dllexport) void LetterList(); 

#endif 

Код библиотеки (DLLTEST.CPP)

#include "dlltest.h" 
#define MAXMODULE 255 
char module[MAXMODULE]; 
extern "C" __declspec(dllexport) void NumberList() 
{
	GetModuleFileNameA(NULL, module, MAXMODULE);
 cout << "\n\nThis function was called from \n"
 << module 
 << endl << endl;
 cout << "NumberList(): ";
 for(int i=0; i<10; i++) 
 {
 cout << i << " ";
 }
 cout << endl << endl;
} 
extern "C" __declspec(dllexport) void LetterList() 
{
	GetModuleFileNameA(NULL, module, MAXMODULE);
 cout << "\n\nThis function was called from \n"
 << module 
 << endl << endl;
 cout << "LetterList(): ";
 for(int i=0; i<26; i++) 
 {
 cout << char(97 + i) << " ";
 }
 cout << endl << endl;
} 

Как видите, ничего особенного в коде нет. Приложение, используемое для примера - консольное, так что здесь просто запрограммированы две функции, выводящие текст. Строка extern "C" __declspec(dllexport) означает, что функция будет видна вне DLL (т.е. ее можно вызывать из нашей программы). После компиляции мы получим библиотеку. Теперь посммотрим, как ее можно использовать. Использование DLL без библиотеки импорта. Динамическое подключение. Чтобы загрузить DLL в программу на этапе выполнения, нужно пройти несколько шагов.
Шаг 1:
Использовать функцию LoadLibrary или LoadLibraryEx, чтобы загрузить DLL.
Шаг 2:
Использовать функцию GetProcAddress, чтобы получить указатель на интересующую нас функцию.
Шаг 3:
По окончании работы не забыть выгрузить DLL с помощью функции FreeLibrary.
В своей программе я пользовался функцией LoadLibrary. Эта функция возвращает дескриптор DLL.
Код:
HINSTANCE hDllInstance = LoadLibrary( "DLLTEST.dll");
Первый параметр - путь к DLL.
Дальше - нам нужно получить указатель на функцию. Тоесть нужно определить тип указателя. Это делается строкой (в нашем случае)
Код:
typedef void (WINAPI *cfunc)( );
Тоесть мы определили cfunc как тип, который указывает на функцию, которая без параметра и возвращает значение void. Далее - дело за малым.
Код:
cfunc NumberList;
cfunc LetterList;
NumberList=(cfunc)GetProcAddress((HMODULE)hLib, "NumberList");
LetterList=(cfunc)GetProcAddress((HMODULE)hLib, "LetterList");

Мы объявили указатель, и с помощью функции GetProcAddress получаем адрес интересующей нас функции. Первый параметр - дескриптор DLL. Второй - имя функции. Теперь можно вызывать эти функции
Код:
NumberList();
LetterList();

Исходный файл приложения, использующего библиотеку DLL - консольное приложение Win32 (DLLRUN02.EXE)

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <conio.h> 
using namespace std;

#define MAXMODULE 255 

typedef void (WINAPI *cfunc)(); 
cfunc NumberList;
cfunc LetterList; 

void main() 
{
	HINSTANCE hLib=LoadLibrary(TEXT("DLLTEST.DLL"));
 if(hLib==NULL) 
 {
 cout << "Unable to load library!" << endl;
 getch();
 return;
 } 
	char mod[MAXMODULE];

 GetModuleFileNameA((HMODULE)hLib, mod, MAXMODULE);
 cout << "Library loaded: " << mod << endl;
 NumberList=(cfunc)GetProcAddress((HMODULE)hLib, "NumberList");
 LetterList=(cfunc)GetProcAddress((HMODULE)hLib, "LetterList");
 if((NumberList==NULL) || (LetterList==NULL)) 
 {
 cout << "Unable to load function(s)." << endl;
 FreeLibrary((HMODULE)hLib);
 return;
 }
 NumberList();
 LetterList();
 FreeLibrary((HMODULE)hLib);
 getch();
}

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

Результаты работы DLLRUN02.EXE

Library loaded: C:\DLLTEST\DLLTEST.DLL 

This function was called from C:\DLLTEST\DLLRUN02.EXE
NumberList(): 0 1 2 3 4 5 6 7 8 9 
This function was called from C:\DLLTEST\DLLRUN02.EXE
LetterList(): a b c d e f g h i j k l m n o p q r s t u v w x y z