Delphi и структура C ++ - PullRequest
       8

Delphi и структура C ++

0 голосов
/ 12 октября 2018

У меня есть следующая функция C ++, которая экспортирует структуру с полем char*, но строковое значение отличается от ожидаемого при использовании в Delphi, хотя оно заканчивается на ноль.

typedef struct _MyStruct{
    char* name;
    // other fields
}MyStruct,*PMyStruct;

extern "C" __declspec(dllexport) __cdecl MyTestStr(PMyStruct _PMyStruct)
{
    std::string str = "string";
    std::vector<char> cstr(str.begin(), str.end);
    cstr.push_back('\0');//null-terminated
    _PMyStruct->name = cstr.data();    
}
type
  PMyStruct = ^MyStruct;
  MyStruct= record
    name : PAnsiChar;
        // other fields
  end;

procedure MyTestStr(_PMyStruct: PMyStruct); cdecl; external 'mytest.dll' name 'MyTestStr';    

procedure TestMyRec();
var
  _MyStruct: MyStruct;
begin
  MyTestStr(@_MyStruct); 
  showmessage(_MyStruct.name);
  // here the result is just 'YYYYYYYYYYYYYYYYYY' not 'string'
end;

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Измените определение _MyStruct::name на const char * и просто присвойте ему литерал.

Обратите внимание, что имена, начинающиеся с _, за которыми следует заглавная буква, зарезервированы для реализации, поэтому все вашеПрограмма имеет неопределенное поведение.

Вам не нужно typedef struct.

struct MyStruct
{ 
    const char* name; // mutable pointer to constant char(s)
    // other fields
};

using PMyStruct = * MyStruct;

extern "C" __declspec(dllexport) __cdecl void MyTestStr(PMyStruct pMyStruct)
{
    pMyStruct->name = "string";
}

В общем случае нежелательно передавать указатели-владельцы через границы dll.Вместо этого вызывающий должен выделить , и функция скопирует в это распределение.Это шаблон, используемый в Win32Api.Вы либо возвращаете размер, либо берете int * параметры, чтобы записать размеры в

C ++ Dll

extern "C" __declspec(dllexport) __cdecl void MyTestStr(PMyStruct pMyStruct = nullptr, int * firstname_size = nullptr, int * lastname_size = nullptr)
{
    if (pMyStruct)
    {
        std::strncpy(pMyStruct->firstname, "string", pMyStruct->firstname_len);
        std::strncpy(pMyStruct->lastname, "other string", pMyStruct->lastname_len);
    }
    if (firstname_size) { *firstname_size = 7; }
    if (lastname_size) { *lastname_size = 13; }
}

Delphi exe

type
  PInteger = ^Integer;
  PMyStruct = ^MyStruct;
  MyStruct= record
    firstname : PAnsiChar;
    firstname_len : Integer;
    lastname : PAnsiChar;
    lastname_len : Integer;
    // other fields
  end;

procedure MyTestStr(pMyStruct: PMyStruct; firstname_len : PInteger; lastname_len : PInteger); cdecl; external 'mytest.dll' name 'MyTestStr';   

procedure TestMyRec();
var
  myStruct: MyStruct;
begin
// If you don't know how much memory you will need, you have to ask
  MyTestStr(nil, @myStruct.firstname_len, @myStruct.lastname_len); 
  GetMem(myStruct.firstname, myStruct.firstname_len);
  GetMem(myStruct.lastname, myStruct.lastname_len);

  MyTestStr(@myStruct); 

  // Use myStruct

  FreeMem(myStruct.firstname);
  FreeMem(myStruct.lastname);
end;
0 голосов
/ 12 октября 2018

_PMyStruct->name=cstr.data(); просто делает указатель на тело строки.Но после вызова функции локальный объект std::string должен быть утилизирован.Таким образом, у вас есть указатель на некоторый адрес памяти с непредсказуемым содержимым, это может вызвать AV, если память больше не принадлежит приложению.

Похоже, вам нужно выделить память и вызвать функцию, которая необходима копий данные в этот адрес памяти.Освободите эту память при необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...