Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

ddetrack.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************* 00002 * Module Name: ddetrack.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module handles tracking of DDE conversations for use in emulating 00007 * DDE shared memory. 00008 * 00009 * History: 00010 * 9-3-91 sanfords Created 00011 * 21-Jan-1992 IanJa ANSI/Unicode netralized (null op) 00012 \***************************************************************************/ 00013 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 00017 PPUBOBJ gpPublicObjectList; 00018 00019 #define TRACE_DDE(str) TAGMSG0(DBGTAG_DDE, str) 00020 #define TRACE_DDE1(s, a) TAGMSG1(DBGTAG_DDE, (s), (a)) 00021 #define TRACE_DDE2(s, a, b) TAGMSG2(DBGTAG_DDE, (s), (a), (b)) 00022 #define TRACE_DDE3(s, a, b, c) TAGMSG3(DBGTAG_DDE, (s), (a), (b), (c)) 00023 00024 BOOL NewConversation(PDDECONV *ppdcNewClient, PDDECONV *ppdcNewServer, 00025 PWND pwndClient, PWND pwndServer); 00026 PDDECONV FindDdeConv(PWND pwndProp, PWND pwndPartner); 00027 BOOL AddConvProp(PWND pwndUs, PWND pwndThem, DWORD flags, PDDECONV pdcNew, 00028 PDDECONV pdcPartner); 00029 FNDDERESPONSE xxxUnexpectedServerPost; 00030 FNDDERESPONSE xxxUnexpectedClientPost; 00031 FNDDERESPONSE xxxAdvise; 00032 FNDDERESPONSE xxxAdviseAck; 00033 FNDDERESPONSE xxxAdviseData; 00034 FNDDERESPONSE xxxAdviseDataAck; 00035 DWORD Unadvise(PDDECONV pDdeConv); 00036 FNDDERESPONSE xxxUnadviseAck; 00037 DWORD Request(PDDECONV pDdeConv); 00038 FNDDERESPONSE xxxRequestAck; 00039 FNDDERESPONSE xxxPoke; 00040 FNDDERESPONSE xxxPokeAck; 00041 FNDDERESPONSE xxxExecute; 00042 FNDDERESPONSE xxxExecuteAck; 00043 DWORD SpontaneousTerminate(PDWORD pmessage, PDDECONV pDdeConv); 00044 FNDDERESPONSE DupConvTerminate; 00045 00046 HANDLE AnticipatePost(PDDECONV pDdeConv, FNDDERESPONSE fnResponse, 00047 HANDLE hClient, HANDLE hServer, PINTDDEINFO pIntDdeInfo, DWORD flags); 00048 PXSTATE Createpxs(FNDDERESPONSE fnResponse, HANDLE hClient, HANDLE hServer, 00049 PINTDDEINFO pIntDdeInfo, DWORD flags); 00050 DWORD AbnormalDDEPost(PDDECONV pDdeConv, DWORD message); 00051 DWORD xxxCopyDdeIn(HANDLE hSrc, PDWORD pflags, PHANDLE phDirect, PINTDDEINFO *ppi); 00052 DWORD xxxCopyAckIn(PDWORD pmessage, LPARAM *plParam, PDDECONV pDdeConv, PINTDDEINFO *ppIntDdeInfo); 00053 HANDLE xxxCopyDDEOut(PINTDDEINFO pIntDdeInfo, PHANDLE phDirect); 00054 BOOL FreeListAdd(PDDECONV pDdeConv, HANDLE hClient, DWORD flags); 00055 VOID xxxFreeListFree(PFREELIST pfl); 00056 VOID PopState(PDDECONV pDdeConv); 00057 PDDECONV UnlinkConv(PDDECONV pDdeConv); 00058 00059 VOID FreeDDEHandle(PDDECONV pDdeConv, HANDLE hClient, DWORD flags); 00060 DWORD ClientFreeDDEHandle(HANDLE hClient, DWORD flags); 00061 DWORD ClientGetDDEFlags(HANDLE hClient, DWORD flags); 00062 DWORD xxxClientCopyDDEIn1(HANDLE hClient, DWORD flags, PINTDDEINFO *ppi); 00063 HANDLE xxxClientCopyDDEOut1(PINTDDEINFO pIntDdeInfo); 00064 DWORD xxxClientCopyDDEOut2(PINTDDEINFO pIntDdeInfo); 00065 00066 PPUBOBJ IsObjectPublic(HANDLE hObj); 00067 BOOL AddPublicObject(UINT format, HANDLE hObj, W32PID pid); 00068 BOOL RemovePublicObject(UINT format, HANDLE hObj); 00069 BOOL GiveObject(UINT format, HANDLE hObj, W32PID pid); 00070 #if DBG 00071 VOID ValidatePublicObjectList(VOID); 00072 #define MSG_SENT 0 00073 #define MSG_POST 1 00074 #define MSG_RECV 2 00075 #define MSG_PEEK 3 00076 VOID TraceDdeMsg(UINT msg, HWND hwndFrom, HWND hwndTo, UINT code); 00077 #else 00078 #define ValidatePublicObjectList() 00079 #define TraceDdeMsg(m, h1, h2, c) 00080 #endif // DBG 00081 00082 /* 00083 * The Big Picture: 00084 * 00085 * When a WM_DDE_ACK message is SENT, it implies the begining of a DDE 00086 * Conversation. The tracking layer creates DDECONV structure for each 00087 * window in volved in the conversation and cross links the structures. 00088 * Thus a unique window pair identifies a conversation. Each window has 00089 * its DDECONV structure attached to it via a private property. 00090 * 00091 * As DDE messages are posted, the tracking layer copies data into the 00092 * CSR server side of USER into a INTDDEINFO structure. This structure 00093 * contains flags which direct how the data is to be freed when the 00094 * time comes. This info is placed within an XSTATE structure along 00095 * with context infomation. A pointer to the XSTATE structure is 00096 * placed in the lParam of the message and the MSB of message is set 00097 * for special processing when the message is recieved on the other side. 00098 * 00099 * If the message posted requires a responding message to follow the DDE 00100 * protocol, a XSTATE structure is created and attached to DDECONV 00101 * structure associated with the window that is expected to post the message. 00102 * The XSTATE structure directs the tracking layer so that it knows the 00103 * context of the message when it is posted and also includes any 00104 * information needed for proper freeing of extra DDE data. 00105 * 00106 * When the message is extracted from the queue either by a hook, peek, 00107 * or by GetMessage, the id is checked to see if it lies in the special 00108 * range. If so, the XSTATE structure pointed to by the lParam is 00109 * operated on. This causes the data to be copied from the CSR server 00110 * side of USER to the target process context. Once this is done, the 00111 * XSTATE structure may or may not be freed depending on flags and 00112 * the message is restored to a proper DDE message form ready to be 00113 * used by the target process. Since the message id is changed back, 00114 * subsequent peeks or hooks to the message will not result in duplicated 00115 * processing of the message. 00116 * 00117 * During the course of come transactions it becomes evident that an object 00118 * on the opposite side process needs to be freed. This is done 00119 * asynchronously by inserting the object that needs freeing along with 00120 * associated flags into a freeing list which is tied to the DDECONV 00121 * structure associated with the window on the opposite side. Whenever 00122 * a DDE messages is posted, this freeing list is checked and processed. 00123 * 00124 * When a WM_DDE_TERMINATE message is finally recieved, flags are set 00125 * in the DDECONV structure indicating that the conversation is terminating. 00126 * This alters the way the mapping layer handles DDE messages posted. 00127 * When the responding side posts a WM_DDE_TERMINATE, the DDECONV structures 00128 * and all associated information is freed and unlinked from the windows 00129 * concerned. 00130 * 00131 * Should a DDE window get destroyed before proper termination, the 00132 * xxxDDETrackWindowDying function is called to make sure proper termination 00133 * is done prior to the window being destroyed. 00134 */ 00135 00136 00137 /************************************************************************ 00138 * xxxDDETrackSendHook 00139 * 00140 * Called when a DDE message is passed to SendMessage(). 00141 * 00142 * Returns fSendOk. 00143 * 00144 * History: 00145 * 9-3-91 sanfords Created 00146 \***********************************************************************/ 00147 BOOL xxxDDETrackSendHook( 00148 PWND pwndTo, 00149 DWORD message, 00150 WPARAM wParam, 00151 LPARAM lParam) 00152 { 00153 PWND pwndServer; 00154 PDDECONV pdcNewClient, pdcNewServer; 00155 00156 if (MonitorFlags & MF_SENDMSGS) { 00157 DDEML_MSG_HOOK_DATA dmhd; 00158 00159 dmhd.cbData = 0; // Initiate and Ack sent messages have no data. 00160 dmhd.uiLo = LOWORD(lParam); // they arn't packed either. 00161 dmhd.uiHi = HIWORD(lParam); 00162 xxxMessageEvent(pwndTo, message, wParam, lParam, MF_SENDMSGS, &dmhd); 00163 } 00164 00165 if (PtiCurrent()->ppi == GETPWNDPPI(pwndTo)) { 00166 /* 00167 * Skip monitoring of all intra-process conversations. 00168 */ 00169 return(TRUE); 00170 } 00171 00172 if (message != WM_DDE_ACK) { 00173 if (message == WM_DDE_INITIATE) { 00174 return TRUE; // this is cool 00175 } 00176 return(FALSE); 00177 } 00178 00179 pwndServer = ValidateHwnd((HWND)wParam); 00180 if (pwndServer == NULL) { 00181 return(FALSE); 00182 } 00183 00184 pdcNewServer = FindDdeConv(pwndServer, pwndTo); 00185 if (pdcNewServer != NULL) { 00186 RIPMSG2(RIP_WARNING, 00187 "DDE protocol violation - non-unique window pair (%#p:%#p)", 00188 PtoH(pwndTo), PtoH(pwndServer)); 00189 /* 00190 * Duplicate Conversation case: 00191 * Don't allow the ACK to pass, post a terminate to the server 00192 * to shut down the duplicate on his end. 00193 */ 00194 AnticipatePost(pdcNewServer, DupConvTerminate, NULL, NULL, NULL, 0); 00195 _PostMessage(pwndServer, WM_DDE_TERMINATE, (WPARAM)PtoH(pwndTo), 0); 00196 return(FALSE); 00197 } 00198 00199 if (!NewConversation(&pdcNewClient, &pdcNewServer, pwndTo, pwndServer)) { 00200 return(FALSE); 00201 } 00202 00203 TRACE_DDE2("%#p->%#p DDE Conversation started", PtoH(pwndTo), wParam); 00204 return(TRUE); 00205 } 00206 00207 00208 /************************************************************************ 00209 * AddConvProp 00210 * 00211 * Helper for xxxDDETrackSendHook - associates a new DDECONV struct with 00212 * a window and initializes it. 00213 * 00214 * History: 00215 * 9-3-91 sanfords Created 00216 \***********************************************************************/ 00217 BOOL AddConvProp( 00218 PWND pwndUs, 00219 PWND pwndThem, 00220 DWORD flags, 00221 PDDECONV pdcNew, 00222 PDDECONV pdcPartner) 00223 { 00224 PDDECONV pDdeConv; 00225 PDDEIMP pddei; 00226 00227 pDdeConv = (PDDECONV)_GetProp(pwndUs, PROP_DDETRACK, PROPF_INTERNAL); 00228 Lock(&(pdcNew->snext), pDdeConv); 00229 Lock(&(pdcNew->spwnd), pwndUs); 00230 Lock(&(pdcNew->spwndPartner), pwndThem); 00231 00232 /* 00233 * Assert to catch stress bug. 00234 */ 00235 UserAssert(pdcPartner != (PDDECONV)(-1)); 00236 00237 Lock(&(pdcNew->spartnerConv), pdcPartner); 00238 pdcNew->spxsIn = NULL; 00239 pdcNew->spxsOut = NULL; 00240 pdcNew->flags = flags; 00241 pddei = (PDDEIMP)_GetProp((flags & CXF_IS_SERVER) ? 00242 pwndThem : pwndUs, PROP_DDEIMP, PROPF_INTERNAL); 00243 if (pddei != NULL) { // This can be NULL if a bad WOW app has been 00244 pddei->cRefConv++; // allowed through for compatability. 00245 } 00246 pdcNew->pddei = pddei; 00247 00248 HMLockObject(pdcNew); // lock for property 00249 InternalSetProp(pwndUs, PROP_DDETRACK, pdcNew, PROPF_INTERNAL); 00250 return(TRUE); 00251 } 00252 00253 00254 /************************************************************************ 00255 * UnlinkConv 00256 * 00257 * Unlinks a DDECONV structure from the property list it is associated with. 00258 * 00259 * returns pDdeConv->snext 00260 * 00261 * History: 00262 * 9-3-91 sanfords Created 00263 \***********************************************************************/ 00264 PDDECONV UnlinkConv( 00265 PDDECONV pDdeConv) 00266 { 00267 PDDECONV pdcPrev, pdcT, pDdeConvNext; 00268 00269 /* 00270 * Already unlinked 00271 */ 00272 if (pDdeConv->spwnd == NULL) { 00273 return(NULL); 00274 } 00275 TRACE_DDE1("UnlinkConv(%#p)", pDdeConv); 00276 00277 pdcT = (PDDECONV)_GetProp(pDdeConv->spwnd, 00278 PROP_DDETRACK, PROPF_INTERNAL); 00279 if (pdcT == NULL) { 00280 return(NULL); // already unlinked 00281 } 00282 00283 pdcPrev = NULL; 00284 while (pdcT != pDdeConv) { 00285 pdcPrev = pdcT; 00286 pdcT = pdcT->snext; 00287 if (pdcT == NULL) { 00288 return(NULL); // already unlinked 00289 } 00290 } 00291 00292 if (pdcPrev == NULL) { 00293 if (pDdeConv->snext == NULL) { 00294 // last one out removes the property 00295 InternalRemoveProp(pDdeConv->spwnd, PROP_DDETRACK, PROPF_INTERNAL); 00296 } else { 00297 // head conv unlinked - update prop 00298 InternalSetProp(pDdeConv->spwnd, PROP_DDETRACK, pDdeConv->snext, 00299 PROPF_INTERNAL); 00300 } 00301 } else { 00302 Lock(&(pdcPrev->snext), pDdeConv->snext); 00303 } 00304 pDdeConvNext = Unlock(&(pDdeConv->snext)); 00305 HMUnlockObject(pDdeConv); // unlock for property detachment 00306 return(pDdeConvNext); 00307 } 00308 00309 00310 /************************************************************************ 00311 * xxxDDETrackPostHook 00312 * 00313 * Hook function for handling posted DDE messages. 00314 * 00315 * returns post action code - DO_POST, FAKE_POST, FAIL_POST. 00316 * 00317 * History: 00318 * 9-3-91 sanfords Created 00319 \***********************************************************************/ 00320 DWORD xxxDDETrackPostHook( 00321 PUINT pmessage, 00322 PWND pwndTo, 00323 WPARAM wParam, 00324 LPARAM *plParam, 00325 BOOL fSent) 00326 { 00327 PWND pwndFrom; 00328 PDDECONV pDdeConv = NULL; 00329 DWORD dwRet; 00330 TL tlpDdeConv; 00331 PFREELIST pfl, *ppfl; 00332 DWORD MFlag; 00333 00334 CheckLock(pwndTo); 00335 00336 MFlag = fSent ? MF_SENDMSGS : MF_POSTMSGS; 00337 if (MonitorFlags & MFlag) { 00338 DDEML_MSG_HOOK_DATA dmhd; 00339 00340 switch (*pmessage ) { 00341 case WM_DDE_DATA: 00342 case WM_DDE_POKE: 00343 case WM_DDE_ADVISE: 00344 case WM_DDE_EXECUTE: 00345 case WM_DDE_ACK: 00346 ClientGetDDEHookData(*pmessage, *plParam, &dmhd); 00347 break; 00348 00349 default: 00350 // WM_DDE_REQUEST 00351 // WM_DDE_TERMINATE 00352 // WM_DDE_UNADVISE 00353 dmhd.cbData = 0; 00354 dmhd.uiLo = LOWORD(*plParam); 00355 dmhd.uiHi = HIWORD(*plParam); 00356 } 00357 xxxMessageEvent(pwndTo, *pmessage, wParam, *plParam, MFlag, 00358 &dmhd); 00359 } 00360 00361 if (PtiCurrent()->ppi == GETPWNDPPI(pwndTo)) { 00362 /* 00363 * skip all intra-process conversation tracking. 00364 */ 00365 dwRet = DO_POST; 00366 goto Exit; 00367 } 00368 00369 if (*pmessage == WM_DDE_INITIATE) { 00370 RIPMSG2(RIP_WARNING, 00371 "DDE Post failed (%#p:%#p) - WM_DDE_INITIATE posted", 00372 wParam, PtoH(pwndTo)); 00373 dwRet = FAIL_POST; 00374 goto Exit; 00375 } 00376 00377 pwndFrom = ValidateHwnd((HWND)wParam); 00378 if (pwndFrom == NULL) { 00379 /* 00380 * This is a post AFTER a window has been destroyed. This is not 00381 * expected except in the case where xxxDdeTrackWindowDying() 00382 * is posting a cleanup terminate. 00383 */ 00384 dwRet = *pmessage == WM_DDE_TERMINATE ? DO_POST : FAKE_POST; 00385 goto Exit; 00386 } 00387 00388 /* 00389 * locate conversation info. 00390 */ 00391 pDdeConv = FindDdeConv(pwndFrom, pwndTo); 00392 if (pDdeConv == NULL) { 00393 if (*pmessage != WM_DDE_TERMINATE && 00394 (GETPTI(pwndFrom)->TIF_flags & TIF_16BIT) && 00395 (pwndTo->head.rpdesk == pwndFrom->head.rpdesk)) { 00396 /* 00397 * If a WOW app bypasses initiates and posts directly to 00398 * a window on the same desktop, let it sneak by here. 00399 * 00400 * This allows some evil apps such as OpenEngine and CA-Cricket 00401 * to get away with murder. 00402 * 00403 * TERMINATES out of the blue however may be due to an app 00404 * posting its WM_DDE_TERMINATE after it has destroyed its 00405 * window. Since window destruction would have generated the 00406 * TERMINATE already, don't let it through here. 00407 */ 00408 NewConversation(&pDdeConv, NULL, pwndFrom, pwndTo); 00409 } 00410 if (pDdeConv == NULL) { 00411 RIPMSG2(RIP_VERBOSE, "Can't find DDE conversation for (%#p:%#p).", 00412 wParam, PtoH(pwndTo)); 00413 dwRet = *pmessage == WM_DDE_TERMINATE ? FAKE_POST : FAIL_POST; 00414 goto Exit; 00415 } 00416 } 00417 00418 if (fSent && pDdeConv->spartnerConv->spxsOut != NULL) { 00419 /* 00420 * Sent DDE messages will not work if any posted DDE messages are 00421 * in the queue because this will violate the message ordering rule. 00422 */ 00423 RIPMSG0(RIP_VERBOSE, 00424 "Sent DDE message failed - queue contains a previous post."); 00425 dwRet = FAIL_POST; 00426 goto Exit; 00427 } 00428 00429 /* 00430 * The tracking layer never did allow multiple threads to handle 00431 * the same DDE conversation but win95 shipped and some apps 00432 * got out there that did just this. We will let it slide for 00433 * 4.0 apps only so that when they rev their app, they will see 00434 * that they were wrong. 00435 */ 00436 if (PtiCurrent() != GETPTI(pDdeConv) && 00437 PtiCurrent()->dwExpWinVer != VER40) { 00438 RIPERR0(ERROR_WINDOW_OF_OTHER_THREAD, 00439 RIP_ERROR, 00440 "Posting DDE message from wrong thread!"); 00441 00442 dwRet = FAIL_POST; 00443 goto Exit; 00444 } 00445 00446 ThreadLockAlways(pDdeConv, &tlpDdeConv); 00447 00448 /* 00449 * If the handle we're using is in the free list, remove it 00450 */ 00451 ppfl = &pDdeConv->pfl; 00452 while (*ppfl != NULL) { 00453 if ((*ppfl)->h == (HANDLE)*plParam) { 00454 /* Let's stop to check this out */ 00455 UserAssert((*ppfl)->h == (HANDLE)*plParam); 00456 *ppfl = (*ppfl)->next; 00457 } else { 00458 ppfl = &(*ppfl)->next; 00459 } 00460 } 00461 pfl = pDdeConv->pfl; 00462 pDdeConv->pfl = NULL; 00463 xxxFreeListFree(pfl); 00464 00465 if (*pmessage != WM_DDE_TERMINATE && 00466 (pDdeConv->flags & (CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED))) { 00467 dwRet = FAKE_POST; 00468 goto UnlockExit; 00469 } 00470 00471 if (pDdeConv->spxsOut == NULL) { 00472 if (pDdeConv->flags & CXF_IS_SERVER) { 00473 dwRet = xxxUnexpectedServerPost((PDWORD)pmessage, plParam, pDdeConv); 00474 } else { 00475 dwRet = xxxUnexpectedClientPost((PDWORD)pmessage, plParam, pDdeConv); 00476 } 00477 } else { 00478 dwRet = (pDdeConv->spxsOut->fnResponse)(pmessage, plParam, pDdeConv); 00479 } 00480 00481 UnlockExit: 00482 00483 ThreadUnlock(&tlpDdeConv); 00484 00485 Exit: 00486 00487 if (dwRet == FAKE_POST && !((PtiCurrent())->TIF_flags & TIF_INCLEANUP)) { 00488 /* 00489 * We faked the post so do a client side cleanup here so that we 00490 * don't make it appear there is a leak in the client app. 00491 */ 00492 DWORD flags = XS_DUMPMSG; 00493 /* 00494 * The XS_DUMPMSG tells FreeDDEHandle to also free the atoms 00495 * associated with the data - since a faked post would make the app 00496 * think that the receiver was going to cleanup the atoms. 00497 * It also tells FreeDDEHandle to pay attention to the 00498 * fRelease bit when freeing the data - this way, loaned data 00499 * won't be destroyed. 00500 */ 00501 00502 switch (*pmessage & 0xFFFF) { 00503 case WM_DDE_UNADVISE: 00504 case WM_DDE_REQUEST: 00505 goto DumpMsg; 00506 00507 case WM_DDE_ACK: 00508 flags |= XS_PACKED; 00509 goto DumpMsg; 00510 00511 case WM_DDE_ADVISE: 00512 flags |= XS_PACKED | XS_HIHANDLE; 00513 goto DumpMsg; 00514 00515 case WM_DDE_DATA: 00516 case WM_DDE_POKE: 00517 flags |= XS_DATA | XS_LOHANDLE | XS_PACKED; 00518 goto DumpMsg; 00519 00520 case WM_DDE_EXECUTE: 00521 flags |= XS_EXECUTE; 00522 // fall through 00523 DumpMsg: 00524 if (pDdeConv != NULL) { 00525 TRACE_DDE("xxxDdeTrackPostHook: dumping message..."); 00526 FreeDDEHandle(pDdeConv, (HANDLE)*plParam, flags); 00527 dwRet = FAILNOFREE_POST; 00528 } 00529 } 00530 } 00531 #if DBG 00532 if (fSent) { 00533 TraceDdeMsg(*pmessage, (HWND)wParam, PtoH(pwndTo), MSG_SENT); 00534 } else { 00535 TraceDdeMsg(*pmessage, (HWND)wParam, PtoH(pwndTo), MSG_POST); 00536 } 00537 if (dwRet == FAKE_POST) { 00538 TRACE_DDE("...FAKED!"); 00539 } else if (dwRet == FAIL_POST) { 00540 TRACE_DDE("...FAILED!"); 00541 } else if (dwRet == FAILNOFREE_POST) { 00542 TRACE_DDE("...FAILED, DATA FREED!"); 00543 } 00544 #endif // DBG 00545 return(dwRet); 00546 } 00547 00548 void xxxCleanupDdeConv( 00549 PWND pwndProp) 00550 { 00551 PDDECONV pDdeConv; 00552 00553 Restart: 00554 00555 CheckCritIn(); 00556 00557 pDdeConv = (PDDECONV)_GetProp(pwndProp, PROP_DDETRACK, PROPF_INTERNAL); 00558 00559 while (pDdeConv != NULL) { 00560 if ((pDdeConv->flags & (CXF_IS_SERVER | CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED)) 00561 == (CXF_IS_SERVER | CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED) && 00562 00563 (pDdeConv->spartnerConv->flags & CXF_TERMINATE_POSTED)) { 00564 00565 /* 00566 * clean up client side objects on this side 00567 */ 00568 BOOL fUnlockDdeConv; 00569 TL tlpDdeConv; 00570 00571 RIPMSG1(RIP_VERBOSE, "xxxCleanupDdeConv %p", pDdeConv); 00572 00573 fUnlockDdeConv = (pDdeConv->pfl != NULL); 00574 if (fUnlockDdeConv) { 00575 PFREELIST pfl; 00576 00577 ThreadLockAlways(pDdeConv, &tlpDdeConv); 00578 00579 pfl = pDdeConv->pfl; 00580 pDdeConv->pfl = NULL; 00581 xxxFreeListFree(pfl); 00582 } 00583 00584 FreeDdeConv(pDdeConv->spartnerConv); 00585 FreeDdeConv(pDdeConv); 00586 00587 if (fUnlockDdeConv) { 00588 ThreadUnlock(&tlpDdeConv); 00589 } 00590 00591 /* 00592 * Take it back from the top. The list might have changed 00593 * if we left the critical section 00594 */ 00595 goto Restart; 00596 } 00597 00598 pDdeConv = pDdeConv->snext; 00599 } 00600 } 00601 00602 00603 /************************************************************************ 00604 * xxxDDETrackGetMessageHook 00605 * 00606 * This routine is used to complete an inter-process copy from the 00607 * CSRServer context to the target context. pmsg->lParam is a 00608 * pxs that is used to obtain the pIntDdeInfo needed to 00609 * complete the copy. The pxs is either filled with the target side 00610 * direct handle or is freed depending on the message and its context. 00611 * 00612 * The XS_FREEPXS bit of the flags field of the pxs tells this function 00613 * to free the pxs when done. 00614 * 00615 * History: 00616 * 9-3-91 sanfords Created 00617 \***********************************************************************/ 00618 VOID xxxDDETrackGetMessageHook( 00619 PMSG pmsg) 00620 { 00621 PXSTATE pxs; 00622 HANDLE hDirect; 00623 DWORD flags; 00624 BOOL fUnlockDdeConv; 00625 TL tlpDdeConv, tlpxs; 00626 00627 TraceDdeMsg(pmsg->message, (HWND)pmsg->wParam, pmsg->hwnd, MSG_RECV); 00628 00629 if (pmsg->message == WM_DDE_TERMINATE) { 00630 PWND pwndFrom, pwndTo; 00631 PDDECONV pDdeConv; 00632 00633 pwndTo = ValidateHwnd(pmsg->hwnd); 00634 00635 /* 00636 * We should get the pwnd even if the partner is destroyed in order 00637 * to clean up the DDE objects now. Exiting now would work, but would 00638 * leave the conversation objects locked and present until the To window 00639 * gets destroyed, which seems excessive. 00640 */ 00641 pwndFrom = RevalidateCatHwnd((HWND)pmsg->wParam); 00642 00643 if (pwndTo == NULL) { 00644 TRACE_DDE("TERMINATE ignored, invalid window(s)."); 00645 return; 00646 00647 } else if (pwndFrom == NULL) { 00648 00649 CleanupAndExit: 00650 /* 00651 * Do this only for appcompat 00652 */ 00653 if (GetAppCompatFlags2(VERMAX) & GACF2_DDE) { 00654 xxxCleanupDdeConv(pwndTo); 00655 } else { 00656 TRACE_DDE("TERMINATE ignored, invalid window(s)."); 00657 } 00658 return; 00659 } 00660 00661 /* 00662 * locate conversation info. 00663 */ 00664 pDdeConv = FindDdeConv(pwndTo, pwndFrom); 00665 if (pDdeConv == NULL) { 00666 /* 00667 * Must be a harmless extra terminate. 00668 */ 00669 TRACE_DDE("TERMINATE ignored, conversation not found."); 00670 return; 00671 } 00672 00673 if (pDdeConv->flags & CXF_TERMINATE_POSTED && 00674 pDdeConv->spartnerConv->flags & CXF_TERMINATE_POSTED) { 00675 00676 /* 00677 * clean up client side objects on this side 00678 */ 00679 fUnlockDdeConv = FALSE; 00680 if (pDdeConv->pfl != NULL) { 00681 PFREELIST pfl; 00682 00683 fUnlockDdeConv = TRUE; 00684 ThreadLockAlways(pDdeConv, &tlpDdeConv); 00685 pfl = pDdeConv->pfl; 00686 pDdeConv->pfl = NULL; 00687 xxxFreeListFree(pfl); 00688 } 00689 00690 TRACE_DDE2("DDE conversation (%#p:%#p) closed", 00691 (pDdeConv->flags & CXF_IS_SERVER) ? pmsg->wParam : (ULONG_PTR)pmsg->hwnd, 00692 (pDdeConv->flags & CXF_IS_SERVER) ? (ULONG_PTR)pmsg->hwnd : pmsg->wParam); 00693 00694 FreeDdeConv(pDdeConv->spartnerConv); 00695 FreeDdeConv(pDdeConv); 00696 00697 if (fUnlockDdeConv) { 00698 ThreadUnlock(&tlpDdeConv); 00699 } 00700 } 00701 00702 goto CleanupAndExit; 00703 } 00704 00705 pxs = (PXSTATE)HMValidateHandleNoRip((HANDLE)pmsg->lParam, TYPE_DDEXACT); 00706 if (pxs == NULL) { 00707 /* 00708 * The posting window has died and the pxs was freed so this 00709 * message shouldn't be bothered with...map to WM_NULL. 00710 */ 00711 pmsg->lParam = 0; 00712 pmsg->message = WM_NULL; 00713 return; 00714 } 00715 flags = pxs->flags; 00716 00717 ThreadLockAlways(pxs, &tlpxs); 00718 pmsg->lParam = (LPARAM)xxxCopyDDEOut(pxs->pIntDdeInfo, &hDirect); 00719 if (pmsg->lParam == (LPARAM)NULL) { 00720 /* 00721 * Turn this message into a terminate - we failed to copy the 00722 * message data out which implies we are too low on memory 00723 * to continue the conversation. Shut it down now before 00724 * other problems pop up that this failure will cause. 00725 */ 00726 pmsg->message = WM_DDE_TERMINATE; 00727 RIPMSG0(RIP_WARNING, "DDETrack: couldn't copy data out, terminate faked."); 00728 } 00729 if (ThreadUnlock(&tlpxs) == NULL) { 00730 return; 00731 } 00732 00733 if (flags & XS_FREEPXS) { 00734 FreeDdeXact(pxs); 00735 return; 00736 } 00737 00738 /* 00739 * The only reason XS_FREEPXS isn't set is because we don't know which 00740 * side frees the data till an ACK comes back, thus one of the client 00741 * handles in pxs is already set via xxxDDETrackPostHook(). The one thats 00742 * not yet set gets set here. 00743 */ 00744 00745 if (pxs->hClient == NULL) { 00746 TRACE_DDE1("Saving %#p into hClient", hDirect); 00747 pxs->hClient = hDirect; 00748 } else { 00749 TRACE_DDE1("Saving %#p into hServer.", hDirect); 00750 pxs->hServer = hDirect; 00751 } 00752 return; 00753 } 00754 00755 00756 00757 /************************************************************************ 00758 * xxxDDETrackWindowDying 00759 * 00760 * Called when a window with PROP_DDETRACK is destroyed. 00761 * 00762 * This posts a terminate to the partner window and sets up for proper 00763 * terminate post fake from other end. 00764 * 00765 * History: 00766 * 9-3-91 sanfords Created 00767 \***********************************************************************/ 00768 VOID xxxDDETrackWindowDying( 00769 PWND pwnd, 00770 PDDECONV pDdeConv) 00771 { 00772 TL tlpDdeConv, tlpDdeConvNext; 00773 00774 UNREFERENCED_PARAMETER(pwnd); 00775 00776 CheckLock(pwnd); 00777 CheckLock(pDdeConv); 00778 00779 TRACE_DDE2("xxxDDETrackWindowDying(%#p, %#p)", PtoH(pwnd), pDdeConv); 00780 00781 while (pDdeConv != NULL) { 00782 00783 PFREELIST pfl; 00784 00785 /* 00786 * If there are any active conversations for this window 00787 * start termination if not already started. 00788 */ 00789 if (!(pDdeConv->flags & CXF_TERMINATE_POSTED)) { 00790 /* 00791 * Win9x doesn't do any tracking. This breaks some apps that 00792 * destroy the window first and then post the terminate. The 00793 * other side gets two terminates. 00794 */ 00795 if (!(GACF2_NODDETRKDYING & GetAppCompatFlags2(VER40)) 00796 || (pDdeConv->spwndPartner == NULL) 00797 || !(GACF2_NODDETRKDYING 00798 & GetAppCompatFlags2ForPti(GETPTI(pDdeConv->spwndPartner), VER40))) { 00799 00800 /* 00801 * CXF_TERMINATE_POSTED would have been set if the window had died. 00802 */ 00803 _PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE, 00804 (WPARAM)PtoH(pDdeConv->spwnd), 0); 00805 // pDdeConv->flags |= CXF_TERMINATE_POSTED; set by PostHookProc 00806 } else { 00807 RIPMSG2(RIP_WARNING, "xxxDDETrackWindowDying(GACF2_NODDETRKDYING) not posting terminate from %#p to %#p\r\n", 00808 pwnd, pDdeConv->spwndPartner); 00809 } 00810 } 00811 00812 /* 00813 * now fake that the other side already posted a terminate since 00814 * we will be gone. 00815 */ 00816 pDdeConv->spartnerConv->flags |= 00817 CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED; 00818 00819 ThreadLock(pDdeConv->snext, &tlpDdeConvNext); 00820 ThreadLockAlways(pDdeConv, &tlpDdeConv); 00821 00822 pfl = pDdeConv->pfl; 00823 pDdeConv->pfl = NULL; 00824 00825 if (pDdeConv->flags & CXF_PARTNER_WINDOW_DIED) { 00826 00827 ThreadUnlock(&tlpDdeConv); 00828 /* 00829 * he's already gone, free up conversation tracking data 00830 */ 00831 FreeDdeConv(pDdeConv->spartnerConv); 00832 FreeDdeConv(pDdeConv); 00833 } else { 00834 UnlinkConv(pDdeConv); 00835 ThreadUnlock(&tlpDdeConv); 00836 } 00837 xxxFreeListFree(pfl); 00838 00839 pDdeConv = ThreadUnlock(&tlpDdeConvNext); 00840 } 00841 } 00842 00843 00844 00845 /************************************************************************ 00846 * xxxUnexpectedServerPost 00847 * 00848 * Handles Server DDE messages not anticipated. (ie spontaneous or abnormal) 00849 * 00850 * History: 00851 * 9-3-91 sanfords Created 00852 \***********************************************************************/ 00853 DWORD xxxUnexpectedServerPost( 00854 PDWORD pmessage, 00855 LPARAM *plParam, 00856 PDDECONV pDdeConv) 00857 { 00858 switch (*pmessage) { 00859 case WM_DDE_TERMINATE: 00860 return(SpontaneousTerminate(pmessage, pDdeConv)); 00861 00862 case WM_DDE_DATA: 00863 return(xxxAdviseData(pmessage, plParam, pDdeConv)); 00864 00865 case WM_DDE_ACK: 00866 00867 /* 00868 * Could be an extra NACK due to timeout problems, just fake it. 00869 */ 00870 TRACE_DDE("xxxUnexpectedServerPost: dumping ACK data..."); 00871 FreeDDEHandle(pDdeConv, (HANDLE)*plParam, XS_PACKED); 00872 return(FAILNOFREE_POST); 00873 00874 case WM_DDE_ADVISE: 00875 case WM_DDE_UNADVISE: 00876 case WM_DDE_REQUEST: 00877 case WM_DDE_POKE: 00878 case WM_DDE_EXECUTE: 00879 return(AbnormalDDEPost(pDdeConv, *pmessage)); 00880 } 00881 return 0; 00882 } 00883 00884 00885 00886 /************************************************************************ 00887 * xxxUnexpectedClientPost 00888 * 00889 * 00890 * Handles Client DDE messages not anticipated. (ie spontaneous or abnormal) 00891 * 00892 * History: 00893 * 9-3-91 sanfords Created 00894 \***********************************************************************/ 00895 DWORD xxxUnexpectedClientPost( 00896 PDWORD pmessage, 00897 LPARAM *plParam, 00898 PDDECONV pDdeConv) 00899 { 00900 switch (*pmessage) { 00901 case WM_DDE_TERMINATE: 00902 return(SpontaneousTerminate(pmessage, pDdeConv)); 00903 00904 case WM_DDE_ACK: 00905 00906 /* 00907 * Could be an extra NACK due to timeout problems, just fake it. 00908 */ 00909 TRACE_DDE("xxxUnexpectedClientPost: dumping ACK data..."); 00910 FreeDDEHandle(pDdeConv, (HANDLE)*plParam, XS_PACKED); 00911 return(FAILNOFREE_POST); 00912 00913 case WM_DDE_DATA: 00914 return(AbnormalDDEPost(pDdeConv, *pmessage)); 00915 00916 case WM_DDE_ADVISE: 00917 return(xxxAdvise(pmessage, plParam, pDdeConv)); 00918 00919 case WM_DDE_UNADVISE: 00920 return(Unadvise(pDdeConv)); 00921 00922 case WM_DDE_REQUEST: 00923 return(Request(pDdeConv)); 00924 00925 case WM_DDE_POKE: 00926 return(xxxPoke(pmessage, plParam, pDdeConv)); 00927 00928 case WM_DDE_EXECUTE: 00929 return(xxxExecute(pmessage, plParam, pDdeConv)); 00930 } 00931 return 0; 00932 } 00933 00934 00935 00936 /************************************************************************ 00937 * ADVISE TRANSACTION PROCESSING * 00938 \***********************************************************************/ 00939 00940 00941 00942 DWORD xxxAdvise( // Spontaneous Client transaction = WM_DDE_ADVISE 00943 PDWORD pmessage, 00944 LPARAM *plParam, 00945 PDDECONV pDdeConv) 00946 { 00947 PINTDDEINFO pIntDdeInfo; 00948 HANDLE hDirect; 00949 DWORD flags, dwRet; 00950 00951 CheckLock(pDdeConv); 00952 00953 TRACE_DDE("xxxAdvise"); 00954 flags = XS_PACKED | XS_LOHANDLE; 00955 dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo); 00956 if (dwRet == DO_POST) { 00957 UserAssert(pIntDdeInfo != NULL); 00958 *pmessage |= MSGFLAG_DDE_MID_THUNK; 00959 *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxAdviseAck, 00960 hDirect, NULL, pIntDdeInfo, flags); 00961 if (*plParam == 0) { 00962 dwRet = FAILNOFREE_POST; 00963 } 00964 } 00965 return dwRet; 00966 } 00967 00968 /* 00969 * If its inter-process: 00970 * 00971 * xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_ADVISE 00972 * is received. pIntDdeInfo is then freed. The hServer handle is saved into the 00973 * pxs structure pointed to by lParam is a direct data structure since 00974 * packed DDE messages are always assumed to have the packing handle freed. 00975 */ 00976 00977 00978 DWORD xxxAdviseAck( // Server response to advise - WM_DDE_ACK expected 00979 PDWORD pmessage, 00980 LPARAM *plParam, 00981 PDDECONV pDdeConv) 00982 { 00983 PXSTATE pxsFree; 00984 PINTDDEINFO pIntDdeInfo; 00985 DWORD dwRet; 00986 00987 CheckLock(pDdeConv); 00988 00989 if (*pmessage != WM_DDE_ACK) { 00990 return(xxxUnexpectedServerPost(pmessage, plParam, pDdeConv)); 00991 } 00992 00993 TRACE_DDE("xxxAdviseAck"); 00994 00995 dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo); 00996 if (dwRet != DO_POST) { 00997 return dwRet; 00998 } 00999 UserAssert(pIntDdeInfo != NULL); 01000 01001 pxsFree = pDdeConv->spxsOut; 01002 if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) { 01003 01004 /* 01005 * positive ack implies server accepted the hOptions data - free from 01006 * client at postmessage time. 01007 */ 01008 TRACE_DDE("xxxAdviseAck: +ACK delayed freeing data from client"); 01009 FreeListAdd(pDdeConv->spartnerConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED); 01010 } else { 01011 // Shouldn't this be freed directly? 01012 TRACE_DDE("xxxAdviseAck: -ACK delayed freeing data from server"); 01013 FreeListAdd(pDdeConv, pxsFree->hServer, pxsFree->flags & ~XS_PACKED); 01014 } 01015 01016 PopState(pDdeConv); 01017 return(DO_POST); 01018 } 01019 01020 01021 01022 /************************************************************************ 01023 * ADVISE DATA TRANSACTION PROCESSING * 01024 \***********************************************************************/ 01025 01026 01027 01028 DWORD xxxAdviseData( // spontaneous from server - WM_DDE_DATA 01029 PDWORD pmessage, 01030 LPARAM *plParam, 01031 PDDECONV pDdeConv) 01032 { 01033 DWORD flags, dwRet; 01034 PINTDDEINFO pIntDdeInfo; 01035 HANDLE hDirect; 01036 PXSTATE pxs; 01037 01038 CheckLock(pDdeConv); 01039 01040 TRACE_DDE("xxxAdviseData"); 01041 01042 flags = XS_PACKED | XS_LOHANDLE | XS_DATA; 01043 01044 dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo); 01045 if (dwRet == DO_POST) { 01046 UserAssert(pIntDdeInfo != NULL); 01047 TRACE_DDE1("xxxAdviseData: wStatus = %x", 01048 ((PDDE_DATA)(pIntDdeInfo + 1))->wStatus); 01049 if (!(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & (DDE_FACK | DDE_FRELEASE))) { 01050 RIPMSG0(RIP_ERROR, "DDE protocol violation - no RELEASE or ACK bit set - setting RELEASE."); 01051 ((PDDE_DATA)(pIntDdeInfo + 1))->wStatus |= DDE_FRELEASE; 01052 } 01053 if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FRELEASE) { 01054 /* 01055 * giving it away 01056 */ 01057 if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) { 01058 RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object."); 01059 UserFreePool(pIntDdeInfo); 01060 return(FAILNOFREE_POST); 01061 } 01062 if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt, 01063 pIntDdeInfo->hIndirect, 01064 (W32PID)(GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid))) { 01065 flags |= XS_GIVEBACKONNACK; 01066 } 01067 flags |= XS_FRELEASE; 01068 } else { 01069 /* 01070 * on loan 01071 */ 01072 if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt, 01073 pIntDdeInfo->hIndirect, 01074 (W32PID)(GETPTI(pDdeConv->spwnd)->ppi->W32Pid))) { 01075 flags |= XS_PUBLICOBJ; 01076 } 01077 } 01078 01079 *pmessage |= MSGFLAG_DDE_MID_THUNK; 01080 if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FACK) { 01081 *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, 01082 xxxAdviseDataAck, NULL, hDirect, pIntDdeInfo, flags); 01083 } else { 01084 TRACE_DDE("xxxAdviseData: dumping non Ackable data..."); 01085 UserAssert(hDirect != (HANDLE)*plParam); 01086 FreeDDEHandle(pDdeConv, hDirect, flags & ~XS_PACKED); 01087 pxs = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS); 01088 if (pxs != NULL) { 01089 pxs->head.pti = GETPTI(pDdeConv->spwndPartner); 01090 } 01091 *plParam = (LPARAM)PtoH(pxs); 01092 } 01093 if (*plParam == 0) { 01094 dwRet = FAILNOFREE_POST; 01095 } 01096 } 01097 return dwRet; 01098 } 01099 01100 01101 /* 01102 * If its inter-process: 01103 * 01104 * xxxDDETrackGetMessageHook() completes the copy from pIntDdeInfo when WM_DDE_DATA 01105 * is received. pIntDdeInfo is then freed. The hServer handle saved into the 01106 * pxs structure pointed to by lParam is a directdata structure since 01107 * packed DDE messages are always assumed to have the packing handle freed 01108 * by the receiving app. 01109 * For the !fAckReq case, the pxs is freed due to the XS_FREEPXS flag. 01110 */ 01111 01112 01113 DWORD xxxAdviseDataAck( // Client response to advise data - WM_DDE_ACK expected 01114 PDWORD pmessage, 01115 LPARAM *plParam, 01116 PDDECONV pDdeConv) 01117 { 01118 PXSTATE pxsFree; 01119 PINTDDEINFO pIntDdeInfo; 01120 DWORD dwRet; 01121 01122 CheckLock(pDdeConv); 01123 01124 /* 01125 * This is also used for request data ack processing. 01126 */ 01127 if (*pmessage != WM_DDE_ACK) { 01128 return(xxxUnexpectedClientPost(pmessage, plParam, pDdeConv)); 01129 } 01130 01131 TRACE_DDE("xxxAdviseDataAck"); 01132 01133 dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo); 01134 if (dwRet != DO_POST) { 01135 return dwRet; 01136 } 01137 UserAssert(pIntDdeInfo != NULL); 01138 01139 pxsFree = pDdeConv->spxsOut; 01140 TRACE_DDE3("xxxAdviseDataAck:pxs.hClient(%#p), hServer(%#p), wStatus(%x)", 01141 pxsFree->hClient, pxsFree->hServer, pIntDdeInfo->DdePack.uiLo); 01142 if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) { 01143 01144 /* 01145 * positive ack implies client accepted the data - free from 01146 * server at postmessage time iff FRELEASE was set in data msg. 01147 */ 01148 if (pxsFree->flags & XS_FRELEASE) { 01149 TRACE_DDE("xxxAdviseDataAck: +ACK delayed server data free"); 01150 FreeListAdd(pDdeConv->spartnerConv, pxsFree->hServer, 01151 pxsFree->flags & ~XS_PACKED); 01152 } else { 01153 /* 01154 * Ack w/out fRelease bit means client is done with data. 01155 */ 01156 TRACE_DDE1("xxxAdviseDataAck: Freeing %#p. (+ACK)", 01157 pxsFree->hClient); 01158 UserAssert(pxsFree->hClient != (HANDLE)*plParam); 01159 FreeDDEHandle(pDdeConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED); 01160 } 01161 01162 } else { 01163 TRACE_DDE1("xxxAdviseDataAck: Freeing %#p. (-ACK)", 01164 pxsFree->hClient); 01165 FreeDDEHandle(pDdeConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED); 01166 UserAssert(pxsFree->hClient != (HANDLE)*plParam); 01167 } 01168 PopState(pDdeConv); 01169 return(DO_POST); 01170 } 01171 01172 01173 01174 /************************************************************************ 01175 * UNADVISE TRANSACTION PROCESSING * 01176 \***********************************************************************/ 01177 01178 01179 01180 DWORD Unadvise( // Spontaneous client transaction = WM_DDE_UNADVISE 01181 PDDECONV pDdeConv) 01182 { 01183 TRACE_DDE("Unadvise"); 01184 if (AnticipatePost(pDdeConv->spartnerConv, xxxUnadviseAck, NULL, NULL, NULL, 0)) { 01185 return(DO_POST); 01186 } else { 01187 return(FAIL_POST); 01188 } 01189 } 01190 01191 01192 01193 DWORD xxxUnadviseAck( // Server response to unadvise - WM_DDE_ACK expected 01194 PDWORD pmessage, 01195 LPARAM *plParam, 01196 PDDECONV pDdeConv) 01197 { 01198 DWORD dwRet; 01199 PINTDDEINFO pIntDdeInfo; 01200 CheckLock(pDdeConv); 01201 01202 if (*pmessage != WM_DDE_ACK) { 01203 return(xxxUnexpectedServerPost(pmessage, plParam, pDdeConv)); 01204 } 01205 TRACE_DDE("xxxUnadviseAck"); 01206 dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo); 01207 if (dwRet != DO_POST) { 01208 return dwRet; 01209 } 01210 UserAssert(pIntDdeInfo != NULL); 01211 PopState(pDdeConv); 01212 return(DO_POST); 01213 } 01214 01215 01216 01217 /************************************************************************ 01218 * REQUEST TRANSACTION PROCESSING * 01219 \***********************************************************************/ 01220 01221 DWORD Request( // Spontaneous Client transaction - WM_DDE_REQUEST 01222 PDDECONV pDdeConv) 01223 { 01224 TRACE_DDE("Request"); 01225 if (AnticipatePost(pDdeConv->spartnerConv, xxxRequestAck, NULL, NULL, NULL, 0)) { 01226 return(DO_POST); 01227 } else { 01228 return(FAIL_POST); 01229 } 01230 } 01231 01232 01233 01234 DWORD xxxRequestAck( // Server response - WM_DDE_ACK or WM_DDE_DATA expected 01235 PDWORD pmessage, 01236 LPARAM *plParam, 01237 PDDECONV pDdeConv) 01238 { 01239 PXSTATE pxsFree; 01240 DWORD flags; 01241 PINTDDEINFO pIntDdeInfo; 01242 HANDLE hDirect; 01243 DWORD dwStatus, dwRet; 01244 01245 CheckLock(pDdeConv); 01246 01247 TRACE_DDE("xxxRequestAck or xxxAdviseData"); 01248 switch (*pmessage) { 01249 case WM_DDE_DATA: 01250 01251 /* 01252 * This is very close to advise data handling - the only catch 01253 * is that if the fRequest bit is clear this IS advise data. 01254 */ 01255 flags = XS_PACKED | XS_LOHANDLE | XS_DATA; 01256 01257 dwStatus = ClientGetDDEFlags((HANDLE)*plParam, flags); 01258 01259 if (!(dwStatus & DDE_FREQUESTED)) { 01260 01261 /* 01262 * Its NOT a request Ack - it must be advise data 01263 */ 01264 return(xxxAdviseData(pmessage, plParam, pDdeConv)); 01265 } 01266 01267 pxsFree = pDdeConv->spxsOut; 01268 dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo); 01269 if (dwRet == DO_POST) { 01270 UserAssert(pIntDdeInfo != NULL); 01271 if (!(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & (DDE_FACK | DDE_FRELEASE))) { 01272 RIPMSG0(RIP_ERROR, "DDE protocol violation - no RELEASE or ACK bit set - setting RELEASE."); 01273 ((PDDE_DATA)(pIntDdeInfo + 1))->wStatus |= DDE_FRELEASE; 01274 } 01275 if (dwStatus & DDE_FRELEASE) { 01276 /* 01277 * giving it away 01278 */ 01279 if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) { 01280 RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object."); 01281 UserFreePool(pIntDdeInfo); 01282 return FAILNOFREE_POST; 01283 } 01284 if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt, 01285 pIntDdeInfo->hIndirect, 01286 (W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid)) { 01287 flags |= XS_GIVEBACKONNACK; 01288 } 01289 flags |= XS_FRELEASE; 01290 } else { 01291 /* 01292 * on loan 01293 */ 01294 if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt, 01295 pIntDdeInfo->hIndirect, 01296 (W32PID)GETPTI(pDdeConv->spwnd)->ppi->W32Pid)) { 01297 flags |= XS_PUBLICOBJ; 01298 } 01299 } 01300 *pmessage |= MSGFLAG_DDE_MID_THUNK; 01301 if (dwStatus & DDE_FACK) { 01302 *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, 01303 xxxAdviseDataAck, NULL, hDirect, pIntDdeInfo, flags); 01304 } else { 01305 TRACE_DDE("xxxRequestAck: Delayed freeing non-ackable request data"); 01306 FreeListAdd(pDdeConv, hDirect, flags & ~XS_PACKED); 01307 pxsFree = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS); 01308 if (pxsFree != NULL) { 01309 pxsFree->head.pti = GETPTI(pDdeConv->spwndPartner); 01310 } 01311 *plParam = (LPARAM)PtoH(pxsFree); 01312 } 01313 01314 if (*plParam != 0) { 01315 PopState(pDdeConv); 01316 } else { 01317 dwRet = FAILNOFREE_POST; 01318 } 01319 } 01320 return dwRet; 01321 01322 case WM_DDE_ACK: // server NACKs request 01323 dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo); 01324 if (dwRet != DO_POST) { 01325 return dwRet; 01326 } 01327 UserAssert(pIntDdeInfo != NULL); 01328 PopState(pDdeConv); 01329 return(DO_POST); 01330 01331 default: 01332 return(xxxUnexpectedServerPost(pmessage, plParam, pDdeConv)); 01333 } 01334 } 01335 01336 01337 01338 /************************************************************************ 01339 * POKE TRANSACTION PROCESSING * 01340 \***********************************************************************/ 01341 01342 01343 01344 DWORD xxxPoke( // spontaneous client transaction - WM_DDE_POKE 01345 PDWORD pmessage, 01346 LPARAM *plParam, 01347 PDDECONV pDdeConv) 01348 { 01349 DWORD flags, dwRet; 01350 PINTDDEINFO pIntDdeInfo; 01351 HANDLE hDirect; 01352 01353 CheckLock(pDdeConv); 01354 01355 TRACE_DDE("xxxPoke"); 01356 flags = XS_PACKED | XS_LOHANDLE | XS_DATA; 01357 dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo); 01358 if (dwRet == DO_POST) { 01359 UserAssert(pIntDdeInfo != NULL); 01360 if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FRELEASE) { 01361 /* 01362 * giving it away 01363 */ 01364 if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) { 01365 RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object."); 01366 UserFreePool(pIntDdeInfo); 01367 return FAILNOFREE_POST; 01368 } 01369 if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt, 01370 pIntDdeInfo->hIndirect, 01371 (W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid)) { 01372 flags |= XS_GIVEBACKONNACK; 01373 } 01374 flags |= XS_FRELEASE; 01375 } else { 01376 /* 01377 * on loan 01378 */ 01379 /* 01380 * fAck bit is ignored and assumed on. 01381 */ 01382 if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt, 01383 pIntDdeInfo->hIndirect, 01384 (W32PID)GETPTI(pDdeConv->spwnd)->ppi->W32Pid)) { 01385 flags |= XS_PUBLICOBJ; 01386 } 01387 } 01388 *pmessage |= MSGFLAG_DDE_MID_THUNK; 01389 *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxPokeAck, 01390 hDirect, NULL, pIntDdeInfo, flags); 01391 if (*plParam == 0) { 01392 dwRet = FAILNOFREE_POST; 01393 } 01394 } 01395 return dwRet; 01396 } 01397 01398 01399 /* 01400 * If its inter-process: 01401 * 01402 * xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_ADVISE 01403 * is received. pIntDdeInfo is then freed. The hServer handle saved into the 01404 * pxs structure pointer to by lParam is a directdata structure since 01405 * packed DDE messages are always assumed to have the packing handle freed 01406 * by the receiving app. 01407 * For the !fAckReq case, the pxs is also freed due to the XS_FREEPXS flag. 01408 */ 01409 01410 01411 DWORD xxxPokeAck( // Server response to poke data - WM_DDE_ACK expected 01412 PDWORD pmessage, 01413 LPARAM *plParam, 01414 PDDECONV pDdeConv) 01415 { 01416 PXSTATE pxsFree; 01417 PINTDDEINFO pIntDdeInfo; 01418 DWORD dwRet; 01419 01420 CheckLock(pDdeConv); 01421 01422 if (*pmessage != WM_DDE_ACK) { 01423 return(xxxUnexpectedServerPost(pmessage, plParam, pDdeConv)); 01424 } 01425 01426 TRACE_DDE("xxxPokeAck"); 01427 01428 dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo); 01429 if (dwRet != DO_POST) { 01430 return dwRet; 01431 } 01432 UserAssert(pIntDdeInfo != NULL); 01433 01434 pxsFree = pDdeConv->spxsOut; 01435 if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) { 01436 // positive ack implies server accepted the data - free from 01437 // client at postmessage time iff fRelease was set in poke message. 01438 if (pxsFree->flags & XS_FRELEASE) { 01439 TRACE_DDE("xxxPokeAck: delayed freeing client data"); 01440 FreeListAdd(pDdeConv->spartnerConv, pxsFree->hClient, 01441 pxsFree->flags & ~XS_PACKED); 01442 } 01443 } else { 01444 // Nack means that sender is responsible for freeing it. 01445 // We must free it in the receiver's context for him. 01446 TRACE_DDE("xxxPokeAck: freeing Nacked data"); 01447 UserAssert(pxsFree->hServer != (HANDLE)*plParam); 01448 FreeDDEHandle(pDdeConv, pxsFree->hServer, pxsFree->flags & ~XS_PACKED); 01449 } 01450 PopState(pDdeConv); 01451 return(DO_POST); 01452 } 01453 01454 01455 01456 /************************************************************************ 01457 * EXECUTE TRANSACTION PROCESSING * 01458 \***********************************************************************/ 01459 01460 DWORD xxxExecute( // spontaneous client transaction - WM_DDE_EXECUTE 01461 PDWORD pmessage, 01462 LPARAM *plParam, 01463 PDDECONV pDdeConv) 01464 { 01465 DWORD flags, dwRet; 01466 PINTDDEINFO pIntDdeInfo; 01467 HANDLE hDirect; 01468 01469 CheckLock(pDdeConv); 01470 01471 TRACE_DDE("xxxExecute"); 01472 01473 flags = XS_EXECUTE; 01474 if (!TestWF(pDdeConv->spwnd, WFANSIPROC) && 01475 !TestWF(pDdeConv->spwndPartner, WFANSIPROC)) { 01476 flags |= XS_UNICODE; 01477 } 01478 dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo); 01479 if (dwRet == DO_POST) { 01480 UserAssert(pIntDdeInfo != NULL); 01481 *pmessage |= MSGFLAG_DDE_MID_THUNK; 01482 *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxExecuteAck, 01483 hDirect, NULL, pIntDdeInfo, flags); 01484 /* 01485 * Check for != 0 to make sure the AnticipatePost() succeeded. 01486 */ 01487 if (*plParam != 0) { 01488 01489 /* 01490 * In the execute case it is likely that the postee will want to activate 01491 * itself and come on top (OLE 1.0 is an example). In this case, allow 01492 * both the postee and the poster to foreground activate for the next 01493 * activate (poster because it will want to activate itself again 01494 * probably, once the postee is done.) 01495 */ 01496 GETPTI(pDdeConv->spwnd)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 01497 TAGMSG1(DBGTAG_FOREGROUND, "xxxExecute set TIF %#p", GETPTI(pDdeConv->spwnd)); 01498 GETPTI(pDdeConv->spwndPartner)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 01499 TAGMSG1(DBGTAG_FOREGROUND, "xxxExecute set TIF %#p", GETPTI(pDdeConv->spwndPartner)); 01500 } else { 01501 dwRet = FAILNOFREE_POST; 01502 } 01503 01504 } 01505 return dwRet; 01506 } 01507 01508 01509 /* 01510 * xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_EXECUTE 01511 * is received. pIntDdeInfo is then freed. 01512 */ 01513 01514 01515 DWORD xxxExecuteAck( // Server response to execute data - WM_DDE_ACK expected 01516 PDWORD pmessage, 01517 LPARAM *plParam, 01518 PDDECONV pDdeConv) 01519 { 01520 PXSTATE pxsFree; 01521 PINTDDEINFO pi; 01522 DWORD flags = XS_PACKED | XS_FREESRC | XS_EXECUTE; 01523 DWORD dwRet; 01524 01525 CheckLock(pDdeConv); 01526 01527 if (*pmessage != WM_DDE_ACK) { 01528 return(xxxUnexpectedServerPost(pmessage, plParam, pDdeConv)); 01529 } 01530 01531 TRACE_DDE("xxxExecuteAck"); 01532 dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, NULL, &pi); 01533 if (dwRet == DO_POST) { 01534 UserAssert(pi != NULL); 01535 /* 01536 * the server must respond to the execute with an ack containing the 01537 * same handle it was given. 01538 */ 01539 pi->DdePack.uiHi = (ULONG_PTR)pDdeConv->spxsOut->hClient; 01540 pi->hDirect = NULL; 01541 pi->cbDirect = 0; 01542 *pmessage |= MSGFLAG_DDE_MID_THUNK; 01543 pxsFree = Createpxs(NULL, NULL, NULL, pi, XS_PACKED | XS_FREEPXS); 01544 if (pxsFree != NULL) { 01545 pxsFree->head.pti = GETPTI(pDdeConv->spwndPartner); 01546 } 01547 *plParam = (LPARAM)PtoH(pxsFree); 01548 if (*plParam != 0) { 01549 PopState(pDdeConv); 01550 } else { 01551 dwRet = FAILNOFREE_POST; 01552 } 01553 } 01554 return dwRet; 01555 } 01556 01557 01558 01559 /************************************************************************ 01560 * TERMINATE TRANSACTION PROCESSING * 01561 \***********************************************************************/ 01562 01563 01564 01565 DWORD SpontaneousTerminate( 01566 PDWORD pmessage, 01567 PDDECONV pDdeConv) 01568 { 01569 TRACE_DDE("SpontaneousTerminate"); 01570 if (pDdeConv->flags & CXF_TERMINATE_POSTED) { 01571 return(FAKE_POST); 01572 } else { 01573 pDdeConv->flags |= CXF_TERMINATE_POSTED; 01574 *pmessage |= MSGFLAG_DDE_MID_THUNK; 01575 return(DO_POST); 01576 } 01577 } 01578 01579 /* 01580 * The xxxDDETrackGetMessageHook() function restores the *pmessage value. 01581 * Unless a spontaneous terminate from the other app has already 01582 * arrived, it will note that CXF_TERMINATE_POSTED is NOT set on 01583 * both sides so no action is taken. 01584 */ 01585 01586 01587 /************************************************************************ 01588 * DUPLICATE CONVERSATION TERMINATION * 01589 \***********************************************************************/ 01590 01591 /* 01592 * This routine is called when a DDE server window sent a WM_DDE_ACK 01593 * message to a client window which is already engaged in a conversation 01594 * with that server window. We swallow the ACK and post a terminate to 01595 * the server window to shut this conversation down. When the server 01596 * posts the terminate, this function is called to basically fake 01597 * a sucessful post. Thus the client is never bothered while the 01598 * errant server thinks the conversation was connected and then 01599 * imediately terminated. 01600 */ 01601 DWORD DupConvTerminate( // WM_DDE_TERMINATE expected 01602 PDWORD pmessage, 01603 LPARAM *plParam, 01604 PDDECONV pDdeConv) 01605 { 01606 CheckLock(pDdeConv); 01607 01608 TRACE_DDE("DupConvTerminate"); 01609 01610 if (*pmessage != WM_DDE_TERMINATE) { 01611 return(xxxUnexpectedServerPost(pmessage, plParam, pDdeConv)); 01612 } 01613 01614 PopState(pDdeConv); 01615 return(FAKE_POST); 01616 } 01617 01618 01619 01620 /************************************************************************ 01621 * HELPER ROUTINES FOR TRANSACTION TRACKING * 01622 \***********************************************************************/ 01623 01624 01625 01626 /************************************************************************ 01627 * AnticipatePost 01628 * 01629 * Allocates, fills and links XSTATE structures. 01630 * 01631 * History: 01632 * 9-3-91 sanfords Created 01633 \***********************************************************************/ 01634 HANDLE AnticipatePost( 01635 PDDECONV pDdeConv, 01636 FNDDERESPONSE fnResponse, 01637 HANDLE hClient, 01638 HANDLE hServer, 01639 PINTDDEINFO pIntDdeInfo, 01640 DWORD flags) 01641 { 01642 PXSTATE pxs; 01643 01644 pxs = Createpxs(fnResponse, hClient, hServer, pIntDdeInfo, flags); 01645 if (pxs != NULL) { 01646 pxs->head.pti = pDdeConv->head.pti; 01647 if (pDdeConv->spxsOut == NULL) { 01648 UserAssert(pDdeConv->spxsIn == NULL); 01649 Lock(&(pDdeConv->spxsOut), pxs); 01650 Lock(&(pDdeConv->spxsIn), pxs); 01651 } else { 01652 UserAssert(pDdeConv->spxsIn != NULL); 01653 Lock(&(pDdeConv->spxsIn->snext), pxs); 01654 Lock(&(pDdeConv->spxsIn), pxs); 01655 } 01656 #if 0 01657 { 01658 int i; 01659 HANDLEENTRY *phe; 01660 01661 for (i = 0, phe = gSharedInfo.aheList; 01662 i <= (int)giheLast; 01663 i++) { 01664 if (phe[i].bType == TYPE_DDEXACT) { 01665 UserAssert(((PXSTATE)(phe[i].phead))->snext != pDdeConv->spxsOut); 01666 } 01667 if (phe[i].bType == TYPE_DDECONV && 01668 (PDDECONV)phe[i].phead != pDdeConv) { 01669 UserAssert(((PDDECONV)(phe[i].phead))->spxsOut != pDdeConv->spxsOut); 01670 UserAssert(((PDDECONV)(phe[i].phead))->spxsIn != pDdeConv->spxsOut); 01671 } 01672 } 01673 } 01674 #endif 01675 } 01676 return(PtoH(pxs)); 01677 } 01678 01679 01680 01681 /************************************************************************ 01682 * Createpxs 01683 * 01684 * Allocates and fills XSTATE structures. 01685 * 01686 * History: 01687 * 9-3-91 sanfords Created 01688 \***********************************************************************/ 01689 PXSTATE Createpxs( 01690 FNDDERESPONSE fnResponse, 01691 HANDLE hClient, 01692 HANDLE hServer, 01693 PINTDDEINFO pIntDdeInfo, 01694 DWORD flags) 01695 { 01696 PXSTATE pxs; 01697 01698 pxs = HMAllocObject(PtiCurrent(), NULL, TYPE_DDEXACT, sizeof(XSTATE)); 01699 if (pxs == NULL) { 01700 #if DBG 01701 RIPMSG0(RIP_WARNING, "Unable to alloc DDEXACT"); 01702 #endif 01703 return(NULL); 01704 } 01705 pxs->snext = NULL; 01706 pxs->fnResponse = fnResponse; 01707 pxs->hClient = hClient; 01708 pxs->hServer = hServer; 01709 pxs->pIntDdeInfo = pIntDdeInfo; 01710 pxs->flags = flags; 01711 ValidatePublicObjectList(); 01712 UserAssert(pxs->head.cLockObj == 0); 01713 return(pxs); 01714 } 01715 01716 01717 01718 01719 /************************************************************************ 01720 * AbnormalDDEPost 01721 * 01722 * This is the catch-all routine for wierd cases 01723 * 01724 * returns post action code - DO_POST, FAKE_POST, FAIL_POST. 01725 * 01726 * History: 01727 * 9-3-91 sanfords Created 01728 \***********************************************************************/ 01729 DWORD AbnormalDDEPost( 01730 PDDECONV pDdeConv, 01731 DWORD message) 01732 { 01733 01734 #if DBG 01735 if (message != WM_DDE_TERMINATE) { 01736 RIPMSG2(RIP_WARNING, 01737 "DDE Post failed (%#p:%#p) - protocol violation.", 01738 PtoH(pDdeConv->spwnd), PtoH(pDdeConv->spwndPartner)); 01739 } 01740 #endif // DBG 01741 01742 // shutdown this conversation by posting a terminate on 01743 // behalf of this guy, then fail all future posts but 01744 // fake a successful terminate. 01745 01746 if (!(pDdeConv->flags & CXF_TERMINATE_POSTED)) { 01747 _PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE, 01748 (WPARAM)PtoH(pDdeConv->spwnd), 0); 01749 // pDdeConv->flags |= CXF_TERMINATE_POSTED; Set by post hook proc 01750 } 01751 return(message == WM_DDE_TERMINATE ? FAKE_POST : FAIL_POST); 01752 } 01753 01754 01755 01756 /************************************************************************ 01757 * NewConversation 01758 * 01759 * Worker function used to create a saimese pair of DDECONV structures. 01760 * 01761 * Returns fCreateOk 01762 * 01763 * History: 01764 * 11-5-92 sanfords Created 01765 \***********************************************************************/ 01766 BOOL NewConversation( 01767 PDDECONV *ppdcNewClient, 01768 PDDECONV *ppdcNewServer, 01769 PWND pwndClient, 01770 PWND pwndServer) 01771 { 01772 PDDECONV pdcNewClient; 01773 PDDECONV pdcNewServer; 01774 01775 pdcNewClient = HMAllocObject(GETPTI(pwndClient), NULL, 01776 TYPE_DDECONV, sizeof(DDECONV)); 01777 if (pdcNewClient == NULL) { 01778 return(FALSE); 01779 } 01780 01781 pdcNewServer = HMAllocObject(GETPTI(pwndServer), NULL, 01782 TYPE_DDECONV, sizeof(DDECONV)); 01783 if (pdcNewServer == NULL) { 01784 HMFreeObject(pdcNewClient); // we know it's not locked. 01785 return(FALSE); 01786 } 01787 01788 AddConvProp(pwndClient, pwndServer, 0, pdcNewClient, pdcNewServer); 01789 AddConvProp(pwndServer, pwndClient, CXF_IS_SERVER, pdcNewServer, 01790 pdcNewClient); 01791 01792 if (ppdcNewClient != NULL) { 01793 *ppdcNewClient = pdcNewClient; 01794 } 01795 if (ppdcNewServer != NULL) { 01796 *ppdcNewServer = pdcNewServer; 01797 } 01798 return(TRUE); 01799 } 01800 01801 01802 /************************************************************************ 01803 * FindDdeConv 01804 * 01805 * Locates the pDdeConv associated with pwndProp, and pwndPartner. 01806 * Only searches pwndProp's property list. 01807 * 01808 * History: 01809 * 3-31-91 sanfords Created 01810 \***********************************************************************/ 01811 PDDECONV FindDdeConv( 01812 PWND pwndProp, 01813 PWND pwndPartner) 01814 { 01815 PDDECONV pDdeConv; 01816 01817 pDdeConv = (PDDECONV)_GetProp(pwndProp, PROP_DDETRACK, PROPF_INTERNAL); 01818 while (pDdeConv != NULL && pDdeConv->spwndPartner != pwndPartner) { 01819 pDdeConv = pDdeConv->snext; 01820 } 01821 01822 return(pDdeConv); 01823 } 01824 01825 01826 01827 /************************************************************************ 01828 * xxxCopyAckIn 01829 * 01830 * A common occurance helper function 01831 * 01832 * History: 01833 * 9-3-91 sanfords Created 01834 \***********************************************************************/ 01835 DWORD xxxCopyAckIn( 01836 LPDWORD pmessage, 01837 LPARAM *plParam, 01838 PDDECONV pDdeConv, 01839 PINTDDEINFO * ppIntDdeInfo) 01840 { 01841 PINTDDEINFO pIntDdeInfo; 01842 DWORD flags, dwRet; 01843 PXSTATE pxs; 01844 01845 CheckLock(pDdeConv); 01846 01847 flags = XS_PACKED | XS_FREESRC; 01848 dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, NULL, ppIntDdeInfo); 01849 if (dwRet == DO_POST) { 01850 UserAssert(*ppIntDdeInfo != NULL); 01851 pIntDdeInfo = *ppIntDdeInfo; 01852 if (pDdeConv->spxsOut->flags & XS_GIVEBACKONNACK && 01853 !(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FACK)) { 01854 GiveObject(((PDDE_DATA)(pDdeConv->spxsOut->pIntDdeInfo + 1))->wFmt, 01855 pDdeConv->spxsOut->pIntDdeInfo->hIndirect, 01856 (W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid); 01857 } 01858 if (pDdeConv->spxsOut->flags & XS_PUBLICOBJ) { 01859 RemovePublicObject(((PDDE_DATA)(pDdeConv->spxsOut->pIntDdeInfo + 1))->wFmt, 01860 pDdeConv->spxsOut->pIntDdeInfo->hIndirect); 01861 pDdeConv->spxsOut->flags &= ~XS_PUBLICOBJ; 01862 } 01863 pxs = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS); 01864 if (pxs != NULL) { 01865 pxs->head.pti = GETPTI(pDdeConv->spwndPartner); 01866 } 01867 *plParam = (LPARAM)PtoH(pxs); 01868 if (*plParam == 0) { 01869 return FAILNOFREE_POST; 01870 } 01871 *pmessage |= MSGFLAG_DDE_MID_THUNK; 01872 } 01873 return dwRet; 01874 } 01875 01876 01877 01878 /************************************************************************ 01879 * FreeListAdd 01880 * 01881 * Adds a CSR Client handle to the free list associated with pDdeConv. 01882 * This allows us to make sure stuff is freed that isn't in a context 01883 * we have access at the time we know it must be freed. 01884 * 01885 * returns fSuccess 01886 * 01887 * History: 01888 * 9-3-91 sanfords Created 01889 \***********************************************************************/ 01890 BOOL FreeListAdd( 01891 PDDECONV pDdeConv, 01892 HANDLE hClient, 01893 DWORD flags) 01894 { 01895 PFREELIST pfl; 01896 01897 pfl = (PFREELIST)UserAllocPool(sizeof(FREELIST), TAG_DDE1); 01898 if (!pfl) { 01899 return(FALSE); 01900 } 01901 TRACE_DDE2("FreeListAdd: %x for thread %x.", hClient, 01902 pDdeConv->head.pti->pEThread->Cid.UniqueThread); 01903 pfl->h = hClient; 01904 pfl->flags = flags; 01905 pfl->next = pDdeConv->pfl; 01906 pDdeConv->pfl = pfl; 01907 return(TRUE); 01908 } 01909 01910 01911 /************************************************************************ 01912 * FreeDDEHandle 01913 * 01914 * Frees contents DDE client side handle - delayed free if a WOW process. 01915 * 01916 * History: 01917 * 7-28-94 sanfords Created 01918 \***********************************************************************/ 01919 VOID FreeDDEHandle( 01920 PDDECONV pDdeConv, 01921 HANDLE hClient, 01922 DWORD flags) 01923 { 01924 if (PtiCurrent()->TIF_flags & TIF_16BIT) { 01925 TRACE_DDE1("FreeDDEHandle: (WOW hack) delayed Freeing %#p.", hClient); 01926 FreeListAdd(pDdeConv, hClient, flags); 01927 } else { 01928 TRACE_DDE1("FreeDDEHandle: Freeing %#p.", hClient); 01929 ClientFreeDDEHandle(hClient, flags); 01930 } 01931 } 01932 01933 01934 01935 /************************************************************************ 01936 * xxxFreeListFree 01937 * 01938 * Frees contents of the free list associated with pDdeConv. 01939 * 01940 * History: 01941 * 9-3-91 sanfords Created 01942 \***********************************************************************/ 01943 VOID FreeListFree( 01944 PFREELIST pfl) 01945 { 01946 PFREELIST pflPrev; 01947 01948 CheckCritIn(); 01949 01950 UserAssert(pfl != NULL); 01951 01952 while (pfl != NULL) { 01953 pflPrev = pfl; 01954 pfl = pfl->next; 01955 UserFreePool(pflPrev); 01956 } 01957 } 01958 01959 01960 VOID xxxFreeListFree( 01961 PFREELIST pfl) 01962 { 01963 PFREELIST pflPrev; 01964 BOOL fInCleanup; 01965 TL tlPool; 01966 01967 CheckCritIn(); 01968 01969 if (pfl == NULL) { 01970 return; 01971 } 01972 01973 fInCleanup = (PtiCurrent())->TIF_flags & TIF_INCLEANUP; 01974 01975 while (pfl != NULL) { 01976 01977 ThreadLockPoolCleanup(PtiCurrent(), pfl, &tlPool, FreeListFree); 01978 01979 if (!fInCleanup) { 01980 TRACE_DDE1("Freeing %#p from free list.\n", pfl->h); 01981 ClientFreeDDEHandle(pfl->h, pfl->flags); 01982 } 01983 01984 ThreadUnlockPoolCleanup(PtiCurrent(), &tlPool); 01985 01986 pflPrev = pfl; 01987 pfl = pfl->next; 01988 UserFreePool(pflPrev); 01989 } 01990 } 01991 01992 01993 /************************************************************************ 01994 * PopState 01995 * 01996 * Frees spxsOut from pDdeConv and handles empty queue case. 01997 * 01998 * History: 01999 * 9-3-91 sanfords Created 02000 \***********************************************************************/ 02001 VOID PopState( 02002 PDDECONV pDdeConv) 02003 { 02004 PXSTATE pxsNext, pxsFree; 02005 TL tlpxs; 02006 02007 UserAssert(pDdeConv->spxsOut != NULL); 02008 #if 0 02009 { 02010 int i; 02011 HANDLEENTRY *phe; 02012 02013 for (i = 0, phe = gSharedInfo.aheList; 02014 i <= giheLast; 02015 i++) { 02016 if (phe[i].bType == TYPE_DDEXACT) { 02017 UserAssert(((PXSTATE)(phe[i].phead))->snext != pDdeConv->spxsOut); 02018 } 02019 } 02020 } 02021 #endif 02022 UserAssert(!(pDdeConv->spxsOut->flags & XS_FREEPXS)); 02023 UserAssert(pDdeConv->spxsIn != NULL); 02024 UserAssert(pDdeConv->spxsIn->snext == NULL); 02025 02026 ThreadLockAlways(pDdeConv->spxsOut, &tlpxs); // hold it fast 02027 pxsNext = pDdeConv->spxsOut->snext; 02028 pxsFree = Lock(&(pDdeConv->spxsOut), pxsNext); // lock next into head 02029 if (pxsNext == NULL) { 02030 UserAssert(pDdeConv->spxsIn == pxsFree); 02031 Unlock(&(pDdeConv->spxsIn)); // queue is empty. 02032 } else { 02033 Unlock(&(pxsFree->snext)); // clear next ptr 02034 } 02035 pxsFree = ThreadUnlock(&tlpxs); // undo our lock 02036 if (pxsFree != NULL) { 02037 FreeDdeXact(pxsFree); // cleanup. 02038 } 02039 } 02040 02041 02042 VOID FreeDdeConv( 02043 PDDECONV pDdeConv) 02044 { 02045 02046 TRACE_DDE1("FreeDdeConv(%#p)", pDdeConv); 02047 02048 if (!(pDdeConv->flags & CXF_TERMINATE_POSTED) && 02049 !HMIsMarkDestroy(pDdeConv->spwndPartner)) { 02050 _PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE, 02051 (WPARAM)PtoH(pDdeConv->spwnd), 0); 02052 // pDdeConv->flags |= CXF_TERMINATE_POSTED; set by PostHookProc 02053 } 02054 02055 if (pDdeConv->spartnerConv != NULL && 02056 GETPTI(pDdeConv)->TIF_flags & TIF_INCLEANUP) { 02057 /* 02058 * Fake that the other side already posted a terminate. 02059 * This prevents vestigal dde structures from hanging 02060 * around after thread cleanup if the conversation structure 02061 * is destroyed before the associated window. 02062 */ 02063 pDdeConv->spartnerConv->flags |= CXF_TERMINATE_POSTED; 02064 } 02065 02066 UnlinkConv(pDdeConv); 02067 02068 if (pDdeConv->pddei != NULL) { 02069 pDdeConv->pddei->cRefConv--; 02070 if (pDdeConv->pddei->cRefConv == 0 && pDdeConv->pddei->cRefInit == 0) { 02071 SeDeleteClientSecurity(&pDdeConv->pddei->ClientContext); 02072 UserFreePool(pDdeConv->pddei); 02073 } 02074 pDdeConv->pddei = NULL; 02075 } 02076 02077 Unlock(&(pDdeConv->spartnerConv)); 02078 Unlock(&(pDdeConv->spwndPartner)); 02079 Unlock(&(pDdeConv->spwnd)); 02080 02081 if (!HMMarkObjectDestroy((PHEAD)pDdeConv)) 02082 return; 02083 02084 while (pDdeConv->spxsOut) { 02085 PopState(pDdeConv); 02086 } 02087 02088 HMFreeObject(pDdeConv); 02089 } 02090 02091 02092 02093 /***************************************************************************\ 02094 * xxxCopyDdeIn 02095 * 02096 * Description: 02097 * Copies DDE data from the CSR client to the CSR server side. 02098 * Crosses the CSR barrier as many times as is needed to get all the data 02099 * through the CSR window. 02100 * 02101 * History: 02102 * 11-1-91 sanfords Created. 02103 \***************************************************************************/ 02104 DWORD xxxCopyDdeIn( 02105 HANDLE hSrc, 02106 PDWORD pflags, 02107 PHANDLE phDirect, 02108 PINTDDEINFO *ppi) 02109 { 02110 DWORD dwRet; 02111 PINTDDEINFO pi; 02112 02113 dwRet = xxxClientCopyDDEIn1(hSrc, *pflags, ppi); 02114 pi = *ppi; 02115 TRACE_DDE2(*pflags & XS_FREESRC ? 02116 "Copying in and freeing %#p(%#p)" : 02117 "Copying in %#p(%#p)", 02118 hSrc, pi ? pi->hDirect : 0); 02119 02120 if (dwRet == DO_POST) { 02121 UserAssert(*ppi != NULL); 02122 *pflags = pi->flags; 02123 TRACE_DDE3("xxxCopyDdeIn: uiLo=%x, uiHi=%x, hDirect=%#p", 02124 pi->DdePack.uiLo, pi->DdePack.uiHi, pi->hDirect); 02125 if (phDirect != NULL) { 02126 *phDirect = pi->hDirect; 02127 } 02128 } 02129 #if DBG 02130 else { 02131 RIPMSG0(RIP_WARNING, "Unable to alloc DDE INTDDEINFO"); 02132 } 02133 #endif 02134 02135 return(dwRet); 02136 } 02137 02138 02139 02140 /***********************************************************************\ 02141 * xxxCopyDDEOut 02142 * 02143 * Returns: the apropriate client side handle for lParam or NULL on 02144 * failure. (Since only TERMINATES should have 0 here) 02145 * 02146 * 11/7/1995 Created SanfordS 02147 \***********************************************************************/ 02148 02149 HANDLE xxxCopyDDEOut( 02150 PINTDDEINFO pi, 02151 PHANDLE phDirect) // receives the target client side GMEM handle. 02152 { 02153 HANDLE hDst; 02154 02155 TRACE_DDE3("xxxCopyDDEOut: cbDirect=%x, cbIndirect=%x, flags=%x", 02156 pi->cbDirect, pi->cbIndirect, pi->flags); 02157 hDst = xxxClientCopyDDEOut1(pi); 02158 TRACE_DDE3("xxxCopyDDEOut: uiLo=%x, uiHi=%x, hResult=%#p", 02159 pi->DdePack.uiLo, pi->DdePack.uiHi, hDst); 02160 if (hDst != NULL) { 02161 if (phDirect != NULL) { 02162 TRACE_DDE1("xxxCopyDDEOut: *phDirect=%#p", pi->hDirect); 02163 *phDirect = pi->hDirect; 02164 } 02165 } 02166 return(hDst); 02167 } 02168 02169 02170 02171 /* 02172 * This API is used to set the QOS associated with a potential DDE client window. 02173 * It should be called prior to sending a WM_DDE_INITIATE message and the qos set 02174 * will hold until the WM_DDE_INITIATE send or broadcast returns. 02175 */ 02176 BOOL _DdeSetQualityOfService( 02177 PWND pwndClient, 02178 CONST PSECURITY_QUALITY_OF_SERVICE pqosNew, 02179 PSECURITY_QUALITY_OF_SERVICE pqosOld) 02180 { 02181 PSECURITY_QUALITY_OF_SERVICE pqosUser; 02182 PSECURITY_QUALITY_OF_SERVICE pqosAlloc = NULL; 02183 BOOL fRet; 02184 02185 /* 02186 * ASSUME: calling process is owner of pwndClient - ensured in thunk. 02187 */ 02188 pqosUser = (PSECURITY_QUALITY_OF_SERVICE)InternalRemoveProp(pwndClient, 02189 PROP_QOS, PROPF_INTERNAL); 02190 if (pqosUser == NULL) { 02191 if (RtlEqualMemory(pqosNew, &gqosDefault, sizeof(SECURITY_QUALITY_OF_SERVICE))) { 02192 return(TRUE); // no PROP_QOS property implies default QOS 02193 } 02194 pqosAlloc = (PSECURITY_QUALITY_OF_SERVICE)UserAllocPoolZInit( 02195 sizeof(SECURITY_QUALITY_OF_SERVICE), TAG_DDE2); 02196 if (pqosAlloc == NULL) { 02197 return(FALSE); // memory allocation failure - can't change from default 02198 } 02199 pqosUser = pqosAlloc; 02200 } 02201 *pqosOld = *pqosUser; 02202 *pqosUser = *pqosNew; 02203 02204 fRet = InternalSetProp(pwndClient, PROP_QOS, pqosUser, PROPF_INTERNAL); 02205 if ((fRet == FALSE) && (pqosAlloc != NULL)) { 02206 UserFreePool(pqosAlloc); 02207 } 02208 02209 return fRet; 02210 } 02211 02212 02213 /* 02214 * This is a private API for NetDDE's use. It extracts the QOS associated with an 02215 * active DDE conversation. Intra-process conversations always are set to the default 02216 * QOS. 02217 */ 02218 BOOL _DdeGetQualityOfService( 02219 PWND pwndClient, 02220 PWND pwndServer, 02221 PSECURITY_QUALITY_OF_SERVICE pqos) 02222 { 02223 PDDECONV pDdeConv; 02224 PSECURITY_QUALITY_OF_SERVICE pqosClient; 02225 02226 if (pwndServer == NULL) { 02227 /* 02228 * Special case to support DDEML-RAW conversations that need to get 02229 * the QOS prior to initiation completion. 02230 */ 02231 pqosClient = _GetProp(pwndClient, PROP_QOS, PROPF_INTERNAL); 02232 if (pqosClient == NULL) { 02233 *pqos = gqosDefault; 02234 } else { 02235 *pqos = *pqosClient; 02236 } 02237 return(TRUE); 02238 } 02239 if (GETPWNDPPI(pwndClient) == GETPWNDPPI(pwndServer)) { 02240 *pqos = gqosDefault; 02241 return(TRUE); 02242 } 02243 pDdeConv = FindDdeConv(pwndClient, pwndServer); 02244 if (pDdeConv == NULL) { 02245 return(FALSE); 02246 } 02247 if (pDdeConv->pddei == NULL) { 02248 return(FALSE); 02249 } 02250 *pqos = pDdeConv->pddei->qos; 02251 return(TRUE); 02252 } 02253 02254 02255 02256 BOOL _ImpersonateDdeClientWindow( 02257 PWND pwndClient, 02258 PWND pwndServer) 02259 { 02260 PDDECONV pDdeConv; 02261 NTSTATUS Status; 02262 02263 /* 02264 * Locate token used in the conversation 02265 */ 02266 pDdeConv = FindDdeConv(pwndClient, pwndServer); 02267 if (pDdeConv == NULL || pDdeConv->pddei == NULL) 02268 return(FALSE); 02269 02270 /* 02271 * Stick the token into the dde server thread 02272 */ 02273 Status = SeImpersonateClientEx(&pDdeConv->pddei->ClientContext, 02274 PsGetCurrentThread()); 02275 if (!NT_SUCCESS(Status)) { 02276 RIPNTERR0(Status, RIP_VERBOSE, ""); 02277 return FALSE; 02278 } 02279 return TRUE; 02280 } 02281 02282 02283 02284 02285 VOID FreeDdeXact( 02286 PXSTATE pxs) 02287 { 02288 if (!HMMarkObjectDestroy(pxs)) 02289 return; 02290 02291 #if 0 02292 { 02293 int i; 02294 HANDLEENTRY *phe; 02295 02296 for (i = 0, phe = gSharedInfo.aheList; 02297 i <= giheLast; 02298 i++) { 02299 if (phe[i].bType == TYPE_DDEXACT) { 02300 UserAssert(((PXSTATE)(phe[i].phead))->snext != pxs); 02301 } 02302 if (phe[i].bType == TYPE_DDECONV) { 02303 UserAssert(((PDDECONV)(phe[i].phead))->spxsOut != pxs); 02304 UserAssert(((PDDECONV)(phe[i].phead))->spxsIn != pxs); 02305 } 02306 } 02307 } 02308 UserAssert(pxs->head.cLockObj == 0); 02309 UserAssert(pxs->snext == NULL); 02310 #endif 02311 02312 if (pxs->pIntDdeInfo != NULL) { 02313 /* 02314 * free any server-side GDI objects 02315 */ 02316 if (pxs->pIntDdeInfo->flags & (XS_METAFILEPICT | XS_ENHMETAFILE)) { 02317 GreDeleteServerMetaFile(pxs->pIntDdeInfo->hIndirect); 02318 } 02319 if (pxs->flags & XS_PUBLICOBJ) { 02320 RemovePublicObject(((PDDE_DATA)(pxs->pIntDdeInfo + 1))->wFmt, 02321 pxs->pIntDdeInfo->hIndirect); 02322 pxs->flags &= ~XS_PUBLICOBJ; 02323 } 02324 UserFreePool(pxs->pIntDdeInfo); 02325 } 02326 02327 HMFreeObject(pxs); 02328 ValidatePublicObjectList(); 02329 } 02330 02331 02332 02333 PPUBOBJ IsObjectPublic( 02334 HANDLE hObj) 02335 { 02336 PPUBOBJ ppo; 02337 02338 for (ppo = gpPublicObjectList; ppo != NULL; ppo = ppo->next) { 02339 if (ppo->hObj == hObj) { 02340 break; 02341 } 02342 } 02343 return(ppo); 02344 } 02345 02346 02347 02348 BOOL AddPublicObject( 02349 UINT format, 02350 HANDLE hObj, 02351 W32PID pid) 02352 { 02353 PPUBOBJ ppo; 02354 02355 switch (format) { 02356 case CF_BITMAP: 02357 case CF_DSPBITMAP: 02358 case CF_PALETTE: 02359 break; 02360 02361 default: 02362 return(FALSE); 02363 } 02364 02365 ppo = IsObjectPublic(hObj); 02366 if (ppo == NULL) { 02367 ppo = UserAllocPool(sizeof(PUBOBJ), TAG_DDE4); 02368 if (ppo == NULL) { 02369 return(FALSE); 02370 } 02371 ppo->count = 1; 02372 ppo->hObj = hObj; 02373 ppo->pid = pid; 02374 ppo->next = gpPublicObjectList; 02375 gpPublicObjectList = ppo; 02376 GiveObject(format, hObj, OBJECT_OWNER_PUBLIC); 02377 } else { 02378 ppo->count++; 02379 } 02380 return(TRUE); 02381 } 02382 02383 02384 02385 BOOL RemovePublicObject( 02386 UINT format, 02387 HANDLE hObj) 02388 { 02389 PPUBOBJ ppo, ppoPrev; 02390 02391 switch (format) { 02392 case CF_BITMAP: 02393 case CF_DSPBITMAP: 02394 case CF_PALETTE: 02395 break; 02396 02397 default: 02398 return(FALSE); 02399 } 02400 02401 for (ppoPrev = NULL, ppo = gpPublicObjectList; 02402 ppo != NULL; 02403 ppoPrev = ppo, ppo = ppo->next) { 02404 if (ppo->hObj == hObj) { 02405 break; 02406 } 02407 } 02408 if (ppo == NULL) { 02409 UserAssert(FALSE); 02410 return(FALSE); 02411 } 02412 ppo->count--; 02413 if (ppo->count == 0) { 02414 GiveObject(format, hObj, ppo->pid); 02415 if (ppoPrev != NULL) { 02416 ppoPrev->next = ppo->next; 02417 } else { 02418 gpPublicObjectList = ppo->next; 02419 } 02420 UserFreePool(ppo); 02421 } 02422 return(TRUE); 02423 } 02424 02425 02426 BOOL 02427 GiveObject( 02428 UINT format, 02429 HANDLE hObj, 02430 W32PID pid) 02431 { 02432 switch (format) { 02433 case CF_BITMAP: 02434 case CF_DSPBITMAP: 02435 GreSetBitmapOwner(hObj, pid); 02436 return(TRUE); 02437 02438 case CF_PALETTE: 02439 GreSetPaletteOwner(hObj, pid); 02440 return(TRUE); 02441 02442 default: 02443 return(FALSE); 02444 } 02445 } 02446 02447 #if DBG 02448 VOID ValidatePublicObjectList() 02449 { 02450 PPUBOBJ ppo; 02451 int i, count; 02452 HANDLEENTRY *phe; 02453 02454 for (count = 0, ppo = gpPublicObjectList; 02455 ppo != NULL; 02456 ppo = ppo->next) { 02457 count += ppo->count; 02458 } 02459 for (i = 0, phe = gSharedInfo.aheList; 02460 i <= (int)giheLast; 02461 i++) { 02462 if (phe[i].bType == TYPE_DDEXACT) { 02463 if (((PXSTATE)(phe[i].phead))->flags & XS_PUBLICOBJ) { 02464 UserAssert(((PXSTATE)(phe[i].phead))->pIntDdeInfo != NULL); 02465 UserAssert(IsObjectPublic(((PXSTATE) 02466 (phe[i].phead))->pIntDdeInfo->hIndirect) != NULL); 02467 count--; 02468 } 02469 } 02470 } 02471 UserAssert(count == 0); 02472 } 02473 02474 02475 VOID TraceDdeMsg( 02476 UINT msg, 02477 HWND hwndFrom, 02478 HWND hwndTo, 02479 UINT code) 02480 { 02481 LPSTR szMsg, szType; 02482 02483 msg = msg & 0xFFFF; 02484 02485 switch (msg) { 02486 case WM_DDE_INITIATE: 02487 szMsg = "INITIATE"; 02488 break; 02489 02490 case WM_DDE_TERMINATE: 02491 szMsg = "TERMINATE"; 02492 break; 02493 02494 case WM_DDE_ADVISE: 02495 szMsg = "ADVISE"; 02496 break; 02497 02498 case WM_DDE_UNADVISE: 02499 szMsg = "UNADVISE"; 02500 break; 02501 02502 case WM_DDE_ACK: 02503 szMsg = "ACK"; 02504 break; 02505 02506 case WM_DDE_DATA: 02507 szMsg = "DATA"; 02508 break; 02509 02510 case WM_DDE_REQUEST: 02511 szMsg = "REQUEST"; 02512 break; 02513 02514 case WM_DDE_POKE: 02515 szMsg = "POKE"; 02516 break; 02517 02518 case WM_DDE_EXECUTE: 02519 szMsg = "EXECUTE"; 02520 break; 02521 02522 default: 02523 szMsg = "BOGUS"; 02524 UserAssert(msg >= WM_DDE_FIRST && msg <= WM_DDE_LAST); 02525 break; 02526 } 02527 02528 switch (code) { 02529 case MSG_SENT: 02530 szType = "[sent]"; 02531 break; 02532 02533 case MSG_POST: 02534 szType = "[posted]"; 02535 break; 02536 02537 case MSG_RECV: 02538 szType = "[received]"; 02539 break; 02540 02541 case MSG_PEEK: 02542 szType = "[peeked]"; 02543 break; 02544 02545 default: 02546 szType = "[bogus]"; 02547 UserAssert(FALSE); 02548 break; 02549 } 02550 02551 RIPMSG4(RIP_VERBOSE, 02552 "%#p->%#p WM_DDE_%s %s", 02553 hwndFrom, hwndTo, szMsg, szType); 02554 } 02555 #endif //DBG

Generated on Sat May 15 19:39:39 2004 for test by doxygen 1.3.7