Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2011.08.21;
Скачать: CL | DM;

Вниз

передача параметров из сишной 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;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.008 c
15-1304274899
IPranker
2011-05-01 22:34
2011.08.21
C++ константы -> Delphi константы.


1-1262110832
Maloj2008
2009-12-29 21:20
2011.08.21
TListView сортировка и изменение данных


2-1305111938
leonid666
2011-05-11 15:05
2011.08.21
ole-container немогу открыть ворд


15-1304313612
Константинов
2011-05-02 09:20
2011.08.21
Домашняя сеть


15-1303664339
TUser
2011-04-24 20:58
2011.08.21
Материализм и эмпириокритицизм