由于导入C ++ DLL,C#ShowDialog()抛出错误

这个C#程序在没有使用showdialog()的情况下工作正常但是当我尝试使用showdialog()时它会产生“系统访问冲突”exception。 奇怪的!!

C#代码

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace w_CSharp_GUI_1 { public partial class Form1 : Form { private String W_Addr,C_Addr,Pic_Addr="lol"; [DllImport("face_proj_trial_dll.dll")] public static extern string f_detect(string path); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog2 = new OpenFileDialog(); openFileDialog2.ShowDialog(this); Pic_Addr = (f_detect("C:\\pic.jpg")); textBox1.Text = Convert.ToString(Pic_Addr); } } } 

C ++代码:

 #include "face_detect_DLL.h" extern "C" __declspec(dllexport) char* _stdcall f_detect(char* path) { return path; } 

这并不奇怪。 您正在返回实际由C#marshaller创建的C字符串。 然后编组人员试图将该记忆释放两次。 一旦作为返回值,一次为参数传递给DLL。 第一个空闲将失败,因为内存未分配C#marshaller假定的分配器。

无论如何,你根本不想从你的DLL返回一个char* 。 我不确定你真正想做什么但是字符串P / invokes的正常模式是:

  1. 对于从C#到C ++的编组字符串,将它们声明为C#中的string和C ++中的char*
  2. 当走另一种方式时使用StringBuilder 。 在调用和使用MarshalAs之前分配缓冲区。 这种模式在网络上有很多例子。

返回字符串的函数是内存管理问题。 必须释放字符串的内存。 pinvoke marshaller将在返回的字符串上调用CoTaskMemFree()。 这会在Vista上崩溃,因为字符串没有用CoTaskMemAlloc分配,所以在XP上默默泄漏内存。

您需要将返回类型声明为IntPtr以防止编组器执行此操作。 并使用Marshal.PtrToStringAnsi()自行编组。 这解决了崩溃而不是内存泄漏。 您需要将该函数声明为void f_detect(const char * path,char * somevalue,size_t somevaluebuffersize),以便调用者可以传递自己的缓冲区。 管理方的StringBuilder。