【问题标题】:How to check if a file is being used by another application?如何检查文件是否正在被另一个应用程序使用?
【发布时间】:2015-06-30 12:05:57
【问题描述】:

我正在使用以下代码来检查文件是否正在被另一个应用程序使用:

HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
    MessageBox(NULL, "The file is in use", "Error", 0);
}

如果文件正被其他应用程序使用,则会显示消息框。但是,如果文件不存在,也会显示消息框!

那么我应该怎么做才能解决这个问题,我应该也检查文件是否存在(使用另一个函数),还是可以将CreateFile()的参数更改为仅在文件正在使用时返回INVALID_HANDLE_VALUE并且存在吗?

【问题讨论】:

  • 我认为方法是错误的,我不知道如何编写代码来解决它。但我几乎可以肯定文件上一定有某种锁,因此在尝试打开文件时需要检查锁而不是检查失败。另一方面,如果文件由于锁定而无法打开,那么您必须通过某种系统错误代码检查原因,也许是 errno 变量,但我不知道 WinAPI。
  • CreateFile 失败的原因有很多;因为文件不存在而失败应该不足为奇。您的方法存在根本缺陷。
  • 如果你打算以这种方式使用CreateFile(),至少要正确使用它。您需要请求对文件的独占访问权限,而不是只读访问权限(其他进程可能允许对其文件进行读取访问),然后如果失败,您需要使用GetLastError() 区分 ERROR_SHARING_VIOLATION(正在使用的文件)与 ERROR_FILE_NOT_FOUND 等。
  • @Remy: 因为dwShareMode 为零,该代码确实请求独占访问,不是吗? (文档没有说明共享模式受请求访问的影响。)
  • @HarryJohnston:很好,我看错了参数。是的,代码已经在请求对文件的独占访问权限。但是,我关于需要使用 GetLastError() 来区分不同错误情况的评论仍然有效。

标签: c winapi


【解决方案1】:

如果您想知道哪个进程打开了文件,请使用Restart Manager。该过程包括以下步骤(如 Raymond Chen 的博客条目How do I find out which process has a file open? 中所述):

  1. 创建重启管理器会话 (RmStartSession)。
  2. 向会话中添加文件资源 (RmRegisterResource)。
  3. 询问受该资源影响的所有进程的列表 (RmGetList)。
  4. 关闭会话 (RmEndSession)。


示例代码:
#include <Windows.h>
#include <RestartManager.h>
#pragma comment(lib, "Rstrtmgr.lib")

bool IsFileLocked( const wchar_t* PathName ) {
    bool isFileLocked = false;

    DWORD dwSession = 0x0;
    wchar_t szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 };
    if ( RmStartSession( &dwSession, 0x0, szSessionKey ) == ERROR_SUCCESS ) {
        if ( RmRegisterResources( dwSession, 1, &PathName,
                                  0, NULL, 0, NULL ) == ERROR_SUCCESS ) {
            DWORD dwReason = 0x0;
            UINT nProcInfoNeeded = 0;
            UINT nProcInfo = 0;
            if ( RmGetList( dwSession, &nProcInfoNeeded,
                            &nProcInfo, NULL, &dwReason ) == ERROR_MORE_DATA ) {
                isFileLocked = ( nProcInfoNeeded != 0 );
            }
        }
        RmEndSession( dwSession );
    }

    return isFileLocked;
}

【讨论】:

  • Windows 还有一个IFileIsInUse 接口,用于检测文件是否正在使用中。在 Vista 中引入了 RestartManager 和 IFileIsInUse
  • @RemyLebeau 从内存中,应用程序必须专门注册IFileInUse 才能检测到它,我猜大多数人不会。
  • @JonathanPotter:是的,这是一个可选功能。 Windows 资源管理器使用IFileIsInUse 检测正在使用的文件,当没有找到给定文件的IFileIsInUse 时回退到NtQuerySystemInformation,最后根据这篇博客:Did you know? Windows 7 Cool feature
【解决方案2】:

您需要使用GetLastError() 才能知道CreateFile() 失败的原因,例如:

// this is requesting exclusive access to the file, so it will
// fail if the file is already open for any reason. That condition
// is detected by a sharing violation error due to conflicting
// sharing rights...

HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
    switch (GetLastError())
    {
        case ERROR_PATH_NOT_FOUND:
        case ERROR_FILE_NOT_FOUND:
            MessageBox(NULL, "The file does not exist", "Error", 0);
            break;

        case ERROR_SHARING_VIOLATION:
            MessageBox(NULL, "The file is in use", "Error", 0);
            break;

        //...

        default:
            MessageBox(NULL, "Error opening the file", "Error", 0);
            break;
    }
}
else
{
    // the file exists and was not in use.
    // don't forget to close the handle...
    CloseHandle(fh);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-22
    • 2010-11-06
    • 2014-07-12
    • 1970-01-01
    • 2013-09-21
    • 2014-03-26
    相关资源
    最近更新 更多