C# “C”;堆已损坏";使用sam-ba.dll

C# “C”;堆已损坏";使用sam-ba.dll,c#,pointers,atmel,heap-corruption,C#,Pointers,Atmel,Heap Corruption,我正在编写一个C程序,调用samba.dll中的AT91Boot\u Scan函数。在此DLL的中,此函数的签名是void AT91Boot\u Scan(char*pDevList)。此功能的目的是扫描并返回已连接设备的列表 问题:我当前的问题是每次从C#调用此函数时,DLL中的代码都会抛出一个堆已损坏异常 旁白:从阅读中我了解到,char*pDevList参数是指向函数可用于存储设备名称的缓冲区数组的指针。但是,当从C#调用该方法时,IntelliSense报告此函数的签名实际上是void

我正在编写一个C程序,调用
samba.dll
中的
AT91Boot\u Scan
函数。在此DLL的中,此函数的签名是
void AT91Boot\u Scan(char*pDevList)
。此功能的目的是扫描并返回已连接设备的列表

问题:我当前的问题是每次从C#调用此函数时,DLL中的代码都会抛出一个
堆已损坏
异常


旁白:从阅读中我了解到,
char*pDevList
参数是指向函数可用于存储设备名称的缓冲区数组的指针。但是,当从C#调用该方法时,IntelliSense报告此函数的签名实际上是
void AT91Boot_Scan(ref byte pDevList)

我有点搞不懂为什么会这样。单个字节的长度不足以作为指针。32位需要4字节,64位需要8字节。。。如果是
ref
关键字使此参数成为指针,那么我应该传入哪个字节?我的缓冲区数组中的第一个字节还是第一个缓冲区的第一个字节


代码:我编写的调用此函数的C#方法如下所示

/// <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;
    }
//
///返回包含连接设备名称的字符串数组
/// 
/// 
私有字符串[]LoadDeviceList()
{
const int MAX_NUM_DEVICES=10;
const int BYTES_PER_DEVICE_NAME=100;
sambadl samba=新的sambadl();
string[]deviceNames=新字符串[MAX_NUM_DEVICES];
尝试
{
不安全的
{
//分配指针数组(最大设备数)
字节**deviceList=stackalloc字节*[MAX_NUM_DEVICES];
对于(int n=0;n

我试图找到一个解决方案:我注意到行
byte*pointer statortoflist=*deviceList未将
deviceList
的指针正确分配给
PointerStatorToFlist
。地址始终被0x64关闭

我想如果我硬编码一个0x64偏移量,那么两个地址就会匹配,一切都会好起来<代码>指针StatorToFlist+=0x64

然而,尽管强制地址匹配,我仍然得到一个
堆已损坏
错误


我的想法:我认为在我的代码中,我要么没有正确创建缓冲区数组,要么没有正确传递所述数组的指针

最后我无法让
samba.dll
工作。我曾尝试在DLL周围写一个C++包装,但即使如此,它仍然抛出<代码>堆已经损坏< /代码>错误。我的最终解决方案是将SAM-BA可执行文件
SAM BA.exe
,以及它的所有依赖项嵌入到我的C#程序中

然后,每当我需要使用它时,我都会在命令行模式下运行
sam ba.exe
,并将相关参数传递给它。中的第5.1节介绍了如何在命令行模式下运行
sam ba.exe

i、 e


最后,我无法让
samba.dll
工作。我曾尝试在DLL周围写一个C++包装,但即使如此,它仍然抛出<代码>堆已经损坏< /代码>错误。我的最终解决方案是将SAM-BA可执行文件
SAM BA.exe
,以及它的所有依赖项嵌入到我的C#程序中

然后,每当我需要使用它时,我都会在命令行模式下运行
sam ba.exe
,并将相关参数传递给它。中的第5.1节介绍了如何在命令行模式下运行
sam ba.exe

i、 e


MAX_NUM_设备绝对足够大吗?从文档中我可以看出,到目前为止您所做的一切看起来还不错。。。唯一的一件事,也许它不应该是
ref*
,你应该只传递指针。是的,当然。sam-ba.dll的文档没有明确说明,但他们提供了一个代码示例,其中设备数为5(搜索
CHAR*strConnectedDevices[5];
)我试图复制他们的代码示例,但是它似乎是写在 C++< /C>中,而不是 C++ > 这个库设计得不好,只适合从C++程序调用。实际参数类型是
string
,而不是
ref byte
。从技术上讲,您可以通过使用ildasm.exe反编译interop库,修改.il文件以修复参数类型,并将其与ilasm.exe@Matthew Watson:Yeah。。。我不能
SAM-BA.exe \usb\ARM0 AT91SAM9G25-EK myCommand.tcl