Страница 1 из 2

DLL

Добавлено: 08 дек 2004, 21:51
xpymep
Помогите пожалуйста! Я программирую недолго и столкнулся с такой проблемой: У меня есть какая-то длл и я никак не могу ее использовать.. :( . Код на писан на C++ Builder

Код: Выделить всё

bool success = false;
void *lib = LoadLibrary(AnsiString(GetCurrentDir()+"\\testdll.dll").c_str());
if (lib != NULL)
              {
                func =   GetProcAddress(lib,"sleep");
                success = (func != NULL);
                  if (success)
                   {
                        func ();
                   }
                  else
                   {
                       ShowMessage("Функция не загрузилась");
                   }
                    if(!FreeLibrary(lib))
                      {
                         ShowMessage("Память не освобождена");
                       }
А вот код дллки:

Код: Выделить всё

void __export sleep(int s)
 {
  Sleep(s);
 }
При работе программа не может загрузить функцию. Скажите пожалуйста где моя ошибка ? :)

Добавлено: 09 дек 2004, 11:41
Kolinus
По-моему результат функции GetProcAddress() надо приводить к нужному типу - типу функции

Добавлено: 09 дек 2004, 12:13
Romeo
Kolinus, проблема в том, что функция не может загрузиться, а не в том, что она не может правильно вызваться. xpymep, истоки скорее всего в том, что експортное имя функции в DLL не соответствует её "программному" имени. Например Visual C++ компилятор добавляет в конец имени число параметров и список типов параметров с определённым скриптованием. Для того, чтобы насильно задать экспортное имя нужно использовать def файл (опять таки этот выход именно для Visual C++). Ещё одно замечание, если DLL-ка сделана с поддержкой MFC, то приблема не возникает: MFC в своих дебрях это разруливает.

Добавлено: 09 дек 2004, 12:33
Eugie
xpymep, объяви свою функцию так:

Код: Выделить всё

extern "C" __export void __stdcall sleep(int s);

Добавлено: 09 дек 2004, 17:53
xpymep
Гы...Большое спасибо вам! Вся проблема была в объявлении func...

Код: Выделить всё

 //У мя вначале было так :
int (__stdcall* func) (void);
//Естественно прога не могла найти такую функцию... Надо было так:
void (__stdcall* func) (int);
Да,кстати без объявления функции методом:

Код: Выделить всё

extern "C" __export void __stdcall sleep(int s); 
в самой дллки,прога не работала,так что отдельное спасибо Eugie!
Да,кстати я пытался найти ошибку около месяца...при том работал на двух разных компах с разными примерами :) и всеравно не работало :) .
Еще вопросик: "Какая разница в использовании?":

Код: Выделить всё

void __export func();
extern "C" void __export func();
void __declspec(dllexport) func();
У мя первый вариант чаще всего работал (через раз,а оствльные вообще не работали). Да и имеет ли смылс менят __stdcall на __fastcal илиl __msfastcall в дллках, некоторые "спецы" (моя училка по программированию :) ) говорят,что если использовать не __stdcall, то функция будет работать стабильно. Так ли ? Ведь если использовать __fastcall можно было бы добиться более быстрой работы проги,используя extended регистры...

Добавлено: 09 дек 2004, 18:31
Eugie
"Какая разница в использовании?"...
__declspec(dllexport) - вариант MS
__export - Borland (в ранних версиях MS тоже использовался)

Объявление extern "C" задает тип связывания, характерный для C (т.е. без украшений имен в объектных файлах, как в C++). Это полезно, когда требуется вызывать функции, написанные на разных языках или из динамически загружаемых dll, как у тебя.

Вообще, есть два базовых понятия: naming convention и calling convention. Первое определяет, как будет выглядеть имя экспортируемой функции после компиляции, а второе - в как передаются параметры в функцию (порядок, кто организует т.н. стековый кадр и т.д.) Вещи это важные, как ты уже убедился :) Если не согласовано первое, то просто ничего не соберется, т.к. линкер не найдет имени, которое ожидает. Если второе - еще хуже: соберется, но не будет работать.

О разнице между __stdcall и __fastcall - посмотри сам в MSDN. Насчет 'если использовать не __stdcall, то функция будет работать стабильно' - полная чушь. Еще на быстродействии это может сказаться, но уж никак не на стабильности.

Добавлено: 09 дек 2004, 18:47
Romeo
Верно, заявление о стабильности - бредни. Либо работает, либо не работает. Вызов функции - это не операционная система, чтобы говорить о её стабильности :) .

Добавлено: 09 дек 2004, 20:52
xpymep
Сори..."апечатка" я имел ввиду нестабильно... :)
Еще такой вопрос... у мя есть форма:
.h file

Код: Выделить всё

#ifndef Unit1H
#define Unit1H
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class Tformt : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
public:		// User declarations
        __fastcall Tformt(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern Tformt *formt;
//---------------------------------------------------------------------------
#endif
.cpp file

Код: Выделить всё

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

#include <vcl.h>
#include <windows.h>
#include "Unit1.h"

#pragma hdrstop
#pragma argsused
Tformt *formt ;
__fastcall Tformt::Tformt(TComponent* Owner)
        : TForm(Owner)
{
}
extern "C" __export void __stdcall call(void)
{
Tformt *formt = new Tformt(NULL);
formt->ShowModal();
}
Вызываю функцию call в главном проэкте и мне показуют эксепшн:
EResNotFound "Resource Tformt not found"
Как понять ? Я вроде Tformt и ектсерном объявил, а потом еще и в сурс файле, в чем проблема ? Помогите плз!
О разнице между __stdcall и __fastcall - посмотри сам в MSDN
Про разницу я знаю, я просто имел ввиду стабильности этих префиксов. __stdcall - это (по идее, я могу быть не прав) когда компилятор использует 2-байтные регистры: ax,bx,cx,dx (тот кто программит на асм, мя поймет), а __fastcall - это использование 4-байтных (который используются Виндой и всеми 32-разрядными ОСями): eax,ebx,ecx,edx.

Добавлено: 10 дек 2004, 10:31
Absurd
Про разницу я знаю, я просто имел ввиду стабильности этих префиксов. __stdcall - это (по идее, я могу быть не прав) когда компилятор использует 2-байтные регистры: ax,bx,cx,dx (тот кто программит на асм, мя поймет), а __fastcall - это использование 4-байтных (который используются Виндой и всеми 32-разрядными ОСями): eax,ebx,ecx,edx.
Такого вызова - __fastcall в win32 вообще нет, это борландовское изобретение.
По-моему, оно рекоммендует компилятору вообще все параметры передать через регистры, не засовывая их в стек.
__stdcall - это нечто среднее между паскаль-образным и С- образным вызовом функции.
То есть параметры передаются в стек задом наперед, как в С, но очищает стек вызываемая функция, как в паскале.

Добавлено: 10 дек 2004, 17:39
xpymep
Согласен... На счет __fastcall я ошибся. Я просто больше программирую на Борланде и забываю об этом...
По-моему, оно рекоммендует компилятору вообще все параметры передать через регистры, не засовывая их в стек.
Не...в стэк стопудофф попадает. Если посмотреть дебаггером любую __fastcall функцию, то можно увидить pusha и popa в начале и конце функции. Иначе я себе не могу представить, как работали бы проги без стека...
Это конечно хорошо, но форма у мя до сих пор не работает. :) Прошу вас помогите,плз!