Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Петзолд Ч. Программирование для Windows 95 [22].pdf
Скачиваний:
76
Добавлен:
02.05.2014
Размер:
3.02 Mб
Скачать

137

либо формат данных, либо NULL, что означает — данные всех форматов. Старшим словом параметра lParam этого сообщения является либо элемент ATOM, либо NULL, что означает — все элементы.

В программе DDEPOP1 сообщение WM_DDE_UNADVISE обрабатывается путем присвоения соответствующим полям fAdvise структуры POPADVISE значения FALSE и последующим позитивным или негативным подтверждением путем посылки сообщения WM_DDE_ACK.

Сообщение WM_DDE_TERMINATE

Когда клиент решает закончить диалог, он посылает серверу синхронное сообщение WM_DDE_TERMINATE. Сервер просто отвечает клиенту собственным сообщением WM_DDE_TERMINATE. Кроме этого, ServerProc после получения сообщения WM_DDE_TERMINATE удаляет дочернее окно, поскольку оно больше не нужно, и диалог, который это окно поддерживало, завершается.

ServerProc также обрабатывает сообщения WM_DDE_POKE и WM_DDE_EXECUTE, но в обоих случаях она просто отвечает негативным подтверждением получения.

Если программа DDEPOP1 закрывается из собственного системного меню, то она должна завершить все диалоги со своими клиентами. Поэтому, когда WndProc получает сообщение WM_CLOSE, она вызывает функцию

EnumChildWindows с функцией CloseEnumProc. Функция CloseEnumProc посылает всем дочерним окнам асинхронное сообщение WM_CLOSE.

ServerProc отвечает на сообщение WM_CLOSE путем отправки клиенту синхронного сообщения WM_DDE_TERMINATE и затем ждет от клиента ответного сообщения WM_DDE_TERMINATE.

Программа-клиент DDE

Теперь, после того, как мы рассмотрели программу-сервер DDE, которую можно использовать для работы с Microsoft Excel, рассмотрим программу-клиент DDE, сервером для которой является программа DDEPOP1. Эта программа, названная SHOWPOP1, представлена на рис. 17.2.

SHOWPOP1.MAK

#------------------------

# SHOWPOP1.MAK make file

#------------------------

showpop1.exe : showpop1.obj

$(LINKER) $(GUIFLAGS) -OUT:showpop1.exe showpop1.obj $(GUILIBS)

showpop1.obj : showpop1.c showpop.h $(CC) $(CFLAGS) showpop1.c

SHOWPOP1.C

/*-----------------------------------------

 

SHOWPOP1.C --

DDE Client using DDEPOP1

 

(c) Charles Petzold, 1996

-----------------------------------------

*/

#include <windows.h> #include <dde.h> #include <stdlib.h> #include <string.h> #include "showpop.h"

#define

WM_USER_INITIATE(WM_USER + 1)

#define

DDE_TIMEOUT

3000

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

char szAppName[] = "ShowPop1";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

HWND hwnd;

MSG msg;

fDoingInitiate = TRUE; szServerApp[] = "DdePop1", szTopic[] = "US_Population"; hwndServer = NULL;
cxChar, cyChar; aApp, aTop, aItem;
szBuffer[24], szPopulation[16], szItem[16]; DdeAck;
*pDdeData;
*pDdeAdvise;
dwTime;
hDdeAdvise, hDdeData; hdc;
msg;
ps;
i; x, y; tm;
wStatus; uiLow, uiHi;

138

WNDCLASSEX wndclass;

 

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= 0;

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(hInstance, szAppName);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szAppName;

wndclass.hIconSm

= LoadIcon(hInstance, szAppName);

RegisterClassEx(&wndclass);

