2014-11-17 8 views
1

나는 프로그래밍에서 새로운데 누군가가 델파이 DLL에서 Visual C# 함수로 포인터 함수를 호출 할 수있게 도와 줄 수 있습니까?C# Dllimport Delphi Pointer

다음은 DLL에 저장된 델파이 함수입니다. // 델파이 코드가 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 장치를 감지하여 델파이 코드가 디스크로 기록 될 때 화면에 이름이 인쇄되도록하는 것입니다. – mChad

답변

2

에 저장. 그 역할은 호출자가 제공 한 버퍼에 문자열을 복사하는 것입니다. 일반적으로 null로 끝나는 문자열을 사용하지만 Delphi 코드는 그렇게하지 않습니다.

Delphi 코드를 수정할 수 없다고 가정하면 C#에서 호출하는 방법을 설명합니다. 여기서 안전하지 않은 코드는 필요 없으며 안전하지 않은 코드 사용을 중단하는 것이 좋습니다. 모든 P의

먼저/선언 호출 :

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

Size 파라미터 델파이 Integer 입력 갖는다. 그것은 C#의 32 비트 정수입니다. 따라서 반환 값과 마찬가지로 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); 
} 

귀하의 델파이 기능이 제대로하지만 설계되었습니다. 앞서 언급했듯이이 시나리오에서는 Null로 끝나는 문자열을 사용하는 것이 일반적입니다. 그렇게하면 p/invoke marshaller가 보일러 플레이트 코드를 처리하게 할 수 있습니다. 오류 코드도 좋지 않습니다. 사용자가 문자열을 저장하기에 부족한 크기를 전달하면 필요한 공간의 양을 알려야합니다.

Delphi 함수의 구현 또한 차선입니다. 바이트 단위로 복사하는 것이 아니라 한 번에 전체 버퍼를 복사해야합니다.

마지막 조언 하나. 함수는 성공 여부를 나타내는 값을 반환합니다. C# 코드는 반환 값을 무시합니다. 일반적으로 함수가 값을 반환하면 값을주의해야합니다. 특히 interop을 수행 할 때 반환 값은 성공 또는 실패를 나타냅니다.