怪事!关于动态连接dll

wdh 2000-06-09 06:56:00
在我的程序中使用了MS的rapi.dll,开始我使用的是静态链接的方法,即包括rapi.h和rapi.lib两个文件,这时我的程序一切正常。
后来我改用动态链接的方法,即没有包括rapi.h和rapi.lib两个文件,程序编译通过,但执行时出现运行时错误,而且问题颇怪。
当我运行DEBUG版本时,会出现这样的怪事:
for(i=0;i<CeFieldCount;i++)
{
CeRecordset.GetODBCFieldInfo(i,CeFieldInfo);
pCeProps[i].wLenData = 0; //程序在此处出错
...
}

出错原因是变量i的值变成了一个很大的数,而pCeProps是一个不大于50个元素的数组,CeRecordset是CRecordset类的对象,其成员函数GetODBCFieldInfo的声明为:
void GetODBCFieldInfo(short nIndex,CODBCFIELDINFO& fieldinfo)
我认为,从语法来说,i的值是不可能被CeRecordset.GetODBCFieldInfo(i,CeFieldInfo);这条语句改变的,但是我的程序偏偏就出现了这种情况,真是不可思议。
当我运行release版本时,错误却在另外一处发生:
CString strDBName=CeDB.GetDatabaseName();
CeDB是CDatabase类的对象,程序运行到这里就回执行非法操作,可在我静态链接连接rapi.dll时,这条语句工作得很正常。
现在我把我使用动态链接dll的代码的一部分列举如下,希望大侠们帮忙看看有什么错误。

在rapi.h中的声明为:(rapi.h是MS提供的)
STDAPI_(CEOID) CeCreateDatabase(LPWSTR, DWORD, WORD, SORTORDERSPEC*);

我的程序中的声明为:
typedef CEOID (*_pCeCreateDatabase)(LPWSTR, DWORD, WORD, SORTORDERSPEC*);
_pCeCreateDatabase pCeCreateDatabase ;
得到函数地址:
pCeCreateDatabase=(_pCeCreateDatabase)GetProcAddressEx(m_hRapi,_T("CeCreateDatabase"));
调用函数的代码为:
pCeCreateDatabase(...);
其中GetProcAddressEx()为自定义函数,目的是解决GetProcAddress()不能使用UNICODE字符串的问题。其代码如下:
FARPROC CCeDBConvertDlg::GetProcAddressEx(HMODULE hModule, LPCWSTR lpProcName)
{
int iSize=wcslen(lpProcName);
char* strFuncA=NULL;
FARPROC pRet;
try{
strFuncA=new char[iSize+1];
wcstombs(strFuncA,lpProcName,iSize);
strFuncA[iSize]=0;
pRet=GetProcAddress(hModule,strFuncA);
}
catch(...)
{
delete []strFuncA;
}
delete []strFuncA;
return pRet;

}

还望大侠们多多指点.



...全文
251 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
wdh 2000-06-18
  • 打赏
  • 举报
回复
1.当程序出错时,i=4205308,CeFieldCount=13,
我现在对程序做了以下修改:
for(i=0;i<CeFieldCount;i++)
{
short index=0;
index=i;
try{
//CeRecordset.GetODBCFieldInfo(i,CeFieldInfo);
CeRecordset.GetODBCFieldInfo(index,CeFieldInfo);
}
catch(CException* pErr){
pErr->ReportError ();
pErr->Delete ();
return FALSE;
}
.....
结果是:当程序第一次进入循环时,在执行了语句CeRecordset.GetODBCFieldInfo(index,CeFieldInfo);后,
i=4205115,index=-2168,CeFieldCount=13,而且程序没有发出异常
2.Cedb是一个堆栈对象,我也不知道为什么会为NULL,估计是程序的堆栈如你所说
被破坏了,由于这是release版本,我也没有办法调试。
wdh 2000-06-17
  • 打赏
  • 举报
回复
回答6:
AfxMessageBox(_T("start"));
CString strDBName=CeDB.GetDatabaseName();
AfxMessageBox(_T("end"));
当程序弹出start对话框后就出现执行非法操作错误
我已经把我的工程文件寄了一份给你,因为我这边的代理服务器有些问题,不
知道你能否收到。
jy 2000-06-17
  • 打赏
  • 举报
回复
抱歉,没有上网。
提及的几个函数的的调用顺序贴出来看看再说。这里再做一些猜测:
1 关于循环:
for(i=0;i<CeFieldCount;i++)
{
try{
CeRecordset.GetODBCFieldInfo(i,CeFieldInfo);
}
catch(CDBException* e){
e->Report();
e->Delete();
}

pCeProps[i].wLenData = 0; //程序在此处出错
...
}

这里提请注意的是,异常CDBException,或者其他任何从CException, CUserException派生的MFC Exception,请显示调用Delete()方法来清除自身。

2 尝试调用CeCreateDatabaseEx()
3 转换到WCHAR应该写作:
LPWSTR strFuncA = NULL;
...
strFuncA = new WCHAR[iSize+1];
strFuncA[iSize]=0;

4 据一个简单的例子:在被调用函数中这样写:
void a(void){
char buf[20];
memset(buf, 0, 100);
return;
}
就能导致这个调用栈序列的崩溃。进一步,猜测返回地址虽没改变,但其他变化时:如buf[126]=buf[126]+1;就可能正巧改变到i值上。

5 也可能因为其他原因,比如:异常回溯栈机制混乱,可以在可以语句上附加try...catch块来尝试追踪;局部变量被优化,可以关闭局部变量的优化开关,rebuild the project后再行调试。

6 “当我运行release版本时,错误却在另外一处发生:
CString strDBName=CeDB.GetDatabaseName();
CeDB是CDatabase类的对象,程序运行到这里就回执行非法操作,可在我静态链接连接rapi.dll时,这条语句工作得很正常。”

那么,您是如何确认程序试运行到这里就执行非法操作呢?依据,。。。

7 重复,给出完整点的代码和调用吧,否则,我投降了。


celxta 2000-06-17
  • 打赏
  • 举报
回复
回答1:
出错时你的i什是多少?,CeFieldCount什是多少?当施行catch()之后,对象已被消除,不可能再用该对象
回答wdh 6:
Cedb对象已为NULL
jy 2000-06-17
  • 打赏
  • 举报
回复
收到,检查中,搜索中。^-^
wdh 2000-06-16
  • 打赏
  • 举报
回复
谢谢jy的热心帮助,但是我照你的代码改了,问题仍没有解决,请问照成函数调用内部的堆栈引用混乱的可能原因是什么?
jy 2000-06-15
  • 打赏
  • 举报
回复
网络太糟糕了。
出现i植被改变的原因是一种随机现象,一般是因为函数调用内部的堆栈引用混乱,并且后果严重。
不能仔细阅读你的代码,如果仍有问题,直接发信给我好了。
jy 2000-06-15
  • 打赏
  • 举报
回复
你的try...catch不太正确:
try{
strFuncA=new char[iSize+1];
wcstombs(strFuncA,lpProcName,iSize);
strFuncA[iSize]=0;
pRet=GetProcAddress(hModule,strFuncA);
}
catch(...)
{
delete []strFuncA;
}
delete []strFuncA;
return pRet;

}

改为
try{
strFuncA=new char[iSize+1];
wcstombs(strFuncA,lpProcName,iSize);
strFuncA[iSize]=0;
pRet=GetProcAddress(hModule,strFuncA);

delete []strFuncA;
return pRet;
}
catch(...)
{
delete []strFuncA;
return pRet;
}
}

原写法可能会导致delete []strFuncA;被重复调用。
jy 2000-06-15
  • 打赏
  • 举报
回复
你的try...catch不太正确:
try{
strFuncA=new char[iSize+1];
wcstombs(strFuncA,lpProcName,iSize);
strFuncA[iSize]=0;
pRet=GetProcAddress(hModule,strFuncA);
}
catch(...)
{
delete []strFuncA;
}
delete []strFuncA;
return pRet;

}

改为
try{
strFuncA=new char[iSize+1];
wcstombs(strFuncA,lpProcName,iSize);
strFuncA[iSize]=0;
pRet=GetProcAddress(hModule,strFuncA);

}
catch(...)
{
delete []strFuncA;

}
delete []strFuncA;
return pRet;

}

16,466

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