I'm writing a C# program that makes a call to the AT91Boot_Scan
function in sam-ba.dll
. In the documentation for this DLL, the signature for this function is void AT91Boot_Scan(char *pDevList)
. The purpose of this function is to scan and return a list of connected devices.
Problem: My current problem is that every time I call this function from C#, the code in the DLL throws an a heap has been corrupted
exception.
Aside: From what I understand from reading the documentation, the char *pDevList
parameter is a pointer to an array of buffers that the function can use to store the device names. However, when calling the method from C#, IntelliSense reports that the signature for this function is actually void AT91Boot_Scan(ref byte pDevList)
I was sort of confused by why this is. A single byte isn't long enough to be a pointer. We would need 4 bytes for 32-bit and 8 bytes for 64-bit... If it's the ref
keyword that is making this parameter a pointer, then what byte should I be passing in? The first byte in my array of buffers or the first byte of the first buffer?
Code: The C# method I've written that calls this function is as follows.
/// <summary>
/// Returns a string array containing the names of connected devices
/// </summary>
/// <returns></returns>
private string[] LoadDeviceList()
{
const int MAX_NUM_DEVICES = 10;
const int BYTES_PER_DEVICE_NAME = 100;
SAMBADLL samba = new SAMBADLL();
string[] deviceNames = new string[MAX_NUM_DEVICES];
try
{
unsafe
{
// Allocate an array (of size MAX_NUM_DEVICES) of pointers
byte** deviceList = stackalloc byte*[MAX_NUM_DEVICES];
for (int n = 0; n < MAX_NUM_DEVICES; n++)
{
// Allocate a buffer of size 100 for the device name
byte* deviceNameBuffer = stackalloc byte[BYTES_PER_DEVICE_NAME];
// Assign the buffer to a pointer in the deviceList
deviceList[n] = deviceNameBuffer;
}
// Create a pointer to the deviceList
byte* pointerToStartOfList = *deviceList;
// Call the function. A heap has been corrupted error is thrown here.
samba.AT91Boot_Scan(ref* pointerToStartOfList);
// Read back out the names by converting the bytes to strings
for (int n = 0; n < MAX_NUM_DEVICES; n++)
{
byte[] nameAsBytes = new byte[BYTES_PER_DEVICE_NAME];
Marshal.Copy((IntPtr)deviceList[n], nameAsBytes, 0, BYTES_PER_DEVICE_NAME);
string nameAsString = System.Text.Encoding.UTF8.GetString(nameAsBytes);
deviceNames[n] = nameAsString;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return deviceNames;
}
My attempt at a solution: I noticed that the line byte* pointerToStartOfList = *deviceList;
wasn't correctly assigning the pointer for deviceList
to pointerToStartOfList
. The address was always off by 0x64.
I thought if I hard-coded in a 0x64 offset then the two addresses would match and all would be fine. pointerToStartOfList += 0x64;
However despite forcing the addresses to match I was still getting a a heap has been corrupted
error.
My thoughts: I think in my code I'm either not creating the array of buffers correctly, or I'm not passing the pointer for said array correctly .