3 Stimmen

Wie man Delphi Dll (mit PChar-Typ) in C# verwendet

Hier ist der Delphi DLL-Code:

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.

Die Dll-Funktion MsgEncode weist dem pOut-Parameter Speicher zu, und BlockFree wird verwendet, um den von MsgEncode zugewiesenen Speicher freizugeben.

Meine Frage ist: Wie kann ich diese DLL in C# verwenden? Ich bin ein Neuling in C#.

10voto

David Heffernan Punkte 585606

Ich werde Ihre Frage für bare Münze nehmen, allerdings mit einigen Vorbehalten:

  • Ob Sie ein Unicode-Delphi verwenden oder nicht, ist entscheidend für Interop-Code mit PChar denn PChar schwebt zwischen AnsiChar y WideChar abhängig von der Version von Delphi. Ich bin davon ausgegangen, dass Sie Unicode-Delphi verwenden. Wenn nicht, müssen Sie das String-Marshalling auf der P/Invoke-Seite ändern.
  • Ich habe Ihren DLL-Code geändert. Ich habe die Längenparameter entfernt und gehe davon aus, dass Sie nur vertrauenswürdigen Code diese DLL aufrufen lassen werden. Nicht vertrauenswürdiger Code könnte zu Pufferüberläufen führen, aber Sie werden doch nicht zulassen, dass nicht vertrauenswürdiger Code auf Ihrem Rechner ausgeführt wird, oder?
  • Ich habe auch geändert BlockFree so dass es einen nicht typisierten Zeiger empfangen kann. Es ist nicht notwendig, dass es Typen wie PChar ruft es einfach an Free .

Hier ist der geänderte Delphi-Code:

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.

Und hier ist der C#-Code auf der anderen Seite:

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);
        }
    }
}

Damit sollten Sie beginnen können. Da Sie neu in C# sind, werden Sie einiges an Lesestoff über P/Invoke benötigen. Viel Spaß!

4voto

dthorpe Punkte 34584

Beachten Sie, dass C#-Stringdaten Unicode sind. Wenn Sie also mit diesem Delphi-Code unter Verwendung von PChar fortfahren, wird eine versteckte Konvertierung von PChar zu PWideChar im PInvoke-Aufruf durchgeführt. (Konvertierung bedeutet Zuweisung eines anderen Speicherpuffers und Kopieren aller Daten in den neuen Puffer). Wenn Sie beabsichtigen, diesen Delphi-Code mit C# zu verwenden, und Ihnen die Leistung wichtig ist, sollten Sie Ihren Delphi-Code ändern, um stattdessen mit PWideChar-Daten zu arbeiten.

Es gibt noch einen weiteren Grund für die Verwendung von PWideChar anstelle von PChar: Delphi weist den OleString-Typ mithilfe des Win32 SysAllocString-Allokators zu, wie es die COM-Anforderungen verlangen. Das bedeutet, dass der Empfänger des Strings in der Lage ist, die Zuweisung über die Win32-API aufzuheben.

Wenn Sie in Ihrer Funktion nicht tatsächlich Text verarbeiten, sondern PChar als Surrogat für ein Array beliebiger Byte-Werte verwenden, können Sie damit auf der nicht verwalteten Seite des Aufrufs durchkommen, nicht aber auf der verwalteten Seite. Wenn es sich um Byte-Daten handelt, sollte es als Array of Byte deklariert werden, um Zeichensatz- oder Zeichengrößenkonvertierungen zu vermeiden.

Auf der C#-Seite des Hauses müssen Sie PInvoke verwenden, um die nicht verwaltete Delphi-DLL-Funktion aufzurufen. Siehe pinvoke.net für Details darüber, wie man den Aufruf in C# annotiert, damit PInvoke sich automatisch um die Pufferzuweisung kümmert. Suchen Sie eine Win32-API-Funktion, die PChar- (oder PWideChar-) Parameter ähnlich Ihrer Funktion übergibt, und suchen Sie dann auf PInvoke.net nach der PInvoke-Deklaration, die Sie im verwalteten Code verwenden können.

1voto

kludg Punkte 26889

Bearbeitet

Entschuldigung, ich habe nicht gesehen, dass Sie auch die Funktion BlockFree exportieren.

Als Faustregel gilt: Speicher immer im gleichen Modul zuweisen und freigeben; wenn Sie Speicher in einer Dll zuweisen, sollte er auch in der gleichen Dll wieder freigegeben werden.

Wenn Sie also mit BlockFree Speicher freigeben, können Sie im selben Modul Speicher zuweisen und freigeben, das ist in Ordnung.

Beachten Sie, dass die Delphi-String- und PChar-Typen versionsabhängig sind - sie sind ANSI vor Delphi 2009 und UNICODE in Delphi 2009 und danach.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X