
- •Содержание
- •Управление памятью: хорошо, плохо и ужасно
- •Сегментированная память
- •Промежуточные решения
- •И, наконец, 32 бита
- •Выделение памяти
- •Библиотечные функции C
- •Фундаментальное выделение памяти в Windows 95
- •Перемещаемая память
- •Удаляемая память
- •Другие функции и флаги
- •Хорошо ли это?
- •Функции работы с "кучей"
- •Файловый ввод/вывод
- •Старый путь
- •Отличия Windows 95
- •Ввод/вывод с использованием файлов, проецируемых в память
- •Режимы многозадачности
- •Многозадачность в DOS
- •Невытесняющая многозадачность
- •Решения, использующие многопоточность
- •Многопоточная архитектура
- •Коллизии, возникающие при использовании потоков
- •Преимущества Windows
- •Новая программа! Усовершенствованная программа! Многопоточная!
- •Многопоточность в Windows 95
- •И снова случайные прямоугольники
- •Задание на конкурсе программистов
- •Решение с использованием многопоточности
- •О пользе использования функции Sleep
- •Синхронизация потоков
- •Критический раздел
- •Объект Mutex
- •Программа BIGJOB1
- •Объект Event
- •Локальная память потока
- •Печать, буферизация и функции печати
- •Контекст принтера
- •Формирование параметров для функции CreateDC
- •Измененная программа DEVCAPS
- •Вызов функции PrinterProperties
- •Проверка возможности работы с битовыми блоками (BitBlt)
- •Программа FORMFEED
- •Печать графики и текста
- •Каркас программы печати
- •Прерывание печати с помощью процедуры Abort
- •Реализация процедуры прерывания
- •Добавление диалогового окна печати
- •Добавление печати к программе POPPAD
- •Обработка кодов ошибок
- •Техника разбиения на полосы
- •Разбиение на полосы
- •Реализация разбиения страницы на полосы
- •Принтер и шрифты
- •Глава 16 Буфер обмена
- •Простое использование буфера обмена
- •Стандартные форматы данных буфера обмена
- •Передача текста в буфер обмена
- •Получение текста из буфера обмена
- •Открытие и закрытие буфера обмена
- •Использование буфера обмена с битовыми образами
- •Метафайл и картина метафайла
- •Более сложное использование буфера обмена
- •Использование нескольких элементов данных
- •Отложенное исполнение
- •Нестандартные форматы данных
- •Соответствующая программа просмотра буфера обмена
- •Цепочка программ просмотра буфера обмена
- •Функции и сообщения программы просмотра буфера обмена
- •Простая программа просмотра буфера обмена
- •Основные концепции
- •Приложение, раздел и элемент
- •Типы диалогов
- •Символьные строки и атомы
- •Программа сервер DDE
- •Программа DDEPOP1
- •Сообщение WM_DDE_INITIATE
- •Оконная процедура ServerProc
- •Функция PostDataMessage программы DDEPOP1
- •Сообщение WM_DDE_ADVISE
- •Обновление элементов данных
- •Сообщение WM_DDE_UNADVISE
- •Сообщение WM_DDE_TERMINATE
- •Программа-клиент DDE
- •Инициирование диалога DDE
- •Сообщение WM_DDE_DATA
- •Сообщение WM_DDE_TERMINATE
- •Управляющая библиотека DDE
- •Концептуальные различия
- •Реализация DDE с помощью DDEML
- •Элементы MDI
- •Windows 95 и MDI
- •Пример программы
- •Три меню
- •Инициализация программы
- •Создание дочерних окон
- •Дополнительная информация об обработке сообщений в главном окне
- •Дочерние окна документов
- •Освобождение захваченных ресурсов
- •Сила оконной процедуры
- •Основы библиотек
- •Библиотека: одно слово, множество значений
- •Пример простой DLL
- •Разделяемая память в DLL
- •Библиотека STRLIB
- •Точка входа/выхода библиотеки
- •Программа STRPROG
- •Работа программы STRPROG
- •Разделение данных между экземплярами программы STRPROG
- •Некоторые ограничения библиотек
- •Динамическое связывание без импорта
- •Библиотеки, содержащие только ресурсы
- •Глава 20 Что такое OLE?
- •Основы OLE
- •Связь с библиотеками OLE
- •Расшифровка кода результата
- •Интерфейсы модели составного объекта (COM-интерфейсы)
- •Услуги интерфейса IUnknown
- •Является ли OLE спецификацией клиент/сервер?
- •Сервер закрытого компонента
- •IMALLOC.DLL
- •Теперь о макросах
- •Услуги, предоставляемые интерфейсом IUnknown
- •Клиент закрытого компонента
- •Сервер открытого компонента
- •Назначение реестра
- •Способы генерации и использования идентификаторов CLSID
- •Компонент фабрика классов
- •Управление временем жизни сервера
- •Клиент открытого компонента
- •Заключение

