您的位置:首页 > 其它

VC6搭配新SDK后,使用CFileDialog会出现析构异常的

2010-04-23 10:57 537 查看
1)问题的来源:

ISAutomationRunner程序中,主体功能(调用vbs)完成以后。由于这个软件需要在批处理中被调用,处于方便性考虑需要加入控制台输出功能。因为程序主体来自codeguru上别人的程序,而且是GUI的,无法直接进行控制台输出。首先试了试改成支持MFC的console程序的,结果报错,粗略分析了下是由于源码中有几个地方用到了窗口句柄。不得以采用了为GUI程序添加控制台输出的方法:

-------------------------------------

AttachConsole(-1); // 将当前程序附着到父进程上 freopen("CONIN$", "r+t", stdin); // 重定向 STDIN
freopen("CONOUT$", "w+t", stdout); // 重定向STDOUT -------------------------------------

其中AttachConsole需要用新的SDK,因而需要设置_WIN32_WINNT=0x0500,这么一设置后AttachConsole使用正常了。

编译,运行,出现文件选择框,确定。晕,出现异常了。

IDE中调试一番,发现是程序中使用的CTextFile类(Johan Rosengren所写的一个很实用的类)中调用的CFileDialog析构时出现异常了,源码如下

-------------------------------------

BOOL CTextFile::GetFilename( BOOL save, CString& filename )
/* ============================================================
Function : CTextFile::GetFilename
Description : The function will display a standard file
dialog. If the instance is created with an
extension, the extension will be used to
filter files.
Return : BOOL - TRUE if a file was
selected
Parameters : BOOL save - TRUE if the file
should be saved.
CString& filename - Placeholder for the
selected filename ============================================================*/
{
CString filter;
CString extension = GetExtension();
if( extension.GetLength() )
filter = extension + _T( "-files (*." + extension + ")|*." ) + extension + _T( "|All Files (*.*)|*.*||" ); BOOL result = FALSE;
CFileDialog dlg( !save, extension, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter ); if( dlg.DoModal() == IDOK )
{
filename = dlg.GetPathName();
result = TRUE;
} return result; } --------------------------------------

2)问题的原因:

首先注释了新入的AttachConsole函数,问题依旧。自己郁闷的折腾了好一番,没法只好暂时搁置了。刚才又想起来,于是开始google,一搜“ CFileDialog 析构 异常 ”,乖乖-总算让我碰上一个MFC的bug了。

问题的产生原因在

http://codeguru.earthweb.net/forum/printthread.php?t=320297&pp=50

有所解释,我认为大体可以理解为:

VC6 自带的SDK和 MFC42中的定义,再后来的SDK中更新了,从而导致在析构的时候多卸载了内容

3)问题的解决:

a)换回老SDK,手动加载AttachConsole

b)修改CTextFile源码,由在栈上分配CFileDialog改为在堆上分配

根据我的情况,我选择了a方法,手动加载AttachConsole的源码如下

--------------------------------------

//为了在不用PLATFORM SDK的情况下加载AttachConsole
BOOL myAttachConsole(DWORD dwProcessId)
{
typedef BOOL (WINAPI* _AttachConsole)(DWORD dwProcessId);
HINSTANCE hinstance = LoadLibrary(_T("kernel32.dll"));
if (hinstance == NULL)
{
return FALSE;
}
_AttachConsole AttachConsole = NULL;
AttachConsole = (_AttachConsole)GetProcAddress(hinstance , "AttachConsole");
if (AttachConsole == NULL)
{
return FALSE;
}
AttachConsole(dwProcessId);

return TRUE;
}

-------------------------------------- 4)感慨: 写程序就是这样的充满意外。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: