У меня есть несколько процессов, которые пытаются читать и записывать один и тот же файл. Я хочу, чтобы каждый из них блокировал файл, чтобы только один из них обращался к нему за раз.
Я попробовал это (отредактируйте: на этот раз это полный тестовый код):
#include "stdafx.h"
#include "Windows.h"
bool test()
{
const char* path = "test.txt";
HANDLE hFile = CreateFileA(path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("ERROR: Cannot open file %s\n", path);
return false;
}
// Lock the file
{
OVERLAPPED overlapped = {0};
BOOL res = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, ~0, &overlapped);
if (!res)
{
printf("ERROR: Cannot lock file %s\n", path);
return false;
}
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize > 0)
{
char* content = new char[fileSize+1];
// Read the file
BOOL res = ReadFile(hFile, content, fileSize, NULL, NULL);
if (!res)
{
printf("ERROR: Cannot read file %s\n", path);
}
delete[] content;
}
const char* newContent = "bla";
int newContentSize = 3;
// Write the file
BOOL res = WriteFile(hFile, newContent, newContentSize, NULL, NULL);
if (!res)
{
//int err = GetLastError();
printf("ERROR: Cannot write to file\n");
}
// Unlock the file
{
OVERLAPPED overlapped = {0};
UnlockFileEx(hFile, 0, ~0, ~0, &overlapped);
}
CloseHandle(hFile);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool res = test();
return 0;
}
Это отлично работает на моем компьютере, который имеет Windows 8. Но на компьютере моего коллеги, который имеет Windows 7, он сбой. В частности, всегда возникают сбои в ReadFile и WriteFile.
Обратите внимание, что он никогда не входит в коды кода с ошибкой printfs. Этот код не вызывает ошибки, кроме записи в местоположении 0x00000000 в ReadFile (при запуске в Windows 7).
Мы также попытались передать перекрываемую структуру на вызовы ReadFile и WriteFile. Он предотвращает крах, но блокировка больше не работает, файл все скремблирован (не с этим тестовым кодом, с реальным кодом).
Что я делаю не так?
Похоже, ваша проблема:
Параметр lpNumberOfBytesRead [out, optional] имеет значение null в вашем вызове.
Этот параметр может быть NULL, только если параметр lpOverlapped не равен NULL.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Вот ваша проблема:
Вам не хватает необходимого структурного члена и:
0
и ~0
и {0}
- все плохие коды, постоянные выражения, подобные этим, всегда будут давать неизведанные результаты - WINAPI не работает как libc, параметры не всегда сравниваются с константами, вместо этого они проверяются с помощью макросов и других препроцессоров, сами определения, передающие постоянные значения или инициализирующие структуры WINAPI с константами, часто приводят к таким ошибкам.
После нескольких лет экспериментов я обнаружил, что есть только один верный способ избежать их, я буду выражать его в исправленном коде:
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent( ........... ); // put valid parameters here!
UnlockFileEx(hFile, 0 /*"reserved"*/, ULONG_MAX, ULONG_MAX, &overlapped);
внимательно прочитайте это: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365716%28v=vs.85%29.aspx
NULL
вместо нуля - и выбросьте {0}
ReadFile
илиWriteFile
? Это не может разбиться на обоих.