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.

2539 lines
76 KiB

  1. /****************************** Module Header *******************************
  2. * Module Name: ddetrack.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module handles tracking of DDE conversations for use in emulating
  7. * DDE shared memory.
  8. *
  9. * History:
  10. * 9-3-91 sanfords Created
  11. * 21-Jan-1992 IanJa ANSI/Unicode netralized (null op)
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. PPUBOBJ gpPublicObjectList;
  16. #define TRACE_DDE(str) TAGMSG0(DBGTAG_DDE, str)
  17. #define TRACE_DDE1(s, a) TAGMSG1(DBGTAG_DDE, (s), (a))
  18. #define TRACE_DDE2(s, a, b) TAGMSG2(DBGTAG_DDE, (s), (a), (b))
  19. #define TRACE_DDE3(s, a, b, c) TAGMSG3(DBGTAG_DDE, (s), (a), (b), (c))
  20. BOOL NewConversation(PDDECONV *ppdcNewClient, PDDECONV *ppdcNewServer,
  21. PWND pwndClient, PWND pwndServer);
  22. PDDECONV FindDdeConv(PWND pwndProp, PWND pwndPartner);
  23. BOOL AddConvProp(PWND pwndUs, PWND pwndThem, DWORD flags, PDDECONV pdcNew,
  24. PDDECONV pdcPartner);
  25. FNDDERESPONSE xxxUnexpectedServerPost;
  26. FNDDERESPONSE xxxUnexpectedClientPost;
  27. FNDDERESPONSE xxxAdvise;
  28. FNDDERESPONSE xxxAdviseAck;
  29. FNDDERESPONSE xxxAdviseData;
  30. FNDDERESPONSE xxxAdviseDataAck;
  31. DWORD Unadvise(PDDECONV pDdeConv);
  32. FNDDERESPONSE xxxUnadviseAck;
  33. DWORD Request(PDDECONV pDdeConv);
  34. FNDDERESPONSE xxxRequestAck;
  35. FNDDERESPONSE xxxPoke;
  36. FNDDERESPONSE xxxPokeAck;
  37. FNDDERESPONSE xxxExecute;
  38. FNDDERESPONSE xxxExecuteAck;
  39. DWORD SpontaneousTerminate(PDWORD pmessage, PDDECONV pDdeConv);
  40. FNDDERESPONSE DupConvTerminate;
  41. HANDLE AnticipatePost(PDDECONV pDdeConv, FNDDERESPONSE fnResponse,
  42. HANDLE hClient, HANDLE hServer, PINTDDEINFO pIntDdeInfo, DWORD flags);
  43. PXSTATE Createpxs(FNDDERESPONSE fnResponse, HANDLE hClient, HANDLE hServer,
  44. PINTDDEINFO pIntDdeInfo, DWORD flags);
  45. DWORD AbnormalDDEPost(PDDECONV pDdeConv, DWORD message);
  46. DWORD xxxCopyDdeIn(HANDLE hSrc, PDWORD pflags, PHANDLE phDirect, PINTDDEINFO *ppi);
  47. DWORD xxxCopyAckIn(PDWORD pmessage, LPARAM *plParam, PDDECONV pDdeConv, PINTDDEINFO *ppIntDdeInfo);
  48. HANDLE xxxCopyDDEOut(PINTDDEINFO pIntDdeInfo, PHANDLE phDirect);
  49. BOOL FreeListAdd(PDDECONV pDdeConv, HANDLE hClient, DWORD flags);
  50. VOID xxxFreeListFree(PFREELIST pfl);
  51. VOID PopState(PDDECONV pDdeConv);
  52. PDDECONV UnlinkConv(PDDECONV pDdeConv);
  53. VOID FreeDDEHandle(PDDECONV pDdeConv, HANDLE hClient, DWORD flags);
  54. DWORD ClientFreeDDEHandle(HANDLE hClient, DWORD flags);
  55. DWORD ClientGetDDEFlags(HANDLE hClient, DWORD flags);
  56. DWORD xxxClientCopyDDEIn1(HANDLE hClient, DWORD flags, PINTDDEINFO *ppi);
  57. HANDLE xxxClientCopyDDEOut1(PINTDDEINFO pIntDdeInfo);
  58. DWORD xxxClientCopyDDEOut2(PINTDDEINFO pIntDdeInfo);
  59. PPUBOBJ IsObjectPublic(HANDLE hObj);
  60. BOOL AddPublicObject(UINT format, HANDLE hObj, W32PID pid);
  61. BOOL RemovePublicObject(UINT format, HANDLE hObj);
  62. BOOL GiveObject(UINT format, HANDLE hObj, W32PID pid);
  63. /*
  64. * The Big Picture:
  65. *
  66. * When a WM_DDE_ACK message is SENT, it implies the begining of a DDE
  67. * Conversation. The tracking layer creates DDECONV structure for each
  68. * window in volved in the conversation and cross links the structures.
  69. * Thus a unique window pair identifies a conversation. Each window has
  70. * its DDECONV structure attached to it via a private property.
  71. *
  72. * As DDE messages are posted, the tracking layer copies data into the
  73. * CSR server side of USER into a INTDDEINFO structure. This structure
  74. * contains flags which direct how the data is to be freed when the
  75. * time comes. This info is placed within an XSTATE structure along
  76. * with context infomation. A pointer to the XSTATE structure is
  77. * placed in the lParam of the message and the MSB of message is set
  78. * for special processing when the message is recieved on the other side.
  79. *
  80. * If the message posted requires a responding message to follow the DDE
  81. * protocol, a XSTATE structure is created and attached to DDECONV
  82. * structure associated with the window that is expected to post the message.
  83. * The XSTATE structure directs the tracking layer so that it knows the
  84. * context of the message when it is posted and also includes any
  85. * information needed for proper freeing of extra DDE data.
  86. *
  87. * When the message is extracted from the queue either by a hook, peek,
  88. * or by GetMessage, the id is checked to see if it lies in the special
  89. * range. If so, the XSTATE structure pointed to by the lParam is
  90. * operated on. This causes the data to be copied from the CSR server
  91. * side of USER to the target process context. Once this is done, the
  92. * XSTATE structure may or may not be freed depending on flags and
  93. * the message is restored to a proper DDE message form ready to be
  94. * used by the target process. Since the message id is changed back,
  95. * subsequent peeks or hooks to the message will not result in duplicated
  96. * processing of the message.
  97. *
  98. * During the course of come transactions it becomes evident that an object
  99. * on the opposite side process needs to be freed. This is done
  100. * asynchronously by inserting the object that needs freeing along with
  101. * associated flags into a freeing list which is tied to the DDECONV
  102. * structure associated with the window on the opposite side. Whenever
  103. * a DDE messages is posted, this freeing list is checked and processed.
  104. *
  105. * When a WM_DDE_TERMINATE message is finally recieved, flags are set
  106. * in the DDECONV structure indicating that the conversation is terminating.
  107. * This alters the way the mapping layer handles DDE messages posted.
  108. * When the responding side posts a WM_DDE_TERMINATE, the DDECONV structures
  109. * and all associated information is freed and unlinked from the windows
  110. * concerned.
  111. *
  112. * Should a DDE window get destroyed before proper termination, the
  113. * xxxDDETrackWindowDying function is called to make sure proper termination
  114. * is done prior to the window being destroyed.
  115. */
  116. /************************************************************************
  117. * xxxDDETrackSendHook
  118. *
  119. * Called when a DDE message is passed to SendMessage().
  120. *
  121. * Returns fSendOk.
  122. *
  123. * History:
  124. * 9-3-91 sanfords Created
  125. \***********************************************************************/
  126. BOOL xxxDDETrackSendHook(
  127. PWND pwndTo,
  128. DWORD message,
  129. WPARAM wParam,
  130. LPARAM lParam)
  131. {
  132. PWND pwndServer;
  133. PDDECONV pdcNewClient, pdcNewServer;
  134. if (MonitorFlags & MF_SENDMSGS) {
  135. DDEML_MSG_HOOK_DATA dmhd;
  136. dmhd.cbData = 0; // Initiate and Ack sent messages have no data.
  137. dmhd.uiLo = LOWORD(lParam); // they arn't packed either.
  138. dmhd.uiHi = HIWORD(lParam);
  139. xxxMessageEvent(pwndTo, message, wParam, lParam, MF_SENDMSGS, &dmhd);
  140. }
  141. if (PtiCurrent()->ppi == GETPWNDPPI(pwndTo)) {
  142. /*
  143. * Skip monitoring of all intra-process conversations.
  144. */
  145. return TRUE;
  146. }
  147. if (message != WM_DDE_ACK) {
  148. if (message == WM_DDE_INITIATE) {
  149. return TRUE; // this is cool
  150. }
  151. return FALSE;
  152. }
  153. pwndServer = ValidateHwnd((HWND)wParam);
  154. if (pwndServer == NULL) {
  155. return FALSE;
  156. }
  157. pdcNewServer = FindDdeConv(pwndServer, pwndTo);
  158. if (pdcNewServer != NULL) {
  159. RIPMSG2(RIP_WARNING,
  160. "DDE protocol violation - non-unique window pair (%#p:%#p)",
  161. PtoH(pwndTo), PtoH(pwndServer));
  162. /*
  163. * Duplicate Conversation case:
  164. * Don't allow the ACK to pass, post a terminate to the server
  165. * to shut down the duplicate on his end.
  166. */
  167. AnticipatePost(pdcNewServer, DupConvTerminate, NULL, NULL, NULL, 0);
  168. _PostMessage(pwndServer, WM_DDE_TERMINATE, (WPARAM)PtoH(pwndTo), 0);
  169. return FALSE;
  170. }
  171. if (!NewConversation(&pdcNewClient, &pdcNewServer, pwndTo, pwndServer)) {
  172. return FALSE;
  173. }
  174. TRACE_DDE2("%#p->%#p DDE Conversation started", PtoH(pwndTo), wParam);
  175. return TRUE;
  176. }
  177. /************************************************************************
  178. * AddConvProp
  179. *
  180. * Helper for xxxDDETrackSendHook - associates a new DDECONV struct with
  181. * a window and initializes it.
  182. *
  183. * History:
  184. * 9-3-91 sanfords Created
  185. \***********************************************************************/
  186. BOOL AddConvProp(
  187. PWND pwndUs,
  188. PWND pwndThem,
  189. DWORD flags,
  190. PDDECONV pdcNew,
  191. PDDECONV pdcPartner)
  192. {
  193. PDDECONV pDdeConv;
  194. PDDEIMP pddei;
  195. pDdeConv = (PDDECONV)_GetProp(pwndUs, PROP_DDETRACK, PROPF_INTERNAL);
  196. Lock(&(pdcNew->snext), pDdeConv);
  197. Lock(&(pdcNew->spwnd), pwndUs);
  198. Lock(&(pdcNew->spwndPartner), pwndThem);
  199. /*
  200. * Assert to catch stress bug.
  201. */
  202. UserAssert(pdcPartner != (PDDECONV)(-1));
  203. Lock(&(pdcNew->spartnerConv), pdcPartner);
  204. pdcNew->spxsIn = NULL;
  205. pdcNew->spxsOut = NULL;
  206. pdcNew->flags = flags;
  207. pddei = (PDDEIMP)_GetProp((flags & CXF_IS_SERVER) ?
  208. pwndThem : pwndUs, PROP_DDEIMP, PROPF_INTERNAL);
  209. if (pddei != NULL) { // This can be NULL if a bad WOW app has been
  210. pddei->cRefConv++; // allowed through for compatability.
  211. }
  212. pdcNew->pddei = pddei;
  213. HMLockObject(pdcNew); // lock for property
  214. InternalSetProp(pwndUs, PROP_DDETRACK, pdcNew, PROPF_INTERNAL);
  215. return TRUE;
  216. }
  217. /************************************************************************
  218. * UnlinkConv
  219. *
  220. * Unlinks a DDECONV structure from the property list it is associated with.
  221. *
  222. * returns pDdeConv->snext
  223. *
  224. * History:
  225. * 9-3-91 sanfords Created
  226. \***********************************************************************/
  227. PDDECONV UnlinkConv(
  228. PDDECONV pDdeConv)
  229. {
  230. PDDECONV pdcPrev, pdcT, pDdeConvNext;
  231. /*
  232. * Already unlinked
  233. */
  234. if (pDdeConv->spwnd == NULL) {
  235. return NULL;
  236. }
  237. TRACE_DDE1("UnlinkConv(%#p)", pDdeConv);
  238. pdcT = (PDDECONV)_GetProp(pDdeConv->spwnd,
  239. PROP_DDETRACK, PROPF_INTERNAL);
  240. if (pdcT == NULL) {
  241. return NULL; // already unlinked
  242. }
  243. pdcPrev = NULL;
  244. while (pdcT != pDdeConv) {
  245. pdcPrev = pdcT;
  246. pdcT = pdcT->snext;
  247. if (pdcT == NULL) {
  248. return NULL; // already unlinked
  249. }
  250. }
  251. if (pdcPrev == NULL) {
  252. if (pDdeConv->snext == NULL) {
  253. // last one out removes the property
  254. InternalRemoveProp(pDdeConv->spwnd, PROP_DDETRACK, PROPF_INTERNAL);
  255. } else {
  256. // head conv unlinked - update prop
  257. InternalSetProp(pDdeConv->spwnd, PROP_DDETRACK, pDdeConv->snext,
  258. PROPF_INTERNAL);
  259. }
  260. } else {
  261. Lock(&(pdcPrev->snext), pDdeConv->snext);
  262. }
  263. pDdeConvNext = Unlock(&(pDdeConv->snext));
  264. HMUnlockObject(pDdeConv); // unlock for property detachment
  265. return pDdeConvNext;
  266. }
  267. /************************************************************************
  268. * xxxDDETrackPostHook
  269. *
  270. * Hook function for handling posted DDE messages.
  271. *
  272. * returns post action code - DO_POST, FAKE_POST, FAIL_POST.
  273. *
  274. * History:
  275. * 9-3-91 sanfords Created
  276. \***********************************************************************/
  277. DWORD xxxDDETrackPostHook(
  278. PUINT pmessage,
  279. PWND pwndTo,
  280. WPARAM wParam,
  281. LPARAM *plParam,
  282. BOOL fSent)
  283. {
  284. PWND pwndFrom;
  285. PDDECONV pDdeConv = NULL;
  286. DWORD dwRet;
  287. TL tlpDdeConv;
  288. PFREELIST pfl, *ppfl;
  289. DWORD MFlag;
  290. CheckLock(pwndTo);
  291. MFlag = fSent ? MF_SENDMSGS : MF_POSTMSGS;
  292. if (MonitorFlags & MFlag) {
  293. DDEML_MSG_HOOK_DATA dmhd;
  294. switch (*pmessage ) {
  295. case WM_DDE_DATA:
  296. case WM_DDE_POKE:
  297. case WM_DDE_ADVISE:
  298. case WM_DDE_EXECUTE:
  299. case WM_DDE_ACK:
  300. ClientGetDDEHookData(*pmessage, *plParam, &dmhd);
  301. break;
  302. default:
  303. // WM_DDE_REQUEST
  304. // WM_DDE_TERMINATE
  305. // WM_DDE_UNADVISE
  306. dmhd.cbData = 0;
  307. dmhd.uiLo = LOWORD(*plParam);
  308. dmhd.uiHi = HIWORD(*plParam);
  309. }
  310. xxxMessageEvent(pwndTo, *pmessage, wParam, *plParam, MFlag,
  311. &dmhd);
  312. }
  313. if (PtiCurrent()->ppi == GETPWNDPPI(pwndTo)) {
  314. /*
  315. * skip all intra-process conversation tracking.
  316. */
  317. dwRet = DO_POST;
  318. goto Exit;
  319. }
  320. if (*pmessage == WM_DDE_INITIATE) {
  321. RIPMSG2(RIP_WARNING,
  322. "DDE Post failed (%#p:%#p) - WM_DDE_INITIATE posted",
  323. wParam, PtoH(pwndTo));
  324. dwRet = FAIL_POST;
  325. goto Exit;
  326. }
  327. pwndFrom = ValidateHwnd((HWND)wParam);
  328. if (pwndFrom == NULL) {
  329. /*
  330. * This is a post AFTER a window has been destroyed. This is not
  331. * expected except in the case where xxxDdeTrackWindowDying()
  332. * is posting a cleanup terminate.
  333. */
  334. dwRet = *pmessage == WM_DDE_TERMINATE ? DO_POST : FAKE_POST;
  335. goto Exit;
  336. }
  337. /*
  338. * locate conversation info.
  339. */
  340. pDdeConv = FindDdeConv(pwndFrom, pwndTo);
  341. if (pDdeConv == NULL) {
  342. if (*pmessage != WM_DDE_TERMINATE &&
  343. (GETPTI(pwndFrom)->TIF_flags & TIF_16BIT) &&
  344. (pwndTo->head.rpdesk == pwndFrom->head.rpdesk)) {
  345. /*
  346. * If a WOW app bypasses initiates and posts directly to
  347. * a window on the same desktop, let it sneak by here.
  348. *
  349. * This allows some evil apps such as OpenEngine and CA-Cricket
  350. * to get away with murder.
  351. *
  352. * TERMINATES out of the blue however may be due to an app
  353. * posting its WM_DDE_TERMINATE after it has destroyed its
  354. * window. Since window destruction would have generated the
  355. * TERMINATE already, don't let it through here.
  356. */
  357. NewConversation(&pDdeConv, NULL, pwndFrom, pwndTo);
  358. }
  359. if (pDdeConv == NULL) {
  360. RIPMSG2(RIP_VERBOSE, "Can't find DDE conversation for (%#p:%#p).",
  361. wParam, PtoH(pwndTo));
  362. dwRet = *pmessage == WM_DDE_TERMINATE ? FAKE_POST : FAIL_POST;
  363. goto Exit;
  364. }
  365. }
  366. if (fSent && pDdeConv->spartnerConv->spxsOut != NULL &&
  367. !(GETPTI(pwndFrom)->dwCompatFlags2 & GACF2_DDENOSYNC) ) {
  368. /*
  369. * Sent DDE messages will not work if any posted DDE messages are
  370. * in the queue because this will violate the message ordering rule.
  371. */
  372. RIPMSG0(RIP_VERBOSE,
  373. "Sent DDE message failed - queue contains a previous post.");
  374. dwRet = FAIL_POST;
  375. goto Exit;
  376. }
  377. /*
  378. * The tracking layer never did allow multiple threads to handle
  379. * the same DDE conversation but win95 shipped and some apps
  380. * got out there that did just this. We will let it slide for
  381. * 4.0 apps only so that when they rev their app, they will see
  382. * that they were wrong.
  383. */
  384. if (PtiCurrent() != GETPTI(pDdeConv) &&
  385. LOWORD(PtiCurrent()->dwExpWinVer) != VER40) {
  386. RIPERR0(ERROR_WINDOW_OF_OTHER_THREAD,
  387. RIP_ERROR,
  388. "Posting DDE message from wrong thread!");
  389. dwRet = FAIL_POST;
  390. goto Exit;
  391. }
  392. ThreadLockAlways(pDdeConv, &tlpDdeConv);
  393. /*
  394. * If the handle we're using is in the free list, remove it
  395. */
  396. ppfl = &pDdeConv->pfl;
  397. while (*ppfl != NULL) {
  398. if ((*ppfl)->h == (HANDLE)*plParam) {
  399. /* Let's stop to check this out */
  400. UserAssert((*ppfl)->h == (HANDLE)*plParam);
  401. *ppfl = (*ppfl)->next;
  402. } else {
  403. ppfl = &(*ppfl)->next;
  404. }
  405. }
  406. pfl = pDdeConv->pfl;
  407. pDdeConv->pfl = NULL;
  408. xxxFreeListFree(pfl);
  409. if (*pmessage != WM_DDE_TERMINATE &&
  410. (pDdeConv->flags & (CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED))) {
  411. dwRet = FAKE_POST;
  412. goto UnlockExit;
  413. }
  414. if (pDdeConv->spxsOut == NULL) {
  415. if (pDdeConv->flags & CXF_IS_SERVER) {
  416. dwRet = xxxUnexpectedServerPost((PDWORD)pmessage, plParam, pDdeConv);
  417. } else {
  418. dwRet = xxxUnexpectedClientPost((PDWORD)pmessage, plParam, pDdeConv);
  419. }
  420. } else {
  421. dwRet = (pDdeConv->spxsOut->fnResponse)(pmessage, plParam, pDdeConv);
  422. }
  423. UnlockExit:
  424. ThreadUnlock(&tlpDdeConv);
  425. Exit:
  426. if (dwRet == FAKE_POST && !((PtiCurrent())->TIF_flags & TIF_INCLEANUP)) {
  427. /*
  428. * We faked the post so do a client side cleanup here so that we
  429. * don't make it appear there is a leak in the client app.
  430. */
  431. DWORD flags = XS_DUMPMSG;
  432. /*
  433. * The XS_DUMPMSG tells FreeDDEHandle to also free the atoms
  434. * associated with the data - since a faked post would make the app
  435. * think that the receiver was going to cleanup the atoms.
  436. * It also tells FreeDDEHandle to pay attention to the
  437. * fRelease bit when freeing the data - this way, loaned data
  438. * won't be destroyed.
  439. */
  440. switch (*pmessage & 0xFFFF) {
  441. case WM_DDE_UNADVISE:
  442. case WM_DDE_REQUEST:
  443. goto DumpMsg;
  444. case WM_DDE_ACK:
  445. flags |= XS_PACKED;
  446. goto DumpMsg;
  447. case WM_DDE_ADVISE:
  448. flags |= XS_PACKED | XS_HIHANDLE;
  449. goto DumpMsg;
  450. case WM_DDE_DATA:
  451. case WM_DDE_POKE:
  452. flags |= XS_DATA | XS_LOHANDLE | XS_PACKED;
  453. goto DumpMsg;
  454. case WM_DDE_EXECUTE:
  455. flags |= XS_EXECUTE;
  456. // fall through
  457. DumpMsg:
  458. if (pDdeConv != NULL) {
  459. TRACE_DDE("xxxDdeTrackPostHook: dumping message...");
  460. FreeDDEHandle(pDdeConv, (HANDLE)*plParam, flags);
  461. dwRet = FAILNOFREE_POST;
  462. }
  463. }
  464. }
  465. #if DBG
  466. if (fSent) {
  467. TraceDdeMsg(*pmessage, (HWND)wParam, PtoH(pwndTo), MSG_SENT);
  468. } else {
  469. TraceDdeMsg(*pmessage, (HWND)wParam, PtoH(pwndTo), MSG_POST);
  470. }
  471. if (dwRet == FAKE_POST) {
  472. TRACE_DDE("...FAKED!");
  473. } else if (dwRet == FAIL_POST) {
  474. TRACE_DDE("...FAILED!");
  475. } else if (dwRet == FAILNOFREE_POST) {
  476. TRACE_DDE("...FAILED, DATA FREED!");
  477. }
  478. #endif // DBG
  479. return dwRet;
  480. }
  481. VOID xxxCleanupDdeConv(
  482. PWND pwndProp)
  483. {
  484. PDDECONV pDdeConv;
  485. Restart:
  486. CheckCritIn();
  487. pDdeConv = (PDDECONV)_GetProp(pwndProp, PROP_DDETRACK, PROPF_INTERNAL);
  488. while (pDdeConv != NULL) {
  489. if ((pDdeConv->flags & (CXF_IS_SERVER | CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED))
  490. == (CXF_IS_SERVER | CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED) &&
  491. (pDdeConv->spartnerConv->flags & CXF_TERMINATE_POSTED)) {
  492. /*
  493. * clean up client side objects on this side
  494. */
  495. BOOL fUnlockDdeConv;
  496. TL tlpDdeConv;
  497. RIPMSG1(RIP_VERBOSE, "xxxCleanupDdeConv %p", pDdeConv);
  498. fUnlockDdeConv = (pDdeConv->pfl != NULL);
  499. if (fUnlockDdeConv) {
  500. PFREELIST pfl;
  501. ThreadLockAlways(pDdeConv, &tlpDdeConv);
  502. pfl = pDdeConv->pfl;
  503. pDdeConv->pfl = NULL;
  504. xxxFreeListFree(pfl);
  505. }
  506. FreeDdeConv(pDdeConv->spartnerConv);
  507. FreeDdeConv(pDdeConv);
  508. if (fUnlockDdeConv) {
  509. ThreadUnlock(&tlpDdeConv);
  510. }
  511. /*
  512. * Take it back from the top. The list might have changed
  513. * if we left the critical section
  514. */
  515. goto Restart;
  516. }
  517. pDdeConv = pDdeConv->snext;
  518. }
  519. }
  520. /************************************************************************
  521. * xxxDDETrackGetMessageHook
  522. *
  523. * This routine is used to complete an inter-process copy from the
  524. * CSRServer context to the target context. pmsg->lParam is a
  525. * pxs that is used to obtain the pIntDdeInfo needed to
  526. * complete the copy. The pxs is either filled with the target side
  527. * direct handle or is freed depending on the message and its context.
  528. *
  529. * The XS_FREEPXS bit of the flags field of the pxs tells this function
  530. * to free the pxs when done.
  531. *
  532. * History:
  533. * 9-3-91 sanfords Created
  534. \***********************************************************************/
  535. VOID xxxDDETrackGetMessageHook(
  536. PMSG pmsg)
  537. {
  538. PXSTATE pxs;
  539. HANDLE hDirect;
  540. DWORD flags;
  541. BOOL fUnlockDdeConv;
  542. TL tlpDdeConv, tlpxs;
  543. TraceDdeMsg(pmsg->message, (HWND)pmsg->wParam, pmsg->hwnd, MSG_RECV);
  544. if (pmsg->message == WM_DDE_TERMINATE) {
  545. PWND pwndFrom, pwndTo;
  546. PDDECONV pDdeConv;
  547. pwndTo = ValidateHwnd(pmsg->hwnd);
  548. /*
  549. * We should get the pwnd even if the partner is destroyed in order
  550. * to clean up the DDE objects now. Exiting now would work, but would
  551. * leave the conversation objects locked and present until the To window
  552. * gets destroyed, which seems excessive.
  553. */
  554. pwndFrom = RevalidateCatHwnd((HWND)pmsg->wParam);
  555. if (pwndTo == NULL) {
  556. TRACE_DDE("TERMINATE ignored, invalid window(s).");
  557. return;
  558. } else if (pwndFrom == NULL) {
  559. CleanupAndExit:
  560. /*
  561. * Do this only for appcompat
  562. */
  563. if (GetAppCompatFlags2(VERMAX) & GACF2_DDE) {
  564. xxxCleanupDdeConv(pwndTo);
  565. } else {
  566. TRACE_DDE("TERMINATE ignored, invalid window(s).");
  567. }
  568. return;
  569. }
  570. /*
  571. * locate conversation info.
  572. */
  573. pDdeConv = FindDdeConv(pwndTo, pwndFrom);
  574. if (pDdeConv == NULL) {
  575. /*
  576. * Must be a harmless extra terminate.
  577. */
  578. TRACE_DDE("TERMINATE ignored, conversation not found.");
  579. return;
  580. }
  581. if (pDdeConv->flags & CXF_TERMINATE_POSTED &&
  582. pDdeConv->spartnerConv->flags & CXF_TERMINATE_POSTED) {
  583. /*
  584. * clean up client side objects on this side
  585. */
  586. fUnlockDdeConv = FALSE;
  587. if (pDdeConv->pfl != NULL) {
  588. PFREELIST pfl;
  589. fUnlockDdeConv = TRUE;
  590. ThreadLockAlways(pDdeConv, &tlpDdeConv);
  591. pfl = pDdeConv->pfl;
  592. pDdeConv->pfl = NULL;
  593. xxxFreeListFree(pfl);
  594. }
  595. TRACE_DDE2("DDE conversation (%#p:%#p) closed",
  596. (pDdeConv->flags & CXF_IS_SERVER) ? pmsg->wParam : (ULONG_PTR)pmsg->hwnd,
  597. (pDdeConv->flags & CXF_IS_SERVER) ? (ULONG_PTR)pmsg->hwnd : pmsg->wParam);
  598. FreeDdeConv(pDdeConv->spartnerConv);
  599. FreeDdeConv(pDdeConv);
  600. if (fUnlockDdeConv) {
  601. ThreadUnlock(&tlpDdeConv);
  602. }
  603. }
  604. goto CleanupAndExit;
  605. }
  606. pxs = (PXSTATE)HMValidateHandleNoRip((HANDLE)pmsg->lParam, TYPE_DDEXACT);
  607. if (pxs == NULL) {
  608. /*
  609. * The posting window has died and the pxs was freed so this
  610. * message shouldn't be bothered with...map to WM_NULL.
  611. */
  612. pmsg->lParam = 0;
  613. pmsg->message = WM_NULL;
  614. return;
  615. }
  616. flags = pxs->flags;
  617. ThreadLockAlways(pxs, &tlpxs);
  618. pmsg->lParam = (LPARAM)xxxCopyDDEOut(pxs->pIntDdeInfo, &hDirect);
  619. if (pmsg->lParam == (LPARAM)NULL) {
  620. /*
  621. * Turn this message into a terminate - we failed to copy the
  622. * message data out which implies we are too low on memory
  623. * to continue the conversation. Shut it down now before
  624. * other problems pop up that this failure will cause.
  625. */
  626. pmsg->message = WM_DDE_TERMINATE;
  627. RIPMSG0(RIP_WARNING, "DDETrack: couldn't copy data out, terminate faked.");
  628. }
  629. if (ThreadUnlock(&tlpxs) == NULL) {
  630. return;
  631. }
  632. if (flags & XS_FREEPXS) {
  633. FreeDdeXact(pxs);
  634. return;
  635. }
  636. /*
  637. * The only reason XS_FREEPXS isn't set is because we don't know which
  638. * side frees the data till an ACK comes back, thus one of the client
  639. * handles in pxs is already set via xxxDDETrackPostHook(). The one thats
  640. * not yet set gets set here.
  641. */
  642. if (pxs->hClient == NULL) {
  643. TRACE_DDE1("Saving %#p into hClient", hDirect);
  644. pxs->hClient = hDirect;
  645. } else {
  646. TRACE_DDE1("Saving %#p into hServer.", hDirect);
  647. pxs->hServer = hDirect;
  648. }
  649. }
  650. /************************************************************************
  651. * xxxDDETrackWindowDying
  652. *
  653. * Called when a window with PROP_DDETRACK is destroyed.
  654. *
  655. * This posts a terminate to the partner window and sets up for proper
  656. * terminate post fake from other end.
  657. *
  658. * History:
  659. * 9-3-91 sanfords Created
  660. \***********************************************************************/
  661. VOID xxxDDETrackWindowDying(
  662. PWND pwnd,
  663. PDDECONV pDdeConv)
  664. {
  665. TL tlpDdeConv, tlpDdeConvNext;
  666. UNREFERENCED_PARAMETER(pwnd);
  667. CheckLock(pwnd);
  668. CheckLock(pDdeConv);
  669. TRACE_DDE2("xxxDDETrackWindowDying(%#p, %#p)", PtoH(pwnd), pDdeConv);
  670. while (pDdeConv != NULL) {
  671. PFREELIST pfl;
  672. /*
  673. * If there are any active conversations for this window
  674. * start termination if not already started.
  675. */
  676. if (!(pDdeConv->flags & CXF_TERMINATE_POSTED)) {
  677. /*
  678. * Win9x doesn't do any tracking. This breaks some apps that
  679. * destroy the window first and then post the terminate. The
  680. * other side gets two terminates.
  681. */
  682. if (!(GACF2_NODDETRKDYING & GetAppCompatFlags2(VER40))
  683. || (pDdeConv->spwndPartner == NULL)
  684. || !(GACF2_NODDETRKDYING
  685. & GetAppCompatFlags2ForPti(GETPTI(pDdeConv->spwndPartner), VER40))) {
  686. /*
  687. * CXF_TERMINATE_POSTED would have been set if the window had died.
  688. */
  689. _PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE,
  690. (WPARAM)PtoH(pDdeConv->spwnd), 0);
  691. // pDdeConv->flags |= CXF_TERMINATE_POSTED; set by PostHookProc
  692. } else {
  693. RIPMSG2(RIP_WARNING, "xxxDDETrackWindowDying(GACF2_NODDETRKDYING) not posting terminate from %#p to %#p\r\n",
  694. pwnd, pDdeConv->spwndPartner);
  695. }
  696. }
  697. /*
  698. * now fake that the other side already posted a terminate since
  699. * we will be gone.
  700. */
  701. pDdeConv->spartnerConv->flags |=
  702. CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED;
  703. ThreadLock(pDdeConv->snext, &tlpDdeConvNext);
  704. ThreadLockAlways(pDdeConv, &tlpDdeConv);
  705. pfl = pDdeConv->pfl;
  706. pDdeConv->pfl = NULL;
  707. if (pDdeConv->flags & CXF_PARTNER_WINDOW_DIED) {
  708. ThreadUnlock(&tlpDdeConv);
  709. /*
  710. * he's already gone, free up conversation tracking data
  711. */
  712. FreeDdeConv(pDdeConv->spartnerConv);
  713. FreeDdeConv(pDdeConv);
  714. } else {
  715. UnlinkConv(pDdeConv);
  716. ThreadUnlock(&tlpDdeConv);
  717. }
  718. xxxFreeListFree(pfl);
  719. pDdeConv = ThreadUnlock(&tlpDdeConvNext);
  720. }
  721. }
  722. /************************************************************************
  723. * xxxUnexpectedServerPost
  724. *
  725. * Handles Server DDE messages not anticipated. (ie spontaneous or abnormal)
  726. *
  727. * History:
  728. * 9-3-91 sanfords Created
  729. \***********************************************************************/
  730. DWORD xxxUnexpectedServerPost(
  731. PDWORD pmessage,
  732. LPARAM *plParam,
  733. PDDECONV pDdeConv)
  734. {
  735. switch (*pmessage) {
  736. case WM_DDE_TERMINATE:
  737. return SpontaneousTerminate(pmessage, pDdeConv);
  738. case WM_DDE_DATA:
  739. return xxxAdviseData(pmessage, plParam, pDdeConv);
  740. case WM_DDE_ACK:
  741. /*
  742. * Could be an extra NACK due to timeout problems, just fake it.
  743. */
  744. TRACE_DDE("xxxUnexpectedServerPost: dumping ACK data...");
  745. FreeDDEHandle(pDdeConv, (HANDLE)*plParam, XS_PACKED);
  746. return FAILNOFREE_POST;
  747. case WM_DDE_ADVISE:
  748. case WM_DDE_UNADVISE:
  749. case WM_DDE_REQUEST:
  750. case WM_DDE_POKE:
  751. case WM_DDE_EXECUTE:
  752. return AbnormalDDEPost(pDdeConv, *pmessage);
  753. }
  754. return 0;
  755. }
  756. /************************************************************************
  757. * xxxUnexpectedClientPost
  758. *
  759. *
  760. * Handles Client DDE messages not anticipated. (ie spontaneous or abnormal)
  761. *
  762. * History:
  763. * 9-3-91 sanfords Created
  764. \***********************************************************************/
  765. DWORD xxxUnexpectedClientPost(
  766. PDWORD pmessage,
  767. LPARAM *plParam,
  768. PDDECONV pDdeConv)
  769. {
  770. switch (*pmessage) {
  771. case WM_DDE_TERMINATE:
  772. return SpontaneousTerminate(pmessage, pDdeConv);
  773. case WM_DDE_ACK:
  774. /*
  775. * Could be an extra NACK due to timeout problems, just fake it.
  776. */
  777. TRACE_DDE("xxxUnexpectedClientPost: dumping ACK data...");
  778. FreeDDEHandle(pDdeConv, (HANDLE)*plParam, XS_PACKED);
  779. return FAILNOFREE_POST;
  780. case WM_DDE_DATA:
  781. return AbnormalDDEPost(pDdeConv, *pmessage);
  782. case WM_DDE_ADVISE:
  783. return xxxAdvise(pmessage, plParam, pDdeConv);
  784. case WM_DDE_UNADVISE:
  785. return Unadvise(pDdeConv);
  786. case WM_DDE_REQUEST:
  787. return Request(pDdeConv);
  788. case WM_DDE_POKE:
  789. return xxxPoke(pmessage, plParam, pDdeConv);
  790. case WM_DDE_EXECUTE:
  791. return xxxExecute(pmessage, plParam, pDdeConv);
  792. }
  793. return 0;
  794. }
  795. /************************************************************************
  796. * ADVISE TRANSACTION PROCESSING *
  797. \***********************************************************************/
  798. DWORD xxxAdvise( // Spontaneous Client transaction = WM_DDE_ADVISE
  799. PDWORD pmessage,
  800. LPARAM *plParam,
  801. PDDECONV pDdeConv)
  802. {
  803. PINTDDEINFO pIntDdeInfo;
  804. HANDLE hDirect;
  805. DWORD flags, dwRet;
  806. CheckLock(pDdeConv);
  807. TRACE_DDE("xxxAdvise");
  808. flags = XS_PACKED | XS_LOHANDLE;
  809. dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
  810. if (dwRet == DO_POST) {
  811. UserAssert(pIntDdeInfo != NULL);
  812. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  813. *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxAdviseAck,
  814. hDirect, NULL, pIntDdeInfo, flags);
  815. if (*plParam == 0) {
  816. dwRet = FAILNOFREE_POST;
  817. }
  818. }
  819. return dwRet;
  820. }
  821. /*
  822. * If its inter-process:
  823. *
  824. * xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_ADVISE
  825. * is received. pIntDdeInfo is then freed. The hServer handle is saved into the
  826. * pxs structure pointed to by lParam is a direct data structure since
  827. * packed DDE messages are always assumed to have the packing handle freed.
  828. */
  829. DWORD xxxAdviseAck( // Server response to advise - WM_DDE_ACK expected
  830. PDWORD pmessage,
  831. LPARAM *plParam,
  832. PDDECONV pDdeConv)
  833. {
  834. PXSTATE pxsFree;
  835. PINTDDEINFO pIntDdeInfo;
  836. DWORD dwRet;
  837. CheckLock(pDdeConv);
  838. if (*pmessage != WM_DDE_ACK) {
  839. return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
  840. }
  841. TRACE_DDE("xxxAdviseAck");
  842. dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
  843. if (dwRet != DO_POST) {
  844. return dwRet;
  845. }
  846. UserAssert(pIntDdeInfo != NULL);
  847. pxsFree = pDdeConv->spxsOut;
  848. if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) {
  849. /*
  850. * positive ack implies server accepted the hOptions data - free from
  851. * client at postmessage time.
  852. */
  853. TRACE_DDE("xxxAdviseAck: +ACK delayed freeing data from client");
  854. FreeListAdd(pDdeConv->spartnerConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED);
  855. } else {
  856. // Shouldn't this be freed directly?
  857. TRACE_DDE("xxxAdviseAck: -ACK delayed freeing data from server");
  858. FreeListAdd(pDdeConv, pxsFree->hServer, pxsFree->flags & ~XS_PACKED);
  859. }
  860. PopState(pDdeConv);
  861. return DO_POST;
  862. }
  863. /************************************************************************
  864. * ADVISE DATA TRANSACTION PROCESSING *
  865. \***********************************************************************/
  866. DWORD xxxAdviseData( // spontaneous from server - WM_DDE_DATA
  867. PDWORD pmessage,
  868. LPARAM *plParam,
  869. PDDECONV pDdeConv)
  870. {
  871. DWORD flags, dwRet;
  872. PINTDDEINFO pIntDdeInfo;
  873. HANDLE hDirect;
  874. PXSTATE pxs;
  875. CheckLock(pDdeConv);
  876. TRACE_DDE("xxxAdviseData");
  877. flags = XS_PACKED | XS_LOHANDLE | XS_DATA;
  878. dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
  879. if (dwRet == DO_POST) {
  880. UserAssert(pIntDdeInfo != NULL);
  881. TRACE_DDE1("xxxAdviseData: wStatus = %x",
  882. ((PDDE_DATA)(pIntDdeInfo + 1))->wStatus);
  883. if (!(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & (DDE_FACK | DDE_FRELEASE))) {
  884. RIPMSG0(RIP_ERROR, "DDE protocol violation - no RELEASE or ACK bit set - setting RELEASE.");
  885. ((PDDE_DATA)(pIntDdeInfo + 1))->wStatus |= DDE_FRELEASE;
  886. }
  887. if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FRELEASE) {
  888. /*
  889. * giving it away
  890. */
  891. if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) {
  892. RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object.");
  893. UserFreePool(pIntDdeInfo);
  894. return FAILNOFREE_POST;
  895. }
  896. if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
  897. pIntDdeInfo->hIndirect,
  898. (W32PID)(GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid))) {
  899. flags |= XS_GIVEBACKONNACK;
  900. }
  901. flags |= XS_FRELEASE;
  902. } else {
  903. /*
  904. * on loan
  905. */
  906. if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
  907. pIntDdeInfo->hIndirect,
  908. (W32PID)(GETPTI(pDdeConv->spwnd)->ppi->W32Pid))) {
  909. flags |= XS_PUBLICOBJ;
  910. }
  911. }
  912. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  913. if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FACK) {
  914. *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv,
  915. xxxAdviseDataAck, NULL, hDirect, pIntDdeInfo, flags);
  916. } else {
  917. TRACE_DDE("xxxAdviseData: dumping non Ackable data...");
  918. UserAssert(hDirect != (HANDLE)*plParam);
  919. FreeDDEHandle(pDdeConv, hDirect, flags & ~XS_PACKED);
  920. pxs = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS);
  921. if (pxs != NULL) {
  922. pxs->head.pti = GETPTI(pDdeConv->spwndPartner);
  923. }
  924. *plParam = (LPARAM)PtoH(pxs);
  925. }
  926. if (*plParam == 0) {
  927. dwRet = FAILNOFREE_POST;
  928. }
  929. }
  930. return dwRet;
  931. }
  932. /*
  933. * If its inter-process:
  934. *
  935. * xxxDDETrackGetMessageHook() completes the copy from pIntDdeInfo when WM_DDE_DATA
  936. * is received. pIntDdeInfo is then freed. The hServer handle saved into the
  937. * pxs structure pointed to by lParam is a directdata structure since
  938. * packed DDE messages are always assumed to have the packing handle freed
  939. * by the receiving app.
  940. * For the !fAckReq case, the pxs is freed due to the XS_FREEPXS flag.
  941. */
  942. DWORD xxxAdviseDataAck( // Client response to advise data - WM_DDE_ACK expected
  943. PDWORD pmessage,
  944. LPARAM *plParam,
  945. PDDECONV pDdeConv)
  946. {
  947. PXSTATE pxsFree;
  948. PINTDDEINFO pIntDdeInfo;
  949. DWORD dwRet;
  950. CheckLock(pDdeConv);
  951. /*
  952. * This is also used for request data ack processing.
  953. */
  954. if (*pmessage != WM_DDE_ACK) {
  955. return xxxUnexpectedClientPost(pmessage, plParam, pDdeConv);
  956. }
  957. TRACE_DDE("xxxAdviseDataAck");
  958. dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
  959. if (dwRet != DO_POST) {
  960. return dwRet;
  961. }
  962. UserAssert(pIntDdeInfo != NULL);
  963. pxsFree = pDdeConv->spxsOut;
  964. TRACE_DDE3("xxxAdviseDataAck:pxs.hClient(%#p), hServer(%#p), wStatus(%x)",
  965. pxsFree->hClient, pxsFree->hServer, pIntDdeInfo->DdePack.uiLo);
  966. if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) {
  967. /*
  968. * positive ack implies client accepted the data - free from
  969. * server at postmessage time iff FRELEASE was set in data msg.
  970. */
  971. if (pxsFree->flags & XS_FRELEASE) {
  972. TRACE_DDE("xxxAdviseDataAck: +ACK delayed server data free");
  973. FreeListAdd(pDdeConv->spartnerConv, pxsFree->hServer,
  974. pxsFree->flags & ~XS_PACKED);
  975. } else {
  976. /*
  977. * Ack w/out fRelease bit means client is done with data.
  978. */
  979. TRACE_DDE1("xxxAdviseDataAck: Freeing %#p. (+ACK)",
  980. pxsFree->hClient);
  981. UserAssert(pxsFree->hClient != (HANDLE)*plParam);
  982. FreeDDEHandle(pDdeConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED);
  983. }
  984. } else {
  985. TRACE_DDE1("xxxAdviseDataAck: Freeing %#p. (-ACK)",
  986. pxsFree->hClient);
  987. FreeDDEHandle(pDdeConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED);
  988. UserAssert(pxsFree->hClient != (HANDLE)*plParam);
  989. }
  990. PopState(pDdeConv);
  991. return DO_POST;
  992. }
  993. /************************************************************************
  994. * UNADVISE TRANSACTION PROCESSING *
  995. \***********************************************************************/
  996. DWORD Unadvise( // Spontaneous client transaction = WM_DDE_UNADVISE
  997. PDDECONV pDdeConv)
  998. {
  999. TRACE_DDE("Unadvise");
  1000. if (AnticipatePost(pDdeConv->spartnerConv, xxxUnadviseAck, NULL, NULL, NULL, 0)) {
  1001. return DO_POST;
  1002. } else {
  1003. return FAIL_POST;
  1004. }
  1005. }
  1006. DWORD xxxUnadviseAck( // Server response to unadvise - WM_DDE_ACK expected
  1007. PDWORD pmessage,
  1008. LPARAM *plParam,
  1009. PDDECONV pDdeConv)
  1010. {
  1011. DWORD dwRet;
  1012. PINTDDEINFO pIntDdeInfo;
  1013. CheckLock(pDdeConv);
  1014. if (*pmessage != WM_DDE_ACK) {
  1015. return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
  1016. }
  1017. TRACE_DDE("xxxUnadviseAck");
  1018. dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
  1019. if (dwRet != DO_POST) {
  1020. return dwRet;
  1021. }
  1022. UserAssert(pIntDdeInfo != NULL);
  1023. PopState(pDdeConv);
  1024. return DO_POST;
  1025. }
  1026. /************************************************************************
  1027. * REQUEST TRANSACTION PROCESSING *
  1028. \***********************************************************************/
  1029. DWORD Request( // Spontaneous Client transaction - WM_DDE_REQUEST
  1030. PDDECONV pDdeConv)
  1031. {
  1032. TRACE_DDE("Request");
  1033. if (AnticipatePost(pDdeConv->spartnerConv, xxxRequestAck, NULL, NULL, NULL, 0)) {
  1034. return DO_POST;
  1035. } else {
  1036. return FAIL_POST;
  1037. }
  1038. }
  1039. DWORD xxxRequestAck( // Server response - WM_DDE_ACK or WM_DDE_DATA expected
  1040. PDWORD pmessage,
  1041. LPARAM *plParam,
  1042. PDDECONV pDdeConv)
  1043. {
  1044. PXSTATE pxsFree;
  1045. DWORD flags;
  1046. PINTDDEINFO pIntDdeInfo;
  1047. HANDLE hDirect;
  1048. DWORD dwStatus, dwRet;
  1049. CheckLock(pDdeConv);
  1050. TRACE_DDE("xxxRequestAck or xxxAdviseData");
  1051. switch (*pmessage) {
  1052. case WM_DDE_DATA:
  1053. /*
  1054. * This is very close to advise data handling - the only catch
  1055. * is that if the fRequest bit is clear this IS advise data.
  1056. */
  1057. flags = XS_PACKED | XS_LOHANDLE | XS_DATA;
  1058. dwStatus = ClientGetDDEFlags((HANDLE)*plParam, flags);
  1059. if (!(dwStatus & DDE_FREQUESTED)) {
  1060. /*
  1061. * Its NOT a request Ack - it must be advise data
  1062. */
  1063. return xxxAdviseData(pmessage, plParam, pDdeConv);
  1064. }
  1065. pxsFree = pDdeConv->spxsOut;
  1066. dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
  1067. if (dwRet == DO_POST) {
  1068. UserAssert(pIntDdeInfo != NULL);
  1069. if (!(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & (DDE_FACK | DDE_FRELEASE))) {
  1070. RIPMSG0(RIP_ERROR, "DDE protocol violation - no RELEASE or ACK bit set - setting RELEASE.");
  1071. ((PDDE_DATA)(pIntDdeInfo + 1))->wStatus |= DDE_FRELEASE;
  1072. }
  1073. if (dwStatus & DDE_FRELEASE) {
  1074. /*
  1075. * giving it away
  1076. */
  1077. if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) {
  1078. RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object.");
  1079. UserFreePool(pIntDdeInfo);
  1080. return FAILNOFREE_POST;
  1081. }
  1082. if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
  1083. pIntDdeInfo->hIndirect,
  1084. (W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid)) {
  1085. flags |= XS_GIVEBACKONNACK;
  1086. }
  1087. flags |= XS_FRELEASE;
  1088. } else {
  1089. /*
  1090. * on loan
  1091. */
  1092. if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
  1093. pIntDdeInfo->hIndirect,
  1094. (W32PID)GETPTI(pDdeConv->spwnd)->ppi->W32Pid)) {
  1095. flags |= XS_PUBLICOBJ;
  1096. }
  1097. }
  1098. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  1099. if (dwStatus & DDE_FACK) {
  1100. *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv,
  1101. xxxAdviseDataAck, NULL, hDirect, pIntDdeInfo, flags);
  1102. } else {
  1103. TRACE_DDE("xxxRequestAck: Delayed freeing non-ackable request data");
  1104. FreeListAdd(pDdeConv, hDirect, flags & ~XS_PACKED);
  1105. pxsFree = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS);
  1106. if (pxsFree != NULL) {
  1107. pxsFree->head.pti = GETPTI(pDdeConv->spwndPartner);
  1108. }
  1109. *plParam = (LPARAM)PtoH(pxsFree);
  1110. }
  1111. if (*plParam != 0) {
  1112. PopState(pDdeConv);
  1113. } else {
  1114. dwRet = FAILNOFREE_POST;
  1115. }
  1116. }
  1117. return dwRet;
  1118. case WM_DDE_ACK: // server NACKs request
  1119. dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
  1120. if (dwRet != DO_POST) {
  1121. return dwRet;
  1122. }
  1123. UserAssert(pIntDdeInfo != NULL);
  1124. PopState(pDdeConv);
  1125. return DO_POST;
  1126. default:
  1127. return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
  1128. }
  1129. }
  1130. /************************************************************************
  1131. * POKE TRANSACTION PROCESSING *
  1132. \***********************************************************************/
  1133. DWORD xxxPoke( // spontaneous client transaction - WM_DDE_POKE
  1134. PDWORD pmessage,
  1135. LPARAM *plParam,
  1136. PDDECONV pDdeConv)
  1137. {
  1138. DWORD flags, dwRet;
  1139. PINTDDEINFO pIntDdeInfo;
  1140. HANDLE hDirect;
  1141. CheckLock(pDdeConv);
  1142. TRACE_DDE("xxxPoke");
  1143. flags = XS_PACKED | XS_LOHANDLE | XS_DATA;
  1144. dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
  1145. if (dwRet == DO_POST) {
  1146. UserAssert(pIntDdeInfo != NULL);
  1147. if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FRELEASE) {
  1148. /*
  1149. * giving it away
  1150. */
  1151. if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) {
  1152. RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object.");
  1153. UserFreePool(pIntDdeInfo);
  1154. return FAILNOFREE_POST;
  1155. }
  1156. if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
  1157. pIntDdeInfo->hIndirect,
  1158. (W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid)) {
  1159. flags |= XS_GIVEBACKONNACK;
  1160. }
  1161. flags |= XS_FRELEASE;
  1162. } else {
  1163. /*
  1164. * on loan
  1165. */
  1166. /*
  1167. * fAck bit is ignored and assumed on.
  1168. */
  1169. if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
  1170. pIntDdeInfo->hIndirect,
  1171. (W32PID)GETPTI(pDdeConv->spwnd)->ppi->W32Pid)) {
  1172. flags |= XS_PUBLICOBJ;
  1173. }
  1174. }
  1175. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  1176. *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxPokeAck,
  1177. hDirect, NULL, pIntDdeInfo, flags);
  1178. if (*plParam == 0) {
  1179. dwRet = FAILNOFREE_POST;
  1180. }
  1181. }
  1182. return dwRet;
  1183. }
  1184. /*
  1185. * If its inter-process:
  1186. *
  1187. * xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_ADVISE
  1188. * is received. pIntDdeInfo is then freed. The hServer handle saved into the
  1189. * pxs structure pointer to by lParam is a directdata structure since
  1190. * packed DDE messages are always assumed to have the packing handle freed
  1191. * by the receiving app.
  1192. * For the !fAckReq case, the pxs is also freed due to the XS_FREEPXS flag.
  1193. */
  1194. DWORD xxxPokeAck( // Server response to poke data - WM_DDE_ACK expected
  1195. PDWORD pmessage,
  1196. LPARAM *plParam,
  1197. PDDECONV pDdeConv)
  1198. {
  1199. PXSTATE pxsFree;
  1200. PINTDDEINFO pIntDdeInfo;
  1201. DWORD dwRet;
  1202. CheckLock(pDdeConv);
  1203. if (*pmessage != WM_DDE_ACK) {
  1204. return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
  1205. }
  1206. TRACE_DDE("xxxPokeAck");
  1207. dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
  1208. if (dwRet != DO_POST) {
  1209. return dwRet;
  1210. }
  1211. UserAssert(pIntDdeInfo != NULL);
  1212. pxsFree = pDdeConv->spxsOut;
  1213. if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) {
  1214. // positive ack implies server accepted the data - free from
  1215. // client at postmessage time iff fRelease was set in poke message.
  1216. if (pxsFree->flags & XS_FRELEASE) {
  1217. TRACE_DDE("xxxPokeAck: delayed freeing client data");
  1218. FreeListAdd(pDdeConv->spartnerConv, pxsFree->hClient,
  1219. pxsFree->flags & ~XS_PACKED);
  1220. }
  1221. } else {
  1222. // Nack means that sender is responsible for freeing it.
  1223. // We must free it in the receiver's context for him.
  1224. TRACE_DDE("xxxPokeAck: freeing Nacked data");
  1225. UserAssert(pxsFree->hServer != (HANDLE)*plParam);
  1226. FreeDDEHandle(pDdeConv, pxsFree->hServer, pxsFree->flags & ~XS_PACKED);
  1227. }
  1228. PopState(pDdeConv);
  1229. return DO_POST;
  1230. }
  1231. /************************************************************************
  1232. * EXECUTE TRANSACTION PROCESSING *
  1233. \***********************************************************************/
  1234. DWORD xxxExecute( // spontaneous client transaction - WM_DDE_EXECUTE
  1235. PDWORD pmessage,
  1236. LPARAM *plParam,
  1237. PDDECONV pDdeConv)
  1238. {
  1239. DWORD flags, dwRet;
  1240. PINTDDEINFO pIntDdeInfo;
  1241. HANDLE hDirect;
  1242. CheckLock(pDdeConv);
  1243. TRACE_DDE("xxxExecute");
  1244. flags = XS_EXECUTE;
  1245. if (!TestWF(pDdeConv->spwnd, WFANSIPROC) &&
  1246. !TestWF(pDdeConv->spwndPartner, WFANSIPROC)) {
  1247. flags |= XS_UNICODE;
  1248. }
  1249. dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
  1250. if (dwRet == DO_POST) {
  1251. UserAssert(pIntDdeInfo != NULL);
  1252. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  1253. *plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxExecuteAck,
  1254. hDirect, NULL, pIntDdeInfo, flags);
  1255. /*
  1256. * Check for != 0 to make sure the AnticipatePost() succeeded.
  1257. */
  1258. if (*plParam != 0) {
  1259. /*
  1260. * In the execute case it is likely that the postee will want to activate
  1261. * itself and come on top (OLE 1.0 is an example). In this case, allow
  1262. * both the postee and the poster to foreground activate for the next
  1263. * activate (poster because it will want to activate itself again
  1264. * probably, once the postee is done.)
  1265. */
  1266. GETPTI(pDdeConv->spwnd)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
  1267. TAGMSG1(DBGTAG_FOREGROUND, "xxxExecute set TIF %#p", GETPTI(pDdeConv->spwnd));
  1268. GETPTI(pDdeConv->spwndPartner)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
  1269. TAGMSG1(DBGTAG_FOREGROUND, "xxxExecute set TIF %#p", GETPTI(pDdeConv->spwndPartner));
  1270. } else {
  1271. dwRet = FAILNOFREE_POST;
  1272. }
  1273. }
  1274. return dwRet;
  1275. }
  1276. /*
  1277. * xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_EXECUTE
  1278. * is received. pIntDdeInfo is then freed.
  1279. */
  1280. DWORD xxxExecuteAck( // Server response to execute data - WM_DDE_ACK expected
  1281. PDWORD pmessage,
  1282. LPARAM *plParam,
  1283. PDDECONV pDdeConv)
  1284. {
  1285. PXSTATE pxsFree;
  1286. PINTDDEINFO pi;
  1287. DWORD flags = XS_PACKED | XS_FREESRC | XS_EXECUTE;
  1288. DWORD dwRet;
  1289. CheckLock(pDdeConv);
  1290. if (*pmessage != WM_DDE_ACK) {
  1291. return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
  1292. }
  1293. TRACE_DDE("xxxExecuteAck");
  1294. dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, NULL, &pi);
  1295. if (dwRet == DO_POST) {
  1296. UserAssert(pi != NULL);
  1297. /*
  1298. * the server must respond to the execute with an ack containing the
  1299. * same handle it was given.
  1300. */
  1301. pi->DdePack.uiHi = (ULONG_PTR)pDdeConv->spxsOut->hClient;
  1302. pi->hDirect = NULL;
  1303. pi->cbDirect = 0;
  1304. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  1305. pxsFree = Createpxs(NULL, NULL, NULL, pi, XS_PACKED | XS_FREEPXS);
  1306. if (pxsFree != NULL) {
  1307. pxsFree->head.pti = GETPTI(pDdeConv->spwndPartner);
  1308. }
  1309. *plParam = (LPARAM)PtoH(pxsFree);
  1310. if (*plParam != 0) {
  1311. PopState(pDdeConv);
  1312. } else {
  1313. dwRet = FAILNOFREE_POST;
  1314. }
  1315. }
  1316. return dwRet;
  1317. }
  1318. /************************************************************************
  1319. * TERMINATE TRANSACTION PROCESSING *
  1320. \***********************************************************************/
  1321. DWORD SpontaneousTerminate(
  1322. PDWORD pmessage,
  1323. PDDECONV pDdeConv)
  1324. {
  1325. TRACE_DDE("SpontaneousTerminate");
  1326. if (pDdeConv->flags & CXF_TERMINATE_POSTED) {
  1327. return FAKE_POST;
  1328. } else {
  1329. pDdeConv->flags |= CXF_TERMINATE_POSTED;
  1330. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  1331. return DO_POST;
  1332. }
  1333. }
  1334. /*
  1335. * The xxxDDETrackGetMessageHook() function restores the *pmessage value.
  1336. * Unless a spontaneous terminate from the other app has already
  1337. * arrived, it will note that CXF_TERMINATE_POSTED is NOT set on
  1338. * both sides so no action is taken.
  1339. */
  1340. /************************************************************************
  1341. * DUPLICATE CONVERSATION TERMINATION *
  1342. \***********************************************************************/
  1343. /*
  1344. * This routine is called when a DDE server window sent a WM_DDE_ACK
  1345. * message to a client window which is already engaged in a conversation
  1346. * with that server window. We swallow the ACK and post a terminate to
  1347. * the server window to shut this conversation down. When the server
  1348. * posts the terminate, this function is called to basically fake
  1349. * a sucessful post. Thus the client is never bothered while the
  1350. * errant server thinks the conversation was connected and then
  1351. * imediately terminated.
  1352. */
  1353. DWORD DupConvTerminate( // WM_DDE_TERMINATE expected
  1354. PDWORD pmessage,
  1355. LPARAM *plParam,
  1356. PDDECONV pDdeConv)
  1357. {
  1358. CheckLock(pDdeConv);
  1359. TRACE_DDE("DupConvTerminate");
  1360. if (*pmessage != WM_DDE_TERMINATE) {
  1361. return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
  1362. }
  1363. PopState(pDdeConv);
  1364. return FAKE_POST;
  1365. }
  1366. /************************************************************************
  1367. * HELPER ROUTINES FOR TRANSACTION TRACKING *
  1368. \***********************************************************************/
  1369. /************************************************************************
  1370. * AnticipatePost
  1371. *
  1372. * Allocates, fills and links XSTATE structures.
  1373. *
  1374. * History:
  1375. * 9-3-91 sanfords Created
  1376. \***********************************************************************/
  1377. HANDLE AnticipatePost(
  1378. PDDECONV pDdeConv,
  1379. FNDDERESPONSE fnResponse,
  1380. HANDLE hClient,
  1381. HANDLE hServer,
  1382. PINTDDEINFO pIntDdeInfo,
  1383. DWORD flags)
  1384. {
  1385. PXSTATE pxs;
  1386. pxs = Createpxs(fnResponse, hClient, hServer, pIntDdeInfo, flags);
  1387. if (pxs != NULL) {
  1388. pxs->head.pti = pDdeConv->head.pti;
  1389. if (pDdeConv->spxsOut == NULL) {
  1390. UserAssert(pDdeConv->spxsIn == NULL);
  1391. Lock(&(pDdeConv->spxsOut), pxs);
  1392. Lock(&(pDdeConv->spxsIn), pxs);
  1393. } else {
  1394. UserAssert(pDdeConv->spxsIn != NULL);
  1395. Lock(&(pDdeConv->spxsIn->snext), pxs);
  1396. Lock(&(pDdeConv->spxsIn), pxs);
  1397. }
  1398. #if 0
  1399. {
  1400. int i;
  1401. HANDLEENTRY *phe;
  1402. for (i = 0, phe = gSharedInfo.aheList;
  1403. i <= (int)giheLast;
  1404. i++) {
  1405. if (phe[i].bType == TYPE_DDEXACT) {
  1406. UserAssert(((PXSTATE)(phe[i].phead))->snext != pDdeConv->spxsOut);
  1407. }
  1408. if (phe[i].bType == TYPE_DDECONV &&
  1409. (PDDECONV)phe[i].phead != pDdeConv) {
  1410. UserAssert(((PDDECONV)(phe[i].phead))->spxsOut != pDdeConv->spxsOut);
  1411. UserAssert(((PDDECONV)(phe[i].phead))->spxsIn != pDdeConv->spxsOut);
  1412. }
  1413. }
  1414. }
  1415. #endif
  1416. }
  1417. return PtoH(pxs);
  1418. }
  1419. /************************************************************************
  1420. * Createpxs
  1421. *
  1422. * Allocates and fills XSTATE structures.
  1423. *
  1424. * History:
  1425. * 9-3-91 sanfords Created
  1426. \***********************************************************************/
  1427. PXSTATE Createpxs(
  1428. FNDDERESPONSE fnResponse,
  1429. HANDLE hClient,
  1430. HANDLE hServer,
  1431. PINTDDEINFO pIntDdeInfo,
  1432. DWORD flags)
  1433. {
  1434. PXSTATE pxs;
  1435. pxs = HMAllocObject(PtiCurrent(), NULL, TYPE_DDEXACT, sizeof(XSTATE));
  1436. if (pxs == NULL) {
  1437. #if DBG
  1438. RIPMSG0(RIP_WARNING, "Unable to alloc DDEXACT");
  1439. #endif
  1440. return NULL;
  1441. }
  1442. pxs->snext = NULL;
  1443. pxs->fnResponse = fnResponse;
  1444. pxs->hClient = hClient;
  1445. pxs->hServer = hServer;
  1446. pxs->pIntDdeInfo = pIntDdeInfo;
  1447. pxs->flags = flags;
  1448. ValidatePublicObjectList();
  1449. UserAssert(pxs->head.cLockObj == 0);
  1450. return pxs;
  1451. }
  1452. /************************************************************************
  1453. * AbnormalDDEPost
  1454. *
  1455. * This is the catch-all routine for wierd cases
  1456. *
  1457. * returns post action code - DO_POST, FAKE_POST, FAIL_POST.
  1458. *
  1459. * History:
  1460. * 9-3-91 sanfords Created
  1461. \***********************************************************************/
  1462. DWORD AbnormalDDEPost(
  1463. PDDECONV pDdeConv,
  1464. DWORD message)
  1465. {
  1466. #if DBG
  1467. if (message != WM_DDE_TERMINATE) {
  1468. RIPMSG2(RIP_WARNING,
  1469. "DDE Post failed (%#p:%#p) - protocol violation.",
  1470. PtoH(pDdeConv->spwnd), PtoH(pDdeConv->spwndPartner));
  1471. }
  1472. #endif // DBG
  1473. // shutdown this conversation by posting a terminate on
  1474. // behalf of this guy, then fail all future posts but
  1475. // fake a successful terminate.
  1476. if (!(pDdeConv->flags & CXF_TERMINATE_POSTED)) {
  1477. _PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE,
  1478. (WPARAM)PtoH(pDdeConv->spwnd), 0);
  1479. // pDdeConv->flags |= CXF_TERMINATE_POSTED; Set by post hook proc
  1480. }
  1481. return message == WM_DDE_TERMINATE ? FAKE_POST : FAIL_POST;
  1482. }
  1483. /************************************************************************
  1484. * NewConversation
  1485. *
  1486. * Worker function used to create a saimese pair of DDECONV structures.
  1487. *
  1488. * Returns fCreateOk
  1489. *
  1490. * History:
  1491. * 11-5-92 sanfords Created
  1492. \***********************************************************************/
  1493. BOOL NewConversation(
  1494. PDDECONV *ppdcNewClient,
  1495. PDDECONV *ppdcNewServer,
  1496. PWND pwndClient,
  1497. PWND pwndServer)
  1498. {
  1499. PDDECONV pdcNewClient;
  1500. PDDECONV pdcNewServer;
  1501. pdcNewClient = HMAllocObject(GETPTI(pwndClient), NULL,
  1502. TYPE_DDECONV, sizeof(DDECONV));
  1503. if (pdcNewClient == NULL) {
  1504. return FALSE;
  1505. }
  1506. pdcNewServer = HMAllocObject(GETPTI(pwndServer), NULL,
  1507. TYPE_DDECONV, sizeof(DDECONV));
  1508. if (pdcNewServer == NULL) {
  1509. HMFreeObject(pdcNewClient); // we know it's not locked.
  1510. return FALSE;
  1511. }
  1512. AddConvProp(pwndClient, pwndServer, 0, pdcNewClient, pdcNewServer);
  1513. AddConvProp(pwndServer, pwndClient, CXF_IS_SERVER, pdcNewServer,
  1514. pdcNewClient);
  1515. if (ppdcNewClient != NULL) {
  1516. *ppdcNewClient = pdcNewClient;
  1517. }
  1518. if (ppdcNewServer != NULL) {
  1519. *ppdcNewServer = pdcNewServer;
  1520. }
  1521. return TRUE;
  1522. }
  1523. /************************************************************************
  1524. * FindDdeConv
  1525. *
  1526. * Locates the pDdeConv associated with pwndProp, and pwndPartner.
  1527. * Only searches pwndProp's property list.
  1528. *
  1529. * History:
  1530. * 3-31-91 sanfords Created
  1531. \***********************************************************************/
  1532. PDDECONV FindDdeConv(
  1533. PWND pwndProp,
  1534. PWND pwndPartner)
  1535. {
  1536. PDDECONV pDdeConv;
  1537. pDdeConv = (PDDECONV)_GetProp(pwndProp, PROP_DDETRACK, PROPF_INTERNAL);
  1538. while (pDdeConv != NULL && pDdeConv->spwndPartner != pwndPartner) {
  1539. pDdeConv = pDdeConv->snext;
  1540. }
  1541. return pDdeConv;
  1542. }
  1543. /************************************************************************
  1544. * xxxCopyAckIn
  1545. *
  1546. * A common occurance helper function
  1547. *
  1548. * History:
  1549. * 9-3-91 sanfords Created
  1550. \***********************************************************************/
  1551. DWORD xxxCopyAckIn(
  1552. LPDWORD pmessage,
  1553. LPARAM *plParam,
  1554. PDDECONV pDdeConv,
  1555. PINTDDEINFO * ppIntDdeInfo)
  1556. {
  1557. PINTDDEINFO pIntDdeInfo;
  1558. DWORD flags, dwRet;
  1559. PXSTATE pxs;
  1560. CheckLock(pDdeConv);
  1561. flags = XS_PACKED | XS_FREESRC;
  1562. dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, NULL, ppIntDdeInfo);
  1563. if (dwRet == DO_POST) {
  1564. UserAssert(*ppIntDdeInfo != NULL);
  1565. pIntDdeInfo = *ppIntDdeInfo;
  1566. if (pDdeConv->spxsOut->flags & XS_GIVEBACKONNACK &&
  1567. !(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FACK)) {
  1568. GiveObject(((PDDE_DATA)(pDdeConv->spxsOut->pIntDdeInfo + 1))->wFmt,
  1569. pDdeConv->spxsOut->pIntDdeInfo->hIndirect,
  1570. (W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid);
  1571. }
  1572. if (pDdeConv->spxsOut->flags & XS_PUBLICOBJ) {
  1573. RemovePublicObject(((PDDE_DATA)(pDdeConv->spxsOut->pIntDdeInfo + 1))->wFmt,
  1574. pDdeConv->spxsOut->pIntDdeInfo->hIndirect);
  1575. pDdeConv->spxsOut->flags &= ~XS_PUBLICOBJ;
  1576. }
  1577. pxs = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS);
  1578. if (pxs != NULL) {
  1579. pxs->head.pti = GETPTI(pDdeConv->spwndPartner);
  1580. }
  1581. *plParam = (LPARAM)PtoH(pxs);
  1582. if (*plParam == 0) {
  1583. return FAILNOFREE_POST;
  1584. }
  1585. *pmessage |= MSGFLAG_DDE_MID_THUNK;
  1586. }
  1587. return dwRet;
  1588. }
  1589. /************************************************************************
  1590. * FreeListAdd
  1591. *
  1592. * Adds a CSR Client handle to the free list associated with pDdeConv.
  1593. * This allows us to make sure stuff is freed that isn't in a context
  1594. * we have access at the time we know it must be freed.
  1595. *
  1596. * returns fSuccess
  1597. *
  1598. * History:
  1599. * 9-3-91 sanfords Created
  1600. \***********************************************************************/
  1601. BOOL FreeListAdd(
  1602. PDDECONV pDdeConv,
  1603. HANDLE hClient,
  1604. DWORD flags)
  1605. {
  1606. PFREELIST pfl;
  1607. pfl = (PFREELIST)UserAllocPool(sizeof(FREELIST), TAG_DDE1);
  1608. if (!pfl) {
  1609. return FALSE;
  1610. }
  1611. TRACE_DDE2("FreeListAdd: %x for thread %x.", hClient,
  1612. GETPTIID(pDdeConv->head.pti));
  1613. pfl->h = hClient;
  1614. pfl->flags = flags;
  1615. pfl->next = pDdeConv->pfl;
  1616. pDdeConv->pfl = pfl;
  1617. return TRUE;
  1618. }
  1619. /************************************************************************
  1620. * FreeDDEHandle
  1621. *
  1622. * Frees contents DDE client side handle - delayed free if a WOW process.
  1623. *
  1624. * History:
  1625. * 7-28-94 sanfords Created
  1626. \***********************************************************************/
  1627. VOID FreeDDEHandle(
  1628. PDDECONV pDdeConv,
  1629. HANDLE hClient,
  1630. DWORD flags)
  1631. {
  1632. if (PtiCurrent()->TIF_flags & TIF_16BIT) {
  1633. TRACE_DDE1("FreeDDEHandle: (WOW hack) delayed Freeing %#p.", hClient);
  1634. FreeListAdd(pDdeConv, hClient, flags);
  1635. } else {
  1636. TRACE_DDE1("FreeDDEHandle: Freeing %#p.", hClient);
  1637. ClientFreeDDEHandle(hClient, flags);
  1638. }
  1639. }
  1640. /************************************************************************
  1641. * xxxFreeListFree
  1642. *
  1643. * Frees contents of the free list associated with pDdeConv.
  1644. *
  1645. * History:
  1646. * 9-3-91 sanfords Created
  1647. \***********************************************************************/
  1648. VOID FreeListFree(
  1649. PFREELIST pfl)
  1650. {
  1651. PFREELIST pflPrev;
  1652. CheckCritIn();
  1653. UserAssert(pfl != NULL);
  1654. while (pfl != NULL) {
  1655. pflPrev = pfl;
  1656. pfl = pfl->next;
  1657. UserFreePool(pflPrev);
  1658. }
  1659. }
  1660. VOID xxxFreeListFree(
  1661. PFREELIST pfl)
  1662. {
  1663. PFREELIST pflPrev;
  1664. BOOL fInCleanup;
  1665. TL tlPool;
  1666. CheckCritIn();
  1667. if (pfl == NULL) {
  1668. return;
  1669. }
  1670. fInCleanup = (PtiCurrent())->TIF_flags & TIF_INCLEANUP;
  1671. while (pfl != NULL) {
  1672. ThreadLockPoolCleanup(PtiCurrent(), pfl, &tlPool, FreeListFree);
  1673. if (!fInCleanup) {
  1674. TRACE_DDE1("Freeing %#p from free list.\n", pfl->h);
  1675. ClientFreeDDEHandle(pfl->h, pfl->flags);
  1676. }
  1677. ThreadUnlockPoolCleanup(PtiCurrent(), &tlPool);
  1678. pflPrev = pfl;
  1679. pfl = pfl->next;
  1680. UserFreePool(pflPrev);
  1681. }
  1682. }
  1683. /************************************************************************
  1684. * PopState
  1685. *
  1686. * Frees spxsOut from pDdeConv and handles empty queue case.
  1687. *
  1688. * History:
  1689. * 9-3-91 sanfords Created
  1690. \***********************************************************************/
  1691. VOID PopState(
  1692. PDDECONV pDdeConv)
  1693. {
  1694. PXSTATE pxsNext, pxsFree;
  1695. TL tlpxs;
  1696. UserAssert(pDdeConv->spxsOut != NULL);
  1697. #if 0
  1698. {
  1699. int i;
  1700. HANDLEENTRY *phe;
  1701. for (i = 0, phe = gSharedInfo.aheList;
  1702. i <= giheLast;
  1703. i++) {
  1704. if (phe[i].bType == TYPE_DDEXACT) {
  1705. UserAssert(((PXSTATE)(phe[i].phead))->snext != pDdeConv->spxsOut);
  1706. }
  1707. }
  1708. }
  1709. #endif
  1710. UserAssert(!(pDdeConv->spxsOut->flags & XS_FREEPXS));
  1711. UserAssert(pDdeConv->spxsIn != NULL);
  1712. UserAssert(pDdeConv->spxsIn->snext == NULL);
  1713. ThreadLockAlways(pDdeConv->spxsOut, &tlpxs); // hold it fast
  1714. pxsNext = pDdeConv->spxsOut->snext;
  1715. pxsFree = Lock(&(pDdeConv->spxsOut), pxsNext); // lock next into head
  1716. if (pxsNext == NULL) {
  1717. UserAssert(pDdeConv->spxsIn == pxsFree);
  1718. Unlock(&(pDdeConv->spxsIn)); // queue is empty.
  1719. } else {
  1720. Unlock(&(pxsFree->snext)); // clear next ptr
  1721. }
  1722. pxsFree = ThreadUnlock(&tlpxs); // undo our lock
  1723. if (pxsFree != NULL) {
  1724. FreeDdeXact(pxsFree); // cleanup.
  1725. }
  1726. }
  1727. VOID FreeDdeConv(
  1728. PDDECONV pDdeConv)
  1729. {
  1730. TRACE_DDE1("FreeDdeConv(%#p)", pDdeConv);
  1731. if (!(pDdeConv->flags & CXF_TERMINATE_POSTED) &&
  1732. !HMIsMarkDestroy(pDdeConv->spwndPartner)) {
  1733. _PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE,
  1734. (WPARAM)PtoH(pDdeConv->spwnd), 0);
  1735. // pDdeConv->flags |= CXF_TERMINATE_POSTED; set by PostHookProc
  1736. }
  1737. if (pDdeConv->spartnerConv != NULL &&
  1738. GETPTI(pDdeConv)->TIF_flags & TIF_INCLEANUP) {
  1739. /*
  1740. * Fake that the other side already posted a terminate.
  1741. * This prevents vestigal dde structures from hanging
  1742. * around after thread cleanup if the conversation structure
  1743. * is destroyed before the associated window.
  1744. */
  1745. pDdeConv->spartnerConv->flags |= CXF_TERMINATE_POSTED;
  1746. }
  1747. UnlinkConv(pDdeConv);
  1748. if (pDdeConv->pddei != NULL) {
  1749. pDdeConv->pddei->cRefConv--;
  1750. if (pDdeConv->pddei->cRefConv == 0 && pDdeConv->pddei->cRefInit == 0) {
  1751. SeDeleteClientSecurity(&pDdeConv->pddei->ClientContext);
  1752. UserFreePool(pDdeConv->pddei);
  1753. }
  1754. pDdeConv->pddei = NULL;
  1755. }
  1756. Unlock(&(pDdeConv->spartnerConv));
  1757. Unlock(&(pDdeConv->spwndPartner));
  1758. Unlock(&(pDdeConv->spwnd));
  1759. if (!HMMarkObjectDestroy((PHEAD)pDdeConv))
  1760. return;
  1761. while (pDdeConv->spxsOut) {
  1762. PopState(pDdeConv);
  1763. }
  1764. HMFreeObject(pDdeConv);
  1765. }
  1766. /***************************************************************************\
  1767. * xxxCopyDdeIn
  1768. *
  1769. * Description:
  1770. * Copies DDE data from the CSR client to the CSR server side.
  1771. * Crosses the CSR barrier as many times as is needed to get all the data
  1772. * through the CSR window.
  1773. *
  1774. * History:
  1775. * 11-1-91 sanfords Created.
  1776. \***************************************************************************/
  1777. DWORD xxxCopyDdeIn(
  1778. HANDLE hSrc,
  1779. PDWORD pflags,
  1780. PHANDLE phDirect,
  1781. PINTDDEINFO *ppi)
  1782. {
  1783. DWORD dwRet;
  1784. PINTDDEINFO pi;
  1785. dwRet = xxxClientCopyDDEIn1(hSrc, *pflags, ppi);
  1786. pi = *ppi;
  1787. TRACE_DDE2(*pflags & XS_FREESRC ?
  1788. "Copying in and freeing %#p(%#p)" :
  1789. "Copying in %#p(%#p)",
  1790. hSrc, pi ? pi->hDirect : 0);
  1791. if (dwRet == DO_POST) {
  1792. UserAssert(*ppi != NULL);
  1793. *pflags = pi->flags;
  1794. TRACE_DDE3("xxxCopyDdeIn: uiLo=%x, uiHi=%x, hDirect=%#p",
  1795. pi->DdePack.uiLo, pi->DdePack.uiHi, pi->hDirect);
  1796. if (phDirect != NULL) {
  1797. *phDirect = pi->hDirect;
  1798. }
  1799. }
  1800. #if DBG
  1801. else {
  1802. RIPMSG0(RIP_WARNING, "Unable to alloc DDE INTDDEINFO");
  1803. }
  1804. #endif
  1805. return dwRet;
  1806. }
  1807. /***********************************************************************\
  1808. * xxxCopyDDEOut
  1809. *
  1810. * Returns: the apropriate client side handle for lParam or NULL on
  1811. * failure. (Since only TERMINATES should have 0 here)
  1812. *
  1813. * 11/7/1995 Created SanfordS
  1814. \***********************************************************************/
  1815. HANDLE xxxCopyDDEOut(
  1816. PINTDDEINFO pi,
  1817. PHANDLE phDirect) // receives the target client side GMEM handle.
  1818. {
  1819. HANDLE hDst;
  1820. TRACE_DDE3("xxxCopyDDEOut: cbDirect=%x, cbIndirect=%x, flags=%x",
  1821. pi->cbDirect, pi->cbIndirect, pi->flags);
  1822. hDst = xxxClientCopyDDEOut1(pi);
  1823. TRACE_DDE3("xxxCopyDDEOut: uiLo=%x, uiHi=%x, hResult=%#p",
  1824. pi->DdePack.uiLo, pi->DdePack.uiHi, hDst);
  1825. if (hDst != NULL) {
  1826. if (phDirect != NULL) {
  1827. TRACE_DDE1("xxxCopyDDEOut: *phDirect=%#p", pi->hDirect);
  1828. *phDirect = pi->hDirect;
  1829. }
  1830. }
  1831. return hDst;
  1832. }
  1833. /*
  1834. * This API is used to set the QOS associated with a potential DDE client window.
  1835. * It should be called prior to sending a WM_DDE_INITIATE message and the qos set
  1836. * will hold until the WM_DDE_INITIATE send or broadcast returns.
  1837. */
  1838. BOOL _DdeSetQualityOfService(
  1839. PWND pwndClient,
  1840. CONST PSECURITY_QUALITY_OF_SERVICE pqosNew,
  1841. PSECURITY_QUALITY_OF_SERVICE pqosOld)
  1842. {
  1843. PSECURITY_QUALITY_OF_SERVICE pqosUser;
  1844. PSECURITY_QUALITY_OF_SERVICE pqosAlloc = NULL;
  1845. BOOL fRet;
  1846. /*
  1847. * ASSUME: calling process is owner of pwndClient - ensured in thunk.
  1848. */
  1849. pqosUser = (PSECURITY_QUALITY_OF_SERVICE)InternalRemoveProp(pwndClient,
  1850. PROP_QOS, PROPF_INTERNAL);
  1851. if (pqosUser == NULL) {
  1852. if (RtlEqualMemory(pqosNew, &gqosDefault, sizeof(SECURITY_QUALITY_OF_SERVICE))) {
  1853. return TRUE; // no PROP_QOS property implies default QOS
  1854. }
  1855. pqosAlloc = (PSECURITY_QUALITY_OF_SERVICE)UserAllocPoolZInit(
  1856. sizeof(SECURITY_QUALITY_OF_SERVICE), TAG_DDE2);
  1857. if (pqosAlloc == NULL) {
  1858. return FALSE; // memory allocation failure - can't change from default
  1859. }
  1860. pqosUser = pqosAlloc;
  1861. }
  1862. *pqosOld = *pqosUser;
  1863. *pqosUser = *pqosNew;
  1864. fRet = InternalSetProp(pwndClient, PROP_QOS, pqosUser, PROPF_INTERNAL);
  1865. if ((fRet == FALSE) && (pqosAlloc != NULL)) {
  1866. UserFreePool(pqosAlloc);
  1867. }
  1868. return fRet;
  1869. }
  1870. /*
  1871. * This is a private API for NetDDE's use. It extracts the QOS associated with an
  1872. * active DDE conversation. Intra-process conversations always are set to the default
  1873. * QOS.
  1874. */
  1875. BOOL _DdeGetQualityOfService(
  1876. PWND pwndClient,
  1877. PWND pwndServer,
  1878. PSECURITY_QUALITY_OF_SERVICE pqos)
  1879. {
  1880. PDDECONV pDdeConv;
  1881. PSECURITY_QUALITY_OF_SERVICE pqosClient;
  1882. if (pwndServer == NULL) {
  1883. /*
  1884. * Special case to support DDEML-RAW conversations that need to get
  1885. * the QOS prior to initiation completion.
  1886. */
  1887. pqosClient = _GetProp(pwndClient, PROP_QOS, PROPF_INTERNAL);
  1888. if (pqosClient == NULL) {
  1889. *pqos = gqosDefault;
  1890. } else {
  1891. *pqos = *pqosClient;
  1892. }
  1893. return TRUE;
  1894. }
  1895. if (GETPWNDPPI(pwndClient) == GETPWNDPPI(pwndServer)) {
  1896. *pqos = gqosDefault;
  1897. return TRUE;
  1898. }
  1899. pDdeConv = FindDdeConv(pwndClient, pwndServer);
  1900. if (pDdeConv == NULL) {
  1901. return FALSE;
  1902. }
  1903. if (pDdeConv->pddei == NULL) {
  1904. return FALSE;
  1905. }
  1906. *pqos = pDdeConv->pddei->qos;
  1907. return TRUE;
  1908. }
  1909. BOOL _ImpersonateDdeClientWindow(
  1910. PWND pwndClient,
  1911. PWND pwndServer)
  1912. {
  1913. PDDECONV pDdeConv;
  1914. NTSTATUS Status;
  1915. /*
  1916. * Locate token used in the conversation
  1917. */
  1918. pDdeConv = FindDdeConv(pwndClient, pwndServer);
  1919. if (pDdeConv == NULL || pDdeConv->pddei == NULL)
  1920. return FALSE;
  1921. /*
  1922. * Stick the token into the dde server thread
  1923. */
  1924. Status = SeImpersonateClientEx(&pDdeConv->pddei->ClientContext,
  1925. PsGetCurrentThread());
  1926. if (!NT_SUCCESS(Status)) {
  1927. RIPNTERR0(Status, RIP_VERBOSE, "");
  1928. return FALSE;
  1929. }
  1930. return TRUE;
  1931. }
  1932. VOID FreeDdeXact(
  1933. PXSTATE pxs)
  1934. {
  1935. if (!HMMarkObjectDestroy(pxs)) {
  1936. return;
  1937. }
  1938. #if 0
  1939. {
  1940. int i;
  1941. HANDLEENTRY *phe;
  1942. for (i = 0, phe = gSharedInfo.aheList; i <= giheLast; i++) {
  1943. if (phe[i].bType == TYPE_DDEXACT) {
  1944. UserAssert(((PXSTATE)(phe[i].phead))->snext != pxs);
  1945. } else if (phe[i].bType == TYPE_DDECONV) {
  1946. UserAssert(((PDDECONV)(phe[i].phead))->spxsOut != pxs);
  1947. UserAssert(((PDDECONV)(phe[i].phead))->spxsIn != pxs);
  1948. }
  1949. }
  1950. }
  1951. UserAssert(pxs->head.cLockObj == 0);
  1952. UserAssert(pxs->snext == NULL);
  1953. #endif
  1954. if (pxs->pIntDdeInfo != NULL) {
  1955. /*
  1956. * free any server-side GDI objects
  1957. */
  1958. if (pxs->pIntDdeInfo->flags & (XS_METAFILEPICT | XS_ENHMETAFILE)) {
  1959. GreDeleteServerMetaFile(pxs->pIntDdeInfo->hIndirect);
  1960. }
  1961. if (pxs->flags & XS_PUBLICOBJ) {
  1962. RemovePublicObject(((PDDE_DATA)(pxs->pIntDdeInfo + 1))->wFmt,
  1963. pxs->pIntDdeInfo->hIndirect);
  1964. pxs->flags &= ~XS_PUBLICOBJ;
  1965. }
  1966. UserFreePool(pxs->pIntDdeInfo);
  1967. }
  1968. HMFreeObject(pxs);
  1969. ValidatePublicObjectList();
  1970. }
  1971. PPUBOBJ IsObjectPublic(
  1972. HANDLE hObj)
  1973. {
  1974. PPUBOBJ ppo;
  1975. for (ppo = gpPublicObjectList; ppo != NULL; ppo = ppo->next) {
  1976. if (ppo->hObj == hObj) {
  1977. break;
  1978. }
  1979. }
  1980. return ppo;
  1981. }
  1982. BOOL AddPublicObject(
  1983. UINT format,
  1984. HANDLE hObj,
  1985. W32PID pid)
  1986. {
  1987. PPUBOBJ ppo;
  1988. switch (format) {
  1989. case CF_BITMAP:
  1990. case CF_DSPBITMAP:
  1991. case CF_PALETTE:
  1992. break;
  1993. default:
  1994. return FALSE;
  1995. }
  1996. ppo = IsObjectPublic(hObj);
  1997. if (ppo == NULL) {
  1998. ppo = UserAllocPool(sizeof(PUBOBJ), TAG_DDE4);
  1999. if (ppo == NULL) {
  2000. return FALSE;
  2001. }
  2002. ppo->count = 1;
  2003. ppo->hObj = hObj;
  2004. ppo->pid = pid;
  2005. ppo->next = gpPublicObjectList;
  2006. gpPublicObjectList = ppo;
  2007. GiveObject(format, hObj, OBJECT_OWNER_PUBLIC);
  2008. } else {
  2009. ppo->count++;
  2010. }
  2011. return TRUE;
  2012. }
  2013. BOOL RemovePublicObject(
  2014. UINT format,
  2015. HANDLE hObj)
  2016. {
  2017. PPUBOBJ ppo, ppoPrev;
  2018. switch (format) {
  2019. case CF_BITMAP:
  2020. case CF_DSPBITMAP:
  2021. case CF_PALETTE:
  2022. break;
  2023. default:
  2024. return FALSE;
  2025. }
  2026. for (ppoPrev = NULL, ppo = gpPublicObjectList;
  2027. ppo != NULL;
  2028. ppoPrev = ppo, ppo = ppo->next) {
  2029. if (ppo->hObj == hObj) {
  2030. break;
  2031. }
  2032. }
  2033. if (ppo == NULL) {
  2034. UserAssert(FALSE);
  2035. return FALSE;
  2036. }
  2037. ppo->count--;
  2038. if (ppo->count == 0) {
  2039. GiveObject(format, hObj, ppo->pid);
  2040. if (ppoPrev != NULL) {
  2041. ppoPrev->next = ppo->next;
  2042. } else {
  2043. gpPublicObjectList = ppo->next;
  2044. }
  2045. UserFreePool(ppo);
  2046. }
  2047. return TRUE;
  2048. }
  2049. BOOL
  2050. GiveObject(
  2051. UINT format,
  2052. HANDLE hObj,
  2053. W32PID pid)
  2054. {
  2055. switch (format) {
  2056. case CF_BITMAP:
  2057. case CF_DSPBITMAP:
  2058. GreSetBitmapOwner(hObj, pid);
  2059. return TRUE;
  2060. case CF_PALETTE:
  2061. GreSetPaletteOwner(hObj, pid);
  2062. return TRUE;
  2063. default:
  2064. return FALSE;
  2065. }
  2066. }
  2067. #if DBG
  2068. VOID ValidatePublicObjectList()
  2069. {
  2070. PPUBOBJ ppo;
  2071. int i, count;
  2072. HANDLEENTRY *phe;
  2073. for (count = 0, ppo = gpPublicObjectList;
  2074. ppo != NULL;
  2075. ppo = ppo->next) {
  2076. count += ppo->count;
  2077. }
  2078. for (i = 0, phe = gSharedInfo.aheList;
  2079. i <= (int)giheLast;
  2080. i++) {
  2081. if (phe[i].bType == TYPE_DDEXACT) {
  2082. if (((PXSTATE)(phe[i].phead))->flags & XS_PUBLICOBJ) {
  2083. UserAssert(((PXSTATE)(phe[i].phead))->pIntDdeInfo != NULL);
  2084. UserAssert(IsObjectPublic(((PXSTATE)
  2085. (phe[i].phead))->pIntDdeInfo->hIndirect) != NULL);
  2086. count--;
  2087. }
  2088. }
  2089. }
  2090. UserAssert(count == 0);
  2091. }
  2092. VOID TraceDdeMsg(
  2093. UINT msg,
  2094. HWND hwndFrom,
  2095. HWND hwndTo,
  2096. UINT code)
  2097. {
  2098. LPSTR szMsg, szType;
  2099. msg = msg & 0xFFFF;
  2100. switch (msg) {
  2101. case WM_DDE_INITIATE:
  2102. szMsg = "INITIATE";
  2103. break;
  2104. case WM_DDE_TERMINATE:
  2105. szMsg = "TERMINATE";
  2106. break;
  2107. case WM_DDE_ADVISE:
  2108. szMsg = "ADVISE";
  2109. break;
  2110. case WM_DDE_UNADVISE:
  2111. szMsg = "UNADVISE";
  2112. break;
  2113. case WM_DDE_ACK:
  2114. szMsg = "ACK";
  2115. break;
  2116. case WM_DDE_DATA:
  2117. szMsg = "DATA";
  2118. break;
  2119. case WM_DDE_REQUEST:
  2120. szMsg = "REQUEST";
  2121. break;
  2122. case WM_DDE_POKE:
  2123. szMsg = "POKE";
  2124. break;
  2125. case WM_DDE_EXECUTE:
  2126. szMsg = "EXECUTE";
  2127. break;
  2128. default:
  2129. szMsg = "BOGUS";
  2130. UserAssert(msg >= WM_DDE_FIRST && msg <= WM_DDE_LAST);
  2131. break;
  2132. }
  2133. switch (code) {
  2134. case MSG_SENT:
  2135. szType = "[sent]";
  2136. break;
  2137. case MSG_POST:
  2138. szType = "[posted]";
  2139. break;
  2140. case MSG_RECV:
  2141. szType = "[received]";
  2142. break;
  2143. case MSG_PEEK:
  2144. szType = "[peeked]";
  2145. break;
  2146. default:
  2147. szType = "[bogus]";
  2148. UserAssert(FALSE);
  2149. break;
  2150. }
  2151. RIPMSG4(RIP_VERBOSE,
  2152. "%#p->%#p WM_DDE_%s %s",
  2153. hwndFrom, hwndTo, szMsg, szType);
  2154. }
  2155. #endif //DBG