p align="left">// возникла ошибка - может быть функция не поддерживается } else { // все в порядке, работаем как обычно} Несколько неожиданно, что в Windows 98 эти функции не устанавливают код ошибки, функция GetLastError возвращает код ERROR_SUCCESS. Однако о корректной работе функций говорить к сожалению не приходиться... Подробнее -- в приводимом ниже примере. Пример 2B -- работа с томами Данный пример иллюстрирует применение некоторых функций для работы с томами и файлами. Это приложение построено на основе примера 1B, использующего распаковщики сообщений. В окне, созданным данным приложением, просто будут перечисляться имена томов и некоторая информация о них, а также о назначении устройств DOS. Интересно рассмотреть, каким образом осуществляется вывод информации о томах в окно приложения. Это можно было-бы реализовать разными способами: Хуже некуда. Изменить в примере 1B.CPP обработку сообщения WM_PAINT (функция Cls_OnPaint), так, что бы при обработке сообщения опрашивать все устройства и выводить необходимую информацию. Очень плохо в этом то, что такой опрос может занимать значительное время, и приводить к обращениям к устройствам при каждой перерисовке окна. Еще хуже то, что при попытке чтения информации с устройства возможно возникновение ошибок, о которых система будет сообщать в отдельном всплывающем окошке, например “Cannot read from drive A:”. Это окошко окажется, с большой вероятностью, поверх окна приложения, следовательно, при закрытии окна сообщения, наше приложение снова получит сообщение WM_PAINT, снова попробует обратиться к тому-же устройству ... и так далее (что бы этого избежать можно воспользоваться функцией SetErrorMode, отключив вывод сообщений об ошибках). Чуть лучше. Считывать информацию об устройствах при создании окна, формировать где-то в памяти весь текст, затем отображать его при обработке WM_PAINT. Этот способ качественно лучше тем, что получение данных и их отображение осуществляется в разных местах программы и в разное время. Однако и у него есть минусы -- список устройств может изменяться во время работы приложения, а оно этого не отразит, и, кроме того, список может оказаться достаточно большим -- больше размеров окна. Первую проблему мы решать сейчас даже не будем -- этого легко добиться введя меню с командой Обновить (Refresh) или выполняя такое обновление через определенный интервал времени. Вторая проблема приведет к добавлению собственного интерфейса -- обработке сообщений клавиатуры и мыши, что потребует написания значительного кода и продолжительной отладки. Еще лучше. Чуть разовьем второй способ -- получать информацию будем при создании окна, а отображение и работу с мышью и клавиатурой переложим на Windows. Windows предоставляет разработчикам несколько стандартных классов окон, реализующих самые распространенные элементы управления -- кнопки, флажки, списки, простейшее окно-редактор и другие. Вот окном-редактором мы и воспользуемся, причем специально укажем, что текст является неизменяемым, то есть редактор будет работать как окно просмотра. В этом случае при создании главного окна приложения, мы должны создать дочернее окно-редактор, занимающее всю внутреннюю область главного окна Подробнее о работе с окнами смотри в соответствующих разделах.. Затем, сформировав весь необходимый текст, передать его редактору. Окно редактирования будет снабжено полосами прокрутки, поддерживать работу с клавиатурой и мышью, осуществлять передачу текста в буфер обмена -- и все само, без разработки дополнительного кода. Мы должны доделать совсем немного -- обрабатывать сообщения, связанные с изменением размера главного окна (соответственно менять размер дочернего окна), при уничтожении главного окна не забыть уничтожить окно-редактор, а сообщение 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 #define STRICT #include <windows.h> #include <windowsx.h> #define UNUSED_ARG(arg) (arg)=(arg) #ifndef __NT__ // определим необходимые функции при компиляции для Windows API #include "2b16.cpp" // текст файла 2b16.cpp приведен ниже #endif static char szWndClass[]= "test volume functions"; static HINSTANCE hInstance; BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) {UNUSED_ARG(lpCreateStruct); char *temp, *p, *s; DWORD n, i, sernum, complen, flags, spc, bps, fc, tc; char file_system[ 128 ], buffer[ 1024 ]; UINT count, errmode; HWND hwndView; RECT rc; HFILE hf; static OFSTRUCT ofs; static char tempfile[] = “c:\\test.txt”; static char devZ[] = “Z:”; // создадим окно-редактор, занимающее всю внутреннюю область окна GetClientRect(hwnd, &rc); // теоретически в CREATESTRUCT указаны размеры окна, но к сожалению они // могут быть указаны как нулевые, хотя это не так. Функция GetClientRect // в этом случае все равно возвращает корректные данные 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;} // для красоты используем моноширинный шрифт (подробнее см. GDI) SetWindowFont(hwndView, GetStockObject(ANSI_FIXED_FONT), FALSE); // функция SetWindowFont в документации не описана, это макрос, определяемый // в windowsx.h Подробнее -- см. исходный текст этого файла. // запоминаем хендл окна просмотра в структуре описания главного окна // (при регистрации класса надо зарезервировать 4 байта -- что бы и в // Windows API и в Win32 API использовать одинаковые значения и функции) SetWindowLong(hwnd, 0, (LONG)hwndView); // 1. мы не знаем заранее, как много места понадобиться для описания всех // томов и устройств DOS. Для простоты создадим временный файл с заранее // заданным именем c:\test.txt (строго говоря, надо было бы проверить наличие // переменной TEMP или TMP, убедиться, что она указывает на корректный // каталог - в жизни часто она указывает на несуществующий каталог, диск // или даже на защищенный диск - всякое бывает - и создать файл там -- но это // все слишком громоздко для примера). // 2. в этом файле мы соберем нужный текст, а затем разом передадим его окну // просмотра, после чего файл удалим. // 3. для работы с файлами используем функции Windows API, что бы сохранить // переносимость между разными платформами hf = _lcreat(tempfile, 0); if (hf == HFILE_ERROR) { // при ошибке - сообщаем и заканчиваем (окно просмотра будет уничтожено // позже, при обработке WM_DESTROY MessageBox(NULL, "Cannot create temporary file!", NULL, MB_OK); return FALSE;} // пишем первый заголовок _lwrite(hf, "******** GET VOLUME INFORMATION ********\r\n\r\n", 44); SetLastError(ERROR_SUCCESS); n = GetLogicalDriveStrings(0, NULL); if (GetLastError() != ERROR_SUCCESS) { // Функция GetLogicalDriveStrings не реализована в Win32s и (в книгах // часто утверждают) в Windows-95, возможно, иногда это и так, но у меня // в Windows-95 версии 4.00.950a, локализованной для России, работает. // если все же нет, то эмулируем ее работу посредством GetLogicalDrives // которая точно есть во всех реализациях Win32 n = GetLogicalDrives(); // узнаем, сколько всего устройств count = 0; for (i = 1; i; i <<= 1) if (n & i) count++; // формируем строку с именами устройств temp = new char [ count * 4 + 1 ]; if (temp) { p = temp; for (i = 0; i < 32; i ++) if (n & (1L << i)) { *p++ = (char)('A' + i); *p++ = ':'; *p++ = '\\'; *p++ = '\0';} *p++ = '\0';} } else { // если функция GetLogicalDriveStrings работает, то используем ее temp = new char [ n + 1 ]; if (temp) GetLogicalDriveStrings(n, temp); } if (temp) { // исключаем обработку сообщений о критической ошибке errmode = SetErrorMode(SEM_FAILCRITICALERRORS); // если строка получена, то разбираем ее по частям for (p = temp; *p; p += lstrlen(p) + 1) { wsprintf(buffer, "Root: %s", p); switch (GetDriveType(p)) { case 0: s = "???"; break; case 1: s = "invalid"; break; case DRIVE_REMOVABLE: s = "REMOVABLE"; break; case DRIVE_FIXED: s = "FIXED"; break; case DRIVE_REMOTE: s = "REMOTE"; break; case DRIVE_CDROM: s = "CD-ROM"; break; case DRIVE_RAMDISK: s = "RAM DISK"; break; default: s = "what?!"; break;} // укажем явное преобразование указателя на строку `s' к типу // LPSTR -- так как в Windows API для моделей памяти с одним сегментом // данных (tiny,small,medium) указатели по умолчанию 16-ти разрядные // а для функций Windows обязательно нужны 32-х разрядные wsprintf(buffer+lstrlen(buffer), " type=%s volume='", (LPSTR)s); sernum = complen = flags = 0; file_system[0] = '\0'; if ( GetVolumeInformation( p, buffer+lstrlen(buffer), 64, &sernum, &complen, &flags, file_system, sizeof(file_system))) {// если информация о томе прочитана -> получаем и выводим более // подробные сведения wsprintf(buffer+lstrlen(buffer), "' serial=%08lX\r\n", sernum); _lwrite(hf, buffer, lstrlen(buffer)); spc = bps = fc = tc = 0L; GetDiskFreeSpace(p, &spc, &bps, &fc, &tc); bps *= spc; wsprintf( buffer, " comp. length=%lu cluster=%lu total=%luK free=%luK\r\n", complen, bps, bps*tc/1024, bps*fc/1024); _lwrite(hf, buffer, lstrlen(buffer)); wsprintf(buffer, " file system ='%s' flags=", file_system); s = buffer + lstrlen(buffer); if (flags & FS_CASE_IS_PRESERVED) { lstrcpy(s, "CASE_PRESERVED "); s+= lstrlen(s);} if (flags & FS_CASE_SENSITIVE) { lstrcpy(s, "CASE_SENSITIVE "); s+= lstrlen(s);} if (flags & FS_UNICODE_STORED_ON_DISK) { lstrcpy(s, "UNICODE "); s+= lstrlen(s);} if (flags & FS_PERSISTENT_ACLS) { lstrcpy(s, "ACL "); s+= lstrlen(s);} if (flags & FS_FILE_COMPRESSION) { lstrcpy(s, "MAY_COMPRESS "); s+= lstrlen(s);} if (flags & FS_VOL_IS_COMPRESSED) { lstrcpy(s, "COMPRESSED "); s+= lstrlen(s);} lstrcpy(s, "\r\n"); _lwrite(hf, buffer, lstrlen(buffer)); } else { // если информация о томе не получена, то просто сообщаем lstrcpy( buffer+lstrlen(buffer), "' ***** NO VOLUME INFORMATION!\r\n");
Страницы: 1, 2, 3, 4, 5, 6, 7
|