Reputation: 197
I'm using IntPtr in C#, to get array of object from C++ project.
To do that, i allocated the memory needed with Marshal.AllocHGlobal method, and i'm copying the full array in C++ into the ptr.
The thing is I am promoting the pointer, to move to the next object in the array.
My question is: Do i have to restore the first value of the IntPtr, before using the Marshal.FreeHGlobal method?
Here is the code
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(buffer, dirEntry);
buffer += dirEntrySize;
}
Marshal.FreeHGlobal(buffer);
return dirEntries;
}
Upvotes: 1
Views: 2140
Reputation: 1918
You have to create a copy of the original pointer which can be used later use. In this case, it is called current:
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
IntPtr current = buffer;
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(current, dirEntry);
current += dirEntrySize;
}
Marshal.FreeHGlobal(buffer);
return dirEntries;
}
However, there is another possibility without using an explicit copy of your pointer by using IntPtr.Add()
:
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(IntPtr.Add(buffer, i * dirEntrySize), dirEntry);
}
Marshal.FreeHGlobal(buffer);
return dirEntries;
}
Please keep in mind, that your code contains a potential memory leek. You should wrap your code in a try/finally block. In the finally block you free the memory block again if the pointer is not zero:
public List<DirEntry> getDirEntries()
{
int dirEntrySize = Marshal.SizeOf(typeof(DirEntry));
int bufferSize = 28 * dirEntrySize;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
try
{
CppToCsharpAdapter.getDirEntries(this.myDiskPointer, buffer);
DirEntry dirEntry = new DirEntry();
List<DirEntry> dirEntries = new List<DirEntry>();
for (int i = 0; i < 28; i++)
{
Marshal.PtrToStructure(IntPtr.Add(buffer, i * dirEntrySize), dirEntry);
}
}
finally
{
if (buffer != IntPtr.Zero)
Marshal.FreeHGlobal(buffer);
}
return dirEntries;
}
Upvotes: 2