Сборка по socket
Утилиты Windows

Управление файлами

Для создания нового или открытия существующего файла используется функция CreateFile. При использовании функции CreateFile необходимо указать, предполагается чтение или запись в файл или и то и другое. Также необходимо указать, необходимые действия в случае наличия файла на диске или его отсутствия (например, перезаписывать файл, если он существует и создавать новый, если – нет). Также функция CreateFile позволяет указать возможность разделения файла с другими приложениями (одновременного чтения/записи нескольких приложений в файл). Операционная система присваивает каждому открытому файлу уникальный идентификатор (дескриптор, file handle), который может быть использован при обращениях к файлу для записи, чтения и получения информации о файле. Дескриптор действителен до тех пор, пока файл не закрыт. Приложение может наследовать дескрипторы файлов от процесса, который его запустил (если дескрипторы наследуемые).

Функция CreateFile

Функция CreateFile среди прочих объектов позволяет обращаться к файлам и каналам (pipes). При обращении к каналам функция CreateFile позволяет создавать клиентское подключение к именованным каналам, находящимся в режиме ожидания подключения. Серверная часть канала создаётся функцией CreateNamedPipe. Одно приложение может создавать множество клиентских подключений к каналу, но к одному экземпляру канала может подключаться только одно приложение (Стоит отметить, что возможно существование нескольких экземпляров именованных каналов с одинаковыми именами). Функция создаёт указатель на новое устройство типа: Файл Канал mailslot (почтовый канал) комуникационный ресурс (например COM порт) дисковые устройства (только для Windows NT) консоли директории (открывает их) Все эти функции описаны в одном файле. Для С/С++ в хедере (заголовочный файл) winbase.h, для Delphi в модуле windows.pas. Чтобы использовать в своей программе эти функции, достаточно подключить их к своему проекту и вперед. Змечу, для тех кто кодит на С/С++ кроме winbase.h надо подключить еще windows.h. HANDLE CreateFile( LPCTSTR lpFileName, // Указатель на имя файла (устройства) DWORD dwDesiredAccess, //Параметры доступа DWORD dwShareMode, //Разделяемый доступ LPSECURITY_ATTRIBUTES lpSecurityAttributes, //безопасность DWORD dwCreationDistribution,// Описание DWORD dwFlagsAndAttributes, // Атрибуты файла HANDLE hTemplateFile // Файл шаблона Handle FileHandle; FileHandle=CreateFile("file1.txt",GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); CloseHandle(FileHandle); Параметры: lpFileName: литеральной константой, то следует поместить её в макрос TEXT() или поставить L перед открывающей кавычкой. Например, TEXT("C:\\tmp.txt") или L"C:\\tmp.txt" dwDesiredAccess: GENERIC_READ, GENERIC_WRITE и их объединение. При доступе к каналам следует учитывать режим создания канала сервером. Если сервер создал канал для записи, то клиент открывает его для чтения и наоборот. Если сервер создал канал для чтения и записи, то клиент может открыть его как для чтения, так и для записи. dwShareMode: 0 – приложение открывает файл для монопольного доступа. Последующие обращения на открытие данного файла будут безуспешными, пока данных дескриптор не будет закрыт. Для разделения доступа к файлу могут использоваться следующие ключи (один или вместе): FILE_SHARE_READ – разрешены лишь последующие операции открытия только на чтение. FILE_SHARE_WRITE – разрешены лишь последующие операции открытия только на запись. lpSecurityAttributes NULL – это значит, что дескриптор не может быть наследован (для наших приложений этого достаточно). dwCreationDisposition: одно из следующих заначений: Значение Пояснение CREATE_NEW Создаёт файл. Вызов заканчивается неудачей, если файл существует. CREATE_ALWAYS Создаёт новый файл. Если файл существует, то его содержимое и атрибуты будут стёрты. OPEN_EXISTING Открытие файла. Если файл не существует, то вызов закончится неудачей. OPEN_ALWAYS Открывает файл. Если файл не существует, то он будет создан. TRUNCATE_EXISTING Открывает файл, размер которого обнуляется. Файл должен открываться как минимум с режимом доступа GENERIC_WRITE. Если файл не существует, то вызов будет неудачен. dwFlagsAndAttributes: поведение при работе с файлами. Например, запись в файл без буферизации (FILE_FLAG_NO_BUFFERING и FILE_FLAG_WRITE_THROUGH); оптимизация для неупорядоченного доступа (FILE_FLAG_RANDOM_ACCESS); открытие для асинхронного ввода/вывода (FILE_FLAG_OVERLAPPED). FILE_ATTRIBUTE определены следующим образом:
#define FILE_ATTRIBUTE_READONLY0x00000001Файл или каталог только для чтения. Приложения могут читать этот файл, но не могут записать в него или удалить его. Что касается каталога, приложения не могут удалить его.
#define FILE_ATTRIBUTE_HIDDEN0x00000002Файл или каталог - скрытые. Они не включаются в обычный перечень файлов каталога.
#define FILE_ATTRIBUTE_SYSTEM0x00000004Файл или каталог - часть операционной системы или используются исключительно операционной системой.
#define FILE_ATTRIBUTE_DIRECTORY0x00000010Дескриптор идентифицирует каталог.
#define FILE_ATTRIBUTE_ARCHIVE0x00000020Файл или каталог - архивный файл или каталог. Приложения используют этот атрибут, чтобы отметить файлы для резервного копирования или перемещения.
#define FILE_ATTRIBUTE_DEVICE0x00000040
#define FILE_ATTRIBUTE_NORMAL0x00000080Файл или каталог не имеют других установленных атрибутов. Этот атрибут допустим только в том случае, если используется как единственный.
#define FILE_ATTRIBUTE_TEMPORARY0x00000100Файл используется для временного хранения. Файловые системы пытаются держать все данные в памяти для более быстрого доступа вместо того, чтобы сбрасывать данные назад на запоминающее устройство большой емкости. Временный файл должен удаляться приложением, как только он больше не нужен.
#define FILE_ATTRIBUTE_SPARSE_FILE0x00000200Файл - разреженный файл.
#define FILE_ATTRIBUTE_REPARSE_POINT0x00000400Файл имеет связанную точку монтирования.
#define FILE_ATTRIBUTE_COMPRESSED0x00000800Файл или каталог - сжатые. Для файла, это означает, что все данные в файле сжимаются. Для каталога, это означает, что сжатие - значение по умолчанию для недавно созданных файлов и подкаталогов.
#define FILE_ATTRIBUTE_OFFLINE0x00001000Данные файла доступны не сразу. Этот атрибут указывает, что данные файла были физически перемещены, чтобы сохраняться автономно. Этот атрибут используется программами Удаленного хранилища, иерархического управления памятью. Приложения не должны произвольно изменять этот атрибут.
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED0x00002000
#define FILE_ATTRIBUTE_ENCRYPTED0x00004000Файл или каталог - зашифрованные. Для файла, это означает, что все данные в файле зашифрованы. Для каталога, это означает, что шифрование - значение по умолчанию для недавно созданных файлов и подкаталогов.
Возвращаемое значение: Если вызов успешен, возвращается дескриптор открытого файла. Если вызов неудачен, возвращается константа INVALID_HANDLE_VALUE. Код ошибки можно получить вызовом функции GetLastError. Подробную информацию об ошибке (по её коду) можно получить вызовом функции FormatMessage.

Функция CopyFile

BOOL CopyFile( LPCTSTR lpExistingFileName, // имя существующего файла LPCTSTR lpNewFileName, // имя нового файла BOOL bFailIfExists // действие, если файл существует TRUE – ошибка // FALSE - перезаписывать ); В случае успеха возвращается ненулевое значение. Для переименования файлов и директорий используется функция MoveFile: BOOL MoveFile( LPCTSTR lpExistingFileName, // имя файла LPCTSTR lpNewFileName // новое имя файла ); В случае успеха возвращается ненулевое значение.

Функция DeleteFile

Для удаления существующих файлов используется функция DeleteFile: BOOL DeleteFile( LPCTSTR lpFileName // имя удаляемого файла ); В случае успеха возвращается ненулевое значение.

Чтение/запись в файл

Каждый открытый файл имеет файловый указатель (file pointer), который указывает позицию следующего файла, который будет записан/прочтен. При открытии файла его файловый указатель перемещается на начало файла. После прочтения/записи очередного файла система перемещает файловый указатель. Файловый указатель можно перемещать, используя функцию SetFilePointer. Для чтения/записи в файл используются функции ReadFile и WriteFile, при этом необходимо, чтобы файл был открыт на чтение и на запись соответственно.

Функция ReadFile

Функция ReadFile читает из файла указанное количество символов, начиная с позиции, обозначенной файловым указателем. При синхронном (в противоположность асинхронному) чтении файловый указатель сдвигается на фактически прочитанное количество байт. BOOL ReadFile( HANDLE hFile, // дескриптор файла LPVOID lpBuffer, // буфер данных DWORD nNumberOfBytesToRead, // количество байт для прочтения LPDWORD lpNumberOfBytesRead, // количество фактически прочитанных байт LPOVERLAPPED lpOverlapped // указатель на структуру, используемую при // асинхронном чтении ); Параметры: hFile: lpBuffer: nNumberOfBytesToRead: lpNumberOfBytesRead: lpOverlapped: Возвращаемое значение: Если выполнение функции произошло успешно, то возвращается ненулевое значение. Если возвращено ненулевое значение, но прочитано 0 байт, значит файловый указатель стоял на конце файла перед операцией чтения.

Функция WriteFile

Функция WriteFile записывает в файл данные, начиная с позиции, обозначенной файловым указателем. При синхронной (в противоположность асинхронному) записи файловый указатель сдвигается на фактически записанное количество байт. BOOL WriteFile( HANDLE hFile, // дескриптор файла LPCVOID lpBuffer, // буфер данных DWORD nNumberOfBytesToWrite, // количество байт для записи LPDWORD lpNumberOfBytesWritten,// количество фактически записанных байт LPOVERLAPPED lpOverlapped // указатель на структуру, используемую при // асинхронном чтении ); Параметры: hFile: lpBuffer: nNumberOfBytesToWrite: lpNumberOfBytesWritten: lpOverlapped: Возвращаемое значение: Если выполнение функции произошло успешно, то возвращается ненулевое значение.

Блокировка файлов

Т.к. система позволяет более чем одному приложению открывать файл и писать в него, приложения не должны одновременно писать в одну область файла. Эта проблема может быть решена путем временного блокирования части файла. Функция LockFile позволяет приложению получить в монопольное пользования определённое количество байт в файле. Отрезок заблокированных байт может выходить за текущий конец файла. Все попытки сторонних приложений обратиться к заблокированному участку файла потерпят неудачу. Приложение может файл с помощью функции UnlockFile.

Функция LockFile

BOOL LockFile( HANDLE hFile, // дескриптор файла DWORD dwFileOffsetLow, // младшее слово смещения начала отрезка DWORD dwFileOffsetHigh, // старшее слово смещения начала отрезка DWORD nNumberOfBytesToLockLow, // младшее слово длины отрезка DWORD nNumberOfBytesToLockHigh // старшее слово длины отрезка ); Параметры: hFile: dwFileOffsetLow: dwFileOffsetHigh: более чем 232 байт. nNumberOfBytesToLockLow: nNumberOfBytesToLockHigh: Возвращаемое значение: Если выполнение функции произошло успешно, то возвращается ненулевое значение. Блокирование предоставляет процессу монопольный доступ к отрезку файла. Файловые блокировки не наследуются. Остальные процессы не могут ни читать, ни писать в заблокированную часть файла.

Функция UnlockFile

Функция UnlockFile позволяет разблокировать участок файла, ранее заблокированный функцией LockFile. BOOL UnlockFile( HANDLE hFile, // дескриптор файла DWORD dwFileOffsetLow, // младшее слово смещения начала отрезка DWORD dwFileOffsetHigh, // старшее слово смещения начала отрезка DWORD nNumberOfBytesToUnlockLow, // младшее слово длины отрезка DWORD nNumberOfBytesToUnlockHigh // старшее слово длины отрезка ); Параметры данной функции аналогичны параметрам функции LockFile. Возвращаемое значение: Если выполнение функции произошло успешно, то возвращается ненулевое значение. Отрезок файла, который разблокируется функцией UnlockFile должен в точности соответствовать отрезку, заблокированному функцией LockFile. Например, две соседних части файла не могут быть заблокированы по отдельности, а разблокированы как единое целое. Процесс не должен завершать выполнение, имея заблокированные части файлов. Файловый дескриптор, для которого есть заблокированные отрезки, не должен закрываться.

Функция CloseHandle

Для оптимального использования ресурсов операционной системы приложение должно закрывать ненужные файлы с помощью функции CloseHandle. Файлы, открытые на момент завершения приложения, закрываются автоматически. BOOL CloseHandle( HANDLE hObject // Дескриптор объекта (файла, канала и пр.) ); Возвращаемое значение: Если выполнение функции произошло успешно, то возвращается ненулевое значение.

Функция FindFirstFile

Данная функция запускает поиск в указанной директории. Функция возвращает указатель на найденный файл, если нет то возврат будет типа ERROR_NO_MORE_FILES. C/C++ HANDLE FindFirstFile( LPCTSTR lpFileName, // Строка содержащая путь для поиска файлов. LPWIN32_FIND_DATA lpFindFileData // Информация о найденном файле ); lpFileName - строка содержащая путь для поиска файла. Эта строка может указывать наконкретный файл типа 'c:\filename.txt' или может хранить шаблон 'c:\*.*'. Если указывать шаблон, то это даёт возможность перечислить все файлы удовлетворяющие шаблону. lpFindFileData - структура WIN32_FIND_DATA, в которую будет записана инфа о найденом файле. Структура WIN32_FIND_DATA описывает файл, найденный функцией FindFirstFile, FindFirstFileEx или FindNextFile. Синтаксис typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; // Атрибуты файла FILETIME ftCreationTime; // Время создания FILETIME ftLastAccessTime; //Время последнего доступа FILETIME ftLastWriteTime; //Время последней записи в файл DWORD nFileSizeHigh; //Верхний байт размера файла DWORD nFileSizeLow; //Нижний байт размера файла DWORD dwReserved0; //Зарезервировано DWORD dwReserved1; //Зарезервировано TCHAR cFileName[ MAX_PATH ]; //Имя файла TCHAR cAlternateFileName[ 14 ]; //Имя файла для отображения в DOS (8:3) } WIN32_FIND_DATA, *PWIN32_FIND_DATA; Члены структуры dwFileAttributes - Атрибуты искомого файла. Этот член структуры может состоять из одного или нескольких нижеследующих значений. ftCreationTime - Структура FILETIME, которая устанавливается, когда файл или каталог создавались. Если лежащая в основе файловая система не поддерживает время создания, этот член структуры равняется нулю. ftLastAccessTime - Структура FILETIME. Для файла, структура устанавливает, когда последний раз читали из или писали в него или, в случае, если он исполняемый файл, запускали его. Для каталога, структура определяет, когда создавался каталог. Если лежащая в основе файловая система не поддерживает время последнего обращения к файлу, член структуры ftLastAccessTime равняется нулю. В файловой системе FAT, указанная дата и файлов и каталогов должен быть исправляет, но время дня будет всегда устанавливаться в полночь. ftLastWriteTime - Структура FILETIME. Для файла, структура устанавливает, когда последний раз была запись в файл, он обрезался или переписывался (например функциями WriteFile или SetEndOfFile). Эта дата и время не обновляются тогда, когда атрибуты файла или дескрипторы безопасности изменяются. Для каталога, структура определяет, когда каталог создавался. Если лежащая в основе файловая система не поддерживает последнее время записи, этот член структуры равняется нулю. nFileSizeHigh - Старшее двойное слово (DWORD) значения размера файла, в байтах. Это значение равняется нулю, если размер файла не больше, чем определяет его MAXDWORD. Размер файла равен (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow nFileSizeLow - Младшее двойное слово (DWORD) значения размера файла, в байтах. dwReserved0 - Если член структуры dwFileAttributes включает атрибут FILE_ATTRIBUTE_REPARSE_POINT, этот член структуры устанавливает тэг монтирования. В противном случае, это значение не определяется и не должно использоваться. dwReserved1 - Зарезервированный для будущего использования. cFileName - Символьная строка с нулем в конце, которая устанавливает имя файла. cAlternateFileName - Символьная строка с нулем в конце, которая устанавливает альтернативное имя файла. Это имя является в классическом формате имени файла 8.3 (имя файла.расширение). Структура FILETIME Структура FILETIME - 64-битовое значение, представляющее число интервалов по 100 наносекунд с 1 января 1601 (универсальное глобальное время (UTC)). Синтаксис typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME, *PFILETIME; Члены структуры dwLowDateTime - Младшая часть файлового времени. dwHighDateTime - Старшая часть файлового времени. Замечания Чтобы преобразовать структуру FILETIME во время, которое легко показать на экране для пользователя, используйте функцию FileTimeToSystemTime. Не рекомендуется, чтобы Вы добавляли и вычитали значения из структуры FILETIME, чтобы получить относительное время. Вместо этого Вы должны: Скопировать получающуюся структуру FILETIME в структуру ULARGE_INTEGER. Используйте обычную 64-битовую арифметическую операцию со значением ULARGE_INTEGER. То есть, Вы должны скопировать нижнюю и старшую части файлового времени в структуру ULARGE_INTEGER, выполнить 64-битовую арифметическую операцию в члене структуры QuadPart и скопировать члены структуры LowPart и HighPart в структуру FILETIME. Не приводите указатель на структуру FILETIME, или на ULARGE_INTEGER*, или на значение __ int64* , потому что это может вызвать ошибки выравнивания в 64-битовом Windows. Не все файловые системы могут сделать запись создания и времени последнего доступа к файлу, и не все файловые системы делают запись их в той же самой манере. Например, в NT FAT у времени создания разрешающая способность 10 миллисекунд, у времени записи разрешающая способность 2 секунды, а у времени доступа разрешающая способность 1 день (фактически дата доступа. На NTFS у времени доступа разрешающая способность 1 час. Поэтому, функция GetFileTime, возможно, не сможет возвратить ту же самую информацию о файловом времени, при использовании функции SetFileTime. Кроме того, FAT делает запись времени на диске в формате местного времени. Однако, NTFS делает запись времени на диске в универсальном глобальном времени (UTC). Для получения дополнительной информации, см. статью Файловое время. Замечания Если файл имеет длинное имя, полное название появляется в поле cFileName, а обрезанная версия имени формата 8.3 появляется в поле cAlternateFileName. В противном случае, член структуры cAlternateFileName пустой. Как альтернативу, Вы можете использовать функцию GetShortPathName, чтобы найти версию имени файла формата 8.3. Не все файловые системы могут фиксировать время создания и последнего доступа, и не все файловые системы фиксируют это одним и тем же способом. Например, в файловой системе FAT, время создания имеет дискретность 10 миллисекунд, время записи имеет дискретность 2 секунды, а время доступа имеет дискретность 1 день (фактическую дату доступа). В NTFS, время доступа имеет дискретность 1 час. Для получения дополнительной информации, см. Временные характеристики файла. Атрибутами файла может быть комбинация из флагов: FILE_ATTRIBUTE_ARCHIVE - архивный FILE_ATTRIBUTE_COMPRESSED - сжатый FILE_ATTRIBUTE_HIDDEN - скрытый FILE_ATTRIBUTE_NORMAL - нормальный FILE_ATTRIBUTE_OFFLINE - данные файла недоступны FILE_ATTRIBUTE_READONLY - только для чтения FILE_ATTRIBUTE_SYSTEM - системный FILE_ATTRIBUTE_TEMPORARY - временный Размер файла разложен на два байта. Чтоб получить полный размер файла нужно выполнить действие (FInfo.nFileSizeHigh * MAXDWORD) + FInfo.nFileSizeLow. Это не самый эффективный (эффективнее сдвигать), но самый понятный способ. Теперь поглядим рабочий пример: { WIN32_FIND_DATA sss; HANDLE f; f = FindFirstFile("C:\*.*", &sss); ... FindClose(f); }

Функция FindNextFile

Данная функция продолжает поиск начатый функцией FindFirstFile(). Если очередной файл найден, то функция возвращает значение true, иначе возврат будет типа ERROR_NO_MORE_FILES. C/C++ BOOL FindNextFile( HANDLE hFindFile, // Указатель на файл из предыдущего поиска LPWIN32_FIND_DATA lpFindFileData // Информация об очередном найденном файле ); Со вторым параметром всё ясно, из описания функции FindFirstFile. А вот первый - это указатель на файл из предыдущего поиска. Он нужен, чтобы функция FindNextFile знала на каком файле был остановлен поиск и какой надо найти следующим. Теперь поглядим рабочий пример: { WIN32_FIND_DATA sss; HANDLE f; f = FindFirstFile("C:\*.*", &sss); if(f != INVALID_HANDLE_VALUE) do{ ... }while(FindNextFile(f,&sss)); FindClose(f); }

Функция GetFileSize

Данная функция определяет размер файла, на который ссылается переданный указатель. Если размер файла меньше 4 Гб, то функция возвращает размер файла. Если размер файла больше 4Гб, то размер файла записан во втором парамметре. В случае возникновения исключения, будет возвращено значение типа INVALID_FILE_SIZE. C/C++ DWORD GetFileSize( HANDLE hFile, // Указатель на файл LPDWORD lpFileSizeHigh // старший байт размера файла, в качестве // этого парамметра можно указать NULL ); Теперь поглядим рабочий пример: C/C++ { DWORD FileSize; Handle f; ... FileSize=GetFileSize(f,NULL); ... }

Функция SetFilePointer

Допустим, у нас имеется файл, в котором информация записана не подряд одной строкой, а через определенные промежутки. Считывать информацию в этом случае придется, используя такую возможность, как позиционирование в файле, то есть можно указать, с какого места файла будут считываться данные из файла. Осуществить вышеописанные действия позволяет функция SetFilePointer(). Она описана следующим образом: DWORD SetFilePointer (HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod ) hFile - хендл уже открытого файла lDistanceToMove - число, отвечающее, на сколько будет совершено перемещение позиции в файле, с которой впоследствии будет производиться чтение данных. lpDistanceToMoveHigh напрямую связан со вторым. Обратите внимание на их типы: в первом случае это LONG, а во втором - PLONG, то есть указатель. Исходя из этого, можно сказать, что при помощи второго параметра можно передвинуть позицию в файле только на 2^32 (4 байта занимает переменная типа LONG), то есть получается, что это максимальный размер файла, с которым возможно работать. Но в некоторых случая требуется работать с файлами большего размера, для этого-то и предназначен третий параметр, с помощью которого можно изменить позицию в файле на 2^64. Необходимость работать со столь большими файлами возникает очень редко, и поэтому подробно разбирать примеры использования функции SetFilePointer с этим параметром является нерациональным. При вызове функции следует просто передать в этот параметр NULL. Последний аргумент dwMoveMethod указывает, откуда будет начат отсчет, принимает значения: FILE_BEGIN - начало файла FILE_CURRENT - с текущего значения FILE_END - с конца файла. Нужно учесть, что число, на которое следует сдвинуть позицию в файле, может быть отрицательным, это удобно, если отсчет ведется от конца файла. В случае удачного завершения работы функция возвращает новую позицию в файле.

Функция SetEndOfFile

Функция SetEndOfFile(), позволяет указать, где следует установить конец файла. Прототип этой функции: BOOL SetEndOfFile (HANDLE hFile) Функция содержит всего один параметр, а именно хендл открытого файла. Функция возвращает истину, если завершилась удачно, или ложь в случае возникновении ошибки. Концом файла становится то место, в котором находится текущая позиция, установленная функцией SetFilePointer ().

Функция GetLogicalDrives()

DWORD WINAPI GetLogicalDrives(void); Процедура GetLogicalDrives возвращает битовую маску, по которой можно судить, какие диски есть в системе. Например, если 0-ой бит установлен в единицу, значит диск «A:» есть, иначе его нет. Аналогично, 1-ый бит соответствует диску «B:», 2-ой — диску «C:», и так далее до 25-го бита.

Пример

Следующая программа пишет в файл counter.dat количество собственных запусков. Первые пять запусков ничем не примечательны. На шестой и последующие запуски программа сообщает, что у нее истек триал и просит приобрести полную версию. #include #define MAX_TRIAL_RUNS 5 const TCHAR szCounterFileName[] = L"counter.dat"; const TCHAR szMsgTmpl[] = L"Вы запустили программу в %d-й раз. %s."; const TCHAR szCheckOk[] = L"Все в порядке, продолжайте работу"; const TCHAR szCheckFailed[] = L"Триал истек, купите полную версию"; DWORD ReadCounter() { DWORD dwCounter, dwTemp; HANDLE hFile = CreateFile(szCounterFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE == hFile) { return 1; } ReadFile(hFile, &dwCounter, sizeof(dwCounter), &dwTemp, NULL); if(sizeof(dwCounter) != dwTemp) { CloseHandle(hFile); return 1; } CloseHandle(hFile); return dwCounter; } VOID WriteCounter(DWORD dwCounter) { DWORD dwTemp; HANDLE hFile = CreateFile(szCounterFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE == hFile) { return; } WriteFile(hFile, &dwCounter, sizeof(dwCounter), &dwTemp, NULL); CloseHandle(hFile); } int main() { TCHAR szMsg[256]; DWORD dwCounter = ReadCounter(); LPCWSTR lpCheckResult = dwCounter > MAX_TRIAL_RUNS ? szCheckFailed : szCheckOk; wsprintf(szMsg, szMsgTmpl, dwCounter, lpCheckResult); MessageBox(0, szMsg, L"Сообщение", 0); if(dwCounter <= MAX_TRIAL_RUNS) { WriteCounter(dwCounter+1); } ExitProcess(0); }