№ | Поле OPENFILENAME | Содержимое |
lStructSize | Размер структуры (байт) | |
hwndOwner | Идентифицирует окно, соответствующее данному диалогу | |
lpstrFilter | Указатель на строку, где содержатся суффиксы – фильтры для ускоренного просмотра. Если суффиксов несколько, то между ними устанавливается разделитель – нулевой символ, а в конце строки расположены два нулевых символа. Соответствующая информация обычно указывается в файле ресурсов программы (например, "*.TXT *.DOC *.BAK"). Эти суффиксы должны разделяться символом «| », а вся строка заканчиваться нулевым символом | |
nFilterIndex | Показывает индекс конкретного суффикса – фильтра в строке lpstrFilter. Обычно это первый фильтр, поэтому указывают значение 1 | |
lpstrFile | Указывает на буферную строку, которая содержит имя файла. При использовании функцииGetOpenFileName или GetSaveFileName в этот буфер проводник поместит значения полного пути: от накопителя информации до имени файла в папке (включительно) | |
nMaxFile | Определяет размер буферной строки, на которую указывает поле lpstrFile (не менее 256 байт). Если эта строка мала, то функция GetOpenFileName() илиGetSaveFileName() выдаст значение FALSE | |
lpstrFileTitle | Указывает на буферную строку, куда будет помещен заголовок файла без полного пути | |
nMaxFileTitle | Указывает на максимальную длину буферной строки, куда помещается заголовок файла. Если lpstrFileTitleравен NULL, то параметр игнорируется | |
lpstrTitle | Указывает на строку с названием диалогового окна проводника. Если это поле равно NULL, то система использует свои названия по умолчанию (типа «Сохранить как» или «Открыть») | |
lpstrInitialDir | Указывает на строку, где содержится точка начала поиска в файловой системе (конкретная папка или др.) Если поле равно NULL, система начинает работу с текущей папки | |
Flags | Флаги, облегчающие работу с функциями Проводника: OFN_SHOWHELP – помещает в главное меню окна диалога кнопку Help; OFN_PATHMUSTEXIST – обеспечивает контроль правильности действий при указании имени файла и пути к нему во время работы. Проводник делает предупреждения, если пользователь указывает неправильные имена файлов или пути к ним; OFN_FILEMUSTEXIST – обеспечивает контроль правильности действий при указании имени файла. Проводник делает предупреждения, если пользователь указывает неправильные имена файлов |
Если в программе при выполнении функции GetOpenFileName или GetSaveFileName нет ошибок, то соответствующая функция возвращает значение TRUE.
|
Технология работы с Проводником. Создание программного интерфейса между приложением и функциями Проводника обычно состоит из 7 типовых этапов, которые описаны ниже.
Этап 1. Сначала нужно создать в меню (например, в главном меню) и в программе возможность выполнения команды пользователя. Например, в меню это будет кнопка Найти файл, а в программе – метка для соответствующей обработки типа
case IDM_FOPEN:
Значение константы IDM_FOPEN может быть любым, а имя ее может быть другим.
Этап 2. В глобальных переменных программы необходимо разместить системную структуру типа OPENFILENAME для работы Проводника. Назовем ее
OPENFILENAME ofn;
Этап 3. С помощью функции GetCurrentDirectory устанавливает программный интерфейс текущего процесса с конкретной папкой: либо это текущая папка, либо конкретное место в файловой системе (например, "C:\\"). Функция определяется как
|
DWORD GetCurrentDirectory(DWORD nBufferLength,
LPTSTR lpBuffer);
Параметр nBufferLength – это размер буфера для работы с папкой (байт). Указатель содержит адрес буфера для текущей директории.
Этап 4. Целесообразно установить «фильтры» для просмотра содержимого папок в соответствии с суффиксами, например, просматривать только doc-файлы, txt-файлы или какие-то другие. Это делается с помощью функции LoadString(), которая загружает строку ресурсов с фильтрами-суффиксами из исполняемого файла ресурсов, помещает в буфер и оформляет ее нулевыми символами-разделителями. Она определяется как
int LoadString(HINSTANCE hInstance, UINT uID,
LPTSTR lpBuffer, int nBufferMax);
Параметр hInstance – это дескриптор программного модуля, к которому относится строка ресурсов. Идентификатор ресурса указывается параметром uID. Адрес буфера для размещения строки ресурсов указывается параметром lpBuffer, а размер этого буфера задается параметром nBufferMax.
Этап 5. Применив функцию memset(), необходимо предварительно обнулить все поля системной структуры OPENFILENAME. В общем случае эта функция заполняет поля одним символом. Она определяется как
void *memset(void *dest, int c, size_t count);
Параметр dest – это адрес структуры OPENFILENAME. Целочисленный параметр c – это символ (в нашем случае 0). Параметр count определяет суммарную дляну заполняемых полей.
Этап 6. Необходимо заполнить соответствующие поля структуры OPENFILENAME управляющей информацией. Например:
OPENFILENAME ofn; // ofn – имя структуры
ofn.lpstrTitle = "Найти файл";
Этап 7. Только после этого можно выполнить функцию GetOpenFileName() для обращения к Проводнику, а после ее успешного выполнения (когда пользователь выбрал имя файла) – применить функцию fopen(), чтобы физически выполнить открытие файла и начать его обработку. Напоминаем, что функция fopen() определяется как
|
FILE *fopen(const char *filename, const *mode);
Параметр filename – это имя файла: либо имя в текущей директории, либо полный путь. Параметр mode задает один из режимов работы с файлом, которые показаны в таблице 13.2.
Функция fopen() возвращает заполненный дескриптор файла – структуру, которая должна быть предварительно определена как переменная типа FILE. После работы с файлом его необходимо закрыть с помощью функции
int fclose(FILE *streem);
Единственный параметр функции fclose – это дескриптор открытого файла.
Таблица 13.2
Режимы обработки файлов
№ | Параметр mode | Режим |
"r" | Открыть файл для чтения | |
"w" | Открыть файл для записи | |
"a" | Открыть файл для записи в конец файла (новая информация дописывается перед признаком EOF) | |
"r+" | Открыть файл как для чтения, так и для записи (к этому моменту файл должен существовать) | |
"w+" | Открыть файл как для чтения, так и для записи (если к этому моменту файл уже существует, то его содержимое будет утеряно) | |
"a+" | Открыть файл как для чтения, так и для записи в конец файла (новая информация дописывается перед признаком EOF) |
Пример 13-1. Программа работы с Проводником
В следующем примере в качестве каркаса используется программа, рассмотренная в примере 8-2. К ней дописаны описанные выше средства, демонстрирующие возможность работы с проводником.
Файл ресурсов Mydialog.rc после включения кнопки Найти файл теперь выглядит следующим образом:
#include <Windows.h>
#include "Text.h"
MYMENU MENU
{
MENUITEM "&Текст", ID_SHOW
MENUITEM "&Сначала", ID_RESET
MENUITEM "&Найти файл", ID_FOPEN
MENUITEM "Помощь", ID_HELP
}
MYMENU ACCELERATORS
{
VK_F2, ID_SHOW, VIRTKEY
VK_F3, ID_RESET, VIRTKEY
VK_F4, ID_FOPEN, VIRTKEY
VK_F1, ID_HELP, VIRTKEY
}
STRINGTABLE
{
ID_FILTERS "Word-файлы(*.DOC)|*.doc|
Текстовые файлы(*.TXT)|*.txt|
Все файлы (*.*)|*.*|"
}
Секция STRINGTABLE файла ресурсов может обслуживать несколько модулей (и несколько диалогов). Кроме строки IDS_FILTERS могут быть заданы и другие строки. Дело в том, что в разных модулях можно получать конкретную строку. Ее идентификатор – средство связи с программой.
Соответственно, изменится и вспомогательный файл Text.h:
#define ID_SHOW 100
#define ID_RESET 101
#define ID_FOPEN 102
#define ID_HELP 103
#define ID_FILTERS 104
Далее создаем структуру OPENFILENAME и опишем другие глобальные рабочие переменные:
OPENFILENAME ofn;
char filename[256]; // Полное имя файла (путь)
char szFile[256];
char szFilter[256];
UINT cbString;
char chReplace; // Разделитель строк для szFilter
char szFileTitle[256];
char szDirName[256];
FILE *stream; // Дескриптор файла
HINSTANCE hInst; // Дескриптор текущего приложения
Распишем команду Найти файл:
case ID_FOPEN:
GetCurrentDirectory(sizeof(szDirName), szDirName);
szFile[0]= '\0';
cbString = LoadString(hInst, ID_FILTERS, szFilter,
sizeof(szFilter));
chReplace= szFilter[cbString - 1];
for(i=0; szFilter[i]!= '\0'; i++)
if (szFilter[i] == chReplace)
szFilter[i] = '\0'; // Расст. разделителей
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrTitle = "Найти файл";
ofn.lpstrInitialDir = szDirName;
ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST |
OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn))
{
sprintf(filename,"%s", ofn.lpstrFile);
if((stream = fopen(filename,"r")) == NULL)
MessageBox(hwnd, "К Файлу нет доступа",
"Предупреждение:", MB_OK);
else
MessageBox(hwnd, "Файл найден(открыт)",
"Уведомление:", MB_OK);
}
InvalidateRect(hwnd,NULL,1); //Сообщить
break;
Полный текст примера программы, взаимодействующей с Проводником, представлен ниже. На рисунке 13.1 показаны результаты работы программы.
// Демонстрация работы с проводником,
// с использованием виртуального окна
#include <Windows.h>
#include <String.h>
#include <Stdio.h>
#include "Text.h"
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
char szWinName[] = "МоеОкно"; // Имя класса окна
char str[255]; // Буфер строки вывода
int X=0, Y=0; // Текущие координаты строки
int maxX, maxY; // Размеры экрана
HDC memdc; // DC виртуального окна
HBITMAP hbit; // Растр - это виртуальное окно
HBRUSH hbrush; // Дескриптор кисти
OPENFILENAME ofn;
char filename[256]; // Полное имя файла (путь)
char szDirName[256];
char szFile[256];
char szFilter[256];
UINT cbString;
char chReplace; // Разделитель строк для szFilter
char szFileTitle[256];
char szDirName[256];
FILE *stream; // Дескриптор файла
HINSTANCE hInst; // Дескриптор текущего приложения
int WINAPI WinMain (HINSTANCE hThisInst,
HINSTANCE hPrevInst,
LPSTR lpszArgs,
int nWinMode)
{
HWND hwnd;
MSG msg;
WNDCLASS wcl;
HACCEL hAccel;
// Определить класс окна
wcl.hInstance=hThisInst; // Дескриптор приложения
wcl.lpszClassName=szWinName; // Имя класса окна
wcl.lpfnWndProc=WindowFunc; // Функция окна
wcl.style=0; // Стиль по умолчанию
wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION); // Иконка
wcl.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор
wcl.lpszMenuName="MYMENU"; // Меню
wcl.cbClsExtra=0; // Без дополнительной
wcl.cbWndExtra=0; // информации
// Определить заполнение окна белым цветом
wcl.hbrBackground=
(HBRUSH)GetStockObject(WHITE_BRUSH);
if(!RegisterClass(&wcl)) // Зарегистр. класс окна
return 0;
// Создать окно
hwnd=CreateWindow(szWinName, // Имя класса
"Демонстрация работы с проводником",
WS_OVERLAPPEDWINDOW,// Стиль окна
CW_USEDEFAULT, // Х-координата
CW_USEDEFAULT, // Y-координата
CW_USEDEFAULT, // Ширина окна
CW_USEDEFAULT, // Высота окна
HWND_DESKTOP, // Нет родит. окна
NULL, // Нет меню
hThisInst, // Дескрип. приложения
NULL); // Без дополит. аргументов
hInst = hThisInst; // Сохр. дескриптор приложения
// Загрузить акселераторы
hAccel=LoadAccelerators(hThisInst,"MYMENU");
ShowWindow(hwnd,nWinMode); // Показать окно и
UpdateWindow(hwnd); // перерисовать содержимое
// Запустить цикл обработки сообщений
while(GetMessage (&msg,NULL,0,0))
if(!TranslateAccelerator(hwnd,hAccel,&msg))
{
TranslateMessage(&msg); // Использ.Клавиатуры
DispatchMessage (&msg); // Возврат к Windows
}
return msg. wParam;
}
// Следующая функция вызывается операционной системой
// Windows и получает в качестве параметров сообщения
// из очереди сообщений данного приложения
LRESULT CALLBACK WindowFunc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT paintstruct;
TEXTMETRIC tm;
SIZE size;
int i;
switch(message)
{
case WM_CREATE: // Получаем размеры экрана
maxX=GetSystemMetrics(SM_CXSCREEN);
maxY=GetSystemMetrics(SM_CYSCREEN);
hdc=GetDC(hwnd); // Совмест. с окном растр
memdc=CreateCompatibleDC(hdc);
hbit=CreateCompatibleBitmap(hdc,maxX,maxY);
SelectObject(memdc,hbit);
hbrush=(HBRUSH)GetStockObject(WHITE_BRUSH);
SelectObject(memdc,hbrush);
PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
ReleaseDC(hwnd,hdc);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_SHOW:
SetTextColor(memdc,RGB(0,0,0)); // Черн
SetBkColor(memdc,RGB(0,255,255)); //Син
GetTextMetrics(memdc,&tm); // Метрики
sprintf(str,
"Высота шрифта %ld пикселей",
tm.tmHeight);
TextOut(memdc,X,Y,str,strlen(str));
Y=Y+tm.tmHeight // Следующая
+tm.tmExternalLeading; // строка
strcpy(str,"Это следующая строка.");
TextOut(memdc,X,Y,str,strlen(str));
GetTextExtentPoint32(memdc,str, //Длина
strlen(str),
&size);
sprintf(str,
"Длина предыдущей строки %ld",
size.cx);
X=size.cx; // В конец предыдущей строки
TextOut(memdc,X,Y,str,strlen(str));
Y=Y+tm.tmHeight // Следующая
+tm.tmExternalLeading; // строка
X=0; // X опять в начало
sprintf(str,"Размеры экрана %d x %d",
maxX,maxY);
TextOut(memdc,X,Y,str,strlen(str));
Y=Y+tm.tmHeight // Следующая
+tm.tmExternalLeading; // строка
InvalidateRect(hwnd,NULL,1); //Сообщить
break;
case ID_RESET:
X=Y=0; // Стереть перерисовкой фона
PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
InvalidateRect(hwnd,NULL,1); //Сообщить
break;
case IDM_FOPEN:
GetCurrentDirectory(sizeof(szDirName),
szDirName);
szFile[0]= '\0';
cbString =LoadString(hInst,ID_FILTERS,
szFilter,
sizeof(szFilter));
chReplace=szFilter[cbString-1];
for(i=0; szFilter[i]!= '\0'; i++)
if(szFilter[i]==chReplace)
szFilter[i]='\0'; // Разделители
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter;
ofn.nFilterIndex= 1;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle =sizeof(szFileTitle);
ofn.lpstrTitle = "Найти файл";
ofn.lpstrInitialDir = szDirName;
ofn.Flags = OFN_SHOWHELP |
OFN_PATHMUSTEXIST |
OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn))
{
sprintf(filename,"%s",
ofn.lpstrFile);
if((stream=fopen(filename,"r"))
==NULL)
MessageBox(hwnd,
"К Файлу нет доступа",
"Предупреждение:",
MB_OK);
else
MessageBox(hwnd,
"Файл найден(открыт)",
"Уведомление:",
MB_OK);
}
InvalidateRect(hwnd,NULL,1); //Сообщить
break;
case ID_HELP:
MessageBox(hwnd,"F2: Вывести текст\n"
"F3: В начала экрана\n"
"F4: Найти файл",
"Помощь",MB_OK);
InvalidateRect(hwnd,NULL,1); //Сообщить
break;
}
break;
case WM_PAINT: // Перерисовка окна
hdc=BeginPaint(hwnd,&paintstruct); // Пол. DC
// Теперь копируем растр из памяти на экран
BitBlt(hdc,0,0,maxX,maxY,memdc,0,0,SRCCOPY);
EndPaint(hwnd,&paintstruct); // Освободить DC
break;
case WM_DESTROY: // Завершение программы
DeleteDC(memdc); // Удалить виртуальное окно
PostQuitMessage(0);
break;
default:
// Все сообщения, не обрабатываемые в данной
// функции, направляются на обработку по
// умолчанию
return DefWindowProc(hwnd,message,
wParam,lParam);
}
return 0;
}