簡體   English   中英

僅在運行時知道結構時將結構從c ++傳遞給c#

[英]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一起工作:生成一個接口,然后根據該接口發送信息。

我不知道這是否是您問題的直接答案,但是我通過以下方式解決了它。

  1. 您在DLL中調用GetResource並獲取一個IntPtr:

     (...) IntPtr res = Native.GetResource(); 
  2. 然后,為該IntPtr實例化通用包裝:

     ResourceWrapper rw = new ResourceWrapper(res); 
  3. 如果要訪問結構的特定字段,請在包裝器上調用適當的方法:

     int field = rw.GetField(); 
  4. 包裝器在DLL中調用一個函數:

     (...) int result = Native.GetField(res); 
  5. DLL“重新定義”調用:

     __declspec(dllexport) int __stdcall GetField(MyStructure * s) { return s->GetField(); } 
  6. 結構獲取數據(或引發異常或設置錯誤標志或返回錯誤等)

     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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM