2017-01-14 1 views
1

나는 delphy pascal 프로젝트에서 사용되는 C++ dll을 가지고 있으며 이것을 사용하기 위해 C# 프로젝트를 만들고 싶습니다. dll은 인터페이스 객체를 반환하고 dllImport가 인식 할 수 있도록 C# 인터페이스를 구현하는 방법에 대해 지금 당황하고 있습니다. 파스칼로 된 코드를 가지고 있습니다. 또한, 나는 DLL의 C++ 소스에 액세스 할 수 없습니다. 여기 파스칼에서 C로 코드 변환

는 delphy의 일부입니다

interface 
uses 
    IdGlobal; 
type 
// TIdBytes = array of Byte; 
    TBUF2 = array[0..1] of Byte; 
    TBUF3 = array[0..2] of Byte; 
    TBUF4 = array[0..3] of Byte; 
    PBUF4 = ^TBUF4; 
    TBUF6 = array[0..5] of Byte; 
    TBUF8 = array[0..7] of Byte; 
    TBUF16 = array[0..15] of Byte; 

    TUDPRcvRcd = record 
    Head: TBUF3; 
    DevType: Byte; 
    DevID: Byte; 
    DevIP: TBUF4; 
    DevMAC: TBUF6; 
    SoftVer: TBUF2; 
    HardVer: TBUF2; 
    DevName: TBUF16; 
    CHK: Byte; 
    end; 

    ReceiveDataEvent = procedure(aData: TIdBytes) of object; 
    ListRecive = procedure(aData: TIdBytes; aMac: PChar) of object; 

    ILhm = interface 
    function SearchDev: Integer; stdcall; 
    function SetRcvSearchResultProc(aReceiveDataEvent: ReceiveDataEvent): Boolean; stdcall; 
    function ConnectDev(aMac, aIp, aPort, aPsd: PChar): Boolean; stdcall; 
    function RemoveDev(aMac: PChar): Boolean; stdcall; 
    function SendDataByMac(aData: TIdBytes; aMac: PChar): Boolean; stdcall; 
    function SetRcvDevDataProc(aListRecive: ListRecive): Boolean; stdcall; 
    end; 


function ControllerInit: ILhm; stdcall; external 'controller.dll' name 'ControllerInit'; 

implementation 
end. 

나는 지금까지 내 C# 프로젝트에 쓴

내가 잘못 PInvoke를 정의 또는 관한 다양한 오류가 나타납니다
[DllImport("controller.dll", 
//EntryPoint = "ControllerInt", SetLastError = true, 
CallingConvention = CallingConvention.Cdecl)] 
public static extern ILhm ControllerInit(); 

public delegate object ReceiveDataEvent (byte[] aData); 
public delegate object ListRecive(byte[] aData, string aMac); 


    public interface ILhm 
    { 
     int SearchDev(); 

     bool SetRcvSearchResultProc(ReceiveDataEvent aReceiveDataEvent); 

     bool ConnectDev(string aMac, string aIp, string aPort, string aPsd); 
     bool RemoveDev(string aMac); 
     bool SendDataByMac(byte[] aData, string aMac); 
     bool SetRcvDevDataProc(ListRecive aListRecive); 
    } 

:

Additional information: The runtime has encountered a fatal error. The address of the error was at 0x7221dd74, on thread 0x305c. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack. 

감사!

+0

파스칼 코드는'Controller.Init'을'stdcall'이라고 부르지 만 C# 코드는'Cdecl'을 사용합니다. 그러나 더 많은 질문이 있습니다. C++ 라이브러리에서 "일반적인"C 함수 또는 C++ 객체를 호출하고 있습니까? C 함수가 작동해야합니다. COM 인터페이스를 내보내는 경우 C++ 객체는 .NET에서만 호출 할 수 있습니다. –

답변

0

짧은 이야기 - 귀하의 DLL은 C#과 호환되지 않습니다. 그들은 (COM에 IUnknown라고도 함) IInterface에서 파생하고 C#을 측면에 COM 상호 운용성을 사용

  • :하지 않는

    델파이 인터페이스는 C#으로 사용할 수 없습니다.

  • 인터페이스 메서드에 대한 vtable (C 스타일 함수 포인터의 배열)에 대한 포인터가 들어있는 C 스타일 구조체를 선언하여 C# 측 인터페이스를 위조합니다. 그리고 델파이 인터페이스가 예상되는 곳이면 그 외부 구조체에 대한 포인터를 사용할 수 있습니다. 또한

, 당신이 개 이벤트 유형, ReceiveDataEventListRecive은 대의원의 사용이 그들을 위해 작동하지 않도록, 모든 C 번호와 호환되지 않는 델파이 - 특정 기능 ( procedure of object)를 사용하고 있습니다. C 스타일의 함수 포인터 또는 COM 스타일의 이벤트 인터페이스를 사용하십시오.

TIdBytes과 같은 델파이 스타일의 동적 배열도 C#과 전혀 호환되지 않으며 COM에서도 호환되지 않습니다. 정적 배열, C 스타일 동적 배열 또는 COM SafeArrays를 대신 사용해야합니다.

또한 코드에서 실수는 DLL이 stdcall 호출 규칙을 사용하지만 C# 가져 오기가 cdecl을 대신 사용한다는 것입니다.

간단히 말해 C#에서 직접 사용할 수 있기 전에 DLL을 재 설계해야합니다. 그것이 옵션이 아니면 적어도 COM 래퍼를 작성한 다음 C#으로 가져 오십시오.

+0

예, DLL을 다시 작성할 수 없으므로 이제 COM 래퍼를 만드는 방법에 대해 알아 보겠습니다. 비주얼 스튜디오에서 어떻게이 작업을 수행 할 수 있는지 튜토리얼이나 문서로 안내해 주시겠습니까? – daniel

+0

@daniel 언급 한 점은 DLL이 Embarcadero 환경 외부에서 사용되는 것을 방지하므로 Delphi 또는 C++ Builder에서 래퍼를 작성해야합니다. –