C++ DLL 返回巢狀結構體:
struct group { char* groupName; int userCount; char** userNames; };
struct groupList { int count; group* groups; };
extern "C" DLLEXP groupList* getGroupList();
groups 數量不定,.NET 自動封送無法處理指向變長陣列的指標。標準 MarshalAs 僅適用定長結構。
IntPtr(相當於 void*)GroupparseGroupList 逐層解析記憶體
[DllImport("mydll.dll")]
public static extern IntPtr getGroupList();
class Group {
public string Name;
public List UserList = new List();
}
static List parseGroupList(IntPtr groupListPtr) {
var ret = new List();
int groupCount = Marshal.ReadInt32(groupListPtr); // count
for (int i = 0; i < groupCount; i++) {
var group = new Group();
// group* groups 陣列起始位址 (offset 4)
IntPtr groupPtr = Marshal.ReadIntPtr(groupListPtr, 4);
// group 結構體:groupName (offset 0), userCount (offset 4), userNames (offset 8)
group.Name = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(groupPtr, 0));
int userCount = Marshal.ReadInt32(groupPtr, 4);
IntPtr usernameListPtr = Marshal.ReadIntPtr(groupPtr, 8);
for (int j = 0; j < userCount; j++) {
IntPtr usernamePtr = Marshal.ReadIntPtr(usernameListPtr, j * IntPtr.Size);
group.UserList.Add(Marshal.PtrToStringAnsi(usernamePtr));
}
ret.Add(group);
}
return ret;
}
IntPtr.Size 自動適配 32/64 位元指標大小Marshal.ReadInt32/ReadIntPtr 指定偏移量讀取PtrToStringAnsi 處理 C 風格字串切勿直接返回結構體指標! 應設計
GroupListAlloc/GroupListFree/GetGroupList(GroupList*)三件套:
- 呼叫端負責分配/釋放緩衝區
- DLL 僅填充資料
- 避免跨模組堆損壞、記憶體洩漏
字串陣列封送經典文章:Marshaling Array of Strings