Опубликован: 15.11.2010 | Доступ: свободный | Студентов: 643 / 18 | Оценка: 4.00 / 5.00 | Длительность: 17:30:00
Специальности: Программист
Лекция 9:

Ввод-вывод с использованием WinAPI

9.4. Приложение № I. Описание функций создания и открытия файлов

typedef struct tagOFSTRUCT
{
	BYTE	cBytes;
	BYTE	fFixedDisk;
	UINT	nErrCode;
	BYTE	reserved[4];
	char	szPathName[128];
} OFSTRUCT;

Поле cBytes содержит размер самой структуры OFSTRUCT в байтах.

С помощью поля fFixedDisk приложение может определить, находится ли открытый файл на жёстком диске, на флоппи-диске или другом съёмном носителе. Если содержимое этого поля отлично от нуля, то файл находится на жёстком диске.

Если при открытии файла произошла ошибка, в поле nErrCode записывается код ошибки. Возможные значения для кода ошибки приведены в приложении №I к книге [37].

Поле reserved зарезервировано, и не должно использоваться.

В поле szPathName находится полный путь к файлу в кодировке OEM.

9.5. Приложение № II. Основные опции стандартных диалогов GetOpenFileName и GetSaveFileName

typedef struct tagOFN
{
	DWORD	lStructSize;
	HWND  	hwndOwner;
	HINSTANCE	hInstance;
	LPCSTR	lpstrFilter;
	LPSTR  	lpstrCustomFilter;
	DWORD	nMaxCustFilter;
	DWORD 	nFilterIndex;
	LPSTR  	lpstrFile;
	DWORD  	nMaxFile;
	LPSTR  	lpstrFileTitle;
	DWORD 	nMaxFileTitle;
	LPCSTR	lpstrInitialDir;
	LPCSTR	lpstrTitle;
	DWORD 	Flags;
	UINT      	nFileOffset;
	UINT     	nFileExtension
	LPCSTR   	lpstrDefExt;
	LPARAM	lCustData;
	UINT      	(CALLBACK *lpfnHook) (HWND, UINT, WPARAM, LPARAM);
	LPCSTR 	lpTemplateName;
} OPENFILENAME;

В таблице 9.3 представлено назначение полей данной структуры. В таблице 9.4 представлено описание и расшифровка режимов вывода файлов, записанных в переменную Flags.

