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

connect.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: connect.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * DDE Manager conversation connection functions 00007 * 00008 * Created: 11/3/91 Sanford Staab 00009 * 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 #include "nddeagnt.h" 00015 00016 //#define TESTING 00017 #ifdef TESTING 00018 ULONG 00019 DbgPrint( 00020 PCH Format, 00021 ... 00022 ); 00023 VOID 00024 DbgUserBreakPoint( 00025 VOID 00026 ); 00027 00028 BOOL ValidateConvList( 00029 HCONVLIST hConvList) 00030 { 00031 PCONVLIST pcl; 00032 PCL_CONV_INFO pci; 00033 PXACT_INFO pxi; 00034 int i; 00035 BOOL fMatch; 00036 00037 if (hConvList == 0) { 00038 return(TRUE); 00039 } 00040 pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList, 00041 HTYPE_CONVERSATION_LIST, 00042 HINST_ANY); 00043 for (i = 0; i < pcl->chwnd; i++) { 00044 /* 00045 * all windows in the list are valid 00046 */ 00047 if (!IsWindow(pcl->ahwnd[i])) { 00048 DebugBreak(); 00049 } 00050 pci = (PCL_CONV_INFO)GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI); 00051 /* 00052 * All windows have at least one convinfo associated with them. 00053 */ 00054 if (pci == NULL) { 00055 DebugBreak(); 00056 } 00057 fMatch = FALSE; 00058 while (pci != NULL) { 00059 /* 00060 * All non-zombie conversations have hConvList set correctly. 00061 */ 00062 if (pci->hConvList != hConvList && 00063 TypeFromHandle(pci->ci.hConv) != HTYPE_ZOMBIE_CONVERSATION) { 00064 DebugBreak(); 00065 } 00066 /* 00067 * All conversations have hConvList clear or set correctly. 00068 */ 00069 if (pci->hConvList != 0 && pci->hConvList != hConvList) { 00070 DebugBreak(); 00071 } 00072 /* 00073 * At least 1 of the conversations references the list 00074 */ 00075 if (pci->hConvList == hConvList) { 00076 fMatch = TRUE; 00077 } 00078 for (pxi = pci->ci.pxiOut; pxi; pxi = pxi->next) { 00079 if ((PCL_CONV_INFO)pxi->pcoi != pci) { 00080 DebugBreak(); 00081 } 00082 } 00083 pci = (PCL_CONV_INFO)pci->ci.next; 00084 } 00085 if (!fMatch) { 00086 /* 00087 * At least 1 of the conversations references the list 00088 */ 00089 DebugBreak; 00090 } 00091 } 00092 return(TRUE); 00093 } 00094 00095 VOID ValidateAllConvLists() 00096 { 00097 ApplyFunctionToObjects(HTYPE_CONVERSATION_LIST, HINST_ANY, 00098 (PFNHANDLEAPPLY)ValidateConvList); 00099 } 00100 00101 #else // TESTING 00102 #define ValidateConvList(h) 00103 #define ValidateAllConvLists() 00104 #endif // TESTING 00105 00106 CONVCONTEXT TempConvContext; 00107 CONVCONTEXT DefConvContext = { 00108 sizeof(CONVCONTEXT), 00109 0, 00110 0, 00111 CP_WINANSI, 00112 0L, 00113 0L, 00114 { 00115 sizeof(SECURITY_QUALITY_OF_SERVICE), 00116 SecurityImpersonation, 00117 SECURITY_STATIC_TRACKING, 00118 TRUE 00119 } 00120 }; 00121 00122 typedef struct tagINIT_ENUM { 00123 HWND hwndClient; 00124 HWND hwndSkip; 00125 LONG lParam; 00126 LATOM laServiceRequested; 00127 LATOM laTopic; 00128 HCONVLIST hConvList; 00129 DWORD clst; 00130 } INIT_ENUM, *PINIT_ENUM; 00131 00132 00133 BOOL InitiateEnumerationProc(HWND hwndTarget, PINIT_ENUM pie); 00134 VOID DisconnectConv(PCONV_INFO pcoi); 00135 00136 00137 /***************************************************************************\ 00138 * DdeConnect (DDEML API) 00139 * 00140 * Description: 00141 * Initiates a DDE conversation. 00142 * 00143 * History: 00144 * 11-1-91 sanfords Created. 00145 \***************************************************************************/ 00146 HCONV DdeConnect( 00147 DWORD idInst, 00148 HSZ hszService, 00149 HSZ hszTopic, 00150 PCONVCONTEXT pCC) 00151 { 00152 PCL_INSTANCE_INFO pcii; 00153 PCL_CONV_INFO pci; 00154 HCONV hConvRet = 0; 00155 HWND hwndTarget = 0; 00156 LATOM aNormalSvcName = 0; 00157 00158 EnterDDECrit; 00159 00160 if (!ValidateConnectParameters((HANDLE)LongToHandle( idInst ), &pcii, &hszService, hszTopic, 00161 &aNormalSvcName, &pCC, &hwndTarget, 0)) { 00162 goto Exit; 00163 } 00164 pci = ConnectConv(pcii, LATOM_FROM_HSZ(hszService), LATOM_FROM_HSZ(hszTopic), 00165 hwndTarget, 00166 (pcii->afCmd & CBF_FAIL_SELFCONNECTIONS) ? pcii->hwndMother : 0, 00167 pCC, 0, CLST_SINGLE_INITIALIZING); 00168 if (pci == NULL) { 00169 SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED); 00170 goto Exit; 00171 } else { 00172 hConvRet = pci->ci.hConv; 00173 } 00174 00175 Exit: 00176 if (aNormalSvcName) { 00177 GlobalDeleteAtom(aNormalSvcName); 00178 } 00179 LeaveDDECrit; 00180 return (hConvRet); 00181 } 00182 00183 00184 00185 /***************************************************************************\ 00186 * DdeConnectList (DDEML API) 00187 * 00188 * Description: 00189 * Initiates DDE conversations with multiple servers or adds unique servers 00190 * to an existing conversation list. 00191 * 00192 * History: 00193 * 11-12-91 sanfords Created. 00194 \***************************************************************************/ 00195 HCONVLIST DdeConnectList( 00196 DWORD idInst, 00197 HSZ hszService, 00198 HSZ hszTopic, 00199 HCONVLIST hConvList, 00200 PCONVCONTEXT pCC) 00201 { 00202 PCL_INSTANCE_INFO pcii; 00203 PCONV_INFO pcoi, pcoiNew, pcoiExisting, pcoiNext; 00204 HCONVLIST hConvListRet = 0; 00205 HWND hwndTarget = 0; 00206 LATOM aNormalSvcName = 0; 00207 PCONVLIST pcl = NULL; 00208 HCONVLIST hConvListOld; 00209 int i; 00210 00211 CheckDDECritOut; 00212 00213 EnterDDECrit; 00214 00215 if (!ValidateConnectParameters((HANDLE)LongToHandle( idInst ), &pcii, &hszService, hszTopic, 00216 &aNormalSvcName, &pCC, &hwndTarget, hConvList)) { 00217 goto Exit; 00218 } 00219 00220 ValidateConvList(hConvList); 00221 00222 hConvListOld = hConvList; 00223 pcoi = (PCONV_INFO)ConnectConv(pcii, 00224 LATOM_FROM_HSZ(hszService), 00225 LATOM_FROM_HSZ(hszTopic), 00226 hwndTarget, 00227 (pcii->afCmd & (CBF_FAIL_SELFCONNECTIONS | CBF_FAIL_CONNECTIONS)) ? 00228 pcii->hwndMother : 0, 00229 pCC, 00230 hConvListOld, 00231 CLST_MULT_INITIALIZING); 00232 00233 if (pcoi == NULL) { 00234 /* 00235 * no new connections made 00236 */ 00237 SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED); 00238 hConvListRet = hConvListOld; 00239 goto Exit; 00240 } 00241 00242 /* 00243 * allocate or reallocate the hConvList hwnd list for later addition 00244 * If we already have a valid list, reuse the handle so we don't have 00245 * to alter the preexisting pcoi->hConvList values. 00246 */ 00247 if (hConvListOld == 0) { 00248 pcl = (PCONVLIST)DDEMLAlloc(sizeof(CONVLIST)); 00249 if (pcl == NULL) { 00250 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00251 DisconnectConv(pcoi); 00252 goto Exit; 00253 } 00254 // pcl->chwnd = 0; LPTR zero inits. 00255 00256 hConvList = (HCONVLIST)CreateHandle((ULONG_PTR)pcl, 00257 HTYPE_CONVERSATION_LIST, InstFromHandle(pcii->hInstClient)); 00258 if (hConvList == 0) { 00259 DDEMLFree(pcl); 00260 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00261 DisconnectConv(pcoi); 00262 goto Exit; 00263 } 00264 } else { 00265 pcl = (PCONVLIST)GetHandleData((HANDLE)hConvList); 00266 pcl = DDEMLReAlloc(pcl, sizeof(CONVLIST) + sizeof(HWND) * pcl->chwnd); 00267 if (pcl == NULL) { 00268 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00269 hConvListRet = hConvListOld; 00270 DisconnectConv(pcoi); 00271 goto Exit; 00272 } 00273 SetHandleData((HANDLE)hConvList, (ULONG_PTR)pcl); 00274 } 00275 00276 ValidateConvList(hConvListOld); 00277 00278 if (hConvListOld) { 00279 /* 00280 * remove duplicates from new conversations 00281 * 00282 * Although we tried to prevent duplicates from happening 00283 * within the initiate enumeration code, wild initiates or 00284 * servers responding with different service names than 00285 * requested could cause duplicates. 00286 */ 00287 00288 /* For each client window... */ 00289 00290 for (i = 0; i < pcl->chwnd; i++) { 00291 00292 /* For each existing conversation in that window... */ 00293 00294 for (pcoiExisting = (PCONV_INFO) 00295 GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI); 00296 pcoi != NULL && pcoiExisting != NULL; 00297 pcoiExisting = pcoiExisting->next) { 00298 00299 if (!(pcoiExisting->state & ST_CONNECTED)) 00300 continue; 00301 00302 /* For each new conversation... */ 00303 00304 for (pcoiNew = pcoi; pcoiNew != NULL; pcoiNew = pcoiNext) { 00305 00306 pcoiNext = pcoiNew->next; 00307 00308 /* see if the new conversation duplicates the existing one */ 00309 00310 if (!(pcoiNew->state & ST_CONNECTED)) 00311 continue; 00312 00313 UserAssert(((PCL_CONV_INFO)pcoiExisting)->hwndReconnect); 00314 UserAssert(((PCL_CONV_INFO)pcoiNew)->hwndReconnect); 00315 00316 if (((PCL_CONV_INFO)pcoiExisting)->hwndReconnect == 00317 ((PCL_CONV_INFO)pcoiNew)->hwndReconnect && 00318 pcoiExisting->laTopic == pcoiNew->laTopic && 00319 pcoiExisting->laService == pcoiNew->laService) { 00320 /* 00321 * duplicate conversation - disconnection causes an unlink 00322 */ 00323 if (pcoiNew == pcoi) { 00324 /* 00325 * We are freeing up the head of the list, 00326 * Reset the head to the next guy. 00327 */ 00328 pcoi = pcoiNext; 00329 } 00330 ValidateConvList(hConvList); 00331 ShutdownConversation(pcoiNew, FALSE); 00332 ValidateConvList(hConvList); 00333 break; 00334 } 00335 } 00336 } 00337 } 00338 00339 for (pcoiExisting = pcoi; pcoiExisting != NULL; pcoiExisting = pcoiExisting->next) { 00340 /* 00341 * if these are all zombies - we DONT want to link it in! 00342 * This is possible because ShutdownConversation() leaves the critical section 00343 * and could allow responding terminates to come through. 00344 */ 00345 if (pcoiExisting->state & ST_CONNECTED) { 00346 goto FoundOne; 00347 } 00348 } 00349 pcoi = NULL; // abandon this guy - he will clean up in time. 00350 FoundOne: 00351 /* 00352 * add new pcoi (if any are left) hwnd to ConvList hwnd list. 00353 */ 00354 if (pcoi != NULL) { 00355 UserAssert(pcoi->hwndConv); 00356 pcl->ahwnd[pcl->chwnd] = pcoi->hwndConv; 00357 pcl->chwnd++; 00358 hConvListRet = hConvList; 00359 } else { 00360 hConvListRet = hConvListOld; 00361 if (!hConvListOld) { 00362 DestroyHandle((HANDLE)hConvList); 00363 } 00364 } 00365 00366 00367 } else { // no hConvListOld 00368 00369 UserAssert(pcoi->hwndConv); 00370 pcl->ahwnd[0] = pcoi->hwndConv; 00371 pcl->chwnd = 1; 00372 hConvListRet = hConvList; 00373 } 00374 00375 if (pcoi != NULL) { 00376 /* 00377 * set hConvList field for all remaining new conversations. 00378 */ 00379 UserAssert(hConvListRet); 00380 for (pcoiNew = pcoi; pcoiNew != NULL; pcoiNew = pcoiNew->next) { 00381 if (pcoiNew->state & ST_CONNECTED) { 00382 ((PCL_CONV_INFO)pcoiNew)->hConvList = hConvListRet; 00383 } 00384 } 00385 } 00386 00387 Exit: 00388 if (aNormalSvcName) { 00389 DeleteAtom(aNormalSvcName); 00390 } 00391 ValidateConvList(hConvListRet); 00392 LeaveDDECrit; 00393 return (hConvListRet); 00394 } 00395 00396 00397 00398 00399 /***************************************************************************\ 00400 * DdeReconnect (DDEML API) 00401 * 00402 * Description: 00403 * Attempts to reconnect an externally (from the server) terminated 00404 * client side conversation. 00405 * 00406 * History: 00407 * 11-12-91 sanfords Created. 00408 \***************************************************************************/ 00409 HCONV DdeReconnect( 00410 HCONV hConv) 00411 { 00412 PCL_INSTANCE_INFO pcii; 00413 PCL_CONV_INFO pci, pciNew; 00414 HCONV hConvRet = 0; 00415 CONVCONTEXT cc; 00416 00417 EnterDDECrit; 00418 00419 pcii = PciiFromHandle((HANDLE)hConv); 00420 if (pcii == NULL) { 00421 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 00422 goto Exit; 00423 } 00424 pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConv, 00425 HTYPE_CLIENT_CONVERSATION, HINST_ANY); 00426 if (pci == NULL) { 00427 SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); 00428 goto Exit; 00429 } 00430 00431 if (pci->ci.state & ST_CONNECTED) { 00432 goto Exit; 00433 } 00434 00435 GetConvContext(pci->ci.hwndConv, (LONG *)&cc); 00436 pciNew = ConnectConv(pcii, pci->ci.laService, pci->ci.laTopic, 00437 pci->hwndReconnect, 0, &cc, 0, CLST_SINGLE_INITIALIZING); 00438 if (pciNew == NULL) { 00439 SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED); 00440 goto Exit; 00441 } else { 00442 hConvRet = pciNew->ci.hConv; 00443 if (pci->ci.cLinks) { 00444 PXACT_INFO pxi; 00445 int iLink; 00446 PADVISE_LINK paLink; 00447 00448 /* 00449 * reestablish advise links 00450 */ 00451 00452 for (paLink = pci->ci.aLinks, iLink = pci->ci.cLinks; 00453 iLink; paLink++, iLink--) { 00454 00455 pxi = (PXACT_INFO)DDEMLAlloc(sizeof(XACT_INFO)); 00456 if (pxi == NULL) { 00457 break; // abort relinking 00458 } 00459 pxi->pcoi = (PCONV_INFO)pciNew; 00460 pxi->gaItem = LocalToGlobalAtom(paLink->laItem); // pxi copy 00461 pxi->wFmt = paLink->wFmt; 00462 pxi->wType = (WORD)((paLink->wType >> 12) | XTYP_ADVSTART); 00463 if (ClStartAdvise(pxi)) { 00464 pxi->flags |= XIF_ABANDONED; 00465 } else { 00466 GlobalDeleteAtom(pxi->gaItem); 00467 DDEMLFree(pxi); 00468 } 00469 } 00470 } 00471 } 00472 00473 Exit: 00474 LeaveDDECrit; 00475 return (hConvRet); 00476 } 00477 00478 00479 /***************************************************************************\ 00480 * ValidateConnectParameters 00481 * 00482 * Description: 00483 * worker function to handle common validation code. 00484 * 00485 * Note that paNormalSvcName is set to the atom value created upon extracting 00486 * a normal HSZ from an InstanceSpecific HSZ. 00487 * 00488 * History: 00489 * 11-12-91 sanfords Created. 00490 \***************************************************************************/ 00491 BOOL ValidateConnectParameters( 00492 HANDLE hInst, 00493 PCL_INSTANCE_INFO *ppcii, // set if valid hInst 00494 HSZ *phszService, // altered if InstSpecific HSZ 00495 HSZ hszTopic, 00496 LATOM *plaNormalSvcName, // set to atom that needs freeing when done 00497 PCONVCONTEXT *ppCC, // set to point to DefConvContext if NULL 00498 HWND *phwndTarget, // set if hszService is InstSpecific 00499 HCONVLIST hConvList) 00500 { 00501 DWORD hszType; 00502 BOOL fError = FALSE; 00503 00504 *ppcii = ValidateInstance(hInst); 00505 if (*ppcii == NULL) { 00506 return (FALSE); 00507 } 00508 hszType = ValidateHSZ(*phszService); 00509 if (hszType == HSZT_INVALID || ValidateHSZ(hszTopic) == HSZT_INVALID) { 00510 SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER); 00511 return (FALSE); 00512 } 00513 if (hszType == HSZT_INST_SPECIFIC) { 00514 *phwndTarget = ParseInstSpecificAtom(LATOM_FROM_HSZ(*phszService), 00515 plaNormalSvcName); 00516 if (*plaNormalSvcName == 0) { 00517 SetLastDDEMLError(*ppcii, DMLERR_SYS_ERROR); 00518 return (FALSE); 00519 } 00520 *phszService = NORMAL_HSZ_FROM_LATOM(*plaNormalSvcName); 00521 } 00522 if (*ppCC == NULL) { 00523 *ppCC = &DefConvContext; 00524 if ((*ppcii)->flags & IIF_UNICODE) { 00525 (*ppCC)->iCodePage = CP_WINUNICODE; 00526 } else { 00527 (*ppCC)->iCodePage = CP_WINANSI; 00528 } 00529 } else try { 00530 if ((*ppCC)->cb > sizeof(CONVCONTEXT)) { 00531 SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER); 00532 fError = TRUE; 00533 } else if ((*ppCC)->cb < sizeof(CONVCONTEXT)) { 00534 TempConvContext = DefConvContext; 00535 /* 00536 * we can use this static temp because we are synchronized. 00537 */ 00538 RtlCopyMemory(&TempConvContext, *ppCC, (*ppCC)->cb); 00539 *ppCC = &TempConvContext; 00540 } 00541 } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { 00542 SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER); 00543 fError = TRUE; 00544 } 00545 if (fError) { 00546 return(FALSE); 00547 } 00548 if (hConvList != 0 && 00549 !ValidateCHandle((HANDLE)hConvList, HTYPE_CONVERSATION_LIST, 00550 (DWORD)InstFromHandle((*ppcii)->hInstClient))) { 00551 return (FALSE); 00552 } 00553 return (TRUE); 00554 } 00555 00556 00557 00558 /***************************************************************************\ 00559 * ConnectConv 00560 * 00561 * Description: 00562 * Work function for all Connect cases. 00563 * 00564 * Method: 00565 * 00566 * To reduce the number of windows we use and to simplify how client 00567 * windows handle multiple WM_DDE_ACK messages during initiation, a 00568 * single client window can handle many conversations, each with 00569 * a different server window. 00570 * 00571 * The client window is created and set to a initiation state via the 00572 * GWL_CONVSTATE window word. Initiates are then sent to enumerated server 00573 * window candidates. 00574 * The GWL_CONVSTATE value is used by the DDEML mother windows 00575 * to determine if only one or several ACKs are desired to minimize 00576 * unnessary message traffic. 00577 * 00578 * The client window GWL_CONVCONTEXT? window words are also used by 00579 * Event Windows to pass context information. 00580 * 00581 * Note that all client and server windows are children of the mother 00582 * window. This reduces the number of top level windows that 00583 * WM_DDE_INITIATES need to hit. 00584 * 00585 * Each WM_DDE_ACK that is received by a client window while in the 00586 * initiation state causes it to create a CL_CONV_INFO structure, 00587 * partially initialize it, and link it into its list of CL_CONV_INFO 00588 * structures. The head of the list is pointed to by the GWLP_PCI 00589 * client window word. 00590 * 00591 * After each WM_DDE_INITIALIZE is sent, the GWLP_PCI value is checked 00592 * to see if it exists and needs initialization to be completed. If 00593 * this is the case the init code knows that at least one ACK was 00594 * received in response to the WM_DDE_INITIALIZE send. The 00595 * initialization of each CL_CONV_INFO struct that needs it is then completed. 00596 * 00597 * Once the broadcasting of WM_DDE_INITIALIZE is done, the init code 00598 * then sets the GWL_CONVSTATE value in the client window to indicate that 00599 * initialization is complete. 00600 * 00601 * Returns: 00602 * The head pci to the client window or NULL if no connections made it. 00603 * 00604 * History: 00605 * 11-1-91 sanfords Created. 00606 \***************************************************************************/ 00607 PCL_CONV_INFO ConnectConv( 00608 PCL_INSTANCE_INFO pcii, 00609 LATOM laService, 00610 LATOM laTopic, 00611 HWND hwndTarget, // 0 implies broadcast 00612 HWND hwndSkip, // 0 implies no skips - avoids self-connections. 00613 PCONVCONTEXT pCC, 00614 HCONVLIST hConvList, 00615 DWORD clst) 00616 { 00617 INIT_ENUM ie; 00618 PCL_CONV_INFO pci; 00619 PCONV_INFO pcoi; 00620 GATOM gaService, gaTopic; 00621 00622 CheckDDECritIn; 00623 00624 if (hwndTarget && hwndTarget == hwndSkip) { 00625 return(NULL); 00626 } 00627 00628 LeaveDDECrit; 00629 CheckDDECritOut; 00630 00631 if (pcii->flags & IIF_UNICODE) { 00632 ie.hwndClient = CreateWindowW((LPWSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTW]), 00633 L"", 00634 WS_CHILD, 00635 0, 0, 0, 0, 00636 pcii->hwndMother, 00637 (HMENU)0, 00638 (HANDLE)0, 00639 (LPVOID)NULL); 00640 } else { 00641 ie.hwndClient = CreateWindowA((LPSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTA]), 00642 "", 00643 WS_CHILD, 00644 0, 0, 0, 0, 00645 pcii->hwndMother, 00646 (HMENU)0, 00647 (HANDLE)0, 00648 (LPVOID)NULL); 00649 } 00650 00651 EnterDDECrit; 00652 00653 if (ie.hwndClient == 0) { 00654 return (NULL); 00655 } 00656 00657 if (pCC != NULL) { 00658 if (!NtUserDdeSetQualityOfService(ie.hwndClient, &(pCC->qos), NULL)) { 00659 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00660 goto Error; 00661 } 00662 } 00663 /* 00664 * Note that a pci will be created and allocated for each ACK recieved. 00665 */ 00666 SetConvContext(ie.hwndClient, (LONG *)pCC); 00667 SetWindowLong(ie.hwndClient, GWL_CONVSTATE, clst); 00668 SetWindowLongPtr(ie.hwndClient, GWLP_SHINST, (LONG_PTR)pcii->hInstServer); 00669 SetWindowLongPtr(ie.hwndClient, GWLP_CHINST, (LONG_PTR)pcii->hInstClient); 00670 00671 gaService = LocalToGlobalAtom(laService); 00672 gaTopic = LocalToGlobalAtom(laTopic); 00673 ie.lParam = MAKELONG(gaService, gaTopic); 00674 if (!hwndTarget) { 00675 ie.hwndSkip = hwndSkip; 00676 ie.laServiceRequested = laService; 00677 ie.laTopic = laTopic; 00678 ie.hConvList = hConvList; 00679 ie.clst = clst; 00680 } 00681 00682 LeaveDDECrit; 00683 00684 if (hwndTarget) { 00685 SendMessage(hwndTarget, WM_DDE_INITIATE, (WPARAM)ie.hwndClient, 00686 ie.lParam); 00687 } else { 00688 /* 00689 * Send this message to the nddeagnt app first so it can start 00690 * the netdde services BEFORE we do an enumeration of windows. 00691 * This lets things work the first time. NetDDEAgent caches 00692 * service status so this is the fastest way to do this. 00693 */ 00694 HWND hwndAgent = FindWindowW(SZ_NDDEAGNT_CLASS, SZ_NDDEAGNT_TITLE); 00695 if (hwndAgent) { 00696 SendMessage(hwndAgent, 00697 WM_DDE_INITIATE, (WPARAM)ie.hwndClient, ie.lParam); 00698 } 00699 EnumWindows((WNDENUMPROC)InitiateEnumerationProc, (LPARAM)&ie); 00700 } 00701 00702 EnterDDECrit; 00703 /* 00704 * hConvList may have been destroyed during the enumeration but we are 00705 * done with it now so no need to revalidate. 00706 */ 00707 00708 #if DBG 00709 { 00710 WCHAR sz[10]; 00711 00712 if (gaService && GlobalGetAtomName(gaService, sz, 10) == 0) { 00713 RIPMSG1(RIP_ERROR, "Bad Service Atom after Initiate phase: %lX", (DWORD)gaService); 00714 } 00715 if (gaTopic && GlobalGetAtomName(gaTopic, sz, 10) == 0) { 00716 RIPMSG1(RIP_ERROR, "Bad Topic Atom after Initiate phase: %lX", (DWORD)gaTopic); 00717 } 00718 } 00719 #endif // DBG 00720 00721 GlobalDeleteAtom(gaService); 00722 GlobalDeleteAtom(gaTopic); 00723 00724 // 00725 // Get the first pci allocated when a WM_DDE_ACK was recieved. 00726 // 00727 pci = (PCL_CONV_INFO)GetWindowLongPtr(ie.hwndClient, GWLP_PCI); 00728 if (pci == NULL) { 00729 Error: 00730 LeaveDDECrit; 00731 NtUserDestroyWindow(ie.hwndClient); 00732 EnterDDECrit; 00733 return (NULL); 00734 } 00735 00736 SetWindowLong(ie.hwndClient, GWL_CONVSTATE, CLST_CONNECTED); 00737 if (hwndTarget) { 00738 /* 00739 * If hwndTarget was NULL, the enumeration proc took care of this. 00740 */ 00741 pci->hwndReconnect = hwndTarget; 00742 UserAssert(pci->ci.next == NULL); 00743 pci->ci.laServiceRequested = laService; 00744 IncLocalAtomCount(laService); // pci copy 00745 } 00746 00747 if (pcii->MonitorFlags & MF_CONV) { 00748 for (pcoi = (PCONV_INFO)pci; pcoi; pcoi = pcoi->next) { 00749 MONCONV(pcoi, TRUE); 00750 } 00751 } 00752 return (pci); 00753 } 00754 00755 00756 /* 00757 * Undoes the work of ConnectConv() 00758 */ 00759 VOID DisconnectConv( 00760 PCONV_INFO pcoi) 00761 { 00762 PCONV_INFO pcoiNext; 00763 00764 for (; pcoi; pcoi = pcoiNext) { 00765 pcoiNext = pcoi->next; 00766 ShutdownConversation(pcoi, FALSE); 00767 } 00768 } 00769 00770 00771 /***************************************************************************\ 00772 * InitiateEnumerationProc (FILE LOCAL) 00773 * 00774 * Description: 00775 * Function used via EnumWindows to enumerate all server window candidates 00776 * during DDE initiation. The enumeration allows DDEML to know what 00777 * window WM_DDE_INITIATE was sent to so that it can be remembered for 00778 * possible reconnection later. (The window that receives the WM_DDE_INITIATE 00779 * message is not necessarily going to be the server window.) 00780 * 00781 * History: 00782 * 11-1-91 sanfords Created. 00783 \***************************************************************************/ 00784 BOOL InitiateEnumerationProc( 00785 HWND hwndTarget, 00786 PINIT_ENUM pie) 00787 { 00788 PCL_CONV_INFO pci; 00789 00790 CheckDDECritOut; 00791 00792 if (hwndTarget == pie->hwndSkip) { 00793 return (TRUE); 00794 } 00795 00796 if (pie->hConvList && pie->laTopic && pie->laServiceRequested) { 00797 /* 00798 * Head off duplicates BEFORE we send the WM_DDE_INITIATE messages! 00799 */ 00800 PCONVLIST pcl; 00801 PCONV_INFO pcoiExisting; 00802 int i; 00803 00804 EnterDDECrit; 00805 /* 00806 * We revalidate hConvList here because we left the critical section. 00807 */ 00808 pcl = (PCONVLIST)ValidateCHandle((HANDLE)pie->hConvList, 00809 HTYPE_CONVERSATION_LIST, HINST_ANY); 00810 if (pcl != NULL) { 00811 for (i = 0; i < pcl->chwnd; i++) { 00812 for (pcoiExisting = (PCONV_INFO)GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI); 00813 pcoiExisting != NULL; 00814 pcoiExisting = pcoiExisting->next) { 00815 if (pcoiExisting->state & ST_CONNECTED && 00816 ((PCL_CONV_INFO)pcoiExisting)->hwndReconnect == hwndTarget && 00817 pcoiExisting->laTopic == pie->laTopic && 00818 pcoiExisting->laService == pie->laServiceRequested) { 00819 LeaveDDECrit; 00820 return(TRUE); 00821 } 00822 } 00823 } 00824 } 00825 LeaveDDECrit; 00826 } 00827 00828 CheckDDECritOut; 00829 00830 SendMessage(hwndTarget, WM_DDE_INITIATE, (WPARAM)pie->hwndClient, 00831 pie->lParam); 00832 00833 EnterDDECrit; 00834 00835 // 00836 // During the initiate process, any acks received cause more pci's 00837 // to become linked together under the same hwndClient. Once 00838 // the SendMessage() returns, we set the parts of the new pci's 00839 // that hold initiate context information. 00840 // 00841 pci = (PCL_CONV_INFO)GetWindowLongPtr(pie->hwndClient, GWLP_PCI); 00842 if (pci == NULL) { 00843 LeaveDDECrit; 00844 return (TRUE); 00845 } 00846 00847 while (pci != NULL) { 00848 if (pci->hwndReconnect == 0) { // this one needs updating 00849 pci->hwndReconnect = hwndTarget; 00850 if (pie->laServiceRequested) { 00851 pci->ci.laServiceRequested = pie->laServiceRequested; 00852 IncLocalAtomCount(pie->laServiceRequested); // pci copy 00853 } 00854 } 00855 if (pie->clst == CLST_SINGLE_INITIALIZING) { 00856 break; 00857 } 00858 pci = (PCL_CONV_INFO)pci->ci.next; 00859 } 00860 LeaveDDECrit; 00861 return (pie->clst == CLST_MULT_INITIALIZING); 00862 } 00863 00864 00865 00866 00867 /***************************************************************************\ 00868 * SetCommonStateFlags() 00869 * 00870 * Description: 00871 * Common client/server worker function 00872 * 00873 * History: 00874 * 05-12-91 sanfords Created. 00875 \***************************************************************************/ 00876 VOID SetCommonStateFlags( 00877 HWND hwndUs, 00878 HWND hwndThem, 00879 PWORD pwFlags) 00880 { 00881 DWORD pidUs, pidThem; 00882 00883 GetWindowThreadProcessId(hwndUs, &pidUs); 00884 GetWindowThreadProcessId(hwndThem, &pidThem); 00885 if (pidUs == pidThem) { 00886 *pwFlags |= ST_INTRA_PROCESS; 00887 } 00888 00889 if (IsWindowUnicode(hwndUs) && IsWindowUnicode(hwndThem)) { 00890 *pwFlags |= ST_UNICODE_EXECUTE; 00891 } 00892 } 00893 00894 00895 00896 00897 /***************************************************************************\ 00898 * DdeQueryNextServer (DDEML API) 00899 * 00900 * Description: 00901 * Enumerates conversations within a list. 00902 * 00903 * History: 00904 * 11-12-91 sanfords Created. 00905 \***************************************************************************/ 00906 HCONV DdeQueryNextServer( 00907 HCONVLIST hConvList, 00908 HCONV hConvPrev) 00909 { 00910 HCONV hConvRet = 0; 00911 PCONVLIST pcl; 00912 HWND *phwnd; 00913 int i; 00914 PCL_CONV_INFO pci; 00915 PCL_INSTANCE_INFO pcii; 00916 00917 EnterDDECrit; 00918 00919 pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList, 00920 HTYPE_CONVERSATION_LIST, HINST_ANY); 00921 if (pcl == NULL) { 00922 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 00923 goto Exit; 00924 } 00925 if (!pcl->chwnd) { // empty list 00926 goto Exit; 00927 } 00928 pcii = PciiFromHandle((HANDLE)hConvList); 00929 if (pcii == NULL) { 00930 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 00931 goto Exit; 00932 } 00933 00934 pcii->LastError = DMLERR_NO_ERROR; 00935 00936 do { 00937 00938 hConvRet = 0; 00939 00940 if (hConvPrev == 0) { 00941 pci = (PCL_CONV_INFO)GetWindowLongPtr(pcl->ahwnd[0], GWLP_PCI); 00942 if (pci == NULL) { 00943 goto Exit; // Must have all conversations zombied. 00944 } 00945 hConvPrev = hConvRet = pci->ci.hConv; 00946 continue; 00947 } 00948 00949 pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConvPrev, 00950 HTYPE_CLIENT_CONVERSATION, InstFromHandle(hConvList)); 00951 if (pci == NULL) { 00952 pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConvPrev, 00953 HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(hConvList)); 00954 if (pci == NULL) { 00955 SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); 00956 break; 00957 } else { 00958 goto ZombieSkip; 00959 } 00960 } 00961 00962 if (pci->hConvList != hConvList) { 00963 SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); 00964 break; 00965 } 00966 00967 ZombieSkip: 00968 00969 if (pci->ci.next == NULL) { 00970 00971 /* 00972 * end of list for this window, go to next window 00973 */ 00974 for (phwnd = pcl->ahwnd, i = 0; (i + 1) < pcl->chwnd; i++) { 00975 if (phwnd[i] == pci->ci.hwndConv) { 00976 pci = (PCL_CONV_INFO)GetWindowLongPtr(phwnd[i + 1], GWLP_PCI); 00977 if (pci == NULL) { 00978 break; 00979 } 00980 hConvPrev = hConvRet = pci->ci.hConv; 00981 break; 00982 } 00983 } 00984 } else { 00985 00986 hConvPrev = hConvRet = pci->ci.next->hConv; // next conv for this window. 00987 } 00988 00989 } while (hConvRet && TypeFromHandle(hConvRet) == HTYPE_ZOMBIE_CONVERSATION); 00990 Exit: 00991 LeaveDDECrit; 00992 return (hConvRet); 00993 } 00994 00995 00996 00997 00998 00999 /***************************************************************************\ 01000 * DdeDisconnect (DDEML API) 01001 * 01002 * Description: 01003 * Terminates a conversation. 01004 * 01005 * History: 01006 * 11-12-91 sanfords Created. 01007 \***************************************************************************/ 01008 BOOL DdeDisconnect( 01009 HCONV hConv) 01010 { 01011 BOOL fRet = FALSE; 01012 PCONV_INFO pcoi; 01013 PCL_INSTANCE_INFO pcii; 01014 01015 CheckDDECritOut; 01016 EnterDDECrit; 01017 01018 pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, 01019 HTYPE_CLIENT_CONVERSATION, HINST_ANY); 01020 if (pcoi == NULL) { 01021 pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, 01022 HTYPE_SERVER_CONVERSATION, HINST_ANY); 01023 } 01024 if (pcoi == NULL) { 01025 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 01026 goto Exit; 01027 } 01028 pcii = PciiFromHandle((HANDLE)hConv); 01029 if (pcii == NULL) { 01030 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 01031 goto Exit; 01032 } 01033 if (pcoi->state & ST_CONNECTED) { 01034 ShutdownConversation(pcoi, FALSE); 01035 } 01036 fRet = TRUE; 01037 01038 Exit: 01039 LeaveDDECrit; 01040 return (fRet); 01041 } 01042 01043 01044 /***************************************************************************\ 01045 * DdeDisconnectList (DDEML API) 01046 * 01047 * Description: 01048 * Terminates all conversations in a conversation list and frees the list. 01049 * 01050 * History: 01051 * 11-12-91 sanfords Created. 01052 \***************************************************************************/ 01053 BOOL DdeDisconnectList( 01054 HCONVLIST hConvList) 01055 { 01056 BOOL fRet = FALSE; 01057 PCL_INSTANCE_INFO pcii; 01058 PCONVLIST pcl; 01059 PCONV_INFO pcoi, pcoiNext; 01060 int i; 01061 01062 CheckDDECritOut; 01063 EnterDDECrit; 01064 01065 pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList, 01066 HTYPE_CONVERSATION_LIST, HINST_ANY); 01067 if (pcl == NULL) { 01068 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 01069 goto Exit; 01070 } 01071 ValidateConvList(hConvList); 01072 pcii = PciiFromHandle((HANDLE)hConvList); 01073 if (pcii == NULL) { 01074 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 01075 goto Exit; 01076 } 01077 01078 for(i = pcl->chwnd - 1; i >= 0; i--) { 01079 pcoi = (PCONV_INFO)GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI); 01080 while (pcoi != NULL && pcoi->state & ST_CONNECTED) { 01081 pcoiNext = pcoi->next; 01082 ShutdownConversation(pcoi, FALSE); // may unlink pcoi! 01083 pcoi = pcoiNext; 01084 } 01085 } 01086 01087 DestroyHandle((HANDLE)hConvList); 01088 DDEMLFree(pcl); 01089 fRet = TRUE; 01090 01091 Exit: 01092 LeaveDDECrit; 01093 return (fRet); 01094 } 01095 01096 01097 01098 01099 /***************************************************************************\ 01100 * ShutdownConversation 01101 * 01102 * Description: 01103 * This function causes an imediate termination of the given conversation 01104 * and generates apropriate callbacks to notify the application. 01105 * 01106 * History: 01107 * 11-12-91 sanfords Created. 01108 \***************************************************************************/ 01109 VOID ShutdownConversation( 01110 PCONV_INFO pcoi, 01111 BOOL fMakeCallback) 01112 { 01113 CheckDDECritIn; 01114 01115 if (pcoi->state & ST_CONNECTED) { 01116 pcoi->state &= ~ST_CONNECTED; 01117 01118 if (IsWindow(pcoi->hwndPartner)) { 01119 PostMessage(pcoi->hwndPartner, WM_DDE_TERMINATE, 01120 (WPARAM)pcoi->hwndConv, 0); 01121 } 01122 if (fMakeCallback && !(pcoi->pcii->afCmd & CBF_SKIP_DISCONNECTS)) { 01123 DoCallback(pcoi->pcii, (WORD)XTYP_DISCONNECT, 0, pcoi->hConv, 01124 0, 0, 0, 0, (pcoi->state & ST_ISSELF) ? 1L : 0L); 01125 } 01126 MONCONV(pcoi, FALSE); 01127 } 01128 01129 FreeConversationResources(pcoi); 01130 } 01131 01132 01133 01134 /***************************************************************************\ 01135 * UnlinkConvFromOthers 01136 * 01137 * Description: 01138 * 01139 * Helper function to handle ugly cross dependency removal. If we are 01140 * unlinking a conversation that is going zombie, fGoingZombie is TRUE; 01141 * 01142 * Conversations that are going zombie are in phase 1 of a 2 phase unlink. 01143 * Phase 1 unlinks do not remove the pcoi from its hwnd's list. 01144 * All unlinks should result in: 01145 * pcoi->hConvList = 0; 01146 * hConvList/aServerLookup no longer refrences pcoi->hwndConv unless 01147 * one of the pcoi's related to hwndConv is still active. 01148 * 01149 * 01150 * History: 01151 * 3-2-92 sanfords Created. 01152 \***************************************************************************/ 01153 VOID UnlinkConvFromOthers( 01154 PCONV_INFO pcoi, 01155 BOOL gGoingZombie) 01156 { 01157 PCONV_INFO pcoiPrev, pcoiFirst, pcoiNow; 01158 PCONVLIST pcl; 01159 int i, cActiveInList = 0; 01160 #ifdef TESTING 01161 DWORD path = 0; 01162 #define ORPATH(x) path |= x; 01163 #else 01164 #define ORPATH(x) 01165 #endif // TESTING 01166 01167 CheckDDECritIn; 01168 01169 /* 01170 * Scan pcoi linked list to get key pointers. 01171 */ 01172 pcoiPrev = NULL; 01173 pcoiFirst = pcoiNow = (PCONV_INFO)GetWindowLongPtr(pcoi->hwndConv, GWLP_PCI); 01174 01175 #ifdef TESTING 01176 /* 01177 * verify that pcoi is in the conv list for this window. 01178 */ 01179 while (pcoiNow != NULL) { 01180 if (pcoiNow == pcoi) { 01181 goto FoundIt; 01182 } 01183 pcoiNow = pcoiNow->next; 01184 } 01185 DebugBreak(); 01186 FoundIt: 01187 pcoiNow = pcoiFirst; 01188 #endif // TESTING 01189 01190 UserAssert(pcoiFirst); 01191 while (pcoiNow != NULL) { 01192 if (TypeFromHandle(pcoiNow->hConv) != HTYPE_ZOMBIE_CONVERSATION) { 01193 ORPATH(1); 01194 cActiveInList++; 01195 } 01196 if (pcoiNow->next == pcoi) { 01197 pcoiPrev = pcoiNow; 01198 } 01199 pcoiNow = pcoiNow->next; 01200 } 01201 01202 ValidateAllConvLists(); 01203 01204 /* 01205 * Unlink conversation unless its going Zombie. 01206 */ 01207 if (!gGoingZombie) { 01208 ORPATH(2); 01209 if (TypeFromHandle(pcoi->hConv) != HTYPE_ZOMBIE_CONVERSATION) { 01210 ORPATH(4); 01211 cActiveInList--; 01212 } 01213 01214 if (pcoiPrev == NULL) { 01215 ORPATH(8); 01216 pcoiFirst = pcoi->next; 01217 SetWindowLongPtr(pcoi->hwndConv, GWLP_PCI, (LONG_PTR)pcoiFirst); 01218 } else { 01219 pcoiPrev->next = pcoi->next; 01220 } 01221 } 01222 01223 UserAssert(pcoiFirst != NULL || !cActiveInList); 01224 01225 if (cActiveInList == 0) { 01226 ORPATH(0x10); 01227 if (pcoi->state & ST_CLIENT) { 01228 ORPATH(0x20); 01229 if (((PCL_CONV_INFO)pcoi)->hConvList) { 01230 /* 01231 * Remove pcoi's hwnd from its hConvList. 01232 */ 01233 pcl = (PCONVLIST)GetHandleData((HANDLE)((PCL_CONV_INFO)pcoi)->hConvList); 01234 for (i = 0; i < pcl->chwnd; i++) { 01235 if (pcl->ahwnd[i] == pcoi->hwndConv) { 01236 ORPATH(0x40); 01237 pcl->chwnd--; 01238 UserAssert(pcl->ahwnd[pcl->chwnd]); 01239 pcl->ahwnd[i] = pcl->ahwnd[pcl->chwnd]; 01240 ValidateConvList(((PCL_CONV_INFO)pcoi)->hConvList); 01241 break; 01242 } 01243 } 01244 ORPATH(0x80); 01245 } 01246 } else { // SERVER 01247 /* 01248 * remove server window from the service/topic lookup table. 01249 */ 01250 ORPATH(0x100); 01251 for (i = 0; i < pcoi->pcii->cServerLookupAlloc; i++) { 01252 if (pcoi->pcii->aServerLookup[i].hwndServer == pcoi->hwndConv) { 01253 ORPATH(0x200); 01254 01255 /* 01256 * Check for appcompat hack 01257 */ 01258 if (GetAppCompatFlags2(VERMAX) & GACF2_DDE) { 01259 DeleteAtom(pcoi->pcii->aServerLookup[i].laService); // delete laService 01260 DeleteAtom(pcoi->pcii->aServerLookup[i].laTopic); // delete laTopic 01261 } 01262 01263 if (--(pcoi->pcii->cServerLookupAlloc)) { 01264 ORPATH(0x400); 01265 pcoi->pcii->aServerLookup[i] = 01266 pcoi->pcii->aServerLookup[pcoi->pcii->cServerLookupAlloc]; 01267 } else { 01268 DDEMLFree(pcoi->pcii->aServerLookup); 01269 pcoi->pcii->aServerLookup = NULL; 01270 } 01271 break; 01272 } 01273 } 01274 } 01275 } 01276 #ifdef TESTING 01277 else { 01278 /* 01279 * make sure at this point we have at least one non-zombie 01280 */ 01281 pcoiNow = pcoiFirst; 01282 while (pcoiNow != NULL) { 01283 if (TypeFromHandle(pcoiNow->hConv) != HTYPE_ZOMBIE_CONVERSATION) { 01284 goto Out; 01285 } 01286 pcoiNow = pcoiNow->next; 01287 } 01288 DebugBreak(); 01289 Out: 01290 ; 01291 } 01292 #endif // TESTING 01293 01294 ValidateAllConvLists(); 01295 ORPATH(0x800); 01296 01297 /* 01298 * In any case remove hConvList references from client conversation. 01299 */ 01300 if (pcoi->state & ST_CLIENT) { 01301 #ifdef TESTING 01302 /* 01303 * Verify that the hConvList that is being removed, doesn't reference 01304 * this window. 01305 */ 01306 if (((PCL_CONV_INFO)pcoi)->hConvList && !cActiveInList) { 01307 BOOL fFound = FALSE; 01308 01309 pcl = (PCONVLIST)GetHandleData((HANDLE)((PCL_CONV_INFO)pcoi)->hConvList); 01310 for (i = 0; i < pcl->chwnd; i++) { 01311 if (pcl->ahwnd[i] == pcoi->hwndConv) { 01312 fFound = TRUE; 01313 break; 01314 } 01315 } 01316 UserAssert(!fFound); 01317 } 01318 #endif // TESTING 01319 ((PCL_CONV_INFO)pcoi)->hConvList = 0; 01320 pcoi->state &= ~ST_INLIST; 01321 } 01322 01323 /* 01324 * last one out turns out the lights. 01325 */ 01326 if (pcoiFirst == NULL) { 01327 /* 01328 * If the pcoi list is empty, this window can go away. 01329 */ 01330 LeaveDDECrit; 01331 NtUserDestroyWindow(pcoi->hwndConv); 01332 EnterDDECrit; 01333 } 01334 } 01335 01336 01337 01338 01339 01340 /***************************************************************************\ 01341 * FreeConversationResources 01342 * 01343 * Description: 01344 * Used when: Client window is disconnected by app, Server window is 01345 * disconnected by either side, or when a conversation is disconnected 01346 * at Uninitialize time. 01347 * 01348 * This function releases all resources held by the pcoi and unlinks it 01349 * from its host window pcoi chian. pcoi is freed once this return s. 01350 * 01351 * History: 01352 * 12-21-91 sanfords Created. 01353 \***************************************************************************/ 01354 VOID FreeConversationResources( 01355 PCONV_INFO pcoi) 01356 { 01357 PADVISE_LINK paLink; 01358 PDDE_MESSAGE_QUEUE pdmq; 01359 PXACT_INFO pxi; 01360 01361 CheckDDECritIn; 01362 01363 /* 01364 * Don't free resources on locked conversations. 01365 */ 01366 if (pcoi->cLocks > 0) { 01367 pcoi->state |= ST_FREE_CONV_RES_NOW; 01368 return; 01369 } 01370 01371 /* 01372 * Don't free resources if a synchronous transaction is in effect! 01373 */ 01374 pxi = pcoi->pxiOut; 01375 while (pxi != NULL) { 01376 if (pxi->flags & XIF_SYNCHRONOUS) { 01377 /* 01378 * This conversation is in a synchronous transaction. 01379 * Shutdown the modal loop FIRST, then call this when 01380 * the loop exits. 01381 */ 01382 PostMessage(pcoi->hwndConv, WM_TIMER, TID_TIMEOUT, 0); 01383 pcoi->state |= ST_FREE_CONV_RES_NOW; 01384 return; 01385 } 01386 pxi = pxi->next; 01387 } 01388 01389 /* 01390 * If this is an Intra-Process conversation that hasn't yet received 01391 * a terminate message, make it a zombie. We will call this routine 01392 * again once the terminate arrives or when WaitForZombieTerminate() has 01393 * timed out waiting. 01394 */ 01395 if (pcoi->state & ST_INTRA_PROCESS && !(pcoi->state & ST_TERMINATE_RECEIVED)) { 01396 DestroyHandle((HANDLE)pcoi->hConv); 01397 pcoi->hConv = (HCONV)CreateHandle((ULONG_PTR)pcoi, HTYPE_ZOMBIE_CONVERSATION, 01398 InstFromHandle(pcoi->hConv)); 01399 UnlinkConvFromOthers(pcoi, TRUE); 01400 return; 01401 } 01402 01403 /* 01404 * remove any transactions left in progress 01405 */ 01406 while (pcoi->pxiOut != NULL) { 01407 (pcoi->pxiOut->pfnResponse)(pcoi->pxiOut, 0, 0); 01408 } 01409 01410 /* 01411 * Throw away any incoming queued DDE messages. 01412 */ 01413 while (pcoi->dmqOut != NULL) { 01414 01415 pdmq = pcoi->dmqOut; 01416 DumpDDEMessage(!(pcoi->state & ST_INTRA_PROCESS), pdmq->msg, pdmq->lParam); 01417 pcoi->dmqOut = pcoi->dmqOut->next; 01418 if (pcoi->dmqOut == NULL) { 01419 pcoi->dmqIn = NULL; 01420 } 01421 DDEMLFree(pdmq); 01422 } 01423 01424 // 01425 // Remove all link info 01426 // 01427 paLink = pcoi->aLinks; 01428 while (pcoi->cLinks) { 01429 if (pcoi->state & ST_CLIENT) { 01430 MONLINK(pcoi->pcii, FALSE, paLink->wType & XTYPF_NODATA, 01431 pcoi->laService, pcoi->laTopic, 01432 LocalToGlobalAtom(paLink->laItem), 01433 paLink->wFmt, FALSE, 01434 (HCONV)pcoi->hwndPartner, (HCONV)pcoi->hwndConv); 01435 } else { 01436 MONLINK(pcoi->pcii, FALSE, paLink->wType & XTYPF_NODATA, 01437 pcoi->laService, pcoi->laTopic, 01438 LocalToGlobalAtom(paLink->laItem), 01439 paLink->wFmt, TRUE, 01440 (HCONV)pcoi->hwndConv, (HCONV)pcoi->hwndPartner); 01441 } 01442 if (!(pcoi->state & ST_CLIENT)) { 01443 DeleteLinkCount(pcoi->pcii, paLink->pLinkCount); 01444 } 01445 DeleteAtom(paLink->laItem); // link structure copy 01446 paLink++; 01447 pcoi->cLinks--; 01448 } 01449 if (pcoi->aLinks) { 01450 DDEMLFree(pcoi->aLinks); 01451 } 01452 01453 // 01454 // free atoms associated with this conv 01455 // 01456 DeleteAtom(pcoi->laService); 01457 DeleteAtom(pcoi->laTopic); 01458 if (pcoi->laServiceRequested) { 01459 DeleteAtom(pcoi->laServiceRequested); 01460 } 01461 01462 UnlinkConvFromOthers(pcoi, FALSE); 01463 01464 /* 01465 * invalidate app's conversation handle 01466 */ 01467 DestroyHandle((HANDLE)pcoi->hConv); 01468 01469 DDEMLFree(pcoi); 01470 } 01471 01472 01473 01474 BOOL WaitForZombieTerminate( 01475 HANDLE hData) 01476 { 01477 PCONV_INFO pcoi; 01478 MSG msg; 01479 HWND hwnd; 01480 BOOL fTerminated; 01481 DWORD fRet = 0; 01482 01483 CheckDDECritOut; 01484 EnterDDECrit; 01485 01486 fTerminated = FALSE; 01487 while ((pcoi = (PCONV_INFO)ValidateCHandle(hData, 01488 HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(hData))) != NULL && 01489 !(pcoi->state & ST_TERMINATE_RECEIVED)) { 01490 hwnd = pcoi->hwndConv; 01491 LeaveDDECrit; 01492 while (PeekMessage(&msg, hwnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) { 01493 DispatchMessage(&msg); 01494 if (msg.message == WM_DDE_TERMINATE) { 01495 fTerminated = TRUE; 01496 } 01497 } 01498 if (!fTerminated) { 01499 fRet = MsgWaitForMultipleObjectsEx(0, NULL, 100, QS_POSTMESSAGE, 0); 01500 if (fRet == 0xFFFFFFFF) { 01501 RIPMSG0(RIP_WARNING, "WaitForZombieTerminate: I give up - faking terminate."); 01502 ProcessTerminateMsg(pcoi, pcoi->hwndPartner); 01503 EnterDDECrit; 01504 return(FALSE); 01505 } 01506 } 01507 EnterDDECrit; 01508 } 01509 LeaveDDECrit; 01510 return(TRUE); 01511 }

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