如何在C#中使用Delphi Dll(带PChar类型)

Leo*_*Leo 3 .net c# delphi pinvoke

这是Delphi DLL代码:

library Project2;

uses
  SysUtils,
  Classes;

{$R *.res}

function SimpleConv(const s: string): string;
var
  i: Integer;
begin
  Result := '';
  for i := 1 to Length(s) do
    if Ord(S[i]) < 91 then
      Result := Result + S[i];
end;

function MsgEncode(pIn: pchar; InLen: Integer; var pOut: pchar; var OutLen: Integer): Boolean; stdcall;
var
  sIn: string;
  sOut: string;
begin
  SetLength(sIn, InLen);
  Move(pIn^, sIn[1], InLen);

  sOut := SimpleConv(sIn);   // Do something

  OutLen := Length(sOut);
  GetMem(pOut, OutLen);
  Move(sOut[1], pOut^, OutLen);
  Result := OutLen > 0;
end;

procedure BlockFree(Buf: pchar); stdcall;
begin
  if assigned(Buf) then
     FreeMem(Buf);
end;

exports
  MsgEncode,
  BlockFree;

begin
end.
Run Code Online (Sandbox Code Playgroud)

Dll函数MsgEncode将allocmem分配给pOut param,而BlockFree用于释放由MsgEncode分配的内存.

我的问题是:我怎样才能在C#中使用这个dll?我是C#的新手.

Dav*_*nan 9

我将以面值来回答您的问题,并附带几个附带条件:

  • 无论您是否使用Unicode Delphi,都必须知道使用互操作代码,PChar因为PChar浮动之间AnsiCharWideChar取决于Delphi的版本.我假设您使用Unicode Delphi.如果没有,那么你需要在P/Invoke端更改字符串编组.
  • 我修改了你的DLL代码.我删除了长度参数,并假设您只是让受信任的代码调用此DLL.不受信任的代码可能会产生缓冲区溢出,但您不会让不受信任的代码在您的计算机上运行,​​是吗?
  • 我也改变BlockFree了它,它可以接收一个无类型的指针.没有必要将它作为类型PChar,它只是调用Free.

这是修改后的Delphi代码:

library Project2;

uses
  SysUtils;

{$R *.res}

function SimpleConv(const s: string): string;
begin
  Result := LowerCase(s);
end;

function MsgEncode(pIn: PWideChar; out pOut: PWideChar): LongBool; stdcall;
var
  sOut: string;
  BuffSize: Integer;
begin
  sOut := SimpleConv(pIn);
  BuffSize := SizeOf(Char)*(Length(sOut)+1);//+1 for null-terminator
  GetMem(pOut, BuffSize);
  FillChar(pOut^, BuffSize, 0);
  Result := Length(sOut)>0;
  if Result then
    Move(PChar(sOut)^, pOut^, BuffSize);
end;

procedure BlockFree(p: Pointer); stdcall;
begin
  FreeMem(p);//safe to call when p=nil
end;

exports
  MsgEncode,
  BlockFree;

begin
end.
Run Code Online (Sandbox Code Playgroud)

这是另一方的C#代码:

using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("project2.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool MsgEncode(string pIn, out IntPtr pOut);

        [DllImport("project2.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
        public static extern void BlockFree(IntPtr p);

        static void Main(string[] args)
        {
            IntPtr pOut;
            string msg;
            if (MsgEncode("Hello from C#", out pOut))
                msg = Marshal.PtrToStringAuto(pOut);
                BlockFree(pOut);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该让你开始.由于您是C#的新手,因此您需要在P/Invoke上进行相当多的阅读.请享用!

  • @Warren你不能这样做,这段代码不能那样做!它在Delphi中使用相同的堆进行GetMem和FreeMem. (2认同)