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

C#调用Delphi DLL时如何覆盖字符串封送的默认编码?

解决C# .NET Core 7调用Delphi 2007 DLL时指定WIN1250编码封送字符串的问题

Delphi 2007中的PChar对应WIN1250编码的ANSI字符,但C#默认的ANSI字符集封送会使用系统当前代码页,导致非WIN1250环境下字符传递异常。以下是针对输入、输出参数的手动编码控制方案:

一、输入参数的处理

CLR自动封送字符串无法指定编码,需手动将C#字符串转换为WIN1250编码的字节数组,再分配非托管内存传递:

  1. 修改DLL导入定义,用IntPtr替代string作为参数类型:
[DllImport(@"LibraryName.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool TestSignString(IntPtr s, IntPtr sign);
  1. 调用时手动转换并管理内存:
// 定义WIN1250编码
Encoding win1250 = Encoding.GetEncoding(1250);

string inputS = "待传递的字符串";
string inputSign = "签名内容";

// 将字符串转为WIN1250字节数组,添加C风格终止符'\0'
byte[] sBytes = win1250.GetBytes(inputS + '\0');
byte[] signBytes = win1250.GetBytes(inputSign + '\0');

// 分配非托管内存
IntPtr sPtr = Marshal.AllocHGlobal(sBytes.Length);
IntPtr signPtr = Marshal.AllocHGlobal(signBytes.Length);

try
{
    // 将字节数组复制到非托管内存
    Marshal.Copy(sBytes, 0, sPtr, sBytes.Length);
    Marshal.Copy(signBytes, 0, signPtr, signBytes.Length);

    // 调用DLL函数
    bool result = TestSignString(sPtr, signPtr);
}
finally
{
    // 释放非托管内存,避免泄漏
    Marshal.FreeHGlobal(sPtr);
    Marshal.FreeHGlobal(signPtr);
}

二、输出参数的处理

如果DLL函数需要向C#返回字符串(通过输出参数写入缓冲区),需提前分配足够的非托管内存,调用后用WIN1250编码读取内容:

假设Delphi DLL有如下输出函数:

function TestGetSignedString(input: PChar; outputBuffer: PChar; bufferSize: Integer): LongBool; stdcall;
  1. C#导入定义:
[DllImport(@"LibraryName.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool TestGetSignedString(IntPtr input, IntPtr outputBuffer, int bufferSize);
  1. 调用时处理输出:
Encoding win1250 = Encoding.GetEncoding(1250);
string inputStr = "输入字符串";
int bufferSize = 256; // 根据实际需求设置足够大的缓冲区

// 转换输入字符串
byte[] inputBytes = win1250.GetBytes(inputStr + '\0');
IntPtr inputPtr = Marshal.AllocHGlobal(inputBytes.Length);
Marshal.Copy(inputBytes, 0, inputPtr, inputBytes.Length);

// 分配输出缓冲区
IntPtr outputPtr = Marshal.AllocHGlobal(bufferSize);

try
{
    bool success = TestGetSignedString(inputPtr, outputPtr, bufferSize);
    if (success)
    {
        // 从非托管内存读取字节,直到遇到终止符'\0'
        List<byte> outputBytes = new List<byte>();
        int offset = 0;
        while (true)
        {
            byte b = Marshal.ReadByte(outputPtr, offset);
            if (b == 0) break;
            outputBytes.Add(b);
            offset++;
            if (offset >= bufferSize) break; // 防止缓冲区溢出
        }

        // 将字节数组转为C#字符串
        string outputStr = win1250.GetString(outputBytes.ToArray());
    }
}
finally
{
    // 释放所有非托管内存
    Marshal.FreeHGlobal(inputPtr);
    Marshal.FreeHGlobal(outputPtr);
}

关键说明

  • 必须手动管理非托管内存,调用完成后务必释放,避免内存泄漏。
  • Encoding.GetEncoding(1250)依赖系统支持该代码页,WIN1250为常见中欧编码,多数系统默认支持。

内容的提问来源于stack exchange,提问作者J. Ogurek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:25:21