Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Dll - статическое подключение


Автор: NiJazz 17.4.2005, 14:01
У меня есть DLL и Lib к ней - by MSVC++.
Как с помощью lib в С++ Builder подключить мою DLL?

Автор: NiJazz 17.4.2005, 17:41
Я беру dll без lib и прогоняю её через утилиту implib. Создаётся lib типа OMF, то есть подходящая для билдера. В коде подключаю её:
Код

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

#pragma comment (lib, "1.lib")  // Подключаем lib

void Test();


TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Test();
}
//---------------------------------------------------------------------------

Вот что получаю:
Цитата
[Linker Error] Unresolved external 'Test()' referenced from C:\PROGRAM FILES\BORLAND\CBUILDER6\PROJECTS\1\UNIT1.OBJ

В чём тут может быть дело? smile
PS Где в свойствах проекта в билдере можно указать подключаемые библиотеки?
Добавлено @ 17:43
Забыл сказать, что в проекте VC++ я указал, что экспортировать функцию нужно понятно для других компилеров, поэтому impdef и прочие не помогут.
Добавлено @ 17:44
Экспортируемая DLL функция:
Код

__declspec(dllexport) void __stdcall Test()
{
    MessageBox(NULL, "Hello, Builder!", "Hello", MB_OK | MB_ICONINFORMATION);
}

Автор: Vyacheslav 18.4.2005, 10:13
View->Project Manager->правая клавиша мышки на проекте->всплывающее меню-> Add

Автор: NiJazz 18.4.2005, 16:31
Мне ж не cpp, a lib нужно добавить.

Автор: _hunter 18.4.2005, 16:41
есть у меня подозрение что для статической линковки заголовочный файл нужен...

Автор: Vyacheslav 18.4.2005, 16:46
И что из этого? Уже начинает надоедать. Говоришь как надо делать. Вместо того, чтобы сделать как сказали, начинаются теоретические рассуждения.
Ты пробовал? Уверен, что нет.
Если религиозные убеждения не позволяют воспользоваться этим советом, вставляй через
Код

#pragma link 

Автор: NiJazz 20.4.2005, 14:41
Vyacheslav
Теории тут нет, просто невнимательность.
До этого я подключал прагмой.


_hunter
Ну h-файл конечно есть. smile Без него мы до линковки бы даже не дошли. smile

Автор: Bima 5.2.2007, 13:11
Ситуация, как в теме, только за исключением того, что нет *.h файла.
Короче говоря есть Dll и я могу сделать lib через утилиту implib, еще известны какие там функции с параметрами вызова.

Если добавляю через View->Project Manager... Add, то насколько я понимаю, нет заголовочного файла, где описаны функции, поэтому, при вызове этих функций, компилятор ругается.

как правильно сделать, если есть test.dll (созданая не мной, на Delphi, исходников нет) и в этой dll, есть функция:
test: function (param1: PChar): Boolean cdecl;

Предпологаю, что ее нужно наверно записать как bool test(char* param1);


Автор: Bima 5.2.2007, 15:59
Динамически я могу подключить эту dll.

код при динамическом подключении такой:

*.h
Код

//---------------------------------------------------------------------------

#ifndef kodH
#define kodH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>

typedef bool(*pTest)(char *param1);
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
   TLabel *Label1;
   TButton *Button1;
        void __fastcall FormDestroy(TObject *Sender);
        void __fastcall Button1Click(TObject *Sender);
   void __fastcall FormCreate(TObject *Sender);
private:    // User declarations
        HINSTANCE dllinstance;
public:        // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif


*.cpp
Код

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "kod.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner){}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
int Ret;
dllinstance = LoadLibrary("Test.dll");
if(!dllinstance) // если dll не была загружена
   {
   Application->MessageBox("Не могу найти Test.dll. Она должна где-то быть!","Ошибка",MB_ICONWARNING);
   return;
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
FreeLibrary(dllinstance);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
bool Ret;
AnsiString aaa="a";
pTest Test= (pTest)GetProcAddress(dllinstance,"Test");
Ret=Test(aaa.c_str());
if (Ret)
   Application->MessageBox("true","Cool",MB_ICONWARNING);
else
   Application->MessageBox("false","Cool",MB_ICONWARNING);
}
//---------------------------------------------------------------------------


Неудобно постоянно получать адрес функции. У меня этих функций в dll штук 20 и постоянно узнавать их адрес, как то не удобно, хотелось бы один раз объявить эти функции и пользоваться.

Автор: Bima 6.2.2007, 10:41
Пытаюсь статически подключить так:
создал файл test.h
Код

__declspec(dllimport) bool test(char *param1);



В *.cpp пишу так:

Код

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "kod.h"
#include "test.h"
#pragma comment(lib,"test.lib")
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner){}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
bool Ret;
AnsiString aaa="a";
Ret=Test(aaa.c_str());
if (Ret)
   Application->MessageBox("true","Cool",MB_ICONWARNING);
