p align="left">_lwrite(hf, buffer, lstrlen(buffer));}} delete temp; // восстанавливаем режим обработки критических ошибок SetErrorMode(errmode);} else { // если возникла ошибка (не хватило памяти для получения списка устройств) // то просто выводим текст с сообщением, но не заканчиваем, что бы не // заботиться об уничтожении временного файла досрочно _lwrite(hf, "NOT ENOUGHT MEMORY TO GET INFORMATION!\r\n", 40);} // пишем второй заголовок _lwrite(hf, "\r\n******** READ DOS DEVICES MAP ********\r\n\r\n", 44); // просто для примера назначаем Z: как каталог, содержащий win.com GetWindowsDirectory(buffer, sizeof(buffer)); SetLastError(ERROR_SUCCESS); DefineDosDevice(0, devZ, buffer); if (GetLastError() != ERROR_SUCCESS) { // функция DefineDosDevice не реализована - это не Windows NT! _lwrite(hf, "NOTE: DefineDosDevice() is not implemented!\r\n", 45); } else { // если назначить удалось - это NT, получаем полный список и выводим его // хотя может быть и Windows 98 buffer[ QueryDosDevice(NULL, buffer, 1024) ] = `\0'; // функция QueryDosDevice возвращает число символов, скопированных в буфер // и в случае Windows 98 мы получим 0, хотя сам буфер может содержать мусор. for (p = buffer; *p; p += lstrlen(p) + 1) { _lwrite(hf, " ", 15 - lstrlen(p)); _lwrite(hf, p, lstrlen(p)); _lwrite(hf, " = ", 3); // используем массив file_system в качестве временной строки QueryDosDevice(p, file_system, sizeof(file_system)); _lwrite(hf, file_system, lstrlen(file_system)); _lwrite(hf, "\r\n", 2);} GetWindowsDirectory(buffer, sizeof(buffer)); // удаляем назначенное нами устройство DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, "Z:", buffer);} // узнаем длину файла с текстом и выделяем необходимый блок памяти n = _llseek(hf, 0L, 1); temp = new char [ (int)n + 1 ]; if (temp) { // загружаем его в память и добавляем оканчивающий символ `\0' _llseek(hf, 0L, 0); temp[ _lread(hf, temp, (int)n) ] = '\0'; // и передаем окну просмотра SetWindowText(hwndView, temp); // наш временный буфер больше не нужен delete temp; } else { // если памяти не хватило - сообщаем SetWindowText(hwndView, "*** Cannot load text ***");} // закрываем временный файл и удаляем его - система сама этого не сделает _lclose(hf); OpenFile(tempfile, &ofs, OF_DELETE); return TRUE;} 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);} void Cls_OnDestroy(HWND hwnd) {// при закрытии главного окна закрываем его дочернее (лучше это сделать // самим, хотя в крайнем случае система это сделает за вас) HWND hwndView = (HWND)GetWindowLong(hwnd, 0); if (IsWindow(hwndView)) DestroyWindow(hwndView); PostQuitMessage(0);} void Cls_OnSetFocus(HWND hwnd, HWND hwndOldFocus) {UNUSED_ARG(hwndOldFocus); // при получении фокуса главным окном - активируем окно просмотра, что бы // работала клавиатура HWND hwndView = (HWND)GetWindowLong(hwnd, 0); if (IsWindow(hwndView)) SetFocus(hwndView);} 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); default: break;} return DefWindowProc(hWnd, uMsg, wParam, lParam);} static BOOL init_instance(HINSTANCE hInstance) {WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 4; // для хендла окна просмотра wc.hInstance = hInstance; 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; if (!hPrevInst) { if (!init_instance(hInst)) return 1;} hWnd= CreateWindow( szWndClass, // class name "window header", // 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); while (GetMessage(&msg, NULL, NULL, NULL)) { TranslateMessage(&msg); DispatchMessage(&msg);} return msg.wParam;} Файл 2B16.CPP // включаем описания необходимых функций библиотеки времени выполнения #include <dos.h> #include <io.h> // функции GetLastError и SetLastError не описаны в Windows API, эмулируем их #define ERROR_SUCCESS 0 static int error_code = ERROR_SUCCESS; int GetLastError(void) {return error_code;} int SetLastError(int err) {int prev = error_code; return error_code = err;} // функция GetLogicalDriveStrings не реализована в Windows API, причем в некоторых // реализациях Win32 она представлена заглушкой, которую мы и эмулируем int GetLogicalDriveStrings(DWORD size, char* buf) {UNUSED_ARG(size); UNUSED_ARG(buf); SetLastError(1); return 0;} // функция GetLogicalDrives не реализована в Windows API, но нам она нужна // для нормальной работы приложения - эмулируем ее DWORD GetLogicalDrives(void) {DWORD dwDevices = 0L; unsigned n, uTotal, uCurrent, uTest; // запоминаем текущее устройство _dos_getdrive(&uCurrent); _dos_setdrive(uCurrent, &uTotal); for (n = 1; n <= uTotal; n++) _dos_setdrive(n, &uTotal); _dos_getdrive(&uTest); // если устройство удалось сделать текущим - оно описано в системе if (uTest == n) dwDevices // восстанавливаем прежнее устройство _dos_setdrive(uCurrent, &uTotal); return dwDevices;} // функция GetDriveType в Win32 API реализована несколько иначе, чем в Windows; // переопределим функцию Win32 API UINT GetDriveType(LPSTR) через функцию // Windows API UINT GetDriveType(UINT), заодно определим пару недостающих // символов #ifndef DRIVE_CDROM #define DRIVE_CDROM 5 #endif #ifndef DRIVE_RAMDISK #define DRIVE_RAMDISK 6 #endif UINT GetDriveType(char* pRoot) {char c; if (pRoot) { c = (char)AnsiUpper((LPSTR)(DWORD)(UINT)(unsigned char)(pRoot[ 0 ])); if (c >= 'A' && c <= 'Z') return GetDriveType(c - 'A');} return 0;} // функция GetVolumeInformation не определена в Windows API. Эмулируем ее // в сильно упрощенном виде, заодно определяем необходимые символы. #define FS_CASE_IS_PRESERVED 1 #define FS_CASE_SENSITIVE 2 #define FS_UNICODE_STORED_ON_DISK 4 #define FS_PERSISTENT_ACLS 16 #define FS_FILE_COMPRESSION 32 #define FS_VOL_IS_COMPRESSED 64 BOOL GetVolumeInformation( char *pRoot, char* pVolume, int cbVolume, DWORD *sernum, DWORD *complen, DWORD *flags, char *pFS, int cbFS) {BOOL fReturnCode = FALSE; char c; unsigned uDrive, uCurrent, n; UNUSED_ARG(cbVolume); UNUSED_ARG(cbFS); if (pRoot) { c= (char)AnsiUpper((LPSTR)(DWORD)(UINT)(unsigned char)(pRoot[ 0 ])); if (c >= 'A' && c <= 'Z') { uDrive = (unsigned)(c - 'A' + 1); _dos_getdrive(&uCurrent); _dos_setdrive(uDrive, &n); _dos_getdrive(&n); if (uDrive == n) {// убедимся, что устройство определено // строго говоря все это стоит определить точнее: pVolume[0] = '\0'; *sernum = 0L; *complen = 12; *flags = (long)FS_CASE_IS_PRESERVED; pFS = '\0'; // проверим, есть ли доступ к устройству - если мы вернем // TRUE, то позже нами будет предпринята попытка узнать // размер тома if (!access(pRoot, F_OK)) fReturnCode = TRUE;} // восстановим текущее устройство _dos_setdrive(uCurrent, &n);}} return fReturnCode;} // функция GetDiskFree не определена в Windows API, эмулируем ее посредством // функции _dos_getdiskfree стандартной библиотеки времени выполнения. void GetDiskFreeSpace(char* pRoot, DWORD* spc, DWORD* bps, DWORD* fc, DWORD* tc) {char c; diskfree_t df; if (pRoot) { c = (char)AnsiUpper((LPSTR)(DWORD)(UINT)(unsigned char)(pRoot[ 0 ])); if (c >= 'A' && c <= 'Z') { if (!_dos_getdiskfree(c - 'A' + 1, &df)) { *spc = df.sectors_per_cluster; *bps = df.bytes_per_sector; *fc = df.avail_clusters; *tc = df.total_clusters;}}}} // функции DefineDosDevice и QueryDosDevice не реализованы в Windows API. // используем вместо них заглушки, так как они имеют смысл только для NT #define DDD_REMOVE_DEFINITION 1 #define DDD_EXACT_MATCH_ON_REMOVE 2 BOOL DefineDosDevice(DWORD dwFlags, LPSTR lpDosDevice, LPSTR lpPath) {UNUSED_ARG(dwFlags); UNUSED_ARG(lpDosDevice); UNUSED_ARG(lpPath); SetLastError(1); return FALSE;} DWORD QueryDosDevice(LPSTR lpDosDevice, LPSTR lpPath, DWORD ucchMax) {UNUSED_ARG(lpDosDevice); UNUSED_ARG(lpPath); UNUSED_ARG(ucchMax); SetLastError(1); return 0L;} Резюме Любопытно, что в существующем виде приложение по-разному работает на разных платформах -- для получения информации о томах и доступном пространстве предпринимается попытка чтения с устройства. Однако том в устройстве может отсутствовать вовсе -- например, в дисководе может не быть дискеты. Разные платформы реагируют на такое событие разным образом -- Windows-95, убедившись что тома нет, просто возвращает нули, а Windows NT или Windows 3.x выдают сообщение о системной ошибке. В приложении специально применяется функция SetErrorMode, которая позволяет отключить вывод сообщений о невозможности чтения с диска. Любопытно, что в документации часто указано, что эта функция для Win32 API реализована только для RISC процессоров -- странно, но на обычных Intel Pentium она тоже сработала. В пояснениях к результатам теста реакция системы на критические ошибки приводится так, как будто эта функция не применяется. На самом деле в приведенном приложении (с применяемой функцией SetErrorMode) сообщений об ошибках не будет.
Страницы: 1, 2, 3, 4, 5, 6, 7
|