Файл 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.