Файловая система
Работа с файлами, каталогами и томами в Windows и Win32 API. Функции GetWindowsDirectory и GetSystemDirectory. Примеры работы с томами. Получение и изменение атрибутов файлов. Описание минимального набора базовых функций Windows. Чтение и запись файлов.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | лекция |
Язык | русский |
Дата добавления | 24.06.2009 |
Размер файла | 62,7 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Кроме того, SCSI диск, доступный через ASPI, был распознан как RAM DISK.
Среда Windows 95, 16ти разрядное приложение:
******** GET VOLUME INFORMATION ********
Root: A:\ type=REMOVABLE volume='' ***** NO VOLUME INFORMATION!
Root: C:\ type=FIXED volume='' serial=00000000
maximal component length=12 cluster=16384 total=822272K free=70208K
file system ='' flags=CASE_PRESERVED
Root: D:\ type=FIXED volume='' serial=00000000
maximal component length=12 cluster=32768 total=1065792K free=45408K
file system ='' flags=CASE_PRESERVED
Root: E:\ type=REMOTE volume='' ***** NO VOLUME INFORMATION!
******** READ DOS DEVICES MAP ********
NOTE: DefineDosDevice() is not implemented!
Уже неплохо -- результаты совпадают с тем, что было получено для 16ти разрядного приложения в среде Windows 3.11, реакция на получение информации об отсутствующем диске такая-же -- сообщение об ошибке.
Среда Windows 95, 32х разрядное приложение:
******** GET VOLUME INFORMATION ********
Root: a:\ type=REMOVABLE volume='' ***** NO VOLUME INFORMATION!
Root: c:\ type=FIXED volume='BOOTABLE' serial=0E3219D9
maximal component length=255 cluster=16384 total=822272K free=69696K
file system ='FAT' flags=CASE_PRESERVED UNICODE
Root: d:\ type=FIXED volume='SCSI_VOL' serial=025511DA
maximal component length=255 cluster=32768 total=1065792K free=45408K
file system ='FAT' flags=CASE_PRESERVED UNICODE
Root: e:\ type=CD-ROM volume='' ***** NO VOLUME INFORMATION!
******** READ DOS DEVICES MAP ********
NOTE: DefineDosDevice() is not implemented!
Пожалуй, самый приличный результат. Все срабатывает корректно и без сообщений о критических ошибках, даже если не использовать функцию SetErrorMode. Типы дисков и файловые системы определяются корректно.
Среда Windows NT, 16ти разрядное приложение:
******** GET VOLUME INFORMATION ********
Root: A:\ type=REMOVABLE volume='' ***** NO VOLUME INFORMATION!
Root: C:\ type=FIXED volume='' serial=00000000
maximal component length=12 cluster=32768 total=999968K free=615136K
file system ='' flags=CASE_PRESERVED
Root: D:\ type=REMOTE volume='' serial=00000000
maximal component length=12 cluster=16384 total=601632K free=0K
file system ='' flags=CASE_PRESERVED
******** READ DOS DEVICES MAP ********
NOTE: DefineDosDevice() is not implemented!
Поведение приложения вполне соответствует обычному 16ти разрядному приложению в среде Windows 3.x, но вот полный размер диска, превышающий 1Г определяется с ошибкой -- диск C на 1.33Г был определен как диск размером 999М.
Среда Windows NT, 32х разрядное приложение:
******** GET VOLUME INFORMATION ********
Root: A:\ type=REMOVABLE volume='' ***** NO VOLUME INFORMATION!
Root: C:\ type=FIXED volume='' serial=00AE5141
maximal component length=255 cluster=512 total=1405655K free=615143K
file system ='NTFS' flags=CASE_PRESERVED CASE_SENSITIVE UNICODE ACL MAY_COMPRESS
Root: D:\ type=CD-ROM volume='ASART3' serial=E2F025BC
maximal component length=221 cluster=2048 total=601644K free=0K
file system ='CDFS' flags=CASE_SENSITIVE
******** READ DOS DEVICES MAP ********
DISPLAY1 = \Device\Video0
NDIS = \Device\Ndis
DISPLAY2 = \Device\Video1
Z: = \??\C:\WINNT
D: = \Device\CdRom0
$VDMLPT1 = \Device\ParallelVdm0
COM1 = \Device\Serial0
COM2 = \Device\Serial10000
PIPE = \Device\NamedPipe
UNC = \Device\Mup
PhysicalDrive0 = \Device\Harddisk0\Partition0
PRN = \DosDevices\LPT1
A: = \Device\Floppy0
Scsi0: = \Device\ScsiPort0
DC21X41 = \Device\DC21X41
LPT1 = \Device\Parallel0
Scsi1: = \Device\ScsiPort1
C: = \Device\Harddisk1\Partition1
AUX = \DosDevices\COM1
MAILSLOT = \Device\MailSlot
NUL = \Device\Null
Единственное, что кажется несколько странным, так это сообщение о критической ошибке при попытке вызова GetVolumeInformation для отсутствующего диска, хотя под Windows-95 эта функция работает молча -- она же и так возвращает результат “не удалось”, так зачем же еще давать сообщение? Сообщение об ошибке отключается с помощью SetErrorMode, хотя это и не согласуется с формальным описанием функции.
Итого:
Если ваше приложение может работать в Windows 3.x с Win32s, то необходимо особенно тщательное тестирование всех операций с файлами и томами, так как реакция системы может существенно отличаться от той, которая будет в случае Windows-95 и Windows NT. Кроме того особое внимание стоит уделить функциям, возвращающим информацию о томе (типа GetVolumeInformation) -- они производят попытку реального обращения к томам, что может привести либо к возникновению сообщений об ошибках либо даже к «зависанию» всего приложения, если работа с томом сопровождается какой-либо ошибкой. Так, например, отдельной проверки и отладки потребуют все случаи работы со сменными дисками (гибкими, компакт-дисками, магнито-оптическими дисками и т.д.) и с сетевыми томами (особенно случаи, когда удаленный компьютер, предоставляющий свои тома в общее пользование, зависает, отключается или происходят какие-либо неполадки в работе сети -- в такой ситуации возможно даже зависание компьютера, с которого производится вызов функции GetVolumeInformation).
Работа с каталогами и файлами
Win32 API содержит все необходимые функции для работы с каталогами и файлами. При этом набор функций, реализованных в Windows полностью перекрывает обычный набор функций библиотеки времени выполнения, так что необходимость в применении функций последней отпадает. Рассматриваемые здесь функции служат следующим целям:
работа с каталогами (создание, удаление, поиск и получение списка файлов);
получение и изменение атрибутов файлов;
работа с файлами (длинными и короткими именами файлов, копирование, перемещение и удаление файлов);
В таком порядке мы и познакомимся с функциями Win32 API.
Работа с каталогами
Аналогично обычному Windows API в Win32 API используется понятие текущего каталога, в котором должны размещаться файлы, если только в их имени не содержится путь к этим файлам. Иногда возможно задание относительного пути (подробнее см. Работа с файлами, каталогами и томами в Windows API, стр. 1). Вы можете как узнать текущий каталог с помощью функции GetCurrentDirectory, так и сделать текущим какой-либо иной каталог, воспользовавшись функцией SetCurrentDirectory.
DWORD GetCurrentDirectory(cchDir, lpszDir);
BOOL SetCurrentDirectory(lpszDir);
Параметры функций: lpszDir -- буфер, содержащий или получающий имя текущего каталога, cchDir -- максимальное число символов в имени текущего каталога, которые могут уместиться в отведенном буфере. Не забывайте, что длина имени (это полный путь к текущему каталогу) может быть очень большой, поэтому удобно сначала узнать необходимый размер буфера, выделить его и затем получить имя:
DWORD nSize;
char *pszCurDir;
dwSize = GetCurrentDirectory(0, NULL); // возвращается требуемая длина,
pszCurDir = new char [ dwSize ]; // включая завершающий `\0'
GetCurrentDirectory(dwSize, pszCurDir);
При необходимости вы можете создавать или уничтожать каталоги с помощью функций CreateDirectory и RemoveDirectory. Как и в случае функций библиотеки времени выполнения, функция RemoveDirectory может удалить только пустой каталог; в противном случае функция сообщит об ошибке.
BOOL CreateDirectory(lpszDir, lpsaSA);
BOOL RemoveDirectory(lpszDir);
Параметр lpSA является указателем на структуру SECURITY_ATTRIBUTES, с помощью которого вы можете управлять доступом к файлам.
DWORD GetTempPath(cchBuffer, lpszTempPath);
Эта функция дополняет прежние GetTempDrive и GetTempFileName. Она возвращает путь к каталогу, предназначенному для хранения временных файлов.
Несколько других функций предназначены для поиска файла или для получения списка файлов в каталоге. Функция SearchPath ищет определенный файл и возвращает полный путь к файлу, если только этот файл найден.
DWORD SearchPath(lpszPath, lpszFile, lpszExt, cchBuffer, lpszBuffer, plpszFileNamePart);
Параметр lpszPath указывает на каталог, в котором надо искать файл. Если этот параметр равен NULL, то Windows будет искать файл в том каталоге, откуда приложение запущено, в текущем каталоге, в системных каталогах Windows, и в самом каталоге Windows, а также во всех каталогах, перечисленных на пути поиска, заданном параметром окружения PATH. Параметр lpszFile задает имя файла для поиска, lpszExt -- расширение имени искомого файла (используется, если указанное имя не содержит расширения). Параметры cchBuffer, lpszBuffer задают характеристики (размер и адрес) буфера, принимающего имя файла, а указатель на указатель plpszFileNamePart определит позицию, начиная с которой в буфере находится имя файла (то есть первый символ после последнего `\' в пути).
Три функции FindFirstFile, FindNextFile и FindClose примерно соответствуют функциям _dos_findfirst, _dos_findnext и _dos_findclose библиотеки времени выполнения. Функция FindFirstFile требует задания шаблона имен файлов и указателя на специальную структуру WIN32_FIND_DATA, которая будет заполняться информацией о текущем файле, соответствующем шаблону. Функция создает специальный объект, используемый в последующих вызовах функции FindNextFile для продолжения перебора файлов в каталоге. После завершения перебора созданный объект необходимо удалить с помощью функции FindClose.
HANDLE FindFirstFile(lpszFileName, lpFindFileData);
BOOL FindNextFile(hFindFile, lpFindFileData);
BOOL FindClose(hFindFile);
struct WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD dwSizeHigh;
DWORD dwSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
TCHAR cFileName[ MAX_PATH ];
TCHAR cAlternateFileName[ 14 ];};
Пример:
WIN32_FIND_DATA fd;
HANDLE hFD;
hFD = FindFirstFile(“c:\\*.*”, &fd);
if (hFD) {
do {
// анализ структуры fd и выполнение необходимых действий над файлами.
} while (FindNextFile(hFD, &fd));
FindClose(hFD);}
Последние рассматриваемые нами функции позволяют получать информацию об изменении каталога файлов. Система создает специальный объект, который функция FindFirstChangeNotification первоначально устанавливает в занятое состояние, и который автоматически переводится в свободное состояние, как только в каталоге (или в подкаталогах) происходит указанное изменение. Ожидаемое изменение задается параметром fdwFilter при вызове функции FindFirstChangeNotification.
HANDLE FindFirstChangeNotification(lpszPath, fWatchSubTree, fdwFilter);
HANDLE FindNextChangeNotification(hChange);
BOOL FindCloseChangeNotifictaion(hChange); Аналогичная группа функций существует и для получения информации о принтерах (FindFirstPrinterChangeNotification, FindNextPrinterChangeNotification и FindClosePrinterChangeNotification), только она реализована исключительно для Windows NT. Согласно описанию для Windows-95 или Windows 3.x с Win32s эти функции не доступны.
Функции FindFirstChangeNotification и FindNextChangeNotification возвращают управление сразу после установки созданного объекта в занятое состояние. Вы можете использовать функции WaitForSingleObject или WaitForMultipleObjects для ожидания изменений в каталоге.
Функция FindCloseChangeNotifictaion удаляет созданный объект.
Внимание! Эти функции не реализованы для Windows 3.x с Win32s. Однако, помимо этого ограничения, существует еще несколько особенностей в применении этих функций. Так, при работе в Windows-95 переименование одного файла в каталоге может приводить к двукратному сообщению об изменении содержимого каталога. Еще серьезнее ограничение на использование удаленных каталогов (каталогов других компьютеров, предоставленных в общий доступ) -- система вообще не отслеживает изменения в них, даже если эти изменения осуществлены с вашего компьютера. Это справедливо и для Windows-95 и для Windows NT.
Получение и изменение атрибутов файлов
В данном разделе мы рассмотрим основные функции Win32 API для получения и изменения атрибутов файлов. Для каждого файла поддерживается несколько атрибутов, универсальных для разных файловых систем. К ним относятся атрибуты архивный (archive), скрытый (hidden), системный (system), только для чтения (read-only), временный (temporary) и каталог (directory), а также дата и время создания, дата и время последнего изменения и дата и время последнего обращения к файлу.
Некоторые из этих атрибутов поддерживаются ограниченно. Так, например, атрибут временный (temporary) используется только для оптимизации доступа к файлу (система по возможности сохраняет все данные в оперативной памяти, не записывая их на диск), сам же файл при закрытии не удаляется.
Разные файловые системы, которые могут использоваться локальными или удаленными дисками, могут предоставлять даты и времена с разной точностью и в разном комплекте. Так, тома с обычной FAT под управлением MS-DOS хранят только дату и время последнего изменения файла с точностью до 2х секунд, тома с FAT, поддерживаемые системами типа Windows-95, Windows NT или OS/2 сохраняют дату и время создания и последнего изменения с точностью до 2х секунд и дату (без времени) последнего доступа к файлу. Как правило файловые утилиты показывают только время последнего изменения файла, так как эта информация, во-первых, предоставлена всеми используемыми файловыми системами, а во-вторых, потому что именно эта дата обычно интересует пользователя.
Для получения и изменения атрибутов предназначены две функции:
DWORD GetFileAttributes(lpFileName);
DWORD SetFileAttributes(lpFileName, dwFileAttributes);
Обе функции требуют имя файла, атрибуты которого возвращаются (изменяются), а также они упаковывают информацию об атрибутах в виде двойного слова, отдельные биты которого информируют о наличии тех или иных атрибутов. Вы можете использовать следующие символы, определяемые вместо конкретных значений атрибутов:
FILE_ATTRIBUTE_ARCHIVE
FILE_ATTRIBUTE_DIRECTORY
FILE_ATTRIBUTE_HIDDEN
FILE_ATTRIBUTE_NORMAL
FILE_ATTRIBUTE_READONLY
FILE_ATTRIBUTE_SYSTEM
FILE_ATTRIBUTE_TEMPORARY
Помимо двух рассмотренных функций, атрибуты файлов возвращаются еще некоторыми другими, как, например, уже рассмотренная нами функции FindFirstFile и FindNextFile, размещающие эту информацию в структуре WIN32_FIND_DATA, или функция GetFileInformationByHandle, возвращающая их в структуре BY_HANDLE_FILE_INFORMATION. Функция GetFileInformationByHandle не работает в системе Windows 3.x с Win32s.
BOOL GetFileInformationByHandle(hFile, lpFileInformation);
struct BY_HANDLE_FILE_INFORMATION {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD dwVolumeSerialNumber;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD nNumberOfLinks;
DWORD nFileIndexHigh;
DWORD nFileIndexLow;};
Перед рассмотрением функций, работающих с датой и временем, надо сделать несколько оговорок, касающихся способов представления даты и времени.
Во-первых, дата и время могут задаваться как всеобщее (UTC, coordinated universal time, время по Гринвичу) так и как локальное время. Разница сводится к учету часового пояса и перехода на летнее время. Подробнее -- см. описание функций SetTimeZoneInformation и GetTimeZoneInformation.
Во-вторых, и дата и время может быть записана разными способами и в разных форматах. Иногда дата и время объединяются в одну структуру, иногда они разделяются по разным структурам. Способы упаковки данных в структуры различаются как в зависимости от операционных систем, так и в зависимости от тех функций, которые применяют информацию о дате и времени.
При работе с файлами в Win32 API дата и время записаны как одно квадрослово (реально представлено в виде структуры из двух двойных слов) FILETIME.
struct FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;};
Это квадрослово показывает число интервалов по 0.000 000 1 секунде (100 наносекунд), которые прошли, считая от 4 часов утра 1 января 1601 года. Такая, на первый взгляд странная, начальная дата объясняется просто: по правилам григорианского календаря високосными считаются года, номер которых нацело делится на 4, кроме тех, которые делятся нацело на 100, но включая те, номер которых нацело делится на 400. То есть год 1904 был високосным, 1908 тоже, а 1900 -- нет. Однако 2000 год, равно как и 1600 год был таковым. Таким образом за начальную точку отсчета времени был взят первый день последнего 400-летнего цикла.
Для каждого файла определено 3 момента, информация о которых заносится в систему: дата и время создания файла, дата и время последнего изменения файла и дата и время последнего обращения к файлу.
Помимо уже рассмотренных функций FindFirstFile, FindNextFile и GetFileInformationByHandle, вы можете узнать или назначить для конкретного файла эти времена с помощью следующих функций:
BOOL GetFileTime(hFile, lpftCreation, lpftLastAccess, lpftLastWrite);
BOOL SetFileTime(hFile, lpftCreation, lpftLastAccess, lpftLastWrite);
Где hFile является хендлом открытого файла (см. функцию CreateFile), lpftCreation, lpftLastAccess и lpftLastWrite -- указателями на три структуры типа FILETIME. Система использует информацию о дате и времени всегда в виде всеобщего времени.
При необходимости вы можете узнать, какое событие произошло раньше с помощью функции
LONG CompareFileTime(lpft1, lpft2);
А также вы можете преобразовать дату и время из всеобщего в локальное (с учетом часового пояса) и наоборот с помощью функций:
BOOL FileTimeToLocalFileTime(lpftUTC, lpftLocal);
BOOL LocalFileTimeToFileTime(lpftLocal, lpftUTC);
Обе эти функции используют структуры FILETIME для получения времени и возвращения результата.
Если вы переносите разработанную ранее программу под Win32 API, то может быть проще не переписывать все функции, анализирующие дату и время, а просто преобразовать полученные данные в формат MS-DOS. Для этого предназначены функции:
BOOL FileTimeToDosDateTime(lpft, lpwDOSDate, lpwDOSTime);
BOOL DosDateTimeToFileTime(wDOSDate, wDOSTime, lpft);
которые преобразуют дату и время из FILETIME в формат MS-DOS -- два слова, в одном упаковывается дата, а в другом -- время. Однако в иных случаях применять эти функции не рекомендуется. Проще преобразовать FILETIME в SYSTEMTIME, которая содержит всю необходимую информацию в отдельных полях структуры, что позволяет ее легко анализировать.
BOOL FileTimeToSystemTime(lpft, lpst);
BOOL SystemTimeToFileTime(lpst, lpft);
struct SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMillisecond;};
Параметры lpft и lpst являются указателями на структуры FILETIME и SYSTEMTIME соответственно; поля структуры SYSTEMTIME определяют год, месяц (январь считается 1), номер дня недели (0 -- воскресенье), день месяца (начиная с 1), час, минуту, секунду и миллисекунду. Применение этих функций можно увидеть в примере 3B.
Работа с файлами
Как уже говорилось, в Win32 API есть все необходимое для работы с файлами. Приложение не нуждается в разработке дополнительного кода для выполнения типовых операций над файлами. Для удобства разработчиков в Win32 API определены специальные функции, осуществляющие копирование, перемещение, удаление и переименование файлов. Для выполнения этих операций предназначены 4 функции, декларированные в Win32 API:
BOOL CopyFile(lpszFileName, lpszNewFileName, fFailIfExists);
BOOL DeleteFile(lpszFileName);
BOOL MoveFile(lpszFileName, lpszNewFileName);
BOOL MoveFileEx(lpszFileName, lpszNewFileName, fdwFlags);
Функция CopyFile осуществляет копирование файла, заданного параметром lpszFileName в файл, заданный параметром lpszNewFileName. Дополнительный параметр функции fFailIfExist определяет реакцию системы в том случае, когда новый файл уже существует. Если fFailIfExist равно TRUE, то существующий файл сохраняется, а если этот параметр равен FALSE, то файл будет перезаписан.
Функция DeleteFile удаляет указанный файл.
Функции MoveFile и MoveFileEx осуществляют перемещение или копирование указанного файла. Однако области применения этих функций существенно различаются. Согласно описанию, функция MoveFile может переименовывать или перемещать файлы или каталоги, причем каталог перемещается целиком, со всеми входящими в него файлами и подкаталогами. Функция возвращает код ошибки в том случае, когда итоговый файл или каталог уже существует. Если перемещение осуществляется в пределах одного тома, то процесс перемещения сводится только к исправлению записей в каталогах, а реального перемещения данных не происходит. А если перемещение осуществляется на другой том, то функция MoveFile просто копирует файл и удаляет исходный, но при этом перемещение каталога на другой том не осуществляется -- каталог можно перемещать только в пределах своего тома.
Функция MoveFileEx (не реализована в Windows-95 и в Win32s!) может переименовывать, перемещать или удалять только файлы, как в пределах одного тома, так и с тома на том. С помощью дополнительного параметра fdwFlags можно уточнить, каким образом будет осуществляться перемещение файла. Флаг MOVEFILE_REPLACE_EXISTING определяет, что файл будет перемещен или переименован, даже если итоговый файл уже существует. Если файл должен быть перемещен на другой диск, то аналогично функции MoveFile перемещение осуществляется как копирование и удаление исходного файла; если не указать флаг MOVEFILE_COPY_ALLOWED, то такое перемещение будет запрещено. Еще один флаг MOVEFILE_DELAY_UNTIL_REBOOT очень удобен при разработке инсталляционных программ. Этот флаг говорит системе, что файл надо перемещать не сейчас, при последующей загрузке системы. Таким образом появляется возможность замены файлов, являющихся компонентами системы или используемыми системой в процессе работы. Частный случай использования этой функции -- задание параметра lpszNewFileName равным NULL совместно с флагом MOVEFILE_DELAY_UNTIL_REBOOT (согласно описанию допустимо только такое сочетание) -- приводит к удалению указанного файла при перезагрузке системы.
Пример 3B -- работа с каталогами
Данный пример реализован исключительно для платформы Win32, так как в нем демонстрируется применение некоторых функций, специфичных именно для этой платформы. В главном окне приложения отображается содержимое текущего каталога; дополнительно устанавливается механизм извещения приложения об обновлении каталога, так что при любом изменении в каталоге -- создании нового файла, удалении существующего, переименовании и пр. -- содержимое окна обновляется.
В данном примере информирование приложения о смене содержимого каталога осуществляется с помощью функций FindFirstChangeNotification и FindNextChangeNotification, специфичных для Win32 API. Схожего эффекта можно было-бы добиться при использовании средств File Manager Extension (заголовочный файл fmext.h) в рамках Windows API. Схожего, но не такого же. Например, использование расширений диспетчера файлов в Windows API для получения информации об обновлении содержимого каталога ограничено только одним приложением в системе -- два запущенных приложения уже не могут получать такие уведомления.
Функции FindFirstChangeNotification и FindNextChangeNotification используют специальный объект, который переводится в занятое состояние до ближайшего изменения каталога. Напрашивается простейший способ -- вызвать функцию FindFirstChangeNotification и затем сразу функцию WaitForSingleObject, так что приложение остановится до тех пор, пока оно не получит уведомление об изменении каталога. Способ надежный, но остановленное приложение не сможет обновлять своего содержимого в окне (если его окно на время перекроют другие окна), вы даже не сможете завершить ваше приложение, так как оно ждет уведомления об обновлении каталога.
Из этой ситуации можно предложить два выхода -- один, исключительно в стиле Win32 -- создать отдельный поток, который будет ждать обновлений. Наверное, это самый эффективный способ, но о создание многопотоковых приложений будет обсуждено существенно позже. Другой путь -- скрестить средства Windows API и Win32 API -- вместо ожидания освобождения объекта, проверять его состояние по таймеру. В этом приеме практически не требуется дополнительного программирования, достаточно добавить инициализацию таймера и обработку сообщений WM_TIMER.
Собственно, именно таким путем и решена данная задача. Она построена аналогично примеру 2B -- оглавление каталога, сформированное в виде текста, передается специальному окну-редактору, которое закрывает всю внутреннюю область главного окна приложения. В оконную процедуру главного окна приложения добавляется обработка сообщения WM_TIMER. Сам таймер инициализируется и освобождается в функции WinMain. Обработчик сообщений таймера -- Cls_OnTimer -- проверяет состояние синхронизирующего объекта (созданного при создании окна функцией FindFirstChangeNotification) и, если он освободился, принимает меры для обновления окна и снова переводит объект его в занятое состояние с помощью функции FindNextChangeNotification. Конечно, вместо таймера эффективнее было бы применить отдельный поток; однако приведенный вариант сравнительно легко адаптируется под 16ти разрядную платформу, в которой многопотоковые приложения не реализованы.
Функция, получающая оглавление каталога и формирующая отображаемый список вынесена в обработчик специального сообщения MY_REFRESH. Номер этому сообщению мы присваиваем сами, так, что бы он не конфликтовал со стандартными сообщениями окна. Для этого можно воспользоваться символом WM_USER, соответствующим самому младшему номеру сообщения, не являющего стандартным. Все номера сообщений равные или превышающие WM_USER стандартным окном То есть окном, чья процедура построена на функции DefWindowProc. Другие окна, как, скажем, редакторы, кнопки, списки, диалоги и прочее используют сообщения с номерами, большими WM_USER. Однако такие сообщения они только получают сами, но главное окно приложения их не получит. не используются. Это же позволит продемонстрировать определение распаковщиков для собственного сообщения.
Файл 3B.CPP
#define STRICT
#include <windows.h>
#include <windowsx.h>
#define UNUSED_ARG(arg) (arg)=(arg)
// определяем собственное сообщение и его распаковщик
#define MY_REFRESH WM_USER+1
/* void Cls_OnMyRefresh(HWND hwnd); */
#define HANDLE_MY_REFRESH(hwnd,wParam,lParam,fn) ((fn)(hwnd),0L)
#define FORWARD_MY_REFRESH(hwnd,fn) (void)(fn)((hwnd),MY_REFRESH,0,0L)
// резервируем глобальные переменные
static char szWndClass[]= "File & folder operations";
static char *pszCurDir;
static HINSTANCE hInstance;
// разрабатываем функцию, обновляющую содержимое окна просмотра
static void Cls_OnMyRefresh(HWND hwnd)
{int nSize;
char *pszList, szTemp[ 1024 ];
char szCreate[ 20 ], szRead[ 20 ], szWrite[ 20 ], szAttr[ 6 ];
WIN32_FIND_DATA fd;
FILETIME ftLocal;
SYSTEMTIME stTime;
HANDLE hFD;
static char szFileMask[] = "*.*";
static char szTimeFmt[] = "%02u-%02u-%04u %02u:%02u:%02u";
hFD = FindFirstFile(szFileMask, &fd);
if (hFD) {
// так как список файлов может быть длинным, то определяем его дину
nSize = lstrlen(pszCurDir) + 82; // длина заголовка списка
do {
nSize += lstrlen(fd.cFileName) + 76; // длина записи о каждом файле
} while (FindNextFile(hFD, &fd));
FindClose(hFD);
// резервируем необходимое пространство, включая последний `\0' символ
pszList = new char [ nSize + 1 ];
if (pszList) {
// готовимся к получению списка файлов
hFD = FindFirstFile(szFileMask, &fd);
if (hFD) {
// формируем заголовок
pszList[0] = '[';
lstrcpy(pszList + 1, pszCurDir);
nSize = lstrlen(pszCurDir) + 1;
lstrcpy(
pszList + nSize,
"]\r\n creation | last write"
" | last access | attrs | name");
nSize += 81;
do {
// перебираем все файлы по одному
// учитываем переход от Гринвича к локальному времени
FileTimeToLocalFileTime(&(fd.ftCreationTime), &ftLocal);
// преобразуем к приемлемому для чтения формату
FileTimeToSystemTime(&ftLocal, &stTime);
// записываем дату и время
wsprintf(
szCreate, szTimeFmt, stTime.wDay, stTime.wMonth,
stTime.wYear, stTime.wHour, stTime.wMinute, stTime.wSecond);
// аналогично записываем время изменения
FileTimeToLocalFileTime(&(fd.ftLastWriteTime), &ftLocal);
FileTimeToSystemTime(&ftLocal, &stTime);
wsprintf(
szWrite, szTimeFmt, stTime.wDay, stTime.wMonth,
stTime.wYear, stTime.wHour, stTime.wMinute, stTime.wSecond);
// и время последнего доступа
FileTimeToLocalFileTime(&(fd.ftLastAccessTime), &ftLocal);
FileTimeToSystemTime(&ftLocal, &stTime);
wsprintf(
szRead, szTimeFmt, stTime.wDay, stTime.wMonth,
stTime.wYear, stTime.wHour, stTime.wMinute, stTime.wSecond);
// расшифровываем атрибуты файла
szAttr[0] = fd.dwFileAttributes&FILE_ATTRIBUTE_ARCHIVE ? 'A':'-';
szAttr[1] = fd.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN ? 'H':'-';
szAttr[2] = fd.dwFileAttributes&FILE_ATTRIBUTE_SYSTEM ? 'S':'-';
szAttr[3] = fd.dwFileAttributes&FILE_ATTRIBUTE_READONLY ? 'R':'-';
szAttr[4] = fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY?'D':'-';
szAttr[5] = '\0';
// и формируем строку для вывода и добавляем ее в список
wsprintf(
pszList + nSize,
"\r\n%19.19s | %19.19s | %19.19s | %5.5s | ",
szCreate, szWrite, szRead, szAttr);
nSize += 76;
lstrcpy(pszList + nSize, fd.cFileName);
nSize += lstrlen(fd.cFileName);
} while (FindNextFile(hFD, &fd));
FindClose(hFD);
SetWindowText((HWND)GetWindowLong(hwnd, 0), pszList);
// после передачи текста окну просмотра
// выделенный для него буфер больше не нужен.
delete pszList;
return;
// дальше мы можем оказаться только в случае ошибки}
delete pszList;}}
SetWindowText((HWND)GetWindowLong(hwnd, 0), "*** Found errors! ***");}
// а это обработчик сообщения WM_CREATE. Создаем дочернее окно просмотра и // синхронизирующий объект, для получения уведомлений об изменении каталога
static BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{UNUSED_ARG(lpCreateStruct);
HWND hwndView;
RECT rc;
HANDLE hWait;
// создаем окно просмотра
GetClientRect(hwnd, &rc);
hwndView = CreateWindow(
"EDIT", "",
WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|ES_MULTILINE|ES_READONLY,
0, 0, rc.right, rc.bottom, hwnd, (HMENU)1, hInstance, NULL);
if (!IsWindow(hwndView)) {
MessageBox(NULL, "Cannot create viewer window!", NULL, MB_OK);
return FALSE;}
SetWindowFont(hwndView, GetStockObject(ANSI_FIXED_FONT), FALSE);
SetWindowLong(hwnd, 0, (LONG)hwndView);
// инициализируем синхронизирующий объект
hWait = FindFirstChangeNotification(
pszCurDir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
SetWindowLong(hwnd, 4, (LONG)hWait);
// первоначально заполняем окно просмотра
FORWARD_MY_REFRESH(hwnd, PostMessage);
return TRUE;}
// при изменении размеров главного окна надо изменить размеры дочернего окна просмотра
static void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy)
{UNUSED_ARG(state);
HWND hwndView = (HWND)GetWindowLong(hwnd, 0);
if (IsWindow(hwndView)) MoveWindow(hwndView, 0,0, cx, cy, TRUE);}
// когда главное окно закрывается уничтожаем окно просмотра и синхронизирующий объект
static void Cls_OnDestroy(HWND hwnd)
{HWND hwndView = (HWND)GetWindowLong(hwnd, 0);
if (IsWindow(hwndView)) DestroyWindow(hwndView);
HANDLE hWait = (HANDLE)GetWindowLong(hwnd, 4);
if (hWait) FindCloseChangeNotification(hWait);
PostQuitMessage(0);}
// при получении главным окном фокуса ввода, передаем его окну просмотра
static void Cls_OnSetFocus(HWND hwnd, HWND hwndOldFocus)
{UNUSED_ARG(hwndOldFocus);
HWND hwndView = (HWND)GetWindowLong(hwnd, 0);
if (IsWindow(hwndView)) SetFocus(hwndView);}
// по таймеру (у нас - каждые 2 секунды) проверяем состояние синхронизирующего объекта
void Cls_OnTimer(HWND hwnd, UINT id)
{UNUSED_ARG(id);
HANDLE hWait;
hWait = (HANDLE)GetWindowLong(hwnd, 4);
if (hWait) {
if (WaitForSingleObject(hWait, 0) == WAIT_OBJECT_0) {
// объект освобожден - каталог изменился
MessageBeep(MB_OK); // звуковой сигнал для привлечения внимания
FORWARD_MY_REFRESH(hwnd, PostMessage); // снова загрузить список
FindNextChangeNotification(hWait); // и ждать дальше ...}}}
LONG WINAPI _export WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg) {
HANDLE_MSG(hWnd, WM_CREATE, Cls_OnCreate);
HANDLE_MSG(hWnd, WM_DESTROY, Cls_OnDestroy);
HANDLE_MSG(hWnd, WM_SIZE, Cls_OnSize);
HANDLE_MSG(hWnd, WM_SETFOCUS, Cls_OnSetFocus);
HANDLE_MSG(hWnd, MY_REFRESH, Cls_OnMyRefresh);
HANDLE_MSG(hWnd, WM_TIMER, Cls_OnTimer);
default: break;}
return DefWindowProc(hWnd, uMsg, wParam, lParam);}
static BOOL init_instance(HINSTANCE hInst)
{WNDCLASS wc;
hInstance = hInst;
wc.style = 0;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 8;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szWndClass;
return RegisterClass(&wc) == NULL ? FALSE : TRUE;}
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
{UNUSED_ARG(lpszCmdLine);
MSG msg;
HWND hWnd;
int nSize;
nSize = GetCurrentDirectory(0, NULL);
pszCurDir = new char [ nSize ];
GetCurrentDirectory(nSize, pszCurDir);
if (!hPrevInst) {
if (!init_instance(hInst)) return 1;}
hWnd= CreateWindow(
szWndClass, // class name
szWndClass, // window name
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT,CW_USEDEFAULT, // window position
CW_USEDEFAULT,CW_USEDEFAULT, // window size
NULL, // parent window
NULL, // menu
hInst, // current instance
NULL // user-defined parameters);
if (!hWnd) return 1;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// инициализируем таймер так, что бы сообщения передавались каждые 2 секунды
SetTimer(hWnd, 0, 2000, (TIMERPROC)NULL);
while (GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);}
if (pszCurDir) delete pszCurDir;
return msg.wParam;}
Чтение и запись файлов
HANDLE CreateFile(lpszName, fdwAccess, fdwShareMode, lpszSA, fdwCreate, fdwAttrsAndFlags, hTemplateFile);
INVALID_HANDLE_VALUE = (HANDLE)-1 !!!!!!!!!!
BOOL CloseHandle(hFile);
BOOL ReadFile(hFile, lpvBuffer, nBytes, lpdwReaded, lpOverlapped);
BOOL WriteFile(hFile, lpvBuffer, nBytes, lpdwWritten, lpOverlapped);
DWORD SetFilePointer(hFile, lDistanceLow, lDistanceHigh, dwMethod);
BOOL SetEndOfFile(hFile);
BOOL FlushFileBuffers(hFile);
BOOL LockFile(hFile, dwOffsetLow, dwOffsetHigh, cbLockLow, cbLockHigh);
BOOL UnlockFile(hFile, dwOffsetLow, dwOffsetHigh, cbLockLow, cbLockHigh);
BOOL LockFileEx(hFile, dwFlags, dwUnused, cbLockLow, cbLockHigh, lpsOverlapped); // not in 95!
BOOL UnlockFileEx(hFile, dwFlags, dwUnused, cbLockLow, cbLockHigh, lpOverlapped); // not in 95!
BOOL GetOverlappedResult(hFile, lpOverlapped, lpcbTransfer, fWait);
DWORD WaitForSingleObject(hObject, dwTimeOut);
BOOL ReadFileEx(hFile, lpvBuffer, nBytes, lpOverlapped, lpfnCompletionFunc);
BOOL WriteFileEx(hFile, lpvBuffer, nBytes, lpOverlapped, lpfnCompletionFunc);
Подобные документы
Хранение файлов, доступ к ним, установка и изменение атрибутов. Операционные системы DOS, Windows 95/98/Me, Windows NT/2000/XP. Файловая система FAT 16. Уменьшение потерь дискового пространства. Количество секторов в кластере. Главная загрузочная запись.
реферат [72,9 K], добавлен 19.01.2012Появление операционной системы Windows 95. Правила присвоения имен файлам. Порядок хранения файлов на диске. Система хранения файлов и организации каталогов. Многоуровневая иерархическая файловая система. Полное имя файла. Иерархия папок Windows.
презентация [103,0 K], добавлен 11.03.2015Набор данных на диске, имеющий имя. Порядок размещения файлов. Многоуровневая файловая система. Полный адрес файла. Логические диски и файловые системы в Windows. Работа с файлами в Windows. Связь расширения с программой. Поиск компьютеров в сети.
презентация [1,9 M], добавлен 12.12.2012Теоретическое изучение и практическое применение приёмов работы с файлами в операционной системе Windows 95. Файлы и папки: основные понятия и правила формирования имен файлов в Windows. Характеристика и анализ особенностей операций с файлами и папками.
контрольная работа [139,9 K], добавлен 09.03.2011Описание и назначение, основные функции панели задач и меню "Пуск", языковой панели. Порядок установки даты и времени. Методика поиска файлов. Правила запуска программ. Работа с файлами. Профилактика сбоев в работе компьютера. Основные свойства экрана.
методичка [130,0 K], добавлен 05.07.2010Описание типизированных файлов. Принципы работы с файлами, создание и открытие на запись нового файла. Чтение из файла, открытие существующего файла на чтение. Определение имени файла. Запись в текстовый файл. Описание множества и операции над ними.
реферат [86,4 K], добавлен 07.02.2011Фундаментальная структура системы файлов Windows 2000, ее внутреннее представление, восстановление и безопасность. Управление томами и устойчивость к сбоям. Метод экономии памяти. Точки повторного анализа (reparse points). Сетевые средства - протоколы.
презентация [1,4 M], добавлен 24.01.2014Система Windows ХР, ее настройка, защита, восстановление и быстродействие. Свойства панели задач. Защита файлов с помощью пароля экранной заставки. Верификация драйверов. Восстановление системных файлов. Автоматическое обновление. Снятие ненужных служб.
курсовая работа [5,9 M], добавлен 02.04.2009Работа с объектами операционной системы Windows: основные понятия и горячие клавиши. Создание и редактирование файлов и папок. Скриншоты и графический редактор Paint. Редактирование простейших текстовых документов в Блокноте. Работа с калькулятором.
лабораторная работа [16,6 K], добавлен 30.11.2010История Windows. Особенности Windows XP. Файловая система и структура. Основные принципы работы с системой. Начало и завершение работы, главное меню. Запуск и завершение программ. Окна и диалоги, панель задач. Установка Windows XP.
курсовая работа [344,0 K], добавлен 24.04.2007