Reputation: 257
I have dll which accepts Pointer to array of bytes from C++ and try to move this data into AnsiString the following way
procedure Convert(const PByteArr: Pointer; ArrSize: Cardinal); export; cdecl;
var
Buf: AnsiString;
begin
SetString(Buf, PAnsiChar(PByteArr^), ArrSize);
end;
If I call this method from 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;
it works fine, but from c++ if gives AV on SetString.
Please help me with this.
From RredCat:
Let me add some explanation to Yuriy's question: First of all about languages that we use. We need to call Delphi dll in C# project. I've created C++\CLI layer (proxy) for this purposes. Now about C++\CLI code in header file:
HINSTANCE hDelphiDLL;
typedef void (*pPBDFUNC)(byte* aBytes, int size);
pPBDFUNC Convert;
In cpp I set Convert in constructor:
hDelphiDLL = LoadLibrary(<path to dll>);
if(NULL != hDelphiDLL ){
pPBDFUNC clb= GetProcAddress(HMODULE(hDelphiDLL), "Convert");
if(NULL != clb){
Convert= pPBDFUNC (clb);
}...
And last one method that I call from C#:
void Class1::Test(byte* aBytes, int size){
Convert(aBytes,size);
}
Upvotes: 3
Views: 1627
Reputation: 612993
You are making this task much more complicated than it needs to be. C++/CLI is great when you have an existing body of C or C++ code, or a native library with a very large interface. So long as you only have a handful of functions, direct p/invoke to the native Delphi DLL is the way to go here.
Serg has already pointed out the spurious extra level of indirection in your Delphi function. So I would write the Delphi function as:
procedure TestFunction(Text: PAnsiChar); stdcall;
var
Buf: AnsiString;
begin
Buf := Text;
end;
On the C# side you can declare the function like this:
[DllImport(@"mydll.dll")]
static extern void TestFunction(string Text);
You can call this function from your C# code like this:
TestFunction("Hello");
string str = GetStringFromSomewhere();
TestFunction(str);
And that's it! Since at the C# end you have a string variable you can rely on the p/invoke marshaller to provide a null-terminated string to the native code. Hence there is no need to pass the length. The default calling convention for p/invoke is stdcall
so prefer that in the Delphi code.
Upvotes: 1
Reputation: 27493
Your Delphi code passes a pointer to pointer to array of bytes. Simplify it to use just a pointer to array of bytes:
procedure Convert(const PByteArr: Pointer; ArrSize: Cardinal); export; cdecl;
var
Buf: AnsiString;
begin
SetString(Buf, PAnsiChar(PByteArr), ArrSize);
end;
and call it as
Convert(@Arr[0], Length(Arr));
or
Convert(Pointer(Arr), Length(Arr));
which is the same.
Upvotes: 5