我有一个简单的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#中用于导入名为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按钮有效,但第二次程序崩溃..如果您有任何想法,请告诉我......
答案 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;
现在代码完美无缺。