[英]Passing a C# class object in and out of a C++ DLL class
我一直在研究在C#中運行的原型代碼應用程序,並使用舊C ++代碼中的類和函數(以導入的DLL的形式)。 代碼要求是將類對象傳遞給非托管C ++ DLL(來自C#),並將其存儲/修改以便以后由C#應用程序進行檢索。 這是我到目前為止的代碼......
簡單的C ++ DLL類:
class CClass : public CObject
{
public:
int intTest1
};
C ++ DLL函數:
CClass *Holder = new CClass;
extern "C"
{
// obj always comes in with a 0 value.
__declspec(dllexport) void SetDLLObj(CClass* obj)
{
Holder = obj;
}
// obj should leave with value of Holder (from SetDLLObj).
__declspec(dllexport) void GetDLLObj(__out CClass* &obj)
{
obj = Holder;
}
}
C#類和包裝器:
[StructureLayout(LayoutKind.Sequential)]
public class CSObject
{
public int intTest2;
}
class LibWrapper
{
[DLLImport("CPPDLL.dll")]
public static extern void SetDLLObj([MarshalAs(UnmanagedType.LPStruct)]
CSObject csObj);
public static extern void GetDLLObj([MarshalAs(UnmanagedType.LPStruct)]
ref CSObject csObj);
}
C#函數調用DLL:
class TestCall
{
public static void CallDLL()
{
...
CSObject objIn = new CSObject();
objIn.intTest2 = 1234; // Just so it contains something.
LibWrapper.SetDLLObj(objIn);
CSObject objOut = new CSObject();
LibWrapper.GetDLLObj(ref objOut);
MessageBox.Show(objOut.intTest2.ToString()); // This only outputs "0".
...
}
}
只有垃圾值似乎在DLL中可用(來自傳入的C#對象)。 我相信我錯過了類編組或內存/指針問題。 我錯過了什么?
編輯:我改變了上面的代碼,以反映邦德建議的C#/ C ++中方法/函數定義的變化。 傳入的值(1234)現在由C#代碼正確檢索。 這暴露了C ++ DLL中的另一個問題。 1234值不可用於C ++代碼。 相反,該對象在DLL內部的值為0。 我想使用預定義的C ++函數來編輯DLL中的對象。 非常感謝任何更多的幫助。 謝謝!
Bond是正確的,我無法在托管代碼和非托管代碼之間傳遞對象,但仍保留其存儲的信息。
我最后只是調用C ++函數來創建一個對象並將指針傳遞回C#的IntPtr類型。 然后我可以將指針傳遞給我需要的任何C ++函數(假設它是extern)來自C#。 這並不是我們想做的事情,但它會在我們需要的范圍內達到目的。
這是C#我正在使用的包裝器/示例/參考。 (注意:我正在使用StringBuilder而不是上面示例中的'int intTest'。這就是我們原型所需的。為了簡單起見,我只是在類對象中使用了一個整數。):
class LibWrapper
{
[DllImport("CPPDLL.dll")]
public static extern IntPtr CreateObject();
[DllImport("CPPDLL.dll")]
public static extern void SetObjectData(IntPtr ptrObj, StringBuilder strInput);
[DllImport("CPPDLL.dll")]
public static extern StringBuilder GetObjectData(IntPtr ptrObj);
[DllImport("CPPDLL.dll")]
public static extern void DisposeObject(IntPtr ptrObj);
}
public static void CallDLL()
{
try
{
IntPtr ptrObj = Marshal.AllocHGlobal(4);
ptrObj = LibWrapper.CreateObject();
StringBuilder strInput = new StringBuilder();
strInput.Append("DLL Test");
MessageBox.Show("Before DLL Call: " + strInput.ToString());
LibWrapper.SetObjectData(ptrObj, strInput);
StringBuilder strOutput = new StringBuilder();
strOutput = LibWrapper.GetObjectData(ptrObj);
MessageBox.Show("After DLL Call: " + strOutput.ToString());
LibWrapper.DisposeObject(ptrObj);
}
...
}
當然,C ++執行所有必需的修改,C#訪問內容的唯一方法是或多或少地通過C ++請求所需的內容。 C#代碼無法以這種方式訪問未管理的類內容,使得兩端的代碼變得更長。 但是,它對我有用。
這是我用來提出解決方案基礎的參考資料: http : //www.codeproject.com/Articles/18032/How-to-Marshal-aC-Class
希望這可以幫助其他人節省比我試圖解決的更多時間!
我相信你應該像這樣聲明你的返回方法
__declspec(dllexport) void getDLLObj(__out CClass* &obj)
分別是C#原型
public static extern void GetDLLObj([MarshalAs(UnmanagedType.LPStruct)]
ref CSObject csObj);
入站方法也應該使用指向CClass的指針,C#原型是可以的。
如果你只使用C#中的類,那么你應該使用GCHandle來實現這個目的http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle%28v=vs.110%29.aspx
編輯:
CClass *Holder;
extern "C"
{
// obj always comes in with a 0 value.
__declspec(dllexport) void SetDLLObj(CClass* obj)
{
(*Holder) = (*obj);
}
// obj should leave with value of Holder (from SetDLLObj).
__declspec(dllexport) void GetDLLObj(__out CClass** &obj)
{
(**obj) = (*Holder);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.