CreateFile
на самом деле может сделать гораздо больше, чем просто открыть файл. CreateFile2
был создан, чтобы ограничить «поверхностную область» функции только функциями, разрешенными для приложений UWP, и поскольку инструмент WACK не может действительно отличить «хорошее» использование от «плохого» использования функции импорта, только то, что он вообще используется.
Типичный шаблон, который я использую в своих библиотеках C++, выглядит следующим образом. Я использую шаблон RAII для поддержки дескриптора файла при использовании обработки исключений C++ (в дополнение просто быть хорошим современной практикой написания кода на C++):
#include <assert.h>
#include <memory>
struct handle_closer
{ void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) CloseHandle(h); } };
using ScopedHandle = std::unique_ptr<void, handle_closer>;
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
Причина, по которой у меня есть safe_handle
, заключается в том, что CreateFile
и CreateFile2
определены для возврата INVALID_HANDLE_VALUE
(-1) вместо возврата 0 в случае ошибки. Большинство других функций Win32, возвращающих дескрипторы, возвращают 0 в случае сбоя, и я подтвердил, что не бывает случаев, когда '0' является допустимым дескриптором Win32.
Для чтения я использую:
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(
CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));
#else
ScopedHandle hFile(safe_handle(
CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
#endif
if (!hFile)
// Error
Важно использовать FILE_SHARE_READ
вместо 0 для параметра dwShareMode
для чтения. Приложения UWP не имеют эксклюзивного доступа для чтения к существующим файлам, поэтому вызовы завершатся сбоем, если вы используете «эксклюзивный» режим общего доступа (т. е. 0).
И для записи файла:
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(
CreateFile2(szFile, GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, nullptr)));
#else
ScopedHandle hFile(safe_handle(
CreateFileW(szFile, GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, 0, nullptr)));
#endif
if (!hFile)
// Error!
Для записи я запрашиваю разрешение DELETE
, потому что я использую SetFileInformationByHandle
с FILE_DISPOSITION_INFO
для очистки в случае сбоя процесса вывода файла. См. scoped.h.
См. методы кодирования двойного назначения для игр для получения дополнительной информации.
27.03.2018