从C++;到C# 我在C++应用程序中有一个数组,我想用它的指针来创建一个C数组数组委托,不需要复制。 所以我可以让它从C到C++,C++访问C中定义的相同数组,但是不能使它反向工作。

从C++;到C# 我在C++应用程序中有一个数组,我想用它的指针来创建一个C数组数组委托,不需要复制。 所以我可以让它从C到C++,C++访问C中定义的相同数组,但是不能使它反向工作。,c#,c++,pinvoke,dllimport,C#,C++,Pinvoke,Dllimport,C#代码: [DllImport("CppDll.dll",CallingConvention=CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.LPArray)] public static extern int[] GetCppArray(); int test_data[5] = { 12,60,55,49,26 }; extern "C" __declspec(dllexport)

C#代码:

   [DllImport("CppDll.dll",CallingConvention=CallingConvention.Cdecl)]
   [return: MarshalAs(UnmanagedType.LPArray)]
   public static extern int[] GetCppArray();
    int test_data[5] = { 12,60,55,49,26 };

    extern "C" __declspec(dllexport) int* GetCppArray()
    {
        return test_data;
    }
C++代码:

   [DllImport("CppDll.dll",CallingConvention=CallingConvention.Cdecl)]
   [return: MarshalAs(UnmanagedType.LPArray)]
   public static extern int[] GetCppArray();
    int test_data[5] = { 12,60,55,49,26 };

    extern "C" __declspec(dllexport) int* GetCppArray()
    {
        return test_data;
    }
在C#中使用:

我得到了这个错误:

System.Runtime.InteropServices.MarshalDirectiveException:“无法 封送处理“返回值”:无效的托管/非托管类型组合

<>我知道我可以用内存写程序直接用数组指针地址直接写入C++内存。 如果使用相同的<代码> MARSARLAS(unMaundType,LPArray)< /C>参数,并将C++数组传递给C++,但为什么它不能在相反的动作中工作?
注意:我的数据太大了,我真的不能在这里使用任何副本。

您应该先全面阅读这篇文章:

我还发现了相关的QAs:

您的 GETCPARPARE> /Cuff>函数只返回一个指针,它不返回一个自描述的“安全”数组,而.NET中的数组包含长度和秩(维度)信息,因此您必须修改C++代码才能正确地执行。 第一个选项是将数组作为COM样式的安全数组返回,这是通过-完成的,它必须作为参数传递,而不是返回值

在C++中使用COM安全数组有两种主要方法:使用Win32函数,如
SafeArrayCreate
——正确使用这些函数很痛苦,或者使用

(免责声明:我是通过查看API引用编写这段代码的,我还没有测试过它-我甚至不知道它是否可以编译)


我修改了我原来的答案,建议您使用
C++/CLI
。您说过您使用
.netframework
,因此
C++/CLI
是一个不错的选择。通过使用它,您不需要为
C++
指针复制。只需在
C++
指针上创建一个
C++/CLI
包装类。 下面是一个例子

C++代码

using System;
using Wrapper;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayWrapper vector = new ArrayWrapper();

            for (int i = 0; i < vector.Size; i++)
            {
                Console.Write($"{vector[i].ToString()} ");
            }
            Console.WriteLine();
            Console.WriteLine("Done");

            int index = vector.Size / 2;
            Console.WriteLine($"vector[{index.ToString()}]={vector[index].ToString()}");
            vector[index] *= 2;
            Console.WriteLine($"vector[{index.ToString()}]={vector[index].ToString()}");
        }
    }
}
函数.h

#pragma once
#ifdef LIBRARY_EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C"
{
#endif

    API int* GetCppArray();
    API int GetCppArraySize();
    API void DeleteCppArray(int* vec);

#ifdef __cplusplus
}
#endif
#pragma once

using namespace System;

namespace Wrapper 
{
    public ref class ArrayWrapper : public IDisposable
    {
    private:
        int* values;
        int size;
        bool isDisposed;

    public:
        ArrayWrapper();
        ~ArrayWrapper();
        !ArrayWrapper();

        property int Size
        {
            int get();
        }

        property int default[int]
        {
            int get(int index);
            void set(int index, int value);
        }
    };
}
功能。cpp

#include "pch.h"
#include "functions.h"

const int vecSize = 10000;

int* GetCppArray()
{
    int* vec = new int[vecSize];
    for (int i = 0; i < vecSize; ++i)
    {
        vec[i] = i * 2;
    }

    return vec;
}

int GetCppArraySize()
{
    return vecSize;
}

void DeleteCppArray(int* vec)
{
    delete[] vec;
}
#include "pch.h"
#include "Wrapper.h"

#include "../Library/functions.h"

namespace Wrapper
{
    ArrayWrapper::ArrayWrapper()
    {
        this->values = GetCppArray();
        this->size = GetCppArraySize();
        this->isDisposed = false;
    }

    ArrayWrapper::~ArrayWrapper()
    {
        if (this->isDisposed == true)
        {
            return;
        }

        this->!ArrayWrapper();
        this->isDisposed = true;
    }

    ArrayWrapper::!ArrayWrapper()
    {
        DeleteCppArray(this->values);
        this->values = nullptr;
        this->size = 0;
    }

    int ArrayWrapper::Size::get()
    {
        return this->size;
    }

    int ArrayWrapper::default::get(int index)
    {
        if (index < 0 || index >= this->size)
        {
            throw  gcnew Exception("Invalid index");
        }
        return this->values[index];
    }

    void ArrayWrapper::default::set(int index, int value)
    {
        if (index < 0 || index >= this->size)
        {
            throw  gcnew Exception("Invalid index");
        }

        this->values[index] = value;
    }
}
包装器.cpp

