Операционная система Microsoft Windows 3.1 для программиста -том 2

         

Файл listdir\listdir.cpp


// ---------------------------------------- // Использование органа управления // класса "listbox" для просмотра // содержимого каталога // ----------------------------------------

#define STRICT #include <windows.h>
#include <mem.h>
#include <dir.h>

// Идентификатор списка #define ID_LIST 1

// Идентификатор кнопки #define ID_BUTTON 2

// Прототипы функций BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

// Имя класса окна char const szClassName[] = "ListDirAppClass";

// Заголовок окна char const szWindowTitle[] = "Выбор файла";

// Идентификатор копии приложения HINSTANCE hInst;

// ===================================== // Функция WinMain // ===================================== #pragma argsused

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения

// Инициализируем приложение if(!InitApp(hInstance)) return FALSE;

// Сохраняем идентификатор копии приложения // в глобальной переменной hInst = hInstance;

// После успешной инициализации приложения создаем // главное окно приложения hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем расположение и размеры CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, // CW_USEDEFAULT, // 0, // идентификатор родительского окна 0, // идентификатор меню hInstance, // идентификатор приложения NULL);
// указатель на дополнительные // параметры // Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE;



// Рисуем главное окно ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam; }

// ===================================== // Функция InitApp // Выполняет регистрацию класса окна // =====================================


BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна

memset(&wc, 0, sizeof(wc));

wc.style = 0; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = (LPSTR)NULL; wc.lpszClassName = (LPSTR)szClassName;

// Регистрация класса aWndClass = RegisterClass(&wc);

return (aWndClass != 0);
}

// ===================================== // Функция WndProc // =====================================

LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Идентификатор органа управления "listbox" static HWND hListBox;

// Идентификатор кнопки static HWND hButton;

switch (msg) { case WM_CREATE: { // Создаем список hListBox = CreateWindow("listbox", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD | LBS_WANTKEYBOARDINPUT, 30, 30, 200, 200, hwnd, (HMENU) ID_LIST, hInst, NULL);

// Добавляем в список содержимое текущего // каталога

SendMessage(hListBox, LB_DIR, DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_DIRECTORY | DDL_DRIVES | DDL_ARCHIVE, (LPARAM)(LPSTR)"*.*");

// Создаем кнопку hButton = CreateWindow("button", "OK", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 250, 30, 50, 20, hwnd, (HMENU) ID_BUTTON, hInst, NULL);

return 0; }

// Когда главное окно приложения получает // фокус ввода, отдаем фокус списку case WM_SETFOCUS: { SetFocus(hListBox);
return 0; }

case WM_COMMAND: { // Обработка извещения списка об ошибке if(wParam == ID_LIST) { if(HIWORD(lParam) == (unsigned)LBN_ERRSPACE) { MessageBox(hwnd, "Мало памяти", szWindowTitle, MB_OK);
}

// Двойной щелчок по имени файла, каталога // или диска else if(HIWORD(lParam) == LBN_DBLCLK) { // Имитируем приход сообщения от кнопки SendMessage(hwnd, WM_COMMAND, ID_BUTTON, 0L);
return 0; }



// Если пользователь изменил выделенную // строку, выводим в окно новую // выделенную строку else if(HIWORD(lParam) == LBN_SELCHANGE) { int uSelectedItem, nSize; char Buffer[256]; HDC hdc;

// Определяем номер новой выделенной строки uSelectedItem = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0L);

if(uSelectedItem != LB_ERR) { // Получаем строку SendMessage(hListBox, LB_GETTEXT, uSelectedItem, (LPARAM)Buffer);

hdc = GetDC(hwnd);
nSize = lstrlen(Buffer);

TextOut(hdc, 250, 60, (LPSTR)" ", 25);
TextOut(hdc, 250, 60, (LPSTR)Buffer, nSize);

ReleaseDC(hwnd, hdc);
} } }

// Сообщение от кнопки else if(wParam == ID_BUTTON) { int uSelectedItem; char Buffer[256];

// Определяем номер выделенной строки uSelectedItem = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0L);

if(uSelectedItem != LB_ERR) { // Получаем выделенную строку SendMessage(hListBox, LB_GETTEXT, uSelectedItem, (LPARAM)Buffer);

// Если выбрали имя каталога или диска, // пытаемся изменить сначала текущий // каталог, а затем текущий диск if(Buffer[0] == '[') { // Выделяем в выбранной строке имя каталога Buffer[lstrlen(Buffer) - 1] = '\0';

// Пытаемся изменить каталог if(chdir(&Buffer[1]) != 0) { // Если не удалось, значит выбрали имя // диска. В этом случае выделяем букву // имени диска и добавляем строку ":\\: Buffer[3] = '\0'; lstrcat(Buffer, ":\\");

// Изменяем текущий каталог if(chdir(&Buffer[2]) == 0) { // Преобразуем букву диска AnsiLowerBuff(&Buffer[2], 1);

// Устанавливаем новый диск setdisk(Buffer[2] - 'a');
} }

// Сбрасываем содержимое списка SendMessage(hListBox, LB_RESETCONTENT, 0, 0L);

// Заполняем список информацией о файлах // и каталогах в текущем каталоге, а также // вносим туда имена дисков SendMessage(hListBox, LB_DIR, DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_DIRECTORY | DDL_DRIVES | DDL_ARCHIVE, (LPARAM)(LPSTR)"*.*");
}

// Если выбрали файл, выводим его имя на экран else { MessageBox(hwnd, Buffer, szWindowTitle, MB_OK);
} } } return 0; }



// Это сообщение поступает от списка, если он // имеет фокус ввода и пользователь работает // с клавиатурой case WM_VKEYTOITEM: { // Если пользователь нажал клавишу <Enter>
, // посылаем в окно сообщение WM_COMMAND с // параметром wParam, равным идентификатору // кнопки if(wParam == VK_RETURN) { SendMessage(hwnd, WM_COMMAND, ID_BUTTON, 0L);
} return -1; }

case WM_PAINT: { HDC hdc; PAINTSTRUCT ps;

hdc = BeginPaint(hwnd, &ps);

TextOut(hdc, 30, 10, "Выберите файл, каталог или диск", 31);

EndPaint(hwnd, &ps);
return 0; }

case WM_DESTROY: { PostQuitMessage(0);
return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam);
}

Функция WinMain приложения LISTDIR почти ничем не отличается от аналогичной функции предыдущего приложения. Она создает главное окно приложения и запускает цикл обработки сообщений.

Функция главного окна при обработке сообщения WM_CREATE создает одноколоночный список:

hListBox = CreateWindow("listbox", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD | LBS_WANTKEYBOARDINPUT, 30, 30, 200, 200, hwnd, (HMENU) ID_LIST, hInst, NULL);

Для заполнения этого списка именами файлов и каталогов, расположенных в текущем каталоге, а также именами дисков, списку посылается сообщение LB_DIR:

SendMessage(hListBox, LB_DIR, DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_DIRECTORY | DDL_DRIVES | DDL_ARCHIVE, (LPARAM)(LPSTR)"*.*");

Параметр wParam этого сообщения представляет собой набор флагов, влияющих на содержимое списка после заполнения. Приведем список этих флагов и соответствующих им имен объектов, включаемых в список.

Флаг Описание
DDL_ARCHIVE Файлы, для которых в байте атрибутов установлен бит архивирования
DDL_DIRECTORY Каталоги
DDL_DRIVES Дисковые устройства
DDL_EXCLUSIVE В список не будут включены имена обычных файлов
DDL_HIDDEN Скрытые файлы
DDL_READONLY Только читаемые файлы
DDL_READWRITE Файлы, над которыми можно выполнять операции чтения/записи, не имеющие дополнительных атрибутов
DDL_SYSTEM Системные файлы
<


Параметр lParam сообщения LB_DIR должен содержать указатель на текстовую строку, используемую в качестве шаблона имени. В нашем случае используется шаблон "*.*", поэтому в список попадают имена всех файлов.

Когда в функцию главного окна приложения приходит сообщение WM_COMMAND с извещением LBN_DBLCLK о двойном щелчке по строке списка, функция окна посылает сама себе сообщение WM_COMMAND с параметром wParam, равным идентификатору кнопки "OK", созданной приложением в главном окне справа от списка.

Извещение LBN_SELCHANGE обрабатывается таким же образом, что и в предыдущем приложении.

Обработчик сообщения от кнопки определяет номер выделенной строки и копирует эту строку в свой буфер, посылая в список последовательно сообщения LB_GETCURSEL и LB_GETTEXT. Далее выполняется анализ полученной строки.

Если строка начинается с символа "[", то это может быть либо имя каталога (например, "[dos]"), либо имя диска (например, "[-c-]"). Вначале обработчик предполагает, что получено имя каталога (для простоты мы считаем что каталоги с экзотическими именами "-c-" и т. п. не используются). Закрывающая квадратная скобка заменяется на двоичный ноль, вслед за чем вызывается функция chdir (из стандартной библиотеки компилятора), предназначенная для смены текущего каталога.

Если функция chdir вернула ненулевое значение, текущий каталог не содержит подкаталога с указанным именем. В этом случае обработчик сообщения считает, что полученная строка содержит имя диска, состоящее из буквы в обрамлении квадратных скобок и символов "-". Буква имени диска выделяется и к ней дописывается строка ":\\", вслед за чем выполняется повторная попытка изменения текущего каталога на корневой нового диска. Для изменения текущего диска вызывается функция setdisk из стандартной библиотеки компилятора.

Обратите внимание на способ, которым мы преобразуем букву обозначения диска:

AnsiLowerBuff(&Buffer[2], 1);

Мы использовали функцию AnsiLowerBuff, которая выполняет преобразование из заглавной буквы в прописную (маленькую) с учетом используемого национального алфавита.

После изменения текущего диска или каталога содержимое списка сбрасывается, вслед за чем список вновь наполняется именами файлов и каталогов:

SendMessage(hListBox, LB_RESETCONTENT, 0, 0L);
SendMessage(hListBox, LB_DIR, DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_DIRECTORY | DDL_DRIVES | DDL_ARCHIVE, (LPARAM)(LPSTR)"*.*");

Если обработчик так и не смог сменить каталог или диск, полученная от списка строка содержит имя файла. Это имя выводится на экран:

MessageBox(hwnd, Buffer, szWindowTitle, MB_OK);

Файл определения модуля приложения LISTDIR представлено в листинге 2.29.


Содержание раздела