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

xact.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: xact.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * DDE Manager transaction processing module 00007 * 00008 * Created: 11/3/91 Sanford Staab 00009 \***************************************************************************/ 00010 00011 #include "precomp.h" 00012 #pragma hdrstop 00013 00014 00015 /***************************************************************************\ 00016 * DdeClientTransaction (DDEML API) 00017 * 00018 * Description: 00019 * Initiates all DDE transactions. 00020 * 00021 * History: 00022 * 11-1-91 sanfords Created. 00023 \***************************************************************************/ 00024 HDDEDATA DdeClientTransaction( 00025 LPBYTE pData, 00026 DWORD cbData, 00027 HCONV hConv, 00028 HSZ hszItem, 00029 UINT wFmt, 00030 UINT wType, 00031 DWORD ulTimeout, 00032 LPDWORD pulResult) 00033 { 00034 MSG msg; 00035 PCL_INSTANCE_INFO pcii = NULL; 00036 HDDEDATA hRet = 0; 00037 PCL_CONV_INFO pci; 00038 PDDEMLDATA pdd = NULL; 00039 PXACT_INFO pxi; 00040 BOOL fStarted; 00041 PDDE_DATA pdde; 00042 00043 EnterDDECrit; 00044 00045 pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConv, 00046 HTYPE_CLIENT_CONVERSATION, HINST_ANY); 00047 if (pci == NULL) { 00048 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 00049 goto Exit; 00050 } 00051 pcii = pci->ci.pcii; 00052 if (ulTimeout != TIMEOUT_ASYNC && GetClientInfo()->CI_flags & CI_IN_SYNC_TRANSACTION) { 00053 SetLastDDEMLError(pcii, DMLERR_REENTRANCY); 00054 goto Exit; 00055 } 00056 if (!(pci->ci.state & ST_CONNECTED)) { 00057 SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED); 00058 goto Exit; 00059 } 00060 00061 switch (wType) { 00062 case XTYP_POKE: 00063 case XTYP_ADVSTART: 00064 case XTYP_ADVSTART | XTYPF_NODATA: 00065 case XTYP_ADVSTART | XTYPF_ACKREQ: 00066 case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: 00067 case XTYP_REQUEST: 00068 case XTYP_ADVSTOP: 00069 if (hszItem == 0) { 00070 SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); 00071 goto Exit; 00072 } 00073 break; 00074 00075 case XTYP_EXECUTE: // just ignore wFmt & hszItem 00076 break; 00077 00078 default: 00079 SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); 00080 goto Exit; 00081 } 00082 00083 pxi = DDEMLAlloc(sizeof(XACT_INFO)); 00084 if (pxi == NULL) { 00085 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00086 goto Exit; 00087 } 00088 00089 switch (wType) { 00090 case XTYP_EXECUTE: 00091 case XTYP_POKE: 00092 if ((LONG)cbData == -1L) { 00093 00094 // We are accepting an existing data handle for export to another 00095 // app. 00096 00097 pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)pData, 00098 HTYPE_DATA_HANDLE, HINST_ANY); 00099 if (pdd == NULL) { 00100 InvParam: 00101 SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); 00102 DDEMLFree(pxi); 00103 goto Exit; 00104 } 00105 00106 // make sure data handle holds apropriate data for this transaction 00107 00108 if ((pdd->flags & HDATA_EXECUTE && wType != XTYP_EXECUTE) || 00109 (!(pdd->flags & HDATA_EXECUTE) && wType == XTYP_EXECUTE)) { 00110 goto InvParam; 00111 } 00112 00113 // To simplify life, use a copy if this handle is potentially 00114 // a relay or APPOWNED handle. 00115 00116 if (pdd->flags & (HDATA_APPOWNED | HDATA_NOAPPFREE)) { 00117 pxi->hDDESent = CopyDDEData(pdd->hDDE, wType == XTYP_EXECUTE); 00118 if (!pxi->hDDESent) { 00119 MemErr: 00120 DDEMLFree(pxi); 00121 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00122 goto Exit; 00123 } 00124 USERGLOBALLOCK(pxi->hDDESent, pdde); 00125 if (pdde == NULL) { 00126 FreeDDEData(pxi->hDDESent, TRUE, TRUE); 00127 goto MemErr; 00128 } 00129 pdde->wStatus = DDE_FRELEASE; 00130 USERGLOBALUNLOCK(pxi->hDDESent); 00131 } else { 00132 pxi->hDDESent = pdd->hDDE; 00133 } 00134 00135 // make sure handle has proper format 00136 00137 if (wType == XTYP_POKE) { 00138 USERGLOBALLOCK(pxi->hDDESent, pdde); 00139 if (pdde == NULL) { 00140 goto InvParam; 00141 } 00142 pdde->wFmt = (WORD)wFmt; 00143 USERGLOBALUNLOCK(pxi->hDDESent); 00144 } 00145 00146 } else { // Convert data in buffer into an apropriate hDDE 00147 00148 if (wType == XTYP_POKE) { 00149 pxi->hDDESent = AllocAndSetDDEData(pData, cbData, 00150 DDE_FRELEASE, (WORD)wFmt); 00151 } else { 00152 pxi->hDDESent = AllocAndSetDDEData(pData, cbData, 0, 0); 00153 } 00154 if (!pxi->hDDESent) { 00155 goto MemErr; 00156 } 00157 } 00158 } 00159 00160 // FINALLY - start the transaction 00161 00162 pxi->pcoi = (PCONV_INFO)pci; 00163 pxi->gaItem = LocalToGlobalAtom(LATOM_FROM_HSZ(hszItem)); // pxi copy 00164 pxi->wFmt = (WORD)wFmt; 00165 pxi->wType = (WORD)wType; 00166 00167 switch (wType) { 00168 case XTYP_ADVSTART: 00169 case XTYP_ADVSTART | XTYPF_NODATA: 00170 case XTYP_ADVSTART | XTYPF_ACKREQ: 00171 case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: 00172 fStarted = ClStartAdvise(pxi); 00173 break; 00174 00175 case XTYP_ADVSTOP: 00176 fStarted = ClStartUnadvise(pxi); 00177 break; 00178 00179 case XTYP_EXECUTE: 00180 fStarted = ClStartExecute(pxi); 00181 break; 00182 00183 case XTYP_POKE: 00184 fStarted = ClStartPoke(pxi); 00185 break; 00186 00187 case XTYP_REQUEST: 00188 fStarted = ClStartRequest(pxi); 00189 } 00190 00191 if (!fStarted) { 00192 // if we copied or allocated data - free it. 00193 if (pxi->hDDESent && (pdd == NULL || pxi->hDDESent != pdd->hDDE)) { 00194 FreeDDEData(pxi->hDDESent, FALSE, TRUE); // free data copy 00195 } 00196 GlobalDeleteAtom(pxi->gaItem); // pxi copy 00197 DDEMLFree(pxi); 00198 goto Exit; 00199 } 00200 00201 if (pdd != NULL && !(pdd->flags & (HDATA_NOAPPFREE | HDATA_APPOWNED))) { 00202 00203 // invalidate given handle on success - unless we copied it because 00204 // the app will either be return ing it from a callback or potentially 00205 // using it again. 00206 00207 DDEMLFree(pdd); 00208 DestroyHandle((HANDLE)pData); 00209 } 00210 00211 if (ulTimeout == TIMEOUT_ASYNC) { 00212 00213 // asynchronous transaction 00214 00215 if (pulResult != NULL) { 00216 pxi->hXact = CreateHandle((ULONG_PTR)pxi, HTYPE_TRANSACTION, 00217 InstFromHandle(pcii->hInstClient)); 00218 *pulResult = HandleToUlong(pxi->hXact); 00219 } 00220 hRet = (HDDEDATA)TRUE; 00221 00222 } else { 00223 00224 // synchronous transaction 00225 00226 GetClientInfo()->CI_flags |= CI_IN_SYNC_TRANSACTION; 00227 pcii->flags |= IIF_IN_SYNC_XACT; 00228 00229 pxi->flags |= XIF_SYNCHRONOUS; 00230 NtUserSetTimer(pci->ci.hwndConv, TID_TIMEOUT, ulTimeout, NULL); 00231 00232 LeaveDDECrit; 00233 CheckDDECritOut; 00234 00235 GetMessage(&msg, (HWND)NULL, 0, 0); 00236 00237 /* 00238 * stay in modal loop until a timeout happens. 00239 */ 00240 while (msg.hwnd != pci->ci.hwndConv || msg.message != WM_TIMER || 00241 (msg.wParam != TID_TIMEOUT)) { 00242 00243 if (!CallMsgFilter(&msg, MSGF_DDEMGR)) 00244 DispatchMessage(&msg); 00245 00246 GetMessage(&msg, (HWND)NULL, 0, 0); 00247 } 00248 00249 EnterDDECrit; 00250 00251 NtUserKillTimer(pci->ci.hwndConv, TID_TIMEOUT); 00252 GetClientInfo()->CI_flags &= ~CI_IN_SYNC_TRANSACTION; 00253 pcii->flags &= ~IIF_IN_SYNC_XACT; 00254 00255 if (pxi->flags & XIF_COMPLETE) { 00256 if (pulResult != NULL) { 00257 *pulResult = pxi->wStatus; // NACK status bits 00258 } 00259 switch (wType) { 00260 case XTYP_ADVSTART: 00261 case XTYP_ADVSTART | XTYPF_NODATA: 00262 case XTYP_ADVSTART | XTYPF_ACKREQ: 00263 case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: 00264 case XTYP_ADVSTOP: 00265 case XTYP_EXECUTE: 00266 case XTYP_POKE: 00267 hRet = (HDDEDATA)((pxi->wStatus & DDE_FACK) ? TRUE : FALSE); 00268 if (!hRet) { 00269 if (pxi->wStatus & DDE_FBUSY) { 00270 SetLastDDEMLError(pcii, DMLERR_BUSY); 00271 } else { 00272 SetLastDDEMLError(pcii, DMLERR_NOTPROCESSED); 00273 } 00274 } 00275 break; 00276 00277 case XTYP_REQUEST: 00278 if (pxi->hDDEResult == 0) { 00279 hRet = (HDDEDATA)((pxi->wStatus & DDE_FACK) ? TRUE : FALSE); 00280 if (!hRet) { 00281 if (pxi->wStatus & DDE_FBUSY) { 00282 SetLastDDEMLError(pcii, DMLERR_BUSY); 00283 } else { 00284 SetLastDDEMLError(pcii, DMLERR_NOTPROCESSED); 00285 } 00286 } 00287 break; 00288 } 00289 // Note that if the incoming data didn't have the DDE_FRELEASE 00290 // bit set, the transaction code would have made a copy so 00291 // the app is free to keep is as long as he likes. 00292 00293 hRet = InternalCreateDataHandle(pcii, (LPBYTE)pxi->hDDEResult, (DWORD)-1, 0, 00294 HDATA_READONLY, 0, 0); 00295 pxi->hDDEResult = 0; // so cleanup doesn't free it. 00296 } 00297 00298 (pxi->pfnResponse)((struct tagXACT_INFO *)pxi, 0, 0); // cleanup transaction 00299 00300 } else { // Timed out 00301 00302 // abandon the transaction and make it asyncronous so it will 00303 // clean itself up when the response finally comes in. 00304 00305 pxi->flags &= ~XIF_SYNCHRONOUS; 00306 pxi->flags |= XIF_ABANDONED; 00307 00308 switch (wType) { 00309 case XTYP_ADVSTART: 00310 case XTYP_ADVSTART | XTYPF_NODATA: 00311 case XTYP_ADVSTART | XTYPF_ACKREQ: 00312 case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: 00313 SetLastDDEMLError(pcii, DMLERR_ADVACKTIMEOUT); 00314 break; 00315 case XTYP_ADVSTOP: 00316 SetLastDDEMLError(pcii, DMLERR_UNADVACKTIMEOUT); 00317 break; 00318 case XTYP_EXECUTE: 00319 SetLastDDEMLError(pcii, DMLERR_EXECACKTIMEOUT); 00320 break; 00321 case XTYP_POKE: 00322 SetLastDDEMLError(pcii, DMLERR_POKEACKTIMEOUT); 00323 break; 00324 case XTYP_REQUEST: 00325 SetLastDDEMLError(pcii, DMLERR_DATAACKTIMEOUT); 00326 break; 00327 } 00328 // cleanup of pxi happens when transaction actually completes. 00329 } 00330 } 00331 if (pci->ci.state & ST_FREE_CONV_RES_NOW) { 00332 /* 00333 * The conversation was terminated during the synchronous transaction 00334 * so we need to clean up now that we are out of the loop. 00335 */ 00336 FreeConversationResources((PCONV_INFO)pci); 00337 } 00338 00339 Exit: 00340 /* 00341 * Because this API is capable of blocking DdeUninitialize(), we check 00342 * before exit to see if it needs to be called. 00343 */ 00344 if (pcii != NULL && 00345 (pcii->afCmd & APPCMD_UNINIT_ASAP) && 00346 // !(pcii->flags & IIF_IN_SYNC_XACT) && 00347 !pcii->cInDDEMLCallback) { 00348 DdeUninitialize(HandleToUlong(pcii->hInstClient)); 00349 hRet = 0; 00350 } 00351 LeaveDDECrit; 00352 return (hRet); 00353 } 00354 00355 00356 00357 00358 /***************************************************************************\ 00359 * GetConvContext 00360 * 00361 * Description: 00362 * Retrieves conversation context information from the DDEML client window 00363 * given. pl points to a CONVCONTEXT structure. 00364 * 00365 * History: 00366 * 11-12-91 sanfords Created. 00367 \***************************************************************************/ 00368 VOID GetConvContext( 00369 HWND hwnd, 00370 LONG *pl) 00371 { 00372 int i; 00373 00374 for (i = 0; i < sizeof(CONVCONTEXT); i += 4) { 00375 *pl++ = GetWindowLong(hwnd, GWL_CONVCONTEXT + i); 00376 } 00377 } 00378 00379 /***************************************************************************\ 00380 * SetConvContext 00381 * 00382 * Description: 00383 * 00384 * History: 00385 * 11-19-92 sanfords Created. 00386 \***************************************************************************/ 00387 VOID SetConvContext( 00388 HWND hwnd, 00389 LONG *pl) 00390 { 00391 int i; 00392 00393 for (i = 0; i < sizeof(CONVCONTEXT); i += 4) { 00394 SetWindowLong(hwnd, GWL_CONVCONTEXT + i, *pl++); 00395 } 00396 } 00397 00398 00399 00400 00401 /***************************************************************************\ 00402 * DdeQueryConvInfo (DDEML API) 00403 * 00404 * Description: 00405 * Retrieves detailed conversation information on a per conversation/ 00406 * transaction basis. 00407 * 00408 * History: 00409 * 11-12-91 sanfords Created. 00410 \***************************************************************************/ 00411 UINT DdeQueryConvInfo( 00412 HCONV hConv, 00413 DWORD idTransaction, 00414 PCONVINFO pConvInfo) 00415 { 00416 PCONV_INFO pcoi; 00417 PXACT_INFO pxi; 00418 CONVINFO ci; 00419 UINT uiRet = 0; 00420 00421 EnterDDECrit; 00422 00423 if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( idTransaction ), &pcoi, &pxi)) { 00424 goto Exit; 00425 } 00426 00427 try { 00428 if (pConvInfo->cb > sizeof(CONVINFO)) { 00429 SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER); 00430 goto Exit; 00431 } 00432 ci.cb = pConvInfo->cb; 00433 ci.hConvPartner = 0; // no longer supported. 00434 ci.hszSvcPartner = NORMAL_HSZ_FROM_LATOM(pcoi->laService); 00435 ci.hszServiceReq = NORMAL_HSZ_FROM_LATOM(pcoi->laServiceRequested); 00436 ci.hszTopic = NORMAL_HSZ_FROM_LATOM(pcoi->laTopic); 00437 ci.wStatus = pcoi->state; 00438 ci.wLastError = (WORD)pcoi->pcii->LastError; 00439 if (pcoi->state & ST_CLIENT) { 00440 ci.hConvList = ((PCL_CONV_INFO)pcoi)->hConvList; 00441 GetConvContext(pcoi->hwndConv, (LONG *)&ci.ConvCtxt); 00442 } else { 00443 ci.hConvList = 0; 00444 if (pcoi->state & ST_ISLOCAL) { 00445 GetConvContext(pcoi->hwndPartner, (LONG *)&ci.ConvCtxt); 00446 } else { 00447 ci.ConvCtxt = DefConvContext; 00448 } 00449 } 00450 if (pxi == NULL) { 00451 ci.hUser = pcoi->hUser; 00452 ci.hszItem = 0; 00453 ci.wFmt = 0; 00454 ci.wType = 0; 00455 ci.wConvst = XST_CONNECTED; 00456 } else { 00457 ci.hUser = pxi->hUser; 00458 // BUG - not fixable - This will result in extra local atoms 00459 // since we can never know when he is done with them. 00460 ci.hszItem = NORMAL_HSZ_FROM_LATOM(GlobalToLocalAtom(pxi->gaItem)); 00461 ci.wFmt = pxi->wFmt; 00462 ci.wType = pxi->wType; 00463 ci.wConvst = pxi->state; 00464 } 00465 ci.hwnd = pcoi->hwndConv; 00466 ci.hwndPartner = pcoi->hwndPartner; 00467 RtlCopyMemory((LPSTR)pConvInfo, (LPSTR)&ci, pConvInfo->cb); 00468 } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { 00469 SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER); 00470 goto Exit; 00471 } 00472 uiRet = TRUE; 00473 00474 Exit: 00475 LeaveDDECrit; 00476 return (uiRet); 00477 } 00478 00479 00480 /***************************************************************************\ 00481 * DdeSetUserHandle (DDEML API) 00482 * 00483 * Description: 00484 * Sets a user DWORD on a per conversation/transaction basis. 00485 * 00486 * History: 00487 * 11-12-91 sanfords Created. 00488 \***************************************************************************/ 00489 BOOL DdeSetUserHandle( 00490 HCONV hConv, 00491 DWORD id, 00492 DWORD_PTR hUser) 00493 { 00494 PCONV_INFO pcoi; 00495 PXACT_INFO pxi; 00496 BOOL fRet = FALSE; 00497 00498 EnterDDECrit; 00499 00500 if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( id ), &pcoi, &pxi)) { 00501 goto Exit; 00502 } 00503 if (pxi == NULL) { 00504 pcoi->hUser = hUser; 00505 } else { 00506 pxi->hUser = hUser; 00507 } 00508 fRet = TRUE; 00509 00510 Exit: 00511 LeaveDDECrit; 00512 return (fRet); 00513 } 00514 00515 00516 00517 VOID AbandonTransaction( 00518 PCONV_INFO pcoi, 00519 PXACT_INFO pxi) 00520 { 00521 if (pxi != NULL) { 00522 pxi->flags |= XIF_ABANDONED; 00523 } else { 00524 for (pxi = pcoi->pxiIn; pxi != NULL; pxi = pxi->next) { 00525 pxi->flags |= XIF_ABANDONED; 00526 } 00527 } 00528 } 00529 00530 00531 00532 BOOL AbandonEnumerateProc( 00533 HWND hwnd, 00534 LPARAM idTransaction) 00535 { 00536 PCONV_INFO pcoi; 00537 00538 pcoi = (PCONV_INFO)GetWindowLongPtr(hwnd, GWLP_PCI); 00539 if (!pcoi || !(pcoi->state & ST_CLIENT)) { 00540 return(TRUE); 00541 } 00542 while (pcoi) { 00543 AbandonTransaction(pcoi, (PXACT_INFO)idTransaction); 00544 pcoi = pcoi->next; 00545 } 00546 return(TRUE); 00547 } 00548 00549 00550 00551 /***************************************************************************\ 00552 * DdeAbandonTransaction (DDEML API) 00553 * 00554 * Description: 00555 * Cancels application interest in completing an asynchronous transaction. 00556 * 00557 * History: 00558 * 11-12-91 sanfords Created. 00559 \***************************************************************************/ 00560 BOOL DdeAbandonTransaction( 00561 DWORD idInst, 00562 HCONV hConv, 00563 DWORD idTransaction) 00564 { 00565 PCONV_INFO pcoi; 00566 PXACT_INFO pxi; 00567 PCL_INSTANCE_INFO pcii; 00568 BOOL fRet = FALSE; 00569 00570 EnterDDECrit; 00571 00572 pcii = ValidateInstance((HANDLE)LongToHandle( idInst )); 00573 00574 if (hConv == 0 && idTransaction == 0) { 00575 EnumChildWindows(pcii->hwndMother, AbandonEnumerateProc, 0); 00576 goto Exit; 00577 } 00578 if (idTransaction == 0) { 00579 idTransaction = QID_SYNC; 00580 } 00581 if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( idTransaction ), &pcoi, &pxi)) { 00582 goto Exit; 00583 } 00584 if (pcii == NULL || pcoi->pcii != pcii) { 00585 SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER); 00586 goto Exit; 00587 } 00588 AbandonTransaction(pcoi, pxi); 00589 fRet = TRUE; 00590 00591 Exit: 00592 LeaveDDECrit; 00593 return (fRet); 00594 } 00595 00596 00597 00598 00599 /***************************************************************************\ 00600 * UpdateLinkIfChanged 00601 * 00602 * Description: 00603 * Helper function for updating a link 00604 * 00605 * Returns: TRUE if pxi was used - ie fMustReallocPxi 00606 * 00607 * History: 00608 * 3-11-92 sanfords Created. 00609 * 8-24-92 sanfords added cLinksToGo 00610 \***************************************************************************/ 00611 BOOL UpdateLinkIfChanged( 00612 PADVISE_LINK paLink, 00613 PXACT_INFO pxi, 00614 PCONV_INFO pcoi, 00615 PADVISE_LINK paLinkLast, 00616 PBOOL pfSwapped, 00617 DWORD cLinksToGo) 00618 { 00619 ADVISE_LINK aLinkT; 00620 00621 CheckDDECritIn; 00622 00623 *pfSwapped = FALSE; 00624 if (paLink->state & ADVST_CHANGED && !(paLink->state & ADVST_WAITING)) { 00625 pxi->pfnResponse = SvRespAdviseDataAck; 00626 pxi->pcoi = pcoi; 00627 pxi->gaItem = LocalToGlobalAtom(paLink->laItem); // pxi copy 00628 pxi->wFmt = paLink->wFmt; 00629 pxi->wType = paLink->wType; 00630 paLink->state &= ~ADVST_CHANGED; 00631 if (SvStartAdviseUpdate(pxi, cLinksToGo)) { 00632 if (pxi->wType & DDE_FACKREQ) { 00633 paLink->state |= ADVST_WAITING; 00634 /* 00635 * swap paLink with the last non-moved link to make ack search find 00636 * oldest updated format. 00637 */ 00638 if (paLink != paLinkLast) { 00639 aLinkT = *paLink; 00640 RtlMoveMemory(paLink, paLink + 1, 00641 (PBYTE)paLinkLast - (PBYTE)paLink); 00642 *paLinkLast = aLinkT; 00643 *pfSwapped = TRUE; 00644 } 00645 } 00646 return(TRUE); 00647 } else { 00648 GlobalDeleteAtom(pxi->gaItem); // pxi copy 00649 return(FALSE); 00650 } 00651 } 00652 return(FALSE); 00653 } 00654 00655 00656 /***************************************************************************\ 00657 * DdePostAdvise (DDEML API) 00658 * 00659 * Description: 00660 * Updates outstanding server advise links as needed. 00661 * 00662 * History: 00663 * 11-12-91 sanfords Created. 00664 \***************************************************************************/ 00665 BOOL DdePostAdvise( 00666 DWORD idInst, 00667 HSZ hszTopic, 00668 HSZ hszItem) 00669 { 00670 PCL_INSTANCE_INFO pcii; 00671 PSVR_CONV_INFO psi; 00672 PXACT_INFO pxi; 00673 PADVISE_LINK paLink; 00674 BOOL fRet = FALSE, fSwapped, fFound; 00675 int iServer, iLink; 00676 PLINK_COUNT pLinkCount; 00677 #if DBG 00678 int cLinks; 00679 #endif 00680 00681 EnterDDECrit; 00682 00683 pcii = ValidateInstance((HANDLE)LongToHandle( idInst )); 00684 if (pcii == NULL) { 00685 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 00686 goto Exit; 00687 } 00688 if ((ValidateHSZ(hszTopic) == HSZT_INVALID) || 00689 (ValidateHSZ(hszItem) == HSZT_INVALID)) { 00690 SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); 00691 goto Exit; 00692 } 00693 00694 /* 00695 * Initialize all link counters and check if any links qualify 00696 */ 00697 fFound = FALSE; 00698 for (pLinkCount = pcii->pLinkCount; 00699 pLinkCount; pLinkCount = pLinkCount->next) { 00700 pLinkCount->Count = pLinkCount->Total; 00701 fFound |= pLinkCount->laTopic == LATOM_FROM_HSZ(hszTopic) && 00702 pLinkCount->laItem == LATOM_FROM_HSZ(hszItem); 00703 } 00704 if (!fFound && hszTopic && hszItem) { 00705 fRet = TRUE; 00706 goto Exit; 00707 } 00708 00709 /* 00710 * preallocate incase we are low on memory. 00711 */ 00712 pxi = DDEMLAlloc(sizeof(XACT_INFO)); 00713 if (pxi == NULL) { 00714 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00715 fRet = FALSE; 00716 goto Exit; 00717 } 00718 00719 /* 00720 * For each server window on the specified topic 00721 */ 00722 for (iServer = 0; iServer < pcii->cServerLookupAlloc; iServer++) { 00723 if (hszTopic == 0 || 00724 pcii->aServerLookup[iServer].laTopic == LATOM_FROM_HSZ(hszTopic)) { 00725 00726 /* 00727 * For each conversation within that window 00728 */ 00729 psi = (PSVR_CONV_INFO)GetWindowLongPtr( 00730 pcii->aServerLookup[iServer].hwndServer, GWLP_PSI); 00731 UserAssert(psi != NULL && psi->ci.pcii == pcii); // sanity check 00732 while (psi != NULL) { 00733 00734 00735 /* 00736 * UpdateLinkIfChanged might leave the critical section so lock this conversation 00737 */ 00738 psi->ci.cLocks++; 00739 00740 #if DBG 00741 /* 00742 * Rememeber the number of links so we can assert if they change during the loop below 00743 */ 00744 cLinks = psi->ci.cLinks; 00745 #endif 00746 /* 00747 * For each active link on the given item... 00748 */ 00749 for (paLink = psi->ci.aLinks, iLink = 0; 00750 iLink < psi->ci.cLinks; paLink++, iLink++) { 00751 if (hszItem == 0 || 00752 paLink->laItem == LATOM_FROM_HSZ(hszItem)) { 00753 00754 // Bit of a hack here. For FACKREQ links, we don't want the server to 00755 // outrun the client so we set the ADVST_WAITING bit till the ack is 00756 // received. When the ack comes in, the protocol code has to search 00757 // the aLinks array again to locate the apropriate link state flags and 00758 // clear the ADVST_WAITING flag. At that time, if the ADVST_CHANGED flag 00759 // is set, it is cleared and another SvStartAdviseUpdate transaction 00760 // is started to get the link up to date. To complicate matters, 00761 // the ACK contains no format information. Thus we need to move 00762 // the Link info to the end of the list so that the right format 00763 // is updated when the ack comes in. 00764 00765 paLink->state |= ADVST_CHANGED; 00766 if (UpdateLinkIfChanged(paLink, pxi, &psi->ci, 00767 &psi->ci.aLinks[psi->ci.cLinks - 1], 00768 &fSwapped, --paLink->pLinkCount->Count)) { 00769 if (fSwapped) { 00770 paLink--; 00771 } 00772 /* 00773 * preallocate for next advise 00774 */ 00775 pxi = DDEMLAlloc(sizeof(XACT_INFO)); 00776 if (pxi == NULL) { 00777 SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); 00778 /* 00779 * Unlock the conversation 00780 */ 00781 psi->ci.cLocks--; 00782 if ((psi->ci.cLocks == 0) && (psi->ci.state & ST_FREE_CONV_RES_NOW)) { 00783 RIPMSG1(RIP_ERROR, "DdePostAdvise: Conversation terminated. psi:%#p", psi); 00784 FreeConversationResources((PCONV_INFO)psi); 00785 } 00786 goto Exit; 00787 } 00788 } 00789 /* 00790 * We might have left the crit sect... 00791 */ 00792 UserAssert(pcii == ValidateInstance((HANDLE)LongToHandle( idInst ))); 00793 } 00794 } 00795 #if DBG 00796 if (cLinks != psi->ci.cLinks) { 00797 RIPMSG1(RIP_ERROR, "DdePostAdvise: cLinks changed. psi:%#p", psi); 00798 } 00799 #endif 00800 00801 /* 00802 * If the converstaion got nuked, stop working on this conversation chain. 00803 */ 00804 psi->ci.cLocks--; 00805 if ((psi->ci.cLocks == 0) && (psi->ci.state & ST_FREE_CONV_RES_NOW)) { 00806 RIPMSG1(RIP_ERROR, "DdePostAdvise: Conversation terminated. psi:%#p", psi); 00807 FreeConversationResources((PCONV_INFO)psi); 00808 break; 00809 } 00810 00811 psi = (PSVR_CONV_INFO)psi->ci.next; // next conversation 00812 } 00813 } 00814 } 00815 DDEMLFree(pxi); 00816 fRet = TRUE; 00817 00818 Exit: 00819 /* 00820 * Because callbacks are capable of blocking DdeUninitialize(), we check 00821 * before exit to see if it needs to be called. 00822 */ 00823 UserAssert(pcii == ValidateInstance((HANDLE)LongToHandle( idInst ))); 00824 if (pcii != NULL && 00825 pcii->afCmd & APPCMD_UNINIT_ASAP && 00826 !(pcii->flags & IIF_IN_SYNC_XACT) && 00827 !pcii->cInDDEMLCallback) { 00828 DdeUninitialize(HandleToUlong(pcii->hInstClient)); 00829 fRet = TRUE; 00830 } 00831 LeaveDDECrit; 00832 return (fRet); 00833 } 00834 00835 00836 /***************************************************************************\ 00837 * LinkTransaction 00838 * 00839 * Description: 00840 * Adds a transaction structure to the associated conversation's transaction 00841 * queue. 00842 * 00843 * History: 00844 * 11-12-91 sanfords Created. 00845 \***************************************************************************/ 00846 VOID LinkTransaction( 00847 PXACT_INFO pxi) 00848 { 00849 CheckDDECritIn; 00850 00851 pxi->next = NULL; 00852 if (pxi->pcoi->pxiOut == NULL) { 00853 pxi->pcoi->pxiIn = pxi->pcoi->pxiOut = pxi; 00854 } else { 00855 pxi->pcoi->pxiIn->next = pxi; 00856 pxi->pcoi->pxiIn = pxi; 00857 } 00858 #if DBG 00859 /* 00860 * Temporary check to find stress bug - make sure pxi list is not 00861 * looped on itself. If it is, this loop will never exit and things 00862 * will get investigated. (sanfords) 00863 */ 00864 { 00865 PXACT_INFO pxiT; 00866 00867 for (pxiT = pxi->pcoi->pxiOut; pxiT != NULL; pxiT = pxiT->next) { 00868 ; 00869 } 00870 } 00871 #endif // DBG 00872 } 00873 00874 00875 /***************************************************************************\ 00876 * UnlinkTransaction 00877 * 00878 * Description: 00879 * Removes a transaction structure from the associated conversation's transaction 00880 * queue. 00881 * 00882 * History: 00883 * 11-12-91 sanfords Created. 00884 \***************************************************************************/ 00885 VOID UnlinkTransaction( 00886 PXACT_INFO pxi) 00887 { 00888 CheckDDECritIn; 00889 if (pxi == pxi->pcoi->pxiOut) { 00890 pxi->pcoi->pxiOut = pxi->next; 00891 if (pxi->next == NULL) { 00892 pxi->pcoi->pxiIn = NULL; 00893 } 00894 } 00895 } 00896 00897 00898 /***************************************************************************\ 00899 * ValidateTransaction 00900 * 00901 * Description: 00902 * Common validation code for DDEML APIs that take a conversation handle 00903 * and a transaction ID. *ppxi may be null on return if hXact was 0. 00904 * Returns fSuccess. 00905 * 00906 * History: 00907 * 11-12-91 sanfords Created. 00908 \***************************************************************************/ 00909 BOOL ValidateTransaction( 00910 HCONV hConv, 00911 HANDLE hXact, 00912 PCONV_INFO *ppcoi, 00913 PXACT_INFO *ppxi) 00914 { 00915 PCL_INSTANCE_INFO pcii; 00916 00917 *ppcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, 00918 HTYPE_CLIENT_CONVERSATION, HINST_ANY); 00919 if (*ppcoi == NULL) { 00920 *ppcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, 00921 HTYPE_SERVER_CONVERSATION, HINST_ANY); 00922 } 00923 if (*ppcoi == NULL) { 00924 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 00925 return (FALSE); 00926 } 00927 pcii = ValidateInstance((*ppcoi)->pcii->hInstClient); 00928 if (pcii != (*ppcoi)->pcii) { 00929 BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); 00930 return (FALSE); 00931 } 00932 00933 if (hXact == (HANDLE)IntToPtr( QID_SYNC )) { 00934 *ppxi = NULL; 00935 } else { 00936 *ppxi = (PXACT_INFO)ValidateCHandle(hXact, HTYPE_TRANSACTION, 00937 InstFromHandle((*ppcoi)->pcii->hInstClient)); 00938 if (*ppxi == NULL) { 00939 SetLastDDEMLError((*ppcoi)->pcii, DMLERR_INVALIDPARAMETER); 00940 return (FALSE); 00941 } 00942 } 00943 return (TRUE); 00944 }

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