Экспортирование функций из DLL
Чтобы приложение могло обращаться к функциям динамической библиотеки, каждая из них должна занимать строку в таблице экспортируемых функций DLL. Есть два способа занести функцию в эту таблицу на этапе компиляции.
Метод __declspec (dllexport)
Можно экспортировать функцию из DLL, поставив в начале ее описания модификатор __declspec (dllexport).
Второй метод, работает с файлами определения модуля (.def), и позволяет лучше управлять процессом экспортирования.
Файлы определения модуля
Синтаксис файлов с расширением.def в Visual C++ достаточно прямолинеен, главным образом потому, что сложные параметры, использовавшиеся в ранних версиях Windows, в Win32 более не применяются. Как станет ясно из следующего простого примера,.def-файл содержит имя и описание библиотеки, а также список экспортируемых функций:
MyDLL.defLIBRARY "MyDLL"
DESCRIPTION 'MyDLL - пример DLL-библиотеки'
EXPORTS MyFunction @1
В строке экспорта функции можно указать ее порядковый номер, поставив перед ним символ @. Этот номер будет затем использоваться при обращении к GetProcAddress (). На самом деле компилятор присваивает порядковые номера всем экспортируемым объектам. Однако способ, которым он это делает, отчасти непредсказуем, если не присвоить эти номера явно. В строке экспорта можно использовать параметр NONAME. Он запрещает компилятору включать имя функции в таблицу экспортирования DLL:
MyFunction @1 NONAMEИногда это позволяет сэкономить много места в файле DLL. Приложения, использующие библитеку импортирования для неявного подключения DLL, не "заметят" разницы, поскоьку при неявном подключении порядковые номера используются автоматически. Приложениям, загружающим библиотеки DLL динамически, потребуется передавать в GetProcAddress порядковый номер, а не имя функции.
Создание проекта динамической библиотеки
· В меню Файл выберите пункт Создать, а затем пункт Проект.
· В узле Visual C++ выберите Win32 Console Application.
· Выберите имя для проекта, например DlllLib, и введите его в поле Имя. Выберите имя для решения, например DllLibrary, и введите его в поле Имя решения.
· Для запуска мастера приложений Win32 нажмите кнопку ОК. На странице Общие сведения диалогового окна Мастер приложений Win32 нажмите кнопку Далее(Next)
· На странице Параметры(Application Settings) приложения диалогового окна Мастер приложений Win32 в поле Тип (Application type) приложения выберите пункт Динамическая библиотека(DLL).
· На странице Параметры(Application Settings) приложения диалогового окна Мастер приложений Win32 в поле Дополнительные параметры(Additional options) установите флажок пустой проект (Empty project).
· Чтобы создать проект, нажмите кнопку Готово(Finish).
Вариант без использования классов:
// mydll.h
__declspec(dllexport) void Msg (char* msgstr);
// mydll.cpp
#include "Windows.h"
#include <stdexcept>
#include "mydll.h"
using namespace std;
void Msg(char* msgstr)
{
MessageBox(NULL, msgstr, "Message from DLL", MB_OK);
}
Скомпилируйте библиотеку, выбрав команду Построить решение (Build Solution) в меню Построение(Build).
: error C2664: 'MessageBoxW': cannot convert parameter 2 from 'char *' to 'LPCWSTR'
Исправить установив Character Set
В результате будет создана динамическая библиотека, которая может использоваться другими программами (..\dynamicLibrary\Debug\dlllib.lib и..\dynamicLibrary\Debug\dlllib.dll).
Создание консольного приложения, ссылающегося на динамическую библиотеку
· В меню Файл выберите пункт Создать, а затем пункт Проект.
· В узле Visual C++ выберите Win32 Console Application.
· Выберите имя для проекта, например Calldll, и введите его в поле Имя.
· Для запуска мастера приложений Win32 нажмите кнопку ОК. На странице Общие сведения диалогового окна Мастер приложений Win32 нажмите кнопку Далее(Next)
· На странице Параметры(Application Settings) приложения диалогового окна Мастер приложений Win32 в поле Тип (Application type) приложения выберите пункт Консольное приложение(Console application)
· На странице Параметры(Application Settings) приложения диалогового окна Мастер приложений Win32 в поле Дополнительные параметры(Additional options) выберите пункт (Empty project).
· Чтобы создать проект, нажмите кнопку Готово(Finish).
Добавьте файл программы primer.cpp(Add/New item …/C++ file)
#include "mydll.h"
int main(int argc, char* argv[])
{
Msg("Hello, world!");
return 0;
}
Для использования библиотеки необходимо сослаться на эту библиотеку.
Для этого в меню Проект выберите пункт Свойства проекта(Project/CallDll Properties …).
Для создания ссылки на динамическую библиотеку
1. Разверните узел Linker/Input и выберите команду дополнительные ссылки(Additional Dependencies), выберите пустую строку, и нажмите кнопку с многоточием (…) в конце строки. В окне введите имя библиотеки dlllib.lib и нажмите ОК.
2. Разверните узел Linker/General и выберите команду дополнительные каталоги для библиотек (Additional Library Directories), выберите пустую строку, и нажмите кнопку с многоточием (…) в конце строки. В диалоговом окне Выбор каталога нажмите кнопку Выбор папки и выберите каталог, где располагается файл библиотеки dlllib.lib.
В диалоговом окне Дополнительные каталоги включаемых файлов нажмите кнопку ОК чтобы сохранить выбранные значения и закрыть диалоговое окно.
Для создания ссылки на заголовочный файл
Разверните узел С/С++ /General и выберите команду Дополнительные каталоги включаемых файлов (Additional Include Directories), выберите пустую строку, и нажмите кнопку с многоточием (…) в конце строки. В диалоговом окне Выбор каталога нажмите кнопку Выбор папки и выберите каталог, где располагается файл mydll.h. В диалоговом окне Дополнительные каталоги включаемых файлов нажмите кнопку ОК чтобы сохранить выбранные значения и закрыть диалоговое окно.
Постройте исполняемый файл, выбрав команду Построить решение в меню Построение.
Запуск приложения
Ошибка – Не найдена библиотека dlllib.dll
Исправить – скопировать файл dlllib.dll в папку Debug(туда где находится исполнимый файл.exe)
Вариант с классом проект DLLCLASS
(должны совпадать имя проекта и #ifdef DLLCLASS_EXPORTS)
TRational.h
#ifndef _DROB_H
#define _DROB_H
#ifdef DLLCLASS_EXPORTS
#define DLL_EI __declspec(dllexport)
#else
#define DLL_EI __declspec(dllimport)
#endif
#include <string>
using namespace std;
class DLL_EI TRational{
long chis,zn;
void Reduce();
int NOD(long x, long y);
public:
TRational(const long &c=0, const long &z=1);
TRational(const int &c, const int &z);
TRational(const double &r);
string toString();
TRational Add(const TRational &r);
TRational operator +(const TRational &r);
TRational operator +(const long &r);
TRational& operator +=(const TRational &r);
DLL_EI friend ostream& operator >>(ostream &t, const TRational &r);
};
#endif
TRational.cpp
#include "TRational.h"
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int TRational::NOD(long x, long y){
if(y==0)return x;else return NOD(y, x%y);
}
void TRational::Reduce(){
long t;
t = NOD (chis,zn);
chis /= t;
zn /= t;
}
TRational::TRational(const long &c,const long &z):chis(c),zn(z){
if (zn==0) {cout<<"Error - divide by zero"; exit;}
Reduce();
}
TRational::TRational(const int &c, const int &z):chis(c),zn(z){
if(zn==0){cout<<"Error - divide by zero"; exit;}
Reduce();
}
TRational::TRational(const double &r){
double val1, val2;
val1 = r*10000000L; val2 =r* 1000000L;
chis = long(val1 -val2);
zn = 90000000L;
Reduce();
}
string TRational::toString(){
stringstream ss (stringstream::in | stringstream::out);
string str;
ss << chis<<'/'<<zn;
ss >> str;
return str;
}
TRational TRational::Add(const TRational &r){
TRational t =*this;
t.zn *=r.zn;
t.chis = t.chis * r.zn + r.chis * t.zn;
t.Reduce();
return t;
}
TRational TRational::operator +(const TRational &r)
{
TRational t =*this;
t.zn *=r.zn;
t.chis = t.chis * r.zn + r.chis * t.zn;
t.Reduce();
return t;
}
TRational& TRational::operator +=(const TRational &r){
chis = chis * r.zn + r.chis * zn;
zn *=r.zn;
Reduce();
return *this;
}
TRational TRational::operator +(const long &r){
TRational t(r);
t += *this;
t.Reduce();
return t;
}
#include <iostream>
#include "TRational.h"
using namespace std;
int main(){
TRational t(5,10),p(10,5);
cout<<t.toString()<<endl<<p.toString()<<endl;
TRational t1;
t1 = t.Add(p);
cout<<t1.toString()<<endl;
t1 = t + p;
cout<<t1.toString()<<endl;
t1 += p += t;
cout<<t1.toString()<<endl;
cout<<p.toString()<<endl;
p = p + 5;
cout<<p.toString()<<endl;
//p = 5 + p;
//cout<<p.toString()<<endl;
system("pause");
return 0;
}