I am trying to marshal a vector of the following C++ class to C# that is used in a tree:
class CFileNode
{
private:
std::string m_name;
std::vector<CFileNode*> m_children;
bool m_isDirectory;
CFileNode* m_parent;
};
And:
extern DATAACCESSLAYERDLL_API size_t __stdcall Get_FileSystemNodeCount()
{
// GetFileNodeList() returns a std::vector<CFileNode*>&
return CFileSystem::GetFileNodeList().size();
}
extern DATAACCESSLAYERDLL_API void __stdcall Get_FileSystemNodes(size_t count, CFileNode** nodes)
{
nodes = CFileSystem::GetFileNodeList().data();
}
And in C#:
[SuppressUnmanagedCodeSecurity]
[DllImport("MyDll.dll")]
static private extern int Get_FileSystemNodeCount();
[SuppressUnmanagedCodeSecurity]
[DllImport("MyDll.dll")]
static private extern void Get_FileSystemNodes(int count, [In,Out] IntPtr[] outNodes);
And my struct:
[StructLayout(LayoutKind.Sequential, Pack = 1), Serializable]
public struct CFileNode
{
[MarshalAs(UnmanagedType.LPStr)]
string m_name;
[MarshalAs(UnmanagedType.SafeArray)]
IntPtr[] m_children;
[MarshalAs(UnmanagedType.Bool)]
bool m_isDirectory;
[MarshalAs(UnmanagedType.LPStruct)]
IntPtr m_parent;
}
And where I use it:
int count = Get_FileSystemNodeCount();
IntPtr[] results = new IntPtr[count];
Get_FileSystemNodes(count, results);
foreach (IntPtr ptr in results)
{
m_fileSystemNodes.Add(Marshal.PtrToStructure<CFileNode>(ptr));
}
In its current state, the IntPtr[] results is just a big array of zeroes.
If I modify C++ GetFileSystemNodes() to go through the vector and add everything to the array nodes, results will have a load of numbers that look like memory addresses (although I have no idea if they are garbage or not), but then the Marshal.PtrToStructure<CFileNode>(ptr) fails with an AccessViolationException.
I would like to transfer this whole tree structure from C++ to C# in as few PInvoke calls as possible, for speed. This is why, before any of this code is executed, my entire tree is flattened out into a list. Each node still has a pointer to its parent and children, so it's easy to reconstruct it. If it makes it easier, I could also just pass the root node.
Here are my questions:
1) Is marshalling vectors of objects that contain other vectors even possible? Should I make my C++ classes simpler, using arrays or something instead?
2) Is there a way to pass the vector of nodes through GetFileSystemNodes without moving everything in the vector to the array argument?
3) What is the correct way to write my C# struct so it matches my C++ one?