Графический интерфейс GDI в Microsoft Windows
5b239685

Приложение PRNFILE


Для иллюстрации всего сказанного выше мы немного изменили приложение TEDIT, описанное в 12 томе "Библиотеки системного программиста", добавив в него возможность печати. В главном окне этого простейшего редактора текста появилась кнопка "Print", с помощью которой вы можете распечатать текст на любом установленном в системе принтере (рис. 6.5).

Рис. 6.5. Главное окно приложения PRNFILE

Исходный основного файла приложения приведен в листинге 6.1.

Листинг 6.1. Файл prnfile/prnfile.cpp

// ---------------------------------------- // Редактор текстовых файлов с возможностью печати // ----------------------------------------

#define STRICT #include <windows.h> #include <commdlg.h> #include <mem.h> #include <string.h> #include <stdlib.h>

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

// Идентификаторы кнопок #define ID_NEW 2 #define ID_OPEN 3 #define ID_SAVE 4 #define ID_PRINT 5 #define ID_EXIT 6

// Прототипы функций BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM); HFILE OpenFile(void); HFILE OpenSaveFile(void); int PrintFile(HWND, NPSTR, WORD);

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

// Заголовок окна char const szWindowTitle[] = "Text Editor";

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



// Флаг изменений в тексте BOOL bUpdate;

// ===================================== // Функция 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) { // Идентификатор редактора текста static HWND hEdit;

// Идентификаторы кнопок static HWND hButtNew; static HWND hButtOpen; static HWND hButtSave; static HWND hButtPrint; static HWND hButtExit;

// Идентификаторы файлов static HFILE hfSrcFile, hfDstFile;

switch (msg) { case WM_CREATE: { // Создаем редактор текста hEdit = CreateWindow("edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0, 0, 0, 0, hwnd, (HMENU) ID_EDIT, hInst, NULL);

// Устанавливаем максимальную длину // редактируемого текста, равную 32000 байт SendMessage(hEdit, EM_LIMITTEXT, 32000, 0L);

// Сбрасываем флаг обновления текста bUpdate = FALSE;

// Создаем кнопки hButtNew = CreateWindow("button", "New", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, 80, 20, hwnd, (HMENU) ID_NEW, hInst, NULL);



hButtOpen = CreateWindow("button", "Open", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 80, 0, 80, 20, hwnd, (HMENU) ID_OPEN, hInst, NULL);

hButtSave = CreateWindow("button", "Save", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 160, 0, 80, 20, hwnd, (HMENU) ID_SAVE, hInst, NULL);

hButtPrint = CreateWindow("button", "Print", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 240, 0, 80, 20, hwnd, (HMENU) ID_PRINT, hInst, NULL);

hButtExit = CreateWindow("button", "Exit", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 320, 0, 80, 20, hwnd, (HMENU) ID_EXIT, hInst, NULL);

return 0; }

case WM_SIZE: { // Устанавливаем размер органа управления // (текстового редактора) в соответствии // с размерами главного окна приложения MoveWindow(hEdit, 0, 20, LOWORD(lParam), HIWORD(lParam) - 20, TRUE); return 0; }

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

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

// Произошло изменение в редактируемом // тексте else if(HIWORD(lParam) == EN_UPDATE) { // Устанавливаем флаг обновления текста bUpdate = TRUE; } return 0; }

// Нажата кнопка сохранения текста else if(wParam == ID_SAVE) { WORD wSize; HANDLE hTxtBuf; NPSTR npTextBuffer;

// Открываем выходной файл hfDstFile = OpenSaveFile(); if(!hfDstFile) return 0;

// Определяем размер текста wSize = GetWindowTextLength(hEdit);

// Получаем идентификатор блока памяти, // в котором находится редактируемый текст hTxtBuf = (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);

// Фиксируем блок памяти и получаем указатель // на него npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

// Записываем содержимое блока памяти в файл if(wSize != _lwrite(hfDstFile, npTextBuffer, wSize)) { // При ошибке закрываем файл и выдаем сообщение _lclose(hfDstFile); MessageBox(hwnd, "Ошибка при записи файла", szWindowTitle, MB_OK); return 0; }



// Закрываем файл _lclose(hfDstFile);

// Расфиксируем блок памяти LocalUnlock(hTxtBuf);

// Так как файл был только что сохранен, // сбрасываем флаг обновления bUpdate = FALSE;

SetFocus(hEdit); return 0; }

// Создание нового файла else if(wParam == ID_NEW) { // Проверяем флаг обновления if(bUpdate) { if(IDYES == MessageBox(hwnd, "Файл был изменен. Желаете сохранить?", szWindowTitle, MB_YESNO | MB_ICONQUESTION)) return 0; }

// Сбрасываем содержимое текстового редактора SetWindowText(hEdit, "\0");

// Сбрасываем флаг обновления bUpdate = FALSE;

SetFocus(hEdit); return 0; }

