2012-05-22 3 views
3

У меня есть приложение, которое должно контролировать основной диск для изменения файла через ReadDirectoryChangesW. Однако, когда UAC включен, он не работает.Как я могу обойти UAC при использовании ReadDirectoryChanges?

Все вызовы Windows API успешно завершены, но я не уведомлен о каких-либо изменениях.

Я могу обойти это, индивидуально контролируя каждый каталог в корне, но это проблема, потому что это может привести к синему экрану, если слишком много каталогов.

Есть ли приемлемый способ обойти UAC и получать уведомления об изменении файла на всем основном диске?

Ниже приведены соответствующие и ReadDirectoryChangesW. В случае, если он не работает, 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); 

Интересно, что .NET System.IO.FileSystemWatcherделает работу правильно, и она использует те же функции и параметры, как я использую, но он ведет себя правильно.

+1

Он работает, если приложение поднято? –

+0

Нет, это не сработает, когда я запускаю его как администратор, а также не могу дать мне (как администратору) возможность записывать файлы в корень основного тома. –

+1

Как вы можете использовать BlueScreen компьютер из режима неавторизованного пользователя? Вы можете сделать лицо пользователя синим, если вы потребляете достаточное количество ресурсов, хотя ... – ixe013

ответ

1

Во-первых, это лучше всего для приложений, которые используют API ReadDirectoryChangesW для запуска повышенной работы, чтобы сделать файл манифеста для вашего приложения и установить requireAdministrator как уровень requestedExecutionLevel. Проверьте для справки here.

Попробуйте удалить FILE_SHARE_WRITE из CreateFile звонок, если вы используете.

Другой вариант - заставить вашу программу работать как услугу, я не уверен, насколько это применимо к вашим потребностям. Вы могли бы разместить код, как вы получаете дескриптор файла и что вы переходя к ReadDirectoryChangesW

+0

Есть ли разница между запуском приложения в качестве администратора с помощью «Запуск от имени администратора» и запрашивая повышенные привилегии в манифесте? Я пробовал с и без 'FILE_SHARE_WRITE', это не имеет никакого значения. Два вызова функций были добавлены. –

+0

Параметр манифеста гарантирует, что ваше приложение всегда будет работать с административными привилегиями без необходимости в чтобы запустить его как администратора. Вы также можете попробовать удалить FILE_SHARE_DELETE форму своего вызова CreateFile –

+0

И он не работает на вашем диске C, потому что его системный диск ... Вероятно, лучше всего запустить ваше приложение в качестве службы, если все остальные попытки не работают –

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); 
     } 
    } 
} 

Это работает также и для не- привилегированные процессы (как обычные пользовательские процессы).

+0

Это необязательно. Вам не нужно иметь привилегии SE_BACKUP_NAME, чтобы использовать FILE_FLAG_BACKUP_SEMANTICS, чтобы открыть дескриптор каталога. –

0

Вот несколько рабочих тестовых кодов для дальнейшего использования.

#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; 
} 
Смежные вопросы