Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Общение VC++ DLL с Delphi VCL App, проблема с передачей данных в обе сторон 
:(
    Опции темы
Kosoglaz
Дата 1.2.2008, 15:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 1.2.2008

Репутация: нет
Всего: нет



Здравствуйте, программисты!
Помогите, пожалйста, решить проблему передачи данных между приложением 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][i];
        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][i];
        name++;
    }
    name[i] = '\0';

    mx = strlen(szVals[nIndex]);
    for(i=0; i < mx; i++)
    {
        *szVal = szVals[nIndex][i];
        szVal++;
    }
    szVal[i] = '\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;



Такие вот дела. Не пойму, в чём проблемы. А главное, не знаю уже отлаженного решения передачи данных, в т.ч. строковых из СиПП ДЛЛ в Дельфи приложение.
Подскажите решение, пожалуйста. А ещё лучше, если объясните суть проблемы, чтобы я мог сам понять как это всё делается и почему не делается.
Спасибо!
PM MAIL   Вверх
NiJazz
Дата 1.2.2008, 16:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Jazz coder
****


Профиль
Группа: Экс. модератор
Сообщений: 2286
Регистрация: 10.8.2003
Где: Москва

Репутация: 2
Всего: 23



В Delphi, кажется, есть класс PChar для работы с такими функциями.
PM MAIL   Вверх
dizzy1984
Дата 4.2.2008, 06:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 675
Регистрация: 15.2.2007

Репутация: 10
Всего: 25



В си++ строки хранятся как набор байтов с завершающим символом '\0'. В дельфи строка представлена иначе. Если бы строка была представлена так : первый байт - длина строки, потом сама строка, то приведенный дамп бы объяснился просто - съеден первый символ, отображены все символы за завершающим нулем (посчитай их там случайно не 74 - 'J'?).

Это сообщение отредактировал(а) dizzy1984 - 4.2.2008, 06:59
PM MAIL   Вверх
Kosoglaz
Дата 5.2.2008, 10:54 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 1.2.2008

Репутация: нет
Всего: нет



Цитата(dizzy1984 @ 4.2.2008,  06:58)
В си++ строки хранятся как набор байтов с завершающим символом '\0'. В дельфи строка представлена иначе.

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

на

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

И всё работает!
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.1715 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.