2010-03-08 16 views
7

से संरचनाओं की एक सरणी प्राप्त करें मेरे पास एक सी # .NET 2.0 सीएफ प्रोजेक्ट है जहां मुझे देशी सी ++ डीएलएल में एक विधि का आह्वान करने की आवश्यकता है। यह मूल विधि TableEntry प्रकार की एक सरणी देता है। उस समय मूल विधि को बुलाया जाता है, मुझे नहीं पता कि सरणी कितनी बड़ी होगी।देशी डीएल से सी # अनुप्रयोग

मैं देशी डीएलएल से सी # परियोजना में तालिका कैसे प्राप्त कर सकता हूं? नीचे प्रभावी रूप से मेरे पास क्या है।

// 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

+0

@OregonGost - आप सही हैं, यह होना चाहिए। – PaulH

उत्तर

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

अच्छा समाधान, जब तक कि मूल डीएलएल का इंटरफ़ेस बदला नहीं जा सकता (दुर्भाग्यवश, एक आम मामला जब पी/मौजूदा पुस्तकालयों को आमंत्रित करना)। – OregonGhost

+0

हाय @ जेरेडपायर, मुझे लगता है कि आप अभी भी सक्रिय हैं। मेरे पास एक नया सवाल है कि मेरे समाधान के बाद मेरे कोड का मॉडल किया गया है। मैं उम्मीद कर रहा था कि यदि आपके पास समय है और देखें कि क्या आप मुझे सही दिशा में इंगित कर सकते हैं, तो यहां सवाल है http://stackoverflow.com/questions/38648173/pinvoke-marshal-an-array-of- structs-from-सूचक धन्यवाद – ScottN

संबंधित मुद्दे