3

我有一个应用程序需要通过ReadDirectoryChangesW. 但是,当 UAC 启用时,它不起作用。

所有 Windows API 调用都成功,但我没有收到任何更改的通知。

我可以通过单独监视根目录中的每个目录来解决此问题,但这是一个问题,因为如果目录太多,它可能会导致蓝屏。

是否有一种可接受的方法来绕过 UAC 并在整个主驱动器上接收文件更改通知?

相关的CreateFileReadDirectoryChangesW在下面。在它不起作用的情况下,directory是 C:\。如果我监视任何辅助驱动器(即 E:\、F:\、G:\),它会按预期工作。没有任何调用返回错误。

HANDLE fileHandle = CreateFileW(directory.c_str(), FILE_LIST_DIRECTORY, 
    FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 
    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);

BOOL success = ReadDirectoryChangesW(fileHandle, watched.buffer.data(),
    watched.buffer.size(), TRUE, 
    FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, 
    NULL, &watched.overlapped, NULL);

有趣的是,.NETSystem.IO.FileSystemWatcher 确实可以正常工作,它使用与我使用的完全相同的函数和参数,但它的行为正确。

4

3 回答 3

1

ReadDirectoryChangesW首先,使用API 运行提升的应用程序最好为您的应用程序创建一个清单文件并设置requireAdministratorrequestedExecutionLevel级别。在这里查看以供参考。

如果您正在使用它,请尝试FILE_SHARE_WRITECreateFile通话中删除。

另一种选择是让您的程序作为服务运行,我不确定这对您的需求有多适用。您可以发布一些关于如何获取文件句柄以及传递给什么的代码ReadDirectoryChangesW

于 2012-05-22T20:35:31.447 回答
1

这是一些工作测试代码,以供将来参考。

#include <Windows.h>

#include <stdio.h>

int main(int argc, char ** argv)
{
    HANDLE filehandle;
    BYTE buffer[65536];
    DWORD dw;
    FILE_NOTIFY_INFORMATION * fni;
    OVERLAPPED overlapped = {0};

    overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (overlapped.hEvent == NULL)
    {
        printf("CreateEvent: %u\n", GetLastError());
        return 1;
    }

    filehandle = CreateFile(L"C:\\", 
        FILE_LIST_DIRECTORY, 
        FILE_SHARE_READ | FILE_SHARE_DELETE, 
        NULL, 
        OPEN_EXISTING, 
        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 
        NULL);

    if (filehandle == INVALID_HANDLE_VALUE)
    {
        printf("CreateFile: %u\n", GetLastError());
        return 1;
    }

    for (;;)
    {
        if (!ReadDirectoryChangesW(filehandle, buffer, sizeof(buffer),
            TRUE, 
            FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, 
            NULL, &overlapped, NULL))
        {
            printf("ReadDirectoryChangesW: %u\n", GetLastError());
            return 1;
        }

        printf("Queued OK.\n");

        if (!GetOverlappedResult(filehandle, &overlapped, &dw, TRUE))
        {
            printf("GetOverlappedResult: %u\n", GetLastError());
            return 1;
        }

        printf("%u bytes read.\n", dw);

        fni = (FILE_NOTIFY_INFORMATION *)buffer;

        for (;;)
        {
            printf("Next entry offset = %u\n", fni->NextEntryOffset);
            printf("Action = %u\n", fni->Action);
            printf("File name = %.*ws\n", 
                                  fni->FileNameLength / 2, 
                                  fni->FileName);

            if (fni->NextEntryOffset == 0) break;

            fni = (FILE_NOTIFY_INFORMATION *)
                               (((BYTE *)fni) + fni->NextEntryOffset);
        }
    }

    printf("All done\n");
    return 0;
}
于 2012-05-23T21:59:12.480 回答
0

您可以像这样自己调整进程的权限:

// enable the required privileges for this process

LPCTSTR arPrivelegeNames[] = {  SE_BACKUP_NAME,
                                SE_RESTORE_NAME,
                                SE_CHANGE_NOTIFY_NAME
                             };

for (int i=0; i<(sizeof(arPrivelegeNames)/sizeof(LPCTSTR)); ++i)
{
    CAutoGeneralHandle hToken;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken.GetPointer()))
    {
        TOKEN_PRIVILEGES tp = { 1 };

        if (LookupPrivilegeValue(NULL, arPrivelegeNames[i],  &tp.Privileges[0].Luid))
        {
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

            AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
        }
    }
}

这也适用于非特权进程(又名普通用户进程)。

于 2012-05-23T13:51:12.053 回答