2014-10-26 32 views
1

我想將下面的C代碼轉換爲C#...但我似乎被卡住時正確地將結構轉換爲該回調。編譯良好,但在運行時堆棧結果不平衡。P /調用一個C代理結構到C#

Ç

INT32 RegisterCallback4ThirdParty(BtSdkCallbackStru* call_back); 

typedef struct _CallbackStru 
{ 
    BTUINT16 type;     /*type of callback*/ 
    void *func;      /*callback function*/ 
}CallbackStru, *PBCallbackStru; 

以下是我的轉換:

C#

[DllImport("SDK.dll")] 
[return: MarshalAs(UnmanagedType.I4)] 
public static extern Int32 RegisterCallback4ThirdParty(ref CallbackStru callback); 

public class CallbackStru 
{ 
    public ushort type; //type of callback 
    public object func; //callback function 
} 

當調用在C#程序:

CallbackStru cb = new CallbackStru(); 
AppInquiryInd appInquiryInd = AppInquiryInd; 
cb.type = 0x04; 
cb.func = appInquiryInd; 
RegisterCallback4ThirdParty(ref cb); 

在哪裏AppInquiryInd是這個代理:

public delegate void AppInquiryInd(UInt32 deviceHandle); 

它未能在RegisterCallback4ThirdParty(參照CB);

我可以簡單地忽略一些東西嗎?

乾杯。

+0

僅僅因爲你可以在C中給出一個例子並不會使這個C問題。 – Deduplicator 2014-10-26 21:48:15

+0

什麼是最好的話題發佈這下?只是C#? – bl4kh4k 2014-10-26 21:49:15

+0

你在問什麼?不是關於C,只關於C#。具體而言,您正在詢問p/invoke。 – Deduplicator 2014-10-26 21:51:33

回答

4

的委託聲明可能是不正確的,請嘗試:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    public delegate void AppInquiryInd(UInt32 deviceHandle); 

而且一定要申報結構相匹配,因此函數指針可以正確列:

[StructLayout(LayoutKind.Sequential)] 
    private struct _BtSdkCallbackStru { 
     public ushort type;  //type of callback 
     public AppInquiryInd func; //callback function 
    } 

我改變struct,現在的參考論點是正確的:

[DllImport("SDK.dll", CallingConvention = CallingConvention.Cdecl)] 
    private static extern int RegisterCallback4ThirdParty(ref CallbackStru callback); 

堆棧失衡是由於缺少CallingConvention引起的。

您還必須確保委託對象保持對垃圾收集器可見,它不能看到本機代碼使用它。這需要將其存儲在靜態字段中,或者使用GCHandle.Alloc()爲其分配額外的句柄。因此,大致爲:

CallbackStru cb = new CallbackStru(); 
    AppInquiryInd callback = new AppInquiryInd(myCallbackMethod); 
    ToCleanupLater = GCHandle.Alloc(callback); 
    cb.type = 0x04; 
    cb.func = callback; 
    RegisterCallback4ThirdParty(ref cb); 

其中「ToCleanupLater」是一個佔位符變量,所以你可以調用GCHandle.Free()時,本機代碼可以不再做回調。如果沒有阻止回調的機制,那麼不要打擾它。

+0

這有效!需要調用約定......但我必須這樣做:CallingConvention = CallingConvention.Cdecl – bl4kh4k 2014-10-26 22:03:22

+0

爲了將來的參考,我如何知道調用約定是什麼? – bl4kh4k 2014-10-26 22:04:09

+0

你從C代碼中知道它。如果你沒有明確聲明__stdcall,那麼C編譯器通常會選擇__cdecl作爲默認值。 – 2014-10-26 22:06:08