[英]Passing a struct from c++ to c# when the structure is only known during runtime
我有以下問題:
我有一個C#應用程序,它從非托管C ++ dll調用函數。 dll中有一個初始化函數,該函數在C#和C ++之間創建一個接口(基本上是值及其類型的列表),該接口將存儲在結構中。
之后,有一個回調函數,C#應用程序將其發送到dll,該dll會不時地調用一次,並且它會返回接口中定義的struct變量(或字節數組)。
我的問題:您如何通過並封送此結構? 是否可以通過結構本身,還是應該通過字節數組?
如果傳遞字節數組,返回C#應用程序后如何封送它?
我現在所擁有的:
在C#應用中:
封送回調函數:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ProcessOutputDelegate(???); // not sure what should be here.
導入dll函數:
[DllImport("MyDLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void Test(ProcessOutputDelegate ProcessOutput);
調用dll函數:
ProcessOutputDelegate process = new ProcessOutputDelegate(ProcessOutput);
new thread(delegate() { Test(process); } ).Start();
處理輸出:
public void ProcessOutput(???)
{
// Assume we have a list of values that describes the struct/bytes array.
}
在C ++ dll中,我具有以下結構(這是一個示例,因為在不同的運行時中可能會調用不同的dll):
struct
{
int x;
double y;
double z;
} typedef Interface;
以及C#應用調用的函數:
__declspec(dllexport) void Test(void (*ProcessOutput)(Interface* output))
{
int i;
Interface* output = (Interface*)malloc(sizeof(Interface));
for (i = 0; i < 100; i++)
{
sleep(100);
output->x = i;
output->y = i / 2;
output->z = i / 3;
ProcessOutput(output); // or generate a bytes array out of the struct
}
}
編輯:
C#應用程序是一個通用的GUI,它假定顯示了某些c ++ dll執行的大量計算。 在初始化過程中,dll會告知GUI應顯示的變量(及其類型),並且GUI將根據這些指示進行構造(同樣,計算和變量可能會更改,並且值可能是整數,浮點數,字符...)。 之后,該dll運行,並在每個時間步長中,它調用回調函數來更新GUI。 這應該與實現該想法的任何dll一起工作:生成一個接口,然后根據該接口發送信息。
我不知道這是否是您問題的直接答案,但是我通過以下方式解決了它。
您在DLL中調用GetResource並獲取一個IntPtr:
(...) IntPtr res = Native.GetResource();
然后,為該IntPtr實例化通用包裝:
ResourceWrapper rw = new ResourceWrapper(res);
如果要訪問結構的特定字段,請在包裝器上調用適當的方法:
int field = rw.GetField();
包裝器在DLL中調用一個函數:
(...) int result = Native.GetField(res);
DLL“重新定義”調用:
__declspec(dllexport) int __stdcall GetField(MyStructure * s) { return s->GetField(); }
結構獲取數據(或引發異常或設置錯誤標志或返回錯誤等)
int MyStructure::GetField() { return this->field; }
此解決方案需要進行以下更改:
您必須實現某種安全機制,該機制檢查是否可以訪問特定字段。 最簡單的方法如下:
__declspec(dllexport) BOOL __stdcall GetField(MyStruct * s, int & result) { result = 0; try { result = s->GetField(); } catch(...) { return FALSE; } return TRUE; }
和:
protected class Native { [DllImport("MyDll.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetField(IntPtr res, out int result); }
和:
// Wrapper int GetField() { int result; if !(Native.GetField(res, out result)) throw new InvalidOperationException("Resource does not support field!"); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.