Source code of Windows XP (NT5)
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.

822 lines
26 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: STDPTCL.C
  3. *
  4. * This module contains functions that implement the standard DDE protocol
  5. *
  6. * Created: 4/2/91 Sanfords
  7. *
  8. * Copyright (c) 1991 Microsoft Corporation
  9. \***************************************************************************/
  10. #include <string.h>
  11. #include <memory.h>
  12. #include "ddemlp.h"
  13. VOID FreeDdeMsgData(
  14. WORD msg,
  15. LPARAM lParam)
  16. {
  17. WORD fmt;
  18. switch (msg) {
  19. case WM_DDE_DATA:
  20. case WM_DDE_POKE:
  21. /*
  22. * Only free if fRelease is set!
  23. */
  24. {
  25. DDEDATA FAR *pDdeData = (DDEDATA FAR *)GLOBALLOCK(LOWORD(lParam));
  26. if (pDdeData != NULL) {
  27. if (pDdeData->fRelease) {
  28. fmt = pDdeData->cfFormat;
  29. GlobalUnlock(LOWORD(lParam));
  30. FreeDDEData(LOWORD(lParam), fmt);
  31. } else {
  32. GlobalUnlock(LOWORD(lParam));
  33. }
  34. }
  35. }
  36. break;
  37. case WM_DDE_ADVISE:
  38. GLOBALFREE(LOWORD(lParam));
  39. break;
  40. case WM_DDE_EXECUTE:
  41. GLOBALFREE(HIWORD(lParam));
  42. break;
  43. }
  44. }
  45. /***************************** Private Function ****************************\
  46. * Processes a client transfer request issued by DdeClientTransaction
  47. * function. This may be synchronous or asynchronous.
  48. *
  49. * This function is responsible for properly filling in pXferInfo->pulResult.
  50. *
  51. * History:
  52. * Created 9/1/89 Sanfords
  53. \***************************************************************************/
  54. long ClientXferReq(
  55. PXFERINFO pXferInfo,
  56. HWND hwnd,
  57. PCLIENTINFO pci)
  58. {
  59. PCQDATA pcqd;
  60. LAP myLostAck;
  61. long retVal;
  62. if (pci->ci.xad.state != XST_CONNECTED) {
  63. SETLASTERROR(pci->ci.pai, DMLERR_SERVER_DIED);
  64. return(0);
  65. }
  66. if (pXferInfo->ulTimeout == TIMEOUT_ASYNC) {
  67. /*
  68. * Create a client async queue if needed.
  69. */
  70. if (pci->pQ == NULL)
  71. pci->pQ = CreateQ(sizeof(CQDATA));
  72. if (pci->pQ == NULL) {
  73. SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
  74. return(0);
  75. }
  76. /*
  77. * add a client queue item to track this transaction and return
  78. * the ID.
  79. */
  80. pcqd = (PCQDATA)Addqi(pci->pQ);
  81. if (pcqd == NULL) {
  82. SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
  83. return(0);
  84. }
  85. IncHszCount(LOWORD(pXferInfo->hszItem)); // structure copy
  86. hmemcpy((LPBYTE)&pcqd->XferInfo, (LPBYTE)pXferInfo, sizeof(XFERINFO));
  87. pcqd->xad.state = XST_CONNECTED;
  88. pcqd->xad.pdata = 0L;
  89. pcqd->xad.LastError = DMLERR_NO_ERROR;
  90. pcqd->xad.pXferInfo = &pcqd->XferInfo;
  91. pcqd->xad.DDEflags = 0;
  92. /*
  93. * point pulResult to a safe place
  94. */
  95. pcqd->XferInfo.pulResult = (LPDWORD)&pcqd->xad.DDEflags;
  96. /*
  97. * Get transaction started - if it fails, quit now.
  98. */
  99. if ((pcqd->xad.LastError = SendClientReq(pci->ci.pai, &pcqd->xad,
  100. (HWND)pci->ci.hConvPartner, hwnd)) == DMLERR_SERVER_DIED) {
  101. pci->ci.fs = pci->ci.fs & ~ST_CONNECTED;
  102. FreeHsz(LOWORD(pcqd->XferInfo.hszItem));
  103. Deleteqi(pci->pQ, MAKEID(pcqd));
  104. /*
  105. * RARE case of server dyeing in the middle of transaction
  106. * initiation.
  107. */
  108. SETLASTERROR(pci->ci.pai, DMLERR_SERVER_DIED);
  109. return(0);
  110. }
  111. if (pXferInfo->pulResult != NULL) {
  112. *pXferInfo->pulResult = MAKEID(pcqd);
  113. }
  114. return(1);
  115. }
  116. /*
  117. * Set this so messages comming in during the conversation know whats up
  118. */
  119. pci->ci.xad.pXferInfo = pXferInfo;
  120. if (SETLASTERROR(pci->ci.pai,
  121. SendClientReq(pci->ci.pai, &pci->ci.xad, (HWND)pci->ci.hConvPartner, hwnd)) ==
  122. DMLERR_SERVER_DIED) {
  123. return(0);
  124. }
  125. // HACK
  126. // If this is an EXEC and the timeout is 1 sec then this
  127. // is probably PC Tools 2.0 trying to add items to the shell so
  128. // crank up the timout.
  129. if ((pXferInfo->wType == XTYP_EXECUTE) && (pXferInfo->ulTimeout == 1*1000))
  130. {
  131. pXferInfo->ulTimeout = 10*1000;
  132. }
  133. timeout(pci->ci.pai, pXferInfo->ulTimeout, hwnd);
  134. retVal = ClientXferRespond(hwnd, &pci->ci.xad, &pci->ci.pai->LastError);
  135. switch (pci->ci.xad.state) {
  136. case XST_INCOMPLETE:
  137. /* now add a record of the ack we expect to eventually get
  138. * to the lost ack pile. When it arrives we'll know what to
  139. * free up -- either a memory handle or an atom.
  140. */
  141. myLostAck.type = pXferInfo->wType;
  142. if (pXferInfo->wType == XTYP_EXECUTE)
  143. myLostAck.object = HIWORD(pXferInfo->hDataClient);
  144. else
  145. myLostAck.object = LOWORD(pXferInfo->hszItem);
  146. AddPileItem(pLostAckPile, (LPBYTE)&myLostAck, NULL);
  147. pci->ci.xad.state = XST_CONNECTED;
  148. }
  149. if (pci->ci.fs & ST_DISC_ATTEMPTED) {
  150. /*
  151. * During this transaction a call to DdeDisconnect was attempted.
  152. * complete the call now.
  153. */
  154. Disconnect(hwnd, ST_PERM2DIE, pci);
  155. }
  156. return(retVal);
  157. }
  158. /***************************** Private Function ****************************\
  159. * This routine sends the apropriate initiation messages for starting a
  160. * client request according to the transaction data given.
  161. *
  162. * returns any appropriate DMLERR_
  163. *
  164. * History:
  165. * Created 9/1/89 Sanfords
  166. \***************************************************************************/
  167. WORD SendClientReq(
  168. PAPPINFO pai,
  169. PXADATA pXad,
  170. HWND hwndServer,
  171. HWND hwnd)
  172. {
  173. WORD fsStatus = 0;
  174. WORD msg;
  175. WORD lo, hi;
  176. HANDLE hData;
  177. hi = LOWORD(pXad->pXferInfo->hszItem); /* all but exec need this */
  178. switch (pXad->pXferInfo->wType) {
  179. case XTYP_REQUEST:
  180. msg = WM_DDE_REQUEST;
  181. IncHszCount(hi); // message copy
  182. #ifdef DEBUG
  183. cAtoms--; // don't count this
  184. #endif
  185. lo = pXad->pXferInfo->wFmt;
  186. pXad->state = XST_REQSENT;
  187. break;
  188. case XTYP_POKE:
  189. msg = WM_DDE_POKE;
  190. lo = HIWORD(pXad->pXferInfo->hDataClient);
  191. if (!LOWORD(pXad->pXferInfo->hDataClient & HDATA_APPOWNED))
  192. hData = lo; // need to free this on failed post.
  193. pXad->state = XST_POKESENT;
  194. XmitPrep(pXad->pXferInfo->hDataClient, pai);
  195. break;
  196. case XTYP_EXECUTE:
  197. msg = WM_DDE_EXECUTE;
  198. hi = HIWORD(pXad->pXferInfo->hDataClient);
  199. if (!LOWORD(pXad->pXferInfo->hDataClient & HDATA_APPOWNED))
  200. hData = hi; // need to free this on failed post.
  201. lo = 0;
  202. pXad->state = XST_EXECSENT;
  203. // we DONT XmitPrep() because we retain responsibility over the
  204. // data handle during the execute transaction regardless of
  205. // the server's response.
  206. // XmitPrep(pXad->pXferInfo->hDataClient, pai);
  207. break;
  208. case XTYP_ADVSTART:
  209. case XTYP_ADVSTART | XTYPF_NODATA:
  210. case XTYP_ADVSTART | XTYPF_ACKREQ:
  211. case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  212. fsStatus = DDE_FRELEASE | ((pXad->pXferInfo->wType &
  213. (XTYPF_ACKREQ | XTYPF_NODATA)) << 12);
  214. msg = WM_DDE_ADVISE;
  215. if ((hData = AllocDDESel(fsStatus, pXad->pXferInfo->wFmt,
  216. (DWORD)sizeof(DWORD))) == 0) {
  217. pXad->state = XST_CONNECTED;
  218. return(DMLERR_MEMORY_ERROR);
  219. }
  220. lo = hData;
  221. pXad->pXferInfo->hDataClient = (HDDEDATA)MAKELONG(0, hData);
  222. /* free later if we get nack */
  223. pXad->state = XST_ADVSENT;
  224. break;
  225. case XTYP_ADVSTOP:
  226. msg = WM_DDE_UNADVISE;
  227. lo = pXad->pXferInfo->wFmt;
  228. pXad->state = XST_UNADVSENT;
  229. break;
  230. default:
  231. return(DMLERR_INVALIDPARAMETER);
  232. break;
  233. }
  234. /*
  235. * Send transfer
  236. */
  237. if (IsWindow(hwndServer)) {
  238. PCLIENTINFO pci;
  239. pci = (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI);
  240. if (!PostDdeMessage(&pci->ci, msg, hwnd, MAKELONG(lo,hi), 0, 0)) {
  241. pXad->state = XST_CONNECTED;
  242. if (hData)
  243. FreeDDEData(hData, pXad->pXferInfo->wFmt);
  244. return(DMLERR_POSTMSG_FAILED);
  245. }
  246. } else {
  247. /*
  248. * We lost the server, we are TERMINATED arnold!
  249. */
  250. pXad->state = XST_NULL;
  251. if (hData)
  252. FreeDDEData(hData, pXad->pXferInfo->wFmt);
  253. return(DMLERR_SERVER_DIED);
  254. }
  255. return(DMLERR_NO_ERROR);
  256. }
  257. VOID ServerProcessDDEMsg(
  258. PSERVERINFO psi,
  259. WORD msg,
  260. HWND hwndServer,
  261. HWND hwndClient,
  262. WORD lo,
  263. WORD hi)
  264. {
  265. PADVLI pAdviseItem;
  266. WORD wType;
  267. DWORD dwData1 = 0;
  268. HDDEDATA hData = 0L;
  269. WORD wFmt = 0;
  270. WORD wStat = 0;
  271. LPSTR pMem;
  272. HANDLE hMemFree = 0;
  273. BOOL fQueueOnly = FALSE;
  274. /*
  275. * only respond if this is for us.
  276. */
  277. if (hwndClient != (HWND)psi->ci.hConvPartner)
  278. return;
  279. if (!(psi->ci.fs & ST_CONNECTED)) {
  280. /*
  281. * Dde messages have been received AFTER we have terminated. Free up
  282. * the information if appropriate.
  283. * BUG: This doesn't handle NACK freeing of associated data.
  284. */
  285. FreeDdeMsgData(msg, MAKELPARAM(lo, hi));
  286. }
  287. switch (msg) {
  288. case WM_DDE_REQUEST:
  289. wType = XTYP_REQUEST;
  290. wFmt = lo;
  291. break;
  292. case WM_DDE_EXECUTE:
  293. wType = XTYP_EXECUTE;
  294. /* stuff a special flag into the low word to mark as exec data */
  295. // We don't call RecvPrep() because we never have responsability for
  296. // freeing this data.
  297. hData = (HDDEDATA)MAKELONG(HDATA_EXEC | HDATA_NOAPPFREE | HDATA_READONLY, hi);
  298. break;
  299. case WM_DDE_POKE:
  300. wType = XTYP_POKE;
  301. pMem = GLOBALLOCK(lo);
  302. if (pMem == NULL) {
  303. SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
  304. return;
  305. }
  306. wFmt = ((DDEPOKE FAR*)pMem)->cfFormat;
  307. wStat = *(WORD FAR*)pMem;
  308. hData = RecvPrep(psi->ci.pai, lo, HDATA_NOAPPFREE);
  309. break;
  310. case WM_DDE_ADVISE:
  311. wType = XTYP_ADVSTART; /* set ST_ADVISE AFTER app oks advise loop */
  312. pMem = GLOBALLOCK(lo);
  313. if (pMem == NULL) {
  314. SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
  315. return;
  316. }
  317. wFmt = ((DDEADVISE FAR*)pMem)->cfFormat;
  318. wStat = *(WORD FAR*)pMem;
  319. // If this is NACKed, we don't free it (sicko protocol!#$@) so we
  320. // have to have this hang around till qreply gets it.
  321. hMemFree = lo;
  322. /*
  323. * Check if we already are linked on this topic/item/format. If so,
  324. * skip the callback.
  325. */
  326. fQueueOnly = (BOOL)(DWORD)FindAdvList(psi->ci.pai->pServerAdvList, hwndServer,
  327. psi->ci.aTopic, (ATOM)hi, wFmt);
  328. break;
  329. case WM_DDE_UNADVISE:
  330. {
  331. PADVLI padvli;
  332. ATOM aItem;
  333. if (padvli = FindAdvList(psi->ci.pai->pServerAdvList,
  334. hwndServer, 0, hi, lo)) {
  335. wFmt = padvli->wFmt;
  336. aItem = padvli->aItem;
  337. wType = XTYP_ADVSTOP;
  338. MONLINK(psi->ci.pai, FALSE, 0,
  339. (HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
  340. (HSZ)aItem, wFmt, TRUE,
  341. MAKEHCONV(hwndServer), psi->ci.hConvPartner);
  342. if (!DeleteAdvList(psi->ci.pai->pServerAdvList,
  343. hwndServer, 0, aItem, wFmt)) {
  344. psi->ci.fs &= ~ST_ADVISE;
  345. } else {
  346. while (padvli = FindAdvList(psi->ci.pai->pServerAdvList,
  347. hwndServer, 0, hi, lo)) {
  348. /*
  349. * simulate extra XTYP_ADVSTOP callbacks to server here
  350. */
  351. MONLINK(psi->ci.pai, FALSE, 0,
  352. (HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
  353. (HSZ)padvli->aItem, padvli->wFmt, TRUE,
  354. MAKEHCONV(hwndServer), psi->ci.hConvPartner);
  355. MakeCallback(&psi->ci, MAKEHCONV(hwndServer),
  356. (HSZ)psi->ci.aTopic,
  357. (HSZ)padvli->aItem, padvli->wFmt,
  358. XTYP_ADVSTOP, 0, 0, 0, msg, wStat,
  359. NULL, // signals qreply to NOT ack
  360. 0, FALSE);
  361. if (!DeleteAdvList(psi->ci.pai->pServerAdvList,
  362. hwndServer, 0, padvli->aItem, padvli->wFmt)) {
  363. psi->ci.fs &= ~ST_ADVISE;
  364. }
  365. }
  366. }
  367. MakeCallback(&psi->ci, MAKEHCONV(hwndServer), (HSZ)psi->ci.aTopic,
  368. (HSZ)aItem, wFmt, XTYP_ADVSTOP, 0, 0,
  369. (HSZ)hi, // item for ACK - see qreply
  370. msg, wStat, (HWND)psi->ci.hConvPartner, 0, FALSE);
  371. } else {
  372. /* unexpected unadvise, NACK it. */
  373. PostDdeMessage(&psi->ci, WM_DDE_ACK,
  374. hwndServer, MAKELONG(0, hi), 0, 0);
  375. return;
  376. }
  377. return;
  378. }
  379. case WM_DDE_ACK:
  380. /*
  381. * This is an ack in response to the FACKREQ bit being set.
  382. * See if this refers to one of the advise loops.
  383. */
  384. if ((pAdviseItem = FindAdvList(psi->ci.pai->pServerAdvList,
  385. hwndServer, 0, hi, wFmt)) &&
  386. (pAdviseItem->fsStatus & DDE_FACKREQ)) {
  387. /*
  388. * Update advise loop status - no longer waiting for an ack.
  389. */
  390. pAdviseItem->fsStatus &= ~ADVST_WAITING;
  391. if (pAdviseItem->fsStatus & ADVST_CHANGED) {
  392. PostServerAdvise(hwndServer, psi, pAdviseItem, CADV_LATEACK);
  393. }
  394. }
  395. if (hi)
  396. GlobalDeleteAtom(hi); // message copy
  397. // BUG: if a NACK is posted to us, WE need to free any data associated
  398. // with it.
  399. return;
  400. }
  401. MakeCallback(&psi->ci, MAKEHCONV(hwndServer), (HSZ)psi->ci.aTopic,
  402. /* don't know the item on an execute */
  403. wType == XTYP_EXECUTE ? 0L : MAKELONG(hi,0),
  404. wFmt, wType, hData, dwData1, 0, msg, wStat, (HWND)psi->ci.hConvPartner,
  405. hMemFree, fQueueOnly);
  406. /*
  407. * all freeing of atoms and hXXXX stuff is in QReply
  408. */
  409. return;
  410. }
  411. VOID PostServerAdvise(
  412. HWND hwnd,
  413. PSERVERINFO psi,
  414. PADVLI pali,
  415. WORD cLoops)
  416. {
  417. HDDEDATA hData;
  418. HANDLE hMem;
  419. /*
  420. * get the data from the server.
  421. */
  422. hData = DoCallback(psi->ci.pai, MAKEHCONV(hwnd), (HSZ)psi->ci.aTopic,
  423. (HSZ)pali->aItem, pali->wFmt, XTYP_ADVREQ, 0L,
  424. (DWORD)cLoops, 0L);
  425. if (!hData) {
  426. return;
  427. }
  428. hData = DllEntry(&psi->ci, hData);
  429. pali->fsStatus &= ~ADVST_CHANGED;
  430. /*
  431. * set Ack Request bit if advise loop calls for it.
  432. */
  433. if (pali->fsStatus & DDE_FACKREQ) {
  434. LPWORD lpFlags;
  435. pali->fsStatus |= ADVST_WAITING;
  436. lpFlags = (LPWORD)GLOBALPTR(HIWORD(hData));
  437. if (lpFlags == NULL) {
  438. SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
  439. return;
  440. }
  441. if (!(*lpFlags & DDE_FACKREQ)) {
  442. if (LOWORD(hData) & HDATA_APPOWNED) {
  443. // can't mess with it, must use a copy.
  444. hMem = HIWORD(hData);
  445. hData = CopyHDDEDATA(psi->ci.pai, hData);
  446. lpFlags = (LPWORD)GLOBALLOCK(HIWORD(hData));
  447. }
  448. *lpFlags |= DDE_FACKREQ;
  449. }
  450. }
  451. /*
  452. * remove local data handle from local list
  453. */
  454. FindPileItem(psi->ci.pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE);
  455. /*
  456. * post data to waiting client.
  457. */
  458. IncHszCount(pali->aItem); // message copy
  459. #ifdef DEBUG
  460. cAtoms--; // Don't count this because its being shipped out.
  461. #endif
  462. if (!PostDdeMessage(&psi->ci, WM_DDE_DATA, hwnd,
  463. MAKELONG(HIWORD(hData), pali->aItem), 0, 0)) {
  464. FreeDataHandle(psi->ci.pai, hData, TRUE);
  465. }
  466. }
  467. /***************************** Private Function ****************************\
  468. * This routine handles callback replys.
  469. * QReply is responsible for freeing any atoms or handles used
  470. * with the message that generated the callback.
  471. * It also must recover from dead partner windows.
  472. *
  473. * History:
  474. * Created 9/12/89 Sanfords
  475. \***************************************************************************/
  476. void QReply(
  477. PCBLI pcbi,
  478. HDDEDATA hDataRet)
  479. {
  480. PSERVERINFO psi;
  481. WORD fsStatus, msg;
  482. WORD loOut, StatusRet, msgAssoc = 0;
  483. HGLOBAL hGMemRet;
  484. HGLOBAL hAssoc = 0;
  485. SEMCHECKOUT();
  486. // most notification callbacks require no work here.
  487. if (((pcbi->wType & XCLASS_MASK) == XCLASS_NOTIFICATION) &&
  488. (pcbi->wType != XTYP_ADVSTOP) &&
  489. (pcbi->wType != XTYP_XACT_COMPLETE))
  490. return;
  491. StatusRet = LOWORD(hDataRet);
  492. hGMemRet = HIWORD(hDataRet);
  493. if (!IsWindow((HWND)pcbi->hConv)) {
  494. if (pcbi->wType & XCLASS_DATA && hDataRet && hDataRet != CBR_BLOCK) {
  495. FreeDataHandle(pcbi->pai, hDataRet, TRUE);
  496. }
  497. return;
  498. }
  499. psi = (PSERVERINFO)GetWindowLong((HWND)pcbi->hConv, GWL_PCI);
  500. switch (pcbi->msg) {
  501. case WM_DDE_REQUEST:
  502. if (hGMemRet) {
  503. hDataRet = DllEntry(&psi->ci, hDataRet);
  504. loOut = HIWORD(hDataRet);
  505. *(WORD FAR*)GLOBALLOCK(loOut) |=
  506. ((pcbi->fsStatus & DDE_FACKREQ) | DDE_FREQUESTED);
  507. GlobalUnlock(loOut);
  508. XmitPrep(hDataRet, psi->ci.pai);
  509. msg = WM_DDE_DATA;
  510. } else {
  511. /*
  512. * send a -ACK
  513. */
  514. loOut = (StatusRet & (DDE_FBUSY | DDE_FAPPSTATUS));
  515. msg = WM_DDE_ACK;
  516. }
  517. // reuse atom from request message
  518. if (!PostDdeMessage(&psi->ci, msg, (HWND)pcbi->hConv,
  519. MAKELONG(loOut, LOWORD(pcbi->hszItem)), 0, 0) && msg == WM_DDE_DATA)
  520. FreeDataHandle(psi->ci.pai, hDataRet, TRUE);
  521. break;
  522. case WM_DDE_POKE:
  523. if (StatusRet & DDE_FACK) {
  524. FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
  525. } else {
  526. // NACKS are properly freed by the 'poker'
  527. FindPileItem(psi->ci.pai->pHDataPile, CmpHIWORD,
  528. (LPBYTE)&pcbi->hData, FPI_DELETE);
  529. hAssoc = hGMemRet;
  530. msgAssoc = WM_DDE_POKE;
  531. }
  532. if (!PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
  533. MAKELONG(StatusRet & ~DDE_FACKRESERVED, LOWORD(pcbi->hszItem)),
  534. msgAssoc, hAssoc)) {
  535. if (!(StatusRet & DDE_FACK)) {
  536. FreeDDEData(hGMemRet, pcbi->wFmt);
  537. }
  538. }
  539. break;
  540. case WM_DDE_EXECUTE:
  541. /*
  542. * LOWORD(hDataRet) is supposed to be the proper DDE_ constants to return.
  543. * we just stick them in the given hData and return
  544. * it as an ACK.
  545. */
  546. PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
  547. MAKELONG(StatusRet & ~DDE_FACKRESERVED,HIWORD(pcbi->hData)),
  548. 0, 0);
  549. break;
  550. case WM_DDE_ADVISE:
  551. /*
  552. * hDataRet is fStartAdvise
  553. */
  554. if ((BOOL)hDataRet) {
  555. if (!AddAdvList(psi->ci.pai->pServerAdvList, (HWND)pcbi->hConv, psi->ci.aTopic,
  556. (ATOM)pcbi->hszItem,
  557. pcbi->fsStatus & (DDE_FDEFERUPD | DDE_FACKREQ),
  558. pcbi->wFmt)) {
  559. SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
  560. fsStatus = 0;
  561. } else {
  562. MONLINK(psi->ci.pai, TRUE, pcbi->fsStatus & DDE_FDEFERUPD,
  563. (HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
  564. pcbi->hszItem, pcbi->wFmt, TRUE,
  565. pcbi->hConv, psi->ci.hConvPartner);
  566. psi->ci.fs |= ST_ADVISE;
  567. fsStatus = DDE_FACK;
  568. }
  569. GlobalUnlock(pcbi->hMemFree);
  570. GLOBALFREE(pcbi->hMemFree); /* we free the hOptions on ACK */
  571. } else {
  572. fsStatus = 0;
  573. hAssoc = hGMemRet;
  574. msgAssoc = WM_DDE_ADVISE;
  575. #ifdef DEBUG
  576. if (pcbi->hMemFree) {
  577. LogDdeObject(0xF000, pcbi->hMemFree);
  578. }
  579. #endif
  580. }
  581. goto AckBack;
  582. break;
  583. case WM_DDE_UNADVISE:
  584. fsStatus = DDE_FACK;
  585. if (pcbi->hwndPartner) { // set to null for simulated stops due to WILD stuff
  586. // dwData2 == aItem to ack - this could have been wild.
  587. PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
  588. MAKELONG(fsStatus, LOWORD(pcbi->dwData2)), 0, 0);
  589. }
  590. break;
  591. case WM_DDE_DATA:
  592. /*
  593. * must be an advise data item for the CLIENT or maybe some requested
  594. * data mistakenly sent here due to the client queue being flushed.
  595. * hDataRet is fsStatus.
  596. */
  597. /*
  598. * Clean up the status incase the app is messed up.
  599. */
  600. fsStatus = StatusRet & ~DDE_FACKRESERVED;
  601. if (HIWORD(pcbi->hData) &&
  602. (pcbi->fsStatus & DDE_FRELEASE) &&
  603. (fsStatus & DDE_FACK || !(pcbi->fsStatus & DDE_FACKREQ)))
  604. FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
  605. if (fsStatus & DDE_FBUSY)
  606. fsStatus &= ~DDE_FACK;
  607. if (HIWORD(pcbi->hData) && !(fsStatus & DDE_FACK)) {
  608. msgAssoc = WM_DDE_DATA;
  609. hAssoc = HIWORD(pcbi->hData);
  610. }
  611. /*
  612. * send an ack back if requested.
  613. */
  614. if (pcbi->fsStatus & DDE_FACKREQ) {
  615. AckBack:
  616. PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
  617. MAKELONG(fsStatus, LOWORD(pcbi->hszItem)),
  618. msgAssoc, hAssoc);
  619. } else {
  620. if (LOWORD(pcbi->hszItem)) {
  621. GlobalDeleteAtom(LOWORD(pcbi->hszItem)); // data message copy
  622. }
  623. }
  624. break;
  625. case 0:
  626. switch (pcbi->wType) {
  627. case XTYP_XACT_COMPLETE:
  628. FreeHsz(LOWORD(pcbi->hszItem));
  629. FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
  630. Deleteqi(((PCLIENTINFO)psi)->pQ, pcbi->dwData1);
  631. }
  632. }
  633. }
  634. /***************************** Private Function ****************************\
  635. * This function assumes that a client transfer request has been completed -
  636. * or should be completed by the time this is called.
  637. *
  638. * pci contains general client info
  639. * pXad contains the transaction info
  640. * pErr points to where to place the LastError code.
  641. *
  642. * Returns 0 on failure
  643. * Returns TRUE or a Data Selector on success.
  644. * On failure, the conversation is left in a XST_INCOMPLETE state.
  645. * On success, the conversation is left in a XST_CONNECTED state.
  646. *
  647. * History:
  648. * Created 9/1/89 Sanfords
  649. \***************************************************************************/
  650. long ClientXferRespond(
  651. HWND hwndClient,
  652. PXADATA pXad,
  653. LPWORD pErr)
  654. {
  655. PCLIENTINFO pci;
  656. if (pXad->state == XST_INCOMPLETE)
  657. return(0);
  658. pci = (PCLIENTINFO)GetWindowLong(hwndClient, GWL_PCI);
  659. switch (pXad->pXferInfo->wType) {
  660. case XTYP_REQUEST:
  661. if (pXad->state != XST_DATARCVD) {
  662. if (*pErr == DMLERR_NO_ERROR)
  663. *pErr = DMLERR_DATAACKTIMEOUT;
  664. goto failexit;
  665. }
  666. pXad->state = XST_CONNECTED;
  667. return(pXad->pdata); /* this has the handle in low word */
  668. break;
  669. case XTYP_POKE:
  670. if (pXad->state != XST_POKEACKRCVD) {
  671. if (*pErr == DMLERR_NO_ERROR)
  672. *pErr = DMLERR_POKEACKTIMEOUT;
  673. goto failexit;
  674. }
  675. passexit:
  676. pXad->state = XST_CONNECTED;
  677. pXad->pdata = TRUE;
  678. return(TRUE);
  679. break;
  680. case XTYP_EXECUTE:
  681. if (pXad->state != XST_EXECACKRCVD) {
  682. if (*pErr == DMLERR_NO_ERROR)
  683. *pErr = DMLERR_EXECACKTIMEOUT;
  684. goto failexit;
  685. }
  686. goto passexit;
  687. case XTYP_ADVSTART:
  688. case XTYP_ADVSTART | XTYPF_NODATA:
  689. case XTYP_ADVSTART | XTYPF_ACKREQ:
  690. case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  691. if (pXad->state != XST_ADVACKRCVD) {
  692. if (*pErr == DMLERR_NO_ERROR)
  693. *pErr = DMLERR_ADVACKTIMEOUT;
  694. goto failexit;
  695. }
  696. AssertF((UINT)(XTYPF_ACKREQ << 12) == DDE_FACKREQ &&
  697. (UINT)(XTYPF_NODATA << 12) == DDE_FDEFERUPD,
  698. "XTYPF_ constants are wrong");
  699. if (!AddAdvList(pci->pClientAdvList, hwndClient, 0,
  700. LOWORD(pXad->pXferInfo->hszItem),
  701. (pXad->pXferInfo->wType & (XTYPF_ACKREQ | XTYPF_NODATA)) << 12,
  702. pXad->pXferInfo->wFmt)) {
  703. pXad->state = XST_INCOMPLETE;
  704. SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
  705. return(FALSE);
  706. } else {
  707. pci->ci.fs |= ST_ADVISE;
  708. MONLINK(pci->ci.pai, TRUE, pXad->pXferInfo->wType & XTYPF_NODATA,
  709. (HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic,
  710. pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt, FALSE,
  711. pci->ci.hConvPartner, MAKEHCONV(hwndClient));
  712. goto passexit;
  713. }
  714. break;
  715. case XTYP_ADVSTOP:
  716. if (pXad->state != XST_UNADVACKRCVD) {
  717. if (*pErr == DMLERR_NO_ERROR)
  718. *pErr = DMLERR_UNADVACKTIMEOUT;
  719. goto failexit;
  720. }
  721. if (!DeleteAdvList(pci->pClientAdvList, 0, 0,
  722. (ATOM)pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt))
  723. pci->ci.fs &= ~ST_ADVISE;
  724. MONLINK(pci->ci.pai, FALSE, pXad->pXferInfo->wType & XTYPF_NODATA,
  725. (HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic,
  726. pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt, FALSE,
  727. pci->ci.hConvPartner, MAKEHCONV(hwndClient));
  728. goto passexit;
  729. }
  730. failexit:
  731. pXad->state = XST_INCOMPLETE;
  732. return(0);
  733. }