2014-11-17 3 views
1

Я новичок в программировании, может ли кто-нибудь помочь мне вызвать функцию указателя из dll delphi в Visual C#.C# Dllimport Delphi Pointer

Это функция Delphi, хранящаяся в DLL. // Delphi код, хранящийся в DLL

function DeviceName(Size : Integer; Msg : Pointer) : Integer stdcall; 
var 
    i: Integer; 
    TempByte : PByte; 
    TempName : string; 
begin 
    if DLLClass.DevList.HidDevices.Count > 0 then 
    begin 
    TempName := (DLLClass.DevList.HidDevices.Name[DLLClass.HIDTool.CurrentDeviceIndex]); 
    if Length(TempName) <= Size then 
    begin 
     try 
     TempByte := Msg; 
     for i := 0 to Length(TempName) - 1 do 
     begin 
      TempByte^ := Ord(TempName[i+1]); 
      Inc(TempByte) 
     end; 
     Result := Length(TempName); 
     except 
     Result := -2; 
     end; 
    end 
    else 
    begin 
     Result := -3; 
    end; 
    end 
    else 
    begin 
    Result := -1; 
    end; 
end; 

// C# Код ` // Импорт функции Указатель

[DllImport("HID_DLL.dll", CallingConvention= CallingConvention.StdCall, CharSet = CharSet.Ansi)] 
public unsafe static extern int DeviceName(IntPtr Size, [MarshalAs(UnmanagedType.LPStr)] string Msg); 



unsafe static void Main() 
{ 
byte[] buffer = new byte[32768]; 

     DeviceName(255, &**buffer); 

      Console.WriteLine("%s\n" + buffer); 
} 

`

+0

Он компилирует, то, что я получаю на линии cmd, не то, что я ожидаю. Конечным результатом будет мой код для обнаружения USB HID Device, приложенного к принтеру, его имя на экране, как описано в коде delphi. – mChad

ответ

2

Эта функция Delphi является своего рода грязный. Его задача - скопировать строку в буфер, предоставленный вызывающим. Обычно это выполняется с использованием строк с нулевым символом, но код Delphi этого не делает.

Предполагая, что код Delphi не может быть изменен, вот как назвать его с C#. Обратите внимание, что здесь вам не нужен небезопасный код, и я рекомендую вам прекратить использование небезопасного кода.

Прежде всего п/ссылаться на объявление:

[DllImport("Azoteq_HID_DLL.dll", CallingConvention= CallingConvention.StdCall] 
public static extern int DeviceName(int Size, byte[] Msg); 

Параметр Size имеет тип Integer в Delphi. Это 32-битное целое число в C#. Поэтому используйте int, как и для возвращаемого значения. Не используйте IntPtr, который является целым числом, размер которого равен значению указателя. Это неверно в 64-битном процессе. Параметр Msg должен быть выделен как массив байтов, поскольку вы не добавляете нулевой ограничитель. А это, в свою очередь, означает, что нет необходимости указывать CharSet.

Теперь вызов:

byte[] Msg = new byte[256]; 
int retval = DeviceName(Msg.Length, Msg); 
if (retval < 0) 
{ 
    // handle error 
} 
else 
{ 
    string name = Encoding.Default.GetString(Msg, 0, retval); 
} 

Ваша функция Delphi плохо разработана, хотя. Как уже упоминалось, в этом сценарии принято использовать строки с нулевым завершением. Это позволяет разрешить маршаллерам p/invoke обрабатывать код плиты котла. Ваши коды ошибок также плохи. Если пользователь передает размер, который недостаточно для хранения строки, вы должны сообщить им, сколько места требуется.

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

Последний совет. Ваша функция возвращает значения, указывающие, удалось или нет. Ваш код C# просто игнорирует эти возвращаемые значения. Как правило, если функция возвращает значение, вы должны ее прислушиваться. Особенно, когда вы выполняете interop, а возвращаемое значение указывает на успех или неудачу.