Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Ада и другие языки _ Dll.

Автор: Fanat 19.10.2007 22:39

Хочу создать файл Dll. Делаю так File->New->Other->Dll wizard
Там забиваю:


#include <windows.h>
extern "C" __declspec(dllexport)
double AddNumbers(double a, double b)
{
return a + b;
}



Помимо этого там ещё есть функция аналог main. Как правильно сохранить? Я жму сохранить и сам подписываю после точки расширение .dll... После чего открыть этот файл заново не получаеться.
Нам ещё сказали на занятиях что автоматически должен создаться файл .lib? И зачем он мне ещё предлогает сохранить проект какойто который я не создавал?...



Автор: volvo 19.10.2007 22:58

Что я только что сделал:

Открыл Билдер, File -> New -> Other -> Dynamic Link Library...

В диалоговом окне отключил все примочки VCL и Multi-Threading-а, сделал язык не С++, а С.

Открывается редактор:

#include <windows.h>

// Тут много букв - это пока неважно ...

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
//---------------------------------------------------------------------------



Добавляю, собственно, твою функцию... Получаю такой файл:

#include <windows.h>

#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endif


double DLL_EXPORT AddNumbers(double a, double b)
{
return a + b;
}

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}

Сохраняю этот проект, причем файл сохраняется с расширением *.С... Билдим проект - получаем DLL вместо EXE...

Автор: Fanat 19.10.2007 23:19

Сделал так. Получил .dll.
Теперь в другом проекте.



#include <windows.h>
#include <stdio.h>
#define BUILD_DLL

//...

void __fastcall TForm1::Button1Click(TObject *Sender)
{
typedef int(*importFunction)(int, int);

importFunction addNumbers;
int result;

HINSTANCE hinstLib = LoadLibrary("Project2.dll");
addNumbers = (importFunction)GetProcAddress(hinstLib, "AddNumbers");

result = addNumbers(1, 2);
Edit1->Text=IntToStr(result);

FreeLibrary(hinstLib);
}



Что то не так. Файл Project2.dll лежит в тойже папке что и файлы этого проекта.

Автор: volvo 20.10.2007 0:02

DLL:


#include <windows.h>

double __declspec(dllexport) CALLBACK AddNumbers(double a, double b)
{
return a + b;
}

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}



Проект:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
typedef double(CALLBACK *importFunction)(double, double);

importFunction addNumbers;
int result;

HINSTANCE hinstLib = LoadLibrary("Project2.dll");
addNumbers = (importFunction)GetProcAddress(hinstLib, "AddNumbers");

result = addNumbers(1, 2);
Edit1->Text=IntToStr(result);
FreeLibrary(hinstLib);
}

Все работает...

Автор: Fanat 20.10.2007 0:35

Спсибо разобрался... smile.gif

Автор: Fanat 21.10.2007 17:29

А если необходимо создать .dll в котором описаны методы класса...это как сделать?...
Надо ли изменять или создавать файл .h или что то похожее?..

Автор: volvo 21.10.2007 18:40

Ничего не надо ни изменять ни создавать заново. Один и тот же H-файл может использоваться и для DLL, и для использующей ее программы. Только в DLL класс должен описываться как

class __declspec (dllexport) MyClass {
...
};

