C#GUI EXE和C ++ DLL分配解除分配

时间:2014-08-06 16:54:33

标签: c# c++ dll allocation

我有一个简单的C#GUI,上面有一个按钮。单击按钮时,将调用C ++ DLL,并在C ++ DLL中完成一些计算。

C#GUI(可执行文件)导入C ++ DLL,如下所示:

class Call_Link_DLL
    {
        [DllImport(@"Link_DLL.dll", EntryPoint = "OPS_Link_LoadFDD")]
        public static extern System.IntPtr OPS_Link_LoadFDD([In,Out,MarshalAs(UnmanagedType.LPStr)] string char_Ptr_octave_bin_dir);
    }

SystemIntPtr_ReturnedByDLL = Call_Link_DLL.OPS_Link_LoadFDD(char_Ptr_octave_bin_dir);

在C ++ DLL中我正在分配一个指向类对象的指针,如下所示:

FDD*FDD_Ptr_Object=new FDD();

当C ++ DLL完成其计算时,指针将被解除分配,如下所示:

delete FDD_Ptr_Object;//de-allocating makes C# executable (GUI) not able to re-execute without having to close GUI!

但问题是:当我第一次点击GUI按钮时,C ++ DLL会运行并生成结果。但是当我第二次点击GUI按钮时,程序崩溃了。我必须关闭GUI并再次单击GUI按钮重新执行。令人困惑的是,当我注释掉取消分配线(delete FDD_Ptr_Object;)时,当我第二次按下GUI按钮,第三次,依此类推时,GUI工作正常。我想知道是否有人遇到过这样的问题。谢谢。

编辑:我在这里发布所有细节:

以下是使用C#开发的简单GUI。它有一个按钮,当单击按钮时,将调用C ++ DLL(名为Link_DLL.dll)。

C# CUI

以下是C#中用于导入名为Link_DLL.dll的C ++ DLL的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;

namespace GUI_Call_Link_DLL
{
    class Call_Link_DLL
    {
        [DllImport(@"Link_DLL.dll", EntryPoint = "OPS_Link_LoadFDD")]
        public static extern System.IntPtr OPS_Link_LoadFDD([In,Out,MarshalAs(UnmanagedType.LPStr)] string char_Ptr_octave_bin_dir);
        [DllImport(@"Link_DLL.dll", EntryPoint = "OPS_Link_RunFDD_getFreqDomainResults")]
        public static extern System.IntPtr OPS_Link_RunFDD_getFreqDomainResults([In, Out, MarshalAs(UnmanagedType.LPStr)] string char_Address, [In, Out, MarshalAs(UnmanagedType.I4)]int int_NumChann, [In, Out, MarshalAs(UnmanagedType.I4)]int int_SamplingFreq);
        [DllImport(@"Link_DLL.dll", EntryPoint = "OPS_Link_feedFDD_setNaturalFreqSelectedByUser")]
        public static extern System.IntPtr OPS_Link_feedFDD_setNaturalFreqSelectedByUser([In, Out, MarshalAs(UnmanagedType.LPStr)]string char_Address_File_naturalFreqSelectedByUser);
        [DllImport(@"Link_DLL.dll", EntryPoint = "OPS_Link_RunFDD_getModeShapesResults")]
        public static extern System.IntPtr OPS_Link_RunFDD_getModeShapesResults();
        [DllImport(@"Link_DLL.dll", EntryPoint = "OPS_Link_UnloadFDD")]
        public static extern System.IntPtr OPS_Link_UnloadFDD();
    }
}

单击按钮时C#中的代码调用Link_DLL.dll:

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 GUI_Call_Link_DLL
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //you can copy "Octave-3.6.1" folder and subfolders anywhere you want and give binary path here:
            string char_Ptr_octave_bin_dir = @"C:\Software\Octave-3.6.1\bin\";

            string char_Address = openFileDialog1.FileName;
            int int_NumChann = int.Parse(textBox1.Text);
            int int_SamplingFreq = int.Parse(textBox2.Text);

            string char_Address_File_naturalFreqSelectedByUser = "FDD_TEMP_naturalFreqSelectedByUser.txt";

            System.IntPtr SystemIntPtr_ReturnedByDLL;//char* returned by DLL
            string string_ReturnedByDLL = "Good";//convert to string the char* returned by DLL

            try
            {
                SystemIntPtr_ReturnedByDLL = Call_Link_DLL.OPS_Link_LoadFDD(char_Ptr_octave_bin_dir);
                string_ReturnedByDLL = Marshal.PtrToStringAnsi(SystemIntPtr_ReturnedByDLL);
                if (string_ReturnedByDLL != "Good") { throw new Exception(); }

                SystemIntPtr_ReturnedByDLL = Call_Link_DLL.OPS_Link_RunFDD_getFreqDomainResults(char_Address, int_NumChann, int_SamplingFreq);
                string_ReturnedByDLL = Marshal.PtrToStringAnsi(SystemIntPtr_ReturnedByDLL);
                if (string_ReturnedByDLL != "Good") { throw new Exception(); }

                SystemIntPtr_ReturnedByDLL = Call_Link_DLL.OPS_Link_feedFDD_setNaturalFreqSelectedByUser(char_Address_File_naturalFreqSelectedByUser);
                string_ReturnedByDLL = Marshal.PtrToStringAnsi(SystemIntPtr_ReturnedByDLL);
                if (string_ReturnedByDLL != "Good") { throw new Exception(); }

                SystemIntPtr_ReturnedByDLL = Call_Link_DLL.OPS_Link_RunFDD_getModeShapesResults();
                string_ReturnedByDLL = Marshal.PtrToStringAnsi(SystemIntPtr_ReturnedByDLL);
                if (string_ReturnedByDLL != "Good") { throw new Exception(); }

                SystemIntPtr_ReturnedByDLL = Call_Link_DLL.OPS_Link_UnloadFDD();
                string_ReturnedByDLL = Marshal.PtrToStringAnsi(SystemIntPtr_ReturnedByDLL);
                if (string_ReturnedByDLL != "Good") { throw new Exception(); }
            }
            catch (Exception) { MessageBox.Show(string_ReturnedByDLL); }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //show dialog and get result
            DialogResult DialogResult_Object = openFileDialog1.ShowDialog();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {

        }
    }
}

Link_DLL.dll中的C ++代码是:

#include "Link.h"

//Declare handle to FDD_DLL
//This handle is declared within namespace to be accessible from within any function 
namespace namespace_top_of_Link{
    HINSTANCE hDLL=NULL;
}

//Exported function to be called by executable (C# or C++) 
//To load FDD_DLL
//To add dependencies directories to search path
//Dependencies path is determined by executable
extern "C" __declspec(dllexport)
char* OPS_Link_LoadFDD(char* char_Ptr_octave_bin_dir){
    try{
        std::string string_octave_bin_dir = std::string(char_Ptr_octave_bin_dir);//convert char* to std::string
        std::wstring wstring_octave_bin_dir = std::wstring(string_octave_bin_dir.begin(), string_octave_bin_dir.end());// convert std::string to std::wstring
        SetDllDirectory(wstring_octave_bin_dir.c_str());
        //SetDllDirectory((LPCWSTR)L"C:\\Software\\Octave-3.6.1\\bin\\");
        namespace_top_of_Link::hDLL=LoadLibrary((LPCWSTR)L"FDD_DLL.dll");
        if(namespace_top_of_Link::hDLL==NULL){
            throw "FDD DLL or dependencies could not be loaded";
        }
    }
    catch(char*char_Ptr_Exception){
        return char_Ptr_Exception;
    }
    return "Good";
}

//Exported function to be called by executable (C# or C++)
//To run FDD_DLL
//FDD_DLL returns results inside text files
//Results are frequencies and corresponding singular values
extern "C" __declspec(dllexport)
char* OPS_Link_RunFDD_getFreqDomainResults(char* char_Address,int int_NumChann,int int_SamplingFreq){
    try{
        typedef void (*Ptr_OPS_FDD_getFreqDomainResults)(char*, int, int);
        Ptr_OPS_FDD_getFreqDomainResults Ptr_OPS_FDD_getFreqDomainResults_Object=
            (Ptr_OPS_FDD_getFreqDomainResults)GetProcAddress(namespace_top_of_Link::hDLL,"OPS_FDD_getFreqDomainResults");
        Ptr_OPS_FDD_getFreqDomainResults_Object(char_Address, int_NumChann, int_SamplingFreq);
    }
    catch(char*char_Ptr_Exception){
        return char_Ptr_Exception;
    }
    return "Good";
}

//Exported function to be called by executable (C# or C++)
//To pass user-selected natural frequencies to FDD_DLL
//User-selected natural frequencies should be inside a text file
//Address of text file is passed to FDD_DLL
extern "C" __declspec(dllexport)
char* OPS_Link_feedFDD_setNaturalFreqSelectedByUser(const char* char_Address_File_naturalFreqSelectedByUser){
    try{
        typedef void (*Ptr_OPS_FDD_setNaturalFreqSelectedByUser)(const char*);
        Ptr_OPS_FDD_setNaturalFreqSelectedByUser Ptr_OPS_FDD_setNaturalFreqSelectedByUser_Object;
        Ptr_OPS_FDD_setNaturalFreqSelectedByUser_Object=
            (Ptr_OPS_FDD_setNaturalFreqSelectedByUser)GetProcAddress(namespace_top_of_Link::hDLL,"OPS_FDD_setNaturalFreqSelectedByUser");
        Ptr_OPS_FDD_setNaturalFreqSelectedByUser_Object(char_Address_File_naturalFreqSelectedByUser);
    }
    catch(char*char_Ptr_Exception){
        return char_Ptr_Exception;
    }
    return "Good";
}

//Exported function to be called by executable (C# or C++)
//To run FDD_DLL
//FDD_DLL returns results inside text files
//Results are mode shapes at user-selected natural frequencies
extern "C" __declspec(dllexport)
char* OPS_Link_RunFDD_getModeShapesResults(){
    try{
        typedef void (*Ptr_OPS_FDD_getModeShapesResults)();
        Ptr_OPS_FDD_getModeShapesResults Ptr_OPS_FDD_getModeShapesResults_Object=
            (Ptr_OPS_FDD_getModeShapesResults)GetProcAddress(namespace_top_of_Link::hDLL,"OPS_FDD_getModeShapesResults");
        Ptr_OPS_FDD_getModeShapesResults_Object();
    }
    catch(char* char_Ptr_Exception){
        return char_Ptr_Exception;
    }
    return "Good";
}

//Exported function to be called by executable (C# or C++)
//To unload FDD_DLL
extern "C" __declspec(dllexport)
char* OPS_Link_UnloadFDD(){
    try{
        if(FreeLibrary(namespace_top_of_Link::hDLL)==0){//If function can not free, return value is zero
            throw "FDD DLL could not be unloaded";
        }
    }
    catch(char* char_Ptr_Exception){
        return char_Ptr_Exception;
    }
    return "Good";
}

实际上Link_DLL.dll正在加载另一个名为FDD_DLL.dll的C ++ DLL,FDD_DLL.dll中的C ++代码是这样的:

#include "FDD.h"

//Declare object of FDD class
//FDD object is declared within namespace to be accessible from within any function
//FDD object pointer will be de-allocated (delete) when done with it
namespace namespace_top_of_FDD{
    FDD*FDD_Ptr_Object=new FDD();
}

//Exported function to be called by Link_DLL
//To initialize FDD object
//To run FDD object methods
//FDD object methods will return results inside text file
//Results are frequencies and corresponding singular values
extern "C" __declspec(dllexport)
void OPS_FDD_getFreqDomainResults(char* char_Address,int int_NumChann,int int_SamplingFreq){
    namespace_top_of_FDD::FDD_Ptr_Object->m_char_Address=char_Address;
    namespace_top_of_FDD::FDD_Ptr_Object->m_int_NumChann=int_NumChann;
    namespace_top_of_FDD::FDD_Ptr_Object->m_int_SamplingFreq=int_SamplingFreq;
    namespace_top_of_FDD::FDD_Ptr_Object->getMatrixOfChannels();
    namespace_top_of_FDD::FDD_Ptr_Object->getCPSD();
    namespace_top_of_FDD::FDD_Ptr_Object->getSVD();
    namespace_top_of_FDD::FDD_Ptr_Object->getFreqDomainResultsPrinted();
    namespace_top_of_FDD::FDD_Ptr_Object->getFreqPlot();
}

//Exported function to be called by Link_DLL
//To pass user-selected natural frequencies from Link_DLL to FDD_DLL
//User-selected natural frequencies should be inside a text file
//Address of text file is passed
//FDD_DLL would read text file
extern "C" __declspec(dllexport)
void OPS_FDD_setNaturalFreqSelectedByUser(const char* char_Address_File_naturalFreqSelectedByUser){
    namespace_top_of_FDD::FDD_Ptr_Object->getNaturalFreqValue(char_Address_File_naturalFreqSelectedByUser);
}

//Exported function to be called by Link_DLL
//To run FDD object methods
//FDD object methods will return results inside text files
//Results are mode shapes at user-selected natural frequencies
//Finally FDD object pointer will be de-allocated (delete)
extern "C" __declspec(dllexport)
void OPS_FDD_getModeShapesResults(){
    namespace_top_of_FDD::FDD_Ptr_Object->get_NaturalFreqIndex_from_NaturalFreqValue();
    namespace_top_of_FDD::FDD_Ptr_Object->getRealModesFromComplexModesAtNaturalFreq();
    namespace_top_of_FDD::FDD_Ptr_Object->getModeShapesNormalized();
    namespace_top_of_FDD::FDD_Ptr_Object->getModeShapesPrinted();
    //namespace_top_of_FDD::FDD_Ptr_Object->getModesPlot();
    namespace_top_of_FDD::FDD_Ptr_Object->getNormalizedModesPlot();
    //namespace_top_of_FDD::FDD_Ptr_Object->getNormalizedModesPlotAtSinglePlot();
    namespace_top_of_FDD::FDD_Ptr_Object->~FDD();
    //delete namespace_top_of_FDD::FDD_Ptr_Object;//de-allocating makes C# executable (GUI) not able to re-execute without having to close GUI!
    //namespace_top_of_FDD::FDD_Ptr_Object=NULL;
}

FDD::FDD()
        :m_char_Address(""),m_int_NumChann(0),m_int_SamplingFreq(0)
    {
    }

FDD::~FDD(){
}

// The rest of the C++ code inside FDD_DLL.dll is just implementation of methods of FDD class...

可以看出,FDD_DLL.dll中有一行“delete namespace_top_of_FDD::FDD_Ptr_Object;”,当我注释掉该行时,可以多次点击C#GUI的按钮,但是当我取消注释该行时,第一次点击时,C#GUI按钮有效,但第二次程序崩溃..如果您有任何想法,请告诉我......

1 个答案:

答案 0 :(得分:0)

现在问题解决了:

正如AlexD所说,问题是对象的双重破坏。我的代码中有这些陈述:

namespace_top_of_FDD::FDD_Ptr_Object->~FDD();
    delete namespace_top_of_FDD::FDD_Ptr_Object;
    namespace_top_of_FDD::FDD_Ptr_Object=NULL;

问题在于,使用namespace_top_of_FDD::FDD_Ptr_Object->~FDD();显式调用析构函数并使用delete namespace_top_of_FDD::FDD_Ptr_Object;进行解除分配是相互冲突的。在许多情况下,对对象析构函数的显式调用是个坏主意。解决方案是删除对对象析构函数的显式调用,所以现在我只需要取消分配:

delete namespace_top_of_FDD::FDD_Ptr_Object;
    namespace_top_of_FDD::FDD_Ptr_Object=NULL;

现在代码完美无缺。