c++ dll 将字符串返回到 delphi
c++ dll returning string to delphi
Delphi 外部 c++ dll 函数的声明。
Const dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single ; StartY : Single ; StartZ : Single ; EndX : Single ; EndY : Single ; EndZ : Single): PansiChar; stdcall; external dllname;
extern "C" NAVSERVER_API const char* __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ)
{ //const char*
const char* str1;
if (pathSize > 0)
{
std::stringstream ss;
for (int i = 0;i < pathSize; i++)
{
ss << i;
}
ss << "dadsaassaasd";
std::string tmp;
ss >> tmp;
str1 = tmp.c_str();
//ss.str();
return str1;
///tmp.data();
}
else
{
return "Path return no points.";
}
c++ dll 函数,这一切都按预期工作,直到 str1 的特定长度然后 Delphi returns 垃圾。我需要 return 可能很长的字符串。如有任何建议,我们将不胜感激!
问题是 DLL 函数返回一个指向函数退出时自动释放的数据的指针,因此 悬空指针 返回给调用者(即 Delphi).因此,调用者对该指针的任何使用都是 未定义行为。
DLL 需要为返回的指针动态分配内存,然后导出第二个函数,调用者可以使用它来释放内存,例如:
const
dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single; StartY : Single; StartZ : Single; EndX : Single; EndY : Single; EndZ : Single): PAnsiChar; stdcall; external dllname;
procedure FreeMeshPath(Path: PAnsiChar); stdcall; external dllname;
var
Path: PAnsiChar;
begin
Path := FindNavMeshPath(...);
if Path <> nil then
try
...
finally
FreeMeshPath(Path);
end;
end;
extern "C" NAVSERVER_API const char* __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ)
{
char* str1;
if (pathSize > 0)
{
std::ostringstream oss;
for (int i = 0;i < pathSize; i++)
{
oss << i;
}
oss << "dadsaassaasd";
std::string tmp = oss.str();
size_t needed = tmp.size() + 1;
str1 = new(nothrow) char[needed];
if (str1)
std::copy_n(tmp.c_str(), needed, str1);
}
else
{
static const char *errorMsg = "Path return no points.";
static const size_t needed = std::strlen(errorMsg) + 1;
str1 = new(nothrow) char[needed];
if (str1)
std::copy_n(errorMsg, needed, str1);
}
return str1;
}
extern "C" NAVSERVER_API void __stdcall FreeMeshPath(char *Path)
{
delete[] Path;
}
或者,让 DLL 使用 OS 提供的内存管理器,如 LocalAlloc()
或 CoTaskMemAlloc()
,这样调用者就可以使用适当的 ...Free()
函数,例如:
const
dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single; StartY : Single; StartZ : Single; EndX : Single; EndY : Single; EndZ : Single): PAnsiChar; stdcall; external dllname;
var
Path: PAnsiChar;
begin
Path := FindNavMeshPath(...);
if Path <> nil then
try
...
finally
LocalFree(Path);
end;
end;
extern "C" NAVSERVER_API const char* __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ)
{
char* str1;
if (pathSize > 0)
{
std::ostringstream oss;
for (int i = 0;i < pathSize; i++)
{
oss << i;
}
oss << "dadsaassaasd";
std::string tmp = oss.str();
size_t needed = tmp.size() + 1;
str1 = static_cast<char*>(LocalAlloc(LMEM_FIXED, needed));
if (str1)
std::copy_n(tmp.c_str(), needed, str1);
}
else
{
static const char *errorMsg = "Path return no points.";
static const size_t needed = std::strlen(errorMsg) + 1;
str1 = static_cast<char*>(LocalAlloc(LMEM_FIXED, needed));
if (str1)
std::copy_n(errorMsg, needed, str1);
}
return str1;
}
或者,让调用者分配自己的内存缓冲区,该缓冲区被传递到要填充的 DLL 中,然后调用者可以在使用完缓冲区后释放缓冲区。这通常需要调用者调用 DLL 函数两次 - 一次计算必要的缓冲区大小,然后在分配缓冲区后再次填充缓冲区,例如:
const
dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single; StartY : Single; StartZ : Single; EndX : Single; EndY : Single; EndZ : Single; PathBuffer: PAnsiChar; PathBufferSize: integer): integer; stdcall; external dllname;
var
Path: AnsiString;
Size: Integer;
begin
Size := FindNavMeshPath(..., nil, 0);
if Size <> -1 then
begin
SetLength(Path, Size-1);
FindNavMeshPath(..., PAnsiChar(Path), Size);
...
end;
end;
extern "C" NAVSERVER_API int __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ, char *PathBuffer, int PathBufferSize)
{
if (pathSize > 0)
{
std::ostringstream oss;
for (int i = 0;i < pathSize; i++)
{
oss << i;
}
oss << "dadsaassaasd";
std::string tmp = oss.str();
size_t needed = tmp.size() + 1;
if (!PathBuffer)
return needed;
if (PathBufferSize < needed)
return -1;
std::copy_n(tmp.c_str(), needed, PathBuffer);
return needed-1;
}
else
{
static const char *errorMsg = "Path return no points.";
static const size_t needed = std::strlen(errorMsg) + 1;
if (!PathBuffer)
return needed;
if (PathBufferSize < needed)
return -1;
std::copy_n(errorMsg, needed, PathBuffer);
return needed-1;
}
}
Delphi 外部 c++ dll 函数的声明。
Const dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single ; StartY : Single ; StartZ : Single ; EndX : Single ; EndY : Single ; EndZ : Single): PansiChar; stdcall; external dllname;
extern "C" NAVSERVER_API const char* __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ)
{ //const char*
const char* str1;
if (pathSize > 0)
{
std::stringstream ss;
for (int i = 0;i < pathSize; i++)
{
ss << i;
}
ss << "dadsaassaasd";
std::string tmp;
ss >> tmp;
str1 = tmp.c_str();
//ss.str();
return str1;
///tmp.data();
}
else
{
return "Path return no points.";
}
c++ dll 函数,这一切都按预期工作,直到 str1 的特定长度然后 Delphi returns 垃圾。我需要 return 可能很长的字符串。如有任何建议,我们将不胜感激!
问题是 DLL 函数返回一个指向函数退出时自动释放的数据的指针,因此 悬空指针 返回给调用者(即 Delphi).因此,调用者对该指针的任何使用都是 未定义行为。
DLL 需要为返回的指针动态分配内存,然后导出第二个函数,调用者可以使用它来释放内存,例如:
const
dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single; StartY : Single; StartZ : Single; EndX : Single; EndY : Single; EndZ : Single): PAnsiChar; stdcall; external dllname;
procedure FreeMeshPath(Path: PAnsiChar); stdcall; external dllname;
var
Path: PAnsiChar;
begin
Path := FindNavMeshPath(...);
if Path <> nil then
try
...
finally
FreeMeshPath(Path);
end;
end;
extern "C" NAVSERVER_API const char* __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ)
{
char* str1;
if (pathSize > 0)
{
std::ostringstream oss;
for (int i = 0;i < pathSize; i++)
{
oss << i;
}
oss << "dadsaassaasd";
std::string tmp = oss.str();
size_t needed = tmp.size() + 1;
str1 = new(nothrow) char[needed];
if (str1)
std::copy_n(tmp.c_str(), needed, str1);
}
else
{
static const char *errorMsg = "Path return no points.";
static const size_t needed = std::strlen(errorMsg) + 1;
str1 = new(nothrow) char[needed];
if (str1)
std::copy_n(errorMsg, needed, str1);
}
return str1;
}
extern "C" NAVSERVER_API void __stdcall FreeMeshPath(char *Path)
{
delete[] Path;
}
或者,让 DLL 使用 OS 提供的内存管理器,如 LocalAlloc()
或 CoTaskMemAlloc()
,这样调用者就可以使用适当的 ...Free()
函数,例如:
const
dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single; StartY : Single; StartZ : Single; EndX : Single; EndY : Single; EndZ : Single): PAnsiChar; stdcall; external dllname;
var
Path: PAnsiChar;
begin
Path := FindNavMeshPath(...);
if Path <> nil then
try
...
finally
LocalFree(Path);
end;
end;
extern "C" NAVSERVER_API const char* __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ)
{
char* str1;
if (pathSize > 0)
{
std::ostringstream oss;
for (int i = 0;i < pathSize; i++)
{
oss << i;
}
oss << "dadsaassaasd";
std::string tmp = oss.str();
size_t needed = tmp.size() + 1;
str1 = static_cast<char*>(LocalAlloc(LMEM_FIXED, needed));
if (str1)
std::copy_n(tmp.c_str(), needed, str1);
}
else
{
static const char *errorMsg = "Path return no points.";
static const size_t needed = std::strlen(errorMsg) + 1;
str1 = static_cast<char*>(LocalAlloc(LMEM_FIXED, needed));
if (str1)
std::copy_n(errorMsg, needed, str1);
}
return str1;
}
或者,让调用者分配自己的内存缓冲区,该缓冲区被传递到要填充的 DLL 中,然后调用者可以在使用完缓冲区后释放缓冲区。这通常需要调用者调用 DLL 函数两次 - 一次计算必要的缓冲区大小,然后在分配缓冲区后再次填充缓冲区,例如:
const
dllname = 'NavServer.dll';
function FindNavMeshPath(MapID : integer; StartX : Single; StartY : Single; StartZ : Single; EndX : Single; EndY : Single; EndZ : Single; PathBuffer: PAnsiChar; PathBufferSize: integer): integer; stdcall; external dllname;
var
Path: AnsiString;
Size: Integer;
begin
Size := FindNavMeshPath(..., nil, 0);
if Size <> -1 then
begin
SetLength(Path, Size-1);
FindNavMeshPath(..., PAnsiChar(Path), Size);
...
end;
end;
extern "C" NAVSERVER_API int __stdcall FindNavMeshPath(const int MapID, const float StartX, const float StartY, const float StartZ, const float EndX, const float EndY, const float EndZ, char *PathBuffer, int PathBufferSize)
{
if (pathSize > 0)
{
std::ostringstream oss;
for (int i = 0;i < pathSize; i++)
{
oss << i;
}
oss << "dadsaassaasd";
std::string tmp = oss.str();
size_t needed = tmp.size() + 1;
if (!PathBuffer)
return needed;
if (PathBufferSize < needed)
return -1;
std::copy_n(tmp.c_str(), needed, PathBuffer);
return needed-1;
}
else
{
static const char *errorMsg = "Path return no points.";
static const size_t needed = std::strlen(errorMsg) + 1;
if (!PathBuffer)
return needed;
if (PathBufferSize < needed)
return -1;
std::copy_n(errorMsg, needed, PathBuffer);
return needed-1;
}
}