Учебное пособие: Файловая система
Внимание! для доступа к дискам в Windows NT необходимо иметь права доступа администратора системы!
BOOL DeviceIoControl(// нереализованав Win32s!
hDevice, dwIoControlCode,
lpvInBuffer, cbInBuffer,
lpvOutBuffer, cbOutBuffer,
lpcbBytesReturned,
lpoOverlapped);
В этом разделе дополнительно будут обзорно рассмотрены еще две функции, предназначенные для работы с устройствами (это не обязательно тома). Эти функции реализованы только в Windows NT, так что применяются крайне редко — обычно стараются разрабатывать приложения, переносимые между разными реализациями Win32.
BOOL DefineDosDevice(dwFlags, lpszDeviceName, lpTargetPath);
DWORD QueryDosDevice(lpszDeviceName, lpBuffer, cbMaxSize);
Обе функции жестко привязаны к тому, как в Windows NT осуществляется доступ к ее устройствам: в системе существуют свой собственный способ определения всех устройств. Например, имя \Device\Parallel0 определяет первый параллельный порт. Однако, обычно для того–же самого используются имена типа LPT1, вошедшие в обиход со времен, более древних, чем первые IBM PC XT. Для удобства в Windows NT определена специальная таблица, устанавливающая соответствия между именами устройств “в стиле MS–DOS” и именами в системе. Эта таблица глобальная, все работающие приложения (не только приложения MS–DOS) осуществляют доступ к устройствам посредством этой таблицы.
Функция DefineDosDevice позволяет задать самому такое соответствие, а функция QueryDosDevice узнать либо соответствие конкретного имени устройства, либо получить список всех определенных имен. Подробнее смотри в документации, либо в приводимом ниже примере.
Имеется одна несколько странная особенность этих функций — обычно функции Win32 API, не реализованные на той или иной платформе возвращают код ошибки ERROR_CALL_NOT_IMPLEMENTED, который можно получить посредством функции GetLastError. Выглядит такая проверка примерно так:
DefineDosDevice(0, "Z:", buffer);
if(GetLastError() != ERROR_SUCCESS) {
// возникла ошибка - может быть функция не поддерживается
} else {
// все в порядке, работаем как обычно}
Несколько неожиданно, что в Windows 98 эти функции не устанавливают код ошибки, функция GetLastError возвращает код ERROR_SUCCESS. Однако о корректной работе функций говорить к сожалению не приходиться... Подробнее — в приводимом ниже примере.
Пример 2B — работа с томами
Данный пример иллюстрирует применение некоторых функций для работы с томами и файлами. Это приложение построено на основе примера 1B, использующего распаковщики сообщений. В окне, созданным данным приложением, просто будут перечисляться имена томов и некоторая информация о них, а также о назначении устройств DOS.
Интересно рассмотреть, каким образом осуществляется вывод информации о томах в окно приложения. Это можно было–бы реализовать разными способами:
Хуже некуда. Изменить в примере 1B.CPP обработку сообщения WM_PAINT (функция Cls_OnPaint), так, что бы при обработке сообщения опрашивать все устройства и выводить необходимую информацию. Очень плохо в этом то, что такой опрос может занимать значительное время, и приводить к обращениям к устройствам при каждой перерисовке окна. Еще хуже то, что при попытке чтения информации с устройства возможно возникновение ошибок, о которых система будет сообщать в отдельном всплывающем окошке, например “CannotreadfromdriveA:”. Это окошко окажется, с большой вероятностью, поверх окна приложения, следовательно, при закрытии окна сообщения, наше приложение снова получит сообщение WM_PAINT, снова попробует обратиться к тому–же устройству ... и так далее (что бы этого избежать можно воспользоваться функцией SetErrorMode, отключив вывод сообщений об ошибках).
Чуть лучше. Считывать информацию об устройствах при создании окна, формировать где–то в памяти весь текст, затем отображать его при обработке WM_PAINT. Этот способ качественно лучше тем, что получение данных и их отображение осуществляется в разных местах программы и в разное время. Однако и у него есть минусы — список устройств может изменяться во время работы приложения, а оно этого не отразит, и, кроме того, список может оказаться достаточно большим — больше размеров окна. Первую проблему мы решать сейчас даже не будем — этого легко добиться введя меню с командой Обновить (Refresh) или выполняя такое обновление через определенный интервал времени. Вторая проблема приведет к добавлению собственного интерфейса — обработке сообщений клавиатуры и мыши, что потребует написания значительного кода и продолжительной отладки.
Еще лучше. Чуть разовьем второй способ — получать информацию будем при создании окна, а отображение и работу с мышью и клавиатурой переложим на Windows. Windows предоставляет разработчикам несколько стандартных классов окон, реализующих самые распространенные элементы управления — кнопки, флажки, списки, простейшее окно–редактор и другие. Вот окном–редактором мы и воспользуемся, причем специально укажем, что текст является неизменяемым, то есть редактор будет работать как окно просмотра. В этом случае при создании главного окна приложения, мы должны создать дочернее окно–редактор, занимающее всю внутреннюю область главного окна[1] . Затем, сформировав весь необходимый текст, передать его редактору. Окно редактирования будет снабжено полосами прокрутки, поддерживать работу с клавиатурой и мышью, осуществлять передачу текста в буфер обмена — и все само, без разработки дополнительного кода. Мы должны доделать совсем немного — обрабатывать сообщения, связанные с изменением размера главного окна (соответственно менять размер дочернего окна), при уничтожении главного окна не забыть уничтожить окно–редактор, а сообщение WM_PAINT мы можем вообще не обрабатывать.
Приложение рассчитано на работу в Win32, однако это связано только лишь с применением функций Win32 API для получения информации о томах. При создании приложения для Windows 3.x вместо функций, не декларированных в Windows API, используются функции–эмуляторы, включаемые в это приложение при компиляции 16ти разрядного приложения. Это обеспечивает возможность нормальной компиляции и работы приложения на обеих платформах, но с несколько ограниченными возможностями в случае применения Windows API (строго говоря, функции–эмуляторы можно было бы сделать и более мощными, опираясь на функции и структуры данных MS–DOS — просто это выходит за рамки данной книги).
Функции DefineDosDevice и QueryDosDevice, применяемые в числе прочих в этом приложении, работают только в виде 32х разрядного приложения и только под Windows NT, так как они имеют смысл исключительно для реализации Win32 в Windows NT.
Файл 2B.CPP