2016-07-05 9 views
5

У меня есть сторонняя «тайна dll», написанная с помощью Delphi (неизвестная версия), рабочий пример в delphi (в прошлом 2009 году), крайне необходимо использовать указанную DLL в моем коде C# и почти не иметь соответствующих знаний о том, как это сделать.Использование Delphi DLL в C#

Вот пример Delpi в использовании этой библиотеки 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; 

А вот мои попытки интерпретировать его в 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"); 
    } 
} 

К сожалению, то, что у меня есть ошибка: Попытка чтения или записать защищенную память. Это часто свидетельствует о том, что другая память повреждена.

Из того, что я читал в течение дня, я, вероятно, испорчен возвращаемым типом или параметрами. Помогите?

+0

Похоже, что ваша конвенция о вызове может быть неправильной среди других проблем. Я не эксперт Delphi, но это может помочь http://stackoverflow.com/questions/16601423/calling-a-delphi-method-in-a-dll-from-c-sharp –

+0

Eww, функции DLL никогда не должны возвращаться любой тип строки, который может вызвать проблемы. –

+0

Есть ли вероятность, что эта DLL Delphi использует ShareMem? –

ответ

5

Delphi ABI отличается от Microsoft ABI для определенных типов. Delphi WideString - это управляемый тип (в терминологии Delphi), а в качестве типов возврата используется ABI, который несовместим с инструментами Microsoft.

Delphi ABI переводит управляемый возвращаемый тип в скрытый параметр var. Таким образом, компилятор преобразует:

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

в

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

поэтому Вы можете получить доступ к исходной функции Delphi из C#, импортируя функции в трансформированном облике.

[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

Я в основном выяснил это. По какой-то причине мне непонятно, C# can not обрабатывает значения WideString. Если у вас есть доступ к исходному коду delphi, может быть целесообразным обменяться функцией с процедурой и передать возвращаемое значение как параметр «out». В моем случае у меня не было доступа к источнику, поэтому я был вынужден написать прокси-библиотеку для этого. В приведенном выше примере, «прокси» длл код:

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; 

Тогда C# код для доступа к нему:

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

Сво не очень, но для меня, это был ответ.

+0

Вы видели ссылку, которую размещал @MBo? AFAICS, возвращаемое значение WideString ** на самом деле является параметром out ** и должно быть объявлено как таковое на стороне C#. Я бы попробовал это первым. –

+0

Нет необходимости в прокси-библиотеке, см. Мой ответ. Тем не менее, прокси-библиотека - это чистый способ справиться с сложным импортом, здесь просто не нужен. Кроме того, 'Word' отображает' ushort'. –

+0

@DavidHeffernan Я пытался избавиться от прокси-библиотеки DLL, как вы предлагали, но я продолжаю получать «Попытка читать или писать защищенную память». ошибка. Изменено int to ushort btw. –