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

时间:2011-09-22 13:26:16

标签: c# .net c++ dll

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

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;
}

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

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

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