Таблица 9.3. Описание полей структуры OPENFILENAME
Структура: OPENFILENAME
Имя поля Назначение поля структуры
lStructSize Перед вызовом функций, использующих эту структуру, в это поле должен быть занесён размер структуры в байтах.
hwndOwner Поле должно содержать идентификатор окна, создающего диалоговую панель. Можно указать значение NULL, при этом диалоговое окно не будет иметь окна-владельца, но в этом случае будет нельзя использовать флаг OFN_SHOWHELP.
hInstance Поле hInstance используется перед вызовом функции для идентификации блока памяти, содержащего шаблон диалоговой панели. Содержимое поля игнорируется в том случае, если не указан флаг OFN_ENABLETEMPLATE или OFN_ENABLETEMPLATEHANDLE.
lpstrFilter В поле должен быть указан адрес текстовой строки, задающий фильтр для выбора имён файлов (шаблоны имён файлов). Фильтр должен состоять из одной или нескольких расположенных непосредственно друг за другом пар строк, закрытых двоичным нулём. Последняя строка должна иметь на конце два двоичных нуля. Первая строка в паре строк описывает название фильтра (например, "Text Files" ), а во второй строке из пары строк через знак ";" перечисляются возможные шаблоны для имён файлов.
lpsrCustomFilter В поле должен быть указан адрес текстовой строки, задающий фильтр для выбора имён файлов (шаблон для выбора файлов). Фильтр должен состоять из одной расположенных непосредственно друг за другом пары строк, закрытых двоичным нулём. Последняя строка должна иметь на конце два двоичных нуля. Первая строка в паре описывает название фильтра (например, "Text Files" ), а во второй строке пары через знак ";" перечисляются возможные шаблоны для имён файлов. Этот фильтр используется только в том случае, если в поле lpstrFilter содержится NULL.
nMaxCustFilter Определяет размер буфера в байтах, указанного в поле lpstrCustomFile. Размер этого буфера должен быть не меньше 40 байт.
nFilterIndex Поле определяет номер пары строк, используемых для фильтра, указанного в поле lpstrFilter или lpstrCustomFilter.
lpstrFile Поле должно содержать адрес текстовой строки, в которую будет записан полный путь к выбранному файлу. Если перед вызовом функций, использующих эту структуру, заполнить её значением, содержащем путь к файлу, этот путь будет выбран по-умолчанию при открытии диалоговых панелей "Open…" или "Save As…" ;
nMaxFile Поле должно содержать размер в байтах буфера, расположенного по адресу, указанного в поле lpstrFile. Размер этого буфера должен быть достаточным для записи полного пути к файлу. FAT16 запрещает использовать для указания пути строку более 128 символов. VFAT и другие файловые системы имеют большее предельное значение "путевого имени".
lpstrFileTitle В это поле необходимо записать адрес буфера, в который после выбора будет записано имя файла с расширением, но без пути к файлу. Это поле должно быть использовано приложением для отображения имени выбранного файла.
nMaxFileTitle Поле должно содержать размер указанного буфера (13 для файлов MS-DOS и Windows 16, и до 255 для Windows 32/64).
lpstrInitialDir Поле позволяет указать начальный каталог, который будет выбран для поиска файла сразу после отображения диалоговой панели: "Open…". Если нужно просмотреть файл в текущем каталоге, в это поле необходимо записать значение: NULL.
lpstrTitle В этом поле задаётся "нестандартный" заголовок панели, появляющийся при вызове функции. Если в этом поле содержится значение "NULL", используются заголовки по-умолчанию: "Open…" и "Save As…".
Flags Данное поле позволяет задать различные режимы выбора файла, влияющих на внешний вид диалоговых панелей. Описание этих флагов смотри в таблице D.4.???.
nFileOffset После возврата из функции это поле будет содержать смещение первого символа имени файла относительно начала буфера lpstrFile. Это поможет Вам "разделить" имя файла и путь к нему.
nFileExtension После возврата из функции это поле будет содержать смещение первого символа расширения имени файла относительно начала буфера lpstrFile.
lpstrDefExt Поле указывает на буфер, который содержит расширение имени файла, используемого по-умолчанию. Это расширение добавляется к имени выбранного файла, если при выборе расширения имя указано не было.
lCustData Значение, передаваемой функции фильтра через параметр lParam.
(CALLBACK *lpfnHook)(HWND,UINT, WPARAM, LPARAM ) Указатель на функцию фильтра, обрабатывающую сообщения для диалоговой панели. Функция будет вызываться только в том случае, если указан флаг OFN_ENABLEHOOK. Если фильтр не обрабатывал сообщение, он должен вернуть нулевое значение. Если же он вернёт значение, отличное от нуля, стандартная функция диалога не будет обрабатывать сообщение, которое уже обработано функцией фильтра.
lpTemplateName Идентификатор ресурса, содержащего шаблон диалоговой панели, используемого вместо шаблона, имеющегося в библиотеке commdlg.dll. Для ссылки на ресурс можно использовать макрокоманду MAKEINTRESORCE. Для использования альтернативного шаблона в поле Flags следует установить флаг OFN_ENABLETEMPLATE.
Таблица 9.4. Описание флагов структуры OPENFILENAME
Флаги структуры: OPENFILENAME
Флаг Описание
OFN_ALLOWMULTISELECT Разрешается выбор нескольких файлов одновременно. Если указан этот флаг, после выбора поле lpstrFile будет указывать на буфер, заполненный именами выбранных файлов (или путями к выбранным файлам), разделёнными пробелом.
OFN_CREATEPROMPT При использовании этого флага, если указанный файл не существует, создаётся диалоговая панель, в которой предлагается создать файл. Этот флаг устанавливается автоматически при использовании флагов OFN_PATHMUSTEXIST и OFN_FILEMUSTEXIST.
OFN_ENABLEHOOK Разрешается использовать функцию фильтра, адрес которой указан в поле lpfnHook.
OFN_ENABLETEMPLATE Если указан этот флаг, для создания диалоговой панели Windows будет использовать шаблон, определяемыйй содержимым полей hInstance и lpTemplateName.
OFN_ENABLETEMPLATEHANDLE При использоваении этого флага поле hInstance используется для идентификации блока памяти, содержащего предварительно загруженный шаблон диалоговой панели. В этом случае содержимое поля lpTemplateName игнорируется.
OFN_EXTENSIONDIFFERENT Устанавливается после возвращения из функции и указывает, что расширение файла отличается от заданного в поле lpstrDefExt. Этот флаг не устанавливается, если перед вызовом функции в поле lpstrDefExt было записано значение NULL, или если файл не имеет расширения имени.
OFN_FILEMUSTEXIST Можно выбирать только имена файлов, которые существуют. Если в поле "File Name" ("Имя файла") диалоговойц панели набрать имя несуществующего файла, на экране появится диалоговая панель с предупреждающим сообщением.
OFN_HIDEREADONLY Убрать переключатель "Read Only" ("Только чтение").
OFN_NOCHANGEDIR Для выбора используется каталог, который был текущем при вызове функции.
OFN_NOREADONLYRETURN Выбранные файлы не могут иметь атрибут "только чтение" или располагаться в защищённом от записи каталоге.
OFN_NOTESTFILECREATE Перед завершением работы диалоговой панели создание файла не выполняется. Не выполняются и проверки на переполнение диска, защиту записи или наличия доступа в сети.
OFN_NOVALIDATE В возвращаемом имени файла могут присутствовать неразрешённые символы.
OFN_OVERWRITEPROMPT Используется для диалоговой панели "Save as…". Если выбранный файл существует, на экран выводится диалоговая панель с предупреждением.
OFN_PATHMUSTEXIST Можно вводить только существующие пути к файлам.
OFN_READONLY После вызова функции переключатель "Read Only" ("Только чтение") будет находиться во включённом состоянии.
OFN_SHAREWARE Флаг устанавливается после возвращения из функции и указывает, что при вызове функции OpenFile произошла ошибка при совместном доступе к файлу в сети.
OFN_SHOWHELP Если указан этот флаг, то в диалоговой панели будет создана кнопка "Help" ("Справка"). Если указан это флаг, поле hwndOwner не должно содержать значения NULL.

