如何在代码中确保托管/非托管组合? [英] How do I ensure a managed/unmanaged combination in my code?

查看:85
本文介绍了如何在代码中确保托管/非托管组合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using ReturnCPPArrayToCSharpExample_CSharpSide_;

namespace DLLCall
{
    class Program
    {
        [DllImport("E:\\C++Projects\\ReturnC++ArrayToDLLExample(1D)\\DLLFromCPPToCSharp\\Debug\\ArrayDLLFromCPPToCSharp")]
        public static extern IntPtr[] convertMatrix(int height, int width, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(JaggedArrayMarshaler))]byte[][] inputArr);

        [DllImport("E:\\C++Projects\\ReturnC++ArrayToDLLExample(1D)\\DLLFromCPPToCSharp\\Debug\\ArrayDLLFromCPPToCSharp", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ReleaseMemory(IntPtr ptr);

        static void Main(string[] args)
        {
            int height = 3;
            int width = 3;
            byte[][] inputArr = new byte[3][];
            inputArr[0] = new byte[] { 1, 1, 1 };
            inputArr[1] = new byte[] { 1, 1, 1 };
            inputArr[2] = new byte[] { 1, 1, 1 };

            IntPtr[] obj = new IntPtr[3];
            obj = convertMatrix(height, width, inputArr);
            IntPtr[] outputMatrixOfPointers = new IntPtr[3];
            //Marshal.Copy(obj, outputMatrixOfPointers, 0, 3);

            byte[,] result = new byte[3, 3];
            //Marshal.Copy(outputMatrixOfPointers, result, 0, 5);
            for (int i = 0; i < result.Length; i++)
            {
                //Console.WriteLine(result[i]);
            }
            Console.ReadKey();
        }
    }
}




using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ReturnCPPArrayToCSharpExample_CSharpSide_
{
    class JaggedArrayMarshaler : ICustomMarshaler
    {
        static ICustomMarshaler GetInstance(string cookie)
        {
            return new JaggedArrayMarshaler();
        }

        GCHandle[] handles;
        GCHandle buffer;
        Array[] array;
        public void CleanUpManagedData(object ManagedObj)
        {
        }
        public void CleanUpNativeData(IntPtr pNativeData)
        {
            buffer.Free();
            foreach (GCHandle handle in handles)
            {
                handle.Free();
            }
        }
        public int GetNativeDataSize()
        {
            return 4;
        }
        public IntPtr MarshalManagedToNative(object ManagedObj)
        {
            array = (Array[])ManagedObj;
            handles = new GCHandle[array.Length];
            for (int i = 0; i < array.Length; i++)
            {
                handles[i] = GCHandle.Alloc(array[i], GCHandleType.Pinned);
            }
            IntPtr[] pointers = new IntPtr[handles.Length];
            for (int i = 0; i < handles.Length; i++)
            {
                pointers[i] = handles[i].AddrOfPinnedObject();
            }
            buffer = GCHandle.Alloc(pointers, GCHandleType.Pinned);
            return buffer.AddrOfPinnedObject();
        }
        public object MarshalNativeToManaged(IntPtr pNativeData)
        {
            return array;
        }
    }




#include <iostream>

using namespace std;
using byte = unsigned char;


extern "C" __declspec(dllexport) unsigned char** convertMatrix(int height, int width, byte inputArr[][3])
{
	byte** arr = 0;
	arr = new byte*[height];
	for (int i = 0; i < height; i++) 
	{
		arr[i] = new byte[width];
		for (int j = 0; j < width; j++) 
		{
			arr[i][j] = 0;
		}
	}
	return arr;
}

extern "C" __declspec(dllexport) int ReleaseMemory(int* pArray)
{
	delete[] pArray;
	return 0;
}





我的尝试:



我尝试了什么:



-我自己也不确定,但根据我所读到的,IntPtr []可以是用于调用方法,即使方法返回类型不同,因为它可以容纳不同的对象,所以我觉得不应该是一个问题。

- 添加自定义类来编组2D数组从codeproject给出(又名JagggedArrayMarshaller),因为我可以理解正常的编组方法只能满足2D数组。

-但是当我试图调用方法但是我不明白为什么会出现问题将托管代码编组到托管代码不起作用:



What I have tried:

What I have tried:

-I'm not sure about this myself, but based on what I have read, IntPtr[] can be used to invoke methods even if the method return type is different as it could hold different objects, so I felt that should'nt be an issue.
-Add in a custom class to marshal 2D-arrays as given from codeproject as (a.k.a JagggedArrayMarshaller) as I could understand that normal marshaling methods could only cater to a 2D array.
-However there were issues when I tried to invoke the method but I do not understand why the marshalling to unmanaged code to managed does not work:

IntPtr[] obj = new IntPtr[3];
obj = convertMatrix(height, width, inputArr);



结果,它返回错误:



返回类型'System.Runtime.InteropServices.MarshalDirectiveException'的未处理异常在ReturnCPPArrayToCSharpExample(CSharpSide).exe



附加信息:无法封送'返回value':无效的托管/非托管类型组合。


As a result, it returns the error:

An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in ReturnCPPArrayToCSharpExample(CSharpSide).exe

Additional information: Cannot marshal 'return value': Invalid managed/unmanaged type combination.

推荐答案

错误是正确的:在C ++运行时分配内存并在C#中使用它不是一个好主意作为对象。



双指针(字节**)毫无意义。使用一个简单的指针。



解决方案:在C#中分配内存并将其作为参数提供给C ++。看看我的文章,它以简单的方式处理这些内容。



BTW:不要使用完整的pathes,而是将dll复制到正确的目录中。这是糟糕的风格,有一天你会崩溃
The error is correct: It is not a good idea to allocate memory in the C++ runtime and use it in C# as object.

The double pointers (byte**) making no sense. Use a simple pointer.

Solution: allocate in the memory in C# and give it as parameter to C++. Take a look at my article which deals such stuff in a simple way.

BTW: dont use complete pathes, but copy the dll in the correct directory. It is bad style and someday you will have crashes


这篇关于如何在代码中确保托管/非托管组合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