else
   Application->MessageBox("false","Cool",MB_ICONWARNING);

}
//---------------------------------------------------------------------------

при компилировании мне выдает ошибку:

[Linker Error] Unresolved external 'test(char *)' referenced from C:\MY PROJECT FOR C++ BILDER\test\KOD.OBJ

Автор: Vyacheslav 6.2.2007, 11:16
Bima, 
Вы весь топик внимательно читали?
Создатель топика начинал с
Код

#pragma comment (lib, "1.lib")  

Ему вежливо намекнули, что он не прав. Надо либо
Цитата(Vyacheslav @  18.4.2005,  10:13 Найти цитируемый пост)
View->Project Manager->правая клавиша мышки на проекте->всплывающее меню-> Add 

либо использовать
Код

#pragma link “test.lib”

А Вы опять на те же грабли 
Код

#pragma comment(lib,"test.lib")

Эта штука не работает. Уж не знаю почему, но неработает

Автор: Bima 6.2.2007, 11:28
читал и пробовал!!!
когда делаю через View->Project Manager->правая клавиша мышки на проекте->всплывающее меню-> Add (кстати я упоминал что и так делал), то ошибка таже самая:
Код

[Linker Error] Unresolved external 'test(char *)' referenced from C:\MY PROJECT FOR C++ BILDER\test\KOD.OBJ


когда делаю через 
Код

 #pragma link “test.lib” 

то же выскакивает ошибка 
Код

[Linker Error] Unresolved external 'test(char *)' referenced from C:\MY PROJECT FOR C++ BILDER\test\KOD.OBJ




Автор: bilbobagginz 6.2.2007, 11:31
дык а переменная test вида char*, это переменная из твоей либы или как ?


Автор: Bima 6.2.2007, 11:47
или как...
я знаю как функция объявлялась, когда писалась....

bool Test(char *param1);

либ я сделал с помощью implib

Dll работает, проверялась на дельфи и мой код динамического присоединения (см. выше).

Автор: Vyacheslav 6.2.2007, 14:13
Цитата(Bima @  5.2.2007,  13:11 Найти цитируемый пост)
test: function (param1: PChar): Boolean cdecl;

Код

 __declspec(dllimport) __cdecl  bool test(char *param1);



Добавлено @ 14:16 
Виноват. Скорее всего так
Код

extern "C"  __declspec(dllimport)   bool test(char *param1);

Автор: Bima 6.2.2007, 15:59
пробовал, выдает:
Код

[Linker Error] Unresolved external '_test' referenced from C:\MY PROJECT FOR C++ BILDER\TEST\KOD.OBJ

Автор: Vyacheslav 6.2.2007, 16:15
Цитата(Bima @  6.2.2007,  11:47 Найти цитируемый пост)
bool Test(char *param1);

так test или Test ?

Автор: Bima 7.2.2007, 06:47
объявлялась в dll как Test.
но пробовал по всякому(и с маленькой и с большой буквы), не помогает

Автор: dumb 7.2.2007, 10:57
осталось только __stdcall воткнуть в обявление Test'а этого... smile

Автор: Bima 7.2.2007, 15:42
Уже лучше, компилится проект стал. При запуске выдает, что нет определенной dll, нужной для работы вызываемой dll, "повторный запуск приложения исправит эту проблему".

Незнаю, кто писал эту Dll smile. Сегодня исходники достал, буду изучать и попытаюсь обойтись без этой dll.
всем спасибо

Автор: Lotrex 7.2.2007, 15:58
Не спеши расстраиваться, это решаемая проблема. :-)
счас напишу ответ.

Автор: Lotrex 7.2.2007, 16:23
Все дело в том, что C++ Builder и MSVC (черт бы побрал их обоих :-)) по разному
понимают слова __stdcall и __cdecl. То есть объявления и тут и там одинаковые,
а после компиляции получается совсем разное (я уж не говорю про ситуацию, 
кагда в начале опущено extern "C" )

Вот такое объявление функции:

extern "C" __declspec(dllexport) int __stdcall  Test(const char *);

после компиляции Builde-ром версии 5.0 никак не изменит исходное имя функции - в 
объектном файле так и будет сидеть Test

то же самое объявление после компиляции MSVC 6.0 у меня дало в объектном 
файле _Test.

Какой напрашивается выход?

Если функция в исходнике DLL-ки объявлена например как

extern "C" __declspec(dllexport) int __stdcall  Test(const char *);

то в заголовочном файле, который будет для Builde-ра надо написать 
то же имя функции, но с черточкой впереди:

extern "C" __declspec(dllexport) int __stdcall  _Test(const char *);

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

Разумеется, все это работает тока в том случае, если Вы сделали .lib файл
с помощью implib и вставили его (этот .lib-файл) в Ваш проект.

Вот мои художества:

Этот файл компилился в MSVC 6.0 как dll:

Код

#include <windows.h>

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    return TRUE;
}