hwnd = CreateWindow(szAppName, "DDE Client - US Population", WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

SendMessage(hwnd, WM_USER_INITIATE, 0, 0L);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static BOOL static char

static HWND static long ATOM

char DDEACK DDEDATA DDEADVISE DWORD

GLOBALHANDLE

HDC

MSG PAINTSTRUCT short

long TEXTMETRIC WORD

UINT

switch(iMsg)

{

case WM_CREATE :

hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); cxChar = tm.tmAveCharWidth;

cyChar = tm.tmHeight + tm.tmExternalLeading;

139

ReleaseDC(hwnd, hdc); return 0;

case WM_USER_INITIATE :

// Broadcast WM_DDE_INITIATE iMsg

aApp = GlobalAddAtom(szServerApp);

aTop = GlobalAddAtom(szTopic);

SendMessage(HWND_BROADCAST, WM_DDE_INITIATE,(WPARAM) hwnd,

MAKELONG(aApp, aTop));

// If no response, try loading DDEPOP first

if(hwndServer == NULL)

{

WinExec(szServerApp, SW_SHOWMINNOACTIVE);

SendMessage(HWND_BROADCAST, WM_DDE_INITIATE,(WPARAM) hwnd,

MAKELONG(aApp, aTop));

}

// Delete the atoms

GlobalDeleteAtom(aApp);

GlobalDeleteAtom(aTop);

fDoingInitiate = FALSE;

// If still no response, display message box

if(hwndServer == NULL)

{

MessageBox(hwnd, "Cannot connect with DDEPOP1.EXE!", szAppName, MB_ICONEXCLAMATION | MB_OK);

return 0;

}

// Post WM_DDE_ADVISE iMsgs

for(i = 0; i < NUM_STATES; i++)

{

hDdeAdvise = GlobalAlloc(GHND | GMEM_DDESHARE,

sizeof(DDEADVISE));

pDdeAdvise =(DDEADVISE *) GlobalLock(hDdeAdvise);

pDdeAdvise->fAckReq = TRUE;

pDdeAdvise->fDeferUpd = FALSE;

pDdeAdvise->cfFormat = CF_TEXT;

GlobalUnlock(hDdeAdvise);

aItem = GlobalAddAtom(pop[i].szAbb);

if(!PostMessage(hwndServer, WM_DDE_ADVISE,(WPARAM) hwnd, PackDDElParam(WM_DDE_ADVISE,

(UINT) hDdeAdvise, aItem)))

{

GlobalFree(hDdeAdvise);

GlobalDeleteAtom(aItem);

break;

}

140

DdeAck.fAck = FALSE;

dwTime = GetCurrentTime();

while(GetCurrentTime() - dwTime < DDE_TIMEOUT)

{

if(PeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE))

{

GlobalDeleteAtom(HIWORD(msg.lParam));

wStatus = LOWORD(msg.lParam); DdeAck = *((DDEACK *) &wStatus);

if(DdeAck.fAck == FALSE) GlobalFree(hDdeAdvise);

break;

}

}

if(DdeAck.fAck == FALSE) break;

while(PeekMessage(&msg, hwnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE))

{

DispatchMessage(&msg);

}

}

if(i < NUM_STATES)

{

MessageBox(hwnd, "Failure on WM_DDE_ADVISE!", szAppName, MB_ICONEXCLAMATION | MB_OK);

}

return 0;

case WM_DDE_ACK :

// In response to WM_DDE_INITIATE, save server window

if(fDoingInitiate)

{

UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi); FreeDDElParam(WM_DDE_ACK, lParam);

hwndServer =(HWND) wParam; GlobalDeleteAtom((ATOM) uiLow); GlobalDeleteAtom((ATOM) uiHi);

}

return 0;

case WM_DDE_DATA :

//wParam -- sending window handle

//lParam -- DDEDATA memory handle & item atom

UnpackDDElParam(WM_DDE_DATA, lParam, &uiLow, &uiHi); FreeDDElParam(WM_DDE_DATA, lParam);

hDdeData =(GLOBALHANDLE) uiLow;

pDdeData =(DDEDATA *) GlobalLock(hDdeData);

aItem =(ATOM) uiHi;

// Initialize DdeAck structure

141

DdeAck.bAppReturnCode

= 0;

DdeAck.reserved

= 0;

DdeAck.fBusy

= FALSE;

DdeAck.fAck

= FALSE;

// Check for matching format and data item

if(pDdeData->cfFormat == CF_TEXT)

{

GlobalGetAtomName(aItem, szItem, sizeof(szItem));

for(i = 0; i < NUM_STATES; i++) if(strcmp(szItem, pop[i].szAbb) == 0)

break;

if(i < NUM_STATES)

{

strcpy(szPopulation,(char *) pDdeData->Value); pop[i].lPop = atol(szPopulation); InvalidateRect(hwnd, NULL, FALSE);

DdeAck.fAck = TRUE;

}

}

// Acknowledge if necessary

if(pDdeData->fAckReq == TRUE)

{

wStatus = *((WORD *) &DdeAck);

if(!PostMessage((HWND) wParam, WM_DDE_ACK,(WPARAM) hwnd, PackDDElParam(WM_DDE_ACK,

wStatus, aItem)))

{

GlobalDeleteAtom(aItem);

GlobalUnlock(hDdeData);

GlobalFree(hDdeData);

return 0;

}

}

else

{

GlobalDeleteAtom(aItem);

}

// Clean up

if(pDdeData->fRelease == TRUE || DdeAck.fAck == FALSE)

{

GlobalUnlock(hDdeData);

GlobalFree(hDdeData);

}

else

{

GlobalUnlock(hDdeData);

}

return 0;

case WM_PAINT :

hdc = BeginPaint(hwnd, &ps);

for(i = 0; i < NUM_STATES; i++)

142

