在带有C#应用程序的DLL中使用CUDA

时间:2013-11-23 02:41:30

标签: c# c++ dll cuda unmanaged

我要做的是编写一个C#应用程序来生成分形图片(mandlebrot和julia集)。我使用非托管C ++和CUDA来完成繁重的工作,而C#用于用户界面。当我尝试运行此代码时,我无法调用我在DLL中编写的方法 - 我得到一个无效参数的未处理异常错误。

C ++ DLL旨在返回指向位图像素数据的指针,.NET位图使用该位图创建位图并将其显示在PictureBox控件中。

以下是相关代码:

C ++ :(简明省略了CUDA方法

extern "C" __declspec(dllexport) int* generateBitmap(int width, int height)
{
int *bmpData = (int*)malloc(3*width*height*sizeof(int));
int *dev_bmp;

gpuErrchk(cudaMalloc((void**)&dev_bmp, (3*width*height*sizeof(int))));

kernel<<<BLOCKS_PER_GRID, THREADS_PER_BLOCK>>>(dev_bmp, width, height);
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());

cudaFree(dev_bmp);
return bmpData;
}

C#:

public class NativeMethods
{
    [DllImport(@"C:\...\FractalMaxUnmanaged.dll")]
    public static unsafe extern int* generateBitmap(int width, int height);
}

//...

private unsafe void mandlebrotButton_Click(object sender, EventArgs e)
{
    int* ptr = NativeMethods.generateBitmap(FractalBox1.Width, FractalBox1.Height);
    IntPtr iptr = new IntPtr(ptr)

    fractalBitmap = new Bitmap(
                        FractalBox1.Width,
                        FractalBox1.Height,
                        3,
                        System.Drawing.Imaging.PixelFormat.Format24bppRgb,
                        iptr );

     FractalBox1.Image = fractalBitmap;
}

错误:

************** Exception Text **************
Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\...WindowsFormsApplication1.vshost.exe'.

我相信我遇到的问题是使用IntPtr - 这是将指针从非托管C ++传递给C#应用程序的正确方法吗?有更好的方法吗?传递一个指针是完成我想要做的最好的方法,还是有更好的方法将像素数据从非托管C ++传递给C#?

编辑:

从我从调试应用程序时得到的错误中收集到的内容,PInvokeStackImbalance意味着非托管代码和托管代码的签名不匹配。但是,他们确实看起来和我匹配。

我觉得我在这里遗漏了一些明显的东西,任何帮助或推荐的阅读都会受到赞赏。

1 个答案:

答案 0 :(得分:2)

您需要在C和C#中定义相同的调用约定: 在C:

extern "C" __declspec(dllexport) int* __cdecl generateBitmap(int width, int height)

在C#中:

[DllImport(@"C:\...\FractalMaxUnmanaged.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr generateBitmap(int width, int height);

您也可以使用stdcall代替cdecl,它只需要在两侧都相同。 我自己处理了很多托管/非托管代码,我还建议你将图像数组作为参数传递,并在C#中进行内存分配。这样做,您无需在托管环境中手动释放内存。