extern "C" __declspec(dllexport)  int __stdcall Test(const char *str)
{
    MessageBox(NULL, str, "Hello", MB_OK | MB_ICONINFORMATION);
    return 1;
}


Это тексты заголовочного файла и тестовой проги в Builde-ре:

Код

//Заголовок:
#ifndef ___MSVC_DLL_TEST
#define ___MSVC_DLL_TEST

extern "C" __declspec(dllexport) int __stdcall  _Test(const char *);

#endif

//Прога:
//---------------------------------------------------------------------------
#include <windows.h>
#pragma hdrstop
#include "testdll.h"
//---------------------------------------------------------------------------
#pragma argsused
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    _Test("Привет, мир!");
    return 0;
}
//---------------------------------------------------------------------------


Автор: Bima 8.2.2007, 07:09
Мдя, смотрел исходники... они изрядно удивили меня smile
они там объявляются без всяких extern "C" или __declspec(dllexport)  или __stdcall
вот кусок кода заголовочного файла:
Код

bool Test(char *param1);
// -----------------------------------------------------------------------
// Проверка состояния проекта (в данном случае проверка ТОЛЬКО на останов)
int ProjectStatus(void);

Писалось на MSVC 6.0. Вот и думаю, либо пересобрать DLL заново только по нормальному объявлять функции, либо напрямую использовать свои функции в проекте.

Кстати, если выполнить команду impdef Test.def Test.dll
то в файле Test.def, можно увидеть название всех функций без всяких подчеркиваний smile

Автор: Lotrex 8.2.2007, 09:12
Цитата

Писалось на MSVC 6.0. Вот и думаю, либо пересобрать DLL заново только по нормальному объявлять функции, либо напрямую использовать свои функции в проекте.

Кстати, если выполнить команду impdef Test.def Test.dll
то в файле Test.def, можно увидеть название всех функций без всяких подчеркиваний


Приведенный мной текст dll-ки после компиляции и выполнения команды

impdef testdll.def testdll.dll

дает такой результат(содержимое файла testdll.def):
Код

LIBRARY     TESTDLL.DLL

EXPORTS
    _Test@4                       =_Test                          @1

Странно, что у Вас нет подчеркиваний... Или у нас объявления отличаются... А может, дело в ключах компилятора 
MSVC? У меня был следующий набор ключей:
/nologo /MTd /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" 
/D "TESTDLL_EXPORTS" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c

Цитата

Мдя, смотрел исходники... они изрядно удивили мен
они там объявляются без всяких extern "C" или __declspec(dllexport)  или __stdcall
вот кусок кода заголовочного файла:

Код

 bool Test(char *param1);
// -----------------------------------------------------------------------
// Проверка состояния проекта (в данном случае проверка ТОЛЬКО на останов)
int ProjectStatus(void);



Если не использовать extern "C" то компилятор С++ будет модифицировать
имена функций как взбрело в голову создателю данного компилятора. И подключить такую
dll, если она скомпилирована на MSVC, к проге на C++ Builder вряд ли возможно.
Я изменил приведенный мной выше текст dll-ки следующим образом(убрал extern "C"):
Код

#include <windows.h>

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                )
{
    return TRUE;
}
//extern "C"
__declspec(dllexport)  int __stdcall Test(const char *str)
{
    MessageBox(NULL, str, "Hello", MB_OK | MB_ICONINFORMATION);
    return 1;
}

После компиляции в MSVC 6.0 и после компиляции и выполнения команды
impdef testdll.def testdll.dll
получается такой результат:
Код

LIBRARY     TESTDLL2.DLL

EXPORTS
    ?Test@@YGHPBD@Z                @1


Так что я думаю, что Вам надо перед всеми функциями поставить новые
объявления, например так:
Код

#define EXPORT(type) extern "C" __declspec(dllexport) type __stdcall

EXPORT(bool) Test(const char *str);



Автор: Bima 8.2.2007, 11:28
вот что я получил после команды impdef test.def test.dll:

Код

LIBRARY     TEST.DLL

EXPORTS
    Test                  @1   ; Test
    ProjectStatus                  @2   ; ProjectStatus
//другие функции


какие команды были при компиляции я не знаю

Цитата

Так что я думаю, что Вам надо перед всеми функциями поставить новые
объявления, например так:

#define EXPORT(type) extern "C" __declspec(dllexport) type __stdcall

EXPORT(bool) Test(const char *str);

поставлю MSVC и попробую

Автор: Vyacheslav 8.2.2007, 11:40
MSVC может обходится без __declspec(dllexport), по-скольку у него есть возможность просто задать имена функция, которые будут экпортироваться, в def -файле с помощью ключевого слова EXPORT
Цитата

Note that when you export a variable from a DLL with a .def file, you do not need to specify __declspec(dllexport) on the variable. However, in any file that uses the DLL, you must still use __declspec(dllimport) on the declaration of data.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)