2016-07-05 17 views
5

Mam "tajemniczą bibliotekę dll" innej firmy napisaną z Delphi (nieznana wersja), działającym przykładem w delphi (przeszłość 2009), pilną potrzebą użycia wspomnianej biblioteki DLL w moim kodzie C# i prawie nie ma odpowiedniej wiedzy o tym, jak to zrobić.Używanie biblioteki DLL Delphi w C#

Oto przykład Delpi w użyciu tego dll:

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; 

i tu jest moje próby interpretowania go w C#:

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

Niestety, co mam jest błąd: Próba odczytu lub zapisz pamięć chronioną. Często jest to wskazówką, że inna pamięć jest uszkodzona.

Z tego, co przeczytałem w ciągu dnia, prawdopodobnie zmyliłem typ zwrotu lub typy parametrów. Wsparcie?

+0

Wygląda na to, że konwencja telefonowania może być błędna między innymi. Nie jestem ekspertem od Delphi, ale może to pomóc http://stackoverflow.com/questions/16601423/calling-a-delphi-method-in-a-dll-from-c-sharp –

+0

Eww, funkcje DLL nie powinny nigdy powracać dowolny typ łańcucha, który może powodować problemy. –

+0

Czy jest szansa, że ​​ta biblioteka DLL Delphi używa ShareMem? –

Odpowiedz

5

ABI Delphi różni się od ABI Microsoft dla niektórych typów. Delphi WideString to typ zarządzany (w terminologii Delphi), a jako typy zwracane używane są ABI niekompatybilne z narzędziami Microsoft.

Delphi ABI tłumaczy zarządzany typ powrotu na ukryty parametr var. Więc kompilator zamienia:

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

do

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

Można zatem uzyskać dostęp do pierwotnej funkcji Delphi od C# importując funkcję w przekształconej formie.

[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

W zasadzie to rozgryzłem. Z jakiegoś powodu niejasne dla mnie, C# nie może obsługiwać wartości zwracanych WideString. Jeśli masz dostęp do kodu źródłowego delphi, może być właściwa wymiana funkcji za pomocą procedury i przekazywanie wartości zwracanej jako parametru "out". W moim przypadku nie miałem dostępu do źródła, więc musiałem napisać bibliotekę DLL proxy, aby to zrobić. Dla powyższego przykładu, kod dll "proxy":

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; 

Następnie kod C# do niego dostęp:

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

jego nie całkiem, ale dla mnie to była odpowiedź.

+0

Czy widziałeś link opublikowany przez @MBo? AFAICS, wartość zwracana przez WideString ** jest w rzeczywistości obecnie parametrem out i powinna być zadeklarowana jako taka po stronie C#. Najpierw spróbowałbym tego. –

+0

Nie trzeba biblioteki proxy DLL, zobacz moją odpowiedź. To powiedziawszy, proxy DLL jest czystym sposobem radzenia sobie z trudnym importem, po prostu nie jest tu potrzebny. Ponadto, 'Word' zamienia się na' ushort'. –

+0

@DavidHeffernan Próbowałem pozbyć się biblioteki DLL proxy, tak jak sugerowałeś, ale wciąż otrzymuję komunikat "Próba odczytu lub zapisu chronionej pamięci". błąd. Zmieniono int do ushort btw. –