9.6. Приложение № III

/* Файл INIT.CPP */
/**********************************************************
 * Каркас приложений Windows,
 * на основе которого можно строить более
 * сложные приложения MS WINDOWS.
 * Каркас использует правила для написани
 * программ на платформе Turbo C++ 3.1
 * 16-ти разрядных версий Windows.
 *
 * Более подробную информацию о "низкоуровневом" написании
 * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
 * Фролов, "Операционная система Microsoft Windows 3.1.
 * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
 * книги этих авторов.
**********************************************************/
#define STRICT
#include <windows.h>
#include <mem.h>
// Прототипы функций
// Первая функция - для инициализации
// приложения Windows, вторая функция -
// для обработки системных сообщений.
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
/* Значения класса и заголовка впоследствии нужно заменить */
// Имя класса окна
char const szClassName[]   = "WindowAppClass";
// Заголовок окна
char const szWindowTitle[] = "Window Application";
// =====================================
/***************************************
 * Функция WinMain
 * Получает управление при запуске
 * приложени
***************************************/
// =====================================
#pragma argsused
int PASCAL
WinMain(HINSTANCE hInstance,     // идентификатор текущей
				 // копии приложени
	HINSTANCE hPrevInstance, // идентификатор предыдущей
				 // копии приложени
	LPSTR     lpszCmdLine,   // указатель на командную строку
	int       nCmdShow)      // способ отображения главного
	                         // окна приложени
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложени
  // Проверяем, не запускалось ли это приложение ранее
//  if(!hPrevInstance)
//  {
    // Если не запускалось, вызываем функцию InitApp
    // для инициализации приложения.
/*****************************************************
 * Вызываем функцию InitApp
 * для инициализации приложения.
 * Если инициализацию выполнить не удалось,
 * завершаем приложение
*****************************************************/
    if(!InitApp(hInstance))
      return FALSE;
//  }
/****************************************************
 * После успешной инициализации приложения создаём
 * главное окно приложени
****************************************************/
  hwnd = CreateWindow(
    szClassName,         // имя класса окна (см. Выше )
    szWindowTitle,       // заголовок окна (см. Выше)
    WS_OVERLAPPEDWINDOW, // стиль окна
/****************************************************
 * В данном случае это перекрывающееся окно, но эту
 * опцию можно изменить для других типов окон
*****************************************************/
    CW_USEDEFAULT,       // задаём размеры и расположение
    CW_USEDEFAULT,       // окна, принятые по умолчанию
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    0,                   // идентификатор родительского окна
			// Для главного окна его менять нельз
    0,                   // идентификатор меню
/**********************************************************
 * В случае, если у окна необходимо создать меню, вместо
 * нуля сюда вставляется идентификатор меню (тип HMENU),
 * созданный с помощью функции LoadMenu.
 *
 * Если меню подключается как ресурс приложения в функции
 * InitApp, в этом поле также нужно оставить 0
**********************************************************/
    hInstance,           // идентификатор приложени
    NULL);               // указатель на дополнительные
			 // параметры
/**********************************************************
 * Далее код лучше не менять *
**********************************************************/
  // Если создать окно не удалось, завершаем приложение
  if(!hwnd)
    return FALSE;
/**********************************************************
 * В случае если Вам не нужно рисовать главное окно
 * приложения (например, Вы пишете программу мастер)
 * две нижеперечисленные функции:  ShowWindow и
 * UpdateWindow, указывать не надо
**********************************************************/
  // Рисуем окно. Для этого после функции ShowWindow, рисующей
  // окно, вызываем функцию UpdateWindows, посылающую
  // сообщение WM_PAINT в функцию окна
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);
/**********************************************************
 * Далее до конца функции код лучше не менять *
**********************************************************/
  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    DispatchMessage(&msg);
  }
  // Возвращаем значение WParam, переданное
  // в качестве параметра функции PostQuitMessage
  // в процессе инициирования завершения работы
  // приложения из функции окна.
  // Затем завершаем работу приложени
  return msg.wParam;
}
/* Конец функции WinMain *|
// =====================================
/**********************************************************
 * Функция InitApp
 * Вызывается из функции WinMain дл
 * инициализации приложения.
 * Выполняет регистрацию класса окна
**********************************************************/
// =====================================
BOOL InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна
  // Записываем нулевые значения во все поля структуры
  memset(&wc, 0, sizeof(wc));
  // Стиль окна
/**********************************************************
 * Поле style задаёт стиль класса окна и задаётся в виде
 * констант, описанных в файле <windows.h>. Описани
 * констант стилей начинается с префикса CS_. Стиль окна
 * задаёт реакцию окна на изменения его размера, на
 * выполнение в окне операции двойного щелчка мышью, а
 * также задаёт другие характеристики окна.
 * Если в главное окно предполагается вывод информации,
 * необходимо указать, по крайней мере:
 *   wc.style = CS_HREDRAW | CS_REDRAW;
 * в противном случае записать:
 *   wc.style = 0;
**********************************************************/
  wc.style = 0;
  // Указатель на функцию окна, обрабатывающую
  // сообщения, предназначенные для всех окон,
  // созданных на основе данного класса
  /* Желательно не менять! */
  wc.lpfnWndProc = (WNDPROC) WndProc;
  // Размер дополнительной области данных,
  // зарезервированной в описании класса окна
  /* Желательно не менять! */
  wc.cbClsExtra = 0;
  // Размер дополнительной области данных,
  // зарезервированной для каждого окна,
  // созданного на основе данного класса
  /* Желательно не менять! */
  wc.cbWndExtra = 0;
  // Идентификатор приложения, которое
  // создало данный класс
  /* Желательно не менять! */
  wc.hInstance = hInstance;
  // Идентификатор пиктограммы, используемой
  // для окно данного класса
/**********************************************************
 * Иконки создаются или "подгружаются" из специальных
 * файлов с "ресурсами", с помощью команды LoadIcon.
 * Первый параметр функции содержит идентификатор
 * приложения, в котором ищется иконка (значение NULL дл
 * системных областей), второй параметр задаёт имя ресурса-
 * пиктограммы. Если Вы не уверены, то этот параметр
 * менять не нужно.
**********************************************************/
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  // Идентификатор курсора, используемого
  // для окна данного класса
/**********************************************************
 * Курсоры создаются или "подгружаются" из специальных
 * файлов с "ресурсами", с помощью команды LoadCursor.
 * Первый параметр функции содержит идентификатор
 * приложения, в котором ищется курсор (значение NULL дл
 * системных областей), второй параметр задаёт имя ресурса-
 * курсора. Если Вы не уверены, то этот параметр менять
 * не нужно (оставляем стандартный курсор в виде стрелки).
**********************************************************/
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  // Цвет фона окна
  /* Желательно не менять, оставить системный цвет */
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  // Идентификатор меню
/**********************************************************
 * В случае если у окна необходимо создать меню, в это
 * поле нужно указать адрес текстовой строки, содержащей
 * имя шаблона меню в файле ресурсов. Все перекрывающиеся и
 * временные окна, созданные на базе этого класса, будут
 * иметь меню, определённое данным шаблоном. Пример:
 *  wc.lpszMenuName = "APP_MENU";
 * Если для идентификации шаблона использовать целые
 * числа, необходимо использовать макрокоманду
 * MAKEINTRESOURCE. Например, в файле описания ресурсов и в
 * файле исходного приложения определена константа:
 * #define APP_MENU 123
 * В этом случае строка примет вид:
 *  wc.lpszMenuName = MAKEINTRESOURCE( APP_MENU );
 * Если в окне меню не нужно, оставьте параметр без
 * изменения.
**********************************************************/
  wc.lpszMenuName = (LPSTR)NULL;
  /* Желательно не менять остальные операторы до конца
     функции */
  // Имя, которое присваивается создаваемому
  // классу и используется при создании
  // окон данного класса
  wc.lpszClassName = (LPSTR)szClassName;
  // Регистрация класса
  aWndClass = RegisterClass(&wc);
  // Возвращаем результат регистрации класса
  return (aWndClass != 0);
}
/* Файл WinProc.cpp */
#define STRICT
#include <windows.h>
#include <mem.h>
// =====================================
/**********************************************************
 * Функция WndProc
 * НЕ ВЫЗЫВАЕТСЯ ни из одной функции приложения.
 * Эту функцию вызывает Windows в процессе
 * обработки сообщений. Для этого адрес функции WndProc
 * указывается при регистрации класса окна.
 * Функция выполняет обработку сообщений главного
 * окна приложени
 *
 * Более подробную информацию о "низкоуровневом" написании
 * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
 * Фролов, "Операционная система Microsoft Windows 3.1.
 * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
 * книги этих авторов.
**********************************************************/
// =====================================
LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Выполняем обработку сообщений. Идентификатор
  // сообщения передаётся через параметр msg
  switch (msg)
  {
/**********************************************************
 * Это сообщение приходит, когда создаётся окно приложени
 * Здесь нужно вызвать контекст экрана, сохранить в
 * переменных его метрики и освободить его.
**********************************************************/

    case WM_CREATE:
    {
      // Получаем контекст отображения,
      // необходимый для определения метрик.
	return 0;
    }
/**********************************************************
 * Это сообщение приходит, когда "рисуется" окно приложения.
 * Здесь нужно вызвать контекст экрана, вывести необходимые
 * данные на экран, и освободить контекст.
**********************************************************/

    case WM_PAINT:
    {
      // Инициализируем текущую позицию вывода текста
      // Получаем контекст экрана
      // Освобождаем контекст экрана
         return 0;
    }
/*********************************************************
    // Это сообщение приходит, когда вы поместили курсор
    // мыши в область главного окна приложения и нажали
    // левую клавишу мыши
    case WM_LBUTTONDOWN:
      {
	return 0;
      }
    // Это сообщение приходит, когда вы поместили курсор
    // мыши в область главного окна приложения и нажали
    // правую клавишу мыши
    case WM_RBUTTONDOWN:
      {
	return 0;
      }
**********************************************************/
/**********************************************************
 * Это сообщение приходит, когда вы завершаете
 * работу приложения стандартным дл
 * Windows способом
**********************************************************/
    case WM_DESTROY:
    {
      // Инициируем завершение работы приложения,
      // помещая в очередь приложения сообщение
      // WM_QUIT. Это приведёт к завершению
      // цикла обработки сообщений в функции WinMain
      PostQuitMessage(0);
      return 0;
    }
  }
  // Все сообщения, которые не обрабатываются нашей
  // функцией окна, ДОЛЖНЫ передаваться функции
  // DefWindowProc
  return DefWindowProc(hwnd, msg, wParam, lParam);
}
/* Файл WINDOW.DEF */
; =============================
; Файл определения модул
; =============================
; Имя приложени
NAME WINDOW
; Описание приложени
DESCRIPTION 'Приложение WINDOW, (C) 1994, Frolov A.V.'
; Определение типа загрузочного модуля как
; приложения Windows
EXETYPE windows
; Программа, которая будет записана в начало файла
; приложения. Эта программа получит управление
; при попытке запуска приложения в среде MS-DOS
STUB 'winstub.exe'
; Размер стека в байтах
STACKSIZE 5120
; Размер локальной кучи памяти приложения в байтах
HEAPSIZE 1024
; Атрибуты сегмента кода
CODE preload moveable discardable
; Атрибуты сегмента данных
DATA preload moveable multiple
Дмитрий Карпов
Дмитрий Карпов
Россия, Нижний Новгород
Олег Корсак
Олег Корсак
Латвия, Рига