2010-03-08 38 views
7

我有一個C#.NET 2.0 CF項目,我需要在本地C++ DLL中調用一個方法。這種本地方法返回一個TableEntry類型的數組。在調用本地方法時,我不知道數組的大小。從本機dll到c#應用程序獲取一個數組結構

如何從原生DLL獲取表格到C#項目?下面是我現在有效的。

// in C# .NET 2.0 CF project 
[StructLayout(LayoutKind.Sequential)] 
public struct TableEntry 
{ 
    [MarshalAs(UnmanagedType.LPWStr)] public string description; 
    public int item; 
    public int another_item; 
    public IntPtr some_data; 
} 

[DllImport("MyDll.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)] 
public static extern bool GetTable(ref TableEntry[] table); 

SomeFunction() 
{ 
    TableEntry[] table = null; 
    bool success = GetTable(ref table); 
    // at this point, the table is empty 
} 


// In Native C++ DLL 
std::vector<TABLE_ENTRY> global_dll_table; 
extern "C" __declspec(dllexport) bool GetTable(TABLE_ENTRY* table) 
{ 
    table = &global_dll_table.front(); 
    return true; 
} 

感謝, PaulH

+1

難道不該TABLE_ENTRY **,既然你要編寫一個指針? – OregonGhost 2010-03-08 17:13:11

+0

@OregonGhost - 你是對的,應該是。 – PaulH 2010-03-08 18:35:23

回答

11

當編組未知大小的數組從原產地到管理,我覺得最好的策略是如下

  • 類型數組IntPtr在託管代碼
  • 讓本機代碼返回數組和大小參數。
  • 手動將IntPtr中的數據編組到管理端的自定義結構中。

因此,我會對您的代碼進行以下更改。

母語:

extern "C" __declspec(dllexport) bool GetTable(TABLE_ENTRY** table, __int32* pSize) 
{ 
    *table = &global_dll_table.front(); 
    *pSize = static_cast<int32>(global_dll_table.size()); 
    return true; 
} 

管理:

[DllImport("MyDll.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.I1)] 
public static extern bool GetTable(out IntPtr arrayPtr, out int size); 

public static List<TableEntry> GetTable() { 
    var arrayValue = IntPtr.Zero; 
    var size = 0; 
    var list = new List<TableEntry>(); 

    if (!GetTable(out arrayValue, out size)) { 
    return list; 
    } 

    var tableEntrySize = Marshal.SizeOf(typeof(TableEntry)); 
    for (var i = 0; i < size; i++) { 
    var cur = (TableEntry)Marshal.PtrToStructure(arrayValue, typeof(TableEntry)); 
    list.Add(cur); 
    arrayValue = new IntPtr(arrayValue.ToInt32() + tableEntrySize); 
    } 
    return list; 
} 
+0

好的解決方案,除非原生DLL的接口不能改變(不幸的是,當P /調用現有的庫時,這是一個常見的情況)。 – OregonGhost 2010-03-08 17:12:01

+0

嗨@JaredPar,我看到你仍然活躍在這裏。我有一個新問題,即我的代碼是在您的解決方案之後建模的。我希望你可以看看,如果你有時間,看看你能否指出我在正確的方向,這裏是問題http://stackoverflow.com/questions/38648173/pinvoke-marshal-an-array-of-結構從指針謝謝 – ScottN 2016-07-28 23:12:51

相關問題