我要做的是编写一个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意味着非托管代码和托管代码的签名不匹配。但是,他们确实看起来和我匹配。
我觉得我在这里遗漏了一些明显的东西,任何帮助或推荐的阅读都会受到赞赏。
答案 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#中进行内存分配。这样做,您无需在托管环境中手动释放内存。