System.AccessViolationException:C#.NET和C ++应用程序之间的shared_ptr

时间:2018-10-01 10:58:11

标签: c# c++ shared-ptr

在我们的项目中,我们通过命名管道通信两个应用程序,一个使用C#,另一个使用C ++。我们的目的是在它们之间传递内存指针,并能够在两个应用程序中访问它们所指向的对象。我们当前的代码引发System.AccessViolationException:

  

System.AccessViolationException:   尝试读取或写入受保护的内存。这通常是   表示其他内存已损坏。

到目前为止,我们使用的是指向自定义结构的shared_ptr,并使用C ++编写指向缓冲区的指针,如下所示:

typedef struct {
    int one;
    int a;
    int two;
    int b;
} DATA_STRUCT; // C++ struct

    DATA_STRUCT ds;
    ds.one = 10;
    ds.a = 5;
    ds.two = 99;
    ds.b = 0;

    shared_ptr<DATA_STRUCT> ptr_ds(new DATA_STRUCT);
    shared_ptr<DATA_STRUCT> p(ptr_ds);
    *ptr_ds = ds;

    const int size = BUFFER_SIZE;
    char buf[size];
    memset(buf, 0xCC, 100);

    while (keepReading)
    {
        printf("Write message:");
        scanf("%s", buf);
        memcpy(buf, &p, sizeof(shared_ptr<DATA_STRUCT>));
        if (strcmp(buf, "quit") == 0)
            keepReading = false;
        else
        {
            WriteFile(hPipe1, buf, dwBytesToWrite, &cbWritten, NULL);
            memset(buf, 0xCC, 100);
        }
    }

然后,在C#中,我们读取整个缓冲区,将具有相关信息的字节保存在另一个缓冲区(Rc)中,并使用不安全的IntPtr将字节数组转换为我们的自定义数据结构,如下所示:

    buffer = new byte[BUFFER_SIZE];
    bytesRead = clientCSharp.stream.Read(buffer, 0, BUFFER_SIZE);

public struct DATA_STRUCT
    {
        public int one;
        public int a;
        public int two;
        public int b;
    }; // C# struct

unsafe
{
        Buffer.BlockCopy(buffer, 0, Rc, 0, ReadLength);    
        DATA_STRUCT ds = new DATA_STRUCT();

        IntPtr aux_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));    
        IntPtr final_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));

        Marshal.Copy(Rc, 0, aux_ptr, 4);

        final_ptr = (IntPtr)Marshal.PtrToStructure(aux_ptr, typeof(IntPtr));
        ds = (DATA_STRUCT)Marshal.PtrToStructure(final_ptr, typeof(IntPtr));
}

当我们尝试访问final_ptr以便加载DATA_STRUCT(上面显示的最后一个代码行)时,出现异常。这里我给出一些调试图像:

使用Pointer value written to the named pipe buffer

的C ++调试映像

使用Pointer value read from the named pipe reduced buffer (Rc)

的C#调试映像

这与指针长度有关吗?在我看来,在C ++应用程序中它有8个字节,在C#应用程序中它有16个字节?我们应该为C#和C ++声明一个安全的内存位置吗?如果是,那怎么办?

注意::我们的目标是在C#应用程序中使用不安全的IntPtr。在此示例中,我们正在加载DATA_STRUCT对象,因为我们希望确保在C#应用程序中,我们正在检索在C ++应用程序中传递的同一对象。最终的应用程序应在Windows中使用。

1 个答案:

答案 0 :(得分:0)

应用程序数据空间是完全不同的,并且已经存在很多年了。您不能简单地在应用程序之间传递原始指针并期望访问相同的内存。

通常的方法是序列化对象的内容,通过管道将其喷出,然后在接收方重建对象。

您可以设置命名的共享内存区域,它们可以更快地共享大型对象(在unix中,我假设在Windows中),但是这些共享区域可能不会位于相同的地址,因此仍然仅对原始数据。