// Загрузка файла для редактирования else if(wParam == ID_OPEN) { LPSTR lpTextBuffer; DWORD dwFileSize, dwCurrentPos;

// Проверяем флаг обновления if(bUpdate) { if(IDYES == MessageBox(hwnd, "Файл был изменен. Желаете сохранить?", szWindowTitle, MB_YESNO | MB_ICONQUESTION)) return 0; }

// Открываем входной файл. hfSrcFile = OpenFile(); if(!hfSrcFile) return 0;

// Определяем размер файла dwCurrentPos = _llseek(hfSrcFile, 0L, 1); dwFileSize = _llseek(hfSrcFile, 0L, 2); _llseek(hfSrcFile, dwCurrentPos, 0);

// Размер файла не должен превосходить 32000 байт if(dwFileSize >= 32000) { _lclose(hfSrcFile); MessageBox(hwnd, "Размер файла больше 32000 байт", szWindowTitle, MB_OK); return 0; }

// Заказываем память для загрузки файла lpTextBuffer = (LPSTR)malloc(32000); if(lpTextBuffer == NULL) return 0;

// Загружаем текст из файла в буфер _lread(hfSrcFile, lpTextBuffer, dwFileSize);

// Закрываем буфер двоичным нулем lpTextBuffer[(WORD)dwFileSize] = '\0';

// Закрываем файл _lclose(hfSrcFile);

// Переносим содержимое буфера в // текстовый редактор SetWindowText(hEdit, lpTextBuffer);

// Освобождаем буфер free((void *)lpTextBuffer);

// сбрасываем флаг обновления bUpdate = FALSE;

SetFocus(hEdit); return 0; }

// ------------------------------------------ // Печать текста // ------------------------------------------ else if(wParam == ID_PRINT) { WORD wSize; HANDLE hTxtBuf; NPSTR npTextBuffer;



// Определяем размер текста wSize = GetWindowTextLength(hEdit);

// Получаем идентификатор блока памяти, // в котором находится редактируемый текст hTxtBuf = (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);

// Фиксируем блок памяти и получаем указатель // на него npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

PrintFile(hwnd, npTextBuffer, wSize);

// Расфиксируем блок памяти LocalUnlock(hTxtBuf);

SetFocus(hEdit); return 0; }

