Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

954 lines
29 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: xact.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * DDE Manager transaction processing module
  7. *
  8. * Created: 11/3/91 Sanford Staab
  9. \***************************************************************************/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. /***************************************************************************\
  13. * DdeClientTransaction (DDEML API)
  14. *
  15. * Description:
  16. * Initiates all DDE transactions.
  17. *
  18. * History:
  19. * 11-1-91 sanfords Created.
  20. \***************************************************************************/
  21. FUNCLOG8(LOG_GENERAL, HDDEDATA, DUMMYCALLINGTYPE, DdeClientTransaction, LPBYTE, pData, DWORD, cbData, HCONV, hConv, HSZ, hszItem, UINT, wFmt, UINT, wType, DWORD, ulTimeout, LPDWORD, pulResult)
  22. HDDEDATA DdeClientTransaction(
  23. LPBYTE pData,
  24. DWORD cbData,
  25. HCONV hConv,
  26. HSZ hszItem,
  27. UINT wFmt,
  28. UINT wType,
  29. DWORD ulTimeout,
  30. LPDWORD pulResult)
  31. {
  32. MSG msg;
  33. PCL_INSTANCE_INFO pcii = NULL;
  34. HDDEDATA hRet = 0;
  35. PCL_CONV_INFO pci;
  36. PDDEMLDATA pdd = NULL;
  37. PXACT_INFO pxi;
  38. BOOL fStarted;
  39. PDDE_DATA pdde;
  40. EnterDDECrit;
  41. pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConv,
  42. HTYPE_CLIENT_CONVERSATION, HINST_ANY);
  43. if (pci == NULL) {
  44. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  45. goto Exit;
  46. }
  47. pcii = pci->ci.pcii;
  48. if (ulTimeout != TIMEOUT_ASYNC && GetClientInfo()->CI_flags & CI_IN_SYNC_TRANSACTION) {
  49. SetLastDDEMLError(pcii, DMLERR_REENTRANCY);
  50. goto Exit;
  51. }
  52. if (!(pci->ci.state & ST_CONNECTED)) {
  53. SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED);
  54. goto Exit;
  55. }
  56. switch (wType) {
  57. case XTYP_POKE:
  58. case XTYP_ADVSTART:
  59. case XTYP_ADVSTART | XTYPF_NODATA:
  60. case XTYP_ADVSTART | XTYPF_ACKREQ:
  61. case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  62. case XTYP_REQUEST:
  63. case XTYP_ADVSTOP:
  64. if (hszItem == 0) {
  65. SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
  66. goto Exit;
  67. }
  68. break;
  69. case XTYP_EXECUTE: // just ignore wFmt & hszItem
  70. break;
  71. default:
  72. SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
  73. goto Exit;
  74. }
  75. pxi = DDEMLAlloc(sizeof(XACT_INFO));
  76. if (pxi == NULL) {
  77. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  78. goto Exit;
  79. }
  80. switch (wType) {
  81. case XTYP_EXECUTE:
  82. case XTYP_POKE:
  83. if ((LONG)cbData == -1L) {
  84. // We are accepting an existing data handle for export to another
  85. // app.
  86. pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)pData,
  87. HTYPE_DATA_HANDLE, HINST_ANY);
  88. if (pdd == NULL) {
  89. InvParam:
  90. SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
  91. DDEMLFree(pxi);
  92. goto Exit;
  93. }
  94. // make sure data handle holds apropriate data for this transaction
  95. if ((pdd->flags & HDATA_EXECUTE && wType != XTYP_EXECUTE) ||
  96. (!(pdd->flags & HDATA_EXECUTE) && wType == XTYP_EXECUTE)) {
  97. goto InvParam;
  98. }
  99. // To simplify life, use a copy if this handle is potentially
  100. // a relay or APPOWNED handle.
  101. if (pdd->flags & (HDATA_APPOWNED | HDATA_NOAPPFREE)) {
  102. pxi->hDDESent = CopyDDEData(pdd->hDDE, wType == XTYP_EXECUTE);
  103. if (!pxi->hDDESent) {
  104. MemErr:
  105. DDEMLFree(pxi);
  106. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  107. goto Exit;
  108. }
  109. USERGLOBALLOCK(pxi->hDDESent, pdde);
  110. if (pdde == NULL) {
  111. FreeDDEData(pxi->hDDESent, TRUE, TRUE);
  112. goto MemErr;
  113. }
  114. pdde->wStatus = DDE_FRELEASE;
  115. USERGLOBALUNLOCK(pxi->hDDESent);
  116. } else {
  117. pxi->hDDESent = pdd->hDDE;
  118. }
  119. // make sure handle has proper format
  120. if (wType == XTYP_POKE) {
  121. USERGLOBALLOCK(pxi->hDDESent, pdde);
  122. if (pdde == NULL) {
  123. goto InvParam;
  124. }
  125. pdde->wFmt = (WORD)wFmt;
  126. USERGLOBALUNLOCK(pxi->hDDESent);
  127. }
  128. } else { // Convert data in buffer into an apropriate hDDE
  129. if (wType == XTYP_POKE) {
  130. pxi->hDDESent = AllocAndSetDDEData(pData, cbData,
  131. DDE_FRELEASE, (WORD)wFmt);
  132. } else {
  133. pxi->hDDESent = AllocAndSetDDEData(pData, cbData, 0, 0);
  134. }
  135. if (!pxi->hDDESent) {
  136. goto MemErr;
  137. }
  138. }
  139. }
  140. // FINALLY - start the transaction
  141. pxi->pcoi = (PCONV_INFO)pci;
  142. pxi->gaItem = LocalToGlobalAtom(LATOM_FROM_HSZ(hszItem)); // pxi copy
  143. pxi->wFmt = (WORD)wFmt;
  144. pxi->wType = (WORD)wType;
  145. switch (wType) {
  146. case XTYP_ADVSTART:
  147. case XTYP_ADVSTART | XTYPF_NODATA:
  148. case XTYP_ADVSTART | XTYPF_ACKREQ:
  149. case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  150. fStarted = ClStartAdvise(pxi);
  151. break;
  152. case XTYP_ADVSTOP:
  153. fStarted = ClStartUnadvise(pxi);
  154. break;
  155. case XTYP_EXECUTE:
  156. fStarted = ClStartExecute(pxi);
  157. break;
  158. case XTYP_POKE:
  159. fStarted = ClStartPoke(pxi);
  160. break;
  161. case XTYP_REQUEST:
  162. fStarted = ClStartRequest(pxi);
  163. }
  164. if (!fStarted) {
  165. // if we copied or allocated data - free it.
  166. if (pxi->hDDESent && (pdd == NULL || pxi->hDDESent != pdd->hDDE)) {
  167. FreeDDEData(pxi->hDDESent, FALSE, TRUE); // free data copy
  168. }
  169. GlobalDeleteAtom(pxi->gaItem); // pxi copy
  170. DDEMLFree(pxi);
  171. goto Exit;
  172. }
  173. if (pdd != NULL && !(pdd->flags & (HDATA_NOAPPFREE | HDATA_APPOWNED))) {
  174. // invalidate given handle on success - unless we copied it because
  175. // the app will either be return ing it from a callback or potentially
  176. // using it again.
  177. DDEMLFree(pdd);
  178. DestroyHandle((HANDLE)pData);
  179. }
  180. if (ulTimeout == TIMEOUT_ASYNC) {
  181. // asynchronous transaction
  182. if (pulResult != NULL) {
  183. pxi->hXact = CreateHandle((ULONG_PTR)pxi, HTYPE_TRANSACTION,
  184. InstFromHandle(pcii->hInstClient));
  185. *pulResult = HandleToUlong(pxi->hXact);
  186. }
  187. hRet = (HDDEDATA)TRUE;
  188. } else {
  189. // synchronous transaction
  190. GetClientInfo()->CI_flags |= CI_IN_SYNC_TRANSACTION;
  191. pcii->flags |= IIF_IN_SYNC_XACT;
  192. pxi->flags |= XIF_SYNCHRONOUS;
  193. NtUserSetTimer(pci->ci.hwndConv, TID_TIMEOUT, ulTimeout, NULL);
  194. LeaveDDECrit;
  195. CheckDDECritOut;
  196. GetMessage(&msg, (HWND)NULL, 0, 0);
  197. /*
  198. * stay in modal loop until a timeout happens.
  199. */
  200. while (msg.hwnd != pci->ci.hwndConv || msg.message != WM_TIMER ||
  201. (msg.wParam != TID_TIMEOUT)) {
  202. if (!CallMsgFilter(&msg, MSGF_DDEMGR))
  203. DispatchMessage(&msg);
  204. GetMessage(&msg, (HWND)NULL, 0, 0);
  205. }
  206. EnterDDECrit;
  207. NtUserKillTimer(pci->ci.hwndConv, TID_TIMEOUT);
  208. GetClientInfo()->CI_flags &= ~CI_IN_SYNC_TRANSACTION;
  209. pcii->flags &= ~IIF_IN_SYNC_XACT;
  210. if (pxi->flags & XIF_COMPLETE) {
  211. if (pulResult != NULL) {
  212. *pulResult = pxi->wStatus; // NACK status bits
  213. }
  214. switch (wType) {
  215. case XTYP_ADVSTART:
  216. case XTYP_ADVSTART | XTYPF_NODATA:
  217. case XTYP_ADVSTART | XTYPF_ACKREQ:
  218. case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  219. case XTYP_ADVSTOP:
  220. case XTYP_EXECUTE:
  221. case XTYP_POKE:
  222. hRet = (HDDEDATA)((ULONG_PTR)((pxi->wStatus & DDE_FACK) ? TRUE : FALSE));
  223. if (!hRet) {
  224. if (pxi->wStatus & DDE_FBUSY) {
  225. SetLastDDEMLError(pcii, DMLERR_BUSY);
  226. } else {
  227. SetLastDDEMLError(pcii, DMLERR_NOTPROCESSED);
  228. }
  229. }
  230. break;
  231. case XTYP_REQUEST:
  232. if (pxi->hDDEResult == 0) {
  233. hRet = (HDDEDATA)((ULONG_PTR)((pxi->wStatus & DDE_FACK) ? TRUE : FALSE));
  234. if (!hRet) {
  235. if (pxi->wStatus & DDE_FBUSY) {
  236. SetLastDDEMLError(pcii, DMLERR_BUSY);
  237. } else {
  238. SetLastDDEMLError(pcii, DMLERR_NOTPROCESSED);
  239. }
  240. }
  241. break;
  242. }
  243. // Note that if the incoming data didn't have the DDE_FRELEASE
  244. // bit set, the transaction code would have made a copy so
  245. // the app is free to keep is as long as he likes.
  246. hRet = InternalCreateDataHandle(pcii, (LPBYTE)pxi->hDDEResult, (DWORD)-1, 0,
  247. HDATA_READONLY, 0, 0);
  248. pxi->hDDEResult = 0; // so cleanup doesn't free it.
  249. }
  250. (pxi->pfnResponse)((struct tagXACT_INFO *)pxi, 0, 0); // cleanup transaction
  251. } else { // Timed out
  252. // abandon the transaction and make it asyncronous so it will
  253. // clean itself up when the response finally comes in.
  254. pxi->flags &= ~XIF_SYNCHRONOUS;
  255. pxi->flags |= XIF_ABANDONED;
  256. switch (wType) {
  257. case XTYP_ADVSTART:
  258. case XTYP_ADVSTART | XTYPF_NODATA:
  259. case XTYP_ADVSTART | XTYPF_ACKREQ:
  260. case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  261. SetLastDDEMLError(pcii, DMLERR_ADVACKTIMEOUT);
  262. break;
  263. case XTYP_ADVSTOP:
  264. SetLastDDEMLError(pcii, DMLERR_UNADVACKTIMEOUT);
  265. break;
  266. case XTYP_EXECUTE:
  267. SetLastDDEMLError(pcii, DMLERR_EXECACKTIMEOUT);
  268. break;
  269. case XTYP_POKE:
  270. SetLastDDEMLError(pcii, DMLERR_POKEACKTIMEOUT);
  271. break;
  272. case XTYP_REQUEST:
  273. SetLastDDEMLError(pcii, DMLERR_DATAACKTIMEOUT);
  274. break;
  275. }
  276. // cleanup of pxi happens when transaction actually completes.
  277. }
  278. }
  279. if (pci->ci.state & ST_FREE_CONV_RES_NOW) {
  280. /*
  281. * The conversation was terminated during the synchronous transaction
  282. * so we need to clean up now that we are out of the loop.
  283. */
  284. FreeConversationResources((PCONV_INFO)pci);
  285. }
  286. Exit:
  287. /*
  288. * Because this API is capable of blocking DdeUninitialize(), we check
  289. * before exit to see if it needs to be called.
  290. */
  291. if (pcii != NULL &&
  292. (pcii->afCmd & APPCMD_UNINIT_ASAP) &&
  293. // !(pcii->flags & IIF_IN_SYNC_XACT) &&
  294. !pcii->cInDDEMLCallback) {
  295. DdeUninitialize(HandleToUlong(pcii->hInstClient));
  296. hRet = 0;
  297. }
  298. LeaveDDECrit;
  299. return (hRet);
  300. }
  301. /***************************************************************************\
  302. * GetConvContext
  303. *
  304. * Description:
  305. * Retrieves conversation context information from the DDEML client window
  306. * given. pl points to a CONVCONTEXT structure.
  307. *
  308. * History:
  309. * 11-12-91 sanfords Created.
  310. \***************************************************************************/
  311. VOID GetConvContext(
  312. HWND hwnd,
  313. LONG *pl)
  314. {
  315. int i;
  316. for (i = 0; i < sizeof(CONVCONTEXT); i += 4) {
  317. *pl++ = GetWindowLong(hwnd, GWL_CONVCONTEXT + i);
  318. }
  319. }
  320. /***************************************************************************\
  321. * SetConvContext
  322. *
  323. * Description:
  324. *
  325. * History:
  326. * 11-19-92 sanfords Created.
  327. \***************************************************************************/
  328. VOID SetConvContext(
  329. HWND hwnd,
  330. LONG *pl)
  331. {
  332. int i;
  333. for (i = 0; i < sizeof(CONVCONTEXT); i += 4) {
  334. SetWindowLong(hwnd, GWL_CONVCONTEXT + i, *pl++);
  335. }
  336. }
  337. /***************************************************************************\
  338. * DdeQueryConvInfo (DDEML API)
  339. *
  340. * Description:
  341. * Retrieves detailed conversation information on a per conversation/
  342. * transaction basis.
  343. *
  344. * History:
  345. * 11-12-91 sanfords Created.
  346. \***************************************************************************/
  347. FUNCLOG3(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, DdeQueryConvInfo, HCONV, hConv, DWORD, idTransaction, PCONVINFO, pConvInfo)
  348. UINT DdeQueryConvInfo(
  349. HCONV hConv,
  350. DWORD idTransaction,
  351. PCONVINFO pConvInfo)
  352. {
  353. PCONV_INFO pcoi;
  354. PXACT_INFO pxi;
  355. CONVINFO ci;
  356. UINT uiRet = 0;
  357. EnterDDECrit;
  358. if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( idTransaction ), &pcoi, &pxi)) {
  359. goto Exit;
  360. }
  361. try {
  362. if (pConvInfo->cb > sizeof(CONVINFO)) {
  363. SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER);
  364. goto Exit;
  365. }
  366. ci.cb = pConvInfo->cb;
  367. ci.hConvPartner = 0; // no longer supported.
  368. ci.hszSvcPartner = NORMAL_HSZ_FROM_LATOM(pcoi->laService);
  369. ci.hszServiceReq = NORMAL_HSZ_FROM_LATOM(pcoi->laServiceRequested);
  370. ci.hszTopic = NORMAL_HSZ_FROM_LATOM(pcoi->laTopic);
  371. ci.wStatus = pcoi->state;
  372. ci.wLastError = (WORD)pcoi->pcii->LastError;
  373. if (pcoi->state & ST_CLIENT) {
  374. ci.hConvList = ((PCL_CONV_INFO)pcoi)->hConvList;
  375. GetConvContext(pcoi->hwndConv, (LONG *)&ci.ConvCtxt);
  376. } else {
  377. ci.hConvList = 0;
  378. if (pcoi->state & ST_ISLOCAL) {
  379. GetConvContext(pcoi->hwndPartner, (LONG *)&ci.ConvCtxt);
  380. } else {
  381. ci.ConvCtxt = DefConvContext;
  382. }
  383. }
  384. if (pxi == NULL) {
  385. ci.hUser = pcoi->hUser;
  386. ci.hszItem = 0;
  387. ci.wFmt = 0;
  388. ci.wType = 0;
  389. ci.wConvst = XST_CONNECTED;
  390. } else {
  391. ci.hUser = pxi->hUser;
  392. // BUG - not fixable - This will result in extra local atoms
  393. // since we can never know when he is done with them.
  394. ci.hszItem = NORMAL_HSZ_FROM_LATOM(GlobalToLocalAtom(pxi->gaItem));
  395. ci.wFmt = pxi->wFmt;
  396. ci.wType = pxi->wType;
  397. ci.wConvst = pxi->state;
  398. }
  399. ci.hwnd = pcoi->hwndConv;
  400. ci.hwndPartner = pcoi->hwndPartner;
  401. RtlCopyMemory((LPSTR)pConvInfo, (LPSTR)&ci, pConvInfo->cb);
  402. } except(W32ExceptionHandler(FALSE, RIP_WARNING)) {
  403. SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER);
  404. goto Exit;
  405. }
  406. uiRet = TRUE;
  407. Exit:
  408. LeaveDDECrit;
  409. return (uiRet);
  410. }
  411. /***************************************************************************\
  412. * DdeSetUserHandle (DDEML API)
  413. *
  414. * Description:
  415. * Sets a user DWORD on a per conversation/transaction basis.
  416. *
  417. * History:
  418. * 11-12-91 sanfords Created.
  419. \***************************************************************************/
  420. FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeSetUserHandle, HCONV, hConv, DWORD, id, DWORD_PTR, hUser)
  421. BOOL DdeSetUserHandle(
  422. HCONV hConv,
  423. DWORD id,
  424. DWORD_PTR hUser)
  425. {
  426. PCONV_INFO pcoi;
  427. PXACT_INFO pxi;
  428. BOOL fRet = FALSE;
  429. EnterDDECrit;
  430. if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( id ), &pcoi, &pxi)) {
  431. goto Exit;
  432. }
  433. if (pxi == NULL) {
  434. pcoi->hUser = hUser;
  435. } else {
  436. pxi->hUser = hUser;
  437. }
  438. fRet = TRUE;
  439. Exit:
  440. LeaveDDECrit;
  441. return (fRet);
  442. }
  443. VOID AbandonTransaction(
  444. PCONV_INFO pcoi,
  445. PXACT_INFO pxi)
  446. {
  447. if (pxi != NULL) {
  448. pxi->flags |= XIF_ABANDONED;
  449. } else {
  450. for (pxi = pcoi->pxiIn; pxi != NULL; pxi = pxi->next) {
  451. pxi->flags |= XIF_ABANDONED;
  452. }
  453. }
  454. }
  455. BOOL AbandonEnumerateProc(
  456. HWND hwnd,
  457. LPARAM idTransaction)
  458. {
  459. PCONV_INFO pcoi;
  460. pcoi = (PCONV_INFO)GetWindowLongPtr(hwnd, GWLP_PCI);
  461. if (!pcoi || !(pcoi->state & ST_CLIENT)) {
  462. return(TRUE);
  463. }
  464. while (pcoi) {
  465. AbandonTransaction(pcoi, (PXACT_INFO)idTransaction);
  466. pcoi = pcoi->next;
  467. }
  468. return(TRUE);
  469. }
  470. /***************************************************************************\
  471. * DdeAbandonTransaction (DDEML API)
  472. *
  473. * Description:
  474. * Cancels application interest in completing an asynchronous transaction.
  475. *
  476. * History:
  477. * 11-12-91 sanfords Created.
  478. \***************************************************************************/
  479. FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeAbandonTransaction, DWORD, idInst, HCONV, hConv, DWORD, idTransaction)
  480. BOOL DdeAbandonTransaction(
  481. DWORD idInst,
  482. HCONV hConv,
  483. DWORD idTransaction)
  484. {
  485. PCONV_INFO pcoi;
  486. PXACT_INFO pxi;
  487. PCL_INSTANCE_INFO pcii;
  488. BOOL fRet = FALSE;
  489. EnterDDECrit;
  490. pcii = ValidateInstance((HANDLE)LongToHandle( idInst ));
  491. if (hConv == 0 && idTransaction == 0) {
  492. EnumChildWindows(pcii->hwndMother, AbandonEnumerateProc, 0);
  493. goto Exit;
  494. }
  495. if (idTransaction == 0) {
  496. idTransaction = QID_SYNC;
  497. }
  498. if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( idTransaction ), &pcoi, &pxi)) {
  499. goto Exit;
  500. }
  501. if (pcii == NULL || pcoi->pcii != pcii) {
  502. SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER);
  503. goto Exit;
  504. }
  505. AbandonTransaction(pcoi, pxi);
  506. fRet = TRUE;
  507. Exit:
  508. LeaveDDECrit;
  509. return (fRet);
  510. }
  511. /***************************************************************************\
  512. * UpdateLinkIfChanged
  513. *
  514. * Description:
  515. * Helper function for updating a link
  516. *
  517. * Returns: TRUE if pxi was used - ie fMustReallocPxi
  518. *
  519. * History:
  520. * 3-11-92 sanfords Created.
  521. * 8-24-92 sanfords added cLinksToGo
  522. \***************************************************************************/
  523. BOOL UpdateLinkIfChanged(
  524. PADVISE_LINK paLink,
  525. PXACT_INFO pxi,
  526. PCONV_INFO pcoi,
  527. PADVISE_LINK paLinkLast,
  528. PBOOL pfSwapped,
  529. DWORD cLinksToGo)
  530. {
  531. ADVISE_LINK aLinkT;
  532. CheckDDECritIn;
  533. *pfSwapped = FALSE;
  534. if (paLink->state & ADVST_CHANGED && !(paLink->state & ADVST_WAITING)) {
  535. pxi->pfnResponse = SvRespAdviseDataAck;
  536. pxi->pcoi = pcoi;
  537. pxi->gaItem = LocalToGlobalAtom(paLink->laItem); // pxi copy
  538. pxi->wFmt = paLink->wFmt;
  539. pxi->wType = paLink->wType;
  540. paLink->state &= ~ADVST_CHANGED;
  541. if (SvStartAdviseUpdate(pxi, cLinksToGo)) {
  542. if (pxi->wType & DDE_FACKREQ) {
  543. paLink->state |= ADVST_WAITING;
  544. /*
  545. * swap paLink with the last non-moved link to make ack search find
  546. * oldest updated format.
  547. */
  548. if (paLink != paLinkLast) {
  549. aLinkT = *paLink;
  550. RtlMoveMemory(paLink, paLink + 1,
  551. (PBYTE)paLinkLast - (PBYTE)paLink);
  552. *paLinkLast = aLinkT;
  553. *pfSwapped = TRUE;
  554. }
  555. }
  556. return(TRUE);
  557. } else {
  558. GlobalDeleteAtom(pxi->gaItem); // pxi copy
  559. return(FALSE);
  560. }
  561. }
  562. return(FALSE);
  563. }
  564. /***************************************************************************\
  565. * DdePostAdvise (DDEML API)
  566. *
  567. * Description:
  568. * Updates outstanding server advise links as needed.
  569. *
  570. * History:
  571. * 11-12-91 sanfords Created.
  572. \***************************************************************************/
  573. FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdePostAdvise, DWORD, idInst, HSZ, hszTopic, HSZ, hszItem)
  574. BOOL DdePostAdvise(
  575. DWORD idInst,
  576. HSZ hszTopic,
  577. HSZ hszItem)
  578. {
  579. PCL_INSTANCE_INFO pcii;
  580. PSVR_CONV_INFO psi;
  581. PXACT_INFO pxi;
  582. PADVISE_LINK paLink;
  583. BOOL fRet = FALSE, fSwapped, fFound;
  584. int iServer, iLink;
  585. PLINK_COUNT pLinkCount;
  586. #if DBG
  587. int cLinks;
  588. #endif
  589. EnterDDECrit;
  590. pcii = ValidateInstance((HANDLE)LongToHandle( idInst ));
  591. if (pcii == NULL) {
  592. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  593. goto Exit;
  594. }
  595. if ((ValidateHSZ(hszTopic) == HSZT_INVALID) ||
  596. (ValidateHSZ(hszItem) == HSZT_INVALID)) {
  597. SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
  598. goto Exit;
  599. }
  600. /*
  601. * Initialize all link counters and check if any links qualify
  602. */
  603. fFound = FALSE;
  604. for (pLinkCount = pcii->pLinkCount;
  605. pLinkCount; pLinkCount = pLinkCount->next) {
  606. pLinkCount->Count = pLinkCount->Total;
  607. fFound |= pLinkCount->laTopic == LATOM_FROM_HSZ(hszTopic) &&
  608. pLinkCount->laItem == LATOM_FROM_HSZ(hszItem);
  609. }
  610. if (!fFound && hszTopic && hszItem) {
  611. fRet = TRUE;
  612. goto Exit;
  613. }
  614. /*
  615. * preallocate incase we are low on memory.
  616. */
  617. pxi = DDEMLAlloc(sizeof(XACT_INFO));
  618. if (pxi == NULL) {
  619. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  620. fRet = FALSE;
  621. goto Exit;
  622. }
  623. /*
  624. * For each server window on the specified topic
  625. */
  626. for (iServer = 0; iServer < pcii->cServerLookupAlloc; iServer++) {
  627. if (hszTopic == 0 ||
  628. pcii->aServerLookup[iServer].laTopic == LATOM_FROM_HSZ(hszTopic)) {
  629. /*
  630. * For each conversation within that window
  631. */
  632. psi = (PSVR_CONV_INFO)GetWindowLongPtr(
  633. pcii->aServerLookup[iServer].hwndServer, GWLP_PSI);
  634. UserAssert(psi != NULL && psi->ci.pcii == pcii); // sanity check
  635. while (psi != NULL) {
  636. /*
  637. * UpdateLinkIfChanged might leave the critical section so lock this conversation
  638. */
  639. psi->ci.cLocks++;
  640. #if DBG
  641. /*
  642. * Rememeber the number of links so we can assert if they change during the loop below
  643. */
  644. cLinks = psi->ci.cLinks;
  645. #endif
  646. /*
  647. * For each active link on the given item...
  648. */
  649. for (paLink = psi->ci.aLinks, iLink = 0;
  650. iLink < psi->ci.cLinks; paLink++, iLink++) {
  651. if (hszItem == 0 ||
  652. paLink->laItem == LATOM_FROM_HSZ(hszItem)) {
  653. // Bit of a hack here. For FACKREQ links, we don't want the server to
  654. // outrun the client so we set the ADVST_WAITING bit till the ack is
  655. // received. When the ack comes in, the protocol code has to search
  656. // the aLinks array again to locate the apropriate link state flags and
  657. // clear the ADVST_WAITING flag. At that time, if the ADVST_CHANGED flag
  658. // is set, it is cleared and another SvStartAdviseUpdate transaction
  659. // is started to get the link up to date. To complicate matters,
  660. // the ACK contains no format information. Thus we need to move
  661. // the Link info to the end of the list so that the right format
  662. // is updated when the ack comes in.
  663. paLink->state |= ADVST_CHANGED;
  664. if (UpdateLinkIfChanged(paLink, pxi, &psi->ci,
  665. &psi->ci.aLinks[psi->ci.cLinks - 1],
  666. &fSwapped, --paLink->pLinkCount->Count)) {
  667. if (fSwapped) {
  668. paLink--;
  669. }
  670. /*
  671. * preallocate for next advise
  672. */
  673. pxi = DDEMLAlloc(sizeof(XACT_INFO));
  674. if (pxi == NULL) {
  675. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  676. /*
  677. * Unlock the conversation
  678. */
  679. psi->ci.cLocks--;
  680. if ((psi->ci.cLocks == 0) && (psi->ci.state & ST_FREE_CONV_RES_NOW)) {
  681. RIPMSG1(RIP_ERROR, "DdePostAdvise: Conversation terminated. psi:%#p", psi);
  682. FreeConversationResources((PCONV_INFO)psi);
  683. }
  684. goto Exit;
  685. }
  686. }
  687. /*
  688. * We might have left the crit sect...
  689. */
  690. UserAssert(pcii == ValidateInstance((HANDLE)LongToHandle( idInst )));
  691. }
  692. }
  693. #if DBG
  694. if (cLinks != psi->ci.cLinks) {
  695. RIPMSG1(RIP_ERROR, "DdePostAdvise: cLinks changed. psi:%#p", psi);
  696. }
  697. #endif
  698. /*
  699. * If the converstaion got nuked, stop working on this conversation chain.
  700. */
  701. psi->ci.cLocks--;
  702. if ((psi->ci.cLocks == 0) && (psi->ci.state & ST_FREE_CONV_RES_NOW)) {
  703. RIPMSG1(RIP_ERROR, "DdePostAdvise: Conversation terminated. psi:%#p", psi);
  704. FreeConversationResources((PCONV_INFO)psi);
  705. break;
  706. }
  707. psi = (PSVR_CONV_INFO)psi->ci.next; // next conversation
  708. }
  709. }
  710. }
  711. DDEMLFree(pxi);
  712. fRet = TRUE;
  713. Exit:
  714. /*
  715. * Because callbacks are capable of blocking DdeUninitialize(), we check
  716. * before exit to see if it needs to be called.
  717. */
  718. UserAssert(pcii == ValidateInstance((HANDLE)LongToHandle( idInst )));
  719. if (pcii != NULL &&
  720. pcii->afCmd & APPCMD_UNINIT_ASAP &&
  721. !(pcii->flags & IIF_IN_SYNC_XACT) &&
  722. !pcii->cInDDEMLCallback) {
  723. DdeUninitialize(HandleToUlong(pcii->hInstClient));
  724. fRet = TRUE;
  725. }
  726. LeaveDDECrit;
  727. return (fRet);
  728. }
  729. /***************************************************************************\
  730. * LinkTransaction
  731. *
  732. * Description:
  733. * Adds a transaction structure to the associated conversation's transaction
  734. * queue.
  735. *
  736. * History:
  737. * 11-12-91 sanfords Created.
  738. \***************************************************************************/
  739. VOID LinkTransaction(
  740. PXACT_INFO pxi)
  741. {
  742. CheckDDECritIn;
  743. pxi->next = NULL;
  744. if (pxi->pcoi->pxiOut == NULL) {
  745. pxi->pcoi->pxiIn = pxi->pcoi->pxiOut = pxi;
  746. } else {
  747. pxi->pcoi->pxiIn->next = pxi;
  748. pxi->pcoi->pxiIn = pxi;
  749. }
  750. #if DBG
  751. /*
  752. * Temporary check to find stress bug - make sure pxi list is not
  753. * looped on itself. If it is, this loop will never exit and things
  754. * will get investigated. (sanfords)
  755. */
  756. {
  757. PXACT_INFO pxiT;
  758. for (pxiT = pxi->pcoi->pxiOut; pxiT != NULL; pxiT = pxiT->next) {
  759. ;
  760. }
  761. }
  762. #endif // DBG
  763. }
  764. /***************************************************************************\
  765. * UnlinkTransaction
  766. *
  767. * Description:
  768. * Removes a transaction structure from the associated conversation's transaction
  769. * queue.
  770. *
  771. * History:
  772. * 11-12-91 sanfords Created.
  773. \***************************************************************************/
  774. VOID UnlinkTransaction(
  775. PXACT_INFO pxi)
  776. {
  777. CheckDDECritIn;
  778. if (pxi == pxi->pcoi->pxiOut) {
  779. pxi->pcoi->pxiOut = pxi->next;
  780. if (pxi->next == NULL) {
  781. pxi->pcoi->pxiIn = NULL;
  782. }
  783. }
  784. }
  785. /***************************************************************************\
  786. * ValidateTransaction
  787. *
  788. * Description:
  789. * Common validation code for DDEML APIs that take a conversation handle
  790. * and a transaction ID. *ppxi may be null on return if hXact was 0.
  791. * Returns fSuccess.
  792. *
  793. * History:
  794. * 11-12-91 sanfords Created.
  795. \***************************************************************************/
  796. BOOL ValidateTransaction(
  797. HCONV hConv,
  798. HANDLE hXact,
  799. PCONV_INFO *ppcoi,
  800. PXACT_INFO *ppxi)
  801. {
  802. PCL_INSTANCE_INFO pcii;
  803. *ppcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv,
  804. HTYPE_CLIENT_CONVERSATION, HINST_ANY);
  805. if (*ppcoi == NULL) {
  806. *ppcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv,
  807. HTYPE_SERVER_CONVERSATION, HINST_ANY);
  808. }
  809. if (*ppcoi == NULL) {
  810. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  811. return (FALSE);
  812. }
  813. pcii = ValidateInstance((*ppcoi)->pcii->hInstClient);
  814. if (pcii != (*ppcoi)->pcii) {
  815. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  816. return (FALSE);
  817. }
  818. if (hXact == (HANDLE)IntToPtr( QID_SYNC )) {
  819. *ppxi = NULL;
  820. } else {
  821. *ppxi = (PXACT_INFO)ValidateCHandle(hXact, HTYPE_TRANSACTION,
  822. InstFromHandle((*ppcoi)->pcii->hInstClient));
  823. if (*ppxi == NULL) {
  824. SetLastDDEMLError((*ppcoi)->pcii, DMLERR_INVALIDPARAMETER);
  825. return (FALSE);
  826. }
  827. }
  828. return (TRUE);
  829. }