3

を介してファイルの変更についてプライマリドライブを監視する必要があるアプリケーションがありますReadDirectoryChangesW。ただし、UACが有効になっている場合は、機能しません。

すべてのWindowsAPI呼び出しは成功しますが、変更は通知されません。

ルート内の各ディレクトリを個別に監視することでこれを回避できますが、ディレクトリが多すぎるとブルースクリーンが発生する可能性があるため、これは問題です。

UACを回避し、プライマリドライブ全体でファイル変更通知を受信するための許容可能な方法はありますか?

関連するCreateFileReadDirectoryChangesWは以下のとおりです。それが機能しない場合は、directoryC:\です。セカンダリドライブ(つまり、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 を使用して管理者特権で実行するアプリケーションがアプリのマニフェスト ファイルを作成し、レベルrequireAdministratorとして設定するのが最適です。参考までにこちらrequestedExecutionLevelをご覧ください。

使用している場合はFILE_SHARE_WRITE、通話から削除してみてください。CreateFile

別のオプションは、プログラムをサービスとして実行することです。これがニーズにどの程度当てはまるかわかりません。ファイルハンドルを取得する方法と何に渡すかに関するコードを投稿できます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 に答える