Передача данных из Vc++ Dll в Dlphi App

  • Автор темы Kosoglaz
  • Дата начала
K

Kosoglaz

Гость
#1
Здравствуйте, программисты!
Помогите, пожалйста, решить проблему передачи данных между приложением Delphi 2007 и DLL MS Visual C++ 6

Идея такая, что Delphi App делает запрос DLLке, а та возвращает данные.
Вот код C++

#define EXPORTCALLstd extern "C" __declspec(dllexport) __stdcall
typedef struct {
int nLevel;
const char* name;
double fVal;
const char* szVal;
}ITEMDATA;

const char* Names[10] = {"January","February","March","April","May","June","July","August","September","October"};
double fVals[10] = {1.99,2.88,3.77,4.66,5.55,6.44,7.33,8.22,9.11,10.111};
const char* szVals[10] = {"A","B","C","D","E","F","G","H","I","J"};
...

EXPORTCALLstd int GetDataCount()
{
return 10;
}

EXPORTCALLstd int SendItemData(int nIndex, PITEMDATA pItemData)
{
ITEMDATA ItData;

if(nIndex > 9)
nIndex = 9;

ItData.fVal = fVals[nIndex];
ItData.name = Names[nIndex];
ItData.nLevel = nIndex;
ItData.szVal = szVals[nIndex];

//тут вываливается 0xC0000005
(*ItemData).fVal = fVals[nIndex];
(*ItemData).name = (const char*)Names[nIndex];


return 0;
}
/* вариант со структурой
EXPORTCALLstd int SendItemData(int nIndex, int* nLevel, char* name, double* fVal, char* szVal)
{
if(nIndex > 9)
nIndex = 9;

*nLevel = nIndex;
*fVal = fVals[nIndex];

/*
mx = strlen(Names[nIndex]);
szVal = (char*)malloc(mx);
for(i=0; i < mx; i++)
{
*szVal = Names[nIndex];
szVal++;
}
*/
return 1;
}
*/
EXPORTCALLstd int SendItemData(int nIndex, int* nLevel, char* name, double* fVal, char* szVal)
{
int i,mx;

if(nIndex > 9)
nIndex = 9;

*nLevel = nIndex;
*fVal = fVals[nIndex];

mx = strlen(Names[nIndex]);
for(i=0; i < mx; i++)
{
*name = Names[nIndex];
name++;
}
name = '\0';

mx = strlen(szVals[nIndex]);
for(i=0; i < mx; i++)
{
*szVal = szVals[nIndex];
szVal++;
}
szVal = '\0';

return 1;
}


Вариант с параметрами работает, но строковые значения криво возвращаются. Дежучник в Си показывает после вызова из Дельфи с nIndex = 0, что name = 'January', а в уже Дельфи после вызова name = ''anuary'#0#0#0#0#0#0#0#0#0'е'#8'яяі'#2#0#0#1#0#0#0#$E#0#0#0' Ѓ¦'#0'шф'#$12#0'fгУwе'#8'яяf'#$B#$1C#0#$E#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0'Lц'#$12#0'|'#$1E'D'

Вот код Delphi

type
PInteger = ^Integer;
PDouble = ^Double;

PTITEMDATA = ^TITEMDATA;
TITEMDATA = record
nLevel:integer;
szName:ShortString;
fVal:double;
szVal:ShortString;
end;

TformMain = class(TForm)
btRequestData: TButton;
sgrData: TStringGrid;
btChangeData: TButton;
procedure FormCreate(Sender: TObject);
procedure btRequestDataClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }

CppFnGetDataitemsCnt: function: integer; stdcall;
//CppFnGetItemData: function(nIndex:integer; ItemData:TITEMDATA):integer;
CppFnGetItemData: function(nIndex:integer; nLevel:PInteger; Name:PChar; fVal:PDouble; szVal:PChar):integer; stdcall;
end;

procedure TformMain.FormCreate(Sender: TObject);
var
HLib:THandle;
begin
formMain := self;

//загрузь
HLib := LoadLibrary('..\CDT_CppDLL\Debug\CDT_CppDLL.dll');
if HLib < 32 then
ShowMessage('Lib didn`t load')
else
begin
CppFnGetDataItemsCnt := GetProcAddress(HLib,'_GetDataCount@0');
if(not Assigned(CppFnGetDataitemsCnt)) then
ShowMessage('Didn`t find GetDataCount func in lib ');
CppFnGetItemData := GetProcAddress(HLib,'_SendItemData@20');
if(not Assigned(CppFnGetItemData)) then
ShowMessage('Didn`t find SendItemData func in lib ');
end;
end;

procedure TformMain.btRequestDataClick(Sender: TObject);
var
i: integer;
nDataCnt:integer;
nLevel:integer;
Name,szVal:ShortString;
fVal:double;
ItemData:TITEMDATA;
begin
//это работает отлично
nDataCnt := CppFnGetDataItemsCnt;
for i:=0 to (nDataCnt - 1) do
begin

nLevel := 333;
Name := '_123_';
fVal := 25.52;
szVal := '-321-';
//грамотно изменяет числовые значения, но строковые возвращает краказяблами
CppFnGetItemData(i,@nLevel,@Name,@fVal,@szVal);

{
ItemData.nLevel := 999;
ItemData.szName := 'start name';
ItemData.fVal := 9.99;
ItemData.szVal := 'start val';
CppFnGetItemData(i,ItemData);
}
end;
end;


Такие вот дела. Не пойму, в чёи проблемы. А главное, не знаю уже отлаженного решения передачи данных, в т.ч. строковых из СиПП ДЛЛ в Дельфи приложение.
Подскажите решение, пожалуйста. А ещё лучше, если объясните суть проблемы, чтобы я мог сам понять как это всё делается и почему не делается.
Спасибо!
 

grigsoft

Well-Known Member
15.11.2005
735
0
#2
Ну так char* в C++ это указатель на кусок памяти, где с первого байта находятся символы строки. А что такое ShortString? Со структурами еще хуже - там начинается разное выравнивание и прочие радости. Для надежности я бы передавал в длл указатель на память, выделенную через GlocaAlloc, туда складываются результаты, приложение их извлекает.
 
K

Kosoglaz

Гость
#3
Ну так char* в C++ это указатель на кусок памяти, где с первого байта находятся символы строки. А что такое ShortString? Со структурами еще хуже - там начинается разное выравнивание и прочие радости. Для надежности я бы передавал в длл указатель на память, выделенную через GlocaAlloc, туда складываются результаты, приложение их извлекает.
Спасибо за подсказку!
Действительно, представление ShortString в Delphi такое: 0ой символ - длина строки, остальные - содержимое без нулевого на конце.
Просто поменял в Си коде:
mx = strlen(Names[nIndex]);
for(i=0; i < btStrLen; i++)
{
*name= Names[nIndex];
name++;
}
name = '\0';

на

btStrLen = (char)strlen(Names[nIndex]);
*name = btStrLen;
for(i=0; i < btStrLen; i++)
{
*(++name) = Names[nIndex];
}

И всё работает!