235
Клиент открытого компонента
Программа-клиент открытого компонента CALLPUB.EXE была создана из программы клиента закрытого компонента CALLER.EXE. Обе программы вызывают сервер компонента OLE, который обеспечивает интерфейс IMalloc для выделения и освобождения блоков памяти для хранения символьных строк.
Хотя для превращения закрытого сервера в открытый нужно было сделать несколько модификаций — специальные точки входа и фабрика классов — для превращения клиента закрытого компонента в клиента открытого компонента достаточно одного очень незначительного изменения. Вместо вызова функции создания закрытого компонента, программа CALLPUB вызывает функцию библиотеки OLE CoCreateInstance, единственной задачей которой должно быть создание компонентов.
Файлы с исходным текстом программы CALLPUB представлены на рис. 20.7.
CALLPUB.MAK
#-----------------------
# CALLPUB.MAK make file
#-----------------------
callpub.exe : callpub.obj callpub.res pubmem.lib
$(LINKER) $(GUIFLAGS) -OUT:callpub.exe callpub.obj callpub.res \ pubmem.lib $(GUILIBS) uuid.lib ole32.lib
callpub.obj : callpub.c callpub.h pubmem.h $(CC) -DCINTERFACE $(CFLAGS) callpub.c
callpub.res : callpub.rc callpub.h
$(RC) $(RCVARS) callpub.rc
CALLPUB.C
/*---------------------------------------------
CALLPUB.C -- Call into public OLE component
(c) Paul Yao, 1996
---------------------------------------------*/
#include <windows.h> #include <initguid.h> #include "pubmem.h"
#include "callpub.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
char szWndClass[] = "CallerWindow";
char szAppName[] = "Calls Public Malloc";
//-------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
PSTR lpszCmdLine, int cmdShow) |
|
{ |
|
|
HWND |
hwnd; |
|
MSG |
msg; |
|
WNDCLASSEX |
wc; |
|
wc.cbSize |
|
= sizeof(wc); |
wc.lpszClassName |
= szWndClass; |
|
wc.hInstance |
= hInstance; |
|
wc.lpfnWndProc |
= WndProc; |
|
wc.hCursor |
|
= LoadCursor(NULL, IDC_ARROW); |
wc.hIcon |
|
= LoadIcon(NULL, IDI_APPLICATION); |
wc.lpszMenuName |
= "MAIN"; |
|
wc.hbrBackground |
=(HBRUSH)(COLOR_WINDOW + 1); |
|
wc.style |
|
= 0; |
wc.cbClsExtra |
= 0; |
|
wc.cbWndExtra |
= 0; |
|
wc.hIconSm |
|
= LoadIcon(NULL, IDI_APPLICATION); |

236
RegisterClassEx(&wc);
hwnd = CreateWindowEx(0L, szWndClass, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, cmdShow);
UpdateWindow(hwnd);
// Connect to OLE libraries HRESULT hr = CoInitialize(NULL); if(FAILED(hr))
{
// Fail app initialization return FALSE;
}
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Disconnect from OLE libraries CoUninitialize();
return msg.wParam;
}
//-------------------------------------------------------------------
LRESULT CALLBACK
WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{ |
|
static int |
iCurLine = 0; |
static LPMALLOC |
pMalloc = NULL; |
static LPSTR |
szLine[10]; |
static RECT |
rHit[10]; |
switch(iMsg)
{
case WM_CREATE :
// Initialize data pointer array ZeroMemory(szLine, sizeof(szLine)); return 0;
case WM_COMMAND : switch(LOWORD(wParam))
{
case IDM_CREATE :
{
HRESULT hr =
CoCreateInstance(CLSID_ALLOCATOR,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMalloc,
(void **) &pMalloc);
if(FAILED(hr))
{
MessageBox(hwnd, "Error: No allocator", szAppName, MB_OK);
return 0;
}

237
InvalidateRect(hwnd, NULL, TRUE); return 0;
}
case IDM_DESTROY :
{
int i;
//Mark allocated blocks as invalid for(i = 0; i < 10; i++)
{
if((szLine[i] != NULL) && (pMalloc->lpVtbl->DidAlloc(pMalloc,
szLine[i])))
{
szLine[i] = NULL;
}
}
//Disconnect from & free allocator pMalloc->lpVtbl->Release(pMalloc); pMalloc = NULL;
InvalidateRect(hwnd, NULL, TRUE); return 0;
}
case IDM_IUNKNOWN :
{
LPUNKNOWN pUnk;
HRESULT hr =
pMalloc->lpVtbl->QueryInterface(pMalloc, IID_IUnknown,
(void **) &pUnk); if(SUCCEEDED(hr))
{
pUnk->lpVtbl->Release(pUnk); MessageBox(hwnd, "IUnknown supported",
szAppName, MB_OK);
}
else
{
MessageBox(hwnd, "IUnknown not supported", szAppName, MB_OK);
}
return 0;
}
case IDM_IMALLOC :
{
LPUNKNOWN pUnk;
HRESULT hr =
pMalloc->lpVtbl->QueryInterface(pMalloc, IID_IMalloc,
(void **) &pUnk); if(SUCCEEDED(hr))
{
pUnk->lpVtbl->Release(pUnk); MessageBox(hwnd, "IMalloc supported",
szAppName, MB_OK);
}
else
{
MessageBox(hwnd, "IMalloc not supported", szAppName, MB_OK);

238
}
return 0;
}
case IDM_IMARSHAL :
{
LPUNKNOWN pUnk;
HRESULT hr =
pMalloc->lpVtbl->QueryInterface(pMalloc, IID_IMarshal,
(void **) &pUnk); if(SUCCEEDED(hr))
{
pUnk->lpVtbl->Release(pUnk); MessageBox(hwnd, "IMarshal supported",
szAppName, MB_OK);
}
else
{
MessageBox(hwnd, "IMarshal not supported", szAppName, MB_OK);
}
return 0;
}
case IDM_ALLOCATE_CUSTOM : if(szLine[iCurLine] != NULL)
{
MessageBox(hwnd, "Error: Free First",
szAppName, MB_OK);
return 0;
}
// Allocate from IMalloc interface szLine[iCurLine] =
(char *) pMalloc->lpVtbl->Alloc(pMalloc, 100); lstrcpy(szLine[iCurLine], "*IMalloc memory*");
InvalidateRect(hwnd, NULL, TRUE); return 0;
case IDM_ALLOCATE_DEFAULT : if(szLine[iCurLine] != NULL)
{
MessageBox(hwnd, "Error: Free First",
szAppName, MB_OK);
return 0;
}
// Allocate from default heap szLine[iCurLine] =(char *) malloc(100); lstrcpy(szLine[iCurLine], "-Malloc memory-");
InvalidateRect(hwnd, NULL, TRUE); return 0;
case IDM_FREE : if(szLine[iCurLine] == NULL)
{
MessageBox(hwnd, "Error: Nothing to free", szAppName, MB_OK);
return 0;
}
if(pMalloc == NULL)
{

239
goto FreeMalloc;
}
// Free allocated object if(pMalloc->lpVtbl->DidAlloc(pMalloc,
szLine[iCurLine]))
{
pMalloc->lpVtbl->Free(pMalloc, szLine[iCurLine]);
}
else
{
FreeMalloc:
free(szLine[iCurLine]);
}
szLine[iCurLine] = NULL;
InvalidateRect(hwnd, NULL, TRUE); return 0;
}
case WM_DESTROY :
// Disconnect from & free allocator if(pMalloc)
{
pMalloc->lpVtbl->Release(pMalloc); pMalloc = NULL;
}
PostQuitMessage(0); // Handle application shutdown return 0;
case WM_INITMENU : |
|
{ |
|
HMENU hMenu =(HMENU) wParam; |
|
if(pMalloc) |
|
{ |
|
EnableMenuItem(hMenu, IDM_CREATE, |
MF_GRAYED); |
EnableMenuItem(hMenu, IDM_DESTROY, |
MF_ENABLED); |
EnableMenuItem(hMenu, IDM_ALLOCATE_CUSTOM, |
MF_ENABLED); |
EnableMenuItem(hMenu, IDM_IUNKNOWN, |
MF_ENABLED); |
EnableMenuItem(hMenu, IDM_IMALLOC, |
MF_ENABLED); |
EnableMenuItem(hMenu, IDM_IMARSHAL, |
MF_ENABLED); |
} |
|
else |
|
{ |
|
EnableMenuItem(hMenu, IDM_CREATE, |
MF_ENABLED); |
EnableMenuItem(hMenu, IDM_DESTROY, |
MF_GRAYED); |
EnableMenuItem(hMenu, IDM_ALLOCATE_CUSTOM, |
MF_GRAYED); |
EnableMenuItem(hMenu, IDM_IUNKNOWN, |
MF_GRAYED); |
EnableMenuItem(hMenu, IDM_IMALLOC, |
MF_GRAYED); |
EnableMenuItem(hMenu, IDM_IMARSHAL, |
MF_GRAYED); |
} |
|
return 0; |
|
} |
|
case WM_LBUTTONDOWN : |
|
{ |
|
int i; |
|
int x = LOWORD(lParam); |
|
int y = HIWORD(lParam); |
|
POINT pt = { x, y }; |
|
for(i = 0; i < 10; i++)

240
{
if(PtInRect(&rHit[i], pt))
{
if(iCurLine != i) // Minimize screen blink
{
InvalidateRect(hwnd, &rHit[iCurLine], TRUE); InvalidateRect(hwnd, &rHit[i], TRUE); iCurLine = i;
}
break;
}
}
return 0;
}
case WM_PAINT : |
|
{ |
|
char |
szBuff[10]; |
COLORREF |
crText, crBack; |
HDC |
hdc; |
int |
cc; |
int |
i; |
int |
XCount, XText, Y; |
int |
cyLineHeight; |
PAINTSTRUCT |
ps; |
RECT |
rOpaque; |
TEXTMETRIC |
tm; |
hdc = BeginPaint(hwnd, &ps);
//Fetch line height GetTextMetrics(ps.hdc, &tm);
cyLineHeight = tm.tmHeight + tm.tmExternalLeading;
//Fetch current text colors
crText = GetTextColor(ps.hdc); crBack = GetBkColor(ps.hdc);
XCount = tm.tmAveCharWidth * 3;
XText = XCount + tm.tmAveCharWidth * 7;
Y = tm.tmHeight;
for(i = 0; i < 10; i++, Y += cyLineHeight)
{
// Set colors to highlight current line if(i == iCurLine)
{
SetTextColor(ps.hdc, crBack);
SetBkColor(ps.hdc, crText);
SetRect(&rOpaque, 0, Y, 9999, Y + cyLineHeight); ExtTextOut(ps.hdc, 0, 0, ETO_OPAQUE, &rOpaque,
NULL, 0, NULL );
}
else
{
SetTextColor(ps.hdc, crText);
SetBkColor(ps.hdc, crBack);
}
// Display line count
cc = wsprintf(szBuff, "Line %d", i); TextOut(ps.hdc, XCount, Y, szBuff, cc);
// Display text if a string has been defined

241
if(szLine[i] != NULL)
{
cc = lstrlen(szLine[i]);
TextOut(ps.hdc, XText, Y, szLine[i], cc);
}
// Calculate hit test rectangle SetRect(&rHit[i], 0, Y, 9999, Y + cyLineHeight);
}
EndPaint(hwnd, &ps); return 0;
}
default :
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
}
CALLPUB.H
#define IDM_CREATE |
1 |
#define IDM_DESTROY |
2 |
#define IDM_IUNKNOWN |
3 |
#define IDM_IMALLOC |
4 |
#define IDM_IMARSHAL |
5 |
#define IDM_ALLOCATE_CUSTOM |
6 |
#define IDM_ALLOCATE_DEFAULT |
7 |
#define IDM_FREE |
8 |
#define IDM_CHECK |
9 |
CALLPUB.RC
#include "callpub.h"
MAIN MENU |
|
{ |
|
POPUP "&Allocator" |
|
{ |
|
MENUITEM "&Create", |
IDM_CREATE |
MENUITEM "&Destroy", |
IDM_DESTROY |
MENUITEM SEPARATOR |
|
MENUITEM "QueryInterface IID_IUnknown", IDM_IUNKNOWN |
|
MENUITEM "QueryInterface IID_IMalloc", |
IDM_IMALLOC |
MENUITEM "QueryInterface IID_IMarshal", IDM_IMARSHAL
}
POPUP "&Memory"
{
MENUITEM "&Allocate(IMalloc)", IDM_ALLOCATE_CUSTOM
MENUITEM "&Allocate(malloc)", IDM_ALLOCATE_DEFAULT
MENUITEM "&Free", IDM_FREE
}
}
Рис. 20.7 Программа CALLPUB
Поскольку она вызывает функцию библиотеки OLE, программа CALLPUB в начале функции WinMain инициализирует библиотеки OLE:
// Соединение с библиотеками OLE
HRESULT hr = CoInitialize(NULL);
if(FAILED(hr))
{
// Неудачная инициализация return FALSE;
}