在 Freepascal 编译的 DLL 和 Delphi 编译的 EXE 之间交换字符串 (PChar)

2023-12-04

经过大量实验,我找到了一种将 FreePascal 编译的 DLL 中的 PChar 与 Delphi 编译的 EXE 交换的方法。我负责 DLL 和 EXE 源代码,但其中一个必须在 FreePascal 中,另一个在 Delphi 中。我的解决方案涉及DLL中的以下方法:

function GetAString(): PChar;
var aString: string;
begin
  aString := 'My String';
  result := StrAlloc(length(aString) + 1);
  StrPCopy(result, aString); 
end;

procedure FreeString(aString: PChar);
begin
  StrDispose(aString); 
end;

从 Delphi EXE 中,要调用 GetAString 方法,我需要调用 GetAString 方法,将 PChar 保存到实际的 Delphi String 并调用 FreeString 方法。

这是从 FreePascal DLL 与 Delphi EXE 交换字符串的最佳方法吗?我可以避免从 Delphi 调用 FreeString 吗?

最后,如果这是正确的解决方案,默认情况下它在 Delphi 2010 和 WideString 中的表现如何:我是否也需要在 FreePascal 中强制使用 WidePChar?


一种在 DLL 和 Delphi 应用程序之间交换字符串而不使用FreeString调用是从调用应用程序获取字符串缓冲区作为PChar,并填充DLL中的缓冲区。这就是 Windows API 函数需要与调用应用程序交换字符串时的工作方式。

为此,您的调用应用程序创建一个字符串缓冲区,并发送一个PChar将该缓冲区以及缓冲区大小引用到您的 DLL 函数。如果缓冲区大小小于 DLL 必须发送到应用程序的实际字符串,则 DLL 函数可以将缓冲区实际所需的大小发送到调用应用程序。

默认情况下,它在 Delphi 2010 和 WideString 中的表现如何:我也需要在 FreePascal 中强制使用 WidePChar 吗?

在德尔福 2009 和德尔福 2010 中,PChar等于PWideChar。在以前版本的 Delphi 中,据我所知,在 FreePascal 中,PChar等于PAnsiChar。所以如果你回来PChar从您的 DLL 中,您的代码将无法在 Delphi 2010 中正常工作。您应该明确使用PAnsiChar or PWideChar。您可以再次遵循 Windows API 函数的模式:它们几乎为每个 API 函数提供两个版本 - 一个带有WideChar支持谁的名字有W字符作为后缀,另一个带有AnsiChar支持其名字带有A字符作为后缀。

你的 DLL 函数声明将是这样的:

function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean;

function AStringFuncA(Buffer: PAnsiChar; var BufferSize: Integer): Boolean;

EDIT:

这是示例代码:

  1. 您的 DLL 函数WideChar会是这样的:

    function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall;
    var
      MyOutputStr : WideString;
    begin
      Result := False;
    
      // Calculate your output string here.
      MyOutputStr := 'This is a sample output';
    
      // Check if buffer is assigned, and its given length is enough
      if Assigned(Buffer) and (BufferSize >= Length(MyOutputStr) + 1) then
      begin
        // Copy output string into buffer
        StrPCopy(Buffer,MyOutputStr);
        Result := True;
      end;
      // Return actual size of output string.
      BufferSize := Length(MyOutputStr) + 1;
    end;
    

    For the AnsiChar您使用的版本PAnsiChar作为参数和几乎相似的代码AnsiString作为变量,或者将参数转换为PWideChar并调用你自己的AStringFuncW在你的里面AStringFuncA函数,您将其结果转换回PAnsiChar.

  2. 以下是如何在接口单元中定义这些函数以供 DLL 客户端使用:

    unit TestDLLIntf;
    
    interface
    
    const
      TestDll = 'Test.dll';
    
      function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall;
      function AStringFuncA(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall;
      function AStringFunc(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall;
    
    implementation
    
    function AStringFuncW; external TestDll name 'AStringFuncW';
    function AStringFuncA; external TestDll name 'AStringFuncA';
    {$IFDEF UNICODE}
     function AStringFunc; external TestDll name 'AStringFuncW';
    {$ELSE}
     function AStringFunc; external TestDll name 'AStringFuncA';
    {$ENDIF}
    
    end.
    

    在上面的代码中,两者AStringFuncW and AStringFuncA函数被声明为外部函数。这AStringFunc函数是指WideCharDelphi 2009 或 2010 中的版本,以及AnsiChar在旧版本中。

  3. 在这里您可以看到 DLL 客户端如何使用您的函数:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Str : string;
      Size : Integer;
    begin
      // Retrieve required buffer size
      AStringFunc(nil,Size);
      // Set buffer
      SetLength(Str,Size);
      // Retrieve output string from DLL function.
      if AStringFunc(PChar(Str),Size) then
        ShowMessage(Str);
    end;
    

    在上面的代码中,客户端应用程序首先从以下位置获取实际输出大小AStringFunc,然后设置一个字符串缓冲区,并从 DLL 中检索输出字符串。请注意,相同的代码应该在 Delphi 的 Unicode 和非 Unicode 版本中都可以工作,因为AStringFunc指的是AStringFuncA or AStringFuncW在您的 DLL 中,具体取决于您的编译器是否支持 Unicode。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Freepascal 编译的 DLL 和 Delphi 编译的 EXE 之间交换字符串 (PChar) 的相关文章

  • 如何将双精度数转换为保留 2 位小数的字符串?

    我正在将这个双精度数转换为字符串 以便可以将其显示在 TextView 上 我希望使用 String format 使字符串具有 2 个小数位 但我不知道将其放在这行文本中的何处 Example setText Double toStrin
  • Objective-C 右填充

    大家好 希望有人可以提供帮助 我正在浏览网络 但似乎没有什么真正有意义的 S 所以我有一个字符串可以说 123 我想使用如下函数 padr 123 5 x 结果应该是 123xx 抱歉 Objective C 在处理字符串时是一场噩梦 S
  • 如何改变TDateTimePicker的颜色?

    如何更改 a 的颜色TDateTimePicker A 日期和时间选择器可以有一种颜色 通常这是通过设置来完成的Color procedure TForm1 FormCreate Sender TObject begin DateTimeP
  • Pascal - 在定义之前使用过程

    我有一段代码 非常简化 如下所示 program helloworld a integer procedure alpha begin writeln This is procedure alpha beta end procedure b
  • 如何在 JavaScript 中检查字符串是否包含子字符串数组中的文本?

    非常简单 在 javascript 中 我需要检查字符串是否包含数组中保存的任何子字符串 没有任何内置功能可以为您执行此操作 您必须为其编写一个函数 尽管它可能只是对some数组方法 两种方法适合您 Array some method 正则
  • 如何在程序中使用非常大的字符串(5 亿个字符)?

    我有一个 txt 文件 其中包含 5 亿位 Pi 的二进制表示形式 我需要在我的程序中使用它的字符串表示形式 我还需要能够搜索它的子字符串等 换句话说 我需要能够像正常大小的字符串一样对待它 我会努力寻找一个lot子串 所以速度是必要的 我
  • 如何打印垂直对齐的文本

    我想在文件中打印以下格式的输出 1 Introduction 1 1 1 Scope 1 1 2 Relevance 1 1 2 1 Advantages 1 1 2 1 1 Economic 2 1 2 2 Disadvantages
  • 将数据从 DLL 传递到应用程序时出现问题

    我对如何在我的场景中正确使用指针感到有点困惑 我有一个 DLL 其中包含一些嵌入式资源 我在此 DLL 中公开了一个函数 该函数将这些资源之一的二进制数据传递回其调用应用程序 在本例中 我嵌入了 JPG 图像文件 我的 DLL 确实将文件正
  • 加载前检查 OSX 包的签名

    目标 加载已验证已签名 或针对任意算法进行验证 的 so bundle 我希望能够使用 OSX 的内置二进制签名工具或某些自定义算法来验证 so bundle 然后使用 dlopen 加载该 so bundle 问题在于似乎没有编程方式来检
  • 在 C# 中使用 COM dll

    我们有用 C 编写的 COM dll 并已被用 vb 6 0 编写的应用程序使用 我的公司计划在 Net 平台上编写新版本的应用程序 就性能而言 在 C 项目中使用 COM dll 时 我应该从下面列出的 3 个选项中选择什么 只需添加 d
  • 在样式定义中使用@string资源

    我在 styles xml 文件中定义了类似以下内容 如下所示 但是Android由于使用 string fontExtraLarge而崩溃 我假设这是因为定义的顺序 但这合法吗 我可以使用样式 parent 属性来解决此问题 但对于只有一
  • 如何取消注册我的应用程序的文件格式?

    在 Windows 10 中的 Delphi 10 4 2 win 32 VCL 应用程序中 我注册了 ICO我的图形应用程序的文件格式使用DSiWin32 DSiRegisterUserFileAssoc https github com
  • 我如何淡入/淡出 TImage?

    我有一个简单的TForm命名为Form1 Image1 是一个TImage加载了一个 PNGImage 和一个 Button1TButton测试事物 成功实现了对图像1的Alpha Blend的方法 代码如下 procedure SetPN
  • 如何替换 JavaScript 中出现的所有字符串?

    给定一个字符串 s Test abc test test abc test test test abc test test abc 这似乎只删除了第一次出现的abc在上面的字符串中 s s replace abc 我该如何更换all它的出现
  • 使用 ELKI 对字符串数据进行聚类

    我需要使用 ELKI 基于编辑距离 编辑距离对大量字符串进行聚类 由于数据集太大 我想避免基于文件的预计算距离矩阵 我怎么能够 a 从文件 仅 标签 加载 ELKI 中的字符串数据 b 实现访问标签的距离函数 扩展 AbstractDBID
  • 将字符串数组转换为字节数组

    好吧 在有人试图将其标记为重复之前 我是not要求将字符串转换为字节数组 我想要一个字符串数组 包含类似这样的内容 5 168 188 28 29 155 转换为字节数组 我已经搜索过 只能找到字符串到字节数组 这是完全不同的 谢谢 编辑
  • Delphi - 引用在运行时创建的组件

    我正在使用 Delphi 5 并且在运行时创建许多面板 然后在面板上创建按钮 显然也是在运行时创建 我需要这样做 因为将来我可能需要动态创建更多面板 按钮组合 我可以完成所有这些 但我不知道如何引用我创建的面板 因为我找不到访问面板组件名称
  • Delphi 生成的 Dylib 在 OSX 上的可靠部署

    我想在 OSX 上部署一个 dylib 它是用 Delphi 创建的 这个 dylib 应该是可由第三方应用程序加载 这看起来像是一个重复的问题 但经过大量搜索后 我找不到答案 这和这个是同一个问题 https forums embarca
  • 应用程序需要很长时间才能同步线程(或根本不同步)

    我在 Delphi XE5 iOS 和 Android 中使用 REST 组件 我目前正在通过 iOS 模拟器进行测试 我的应用程序often挂在我的代码中的以下行 R Request Execute 经过一些调试后 我发现它特别挂在 RE
  • Python 按照层次结构按多个分隔符分割字符串

    我只想根据多个分隔符 例如 and 和 按顺序分割字符串一次 例子 121 34 adsfd gt 121 34 adsfd dsfsd and adfd gt dsfsd adfd dsfsd adfd gt dsfsd adfd dsf

随机推荐