Операционная система Microsoft Windows 3.1 для программиста. Дополнительные главы

Файл cliptxt/cliptxt.cpp


// ---------------------------------------- // Запись данных в текстовом формате в Clipboard // и чтение текстовых данных из Clipboard // ---------------------------------------- #define STRICT #include <windows.h>
#include <mem.h>
#include "cliptxt.hpp"

BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

char const szClassName[] = "CliptxtClass"; char const szWindowTitle[] = "Clipboard Demo"; char const szClipboardText[] = "Этот текст будет записан\r\n" "в универсальный буфер обмена Clipboard\r\n" "приложением CLIPTXT";

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

// Разрешаем запуск нескольких копий приложения if(!hPrevInstance) if(!InitApp(hInstance)) return FALSE;

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.lpszMenuName = "APP_MENU"; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "APP_ICON");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = (LPSTR)szClassName;




aWndClass = RegisterClass(&wc);
return (aWndClass != 0);
}



// ===================================== // Функция WndProc // ===================================== LRESULT CALLBACK _export WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rc;

static HGLOBAL hglbTextCopyBuf; LPSTR lpTextCopy; static HGLOBAL hglbTextPasteBuf; LPSTR lpTextPaste; static HGLOBAL hglbClipBuf; LPSTR lpClipBuf;

switch (msg) { case WM_CREATE: { // Заказываем буфер для хранения текста, // прочитанного из Clipboard. // Начальный размер этого буфера - 1 байт hglbTextPasteBuf = GlobalAlloc(GHND, 1);
if(hglbTextPasteBuf == NULL) return -1;

// Фиксируем буфер в памяти и получаем его адрес lpTextPaste = (LPSTR)GlobalLock(hglbTextPasteBuf);
if(hglbTextPasteBuf == NULL) return -1;

// Записываем в буфер пустую строку lpTextPaste[0] = '\0';

// Расфиксируем буфер GlobalUnlock(hglbTextPasteBuf);
return 0; } case WM_PAINT: { hdc = BeginPaint(hwnd, &ps);

// Фиксируем текстовый буфер в памяти, // в случае успеха отображаем его содержимое // во внутренней области главного окна lpTextPaste = (LPSTR)GlobalLock(hglbTextPasteBuf);
if(lpTextPaste != NULL) { GetClientRect(hwnd, &rc);
DrawText(hdc, lpTextPaste, -1, &rc, DT_LEFT | DT_EXPANDTABS);
GlobalUnlock(hglbTextPasteBuf);
} EndPaint(hwnd, &ps);
} case WM_COMMAND: { switch (wParam) { // Копируем строку текста в Clipboard case CM_EDITCOPY: { // Заказываем глобальный блок памяти для строки hglbTextCopyBuf = GlobalAlloc(GHND, sizeof(szClipboardText) + 1);
if(hglbTextCopyBuf != NULL) { // Фиксируем блок памяти lpTextCopy = (LPSTR)GlobalLock(hglbTextCopyBuf);
if(lpTextCopy != NULL) { // Копируем строку текста в блок памяти lstrcpy(lpTextCopy, szClipboardText);

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

// Открываем Clipboard и очищаем его OpenClipboard(hwnd);
EmptyClipboard();

// Записываем данные в Clipboard SetClipboardData(CF_TEXT, hglbTextCopyBuf);

// Закрываем Clipboard CloseClipboard();
} else MessageBox(hwnd, "Мало памяти", (LPSTR)szWindowTitle, MB_OK | MB_ICONHAND);
} else MessageBox(hwnd, "Мало памяти", (LPSTR)szWindowTitle, MB_OK | MB_ICONHAND);
return 0; }



// Чтение текстовых данных из Clipboard case CM_EDITPASTE: { // Открываем Clipboard OpenClipboard(hwnd);

// Получаем идентификатор блока памяти, // содержащего текстовые данные Clipboard hglbClipBuf = GetClipboardData(CF_TEXT);

// Если в Clipboard есть данные в текстовом // формате, читаем их if(hglbClipBuf != NULL) { // Фиксируем блок памяти Clipboard lpClipBuf = (LPSTR)GlobalLock(hglbClipBuf);
if(lpClipBuf != NULL) { // Изменяем размер буфера, предназначенного для // хранения данных, прочитанных из Clipboard, // устанавливая его равным размеру блока // данных Clipboard hglbTextPasteBuf = GlobalReAlloc(hglbTextPasteBuf, GlobalSize(hglbClipBuf), GMEM_NODISCARD);

// Фиксируем буфер в памяти и переписываем // в него содержимое Clipboard lpTextPaste = (LPSTR)GlobalLock(hglbTextPasteBuf);
if(lpTextPaste != NULL) { lstrcpy(lpTextPaste, lpClipBuf);

// Перерисовываем главное окно приложения InvalidateRect(hwnd, NULL, TRUE);

// Расфиксируем буфер GlobalUnlock(hglbTextPasteBuf);
} else MessageBox(hwnd, "Мало памяти", (LPSTR)szWindowTitle, MB_OK | MB_ICONHAND);

// Расфиксируем блок памяти Clipboard GlobalUnlock(hglbClipBuf);
} else MessageBox(hwnd, "Мало памяти", (LPSTR)szWindowTitle, MB_OK | MB_ICONHAND);
} else MessageBox(hwnd, "Формат CF_TEXT недоступен", (LPSTR)szWindowTitle, MB_OK | MB_ICONHAND);

// Закрываем Clipboard CloseClipboard();
return 0; }

