将数据从C#传入和传出DLL

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将数据从C#传入和传出DLL相关的知识,希望对你有一定的参考价值。

我正在尝试创建一个C#程序,它可以将数据传递到C / C ++ DLL,存储数据并完成计算。然后将结果返回给C#程序。不使用C#进行计算的原因是我计划用CUDA加速它。

我目前在C#中声明一个字节数组,并将其作为参数传递给DLL来发送数据。

然后我在C#中声明一个相同大小的字节数组,并将其作为参数传递以接收数据。然后DLL应该将结果写入该内存。

当我运行程序时,正确的数字将打印到屏幕上。 (因为我正在向阵列写入1,2,3 ......两次,加上这些是2,4,6 ......)然后打印出“追逐鼠标的猫”。当我按下一个键时,显示“鼠标追逐猫”,程序崩溃后退出显示vshost32.exe停止工作错误。我能够从this question解决这个错误。

现在,当我尝试直接从Windows资源管理器运行EXE时,我将第36步作为第一步打印,但随后我在计算函数调用中收到以下错误:

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

我知道DLL正确加载,因为init函数返回了正确的数字。我不确定为什么它只会在我作为EXE而不是在调试器中运行时崩溃。可能是什么导致了这个?

我应该采用不同的方式处理DLL和C#程序之间的内存交换吗?我的目标是避免使用Marshal Copy复制它,因为我需要这是高性能。最终目标是将GPU复制到GPU或从GPU进行计算的DLL,因此我认为没有理由在进入GPU之前将其复制到DLL中第二次。

C ++ DLL代码(写成C代码)

#include "stdafx.h"  
#include "stdlib.h"
const int CONSTANT = 3;
char** items;
int itemCount = 0;
int xcnt = -1;
int ycnt = -1;

extern "C" int __declspec(dllexport) __stdcall init(int itemcount_local, int xcnt_local, int ycnt_local){
    itemCount = itemcount_local;
    xcnt = xcnt_local;
    ycnt = ycnt_local;
    items = (char**)malloc(itemCount);
    if (items == NULL){
        return -1;
    }
    for (int i = 0; i < itemCount; i++){
        items[i] = (char*)malloc(CONSTANT*xcnt*ycnt);
        if (items[i] == NULL){
            return -1;
        }
        for (int d = 0; d < CONSTANT*xcnt*ycnt; d++){
            items[i][d] = 0;
        }
    }
    return CONSTANT*xcnt*ycnt;
}

//frees the memory created in init
extern "C" void __declspec(dllexport) __stdcall cleanup(){
    for (int i = 0; i < itemCount; i++){
        free(items[i]);
    }
    free(items);
    return;
}

extern "C" void __declspec(dllexport) __stdcall loadItem(int index, char* data){
    memcpy(items[index], data, CONSTANT*xcnt*ycnt);
    return;
}

//fills the buffer with the computed result.  Buffer needs to be the size of CONSTANT*xcnt*ycnt
extern "C" void __declspec(dllexport) __stdcall compute(char* buffer){
    for (int x = 0; x < CONSTANT*xcnt*ycnt; x++){
        int sum = 0;
        for (int i = 0; i < itemCount; i++){
            sum += items[i][x];
        }
        if (sum > 255){ //saturate at 255
            buffer[x] = 255;
        }
        else {
            buffer[x] = sum;
        }
    }
    return;
}

C#代码

class Program
{
[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern int  init(int imagecount_local, int xres_local, int yres_local);

[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern void cleanup();

[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern void loadItem(int index, byte[] data);

[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern void compute(byte[] buffer);

static void Main(string[] args)
{

    int x = 4, y = 3;
    int total = x * y * 3;
    Console.WriteLine(init(5, x, y));

    byte[] a = new byte[total];

    compute(a);
    for (int i = 0; i < total; i++)
    {
        Console.WriteLine(a[i]);
    }

    byte[] b = new byte[total];
    for (int i = 0; i < total; i++)
    {
        b[i] = (byte)i;
    }
    loadItem(0, b);
    loadItem(1, b);

    compute(a);
    for (int i = 0; i < total; i++)
    {
        Console.WriteLine(a[i]);
    }

    //cleanup();
    Console.WriteLine("The cat chased the mouse");
    Console.ReadKey();
    Console.WriteLine("The mouse chased the cat");
    return;
}
}
答案

我能够解决问题。这条线

items = (char**)malloc(itemCount);

本来应该

items = (char**)malloc(itemCount*sizeof(char*));

以上是关于将数据从C#传入和传出DLL的主要内容,如果未能解决你的问题,请参考以下文章

如何在 DLL 中返回向量?

将变量传入和传出 PayPal

XMPP 传入和传出文件委托未调用

如何查看DLL中的函数名及参数

如何在 Python 中将大量变量传入和传出函数?

传出 UDP 流量是不是允许此端口上的传入流量?