慎用GetOpenFileName

时间:2023-03-10 08:17:24
慎用GetOpenFileName

这两天发现了一个小问题,经过一上午的排查终于找到了问题的原因——Windows 7的API函数GetOpenFileName竟然有BUG!

请参考下面的MFC代码:

CFileDialog dlg(TRUE);

dlg.m_ofn.lpstrInitialDir = _T("c:\\");

dlg.DoModal();

这段代码的含义是通过"文件选择对话框"选择一个文件,并且"文件选择对话框"的初始目录是C:\。

使用VC++2010编译上面的代码,在64位Windows 7上的运行结果一切正常——"文件选择对话框"的初始目录一定是C:\

使用VC++6.0编译上面的代码,在64位Windows 7上的运行结果为:"文件选择对话框"的初始目录并不一定是C:\,而是上次选择文件的目录!

查看MFC代码,就知道问题的所在了:VC++6.0的CFileDialog会调用GetOpenFileName或GetSaveFileName打开"文件选择对话框";而VC++2010会判断Windows的版本。如果是Vista以下(不含Vista)版本则会调用GetOpenFileName或GetSaveFileName;如果是Vista以上(含Vista)版本则会通过COM接口IFileOpenDialog或IFileSaveDialog打开"文件选择对话框"。

为了验证GetOpenFileName函数的正确性,特编写了如下代码:

TCHAR                szFile[MAX_PATH] = {'\0'};

OPENFILENAME    ofn;

memset(&ofn,0,sizeof(ofn));

ofn.lStructSize        =    sizeof(ofn);

ofn.lpstrFile        =    szFile;

ofn.nMaxFile        =    MAX_PATH;

ofn.lpstrInitialDir    =    _T("c:\\");

ofn.Flags        =    OFN_HIDEREADONLY | OFN_EXPLORER

|    OFN_ENABLESIZING;

GetOpenFileName(&ofn);

使用VC++2010编译上面的代码,执行结果也不正常了:"文件选择对话框"的初始目录并不一定是C:\,而是上次选择文件的目录!这说明:在Windows 7操作系统下,GetOpenFileName函数未能识别参数ofn.lpstrInitialDir,这应该是一个BUG。

结论:VC++6.0的MFC类CFileDialog通过GetOpenFileName或GetSaveFileName显示"文件选择对话框"。但是这两个函数在Windows 7的实现有BUG,导致初始目录不是设定的值。解决这个问题有两个办法:一是舍弃VC++6.0,改用VC++2010。这样处理最简单,美中不足就是程序只能运行在Windows XP及其以上版本的Windows下,无法在Windows 98/Me/2000上运行;二是改进VC++2010的CFileDialog代码,使得VC++6.0能够编译、使用。

另一个BUG:在Windows 7上使用GetOpenFileName选择一个文件后,该文件所在目录即被锁定。目录被锁定就无法被删除了,退出整个程序后目录锁定才会被解除。