8

MSDN 说使用 ReadDirectoryChangesW 意味着调用进程具有备份和还原权限。

这是否意味着只有在管理员帐户下启动的进程才能正常工作?

我尝试了以下代码,以受限用户身份运行时无法启用所需的权限。

void enablePrivileges() 
{       
    enablePrivilege(SE_BACKUP_NAME);
    enablePrivilege(SE_RESTORE_NAME);
}

void enablePrivilege(LPCTSTR name) 
{       
    HANDLE hToken;    
    DWORD status;
    if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))  
    {        
        TOKEN_PRIVILEGES tp = { 1 };   
        if( ::LookupPrivilegeValue(NULL, name,  &tp.Privileges[0].Luid) )
        {
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            BOOL result = ::AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
            verify (result != FALSE);
            status = ::GetLastError();      
        }
        ::CloseHandle(hToken); 
    } 
}

难道我做错了什么?从非管理员用户帐户使用 ReadDirectoryChangesW 是否有任何解决方法?.NET 的 FileSystemWatcher 似乎可以做到这一点。谢谢!

更新:这是该类的完整代码:

  class DirectoryChangesWatcher
  {
  public:
   DirectoryChangesWatcher(wstring directory)
   {
    enablePrivileges();

    hDir = ::CreateFile(directory.c_str(), 
     FILE_LIST_DIRECTORY | FILE_FLAG_OVERLAPPED, 
     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
     FILE_FLAG_BACKUP_SEMANTICS, NULL);

    ensure (hDir != INVALID_HANDLE_VALUE, err::SystemException);

    ::ZeroMemory(&overlapped, sizeof(OVERLAPPED));
    overlapped.hEvent = dirChangedEvent.getHandle();  
   }

   ~DirectoryChangesWatcher() { ::CloseHandle(hDir); }

  public:
   Event& getEvent() { return dirChangedEvent; }

   FILE_NOTIFY_INFORMATION* getBuffer() { return buffer; }

  public:
   void startAsyncWatch()
   {
    DWORD bytesReturned;   

    const BOOL res = ::ReadDirectoryChangesW(
     hDir,                                  
     &buffer,                                    
     sizeof(buffer),                                
     TRUE,                                 
     FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE,
     &bytesReturned,              
     &overlapped,                          
     NULL);

    ensure(res != FALSE, err::SystemException);
   }

  private:
   void enablePrivileges() 
   {       
    enablePrivilege(SE_BACKUP_NAME);
    enablePrivilege(SE_RESTORE_NAME);
   }

   void enablePrivilege(LPCTSTR name) 
   {       
    HANDLE hToken;    
    DWORD status;
    if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))  
    {        
     TOKEN_PRIVILEGES tp = { 1 };   
     if( ::LookupPrivilegeValue(NULL, name,  &tp.Privileges[0].Luid) )
     {
      tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
      BOOL result = ::AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
      verify (result != FALSE);
      status = ::GetLastError();      
     }
     ::CloseHandle(hToken); 
    } 
   }

  private:
   HANDLE hDir;
   OVERLAPPED overlapped;
   Event dirChangedEvent;
   FILE_NOTIFY_INFORMATION buffer[1024];   
  };

 }

更新:好消息!事实证明,问题确实出在调用 CreateFile 中的 FILE_SHARE_WRITE 标志中。除非我是管理员,否则不会收到通知。当我删除此标志时,现在一切都在非管理员帐户上运行。

4

3 回答 3

5

我在ReadDirectoryChangesW不需要管理员权限的情况下使用过,至少在 Vista 上是这样。我认为您无需手动提升该过程即可在用户已经有权查看的文件夹上使用它。

查看您用于调用的实际代码会更有帮助ReadDirectoryChangesW,包括您如何创建传入的句柄。

于 2010-04-14T20:17:07.773 回答
4

我没有看到 MSDN 说您需要备份或恢复权限。它指示您CreateFile使用File_Flag_Backup_Semantics标志集进行调用,并且在该标志的描述中,MSDN 说

系统确保调用进程在进程具有权限SE_BACKUP_NAME时覆盖文件安全检查。SE_RESTORE_NAME

按照我的阅读方式,如果您拥有这些权限,那么系统将为您覆盖文件安全检查。因此,如果您没有这些权限,那么程序将继续受到通常有效的任何文件安全检查的约束。

于 2010-04-14T20:51:37.707 回答
2

亚历克斯,在您的CreateFile()电话中,您FILE_FLAG_OVERLAPPED处于错误的位置。它应该从第 2 个参数移到第 6 个参数。

于 2015-11-13T15:52:08.760 回答