来自 C++ CLI 项目的非托管数据的 C# 指针

C# pointer on unmanaged data from C++ CLI project

我有一个用 C++ 编写的用于管理设备的 SDK。我控制设备的程序是用 C# 编写的,因此 CLI 包装器 class 自然会在两种语言之间进行翻译。我的 C# 项目包括作为 DLL 的包装器。

我的问题是 C++ SDK 使用指针指向数据数组。这些指针在包装器中也可用。

包装器 .cpp 代码:

Wrapper::Wrapper()
{
    myData = new DataAquis(); //initiate C++ class's instance
}

int Wrapper::Start()
{
    //(..)
    int num = myData->Start();
    ptr = (myData->img);
    return num;
}

此代码初始化设备并创建指向数据结构(unsigned char 数组)的指针。

Wrapper SDK .cpp 代码:

int DataAquis::Start()
{
    // (...)
    // Pointer from SDK
    img = pBuffer;
    // (...)
    return FAILED(nError) ? -1 : 0;
}

包装.h代码:

public ref class Wrapper
{
    public:
        Wrapper();

        // (...)
        unsigned char *ptr;

    private:
        // (...)
};

C# 代码:

public static Wrapper myDataAqui;

// (...)

private static void DataAquisition()
{
    // call the start function in wrapper
    myDataAqui.Start();

    // Unsafe code for pointer use
    unsafe
    {
        // point to aquired data
        byte* imgptr1 = myDataAqui.ptr; 

        // AccesViolationException in above line. 

        // Data processing
        for (y = 0; y < 256; y++)
        {
            for (x = 0; x < 320; x++)
            {
                int temp = x * 256 + 255 - y;
                Spectrum1.X_Data_brut[bufferIndex][temp] = (UInt16)(*imgptr1++ + *imgptr1++ * 256);
                aquirData[temp] = Spectrum1.X_Data_brut[bufferIndex][temp];
            }
        }
        // (...)
    }
}

如图所示,在我将 Wrapper 指针转换为本地字节指针的那一行触发了 AccessViolationException。

如果我在该行放置一个断点,我可以看到 Wrapper 指针正确指向内存地址,但表示它无法读取内存,所以指向的数据永远不会在 C# 中收集。

我读到在 C# 中相当于 C++ 中的 unsigned char 是一个字节,所以通常我应该读取相同数量的数据并且永远不会超出我的数据结构的边界。

可能有用的其他信息:

您知道如何解决这个问题吗?

我不确定您为什么会收到异常,但我会在 C++/CLI 端将其编组到 CLR 数组中,因此在 C# 端不需要不安全的代码。

C++/CLI:

#include <vcclr.h>
#include <algorithm>

#pragma unmanaged

const int data_size = 100;

unsigned char * foo()
{
    auto p = new unsigned char[data_size];
    for (int i = 0; i < data_size; ++i)
        p[i] = (unsigned char)i;
    return p;
}

#pragma managed

public ref class Wrapper
{
public:
    array<unsigned char>^ data;

    void Start()
    {
        auto p = foo();
        data = gcnew array<unsigned char>(data_size);
        pin_ptr<unsigned char> data_pin = &data[0];
        std::copy(p, p+data_size, (unsigned char *)data_pin);
    }
};

C#:

class Program
{
    static void Main(string[] args)
    {
        var wrapper = new Wrapper();
        wrapper.Start();
        System.Console.WriteLine($"{wrapper.data[15]}");
    }
}

这将包含接近源代码的任何可能的问题,并使调试不那么混乱。如果它在 std::copy 中崩溃,那么你只是错误地使用了 C++ 对象。