尝试在C#中传递大量字符时尝试读取或写入受保护的内存

我正在使用标签阅读器,我能够连接它并读取一些数据.我的问题是当我尝试读取标签id时,这是一个很大的字符序列.SDK是用C语言编写的,我正在开发一个c#应用程序.short GetIDBuffer(HANDLE hCom, unsigned char* DataFla...

我正在使用标签阅读器,我能够连接它并读取一些数据.我的问题是当我尝试读取标签id时,这是一个很大的字符序列.

SDK是用C语言编写的,我正在开发一个c#应用程序.

short GetIDBuffer(HANDLE hCom, unsigned char* DataFlag, unsigned char * Count, 
      unsigned char *value, unsigned char* StationNum)

在我的C#应用??程序中:

[DllImport("Reader2.dll",CharSet = CharSet.Ansi)]
public static extern short GetIDBuffer(IntPtr hCom, ref uint DataFlag, 
       ref uint Count, ref String value, ref uint StationNum);

数据标记,计数,站号主要是小序列,其中uint类型表现良好.但是当谈到价值时,这是一个很大的序列.我尝试了类型字符串,但它抛出了这个异常:

Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.

> [MarshalAs(UnmanagedType.LPWStr)]字符串值

没有解决问题
>计数值正确返回
>我的操作系统是64位:我使用corflags application.exe / 32bit,我能够正确加载DLL.

代码快照:

 [DllImport("Reader2.dll")] 
    public static extern byte OpenReader(ref IntPtr hCom, byte LinkType, string com_port, uint port);
    [DllImport("Reader2.dll")]
    public static extern  short GetIDBuffer(IntPtr hCom, ref byte DataFlag, ref byte Count,**(type)** value , ref byte StationNum);

    static  void Main(string[] args)
    {

        byte count = 0, station = 1, flag = 0;
        IntPtr hcom = IntPtr.Zero;        
        OpenReader(ref hcom, 2, "192.168.0.178", 4001);
        // valid handle returned from openReader 
      //
        **GetIDBuffer code**
            //

解决方法:

您不应该使用corflags application.exe / 32bit.您需要做的就是在project / properties / build中将平台目标设置为x86.

这将起作用(它使用我使用上面给出的相同签名创建的测试本机方法).
第一种方法不需要unsafe关键字,或者要求在“允许不安全代码”设置为true的情况下构建项目.

internal static class NativeMethods
{
    [DllImport("Reader2.dll")]
    public static extern short GetIDBuffer(
           IntPtr hCom, ref byte dataFlag, ref byte count, 
           byte [] value, ref byte stationNum);
}

static int TestGetIDBuffer()
{
    const int arraySize = 255;
    byte[] bytes = new byte[arraySize + 1]; 

    byte dataFlag = 0;
    byte count = arraySize;
    byte status = 0;

    int retval = NativeMethods.GetIdBuffer(IntPtr.Zero, ref dataFlag, ref count, bytes, ref status);

    Debug.WriteLine(Encoding.ASCII.GetString(bytes));
    Debug.WriteLine(dataFlag);
    Debug.WriteLine(status);
    Debug.WriteLine(count);
    Debug.WriteLine(retval);

    return retval;
}

这是使用固定字节数组的替代方法.
第二种方法需要unsafe关键字,并且项目是使用“允许不安全代码”设置为true构建的.

internal static class NativeMethods
{
    [DllImport("Reader2.dll")]
    public static extern unsafe short GetIDBuffer(
           IntPtr hCom, ref byte dataFlag, ref byte count, 
           byte* value, ref byte stationNum);
}

static unsafe int TestGetIDBuffer()
{
    const int arraySize = 255;
    byte[] bytes = new byte[arraySize + 1];

    byte dataFlag = 0;
    byte count = arraySize;
    byte status = 0;

    int retval;
    fixed (byte* buffer = bytes)
    retval = NativeMethods.GetIdBuffer(
             IntPtr.Zero, ref dataFlag, ref count, buffer, ref status);

    Debug.WriteLine(Encoding.ASCII.GetString(bytes));
    Debug.WriteLine(dataFlag);
    Debug.WriteLine(status);
    Debug.WriteLine(count);
    Debug.WriteLine(retval);

    return retval;
}

dataFlag,count和stationNum似乎都是输入/输出字节值.

填充的数据缓冲区是一个字节数组.需要修复此缓冲区,以便在调用本机方法时GC不会移动它.这在第一个示例中隐式完成,在第二个示例中显式完成.

我假设可用的缓冲区大小应该传递给count参数中的方法,并且退出时的这个值将是使用的缓冲区数量.我允许一个额外的字节,以确保如果字节数组需要转换为字符串,则存在空终止字符.

实际上有两种形式的固定语句.在这个MSDN article中提到的一个允许你创建固定大小的数组,如
    public fixed byte Bytes [ArraySize];
此MSDN article中的另一个允许您固定变量的位置以获取其地址.

这是我的C测试代码:

extern "C" __declspec(dllexport) unsigned short __stdcall GetIDBuffer( 
    HANDLE hCom, unsigned char * dataFlag, unsigned char * count, 
    unsigned char* buffer,  unsigned char * status )
{
    memset(buffer, 0x1E, *count);

    *dataFlag = 0xa1;
    *count = 0x13;
    *status = 0xfe;

    return 0x7531;
}

上面给出的C#代码与我的测试代码之间的唯一区别是,由于我使用了C编译器,因此必须以不同方式指定入口点,例如

[DllImport("PInvokeTestLib.dll", EntryPoint = "_GetIDBuffer@20")]
public static extern unsafe short GetIdBuffer(...

您可以安全地将传递给方法的参数(不包括值数组参数)指定为除byte之外的基本类型,例如int,long等.这是因为1)值在引用中传递,2)x86使用很少 – 字节序字节排序.这导致单个字节被写入传入的四字节int的最低有效字节.

建议使用匹配类型,在这种情况下为byte.

本文标题为:尝试在C#中传递大量字符时尝试读取或写入受保护的内存

基础教程推荐