![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с вызовом DLL на C из программы на Delphi [D6, Win2k, WinXP]
Valera © (2006-06-06 00:17:00)Суть проблемы.
Имеется программа, написанная на Delphi. Она вызывает DLL, которая написана на C и откомпилирована на Borland C++ Builder 6. Функция, содержащаяся в DLL получает от вызывающей программы в качестве параметров адреса двух двумерных массивов, берет данные из массивов, производит вычисления и пишет результаты вычислений в третий массив, адрес которого также передается в виде параметра. Если результирующий массив - одномерный (вектор), то вызов DLL отрабатывается нормально. Если же сделать результирующий массив двумерным, то при вызове из дельфийской программы DLL выдается ошибка Access Violation ...
Провел следующие эксперименты:
1. Написал вызывающую программу на C и откомпилировал на C++ Builder. Программа на C нормально вызывает ту же самую DLL, на которой спотыкается программа на Delphi.
2. Написал DLL на Delphi. Ее нормально вызывает дельфийская программа, а C-шная программа спотыкается на дельфийской DLL.
Для справки. Соответствие и совместимость типов передаваемых в DLL параметров в Delphi и C соблюдено. Причем проводились эксперименты с разными типами данных. Во всех случаях использовалась динамическая загрузка DLL с помощью функций LoadLibrary и GetProcAddress. Динамическая память в самой DLL не выделяется.
Интересно выяснить чего все-таки я не понимаю в этой жизни. Может быть в Delphi и C по разному организованы двумерные массивы. Хотя входные данные из передаваемых в DLL двумерных массивов читаются правильно (проверялось). Не удается записать данные в двумерный массив. В одномерный получается (см. выше).
Может быть кто-нибудь сталкивался с подобной проблемой ?
atruhin (2006-06-07 14:59:00) [1]
> [7] evvcom © (07.06.06 08:49)
> Тогда уж
Красиво. Вроде знал что const указатель передает, но не задумывался о таком использовании. :)
evvcom (2006-06-07 08:49:00) [2]Тогда уж
TMaskWatershedFunction = function(WidthImage, HeightImage: Word;
constArPImageLines: tArPtr0;
constArPMaskLines: tArPtr0;
var ArPWaterLines: tArPtr0): integer; StdCall;
идеологически более правильно, хотя результат тот же. :)
atruhin (2006-06-07 06:40:00) [3]Можно проще:
TMaskWatershedFunction = function(WidthImage, HeightImage: Word;
var ArPImageLines: tArPtr0;
var ArPMaskLines: tArPtr0;
var ArPWaterLines: tArPtr0): integer; StdCall;
То же самое только удобнее.
Valera (2006-06-06 17:54:00) [4]Допустил ошибку в своем последнем сообщении. Вот правильное объявление типа вызываемой из DLL функции:
TMaskWatershedFunction = function(WidthImage, HeightImage: Word;
ArPImageLines: pArPtr0;
ArPMaskLines: pArPtr0;
ArPWaterLines: pArPtr0): integer; StdCall;
Остальное верно.
Valera (2006-06-06 17:51:00) [5]Разобрался с проблемой самостоятельно.
Проблема была в моем непонимании принципов передачи open array parameters в Delphi. Проблему решил путем изменения типов передаваемых из Delphi параметров:
const MAXARRAYSIZE = MAXINT;
type
pArPtr0 = ^tArPtr0;
tArPtr0 = array[0..MAXARRAYSIZE div sizeof(pointer)-1] of pointer;
TMaskWatershedFunction = function(WidthImage, HeightImage: Word;
var ArPImageLines: pArPtr0;
var ArPMaskLines: pArPtr0;
var ArPWaterLines: pArPtr0): integer; StdCall;
...............
var
WidthImage, HeightImage: Word;
ArPImageLines: pArPtr0;
ArPMaskLines: pArPtr0;
ArPWaterLines: pArPtr0;
MaskWatershedFunction: TMaskWatershedFunction;
...............
LibHandle := LoadLibrary('MaskWatershed.dll');
if LibHandle = HINSTANCE_ERROR then
Writeln('Unable to Load DLL');
@MaskWatershedFunction := GetProcAddress(LibHandle, 'MaskWatershedFunction');
if not (@MaskWatershedFunction = nil) then
begin
res := MaskWatershedFunction(WidthImage, HeightImage,
ArPImageLines, ArPMaskLines, ArPWaterLines);
end;
Код на C в DLL без изменений. В таком виде все работает.
Valera (2006-06-06 15:51:00) [6]Массивы динамические.
Код процедуры на С:
--------------------------
__declspec(dllexport) int __stdcall MaskWatershedFunction(short WidthImage, short HeightImage,
unsigned char **ArPImageLines,
unsigned char **ArPMaskLines,
unsigned int **ArPWaterLines)
{
int i, j;
for (i=0; i<HeightImage; i++) {
for (j=0; j<WidthImage; j++) {
ArPWaterLines[i][j] = ArPImageLines[i][j] + ArPMaskLines[i][j];
}
}
return 0;
}
А вот основаная часть кода на Delphi:
--------------------------------------
type
TByteMatrix = array of array of byte;
TCardinalMatrix = array of array of Cardinal;
TMaskWatershedFunction = function(WidthImage, HeightImage: Word;
var ArPImageLines: TByteMatrix;
var ArPMaskLines: TByteMatrix;
var ArPWaterLines: TCardinalMatrix): integer; StdCall;
...............
var
WidthImage, HeightImage: Word;
ArPImageLines: TByteMatrix;
ArPMaskLines: TByteMatrix;
ArPWaterLines: TCardinalMatrix;
MaskWatershedFunction: TMaskWatershedFunction;
...............
LibHandle := LoadLibrary('MaskWatershed.dll');
if LibHandle = HINSTANCE_ERROR then
Writeln('Unable to Load DLL');
@MaskWatershedFunction := GetProcAddress(LibHandle, 'MaskWatershedFunction');
if not (@MaskWatershedFunction = nil) then
begin
res := MaskWatershedFunction(WidthImage, HeightImage,
ArPImageLines, ArPMaskLines, ArPWaterLines);
end;
atruhin (2006-06-06 06:05:00) [7]Прототипы функций на C++ и delphi
atruhin (2006-06-06 05:57:00) [8]Не указал тип данных массива. Массивы статические? Размерности соблюдены? Вообщем выкладывай прототип описания функции.