0

我有一个使用 BTMemoryModule 并从 DLL 导入/调用函数的 delphi 应用程序。DLL 是用 C/C++ 编写的。

delphi 应用程序将原始 pwidechar(4 字节数组或宽字符数组)发送到函数。

我没有 C/C++ 伪代码,但它看起来像这样:

type
 TMyFunc = function ( p  : pointer ): pointer; stdcall;

procedure anynamehere();
var
 Addr     : TMyFunc;
 MyString : WideString;
begin
 [...]
  Addr := BTMemoryGetProcAddress('mydll.dll', 'ExportedFunc');
  MyString := 'TEST';
 [...]
 ExportedFunc (pwidechar(MyString));
 MessageBoxW (0, pwidechar(MyString), '', 0);
end;

DLL 现在应该具有指向 MyString var 的原始指针。delphiapp 中的过程保持活动状态(直到 dll ExportedFunc 完成)。因此,MyString var 在过程结束后不会被释放。我现在的问题是:是否可以在 DLL 中更改 MyString 的值?(技术上可能......)但是如何?该字符串以空结尾,因此用户知道指针长度有多长。但是如果 C++ DLL 改变了值,用户是不是也分配了新的空间什么的?或者这会自动发生吗?

谢谢你的帮助。

4

3 回答 3

3

如果需要,欢迎 DLL 更改指向的内存,它也不需要知道 的地址MyString。它只需要知道存储在 中 MyString的地址,这正是您已经传递给它的地址。由于该函数接收一个指向以空值结尾的数组的指针WideChar,因此该函数应声明如下:

void* __stdcall ExportedFunc(wchar_t* arg);

它可以用 找出缓冲区的长度wcslen,然后以通常的方式修改缓冲区的内容。例如:

{
  size_t const len = wcslen(arg);
  for (size_t i = 0; i < len; ++i)
    if (arg[i] == 'a')
      arg[i] = 'e';
  return 0;
}

如果你愿意,你可以让它返回一些其他的指针值,但是由于调用者忽略它,在这种情况下它并不重要。

当调用者为 分配值时MyString,操作系统会代表程序通过 自动分配空间SysAllocString。然后调用者将该缓冲区传递给 DLL,DLL 可以对其进行修改。调用者之后不需要对缓冲区做任何特殊的事情。SysFreeString当调用函数结束并MyString超出范围时, Delphi 会自动调用。

您还可以删除PWideChar类型转换并声明函数以WideString在 Delphi中接收 a,BSTR在 C++ 中接收 a。除了使用SysStringLen代替wcslen. 您可以MyString直接传递给函数:

ExportedFunc(MyString);
于 2012-07-30T16:39:32.323 回答
2

C++ 代码可以更改传入的 pwidechar 数组的内容,但它无法更改 delphi 所理解的字符串的长度,因为 C++ 代码本身不理解 delphi 样式的字符串。它接收的只是一个wchar *参数。

如果您想对字符串进行重大更改,例如使其更长,那么您需要通过使用在调用者中分配至少尽可能多的空间SetLength(MyString, size),然后在返回时检查长度,然后再调用SetLength(MyString, retSize)字符串使其成为返回的大小。

同样,对于缓冲区溢出等通常的警告。

我注意到该函数返回一个指针;如果 C++ 代码使用 分配内存new(),那么您将无法从 Delphi 代码管理此内存,因为两个内存分配系统不同。

于 2012-07-30T16:37:09.017 回答
2

DLL 被传递一个指向缓冲区的指针。DLL 完全有可能修改该缓冲区。DLL 可以修改您的代码传递给它的 4 个宽字符中的任何一个。它还可以修改第五个字符,即空终止符。

但是,DLL 无法创建新缓冲区并让调用代码看到该新缓冲区。

于 2012-07-30T16:37:15.163 回答