#include "pch.h"
#include "functions.h"

const int vecSize = 10000;

int* GetCppArray()
{
    int* vec = new int[vecSize];
    for (int i = 0; i < vecSize; ++i)
    {
        vec[i] = i * 2;
    }

    return vec;
}

int GetCppArraySize()
{
    return vecSize;
}

void DeleteCppArray(int* vec)
{
    delete[] vec;
}
#include "pch.h"
#include "Wrapper.h"

#include "../Library/functions.h"

namespace Wrapper
{
    ArrayWrapper::ArrayWrapper()
    {
        this->values = GetCppArray();
        this->size = GetCppArraySize();
        this->isDisposed = false;
    }

    ArrayWrapper::~ArrayWrapper()
    {
        if (this->isDisposed == true)
        {
            return;
        }

        this->!ArrayWrapper();
        this->isDisposed = true;
    }

    ArrayWrapper::!ArrayWrapper()
    {
        DeleteCppArray(this->values);
        this->values = nullptr;
        this->size = 0;
    }

    int ArrayWrapper::Size::get()
    {
        return this->size;
    }

    int ArrayWrapper::default::get(int index)
    {
        if (index < 0 || index >= this->size)
        {
            throw  gcnew Exception("Invalid index");
        }
        return this->values[index];
    }

    void ArrayWrapper::default::set(int index, int value)
    {
        if (index < 0 || index >= this->size)
        {
            throw  gcnew Exception("Invalid index");
        }

        this->values[index] = value;
    }
}
#包括“pch.h”
#包括“Wrapper.h”
#包括“./Library/functions.h”
名称空间包装器
{
ArrayWrapper::ArrayWrapper()
{
此->值=GetCppArray();
此->size=GetCppArraySize();
此->isDisposed=false;
}
ArrayWrapper::~ArrayWrapper()
{
if(this->isDisposed==true)
{
返回;
}
此->!ArrayWrapper();
此->isDisposed=true;
}
ArrayWrapper::!ArrayWrapper()
{
DeleteCppArray(此->值);
该->值=空ptr;
这个->大小=0;
}
int ArrayWrapper::Size::get()
{
返回此->大小;
}
int ArrayWrapper::default::get(int索引)
{
如果(索引<0 | |索引>=此->大小)
{
抛出新异常(“无效索引”);
}
返回此->值[索引];
}
void ArrayWrapper::default::set(int索引,int值)
{
如果(索引<0 | |索引>=此->大小)
{
抛出新异常(“无效索引”);
}
此->值[索引]=值;
}
}
C#代码

using System;
using Wrapper;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayWrapper vector = new ArrayWrapper();

            for (int i = 0; i < vector.Size; i++)
            {
                Console.Write($"{vector[i].ToString()} ");
            }
            Console.WriteLine();
            Console.WriteLine("Done");

            int index = vector.Size / 2;
            Console.WriteLine($"vector[{index.ToString()}]={vector[index].ToString()}");
            vector[index] *= 2;
            Console.WriteLine($"vector[{index.ToString()}]={vector[index].ToString()}");
        }
    }
}
使用系统;
使用包装器;
命名空间TestApp
{
班级计划
{
静态void Main(字符串[]参数)
{
ArrayWrapper向量=新的ArrayWrapper();
对于(int i=0;i
您是否可以使用来处理数据

[DllImport("CppDll.dll",CallingConvention=CallingConvention.Cdecl)]
public static extern IntPtr GetCppArray();

var cpparray = NativeLib.GetCppArray();
var test_data_2 = Marshal.ReadInt32(cpparray, 2 * sizeof(int));
Console.WriteLine(test_data_2); // 55

看起来可能非常接近你想要的;有一个示例非常准确,尽管它仍然需要
不安全的

 Span<int> cpparray;
 unsafe
 {
     cpparray = new Span<int>((int*)NativeLib.GetCppArray(), 5);
 } 
 Console.WriteLine(cpparray[2]); // 55
Span数组;
不安全的
{
cpparray=newspan((int*)NativeLib.GetCppArray(),5);
} 
Console.WriteLine(cpparray[2]);//55

是.NET framework还是.NET core?对于.NET framework,如果你不想复制,你必须1)从GetCppArray返回
IntPtr
,而不是
int[]
,2)使用
unsafe
关键字并将返回的
IntPtr
转换为
int*
,有点像这样:如果你不想
unsafe
代码,您必须以某种方式复制数组。@SimonMourier我不想使用unsafeSo,因此您必须以某种方式复制(使用array.copy)。不能既吃蛋糕又吃蛋糕。另一个选项是使用
C++\CLI
。我更新了我的答案,向您展示了一个示例。没有数据复制,没有不安全,而且您使用
C++\CLI
包装器的方式与使用简单的
C
数组的方式非常相似。我提到了不复制。我想直接使用数组作为unity网格顶点数组。。。所以不能使用这个选项。我知道我可以使用它,即使在内存读取器中也可以读取一个值->复制到另一个新值。我在问题中问的是如何在不复制的情况下将其作为C#数组。我需要C数组,比如转换C++数组指针,从C中得到一个C数组,它可以反向传递C数组指针到C++,得到C++的ARARYI,不想使用不安全代码,没有跨度,很容易从C++得到数组…我想封送返回,我想学习它,看看我的代码有什么问题,但谢谢你还有一件事,你得到了我想要的C#数组,在Unity中用作C#数组property@DraculaBytePair无法使用不安全的方法从C#w/o直接访问非托管内存。有各种各样的方法来解决这个问题,但是