{

if(i <(NUM_STATES + 1) / 2)

{

x = cxChar;

y = i * cyChar;

}

else

{

x = 44 * cxChar;

y =(i -(NUM_STATES + 1) / 2) * cyChar;

}

TextOut(hdc, x, y, szBuffer, wsprintf(szBuffer, "%-20s",

(PSTR) pop[i].szState));

x += 36 * cxChar;

SetTextAlign(hdc, TA_RIGHT | TA_TOP);

TextOut(hdc, x, y, szBuffer,

wsprintf(szBuffer, "%10ld", pop[i].lPop));

SetTextAlign(hdc, TA_LEFT | TA_TOP);

}

EndPaint(hwnd, &ps); return 0;

case WM_DDE_TERMINATE :

// Respond with another WM_DDE_TERMINATE iMsg

PostMessage(hwndServer, WM_DDE_TERMINATE,(WPARAM) hwnd, 0L); hwndServer = NULL;

return 0;

case WM_CLOSE : if(hwndServer == NULL)

break;

// Post WM_DDE_UNADVISE iMsg

PostMessage(hwndServer, WM_DDE_UNADVISE,(WPARAM) hwnd, MAKELONG(CF_TEXT, NULL));

dwTime = GetCurrentTime();

while(GetCurrentTime() - dwTime < DDE_TIMEOUT)

{

if(PeekMessage(&msg, hwnd, WM_DDE_ACK, WM_DDE_ACK, PM_REMOVE))

break;

}

// Post WM_DDE_TERMINATE iMsg

PostMessage(hwndServer, WM_DDE_TERMINATE,(WPARAM) hwnd, 0L);

dwTime = GetCurrentTime();

while(GetCurrentTime() - dwTime < DDE_TIMEOUT)

{

if(PeekMessage(&msg, hwnd, WM_DDE_TERMINATE, WM_DDE_TERMINATE, PM_REMOVE))

break;

143

}

break;

// for default processing

case WM_DESTROY : PostQuitMessage(0); return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

SHOWPOP.H

/*-----------------------

SHOWPOP.H header file

-----------------------*/

 

 

struct

 

 

{

 

 

char *szAbb;

 

 

char *szState;

 

 

long lPop;

 

 

}

 

 

pop[] = {

 

 

"AL", "Alabama",

0, "AK", "Alaska",

0,

"AZ", "Arizona",

0, "AR", "Arkansas",

0,

"CA", "California",

0, "CO", "Colorado",

0,

"CT", "Connecticut",

0, "DE", "Delaware",

0,

"DC", "Dist. of Columbia",

0, "FL", "Florida",

0,

"GA", "Georgia",

0, "HI", "Hawaii",

0,

"ID", "Idaho",

0, "IL", "Illinois",

0,

"IN", "Indiana",

0, "IA", "Iowa",

0,

"KS", "Kansas",

0, "KY", "Kentucky",

0,

"LA", "Louisiana",

0, "ME", "Maine",

0,

"MD", "Maryland",

0, "MA", "Massachusetts",

0,

"MI", "Michigan",

0, "MN", "Minnesota",

0,

"MS", "Mississippi",

0, "MO", "Missouri",

0,

"MT", "Montana",

0, "NE", "Nebraska",

0,

"NV", "Nevada",

0, "NH", "New Hampshire",

0,

"NJ", "New Jersey",

0, "NM", "New Mexico",

0,

"NY", "New York",

0, "NC", "North Carolina",

0,

"ND", "North Dakota",

0, "OH", "Ohio",

0,

"OK", "Oklahoma",

0, "OR", "Oregon",

0,

"PA", "Pennsylvania",

0, "RI", "Rhode Island",

0,

"SC", "South Carolina",

0, "SD", "South Dakota",

0,

"TN", "Tennessee",

0, "TX", "Texas",

0,

"UT", "Utah",

0, "VT", "Vermont",

0,

"VA", "Virginia",

0, "WA", "Washington",

0,

"WV", "West Virginia",

0, "WI", "Wisconsin",

0,

"WY", "Wyoming",

0, "US", "United States Total",

0

};

 

 

#define NUM_STATES(sizeof(pop) / sizeof(pop[0]))

Рис. 17.2 Программа SHOWPOP1

Эта программа отображает в своем окне названия штатов с обновленной численностью населения из программы DDEPOP1, используя возможности сообщения WM_DDE_ADVISE. Обратите внимание, что в программе SHOWPOP1 имеется точно такая же структура pop, как и в программе DDEPOP1, но в данной версии содержатся поля для двухбуквенных аббревиатур штатов, для названия штатов, и поле lPop (инициализируемое нулем), в которое будет заноситься обновленная численность населения, получаемая из программы DDEPOP1.

В программе SHOWPOP1 поддерживается только один диалог DDE, поэтому для этого диалога ей достаточно одного окна. Для него она использует оконную процедуру WndProc.