case CM_HELPABOUT: { MessageBox(hwnd, "Приложение CLIPTXT\n(C) Фролов А.В., 1995", (LPSTR)szWindowTitle, MB_OK | MB_ICONINFORMATION);
return 0; } case CM_FILEEXIT: { DestroyWindow(hwnd);
return 0; } default: return 0; } } case WM_DESTROY: { // Освобождаем буфер, предназначенный для хранения // данных, прочитанных из Clipboard if(hglbTextPasteBuf != NULL) GlobalFree(hglbTextPasteBuf);

PostQuitMessage(0);
return 0; } default: break; } return DefWindowProc(hwnd, msg, wParam, lParam);
}

Обработчик сообщения WM_CREATE заказывает буфер hglbTextPasteBuf, в который будет записан текст, вставленный из Clipboard.


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

После записи пустой строки буфер расфиксируется.

Задача обработчика сообщения WM_PAINT заключается в рисовании содержимого буфера hglbTextPasteBuf. Для рисования используется функция DrawText.

Заметьте, что мы фиксируем буфер hglbTextPasteBuf в памяти только на время рисования. Перед возвратом управления обработчик сообщения WM_PAINT расфиксирует буфер.

Когда пользователь выбирает строку "Copy" из меню "Edit", обработчик сообщения WM_COMMAND выполняет описанные нами ранее действия по копированию текстовой строки szClipboardText в Clipboard.

Прежде всего, он заказывает глобальный блок памяти hglbTextCopyBuf, размер которого равен размеру строки с учетом двоичного нуля, закрывающего строку. Полученный блок памяти фиксируется, после чего в него с помощью функции lstrcpy копируется содержимое строки szClipboardText. Далее блок памяти hglbTextCopyBuf расфиксируется.

Теперь блок памяти подготовлен для записи в Clipboard. Приложение открывает Clipboard и очищает его с помощью функций OpenClipboard и EmptyClipboard:

OpenClipboard(hwnd);
EmptyClipboard();

После этого блок памяти hglbTextCopyBuf передается функции SetClipboardData. Для завершения процесса Clipboard закрывается функцией CloseClipboard:

SetClipboardData(CF_TEXT, hglbTextCopyBuf);
CloseClipboard();

Все! Теперь Clipboard содержит следующий текст:

Этот текст будет записан в универсальный буфер обмена Clipboard приложением CLIPTXT

Вы можете убедиться в этом с помощью приложения Clipboard или ClipBook Viewer (если вы используете Windows for Workgroups).

Если пользователь выберет строку "Paste" из меню "Edit", обработчик сообщения WM_COMMAND скопирует данные из Clipboard в буфер hglbTextPasteBuf, подготовленный приложением на этапе создания главного окна.



В процессе копирования приложение открывает Clipboard функцией OpenClipboard и получает из него текстовые данные, вызывая функцию GetClipboardData:

hglbClipBuf = GetClipboardData(CF_TEXT);

Для получения адреса данных блок фиксируется функцией GlobalLock:

lpClipBuf = (LPSTR)GlobalLock(hglbClipBuf);

Перед тем как скопировать данные из Clipboard в буфер hglbTextPasteBuf его размер делается равным размеру блока памяти hglbClipBuf при помощи функции GlobalReAlloc:

hglbTextPasteBuf = GlobalReAlloc(hglbTextPasteBuf, GlobalSize(hglbClipBuf), GMEM_NODISCARD);

Если изменение размера блока прошло успешно, блок фиксируется в памяти, вслед за чем в него копируются данные при помощи функции lstrcpy.

Чтобы отразить новое содержимое блока памяти hglbTextPasteBuf, приложение перерисовывает главное окно, вызывая функцию InvalidateRect.

В завершении процесса копирования данных из Clipboard блоки памяти hglbTextPasteBuf и hglbClipBuf расфиксируются функцией GlobalUnlock. Затем Clipboard закрывается функцией CloseClipboard.

При завершении работы приложения обработчик сообщения WM_DESTROY уничтожает блок памяти hglbTextPasteBuf, который использовался для хранения данных, прочитанных из Clipboard:

if(hglbTextPasteBuf != NULL) GlobalFree(hglbTextPasteBuf);

Файл cliptxt.hpp (листинг 2.2) содержит определения констант для идентификации строк меню приложения CLIPTXT.


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