2017-08-08 40 views
0

我有一個.dll沒有源代碼。 該庫是用C寫的......我只有一個.H 庫的提取物是這樣的:C#使用指針等C庫

typedef enum 
{ 
    SSHD_ERR_NONE = 0, 
    SSHD_ERR_INVALID_HANDLE, 
    SSHD_ERR_NULL_POINTER, 
}sshdErr_t; 

typedef struct 
{ 
    unsigned long Year;   // 
    unsigned long Month;  // 1...12 
    unsigned long Day;   // 1...31 

    unsigned long Hour;  // 0...23 
    unsigned long Min;   // 0...59 
    unsigned long Sec;   // 0...59 
    unsigned long MilliSec; // 0...999 
} sshdDateTime_t; 


    DllExport HANDLE sshdCreate(void); 
    DllExport sshdErr_t sshdGetDllVersion(char *dllVersion, unsigned long dllVersionMaxLen); 

    DllExport sshdErr_t sshdOpen(HANDLE rh); 

I have write this code: 



     private const String dllPath = @"D:\work\SSHD.dll"; 

    [DllImport(dllPath,EntryPoint = "sshdOpen")] 
     internal static extern eSSHD_Err Extern_sshdOpen(); 


     [DllImport(dllPath,EntryPoint = "sshdGetDllVersion")] 
     //internal static extern string sshdGetDllVersion(); 
     internal static extern eSSHD_Err Extern_sshdGetDllVersion(string dllVer , Int32 maxLen); 

     [DllImport(dllPath, EntryPoint = "sshdCreate")] 
     internal static extern IntPtr Extern_sshdCreate(); 

    public enum eSSHD_Err { 
     SSHD_ERR_NONE = 0, 
     SSHD_ERR_INVALID_HANDLE, 
     SSHD_ERR_NULL_POINTER, 
    } 

    public class SSHDDateTime { 
    public ulong Year { get; set; }  // 
    public ulong Month { get; set; } // 1...12 
    public ulong Day { get; set; }  // 1...31 
    public ulong Hour { get; set; } // 0...23 
    public ulong Min { get; set; }  // 0...59 
    public ulong Sec { get; set; } // 0...59 
    public ulong MilliSec { get; set; } // 0...999 

    public SSHDDateTime() { 
     Year = 0; 
     Month = 0; 
     Day = 0; 
     Hour = 0; 
     Min = 0; 
     Sec = 0; 
     MilliSec = 0; 
    } 
    } 