else if(wParam == ID_EXIT) { // Проверяем флаг обновления if(bUpdate) { if(IDYES == MessageBox(hwnd, "Файл был изменен. Желаете сохранить?", szWindowTitle, MB_YESNO | MB_ICONQUESTION)) return 0; }

// Посылаем в функцию главного окна // сообщение WM_CLOSE SendMessage(hwnd, WM_CLOSE, 0, 0L); return 0; } return 0; }

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

// ------------------------------- // Функция OpenFile // Сохранение файла // -------------------------------

HFILE OpenFile(void) { // Структура для выбора файла OPENFILENAME ofn;

// Буфер для записи пути к выбранному файлу char szFile[256];

// Буфер для записи имени выбранного файла char szFileTitle[256];

// Фильтр расширений имени файлов char szFilter[256] = "Text Files\0*.txt;*.doc\0Any Files\0*.*\0";

// Идентификатор открываемого файла HFILE hf;

// Инициализация имени выбираемого файла // не нужна, поэтому создаем пустую строку szFile[0] = '\0';

// Записываем нулевые значения во все поля // структуры, которая будет использована для // выбора файла memset(&ofn, 0, sizeof(OPENFILENAME));

// Инициализируем нужные нам поля

// Размер структуры ofn.lStructSize = sizeof(OPENFILENAME);

// Идентификатор окна ofn.hwndOwner = NULL;

// Адрес строки фильтра ofn.lpstrFilter = szFilter;

// Номер позиции выбора ofn.nFilterIndex = 1;

// Адрес буфера для записи пути // выбранного файла ofn.lpstrFile = szFile;

// Размер буфера для записи пути // выбранного файла ofn.nMaxFile = sizeof(szFile);

// Адрес буфера для записи имени // выбранного файла ofn.lpstrFileTitle = szFileTitle;



// Размер буфера для записи имени // выбранного файла ofn.nMaxFileTitle = sizeof(szFileTitle);

// В качестве начального каталога для // поиска выбираем текущий каталог ofn.lpstrInitialDir = NULL;

// Определяем режимы выбора файла ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; // Выбираем входной файл if (GetOpenFileName(&ofn)) {

// Открываем выбранный файл hf = _lopen(ofn.lpstrFile, OF_READ);

// Возвращаем идентификатор файла return hf; } // При отказе от выбора возвращаем // нулевое значение else return 0; }

// ------------------------------- // Функция OpenSaveFile // Выбор файла для редактирования // -------------------------------

HFILE OpenSaveFile(void) { OPENFILENAME ofn;

char szFile[256]; char szFileTitle[256]; char szFilter[256] = "Text Files\0*.txt\0Any Files\0*.*\0";

HFILE hf;

szFile[0] = '\0'; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = NULL; ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = sizeof(szFileTitle); ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_HIDEREADONLY;

// Выбираем выходной файл if (GetSaveFileName(&ofn)) {

// При необходимости создаем файл hf = _lcreat(ofn.lpstrFile, 0); return hf; } else return 0; }

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

Когда вы нажимаете кнопку "Print", соответствующий обработчик определяет размер текста, загруженного в редактор, вызывая функцию GetWindowTextLength:

wSize = GetWindowTextLength(hEdit);

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

hTxtBuf = (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L); npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

После этого вызывается функция печати PrintFile, определенная в файле print.cpp (листинг 6.2):

PrintFile(hwnd, npTextBuffer, wSize);



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

После выполнения печати буфер расфиксируется, после чего редактор текста получает фокус ввода:

LocalUnlock(hTxtBuf); SetFocus(hEdit); return 0;

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

Листинг 6.2. Файл prnfile/print.cpp

// ---------------------------------------------------- // Функции для работы с принтером // ---------------------------------------------------- #define STRICT #include <windows.h> #include <windowsx.h> #include <commdlg.h> #include <string.h> #include "prnfile.hpp"

// Прототипы функций BOOL CALLBACK _export AbortDlgFunc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);

BOOL CALLBACK _export AbortFunc(HDC hdc, int nCode); HDC GetPrinterDC(HWND);

// Внешние глобальные переменные extern HWND hdlgAbort; extern BOOL fAbort;

BOOL fAbort = FALSE; HWND hdlgAbort = 0; static PRINTDLG pd;

// ---------------------------------------------------- // Функция PrintFile // Печать файла // ----------------------------------------------------

BOOL PrintFile(HWND hwnd, NPSTR npBuff, WORD wSize) { HDC hdc; int cyPage; int cyChar, yPos, nLength; int i; WORD wCurPos = 0; TEXTMETRIC tm;

ABORTPROC lpAbortFunc; BOOL fDone; char abBuffer[256]; DOCINFO docinfo; DLGPROC lpAbortDlgFunc; HINSTANCE hInst; int rc;

// Получаем контекст устройства для принтера hdc = GetPrinterDC(hwnd);

// Определяем разрешение принтера по вертикали cyPage = GetDeviceCaps(hdc, VERTRES);

// Определяем метрики текста GetTextMetrics(hdc, &tm);

// Вычисляем высоту шрифта cyChar = tm.tmHeight + tm.tmExternalLeading;

// Создаем переходник для функции AbortFunc hInst = GetWindowInstance(hwnd); lpAbortFunc = (ABORTPROC)MakeProcInstance((FARPROC)AbortFunc, hInst);

// Устанавливаем функцию AbortProc rc = SetAbortProc(hdc, lpAbortFunc); if(rc <= 0) { DeleteDC(hdc); return FALSE; }



// Создаем переходник для функции диалога lpAbortDlgFunc = (DLGPROC)MakeProcInstance((FARPROC)AbortDlgFunc, hInst);

// Создаем диалог для отмены печати hdlgAbort = CreateDialogParam ( hInst, MAKEINTRESOURCE(IDD_ABORT), hwnd, lpAbortDlgFunc, NULL) ;

if(!hdlgAbort) { FreeProcInstance((FARPROC)lpAbortFunc); DeleteDC(hdc); return FALSE; }

// Отображаем созданную диалоговую панель ShowWindow(hdlgAbort, SW_SHOWNORMAL); UpdateWindow(hdlgAbort);

// Переводим окно приложения в неактивное // состояние EnableWindow(hwnd, FALSE);

// Заполняем структуру docinfo docinfo.cbSize = sizeof(docinfo); docinfo.lpszDocName = NULL; docinfo.lpszOutput = NULL;

// Начинаем печать документа rc = StartDoc(hdc, &docinfo); if(rc <= 0) { DestroyWindow(hdlgAbort); FreeProcInstance((FARPROC)lpAbortFunc); FreeProcInstance((FARPROC)lpAbortDlgFunc); DeleteDC(hdc); return FALSE; }

// Флаг завершения печати документа fDone = FALSE;

// Цикл печати страниц документа while(!fDone && !fAbort) { // Начинаем печать страницы документа StartPage(hdc);

// Начальная позиция по вертикали yPos = 0;

// Цикл по строкам страницы while(yPos + cyChar < cyPage) { // Проверка завершения печати страницы if(wCurPos > wSize) { fDone = TRUE; break; }

i=0; nLength = 0;

// Цикл по строке // Копируем строку в буфер abBuffer while((npBuff[wCurPos] != 0x0d) && (wCurPos < wSize)) { abBuffer[i] = npBuff[wCurPos]; i++; wCurPos++; nLength++; }

// Рисуем одну строку текста TextOut(hdc, 0, yPos, abBuffer, nLength);

// Переходим к следующей строке wCurPos += 2; yPos += cyChar ; }

// Инициируем печать страницы rc = EndPage(hdc); if(rc < 0) { fAbort = TRUE; break; } }

// При аварийном завершении печати вызываем // функцию AbortDoc, при нормальном - EndDoc if(fAbort) AbortDoc(hdc); else EndDoc(hdc);

// Активизируем главное окно приложения EnableWindow(hwnd, TRUE);

// Удаляем диалоговую панель DestroyWindow(hdlgAbort);

// Освобождаем ресурсы FreeProcInstance((FARPROC)lpAbortFunc); FreeProcInstance((FARPROC)lpAbortDlgFunc); DeleteDC(hdc);



return TRUE ; }

// ---------------------------------------------------- // Функция AbortDlgFunc // Функция диалога для диалоговой панели, // позволяющей прервать процесс печати // ---------------------------------------------------- #pragma argsused

BOOL CALLBACK _export AbortDlgFunc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { // Инициализируем флаги case WM_INITDIALOG: { fAbort = FALSE; hdlgAbort = hdlg; return TRUE; }

case WM_COMMAND: { // Устанавливаем флаг аварийного завершения печати if (wParam == IDOK wParam == IDCANCEL) { fAbort = TRUE; return TRUE; } return FALSE; }

case WM_DESTROY: { hdlgAbort = 0; return FALSE; } } return FALSE; }

// ---------------------------------------------------- // Функция AbortFunc // Обеспечивает возможность работы других // приложений во время печати // ---------------------------------------------------- #pragma argsused

BOOL CALLBACK _export AbortFunc(HDC hdc, int nCode) { MSG msg;

// Второй цикл обработки сообщений while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if(!hdlgAbort !IsDialogMessage (hdlgAbort, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }

return(!fAbort); }

// ---------------------------------------------------- // Функция GetPrinterDC // Выводит на экран диалоговую панель "Print", // с помощью которой можно выбрать принтер. // Возвращает идентификатор контекста для // выбранного принтера // ----------------------------------------------------

HDC GetPrinterDC(HWND hwnd) { BOOL fResult;

// Инициализируем структуру PRINTDLG memset(&pd, 0, sizeof(PRINTDLG));

pd.lStructSize = sizeof(PRINTDLG); pd.hwndOwner = hwnd; pd.Flags = PD_RETURNDC;

// Отображаем диалоговую панель fResult = PrintDlg(&pd);

// При необходимости освобождаем память, полученную // функцией PrintDlg для структур DEVMODE и DEVNAMES if(pd.hDevMode != 0) GlobalFree (pd.hDevMode);

if(pd.hDevNames != 0) GlobalFree (pd.hDevNames);

// В случае успешного завершения возвращаем // контекст принтера if(fResult) return pd.hDC;



else return 0; }

Функция PrintFile выполняет печать файла, загруженного в текстовый редактор.

Она получает контекст печати, вызывая функцию GetPrinterDC, определенную в этом же файле. Функция GetPrinterDC выводит на экран стандартную диалоговую панель "Print", позволяющую выбрать принтер и задать параметры для выбранного принтера.

Далее определяется разрешение принтера по вертикали, метрики текста для шрифта, выбранного в контекст принтера, вычисляется высота шрифта. Вся эта информация необходима для правильного расположения строк текста на листе бумаги.

После этого функция PrintFile создает переходник для функции отмены печати и подключает последнюю, вызывая функцию SetAbortProc.

Далее создается переходник для функции диалога отмены печати, затем создается и выводится на экран диалоговая панель отмены печати. Шаблон диалоговой панели определен в файле ресурсов и содержит единственную кнопку с надписью "Cancel".

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

Перед началом печати заполняется структура DOCINFO и вызывается функция StartDoc.

В цикле печати страниц документа выполняется проверка глобального флага отмены печати, а также флага завершения печати fDone.

Перед началом печати каждой страницы вызывается функция StartPage.

Далее выполняется построчное копирование текста из буфера текстового редактора в буфер abBuffer с последующим выводом содержимого этого буфера на принтер функцией TextOut.

Печать страницы выполняется после вызова функции EndPage.

При нормальном завершении процесса печати вызывается функция EndDoc, а при аварийном - AbortDoc.

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

Идентификатор диалоговой панели определен в файле prnfile.hpp (листинг 6.3).



Листинг 6.3. Файл prnfile/prnfile.hpp

#define IDD_ABORT 25

Шаблон диалоговой панели отмены печати определен в файле описания ресурсов приложения (листинг 6.4).

Листинг 6.4. Файл prnfile/prnfile.rc

#include <g:\tcwin\include\windows.h> #include "prnfile.hpp"

IDD_ABORT DIALOG 50, 30, 89, 43 STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU CAPTION "Печать..." BEGIN CONTROL "Cancel", IDCANCEL, "BUTTON", WS_GROUP, 29, 23, 32, 14 CTEXT "Cancel - отмена печати", -1, -1, 8, 90, 8, WS_CHILD | WS_VISIBLE | WS_GROUP END

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

Листинг 6.5. Файл prnfile/prnfile.def

; ============================= ; Файл определения модуля ; ============================= NAME PRNFILE DESCRIPTION 'Приложение PRNFILE, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 5120 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple


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