а в программе - как
class __declspec (dllimport) MyClass {
...
};
(элементарно делается с использованием #ifdef)

Автор: Fanat 21.10.2007 18:59

Пишу в файле который хочу чтобы был .dll с описанием методов класса.

  
// #include "A.h"
// class __declspec(dllimport) A; Что то из этого нужно?

extern "C" __declspec(dllexport)
void A::setC(int anC)
{
C=anC;
};



Тогда в A.h (тот который должен относиться к .dll) что должно быть?


class __declspec(dllexport) A
{
public:
virtual void setC(int anC);
private:
int C;
};


Автор: volvo 21.10.2007 19:56

Используя LoadLibrary ты замучаешься работать с классом из DLL. Вот тут лежит пример, посмотри:
http://www.codeproject.com/dll/classesexportedusingLL.asp

Гораздо проще работать с LIB-файлом. Для этого случая:

Подключаемый к DLL-проекту header:

class __declspec(dllexport) MyClass {

public:
MyClass(int);
virtual void setConsumerID(int);
int getConsumerID();
private:
int ConsumerID;

};


В подключаемом к основному проекту заменить dllexport на dllimport
Собственно, код библиотеки:

#include <windows.h>
#include "MyClass.h"

MyClass::MyClass(int value) {
ConsumerID = value;
}
void MyClass::setConsumerID(int value) {
ConsumerID = value;
}
int MyClass::getConsumerID() {
return ConsumerID;
}


#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}



Использование (подключаем H-файл с описанием класса и LIB-файл через "Project -> AddToProject -> имя_файла.LIB"):
void __fastcall TForm1::Button1Click(TObject *Sender)
{

MyClass my(10);
ShowMessage(IntToStr(my.getConsumerID()));
}

Автор: Fanat 21.10.2007 21:16

Сделал как ты написал. Спасибо работает. Но является ли это динамической загрузкой.
Исходя из примера пишу HMODULE hMod = LoadLibrary ("ProjectDll.dll") выдаёт ошибку.
Как её загрузить?

Пишу так:


{
typedef int (*importFunction)();
importFunction getConsumer;
HMODULE hMod = LoadLibrary ("ProjectDll.dll");//<--Или .lib?
getConsumer = (importFunction)GetProcAddress(hMod, "getConsumer");
MyClass my(10);
ShowMessage(IntToStr(my.getConsumerID()));
}



Автор: volvo 21.10.2007 21:29

Вообще-то с LoadLibrary проблем быть не должно. У меня по крайней мере оно работает... А вот getConsumer - нулевой...

А это:

...
MyClass my(10);
...

работать не будет, потому как тело конструктора описано тоже в библиотеке, и надо брать адрес конструктора (и вызывать его по адресу), чтобы инициализировать объект.

Автор: Fanat 21.10.2007 22:02

Цитата(volvo @ 21.10.2007 18:29) *

работать не будет, потому как тело конструктора описано тоже в библиотеке, и надо брать адрес конструктора (и вызывать его по адресу), чтобы инициализировать объект.


А как конструктор описать и взять по адресу?
Пробовал через указатели сделать, но никак не получаеться wacko.gif

Автор: volvo 21.10.2007 22:50

http://forum.sources.ru/index.php?showtopic=42324&view=findpost&p=1468727 есть довольно подробное объяснение процесса (и альтернативы тоже)...

Автор: Fanat 21.10.2007 23:45

Цитата(volvo @ 21.10.2007 19:50) *

http://forum.sources.ru/index.php?showtopic=42324&view=findpost&p=1468727 есть довольно подробное объяснение процесса (и альтернативы тоже)...


Во...спасибо...3ий вариант ето то что нужно...а с помощью чего можно открыть файл который разопхивируеться?.. Я так понимаю там пример...он бы мне сильно помог...=)

Автор: volvo 21.10.2007 23:53

blink.gif У меня третьим WinRar-ом свободно открылся...

Автор: Fanat 22.10.2007 0:03

Цитата(volvo @ 21.10.2007 20:53) *

blink.gif У меня третьим WinRar-ом свободно открылся...


Я в смысле тот файл что внутри лежит...

Автор: volvo 22.10.2007 0:22

А что там внутри у тебя не открывается? BPR - файлы проекта, открывай их и компилируй DLL-ку и саму программу...

Автор: Fanat 22.10.2007 0:35

Цитата(volvo @ 21.10.2007 21:22) *

А что там внутри у тебя не открывается? BPR - файлы проекта, открывай их и компилируй DLL-ку и саму программу...


Просто мне почему то пришлось дважды его разорхивировать и появились все файлы...

Автор: Fanat 22.10.2007 2:20

Всё!!! good.gif ...у меня получилось...спасибо огромное...только вопрос один:
откуда вообще в процессе работы программы берёться то что необходимо обратиться к файлу
КлассНаследник.cpp ведь ни один файл его не включает в себя?..

Автор: volvo 22.10.2007 2:34

Цитата
ни один файл его не включает в себя?

FormTestDLL.H:

typedef IMyCls * (__declspec(dllimport) FCreate(int Size));
...
class TfrmTestDll : public TForm {
...
FCreate * Create; // <--- это что по-твоему?
...
};

Автор: Fanat 22.10.2007 2:39

Цитата(volvo @ 21.10.2007 23:34) *

FormTestDLL.H:

typedef IMyCls * (__declspec(dllimport) FCreate(int Size));
...
class TfrmTestDll : public TForm {
...
FCreate * Create; // <--- это что по-твоему?
...
};



Это обьявление указателя на FCreate. А FCreate это ???

Ну а FCreate это вроде функтор.

Автор: volvo 22.10.2007 2:55

Если честно - я не понял, что тебя смущает вообще... У тебя же в DLL создается экземпляр класса-наследника (т.е., MyCls). То, что указатель на него приводится к указателю на предка (то есть, к IMyCls *) - это тебя смущает?

Автор: Fanat 22.10.2007 2:59

Цитата(volvo @ 21.10.2007 23:55) *

Если честно - я не понял, что тебя смущает вообще... У тебя же в DLL создается экземпляр класса-наследника (т.е., MyCls). То, что указатель на него приводится к указателю на предка (то есть, к IMyCls *) - это тебя смущает?


Это не смущает. Смущало то что файл MyCls.cpp нигде не подключался...а он собственно и в обычных программах нигде не поключаеться...

Теперь всё понятно...ещё раз спасибо...

Автор: volvo 22.10.2007 3:27

Как это "не подключается?"

А в DBTEST.BPR что такое:

Цитата
<VERSION value="BCB.05.03"/>
<PROJECT value="&quot;F:\PROJECTS\Cut Expert\DBTEST2\bin\dbtest.dll&quot;"/>
<OBJFILES value="obj\dbm.obj obj\mycls.obj"/>

в нижней строке? smile.gif Файл подключается к проекту и участвует в сборке библиотеки...

Автор: Fanat 22.10.2007 3:30

То есть таким образом он подключаеться. Буду знать.

Автор: Fanat 22.10.2007 23:59

Вот прочитал help на который ты давал ссылку...
откуда взяться файлу .def?..самому создать?..
И как узнать как назвал компилятор мою функцию?..

Автор: volvo 23.10.2007 0:37

Цитата
откуда взяться файлу .def?
Сбрось свою DLL-ку в каталог \BIN в папке Builder-а, и запусти
Цитата(Console)
E:\Program Files\Borland\BDS\4.0\Bin>impdef project.def project3.dll
(ну, со своим именем DLL естественно)

В результате в той же папке появляется файл project.def, который содержит, например, такое:
LIBRARY     PROJECT3.DLL

EXPORTS
@MyClass@$bctr$qi @1 ; MyClass::MyClass(int)
@MyClass@getConsumerID$qv @3 ; MyClass::getConsumerID()
@MyClass@setConsumerID$qi @2 ; MyClass::setConsumerID(int)
@std@nothrow @5 ; std::nothrow
___CPPdebugHook @4 ; ___CPPdebugHook
В первом столбце - то, что тебе нужно...

Автор: Fanat 23.10.2007 0:59

Это через DOS в смысле?
Он ругаеться на то что Program Files отдельно написано...

Автор: volvo 23.10.2007 1:07

Это через Start -> Run -> CMD ...

то, что до знака ">" - это системное приглашение, тебе надо войти в папку \BIN... А там уже напечатать то, что выделено красным...

Автор: Fanat 23.10.2007 1:11

Цитата(volvo @ 22.10.2007 22:07) *

Это через Start -> Run -> CMD ...

то, что до знака ">" - это системное приглашение, тебе надо войти в папку \BIN... А там уже напечатать то, что выделено красным...


Так я так и делал...только он мне не даёт переместиться в папку Program Files...потому что написание раздельное...

Автор: volvo 23.10.2007 1:25

Возьми в кавычки... То есть,
CD "диск_на_котором_у_тебя_билдер:\Program Files\Borland\ну_и_дальше_путь_к_папке" должно дать то же результат...

Автор: Fanat 23.10.2007 1:39

Получил. Так теперь можно задать имя функции своё?

Код
LIBRARY     TWOFUNCPROJECT.DLL

EXPORTS
    @Create$qv                     @1  ; Create()


Переместить этот файл в папку где находиться проект dll и потом заново build?..

Автор: volvo 23.10.2007 1:52

Цитата
Так теперь можно задать имя функции своё?
Никак... Тебе это не нужно. Все что тебе может понадобиться - взять отсюда имя, и использовать его в программе, если тебе нужно сделать GetProcAddress...

Автор: Fanat 23.10.2007 1:54

Понянто...спасибо...