You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Inno Setup Pascal脚本中处理.NET导出函数返回的字符串

解决Unicode版本Inno Setup调用.NET导出函数返回字符串的问题

最优方案:缓冲区填充模式(无指针、无内存泄漏)

Unicode版本Inno Setup v6.3.3默认使用WideString(UTF-16编码),直接返回托管字符串或非托管指针容易引发内存访问错误或泄漏,缓冲区填充模式是最安全可靠的实现方式:由Inno分配内存缓冲区,.NET函数将结果写入缓冲区,同时返回字符串实际长度。

.NET端(C# 示例,基于DllExport)

using System;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;

public class InnoHelper
{
    // 导出函数:填充版本字符串到缓冲区,返回实际需要的缓冲区长度(含终止符)
    [DllExport("GetInnoHelperVersion", CallingConvention = CallingConvention.StdCall)]
    public static int GetInnoHelperVersion(IntPtr buffer, int bufferSize)
    {
        string version = "1.0.0.0"; // 替换为你的实际版本字符串
        // 转换为UTF-16字节数组(匹配Inno的WideString编码),添加字符串终止符
        byte[] versionBytes = System.Text.Encoding.Unicode.GetBytes(version + "\0");
        int requiredLength = versionBytes.Length;

        // 缓冲区有效且大小足够时,写入内容
        if (buffer != IntPtr.Zero && bufferSize >= requiredLength)
        {
            Marshal.Copy(versionBytes, 0, buffer, requiredLength);
        }

        // 返回所需缓冲区长度,供Inno分配内存使用
        return requiredLength;
    }
}

Inno Setup端(Pascal脚本)

[Code]
// 声明导出函数
function GetInnoHelperVersion(buffer: String; var bufferSize: Integer): Integer;
  external 'GetInnoHelperVersion@files:InnoHelper.dll stdcall';

procedure InitializeWizard;
var
  VersionStr: String;
  RequiredSize: Integer;
begin
  // 第一步:获取所需缓冲区的字节长度
  RequiredSize := GetInnoHelperVersion('', 0);
  
  // 第二步:分配对应大小的字符串缓冲区(WideString每个字符占2字节,除以2得到字符数)
  SetLength(VersionStr, RequiredSize div 2);
  
  // 第三步:填充缓冲区并获取版本字符串
  GetInnoHelperVersion(VersionStr, RequiredSize);
  
  // 输出结果(按需使用)
  MsgBox('Helper版本: ' + VersionStr, mbInformation, MB_OK);
end;

之前方法出错的原因

  • 直接返回字符串(GetInnoHelperVersionStr):.NET的托管字符串内存由CLR管理,Inno作为非托管程序无法正确访问这块内存,触发内存访问违规。
  • 返回指针(GetInnoHelperVersionPtrA/W):若用Marshal.AllocHGlobal分配非托管内存,Inno读取后无法直接释放该内存(权限不兼容),必须额外导出释放函数,否则会造成内存泄漏;乱码则是因为ANSI编码(PtrA)与Inno默认的UTF-16编码不匹配。

可选方案:带内存释放的指针模式(不推荐,仅作兼容参考)

如果必须使用指针返回字符串,需额外导出内存释放函数:

.NET端补充代码

[DllExport("FreeInnoHelperString", CallingConvention = CallingConvention.StdCall)]
public static void FreeInnoHelperString(IntPtr ptr)
{
    Marshal.FreeHGlobal(ptr);
}

[DllExport("GetInnoHelperVersionPtrW", CallingConvention = CallingConvention.StdCall)]
public static IntPtr GetInnoHelperVersionPtrW()
{
    string version = "1.0.0.0";
    // 分配非托管UTF-16字符串内存
    return Marshal.StringToHGlobalUni(version);
}

Inno Setup端对应代码

[Code]
function GetInnoHelperVersionPtrW: Integer; external 'GetInnoHelperVersionPtrW@files:InnoHelper.dll stdcall';
procedure FreeInnoHelperString(ptr: Integer); external 'FreeInnoHelperString@files:InnoHelper.dll stdcall';

procedure InitializeWizard;
var
  VersionPtr: Integer;
  VersionStr: String;
begin
  VersionPtr := GetInnoHelperVersionPtrW;
  try
    VersionStr := WideString(VersionPtr);
    MsgBox('Helper版本: ' + VersionStr, mbInformation, MB_OK);
  finally
    FreeInnoHelperString(VersionPtr); // 必须调用释放,否则内存泄漏
  end;
end;

内容的提问来源于stack exchange,提问作者ElektroStudios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:49:52