簡體   English   中英

如何編組c#中的集合以傳遞給本機(C ++)代碼

[英]How to marshal collection in c# to pass to native (C++) code

我正在進行企業應用程序開發。 整個應用程序是用c ++開發的,除了用c#開發的用戶界面,現在是時候用c ++代碼連接用戶界面了。 經過詳細研究,我選擇PInvoke才能這樣做。 一切都是成功的,我遇到的唯一情況是如何將集合傳遞給C ++代碼。 例如:

C#側碼

List<string> lst = new List<string>();
lst.Add("1");
lst.Add("2");
lst.Add("3");
lst.Add("4");

C ++邊碼

std::vector<std::string> vStr;

現在我如何將lst傳遞給本機C ++代碼

正如mzabsky所說,你不能編組這些類型。 但是,您可以編組一個數組:

理論上的C ++導出:

extern "C" __declspec(dllexport) void __stdcall Foo(wchar_t const* const* values, int length)
{
    // Check argument validity...

    // If you really need a vector
    std::vector<std::wstring> vStr(values, values + length);

    //...
}

P / Invoke簽名:

[DllImport("foo.dll")]
static extern void Foo([MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)] string[] values, int length);

來自C#的電話:

Foo(lst.ToArray(), lst.Count);

請注意,我在這里使用std :: wstring; 你可以使用char而不是wchar_t,LPStr而不是LPWStr,而std :: string而不是std :: wstring。

請注意,這將從列表中分配一個數組,然后向量將復制數組的內容。 如果原始列表的大小很小,那么這應該是微不足道的。

編輯:修復標記(&lt;和&gt;)。

你不能這樣做,只能編組C類型。 您將不得不編寫C ++ / CLI包裝器(或C ++向量的C包裝器)。

看到這個答案。

是。 您可以。 實際上,不僅僅是std::stringstd::wstring ,任何標准C ++類或您自己的類都可以被編組或實例化並從C#/ .NET調用。

在C#中包裝std::vector<any_type>確實可以使用常規的P / Invoke Interop,但它很復雜。 甚至任何類型的std::map都可以在C#/ .NET中完成。

從.NET世界實例化C ++對象的基本思想是從.NET分配C ++對象的確切大小,然后調用從C ++ DLL導出的構造函數來初始化對象,然后你就可以調用任何一個訪問該C ++對象的函數,如果任何方法涉及其他C ++類,您還需要將它們包裝在C#類中,對於具有基本類型的方法,您可以簡單地P / Invoke它們。 如果你只有幾種方法可以調用,那很簡單,手動編碼不會花費很長時間。 完成C ++對象后,可以調用C ++對象的析構函數方法,該方法也是導出函數。 如果它沒有,那么你只需要從.NET中釋放你的記憶。

這是一個例子。

public class SampleClass : IDisposable
{    
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,          CallingConvention=CallingConvention.ThisCall)]
    public extern static void SampleClassConstructor(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject, int x);

    IntPtr ptr;

    public SampleClass(int sizeOfYourCppClass)
    {
        this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
        SampleClassConstructor(this.ptr);  
    }

    public void DoSomething()
    {
        DoSomething(this.ptr);
    }

    public void DoSomethingElse(int x)
    {
        DoSomethingElse(this.ptr, x);
    }

    public void Dispose()
    {
        Marshal.FreeHGlobal(this.ptr);
    }
}

有關詳細信息,請參閱以下鏈接,

C#/。NET PInvoke Interop SDK

(我是SDK工具的作者)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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