[英]Delphi and c++ struct
I have the following C++ function that exports a struct with a char*
field in it, but the string value is not as expected when used in Delphi, although it is null-terminated. 我有以下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;
_PMyStruct->name=cstr.data();
just makes pointer onto string body. 只是使指针指向字符串体。 But after function call local object
std::string
should be disposed. 但是在函数调用之后,应该处置本地对象
std::string
。 So you have got pointer to some memory address with unpredictable contents, this might cause AV if memory does not belong to application more. 因此,您已经获得了指向某个具有不可预测内容的内存地址的指针,如果内存不属于应用程序,则可能会导致AV。
Seems you have to allocate memory and call function that copies needed data into this memory address. 似乎您必须分配内存并调用将所需数据复制到此内存地址的函数。 Free this memory when needed.
需要时释放此内存。
Change the definition of _MyStruct::name
to const char *
, and just assign the literal to it. 将
_MyStruct::name
的定义更改为const char *
,并为其分配文字。
Note that names starting _
followed by an uppercase letter are reserved for the implementation, so your whole program has undefined behaviour. 请注意,以
_
开头并以大写字母开头的名称是为实现保留的,因此您的整个程序都具有未定义的行为。
You don't need to typedef struct
. 您不需要
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";
}
In the general case, it is inadvisable to pass owning pointers across dll boundaries. 在一般情况下,不建议跨dll边界传递拥有的指针。 Instead the caller should allocate , and the function copy into that allocation.
相反, 调用者应该分配 ,并且函数将复制到该分配中。 This is the pattern used across the Win32Api.
这是Win32Api上使用的模式。 You either return the size, or take
int *
parameters to write the sizes into 您可以返回大小,也可以使用
int *
参数将大小写入
C++ Dll 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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.