Categories: C/C++

winapi-files/

Из предыдущих постов, посвященных WinAPI, мы научились настраивать Visual Studio и узнали, как в нем писать простые консольные приложения . Следующим маленьким шажком в изучении WinAPI будет освоение работы с файлами.

Для этого нелегкого дела нам понадобятся следующие процедуры:

CreateFile ( szName , dwAccess , dwShareMode , lpSecurityAttributes ,
dwCreationDisposition , dwFlags , hTemplateFile ) ;

В Windows для того, чтобы открыть или создать файл, нужно вызвать процедуру, имеющую целых семь аргументов. К счастью, большинство из них приходится использовать крайне редко. Аргумент szName задает имя файла, а dwAccess — желаемый доступ к файлу, обычно это GENERIC_READ, GENERIC_WRITE или оба значения, объединенные логическим или. Параметр dwShareMode определяет, что могут делать с файлом другие процессы, пока мы с ним работаем. Возможные значения — FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE и их комбинации, однако часто этот параметр просто устанавливают в ноль. Параметр dwCreationDisposition определяет, как именно мы хотим открыть файл, может быть, например, CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING, OPEN_ALWAYS. О семантике этого хозяйства нетрудно догадаться самостоятельно. С помощью dwFlags можно указать дополнительные свойства файла, например, хранить ли его в зашифрованном или сжатом виде, или сказать, что файл является скрытым, временным или системным. Обычно сюда передают FILE_ATTRIBUTE_NORMAL. Наконец, про lpSecurityAttributes и hTemplateFile сейчас знать не нужно, сюда можно смело передавать NULL.

В случае успешного создания или открытия файла, процедура CreateFile возвращает его хэндл. В случае ошибки возвращается специальное значение INVALID_HANDLE_VALUE. Узнать подробности об ошибке можно с помощью GetLastError .

ReadFile ( hFile , lpBuff , dwBuffSize , & dwCount , NULL ) ;

Чтение из файла в буфер lpBuff размером dwBuffSize. В переменную dwCount записывается реальное количество прочитанных байт. Последний опциональный аргумент называется lpOverlapped и о нем сейчас знать не нужно.

WriteFile ( hFile , lpBuff , dwBuffSize , & dwCount , NULL ) ;

Аргументы и семантика процедуры WriteFile полностью аналогичны ReadFile .

CloseHandle ( hFile ) ;

Файловые дескрипторы закрываются с помощью CloseHandle . На самом деле, эта процедура используется не только для работы с файлами, так что мы еще не единожды с нею встретимся.

Посмотрим теперь на все это хозяйство в действии. Следующая программа пишет в файл counter.dat количество собственных запусков. Первые пять запусков ничем не примечательны. На шестой и последующие запуски программа сообщает, что у нее истек триал и просит приобрести полную версию.

#include <windows.h>

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

Как обычно, программа также успешно компилируется при помощи MinGW и запускается под Wine.

В качестве домашнего задания можете попробовать модифицировать программу так, чтобы она выводила время, когда производились все ее запуски. Для этого вам понадобятся процедуры GetLocalTime , SetFilePointer и GetFileSizeEx . Если это задание покажется вам слишком простым, попробуйте найти информацию о том, как при помощи процедур, упомянутых в этой заметке, (1) написать консольное приложение и (2) открыть диск C: на чтение, словно он является обычным файлом.

Если у вас есть дополнения или возникли вопросы, смелее пишите комментарии, не стесняйтесь!

Дополнение: Рекурсивный поиск файлов с использованием WinAPI

admin

Share
Published by
admin
Tags: C/C++

Recent Posts

vim-commands/

Самое главное — побороть боязнь белого листа. Я всегда говорю это себе, когда нужно начать…

1 месяц ago

firefox-thunderbird-en-ru-dict/

По не вполне ясным причинам, Firefox умеет проверять орфографию либо только в русских, либо только…

1 месяц ago

perl-hacks/

Около месяца собирал разные «хаки» на языке программирования Perl. Эта подборка наглядно демонстрирует, как в…

1 месяц ago

perl-cy-check/

C недавних пор я стал увлекаться SEO. Порой передо мной встает задача быстро проверить индекс…

1 месяц ago

which-cms-perl/

Недавно написал несколько скриптов, позволяющих автоматически определять, какая CMS (Content Management System, система управления контентом)…

1 месяц ago

smtp-descr/

Я так подозреваю, что среди вас найдется те, кто скажет, что этот пост боян и…

1 месяц ago