Форум: "Основная";
Текущий архив: 2011.08.21;
Скачать: [xml.tar.bz2];
Внизпередача параметров из сишной dll Найти похожие ветки
← →
Игорь_З (2010-01-12 13:30) [0]Здраствуйте.
Скажите как подсоединить некую функцию в dll (c).
Постоянно выдается ошибка, хотя, подключая ее на с - работает без проблем.
#include <windows.h>
#include <stdio.h>
#if BUILDING_DLL
# define LIB_API __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define LIB_API __declspec (dllimport)
#endif /* Not BUILDING_DLL */
x - входной массив
n - число чисел в массиве
Out - результат
Данная функция произвольная, начинка ее может быть любой.
LIB_API void Mean(double* x, unsigned long n, double* Out)
{
double temp;
if (x == NULL)
{
Out = NULL;
return;
}
if( n<=0 )
{
Out = NULL;
return;
}
SumVal(x,n,&temp);
*Out = temp / (double) n;
return;
}
сборка dll - maindll.dll
подключение ее на делфи
type
TFunc = procedure (FArray:array of double; size:longint; var y:pdouble);
procedure TForm1.Button1Click(Sender: TObject);
var
DLLInstance : THandle;
HelloWorld : TFunc;
v:array[0..5] of double;
g:pdouble;
begin
v[0]:=2;
v[1]:=3;
v[2]:=3;
v[3]:=5;
v[4]:=7;
v[5]:=10;
try
DLLInstance := LoadLibrary("dllmain.dll");
if DLLInstance = 0 then
begin
MessageDlg("Невозможно загрузить DLL", mtError, [mbOK], 0);
Exit;
end;
GetMem(g,sizeof(double));
@HelloWorld := GetProcAddress(DLLInstance, "Mean");
if @HelloWorld <> nil then
HelloWorld (v,6,g) // здесь ошибка
else
MessageDlg("Не найдена искомая процедура!.", mtError, [mbOK], 0);
FreeLibrary(DLLInstance);
freemem(g);
// Caption:=floattostr(g);
except
FreeLibrary(DLLInstance);
freemem(g);
end;
end;
Спасибо.
← →
KSergey © (2010-01-12 13:45) [1]Явная ошибка вот здесь:
type
TFunc = procedure (FArray:array of double; size:longint; var y:pdouble);
Надо оставить либо var (тогда просто double), либо pdouble без var. Иначе указатель на указатель получился, а в прототипе просто указатель.
← →
KSergey © (2010-01-12 13:49) [2]и еще я бы не рисковал со всякими FArray:array of double
Ну т.е. можно, конечно, изучить матчасть, грамотные люди здесь есть, поправят.
Но чтобы точно работало (и без вывертов) - я бы лучше формальнее сделал, т.е. вот так:
type
TFunc = procedure (FArray:array of double; size:longint; var y:pdouble);
==>
type
TFunc = procedure (FArray:pdouble; size:longint; y:pdouble);
и вызов исправить
HelloWorld (Addr(v[0]),6,g)
Я не говорю, что это гарантированно лучше, но во всяком случае фотмально правильно, а там уже когда срастется - можно и экспериментировать
← →
Ega23 © (2010-01-12 18:00) [3]возможно ещё с соглашением о вызовах поиграться надо. типа
type
TFunc = procedure (FArray:array of double; size:longint; var y:pdouble); cdecl;
← →
Игорь Шевченко © (2010-01-12 18:11) [4]
> type
> TFunc = procedure (FArray:array of double; size:longint;
> var y:pdouble);
type
PDouble = ^Double;
TFunc = procedure (FArray: PDouble; Size: LongInt; Y: PDouble); stdcall;
← →
Dimka Maslov © (2010-01-12 18:56) [5]#include <windows.h>
#include <stdio.h>
#if BUILDING_DLL
# define LIB_API __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define LIB_API __declspec (dllimport)
#endif /* Not BUILDING_DLL */
x - входной массив
n - число чисел в массиве
Out - результат
Данная функция произвольная, начинка ее может быть любой.
LIB_API void Mean(double* x, unsigned long n, double* Out) по умолчанию объявляется функция с модификатором вызова cdecl, а в Delphi - некое подобие fastcall.
{
double temp;
if (x == NULL)
{
Out = NULL; // что и чему мы здесь присваиваем? поскольку Out - адрес переменной, которая выделена в Delphi-программе, то ничего и ничему мы здесь не присваиваем
return;
}
if( n<=0 ) // во-первых на нуль мы уже проверили, а меньше нуля unsigned long быть не может, к сожалению
{
Out = NULL;
return;
}
SumVal(x,n,&temp);
*Out = temp / (double) n;
return;
}
сборка dll - maindll.dll
подключение ее на делфи
type
TFunc = procedure (FArray:array of double; size:longint; var y:pdouble);
// array of double сам по себе подразумевает неявную передачу функции длины массива. В данном случае объявлена процедура, получающая указатель на первый элемент массива в регистре eax, его длину в edx, некое число в ecx и указатель на указатель на вещественное число в стеке, тогда как dll ожидает указатель на результат, число элементов и указатель на первый элемент массива в стеке.
procedure TForm1.Button1Click(Sender: TObject);
var
DLLInstance : THandle;
HelloWorld : TFunc;
v:array[0..5] of double;
g:pdouble;
begin
v[0]:=2;
v[1]:=3;
v[2]:=3;
v[3]:=5;
v[4]:=7;
v[5]:=10;
try
DLLInstance := LoadLibrary("dllmain.dll");
if DLLInstance = 0 then
begin
MessageDlg("Невозможно загрузить DLL", mtError, [mbOK], 0);
Exit;
end;
GetMem(g,sizeof(double));
@HelloWorld := GetProcAddress(DLLInstance, "Mean");
if @HelloWorld <> nil then
HelloWorld (v,6,g) // здесь ошибка
else
MessageDlg("Не найдена искомая процедура!.", mtError, [mbOK], 0);
FreeLibrary(DLLInstance);
freemem(g);
// Caption:=floattostr(g);
except
FreeLibrary(DLLInstance);
freemem(g);
end;
end;
А теперь давайте попытаемся избавиться от требухи и написать всё как следует.
C++ код:
__declspec(dllexport) bool __stdcall Mean(double* x, unsinged long n, double* Out)
{
if (x && n)
{
double Temp;
SumVal(x, n, &Temp);
*Out = temp / (double) n;
return true;
}
return false;
}
Delphi код:
type
TFunc = function(var x; cardinal n; out R: Double): LongBool stdcall;
var
H: THandle;
F: TFunc;
v: array[0..5] of Double;
R: Double;
begin
v[0]:=2;
v[1]:=3;
v[2]:=3;
v[3]:=5;
v[4]:=7;
v[5]:=10;
H := LoadLibrary("dllmain.dll");
@F := GetProcAddress(H, "Mean");
if Assigned(@F) and F(V, High(V) - Low(V) + 1, R) then Caption := FloatToStr(R)
else ShowMessage("АШИПКО в 17 строке!");
end;
← →
Игорь Шевченко © (2010-01-12 19:16) [6]
> по умолчанию объявляется функция с модификатором вызова
> cdecl, а в Delphi - некое подобие fastcall.
> {
если не указано __declspec (dllexport)
← →
Dimka Maslov © (2010-01-12 23:34) [7]
> Игорь Шевченко © (12.01.10 19:16) [6]
В любом случае лучше явно указывать модификатор вызова и обязательно использовать одинаковый, который есть stdcall.
← →
Игорь Шевченко © (2010-01-13 01:21) [8]
> В любом случае лучше явно указывать модификатор вызова и
> обязательно использовать одинаковый, который есть stdcall
Это безусловно, явно всегда лучше указывать, особенно при вызове из приложений на других языках.
← →
Ega23 © (2010-01-13 01:21) [9]
> который есть stdcall.
Это у Архангельского он есть одинаковый и явный.
Жизнь гораздо многоцветнее... :)
← →
Dimka Maslov © (2010-01-13 11:20) [10]
> Это у Архангельского он есть одинаковый и явный.
Не знаю что там у него (не читал), но все интерфейсные функции всегда объявляю через stdcall и не разу проблем при передаче параметров не было...
← →
Ega23 © (2010-01-13 11:36) [11]
> Не знаю что там у него (не читал), но все интерфейсные функции
> всегда объявляю через stdcall и не разу проблем при передаче
> параметров не было...
Это, конечно, похвально. Но дадут тебе библиотеку, где как cdecl объявлено - и усё.
← →
Dimka Maslov © (2010-01-13 12:39) [12]
> Но дадут тебе библиотеку, где как cdecl объявлено - и усё
Поскольку я пишу исключительно для нужд внутреннего потребления, то единственное лицо, которое может дать мне библиотеку - это я сам.
← →
KSergey © (2010-01-13 13:36) [13]> Dimka Maslov © (13.01.10 12:39) [12]
Так речь-то не про ваши проекты и не про ваши нужды.
Интересно, автор хоть прочитает?
← →
Dimka Maslov © (2010-01-13 14:18) [14]
> KSergey © (13.01.10 13:36) [13]
Ну хорошо, если мне дадут библиотеку с cdecloм, это можно пережить. А используя встроенный ассемблер можно пережить любой тип вызова функций. Лишь бы реализовано было правильно.
← →
Anatoly Podgoretsky © (2010-01-13 16:43) [15]> Ega23 (13.01.2010 11:36:11) [11]
Библиотеку положено давать с описанием, иначе рулетка.
← →
KSergey © (2010-01-14 09:37) [16]> Dimka Maslov © (13.01.10 14:18) [14]
> Ну хорошо, если мне дадут библиотеку с cdecloм, это можно пережить.
Еще раз. Речь здесь не про вас.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2011.08.21;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.003 c