於是我就用DLL導入,轉換枚舉枚舉(C#)和結構類。 ..

當我嘗試使用我有一個錯誤...

現在使用的代碼庫:

IntPtr handle; 
    handle = Extern_sshdCreate(); 

這可能是工作......這意味着, 「處理」值的變化....但我真的不知道它是否工作!

,當我嘗試使用其它功能,以這樣的方式

int retProva = (int) (Extern_sshdOpen(handle)); 

eSSHD_Err retProva = Extern_sshdOpen(handle); 

我有堆損壞的錯誤...

使用其他功能是相同的結果:

string dllVer="xxxxxxxxxxxxxxx"; 
Int32 maxLen = 10; 
Extern_sshdGetDllVersion(dllVer,maxLen); 

我嘗試使用字符串或字符串的dllVer或使用=「」... 我嘗試存儲重新值而不是 我嘗試使用Int32,字符串,ulong maxLen 螺母都嘗試沒有結果。 ..

錯誤返回,在意大利,是這樣的:

託管調試助手 'PInvokeStackImbalance'!「尤娜chiamata 阿拉funzione的PInvoke 'TestSTSWavetronix TestSTSWavetronix.FormTestWavetronix :: Extern_sshdGetDllVersion' 醫管局sbilanciato lo堆棧。 Questo problemapuòverificarsi quando la firma PInvoke gestate non corrisponde alla firma di destinazione non gestita。驗證我們的方便,並且我們可以提供這樣的服務。

所以我問: 1.如何正確使用這個調用? 2.我在枚舉C#中枚舉枚舉C,但爲了返回值,如何適應? 3.與前面相似,如何將struct C傳遞給函數,如果在C#中我有class而不是? 4.我有一個C參數函數調用指針...如何與他管理?我想C代碼試圖修改我通過的字符串....

編輯: 其他嘗試: - 使用不安全的編譯proprierties和原型 前 - 用 「枚舉:INT」 關於枚舉

編輯2的定義: ********** ************工作液*************

public enum eSSHD_Err { 
    SSHD_ERR_NONE = 0, 
    SSHD_ERR_INVALID_HANDLE, 
    SSHD_ERR_NULL_POINTER, 
} 
    [DllImport(dllPath,EntryPoint = "sshdGetDllVersion",CallingConvention = CallingConvention.Cdecl)] 
    unsafe internal static extern eSSHD_Err Extern_sshdGetDllVersion(ref char dllVer,Int32 maxLen); 
char[] dllVer = new char[250]; 
Int32 maxLen = 250; 
retErrGetDllVer = Extern_sshdGetDllVersion(ref dllVer[0],maxLen); 

感謝所有

的Massimiliano

+0

像https://stackoverflow.com/questions/20419415/c-sharp-call-c-dll-passing -pointer-to-pointer-argument你是否嘗試過在內部靜態extern和DllImport之前放置不安全:CallingConvention = CallingConvention.Cdecl? –

+0

堆棧錯誤通常表示調用函數的返回變量大小與父返回大小不匹配。因此,在枚舉中指定大小:public enum eSSHD_Err:int //或者C++庫的大小。 – jdweng

+0

嗨,我嘗試編譯與不安全(構建選項,並在原型之前) 我嘗試在Cdec中使用CallingConvention,現在我嘗試保留在我的代碼.... @jdweng我現在試試這樣: 的typedef枚舉:整數 { \t SSHD_ERR_NONE = 0, \t SSHD_ERR_INVALID_HANDLE, \t SSHD_ERR_NULL_POINTER, } 但沒有成功... 誤差保持不變。 我嘗試調用該函數而不期待返回。 因此:eSSHD_Err retProva = Extern_sshdOpen(handle);和Extern_sshdOpen(句柄); – holyhope

回答

0

嘗試將StructLayoutAttribute添加到託管結構聲明中。如果C#編譯器認爲它是有益的,則它可以重新命令 以提高效率,所以這會阻止它。由於long通常是 C中的一個32位整數,我已將字段類型更改爲uint

[StructLayout(LayoutKind.Sequential)] 
public class SSHDDateTime { 
    public uint Year { get; set; }  // 
    public uint Month { get; set; } // 1...12 
    public uint Day { get; set; }  // 1...31 
    public uint Hour { get; set; } // 0...23 
    public uint Min { get; set; }  // 0...59 
    public uint Sec { get; set; } // 0...59 
    public uint MilliSec { get; set; } // 0...999 

    public SSHDDateTime() { 
    Year = 0; 
    Month = 0; 
    Day = 0; 
    Hour = 0; 
    Min = 0; 
    Sec = 0; 
    MilliSec = 0; 
    } 
} 

接着,傳遞一個StringBuilderExtern_sshdGetDllVersion功能。此函數需要一個字符 緩衝區,並且字符緩衝區的受管等效物是StringBuilder。 PInvoke封送拆收員詳細瞭解StringBuilder類的 知識來處理字符串的interop編組。您可以將MarshalAsAttribute作爲暗示添加到您正在處理本機庫中ANSI字符串的封送處理器中。此外,DllImportAttribute的默認調用約定是StdCall,這是可能不是你想要的。這個修訂後的簽名規定了Cdecl調用約定,這是C程序的標準約定。如果你的C庫實際上被編譯爲使用StdCall,那麼你可以拿掉那部分,但我認爲這是你的堆棧腐敗的根源。

[DllImport(dllPath, EntryPoint = "sshdGetDllVersion", CallingConvention = CallingConvention.Cdecl)] 
    internal static extern eSSHD_Err Extern_sshdGetDllVersion([MarshlAs(UnmanagedType.LPStr)]StringBuilder dllVer , Int32 maxLen); 

的PInvoke的簽名其它功能會是如下:

[DllImport(dllPath, EntryPoint = "sshdOpen", CallingConvention = CallingConvention.Cdecl))] 
internal static extern eSSHD_Err Extern_sshdOpen(); 

[DllImport(dllPath, EntryPoint = "sshdCreate", CallingConvention = CallingConvention.Cdecl))] 
internal static extern IntPtr Extern_sshdCreate(); 
+0

大家好! 現在工作!我使用調用約定和ref而不是char * ... 現在我編寫工作代碼 – holyhope