2016-07-05 1 views
5

Ich habe eine "mystery dll" von Drittanbietern geschrieben mit Delphi (unbekannte Version), funktionierendes Beispiel in Delphi (letzten 2009), dringend brauche diese DLL in meinem C# -Code und fast keine relevanten Kenntnisse wie man es macht.Verwenden von Delphi DLL in C#

Hier ist Delpi Beispiel diese DLL in Verwendung:

type 
TD_Query = function(host: WideString; port : Word;pud,query : WideString):WideString; stdcall; 
procedure TForm11.Button6Click(Sender: TObject); 
var 
    Handle   : LongWord; 
    D_Query  : TD_Query; 
    sss   : WideString; 
begin 

Handle := LoadLibrary('kobrasdk.dll'); 
sss:=''; 
if Handle <> 0 then 
begin 
    @D_Query := GetProcAddress(Handle, 'D_Query'); 
    sss:=D_Query('host',8201,'pud','query'); 
    FreeLibrary(Handle); 
end; 
end; 

Und hier ist meine Versuche, es in C# zu interpretieren:

class Program 
{ 
    [DllImport("C:\\Games\\kobrasdk.dll", CallingConvention = CallingConvention.StdCall, 
     CharSet = CharSet.Ansi)] 
    [return: MarshalAs(UnmanagedType.LPStr)] 
    public static extern string D_Query(string host, ushort port, string pud, string query); 


    static void Main(string[] args) 
    { 
     D_Query("test", 8201, "test", "test"); 
    } 
} 

Leider, was ich habe, ist ein Fehler: Versuchte zu lesen oder schreibe geschützten Speicher. Dies ist oft ein Hinweis darauf, dass anderer Speicher beschädigt ist.

Von dem, was ich während des Tages gelesen habe, habe ich wahrscheinlich mit Rückgabetyp oder Parameter Typen fudged. Hilfe?

+0

Es scheint, dass Ihre Aufrufkonvention unter anderen Problemen falsch sein kann. Ich bin kein Delphi-Experte, aber das kann helfen http://StackOverflow.com/questions/16601423/calling-a-Delphi-method-in-a-dll-from-c-sharp –

+0

Eww, DLL-Funktionen sollten nie zurückkehren jede Art von String, die Probleme verursachen kann. –

+0

Gibt es eine Chance, dass diese Delphi DLL ShareMem verwendet? –

Antwort

5

Die Delphi ABI unterscheidet sich von der Microsoft ABI für bestimmte Typen. Ein Delphi WideString ist ein verwalteter Typ (in Delphi-Terminologie) und verwendet als Rückgabetypen eine ABI, die mit Microsoft-Tools nicht kompatibel ist.

Der Delphi-ABI übersetzt einen verwalteten Rückgabetyp in einen versteckten var-Parameter. So ist der Compiler wandelt:

function(host: WideString; port: Word; pud, query: WideString): WideString; stdcall; 

in

procedure(var result: WideString; host: WideString; port: Word; pud, query: WideString); 
    stdcall; 

Sie deshalb Ihre ursprüngliche Delphi-Funktion von C# durch den Import der Funktion in seiner transformierten Gestalt zugreifen können.

[DllImport(@"...", CallingConvention = CallingConvention.StdCall)] 
public static extern void My_D_Query(
    [MarshalAs(UnmanagedType.BStr)] 
    out string result, 
    [MarshalAs(UnmanagedType.BStr)] 
    string host, 
    ushort port, 
    [MarshalAs(UnmanagedType.BStr)] 
    string pud, 
    [MarshalAs(UnmanagedType.BStr)] 
    string query 
); 
0

Ich habe es meistens herausgefunden. Aus irgendeinem Grund, der für mich unklar ist, kann C# keine WideString-Rückgabewerte verarbeiten. Wenn Sie Zugriff auf Delphi-Quellcode haben, ist es möglicherweise sinnvoll, die Funktion mit der Prozedur auszutauschen und den Rückgabewert als "out" -Parameter zu übergeben. In meinem Fall hatte ich keinen Zugriff auf die Quelle, weshalb ich gezwungen wurde, eine Proxy-DLL zu schreiben. Zum Beispiel oben, "Proxy" DLL-Code:

type 
    TD_Query = function(host : WideString;port : Word;pud,query : WideString):WideString; stdcall; 

procedure My_D_Query(host: WideString; port: Word; pud, query: WideString; out return : WideString); stdcall; 
var 
    Handle: LongWord; 
    D_Query : TD_Query; 
    sss : WideString; 
begin 
Handle := LoadLibrary('kobrasdk.dll'); 
sss:=''; 
if Handle <> 0 then 
begin 
    @D_Query:=GetProcAddress(Handle, 'D_Query'); 
    sss:=D_Query(host,port,pud,query); 
    FreeLibrary(Handle); 
end; 
return := sss; 
end; 

Dann Code C#, um darauf zuzugreifen:

[DllImport("C:\\MyDll.dll", CallingConvention = CallingConvention.StdCall, 
    CharSet = CharSet.Ansi)] 
public static extern void My_D_Query(
[MarshalAs(UnmanagedType.BStr)] 
     string host, 
     int port, 
[MarshalAs(UnmanagedType.BStr)] 
     string pud, 
[MarshalAs(UnmanagedType.BStr)] 
     string query, 
[MarshalAs(UnmanagedType.BStr)] 
     out string result 
); 

Es ist nicht schön, aber für mich war es die Antwort.

+0

Haben Sie den Link gesehen, den @MBo gepostet hat? AFAICS, der WideString-Rückgabewert ** ist in Wirklichkeit bereits ein out-Parameter ** und sollte auf der C# -Seite als solcher deklariert werden. Ich würde das zuerst versuchen. –

+0

Keine Notwendigkeit für eine Proxy-DLL, siehe meine Antwort. Das heißt, eine Proxy-DLL ist eine saubere Möglichkeit, um knifflige Importe zu bewältigen, sie wird hier nicht benötigt. Außerdem wird "Word" auf "ushort" abgebildet. –

+0

@DavidHeffernan Ich habe versucht, Proxy-DLL loszuwerden, wie Sie vorgeschlagen, aber ich bekomme immer "versucht, geschützten Speicher zu lesen oder zu schreiben." Error. In inthort geändert. –