Я заметил, что запись в файл, его закрытие и перемещение в место назначения случайно завершаются неудачно в Vista. В частности, MoveFileEx () вернет ERROR_ACCESS_DENIED
без видимой причины. Это происходит по крайней мере в Vista SP1 (32 бит). Не бывает на XP SP3.
Нашел эту ветку в интернете примерно об одной и той же проблеме, без реальных решений. Пока что похоже, что ошибка вызвана поисковым индексатором Vista, см. Ниже.
Приведенного примера кода достаточно, чтобы воспроизвести проблему. Я также вставляю это здесь:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
bool test() {
unsigned char buf[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99
};
HANDLE h;
DWORD nbytes;
LPCTSTR fn_tmp = "aaa";
LPCTSTR fn = "bbb";
h = CreateFile(fn_tmp, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);
if (h == INVALID_HANDLE_VALUE) return 0;
if (!WriteFile(h, buf, sizeof buf, &nbytes, 0)) goto error;
if (!FlushFileBuffers(h)) goto error;
if (!CloseHandle(h)) goto error;
if (!MoveFileEx(fn_tmp, fn, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) {
printf("error=%d\n", GetLastError());
return 0;
}
return 1;
error:
CloseHandle(h);
return 0;
}
int main(int argc, char** argv) {
unsigned int i;
for (i = 0;; ++i) {
printf("*%u\n", i);
if (!test()) return 1;
}
return 0;
}
Создайте это как консольное приложение с Visual Studio. Правильным поведением будет бесконечный цикл, который печатает номера тестов. В Vista SP1 программа завершается после случайного числа итераций (обычно до 100 итераций).
Этого не происходит в Windows XP SP2. Там не работает антивирус вообще; и никаких других странных фоновых процессов (на компьютере установлена ванильная ОС + Visual Studio).
Редактировать : Копая дальше через Process Monitor (спасибо @sixlettervariables), я не вижу ничего особенно плохого. Каждая итерация теста приводит к 176 операциям на диске, большинство из которых происходит от SearchProtocolHost.exe (поисковый индексатор). Если служба индексирования поиска остановлена, ошибок не возникает, поэтому похоже, что это виновник.
Во время сбоя (когда приложение получает ERROR_ACCESS_DENIED
), SearchProtocolHost.exe имеет два файла CreateFile (s) для файла определения (bbb), открытых в режимах совместного использования для чтения / записи / удаления, поэтому все должно быть в порядке. За одним из открытий следует оппортунистическая блокировка (FSCTL_REQUEST_FILTER_OPLOCK
), может, в этом причина?
В любом случае, я обнаружил, что могу избежать этой проблемы, установив в файле флаги FILE_ATTRIBUTE_TEMPORARY
и FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
. Похоже, что FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
само по себе достаточно, но пометка файла как временного также значительно сокращает операции на диске, вызванные индексатором поиска.
Но это не реальное решение . Я имею в виду, что если приложение не может рассчитывать на то, что сможет создать файл и переименовать его, потому что какой-то поисковый индексатор Vista с ним не справляется, это просто безумие ! Должен ли он продолжать попытки? Кричать на пользователя (что очень нежелательно)? Делать что-нибудь еще?