Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-1262110832
Maloj2008
2009-12-29 21:20
2011.08.21
TListView сортировка и изменение данных


15-1303980993
DVM
2011-04-28 12:56
2011.08.21
PlaySound из Windows Service под Windows 2008 Server


2-1305015386
werewolf2
2011-05-10 12:16
2011.08.21
освобождение objects stringlist а


4-1249641864
Гость
2009-08-07 14:44
2011.08.21
Получение текста ошибки при вызове LoadLibrary в сервисе


15-1304182636
И. Павел
2011-04-30 20:57
2011.08.21
Связь между "логическим" и "физическим" значением сигнала





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский