DLL问题。主程序动态调用DLL,运行过DLL中的函数后,之后就不能用AnsiString了,用则必出错。

时间:2022-10-25 18:53:27
rt。在主程序中动态调用DLL中的函数后,之后的代码使用AnsiString就会出错,形如TMemo的Lines->Add();类型的以AnsiString为参数的方法也会出错。ShowMessage不会出错。
主程序中有关代码:
    //之前代码给三个二维数组分配内存,并取得前两个数组的数据
    //前两个数组的数据输出到TMemo组件中检查无误
    //下面这个DLL中的函数将前两个二维数组运算后存入第三个二维数组
    typedef void (*MyCalcFunc)(double** ,int ,double**,int ,int ,double ,double**);
    typedef int  (*MyInfoFunc)(HWND, HWND, LPVOID);
    HINSTANCE hiDllFile;
    MyCalcFunc RelationFunc;
    MyInfoFunc ShowDllInfo;
    hiDllFile=LoadLibrary("Relation.dll");
    
    RelationFunc=(MyCalcFunc)GetProcAddress(hiDllFile,"RelationGrade");
    ShowDllInfo=(MyInfoFunc)GetProcAddress(hiDllFile,"ShowMethodInfo");
    
    ShowDllInfo(this->Handle,NULL,NULL);
    RelationFunc(X,XRow,Y,YRow,Col,0.5,R);
    float test=0.0;
    for(int i=0;i<YRow;++i)
    {
//        AnsiString as="";                 //加上就出错

        for(int j=0;j<XRow;++j)
        {
            test+= R[i][j];//FormatFloat("##0.000",R[i][j]) + "   ";
        }
        //mmo1->Lines->Add("Total:");      //加上就出错
        //mmo1->Lines->Add(FloatToStr(test));//加上就出错
        //mmo1->Lines->Add(as);            //加上就出错
    }
    ShowMessage(FloatToStr(test));//这句没错,结果也正确
    FreeLibrary(hiDllFile);

18 个解决方案

#1


别沾AnsiString
用char*

#2


重复定义 as ????????

#3


没有遇到过,应该你的代码和逻辑有问题。

#4


发现了,只要不使用AnsiString就没有问题,比如单步跟踪,R[0][0]本来是0.821,在那个循环后加一条语句AnsiString aaa="";则这个语句过后,R[0][0],变成了4.641!
看来如daydayup234(关中刀客) 所说,不能用AnsiString!?可是我要将结果显示出来,那怎么整!?要显示,总会用到AnsiString的吧!?

#5


你的内存溢出啦。

#6


还没怎么仔细看,看看先……

#7


dll里用 char * 代替AnsiString

#8


很明显是内存溢出了!字符串的处理最怕这种

#9


为什么会溢出?是因为DLL里面的代码,还是因为别的原因?为什么不使用AnsiString就不会溢出?
BTW:什么叫溢出?汗。。。。。。。

#10


AnsiString是一个VCL的类,而在dll中最好用char *,这样才能通用,不然只能bcb和delphi用了

#11


AnsiString as="";                 
这样也出错,内存肯定是乱套了.(因内存乱套,导致调试器找不到期正确的出错行.),这现象是dll中使用了不该使用的内存,估计是:
1, Dll中有溢出代码. 2,调用约定不对.  第2点可能较大.

    typedef void (*MyCalcFunc)(double** ,int ,double**,int ,int ,double ,double**);
    typedef int  (*MyInfoFunc)(HWND, HWND, LPVOID);
这两个是DLL中的函数吧,没使用AnsiString啊. 可能是调用约定不对,你找一下那dll里的定义看看调用约定是不是这样的.

#12


如果是使用vector 这样的数组,在调试模式下,DLL中就比较容易找出错误所在, 使用C类型的数组出错是比较难查的.

#13


本想上午贴出代码,结果突然不能上CSDN,无奈,现在来贴出DLL中的代码:
//-----------------------------H----------------------------------
extern "C" __declspec(dllexport)
int __stdcall RelationGrade(double** X,int XRow,double **Y,int YRow,int Col,double E,double** R);
double Min(double** X,int XRow,double **Y,int Col,int YIndex);
double Max(double** X,int XRow,double **Y,int Col,int YIndex);
//----------------------------CPP----------------------------------
#include "RelationshipUnit.h"
#include <math.h>
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport)
int __stdcall RelationGrade(double** X,int XRow,double **Y,int YRow,int Col,double E,double** R)
{//输入参数:
 //     X:     子因素(二维数组)
 //     Y:     母因素(二维数组)
 //     XRow:  子因素个数
 //     YRow:  母因素个数
 //     Col:   每因素属性个数
 //     E:     分辨系数
 //输出参数:
 //     R:     母因素对子因素的关联度(YRow * XRow矩阵)
 //说明:
 //     XRow,YRow,Col限定了X,Y的大小
 //返回值
 //     0:     成功执行
 //     > 0:
 //     -1:    子元素首列含零值
 //     -2:    母元素首列含零值
 //     -3:    内存不足
 //     -4:    数据格式不对,计算过程出现分母为零
    //判断子母因素数组是否符合要求——首列数据不能有零值,否则无法归一化
    for(int i=0;i<XRow;++i)
    {
        if(X[i][0]<=0.0000001 && X[i][0] >=-0.0000001)
        {
            return -1;
        }
    }
    for(int i=0;i<YRow;++i)
    {
        if(Y[i][0]<=0.0000001 && Y[i][0] >=-0.0000001)
        {
            return -2;
        }
    }

    double **X_Unitary;//归一子因素
    double **Y_Unitary;//归一母因素

try
    {//数组分配一维空间

        X_Unitary=new double* [XRow];
        Y_Unitary=new double* [YRow];
    }
    catch(...)
    {//内存不足
        if(X_Unitary!=NULL)
        {
            delete X_Unitary;
            X_Unitary=NULL;
        }
        return -3;
    }

    for(int i=0;i<XRow;++i)
{//子因素归一化数组分配空间
try
        {
            X_Unitary[i]=new double[Col];
        }
        catch(...)
        {
            for(int j=0;j<i;++j)
            {
                delete X_Unitary[j];
                X_Unitary[j]=NULL;
            }
            delete X_Unitary;
            X_Unitary=NULL;
            delete Y_Unitary;
            Y_Unitary=NULL;
            return -3;
        }
}
    for(int i=0;i<YRow;++i)
{///母因素归一化数组分配空间
try
        {
            Y_Unitary[i]=new double[Col];
        }
        catch(...)
        {
            for(int j=0;j<i;++j)
            {
                delete Y_Unitary[j];
                Y_Unitary[j]=NULL;
            }
            for(int j=0;j<XRow;++j)
            {
                delete X_Unitary[j];
                X_Unitary[j]=NULL;
            }
            delete X_Unitary;
            X_Unitary=NULL;
            delete Y_Unitary;
            Y_Unitary=NULL;
            return -3;
        }
}
//--
    //归一化
    for(int i=0;i<XRow;++i)
    {
        for(int j=0;j<Col;++j)
        {
            X_Unitary[i][j]=X[i][j]/X[i][0];
        }
    }
    for(int i=0;i<YRow;++i)
    {
        for(int j=0;j<Col;++j)
        {
            Y_Unitary[i][j]=Y[i][j]/Y[i][0];
        }
    }
    //以下省略内存分配失败判断,因为基本上不可能失败

    double* fMin=new double [YRow];
    double* fMax=new double [YRow];
    for(int i=0;i<YRow;++i)
    {
        fMin[i]=Min(X_Unitary,XRow,Y_Unitary,Col,i);
        fMax[i]=Max(X_Unitary,XRow,Y_Unitary,Col,i);
    }
    for(int j=0;j<YRow;++j)
    {//计算结果
        for(int i=0;i<XRow;++i)
        {
            R[j][i]=0.0;
            for(int k=0;k<Col;++k)
            {
                double sub=fabs(Y_Unitary[j][k]-X_Unitary[i][k]);
                double kefai;
                if((sub + E*fMax[j])<=0.000001 && (sub + E*fMax[j]) >=-0.000001)
                {//数据格式不符合,分母为零。
                    //回收内存
                    for(int i=0;i<XRow;++i)
                    {
                       delete X_Unitary[i];
                    }
                    delete X_Unitary;
                    for(int i=0;i<YRow;++i)
                    {
                       delete Y_Unitary[i];
                    }
                    delete Y_Unitary;
                    delete fMin;
                    delete fMax;
                    return -4;
                }
                kefai=(fMin[j] + E*fMax[j]) / (sub + E*fMax[j]);
                R[j][i]+=kefai;
            }
            R[j][i]/=Col;
        }
    }
    //回收内存
    for(int i=0;i<XRow;++i)
{
       delete X_Unitary[i];
    }
    delete X_Unitary;
    for(int i=0;i<YRow;++i)
{
       delete Y_Unitary[i];
    }
    delete Y_Unitary;
    delete fMin;
    delete fMax;

//--
return 0;
}
//---------------------------------------------------------------------------
double Min(double** X,int XRow,double **Y,int Col,int YIndex)
{
    double result=0.0;
    for(int i=0;i<XRow;++i)
    {
        double mink=0.0;
        for(int k=0;k<Col;++k)
        {
            double tmp=fabs(Y[YIndex][k]-X[i][k]);
            if(k==0)
            {
                mink = tmp;
            }
            else if(mink > tmp)
            {
                mink=tmp;
            }
        }
        if(i==0)
        {
            result = mink;
        }
        else if(result > mink)
        {
            result = mink;
        }
    }
    return result;
}
//---------------------------------------------------------------------------
double Max(double** X,int XRow,double **Y,int Col,int YIndex)
{
    double result=0.0;
    for(int i=0;i<XRow;++i)
    {
        double mink=0.0;
        for(int k=0;k<Col;++k)
        {
            double tmp=fabs(Y[YIndex][k]-X[i][k]);
            if(k==0)
            {
                mink = tmp;
            }
            else if(mink < tmp)
            {
                mink = tmp;
            }
        }
        if(i==0)
        {
            result = mink;
        }
        else if(result < mink)
        {
            result = mink;
        }
    }
    return result;
}
//---------------------------------------------------------------------------

#14


我自己感觉没有什么不对的地方,汗。
还有,像我这种一个函数内需要new多个数组的情况,如何能保证内存被正确的回收?假设要用到有四个数组A、B、C、D,那么:
情况1:A已经new出来了,后来new B的时候出现了错误,就要delete A然后返回
情况2:A、B已经new出来了,后来new C的时候出现了错误,就要delete A、B然后返回
情况3:A、B、C已经new出来了,后来new D的时候出现了错误,就要delete A、B、C然后返回
情况4:A、B、C都new好了,但是经过一些计算发现继续运行的条件不符合,所以就要delete A、B、C然后返回;
情况5:函数顺利运行完毕,就要delete A、B、C、D然后返回
情况N:。。。。。。。。。。。
可能有N中情况,数组可能也不止四个,如何能通过一个简便的方法来控制内存的回收?每次都是try然后在catch里面delete已经分配好的数组太繁琐了,如果是二维数组就更繁琐了。

#15


導出與調用時都加上__stdcall吧,記得BCB中默認好象不是__stdcall. 
習慣上寫DLL時都指定調用約定,而不用默認約定。

typedef void (__stdcall *MyCalcFunc)(double** ,int ,double**,int ,int ,double ,double**);
typedef int  (__stdcall *MyInfoFunc)(HWND, HWND, LPVOID);

#16


用std::vector做多維數組,沒那麼多內存問題。做一維數組更沒問題。
要控制內存的釋放時刻可考慮用 std::auto_ptr

你是寫dll , 可考慮Dll內部用vector實現,對外接口用C指針,這樣別的編譯器也能使用。

#17


看来是约定的问题,加上__stdcall 之后就没问题了,我看了,Builder默认是__fastcall。多谢以上各位朋友啦,特别感谢PPower(月亮光光,照地堂)。
vector我接触过,不过我不想在DLL里用,按你的说法,看样vector是没问题的,有机会我会改成vector实现的。
关于auto_ptr,我没接触过,我会去看看的!
结贴了。

#18


哦,Mark一下,哈哈。我写的这个DLL是个关联度分析算法,属于灰度理论,留下这些关键字以便于以后有人能搜索到:)。希望搜索到的人用到了可以通知我一下(uhian#hotmail.com),让我有点成就感,咳咳。。。。。。

#1


别沾AnsiString
用char*

#2


重复定义 as ????????

#3


没有遇到过,应该你的代码和逻辑有问题。

#4


发现了,只要不使用AnsiString就没有问题,比如单步跟踪,R[0][0]本来是0.821,在那个循环后加一条语句AnsiString aaa="";则这个语句过后,R[0][0],变成了4.641!
看来如daydayup234(关中刀客) 所说,不能用AnsiString!?可是我要将结果显示出来,那怎么整!?要显示,总会用到AnsiString的吧!?

#5


你的内存溢出啦。

#6


还没怎么仔细看,看看先……

#7


dll里用 char * 代替AnsiString

#8


很明显是内存溢出了!字符串的处理最怕这种

#9


为什么会溢出?是因为DLL里面的代码,还是因为别的原因?为什么不使用AnsiString就不会溢出?
BTW:什么叫溢出?汗。。。。。。。

#10


AnsiString是一个VCL的类,而在dll中最好用char *,这样才能通用,不然只能bcb和delphi用了

#11


AnsiString as="";                 
这样也出错,内存肯定是乱套了.(因内存乱套,导致调试器找不到期正确的出错行.),这现象是dll中使用了不该使用的内存,估计是:
1, Dll中有溢出代码. 2,调用约定不对.  第2点可能较大.

    typedef void (*MyCalcFunc)(double** ,int ,double**,int ,int ,double ,double**);
    typedef int  (*MyInfoFunc)(HWND, HWND, LPVOID);
这两个是DLL中的函数吧,没使用AnsiString啊. 可能是调用约定不对,你找一下那dll里的定义看看调用约定是不是这样的.

#12


如果是使用vector 这样的数组,在调试模式下,DLL中就比较容易找出错误所在, 使用C类型的数组出错是比较难查的.

#13


本想上午贴出代码,结果突然不能上CSDN,无奈,现在来贴出DLL中的代码:
//-----------------------------H----------------------------------
extern "C" __declspec(dllexport)
int __stdcall RelationGrade(double** X,int XRow,double **Y,int YRow,int Col,double E,double** R);
double Min(double** X,int XRow,double **Y,int Col,int YIndex);
double Max(double** X,int XRow,double **Y,int Col,int YIndex);
//----------------------------CPP----------------------------------
#include "RelationshipUnit.h"
#include <math.h>
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport)
int __stdcall RelationGrade(double** X,int XRow,double **Y,int YRow,int Col,double E,double** R)
{//输入参数:
 //     X:     子因素(二维数组)
 //     Y:     母因素(二维数组)
 //     XRow:  子因素个数
 //     YRow:  母因素个数
 //     Col:   每因素属性个数
 //     E:     分辨系数
 //输出参数:
 //     R:     母因素对子因素的关联度(YRow * XRow矩阵)
 //说明:
 //     XRow,YRow,Col限定了X,Y的大小
 //返回值
 //     0:     成功执行
 //     > 0:
 //     -1:    子元素首列含零值
 //     -2:    母元素首列含零值
 //     -3:    内存不足
 //     -4:    数据格式不对,计算过程出现分母为零
    //判断子母因素数组是否符合要求——首列数据不能有零值,否则无法归一化
    for(int i=0;i<XRow;++i)
    {
        if(X[i][0]<=0.0000001 && X[i][0] >=-0.0000001)
        {
            return -1;
        }
    }
    for(int i=0;i<YRow;++i)
    {
        if(Y[i][0]<=0.0000001 && Y[i][0] >=-0.0000001)
        {
            return -2;
        }
    }

    double **X_Unitary;//归一子因素
    double **Y_Unitary;//归一母因素

try
    {//数组分配一维空间

        X_Unitary=new double* [XRow];
        Y_Unitary=new double* [YRow];
    }
    catch(...)
    {//内存不足
        if(X_Unitary!=NULL)
        {
            delete X_Unitary;
            X_Unitary=NULL;
        }
        return -3;
    }

    for(int i=0;i<XRow;++i)
{//子因素归一化数组分配空间
try
        {
            X_Unitary[i]=new double[Col];
        }
        catch(...)
        {
            for(int j=0;j<i;++j)
            {
                delete X_Unitary[j];
                X_Unitary[j]=NULL;
            }
            delete X_Unitary;
            X_Unitary=NULL;
            delete Y_Unitary;
            Y_Unitary=NULL;
            return -3;
        }
}
    for(int i=0;i<YRow;++i)
{///母因素归一化数组分配空间
try
        {
            Y_Unitary[i]=new double[Col];
        }
        catch(...)
        {
            for(int j=0;j<i;++j)
            {
                delete Y_Unitary[j];
                Y_Unitary[j]=NULL;
            }
            for(int j=0;j<XRow;++j)
            {
                delete X_Unitary[j];
                X_Unitary[j]=NULL;
            }
            delete X_Unitary;
            X_Unitary=NULL;
            delete Y_Unitary;
            Y_Unitary=NULL;
            return -3;
        }
}
//--
    //归一化
    for(int i=0;i<XRow;++i)
    {
        for(int j=0;j<Col;++j)
        {
            X_Unitary[i][j]=X[i][j]/X[i][0];
        }
    }
    for(int i=0;i<YRow;++i)
    {
        for(int j=0;j<Col;++j)
        {
            Y_Unitary[i][j]=Y[i][j]/Y[i][0];
        }
    }
    //以下省略内存分配失败判断,因为基本上不可能失败

    double* fMin=new double [YRow];
    double* fMax=new double [YRow];
    for(int i=0;i<YRow;++i)
    {
        fMin[i]=Min(X_Unitary,XRow,Y_Unitary,Col,i);
        fMax[i]=Max(X_Unitary,XRow,Y_Unitary,Col,i);
    }
    for(int j=0;j<YRow;++j)
    {//计算结果
        for(int i=0;i<XRow;++i)
        {
            R[j][i]=0.0;
            for(int k=0;k<Col;++k)
            {
                double sub=fabs(Y_Unitary[j][k]-X_Unitary[i][k]);
                double kefai;
                if((sub + E*fMax[j])<=0.000001 && (sub + E*fMax[j]) >=-0.000001)
                {//数据格式不符合,分母为零。
                    //回收内存
                    for(int i=0;i<XRow;++i)
                    {
                       delete X_Unitary[i];
                    }
                    delete X_Unitary;
                    for(int i=0;i<YRow;++i)
                    {
                       delete Y_Unitary[i];
                    }
                    delete Y_Unitary;
                    delete fMin;
                    delete fMax;
                    return -4;
                }
                kefai=(fMin[j] + E*fMax[j]) / (sub + E*fMax[j]);
                R[j][i]+=kefai;
            }
            R[j][i]/=Col;
        }
    }
    //回收内存
    for(int i=0;i<XRow;++i)
{
       delete X_Unitary[i];
    }
    delete X_Unitary;
    for(int i=0;i<YRow;++i)
{
       delete Y_Unitary[i];
    }
    delete Y_Unitary;
    delete fMin;
    delete fMax;

//--
return 0;
}
//---------------------------------------------------------------------------
double Min(double** X,int XRow,double **Y,int Col,int YIndex)
{
    double result=0.0;
    for(int i=0;i<XRow;++i)
    {
        double mink=0.0;
        for(int k=0;k<Col;++k)
        {
            double tmp=fabs(Y[YIndex][k]-X[i][k]);
            if(k==0)
            {
                mink = tmp;
            }
            else if(mink > tmp)
            {
                mink=tmp;
            }
        }
        if(i==0)
        {
            result = mink;
        }
        else if(result > mink)
        {
            result = mink;
        }
    }
    return result;
}
//---------------------------------------------------------------------------
double Max(double** X,int XRow,double **Y,int Col,int YIndex)
{
    double result=0.0;
    for(int i=0;i<XRow;++i)
    {
        double mink=0.0;
        for(int k=0;k<Col;++k)
        {
            double tmp=fabs(Y[YIndex][k]-X[i][k]);
            if(k==0)
            {
                mink = tmp;
            }
            else if(mink < tmp)
            {
                mink = tmp;
            }
        }
        if(i==0)
        {
            result = mink;
        }
        else if(result < mink)
        {
            result = mink;
        }
    }
    return result;
}
//---------------------------------------------------------------------------

#14


我自己感觉没有什么不对的地方,汗。
还有,像我这种一个函数内需要new多个数组的情况,如何能保证内存被正确的回收?假设要用到有四个数组A、B、C、D,那么:
情况1:A已经new出来了,后来new B的时候出现了错误,就要delete A然后返回
情况2:A、B已经new出来了,后来new C的时候出现了错误,就要delete A、B然后返回
情况3:A、B、C已经new出来了,后来new D的时候出现了错误,就要delete A、B、C然后返回
情况4:A、B、C都new好了,但是经过一些计算发现继续运行的条件不符合,所以就要delete A、B、C然后返回;
情况5:函数顺利运行完毕,就要delete A、B、C、D然后返回
情况N:。。。。。。。。。。。
可能有N中情况,数组可能也不止四个,如何能通过一个简便的方法来控制内存的回收?每次都是try然后在catch里面delete已经分配好的数组太繁琐了,如果是二维数组就更繁琐了。

#15


導出與調用時都加上__stdcall吧,記得BCB中默認好象不是__stdcall. 
習慣上寫DLL時都指定調用約定,而不用默認約定。

typedef void (__stdcall *MyCalcFunc)(double** ,int ,double**,int ,int ,double ,double**);
typedef int  (__stdcall *MyInfoFunc)(HWND, HWND, LPVOID);

#16


用std::vector做多維數組,沒那麼多內存問題。做一維數組更沒問題。
要控制內存的釋放時刻可考慮用 std::auto_ptr

你是寫dll , 可考慮Dll內部用vector實現,對外接口用C指針,這樣別的編譯器也能使用。

#17


看来是约定的问题,加上__stdcall 之后就没问题了,我看了,Builder默认是__fastcall。多谢以上各位朋友啦,特别感谢PPower(月亮光光,照地堂)。
vector我接触过,不过我不想在DLL里用,按你的说法,看样vector是没问题的,有机会我会改成vector实现的。
关于auto_ptr,我没接触过,我会去看看的!
结贴了。

#18


哦,Mark一下,哈哈。我写的这个DLL是个关联度分析算法,属于灰度理论,留下这些关键字以便于以后有人能搜索到:)。希望搜索到的人用到了可以通知我一下(uhian#hotmail.com),让我有点成就感,咳咳。。。。。。