Правильное преобразование байтов из C ++ в delphi AnsiString - PullRequest
3 голосов
/ 01 февраля 2012

У меня есть dll, которая принимает указатель на массив байтов из C ++ и пытается переместить эти данные в AnsiString следующим образом

procedure Convert(const PByteArr: Pointer; ArrSize: Cardinal); export; cdecl;
var
  Buf: AnsiString;
begin
  SetString(Buf, PAnsiChar(PByteArr^), ArrSize);
end;

Если я вызываю этот метод из Delphi

procedure Try;
var
  M: TMemoryStream;
  Arr: TBytes;  
begin
  M := TMemoryStream.Create;
  try
    M.LoadFromFile('myfile.dat');
    SetLength(Arr, M.Size);
    M.Position := 0;
    M.Read(Arr[0], M.Size);
  finally
    M.Free;
  end;
  Convert(@Arr, Length(Arr));
end;

это работает нормально, но из c ++, если дает AV на SetString.

Пожалуйста, помогите мне с этим.


От RredCat:

Позвольте мне добавить некоторые пояснения кВопрос Юрия: Прежде всего о языках, которые мы используем.Нам нужно вызвать Delphi dll в проекте C #.Я создал слой C ++ \ CLI (прокси) для этих целей.Теперь о C ++ \ CLI-коде в заголовочном файле:

HINSTANCE hDelphiDLL;
typedef void (*pPBDFUNC)(byte* aBytes, int size);
pPBDFUNC Convert;

В cpp я устанавливаю Convert in constructor:

hDelphiDLL = LoadLibrary(<path to dll>);

if(NULL != hDelphiDLL ){
    pPBDFUNC clb= GetProcAddress(HMODULE(hDelphiDLL), "Convert");
        if(NULL != clb){
            Convert= pPBDFUNC (clb);
        }...

И последний метод, который я вызываю из C #:

void Class1::Test(byte* aBytes, int size){
    Convert(aBytes,size);
}

Ответы [ 2 ]

5 голосов
/ 01 февраля 2012

Ваш Delphi-код передает указатель на указатель на массив байтов.Упростите его, чтобы использовать только указатель на массив байтов:

procedure Convert(const PByteArr: Pointer; ArrSize: Cardinal); export; cdecl;
var
  Buf: AnsiString;
begin
  SetString(Buf, PAnsiChar(PByteArr), ArrSize);
end;

и вызывать его как

Convert(@Arr[0], Length(Arr));

или

Convert(Pointer(Arr), Length(Arr));

, что тоже самое.

1 голос
/ 01 февраля 2012

Вы делаете эту задачу намного сложнее, чем нужно.C ++ / CLI отлично подходит, когда у вас есть существующее тело кода на C или C ++ или встроенная библиотека с очень большим интерфейсом.До тех пор, пока у вас есть только несколько функций, прямой путь p / invoke к нативной DLL-библиотеке Delphi является подходящим вариантом.

Serg уже указал на ложный дополнительный уровень косвенности в вашей функции Delphi.Поэтому я написал бы функцию Delphi следующим образом:

procedure TestFunction(Text: PAnsiChar); stdcall;
var
  Buf: AnsiString;
begin
  Buf := Text;
end;

На стороне C # вы можете объявить функцию следующим образом:

[DllImport(@"mydll.dll")]
static extern void TestFunction(string Text);

Вы можете вызвать эту функцию из своего кода C # следующим образом:

TestFunction("Hello");
string str = GetStringFromSomewhere();
TestFunction(str);

И это все!Поскольку в конце C # у вас есть строковая переменная, вы можете положиться на маршаллер p / invoke для предоставления строки с нулевым символом в конце для собственного кода.Следовательно, нет необходимости передавать длину.Соглашение о вызовах по умолчанию для p / invoke - stdcall, поэтому предпочитайте его в коде Delphi.

...