这两天发现了一个小问题,经过一上午的排查终于找到了问题的原因——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选择一个文件后,该文件所在目录即被锁定。目录被锁定就无法被删除了,退出整个程序后目录锁定才会被解除。