2012-02-15 80 views
1

我是一位經驗豐富的軟件工程師,但對C#來說有點新鮮。我有一個由C++對象組成的DLL,如圖所示。我使用了這個C接口,因爲我不確定是否存在從我的C#應用​​程序訪問DLL中的C++入口點的方法。如何從DLL傳遞對象指針並傳遞給DLL?

__declspec(dllexport) void *Constructor(); 
    __declspec(dllexport) void Destructor(void *pObj); 
    __declspec(dllexport) int Method(void *pObj, char *pSrcDst, int len); 

這是上述接口的C代碼。

extern "C" void *Constructor() 
{ 
    return (void *)new Object; 
} 
extern "C" void Destructor(void *pObj) 
{ 
    delete (Object *)pObj; 
} 
extern "C" int Method(void *pObj, char *pSrcDst, int len) 
{ 
    if (!pObj) return 0; 
    return ((Object *)pObj)->Method(pSrcDst, len); 
} 

到目前爲止好。現在,我需要能夠從C#應用程序訪問此接口。從我所學到的,我已經實現了以下C#接口。

unsafe public class Wrapper 
    { 
     [SuppressUnmanagedCodeSecurityAttribute()] 
     [DllImport("MyDLL.dll")] 
     public static extern 
     IntPtr Constructor(); 
     [SuppressUnmanagedCodeSecurityAttribute()] 
     [DllImport("MyDLL.dll")] 
     public static extern 
     void Destructor(IntPtr pObj); 
     [SuppressUnmanagedCodeSecurityAttribute()] 
     [DllImport("MyDLL.dll")] 
     public static extern 
     int Method(IntPtr pObj, [In,Out] byte[] pSrcDst, int len); 

而這裏是使用上述接口的C#代碼。

private IntPtr pObject; 
    public object() 
    { 
    pObject = Wrapper.Constructor(); 
    } 
    ~object() 
    { 
    Wrapper.Destructor(pObject); 
    } 
    public override byte[] method() 
    { 
    byte[] bytes = new byte[100]; 
    int converted = Wrapper.Method(pObject, bytes, bytes.length); 
    return bytes; 
    } 

代碼在對Wrapper.Method和Wrapper.Destructor的調用中都聲明。我假設我沒有正確處理對象的指針。有什麼建議麼?

+0

你是什麼意思「代碼斷言」?你是否收到一些錯誤信息? – svick 2012-02-15 21:22:29

+0

是的,'檢測到PInvokeStackImbalance'。 – 2012-02-15 21:28:59

+0

請記住,大多數編譯器假定'extern「C」'函數不會拋出異常(尤其是如果C代碼正在調用它們),所以您需要確保將'new Object()'位一個用於防止任何異常(特別是'std :: bad_alloc')轉義的異常塊。 – 2012-02-15 21:31:57

回答

3

最可能的問題是您的代碼不使用正確的calling convention。在C++中,缺省值爲__cdecl,但對於DllImport,缺省值爲__stdcall

爲了解決這個問題,specify the calling convention explicitly

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
+0

如果OP不知道,Visual Studio默認的調用約定是[編譯器設置](http:// msdn.microsoft.com/en-us/library/46t77ak2.aspx)。它可以改爲'__stdcall'以匹配默認的'[DllImport()]'約定。 – 2012-02-15 21:33:51

+0

看起來像這是問題,謝謝! – 2012-02-15 21:43:50

+1

@RobertKirnum,如果這個答案解決了你的問題,你應該[接受它](http://meta.stackexchange.com/a/5235/130186)。 – svick 2012-02-15 21:50:38

1

我的印象是,做這樣的事情的最好方法是使用託管C++/CLI包裝。

Creating simple c++.net wrapper. Step-by-step

http://devmaster.net/forums/topic/7357-how-to-build-a-net-wrapper-for-a-c-library/

看起來像希望的線索。

+1

如果你只需要調用一些非託管函數,PInvoke可能更容易。但是,C++/CLI肯定是一種選擇。 – svick 2012-02-15 21:31:48

+0

的確如此,但這些非託管功能甚至存在的唯一原因是缺乏對C++/CLI的瞭解。如果有辦法「做得對」,爲什麼不使用它。你真的會用一個叫做「void * Constructor」的函數嗎? – Andrei 2012-02-15 21:50:40

+0

只要它沒有公開地暴露給其餘的C#代碼,我就沒有問題了。如果您瞭解C#,學習使用PInvoke比學習使用C++/CLI更容易。 – svick 2012-02-15 21:53:19