2010-04-14 38 views
10

我有一個非託管dll,裏面有一個「MyClass」類。 現在有辦法在C#代碼中創建這個類的實例嗎?調用它的構造函數?我嘗試過,但視覺工作室報告錯誤,並提示此內存區域已損壞或出現錯誤。在C#中創建非託管C++對象#

在此先感謝

+0

你能發表你試過的嗎? – SwDevMan81 2010-04-14 11:44:01

+0

和錯誤消息? – Asher 2010-04-14 11:46:01

+0

1) static void Main(string [] args) IntPtr p = new IntPtr(); Program.CreateObserv(ref p); } [的DllImport(@ 「C:\ mm_2008 \ liba.dll」, 入口點= 「?? 0CRls @ @@ FLD QAE @ @@ ABV01 Z」,SetLastError =真, CallingConvention = CallingConvention。ThisCall)] 內部靜態extern void CreateObserv(ref IntPtr p); 此代碼拋出AccessViolationException:accessviolationexception嘗試讀取或寫入受保護的內存... – Evgeny007 2010-04-14 12:00:36

回答

19

C#無法創建從本機Dll導出的類實例。你有兩種選擇:

  1. 創建C++/CLI包裝。這是.NET類庫,可以作爲參考添加到任何其他.NET項目中。在內部,C++/CLI類使用非託管類,通過標準C++規則鏈接到本地​​Dll。對於.NET客戶端,這個C++/CLI類看起來像.NET類。

  2. 爲C++類編寫C封裝,可以由.NET客戶端使用PInvoke。例如,過於簡單化的C++類:

 

    class MyClass() 
    { 
    public: 
     MyClass(int n){data=n;} 
     ~MyClass(){} 
     int GetData(){return data;} 
    private: 
     int data; 
    }; 

該類C API的包裝:

 

    void* CreateInstance() 
    { 
     MyClass* p = new MyClass(); 
     return p; 
    } 

    void ReleaseInstance(void* pInstance) 
    { 
     MyClass* p = (MyClass*)pInstance; 
     delete p; 
    } 

    int GetData(void* pInstance) 
    { 
     MyClass* p = (MyClass*)pInstance; 
     return p->GetData(); 
    } 

    // Write wrapper function for every MyClass public method. 
    // First parameter of every wrapper function should be class instance. 

的CreateInstance,ReleaseInstance和的GetData可以在C#客戶端使用的PInvoke聲明,並且直接調用。 void *參數應在PInvoke聲明中聲明爲IntPtr。

+1

您在包裝函數中錯過了一個外部「C」。 – Danvil 2010-04-16 08:09:45

+0

丹維爾 - 這是我在問題筆記中寫的。無論如何,謝謝,我現在感覺好多了。 – 2010-04-16 15:02:12

+0

@Alex如果在本機C++ dll中有一個類的層次結構...? – rsjethani 2012-05-07 19:19:38

2

您不能在C#中直接使用unmanged C++代碼。互操作性可以使用PInvoke完成。有a lot of issues related to this topic,尤其是在調用具有指針作爲參數的函數時。

的基本過程是這樣的:

C#部

namespace MyNamespace { 
    public class Test { 
    [DllImport("TheNameOfThe.dll")] 
    public static extern void CreateMyClassInstance(); 

    public void CallIt() { 
     CreateMyClassInstance(); // calls the unmanged function via PInvoke 
    } 
    } 
} 

C++部分

class MyClass { 
    public: MyClass() { /** Constructor */ } 
}; 

MyClass* staticObject; 

extern "C" void CreateMyObjectInstance() { 
    staticObject = new MyClass(); // constructor is called 
} 
+0

感謝大家,我討厭承認它,但看起來除了編寫包裝外,沒有別的辦法。 – Evgeny007 2010-04-14 12:09:06

+0

其他選項是使用compiler/crl標誌編寫託管C++。然後,您可以在同一個DLL中混合使用非託管和託管代碼,然後在您的C#代碼中使用簡單的調用託管方法。它會生成sam IL代碼,就像在代碼中包裝本機方法一樣。快速入門http://www.codeproject.com/Articles/19354/Quick-C-CLI-Learn-C-CLI-in-less-than-minutes – 2015-11-12 07:48:45

2

的解決方案是創建C++/CLI包裝等:

#include "DllExportClass.h" 

public ref class ManagedOperationHelper 
{ 
    public: 

    double Sum(double add1, double add2) 
    { 
     CDllExportClass obj; 
     double ret=obj.Sum(add1, add2); 
     return ret; 
    } 

    double Mult(double mult1, double mult2) 
    { 
     CDllExportClass obj; 
     double ret=obj.Mult(mult1, mult2); 
     return ret; 
    } 
}; 

其中CDllExportClass是從本機代碼導出的類。以上是C++/CLI的.h。注意讓lib找到這個dll。將dll和lib放在同一個目錄下,並編譯C++/CLI代碼。在託管代碼目錄中放置原生dll和C++/CLI dll。在託管項目中放置了C++/CLI項目的參考。 Instanciate在C++/CLI類的惡意代碼中是這樣的:

ManagedOperationHelper obj = new ManagedOperationHelper(); 
double ret=obj.Sum(10, 20); 

這一切。