PINVOKE字节阵列从C 到C#

pinvoke byte array from c++ to c#

本文关键字:字节 阵列 PINVOKE      更新时间:2023-10-16

我正在尝试将C 中创建的字节数组移动到C#以供使用,现在我看到字节数组在C 方面有效,但我在我回到C#。

C 代码

__declspec(dllexport) void test(unsigned char* t_memory, int* t_size)
{
    int width, height, channels_in_file;
    t_memory = stbi_load("test.png", &width, &height, &channels_in_file, 0);
    *t_size = width*height;
}

c#代码

[DllImport(DllFilePath, EntryPoint = "test", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern int _test(ref IntPtr memory, out int size);
public static void Test()
{   
    IntPtr memory = IntPtr.Zero;
    _test(ref memory, out int size);
    byte[] memoryArray = new byte[size];
    Marshal.Copy(memory, memoryArray, 0, size);
    Bitmap bmp;
    using (var ms = new MemoryStream(memoryArray))
    {
        bmp = new Bitmap(ms);
    }
    bmp.Save("test_recreated.png");
}

C 代码不会返回数组,因为参数错误地声明了。您通过指针,但需要通过指针的地址。

应该像这样更改C 代码以匹配C#代码:

__declspec(dllexport) int test(unsigned char** t_memory, int* t_size)
{
    int width, height, channels_in_file;
    *t_memory = stbi_load("test.png", &width, &height, &channels_in_file, 0);
    *t_size = width*height;
    return 0;
}

您必须传递数组的地址,而不是数组本身。注意与此更改后大小参数的设置相似。

我还包括一个返回值以匹配C#代码。

您还需要导出Deallocator,以免泄漏此内存。

在下面尝试代码。一旦您存在,方法T_Size将不存在。因此,必须在调用方法中分配内存。您的形象有多大。大小可能必须是长而不是int。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
namespace ConsoleApplication1
{
    class Program
    {
        const string DllFilePath = @"c:temp";
        [DllImport(DllFilePath, EntryPoint = "test", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
        private static extern int _test(ref IntPtr memory, ref IntPtr size);
        static void Main(string[] args)
        {
        }
        public static void Test()
        {   
            IntPtr memory = IntPtr.Zero;
            IntPtr _size = Marshal.AllocCoTaskMem(sizeof(int));
            _test(ref memory, ref _size);
            int size = (int)Marshal.PtrToStructure(_size, typeof(int));
            byte[] memoryArray = new byte[size];
            Marshal.Copy(memory, memoryArray, 0, size);
            Bitmap bmp;
            using (var ms = new MemoryStream(memoryArray))
            {
                bmp = new Bitmap(ms);
            }
            bmp.Save("test_recreated.png");
        }
    }
}