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.

1524 lines
45 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: connect.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * DDE Manager conversation connection functions
  7. *
  8. * Created: 11/3/91 Sanford Staab
  9. *
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "nddeagnt.h"
  14. //#define TESTING
  15. #ifdef TESTING
  16. ULONG
  17. DbgPrint(
  18. PCH Format,
  19. ...
  20. );
  21. VOID
  22. DbgUserBreakPoint(
  23. VOID
  24. );
  25. BOOL ValidateConvList(
  26. HCONVLIST hConvList)
  27. {
  28. PCONVLIST pcl;
  29. PCL_CONV_INFO pci;
  30. PXACT_INFO pxi;
  31. int i;
  32. BOOL fMatch;
  33. if (hConvList == 0) {
  34. return(TRUE);
  35. }
  36. pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList,
  37. HTYPE_CONVERSATION_LIST,
  38. HINST_ANY);
  39. for (i = 0; i < pcl->chwnd; i++) {
  40. /*
  41. * all windows in the list are valid
  42. */
  43. if (!IsWindow(pcl->ahwnd[i])) {
  44. DebugBreak();
  45. }
  46. pci = (PCL_CONV_INFO)GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI);
  47. /*
  48. * All windows have at least one convinfo associated with them.
  49. */
  50. if (pci == NULL) {
  51. DebugBreak();
  52. }
  53. fMatch = FALSE;
  54. while (pci != NULL) {
  55. /*
  56. * All non-zombie conversations have hConvList set correctly.
  57. */
  58. if (pci->hConvList != hConvList &&
  59. TypeFromHandle(pci->ci.hConv) != HTYPE_ZOMBIE_CONVERSATION) {
  60. DebugBreak();
  61. }
  62. /*
  63. * All conversations have hConvList clear or set correctly.
  64. */
  65. if (pci->hConvList != 0 && pci->hConvList != hConvList) {
  66. DebugBreak();
  67. }
  68. /*
  69. * At least 1 of the conversations references the list
  70. */
  71. if (pci->hConvList == hConvList) {
  72. fMatch = TRUE;
  73. }
  74. for (pxi = pci->ci.pxiOut; pxi; pxi = pxi->next) {
  75. if ((PCL_CONV_INFO)pxi->pcoi != pci) {
  76. DebugBreak();
  77. }
  78. }
  79. pci = (PCL_CONV_INFO)pci->ci.next;
  80. }
  81. if (!fMatch) {
  82. /*
  83. * At least 1 of the conversations references the list
  84. */
  85. DebugBreak;
  86. }
  87. }
  88. return(TRUE);
  89. }
  90. VOID ValidateAllConvLists()
  91. {
  92. ApplyFunctionToObjects(HTYPE_CONVERSATION_LIST, HINST_ANY,
  93. (PFNHANDLEAPPLY)ValidateConvList);
  94. }
  95. #else // TESTING
  96. #define ValidateConvList(h)
  97. #define ValidateAllConvLists()
  98. #endif // TESTING
  99. CONVCONTEXT TempConvContext;
  100. CONVCONTEXT DefConvContext = {
  101. sizeof(CONVCONTEXT),
  102. 0,
  103. 0,
  104. CP_WINANSI,
  105. 0L,
  106. 0L,
  107. {
  108. sizeof(SECURITY_QUALITY_OF_SERVICE),
  109. SecurityImpersonation,
  110. SECURITY_STATIC_TRACKING,
  111. TRUE
  112. }
  113. };
  114. typedef struct tagINIT_ENUM {
  115. HWND hwndClient;
  116. HWND hwndSkip;
  117. LONG lParam;
  118. LATOM laServiceRequested;
  119. LATOM laTopic;
  120. HCONVLIST hConvList;
  121. DWORD clst;
  122. } INIT_ENUM, *PINIT_ENUM;
  123. BOOL InitiateEnumerationProc(HWND hwndTarget, PINIT_ENUM pie);
  124. VOID DisconnectConv(PCONV_INFO pcoi);
  125. /***************************************************************************\
  126. * DdeConnect (DDEML API)
  127. *
  128. * Description:
  129. * Initiates a DDE conversation.
  130. *
  131. * History:
  132. * 11-1-91 sanfords Created.
  133. \***************************************************************************/
  134. FUNCLOG4(LOG_GENERAL, HCONV, DUMMYCALLINGTYPE, DdeConnect, DWORD, idInst, HSZ, hszService, HSZ, hszTopic, PCONVCONTEXT, pCC)
  135. HCONV DdeConnect(
  136. DWORD idInst,
  137. HSZ hszService,
  138. HSZ hszTopic,
  139. PCONVCONTEXT pCC)
  140. {
  141. PCL_INSTANCE_INFO pcii;
  142. PCL_CONV_INFO pci;
  143. HCONV hConvRet = 0;
  144. HWND hwndTarget = 0;
  145. LATOM aNormalSvcName = 0;
  146. EnterDDECrit;
  147. if (!ValidateConnectParameters((HANDLE)LongToHandle( idInst ), &pcii, &hszService, hszTopic,
  148. &aNormalSvcName, &pCC, &hwndTarget, 0)) {
  149. goto Exit;
  150. }
  151. pci = ConnectConv(pcii, LATOM_FROM_HSZ(hszService), LATOM_FROM_HSZ(hszTopic),
  152. hwndTarget,
  153. (pcii->afCmd & CBF_FAIL_SELFCONNECTIONS) ? pcii->hwndMother : 0,
  154. pCC, 0, CLST_SINGLE_INITIALIZING);
  155. if (pci == NULL) {
  156. SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED);
  157. goto Exit;
  158. } else {
  159. hConvRet = pci->ci.hConv;
  160. }
  161. Exit:
  162. if (aNormalSvcName) {
  163. GlobalDeleteAtom(aNormalSvcName);
  164. }
  165. LeaveDDECrit;
  166. return (hConvRet);
  167. }
  168. /***************************************************************************\
  169. * DdeConnectList (DDEML API)
  170. *
  171. * Description:
  172. * Initiates DDE conversations with multiple servers or adds unique servers
  173. * to an existing conversation list.
  174. *
  175. * History:
  176. * 11-12-91 sanfords Created.
  177. \***************************************************************************/
  178. FUNCLOG5(LOG_GENERAL, HCONVLIST, DUMMYCALLINGTYPE, DdeConnectList, DWORD, idInst, HSZ, hszService, HSZ, hszTopic, HCONVLIST, hConvList, PCONVCONTEXT, pCC)
  179. HCONVLIST DdeConnectList(
  180. DWORD idInst,
  181. HSZ hszService,
  182. HSZ hszTopic,
  183. HCONVLIST hConvList,
  184. PCONVCONTEXT pCC)
  185. {
  186. PCL_INSTANCE_INFO pcii;
  187. PCONV_INFO pcoi, pcoiNew, pcoiExisting, pcoiNext;
  188. HCONVLIST hConvListRet = 0;
  189. HWND hwndTarget = 0;
  190. LATOM aNormalSvcName = 0;
  191. PCONVLIST pcl = NULL, pclTemp = NULL;
  192. HCONVLIST hConvListOld;
  193. int i;
  194. CheckDDECritOut;
  195. EnterDDECrit;
  196. if (!ValidateConnectParameters((HANDLE)LongToHandle( idInst ), &pcii, &hszService, hszTopic,
  197. &aNormalSvcName, &pCC, &hwndTarget, hConvList)) {
  198. goto Exit;
  199. }
  200. ValidateConvList(hConvList);
  201. hConvListOld = hConvList;
  202. pcoi = (PCONV_INFO)ConnectConv(pcii,
  203. LATOM_FROM_HSZ(hszService),
  204. LATOM_FROM_HSZ(hszTopic),
  205. hwndTarget,
  206. (pcii->afCmd & (CBF_FAIL_SELFCONNECTIONS | CBF_FAIL_CONNECTIONS)) ?
  207. pcii->hwndMother : 0,
  208. pCC,
  209. hConvListOld,
  210. CLST_MULT_INITIALIZING);
  211. if (pcoi == NULL) {
  212. /*
  213. * no new connections made
  214. */
  215. SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED);
  216. hConvListRet = hConvListOld;
  217. goto Exit;
  218. }
  219. /*
  220. * allocate or reallocate the hConvList hwnd list for later addition
  221. * If we already have a valid list, reuse the handle so we don't have
  222. * to alter the preexisting pcoi->hConvList values.
  223. */
  224. if (hConvListOld == 0) {
  225. pcl = (PCONVLIST)DDEMLAlloc(sizeof(CONVLIST));
  226. if (pcl == NULL) {
  227. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  228. DisconnectConv(pcoi);
  229. goto Exit;
  230. }
  231. // pcl->chwnd = 0; LPTR zero inits.
  232. hConvList = (HCONVLIST)CreateHandle((ULONG_PTR)pcl,
  233. HTYPE_CONVERSATION_LIST, InstFromHandle(pcii->hInstClient));
  234. if (hConvList == 0) {
  235. DDEMLFree(pcl);
  236. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  237. DisconnectConv(pcoi);
  238. goto Exit;
  239. }
  240. } else {
  241. pcl = (PCONVLIST)GetHandleData((HANDLE)hConvList);
  242. pclTemp = DDEMLReAlloc(pcl, sizeof(CONVLIST) + sizeof(HWND) * pcl->chwnd);
  243. if (pclTemp == NULL) {
  244. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  245. hConvListRet = hConvListOld;
  246. DisconnectConv(pcoi);
  247. goto Exit;
  248. }
  249. pcl = pclTemp;
  250. SetHandleData((HANDLE)hConvList, (ULONG_PTR)pcl);
  251. }
  252. ValidateConvList(hConvListOld);
  253. if (hConvListOld) {
  254. /*
  255. * remove duplicates from new conversations
  256. *
  257. * Although we tried to prevent duplicates from happening
  258. * within the initiate enumeration code, wild initiates or
  259. * servers responding with different service names than
  260. * requested could cause duplicates.
  261. */
  262. /* For each client window... */
  263. for (i = 0; i < pcl->chwnd; i++) {
  264. /* For each existing conversation in that window... */
  265. for (pcoiExisting = (PCONV_INFO)
  266. GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI);
  267. pcoi != NULL && pcoiExisting != NULL;
  268. pcoiExisting = pcoiExisting->next) {
  269. if (!(pcoiExisting->state & ST_CONNECTED))
  270. continue;
  271. /* For each new conversation... */
  272. for (pcoiNew = pcoi; pcoiNew != NULL; pcoiNew = pcoiNext) {
  273. pcoiNext = pcoiNew->next;
  274. /* see if the new conversation duplicates the existing one */
  275. if (!(pcoiNew->state & ST_CONNECTED))
  276. continue;
  277. UserAssert(((PCL_CONV_INFO)pcoiExisting)->hwndReconnect);
  278. UserAssert(((PCL_CONV_INFO)pcoiNew)->hwndReconnect);
  279. if (((PCL_CONV_INFO)pcoiExisting)->hwndReconnect ==
  280. ((PCL_CONV_INFO)pcoiNew)->hwndReconnect &&
  281. pcoiExisting->laTopic == pcoiNew->laTopic &&
  282. pcoiExisting->laService == pcoiNew->laService) {
  283. /*
  284. * duplicate conversation - disconnection causes an unlink
  285. */
  286. if (pcoiNew == pcoi) {
  287. /*
  288. * We are freeing up the head of the list,
  289. * Reset the head to the next guy.
  290. */
  291. pcoi = pcoiNext;
  292. }
  293. ValidateConvList(hConvList);
  294. ShutdownConversation(pcoiNew, FALSE);
  295. ValidateConvList(hConvList);
  296. break;
  297. }
  298. }
  299. }
  300. }
  301. for (pcoiExisting = pcoi; pcoiExisting != NULL; pcoiExisting = pcoiExisting->next) {
  302. /*
  303. * if these are all zombies - we DONT want to link it in!
  304. * This is possible because ShutdownConversation() leaves the critical section
  305. * and could allow responding terminates to come through.
  306. */
  307. if (pcoiExisting->state & ST_CONNECTED) {
  308. goto FoundOne;
  309. }
  310. }
  311. pcoi = NULL; // abandon this guy - he will clean up in time.
  312. FoundOne:
  313. /*
  314. * add new pcoi (if any are left) hwnd to ConvList hwnd list.
  315. */
  316. if (pcoi != NULL) {
  317. UserAssert(pcoi->hwndConv);
  318. pcl->ahwnd[pcl->chwnd] = pcoi->hwndConv;
  319. pcl->chwnd++;
  320. hConvListRet = hConvList;
  321. } else {
  322. hConvListRet = hConvListOld;
  323. if (!hConvListOld) {
  324. DestroyHandle((HANDLE)hConvList);
  325. }
  326. }
  327. } else { // no hConvListOld
  328. UserAssert(pcoi->hwndConv);
  329. pcl->ahwnd[0] = pcoi->hwndConv;
  330. pcl->chwnd = 1;
  331. hConvListRet = hConvList;
  332. }
  333. if (pcoi != NULL) {
  334. /*
  335. * set hConvList field for all remaining new conversations.
  336. */
  337. UserAssert(hConvListRet);
  338. for (pcoiNew = pcoi; pcoiNew != NULL; pcoiNew = pcoiNew->next) {
  339. if (pcoiNew->state & ST_CONNECTED) {
  340. ((PCL_CONV_INFO)pcoiNew)->hConvList = hConvListRet;
  341. }
  342. }
  343. }
  344. Exit:
  345. if (aNormalSvcName) {
  346. DeleteAtom(aNormalSvcName);
  347. }
  348. ValidateConvList(hConvListRet);
  349. LeaveDDECrit;
  350. return (hConvListRet);
  351. }
  352. /***************************************************************************\
  353. * DdeReconnect (DDEML API)
  354. *
  355. * Description:
  356. * Attempts to reconnect an externally (from the server) terminated
  357. * client side conversation.
  358. *
  359. * History:
  360. * 11-12-91 sanfords Created.
  361. \***************************************************************************/
  362. FUNCLOG1(LOG_GENERAL, HCONV, DUMMYCALLINGTYPE, DdeReconnect, HCONV, hConv)
  363. HCONV DdeReconnect(
  364. HCONV hConv)
  365. {
  366. PCL_INSTANCE_INFO pcii;
  367. PCL_CONV_INFO pci, pciNew;
  368. HCONV hConvRet = 0;
  369. CONVCONTEXT cc;
  370. EnterDDECrit;
  371. pcii = PciiFromHandle((HANDLE)hConv);
  372. if (pcii == NULL) {
  373. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  374. goto Exit;
  375. }
  376. pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConv,
  377. HTYPE_CLIENT_CONVERSATION, HINST_ANY);
  378. if (pci == NULL) {
  379. SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
  380. goto Exit;
  381. }
  382. if (pci->ci.state & ST_CONNECTED) {
  383. goto Exit;
  384. }
  385. GetConvContext(pci->ci.hwndConv, (LONG *)&cc);
  386. pciNew = ConnectConv(pcii, pci->ci.laService, pci->ci.laTopic,
  387. pci->hwndReconnect, 0, &cc, 0, CLST_SINGLE_INITIALIZING);
  388. if (pciNew == NULL) {
  389. SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED);
  390. goto Exit;
  391. } else {
  392. hConvRet = pciNew->ci.hConv;
  393. if (pci->ci.cLinks) {
  394. PXACT_INFO pxi;
  395. int iLink;
  396. PADVISE_LINK paLink;
  397. /*
  398. * reestablish advise links
  399. */
  400. for (paLink = pci->ci.aLinks, iLink = pci->ci.cLinks;
  401. iLink; paLink++, iLink--) {
  402. pxi = (PXACT_INFO)DDEMLAlloc(sizeof(XACT_INFO));
  403. if (pxi == NULL) {
  404. break; // abort relinking
  405. }
  406. pxi->pcoi = (PCONV_INFO)pciNew;
  407. pxi->gaItem = LocalToGlobalAtom(paLink->laItem); // pxi copy
  408. pxi->wFmt = paLink->wFmt;
  409. pxi->wType = (WORD)((paLink->wType >> 12) | XTYP_ADVSTART);
  410. if (ClStartAdvise(pxi)) {
  411. pxi->flags |= XIF_ABANDONED;
  412. } else {
  413. GlobalDeleteAtom(pxi->gaItem);
  414. DDEMLFree(pxi);
  415. }
  416. }
  417. }
  418. }
  419. Exit:
  420. LeaveDDECrit;
  421. return (hConvRet);
  422. }
  423. /***************************************************************************\
  424. * ValidateConnectParameters
  425. *
  426. * Description:
  427. * worker function to handle common validation code.
  428. *
  429. * Note that paNormalSvcName is set to the atom value created upon extracting
  430. * a normal HSZ from an InstanceSpecific HSZ.
  431. *
  432. * History:
  433. * 11-12-91 sanfords Created.
  434. \***************************************************************************/
  435. BOOL ValidateConnectParameters(
  436. HANDLE hInst,
  437. PCL_INSTANCE_INFO *ppcii, // set if valid hInst
  438. HSZ *phszService, // altered if InstSpecific HSZ
  439. HSZ hszTopic,
  440. LATOM *plaNormalSvcName, // set to atom that needs freeing when done
  441. PCONVCONTEXT *ppCC, // set to point to DefConvContext if NULL
  442. HWND *phwndTarget, // set if hszService is InstSpecific
  443. HCONVLIST hConvList)
  444. {
  445. DWORD hszType;
  446. BOOL fError = FALSE;
  447. *ppcii = ValidateInstance(hInst);
  448. if (*ppcii == NULL) {
  449. return (FALSE);
  450. }
  451. hszType = ValidateHSZ(*phszService);
  452. if (hszType == HSZT_INVALID || ValidateHSZ(hszTopic) == HSZT_INVALID) {
  453. SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER);
  454. return (FALSE);
  455. }
  456. if (hszType == HSZT_INST_SPECIFIC) {
  457. *phwndTarget = ParseInstSpecificAtom(LATOM_FROM_HSZ(*phszService),
  458. plaNormalSvcName);
  459. if (*plaNormalSvcName == 0) {
  460. SetLastDDEMLError(*ppcii, DMLERR_SYS_ERROR);
  461. return (FALSE);
  462. }
  463. *phszService = NORMAL_HSZ_FROM_LATOM(*plaNormalSvcName);
  464. }
  465. if (*ppCC == NULL) {
  466. *ppCC = &DefConvContext;
  467. if ((*ppcii)->flags & IIF_UNICODE) {
  468. (*ppCC)->iCodePage = CP_WINUNICODE;
  469. } else {
  470. (*ppCC)->iCodePage = CP_WINANSI;
  471. }
  472. } else try {
  473. if ((*ppCC)->cb > sizeof(CONVCONTEXT)) {
  474. SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER);
  475. fError = TRUE;
  476. } else if ((*ppCC)->cb < sizeof(CONVCONTEXT)) {
  477. TempConvContext = DefConvContext;
  478. /*
  479. * we can use this static temp because we are synchronized.
  480. */
  481. RtlCopyMemory(&TempConvContext, *ppCC, (*ppCC)->cb);
  482. *ppCC = &TempConvContext;
  483. }
  484. } except(W32ExceptionHandler(FALSE, RIP_WARNING)) {
  485. SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER);
  486. fError = TRUE;
  487. }
  488. if (fError) {
  489. return(FALSE);
  490. }
  491. if (hConvList != 0 &&
  492. !ValidateCHandle((HANDLE)hConvList, HTYPE_CONVERSATION_LIST,
  493. (DWORD)InstFromHandle((*ppcii)->hInstClient))) {
  494. return (FALSE);
  495. }
  496. return (TRUE);
  497. }
  498. /***************************************************************************\
  499. * ConnectConv
  500. *
  501. * Description:
  502. * Work function for all Connect cases.
  503. *
  504. * Method:
  505. *
  506. * To reduce the number of windows we use and to simplify how client
  507. * windows handle multiple WM_DDE_ACK messages during initiation, a
  508. * single client window can handle many conversations, each with
  509. * a different server window.
  510. *
  511. * The client window is created and set to a initiation state via the
  512. * GWL_CONVSTATE window word. Initiates are then sent to enumerated server
  513. * window candidates.
  514. * The GWL_CONVSTATE value is used by the DDEML mother windows
  515. * to determine if only one or several ACKs are desired to minimize
  516. * unnessary message traffic.
  517. *
  518. * The client window GWL_CONVCONTEXT? window words are also used by
  519. * Event Windows to pass context information.
  520. *
  521. * Note that all client and server windows are children of the mother
  522. * window. This reduces the number of top level windows that
  523. * WM_DDE_INITIATES need to hit.
  524. *
  525. * Each WM_DDE_ACK that is received by a client window while in the
  526. * initiation state causes it to create a CL_CONV_INFO structure,
  527. * partially initialize it, and link it into its list of CL_CONV_INFO
  528. * structures. The head of the list is pointed to by the GWLP_PCI
  529. * client window word.
  530. *
  531. * After each WM_DDE_INITIALIZE is sent, the GWLP_PCI value is checked
  532. * to see if it exists and needs initialization to be completed. If
  533. * this is the case the init code knows that at least one ACK was
  534. * received in response to the WM_DDE_INITIALIZE send. The
  535. * initialization of each CL_CONV_INFO struct that needs it is then completed.
  536. *
  537. * Once the broadcasting of WM_DDE_INITIALIZE is done, the init code
  538. * then sets the GWL_CONVSTATE value in the client window to indicate that
  539. * initialization is complete.
  540. *
  541. * Returns:
  542. * The head pci to the client window or NULL if no connections made it.
  543. *
  544. * History:
  545. * 11-1-91 sanfords Created.
  546. \***************************************************************************/
  547. PCL_CONV_INFO ConnectConv(
  548. PCL_INSTANCE_INFO pcii,
  549. LATOM laService,
  550. LATOM laTopic,
  551. HWND hwndTarget, // 0 implies broadcast
  552. HWND hwndSkip, // 0 implies no skips - avoids self-connections.
  553. PCONVCONTEXT pCC,
  554. HCONVLIST hConvList,
  555. DWORD clst)
  556. {
  557. INIT_ENUM ie;
  558. PCL_CONV_INFO pci;
  559. PCONV_INFO pcoi;
  560. GATOM gaService, gaTopic;
  561. CheckDDECritIn;
  562. if (hwndTarget && hwndTarget == hwndSkip) {
  563. return(NULL);
  564. }
  565. LeaveDDECrit;
  566. CheckDDECritOut;
  567. if (pcii->flags & IIF_UNICODE) {
  568. ie.hwndClient = CreateWindowW((LPWSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTW]),
  569. L"",
  570. WS_CHILD,
  571. 0, 0, 0, 0,
  572. pcii->hwndMother,
  573. (HMENU)0,
  574. (HANDLE)0,
  575. (LPVOID)NULL);
  576. } else {
  577. ie.hwndClient = CreateWindowA((LPSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTA]),
  578. "",
  579. WS_CHILD,
  580. 0, 0, 0, 0,
  581. pcii->hwndMother,
  582. (HMENU)0,
  583. (HANDLE)0,
  584. (LPVOID)NULL);
  585. }
  586. EnterDDECrit;
  587. if (ie.hwndClient == 0) {
  588. return (NULL);
  589. }
  590. if (pCC != NULL) {
  591. if (!NtUserDdeSetQualityOfService(ie.hwndClient, &(pCC->qos), NULL)) {
  592. SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
  593. goto Error;
  594. }
  595. }
  596. /*
  597. * Note that a pci will be created and allocated for each ACK recieved.
  598. */
  599. SetConvContext(ie.hwndClient, (LONG *)pCC);
  600. SetWindowLong(ie.hwndClient, GWL_CONVSTATE, clst);
  601. SetWindowLongPtr(ie.hwndClient, GWLP_SHINST, (LONG_PTR)pcii->hInstServer);
  602. SetWindowLongPtr(ie.hwndClient, GWLP_CHINST, (LONG_PTR)pcii->hInstClient);
  603. gaService = LocalToGlobalAtom(laService);
  604. gaTopic = LocalToGlobalAtom(laTopic);
  605. ie.lParam = MAKELONG(gaService, gaTopic);
  606. if (!hwndTarget) {
  607. ie.hwndSkip = hwndSkip;
  608. ie.laServiceRequested = laService;
  609. ie.laTopic = laTopic;
  610. ie.hConvList = hConvList;
  611. ie.clst = clst;
  612. }
  613. LeaveDDECrit;
  614. if (hwndTarget) {
  615. SendMessage(hwndTarget, WM_DDE_INITIATE, (WPARAM)ie.hwndClient,
  616. ie.lParam);
  617. } else {
  618. /*
  619. * Send this message to the nddeagnt app first so it can start
  620. * the netdde services BEFORE we do an enumeration of windows.
  621. * This lets things work the first time. NetDDEAgent caches
  622. * service status so this is the fastest way to do this.
  623. */
  624. HWND hwndAgent = FindWindowW(SZ_NDDEAGNT_CLASS, SZ_NDDEAGNT_TITLE);
  625. if (hwndAgent) {
  626. SendMessage(hwndAgent,
  627. WM_DDE_INITIATE, (WPARAM)ie.hwndClient, ie.lParam);
  628. }
  629. EnumWindows((WNDENUMPROC)InitiateEnumerationProc, (LPARAM)&ie);
  630. }
  631. EnterDDECrit;
  632. /*
  633. * hConvList may have been destroyed during the enumeration but we are
  634. * done with it now so no need to revalidate.
  635. */
  636. #if DBG
  637. {
  638. WCHAR sz[10];
  639. if (gaService && GlobalGetAtomName(gaService, sz, 10) == 0) {
  640. RIPMSG1(RIP_ERROR, "Bad Service Atom after Initiate phase: %lX", (DWORD)gaService);
  641. }
  642. if (gaTopic && GlobalGetAtomName(gaTopic, sz, 10) == 0) {
  643. RIPMSG1(RIP_ERROR, "Bad Topic Atom after Initiate phase: %lX", (DWORD)gaTopic);
  644. }
  645. }
  646. #endif // DBG
  647. GlobalDeleteAtom(gaService);
  648. GlobalDeleteAtom(gaTopic);
  649. //
  650. // Get the first pci allocated when a WM_DDE_ACK was recieved.
  651. //
  652. pci = (PCL_CONV_INFO)GetWindowLongPtr(ie.hwndClient, GWLP_PCI);
  653. if (pci == NULL) {
  654. Error:
  655. LeaveDDECrit;
  656. NtUserDestroyWindow(ie.hwndClient);
  657. EnterDDECrit;
  658. return (NULL);
  659. }
  660. SetWindowLong(ie.hwndClient, GWL_CONVSTATE, CLST_CONNECTED);
  661. if (hwndTarget) {
  662. /*
  663. * If hwndTarget was NULL, the enumeration proc took care of this.
  664. */
  665. pci->hwndReconnect = hwndTarget;
  666. UserAssert(pci->ci.next == NULL);
  667. pci->ci.laServiceRequested = laService;
  668. IncLocalAtomCount(laService); // pci copy
  669. }
  670. if (pcii->MonitorFlags & MF_CONV) {
  671. for (pcoi = (PCONV_INFO)pci; pcoi; pcoi = pcoi->next) {
  672. MONCONV(pcoi, TRUE);
  673. }
  674. }
  675. return (pci);
  676. }
  677. /*
  678. * Undoes the work of ConnectConv()
  679. */
  680. VOID DisconnectConv(
  681. PCONV_INFO pcoi)
  682. {
  683. PCONV_INFO pcoiNext;
  684. for (; pcoi; pcoi = pcoiNext) {
  685. pcoiNext = pcoi->next;
  686. ShutdownConversation(pcoi, FALSE);
  687. }
  688. }
  689. /***************************************************************************\
  690. * InitiateEnumerationProc (FILE LOCAL)
  691. *
  692. * Description:
  693. * Function used via EnumWindows to enumerate all server window candidates
  694. * during DDE initiation. The enumeration allows DDEML to know what
  695. * window WM_DDE_INITIATE was sent to so that it can be remembered for
  696. * possible reconnection later. (The window that receives the WM_DDE_INITIATE
  697. * message is not necessarily going to be the server window.)
  698. *
  699. * History:
  700. * 11-1-91 sanfords Created.
  701. \***************************************************************************/
  702. BOOL InitiateEnumerationProc(
  703. HWND hwndTarget,
  704. PINIT_ENUM pie)
  705. {
  706. PCL_CONV_INFO pci;
  707. CheckDDECritOut;
  708. if (hwndTarget == pie->hwndSkip) {
  709. return (TRUE);
  710. }
  711. if (pie->hConvList && pie->laTopic && pie->laServiceRequested) {
  712. /*
  713. * Head off duplicates BEFORE we send the WM_DDE_INITIATE messages!
  714. */
  715. PCONVLIST pcl;
  716. PCONV_INFO pcoiExisting;
  717. int i;
  718. EnterDDECrit;
  719. /*
  720. * We revalidate hConvList here because we left the critical section.
  721. */
  722. pcl = (PCONVLIST)ValidateCHandle((HANDLE)pie->hConvList,
  723. HTYPE_CONVERSATION_LIST, HINST_ANY);
  724. if (pcl != NULL) {
  725. for (i = 0; i < pcl->chwnd; i++) {
  726. for (pcoiExisting = (PCONV_INFO)GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI);
  727. pcoiExisting != NULL;
  728. pcoiExisting = pcoiExisting->next) {
  729. if (pcoiExisting->state & ST_CONNECTED &&
  730. ((PCL_CONV_INFO)pcoiExisting)->hwndReconnect == hwndTarget &&
  731. pcoiExisting->laTopic == pie->laTopic &&
  732. pcoiExisting->laService == pie->laServiceRequested) {
  733. LeaveDDECrit;
  734. return(TRUE);
  735. }
  736. }
  737. }
  738. }
  739. LeaveDDECrit;
  740. }
  741. CheckDDECritOut;
  742. SendMessage(hwndTarget, WM_DDE_INITIATE, (WPARAM)pie->hwndClient,
  743. pie->lParam);
  744. EnterDDECrit;
  745. //
  746. // During the initiate process, any acks received cause more pci's
  747. // to become linked together under the same hwndClient. Once
  748. // the SendMessage() returns, we set the parts of the new pci's
  749. // that hold initiate context information.
  750. //
  751. pci = (PCL_CONV_INFO)GetWindowLongPtr(pie->hwndClient, GWLP_PCI);
  752. if (pci == NULL) {
  753. LeaveDDECrit;
  754. return (TRUE);
  755. }
  756. while (pci != NULL) {
  757. if (pci->hwndReconnect == 0) { // this one needs updating
  758. pci->hwndReconnect = hwndTarget;
  759. if (pie->laServiceRequested) {
  760. pci->ci.laServiceRequested = pie->laServiceRequested;
  761. IncLocalAtomCount(pie->laServiceRequested); // pci copy
  762. }
  763. }
  764. if (pie->clst == CLST_SINGLE_INITIALIZING) {
  765. break;
  766. }
  767. pci = (PCL_CONV_INFO)pci->ci.next;
  768. }
  769. LeaveDDECrit;
  770. return (pie->clst == CLST_MULT_INITIALIZING);
  771. }
  772. /***************************************************************************\
  773. * SetCommonStateFlags()
  774. *
  775. * Description:
  776. * Common client/server worker function
  777. *
  778. * History:
  779. * 05-12-91 sanfords Created.
  780. \***************************************************************************/
  781. VOID SetCommonStateFlags(
  782. HWND hwndUs,
  783. HWND hwndThem,
  784. PWORD pwFlags)
  785. {
  786. DWORD pidUs, pidThem;
  787. GetWindowThreadProcessId(hwndUs, &pidUs);
  788. GetWindowThreadProcessId(hwndThem, &pidThem);
  789. if (pidUs == pidThem) {
  790. *pwFlags |= ST_INTRA_PROCESS;
  791. }
  792. if (IsWindowUnicode(hwndUs) && IsWindowUnicode(hwndThem)) {
  793. *pwFlags |= ST_UNICODE_EXECUTE;
  794. }
  795. }
  796. /***************************************************************************\
  797. * DdeQueryNextServer (DDEML API)
  798. *
  799. * Description:
  800. * Enumerates conversations within a list.
  801. *
  802. * History:
  803. * 11-12-91 sanfords Created.
  804. \***************************************************************************/
  805. FUNCLOG2(LOG_GENERAL, HCONV, DUMMYCALLINGTYPE, DdeQueryNextServer, HCONVLIST, hConvList, HCONV, hConvPrev)
  806. HCONV DdeQueryNextServer(
  807. HCONVLIST hConvList,
  808. HCONV hConvPrev)
  809. {
  810. HCONV hConvRet = 0;
  811. PCONVLIST pcl;
  812. HWND *phwnd;
  813. int i;
  814. PCL_CONV_INFO pci;
  815. PCL_INSTANCE_INFO pcii;
  816. EnterDDECrit;
  817. pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList,
  818. HTYPE_CONVERSATION_LIST, HINST_ANY);
  819. if (pcl == NULL) {
  820. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  821. goto Exit;
  822. }
  823. if (!pcl->chwnd) { // empty list
  824. goto Exit;
  825. }
  826. pcii = PciiFromHandle((HANDLE)hConvList);
  827. if (pcii == NULL) {
  828. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  829. goto Exit;
  830. }
  831. pcii->LastError = DMLERR_NO_ERROR;
  832. do {
  833. hConvRet = 0;
  834. if (hConvPrev == 0) {
  835. pci = (PCL_CONV_INFO)GetWindowLongPtr(pcl->ahwnd[0], GWLP_PCI);
  836. if (pci == NULL) {
  837. goto Exit; // Must have all conversations zombied.
  838. }
  839. hConvPrev = hConvRet = pci->ci.hConv;
  840. continue;
  841. }
  842. pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConvPrev,
  843. HTYPE_CLIENT_CONVERSATION, InstFromHandle(hConvList));
  844. if (pci == NULL) {
  845. pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConvPrev,
  846. HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(hConvList));
  847. if (pci == NULL) {
  848. SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
  849. break;
  850. } else {
  851. goto ZombieSkip;
  852. }
  853. }
  854. if (pci->hConvList != hConvList) {
  855. SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
  856. break;
  857. }
  858. ZombieSkip:
  859. if (pci->ci.next == NULL) {
  860. /*
  861. * end of list for this window, go to next window
  862. */
  863. for (phwnd = pcl->ahwnd, i = 0; (i + 1) < pcl->chwnd; i++) {
  864. if (phwnd[i] == pci->ci.hwndConv) {
  865. pci = (PCL_CONV_INFO)GetWindowLongPtr(phwnd[i + 1], GWLP_PCI);
  866. if (pci == NULL) {
  867. break;
  868. }
  869. hConvPrev = hConvRet = pci->ci.hConv;
  870. break;
  871. }
  872. }
  873. } else {
  874. hConvPrev = hConvRet = pci->ci.next->hConv; // next conv for this window.
  875. }
  876. } while (hConvRet && TypeFromHandle(hConvRet) == HTYPE_ZOMBIE_CONVERSATION);
  877. Exit:
  878. LeaveDDECrit;
  879. return (hConvRet);
  880. }
  881. /***************************************************************************\
  882. * DdeDisconnect (DDEML API)
  883. *
  884. * Description:
  885. * Terminates a conversation.
  886. *
  887. * History:
  888. * 11-12-91 sanfords Created.
  889. \***************************************************************************/
  890. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeDisconnect, HCONV, hConv)
  891. BOOL DdeDisconnect(
  892. HCONV hConv)
  893. {
  894. BOOL fRet = FALSE;
  895. PCONV_INFO pcoi;
  896. PCL_INSTANCE_INFO pcii;
  897. CheckDDECritOut;
  898. EnterDDECrit;
  899. pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv,
  900. HTYPE_CLIENT_CONVERSATION, HINST_ANY);
  901. if (pcoi == NULL) {
  902. pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv,
  903. HTYPE_SERVER_CONVERSATION, HINST_ANY);
  904. }
  905. if (pcoi == NULL) {
  906. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  907. goto Exit;
  908. }
  909. pcii = PciiFromHandle((HANDLE)hConv);
  910. if (pcii == NULL) {
  911. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  912. goto Exit;
  913. }
  914. if (pcoi->state & ST_CONNECTED) {
  915. ShutdownConversation(pcoi, FALSE);
  916. }
  917. fRet = TRUE;
  918. Exit:
  919. LeaveDDECrit;
  920. return (fRet);
  921. }
  922. /***************************************************************************\
  923. * DdeDisconnectList (DDEML API)
  924. *
  925. * Description:
  926. * Terminates all conversations in a conversation list and frees the list.
  927. *
  928. * History:
  929. * 11-12-91 sanfords Created.
  930. \***************************************************************************/
  931. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeDisconnectList, HCONVLIST, hConvList)
  932. BOOL DdeDisconnectList(
  933. HCONVLIST hConvList)
  934. {
  935. BOOL fRet = FALSE;
  936. PCL_INSTANCE_INFO pcii;
  937. PCONVLIST pcl;
  938. PCONV_INFO pcoi, pcoiNext;
  939. int i;
  940. CheckDDECritOut;
  941. EnterDDECrit;
  942. pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList,
  943. HTYPE_CONVERSATION_LIST, HINST_ANY);
  944. if (pcl == NULL) {
  945. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  946. goto Exit;
  947. }
  948. ValidateConvList(hConvList);
  949. pcii = PciiFromHandle((HANDLE)hConvList);
  950. if (pcii == NULL) {
  951. BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
  952. goto Exit;
  953. }
  954. for(i = pcl->chwnd - 1; i >= 0; i--) {
  955. pcoi = (PCONV_INFO)GetWindowLongPtr(pcl->ahwnd[i], GWLP_PCI);
  956. while (pcoi != NULL && pcoi->state & ST_CONNECTED) {
  957. pcoiNext = pcoi->next;
  958. ShutdownConversation(pcoi, FALSE); // may unlink pcoi!
  959. pcoi = pcoiNext;
  960. }
  961. }
  962. DestroyHandle((HANDLE)hConvList);
  963. DDEMLFree(pcl);
  964. fRet = TRUE;
  965. Exit:
  966. LeaveDDECrit;
  967. return (fRet);
  968. }
  969. /***************************************************************************\
  970. * ShutdownConversation
  971. *
  972. * Description:
  973. * This function causes an imediate termination of the given conversation
  974. * and generates apropriate callbacks to notify the application.
  975. *
  976. * History:
  977. * 11-12-91 sanfords Created.
  978. \***************************************************************************/
  979. VOID ShutdownConversation(
  980. PCONV_INFO pcoi,
  981. BOOL fMakeCallback)
  982. {
  983. CheckDDECritIn;
  984. if (pcoi->state & ST_CONNECTED) {
  985. pcoi->state &= ~ST_CONNECTED;
  986. if (IsWindow(pcoi->hwndPartner)) {
  987. PostMessage(pcoi->hwndPartner, WM_DDE_TERMINATE,
  988. (WPARAM)pcoi->hwndConv, 0);
  989. }
  990. if (fMakeCallback && !(pcoi->pcii->afCmd & CBF_SKIP_DISCONNECTS)) {
  991. DoCallback(pcoi->pcii, (WORD)XTYP_DISCONNECT, 0, pcoi->hConv,
  992. 0, 0, 0, 0, (pcoi->state & ST_ISSELF) ? 1L : 0L);
  993. }
  994. MONCONV(pcoi, FALSE);
  995. }
  996. FreeConversationResources(pcoi);
  997. }
  998. /***************************************************************************\
  999. * UnlinkConvFromOthers
  1000. *
  1001. * Description:
  1002. *
  1003. * Helper function to handle ugly cross dependency removal. If we are
  1004. * unlinking a conversation that is going zombie, fGoingZombie is TRUE;
  1005. *
  1006. * Conversations that are going zombie are in phase 1 of a 2 phase unlink.
  1007. * Phase 1 unlinks do not remove the pcoi from its hwnd's list.
  1008. * All unlinks should result in:
  1009. * pcoi->hConvList = 0;
  1010. * hConvList/aServerLookup no longer refrences pcoi->hwndConv unless
  1011. * one of the pcoi's related to hwndConv is still active.
  1012. *
  1013. *
  1014. * History:
  1015. * 3-2-92 sanfords Created.
  1016. \***************************************************************************/
  1017. VOID UnlinkConvFromOthers(
  1018. PCONV_INFO pcoi,
  1019. BOOL gGoingZombie)
  1020. {
  1021. PCONV_INFO pcoiPrev, pcoiFirst, pcoiNow;
  1022. PCONVLIST pcl;
  1023. int i, cActiveInList = 0;
  1024. #ifdef TESTING
  1025. DWORD path = 0;
  1026. #define ORPATH(x) path |= x;
  1027. #else
  1028. #define ORPATH(x)
  1029. #endif // TESTING
  1030. CheckDDECritIn;
  1031. /*
  1032. * Scan pcoi linked list to get key pointers.
  1033. */
  1034. pcoiPrev = NULL;
  1035. pcoiFirst = pcoiNow = (PCONV_INFO)GetWindowLongPtr(pcoi->hwndConv, GWLP_PCI);
  1036. #ifdef TESTING
  1037. /*
  1038. * verify that pcoi is in the conv list for this window.
  1039. */
  1040. while (pcoiNow != NULL) {
  1041. if (pcoiNow == pcoi) {
  1042. goto FoundIt;
  1043. }
  1044. pcoiNow = pcoiNow->next;
  1045. }
  1046. DebugBreak();
  1047. FoundIt:
  1048. pcoiNow = pcoiFirst;
  1049. #endif // TESTING
  1050. UserAssert(pcoiFirst);
  1051. while (pcoiNow != NULL) {
  1052. if (TypeFromHandle(pcoiNow->hConv) != HTYPE_ZOMBIE_CONVERSATION) {
  1053. ORPATH(1);
  1054. cActiveInList++;
  1055. }
  1056. if (pcoiNow->next == pcoi) {
  1057. pcoiPrev = pcoiNow;
  1058. }
  1059. pcoiNow = pcoiNow->next;
  1060. }
  1061. ValidateAllConvLists();
  1062. /*
  1063. * Unlink conversation unless its going Zombie.
  1064. */
  1065. if (!gGoingZombie) {
  1066. ORPATH(2);
  1067. if (TypeFromHandle(pcoi->hConv) != HTYPE_ZOMBIE_CONVERSATION) {
  1068. ORPATH(4);
  1069. cActiveInList--;
  1070. }
  1071. if (pcoiPrev == NULL) {
  1072. ORPATH(8);
  1073. pcoiFirst = pcoi->next;
  1074. SetWindowLongPtr(pcoi->hwndConv, GWLP_PCI, (LONG_PTR)pcoiFirst);
  1075. } else {
  1076. pcoiPrev->next = pcoi->next;
  1077. }
  1078. }
  1079. UserAssert(pcoiFirst != NULL || !cActiveInList);
  1080. if (cActiveInList == 0) {
  1081. ORPATH(0x10);
  1082. if (pcoi->state & ST_CLIENT) {
  1083. ORPATH(0x20);
  1084. if (((PCL_CONV_INFO)pcoi)->hConvList) {
  1085. /*
  1086. * Remove pcoi's hwnd from its hConvList.
  1087. */
  1088. pcl = (PCONVLIST)GetHandleData((HANDLE)((PCL_CONV_INFO)pcoi)->hConvList);
  1089. for (i = 0; i < pcl->chwnd; i++) {
  1090. if (pcl->ahwnd[i] == pcoi->hwndConv) {
  1091. ORPATH(0x40);
  1092. pcl->chwnd--;
  1093. UserAssert(pcl->ahwnd[pcl->chwnd]);
  1094. pcl->ahwnd[i] = pcl->ahwnd[pcl->chwnd];
  1095. ValidateConvList(((PCL_CONV_INFO)pcoi)->hConvList);
  1096. break;
  1097. }
  1098. }
  1099. ORPATH(0x80);
  1100. }
  1101. } else { // SERVER
  1102. /*
  1103. * remove server window from the service/topic lookup table.
  1104. */
  1105. ORPATH(0x100);
  1106. for (i = 0; i < pcoi->pcii->cServerLookupAlloc; i++) {
  1107. if (pcoi->pcii->aServerLookup[i].hwndServer == pcoi->hwndConv) {
  1108. ORPATH(0x200);
  1109. /*
  1110. * Check for appcompat hack
  1111. */
  1112. if (GetAppCompatFlags2(VERMAX) & GACF2_DDE) {
  1113. DeleteAtom(pcoi->pcii->aServerLookup[i].laService); // delete laService
  1114. DeleteAtom(pcoi->pcii->aServerLookup[i].laTopic); // delete laTopic
  1115. }
  1116. if (--(pcoi->pcii->cServerLookupAlloc)) {
  1117. ORPATH(0x400);
  1118. pcoi->pcii->aServerLookup[i] =
  1119. pcoi->pcii->aServerLookup[pcoi->pcii->cServerLookupAlloc];
  1120. } else {
  1121. DDEMLFree(pcoi->pcii->aServerLookup);
  1122. pcoi->pcii->aServerLookup = NULL;
  1123. }
  1124. break;
  1125. }
  1126. }
  1127. }
  1128. }
  1129. #ifdef TESTING
  1130. else {
  1131. /*
  1132. * make sure at this point we have at least one non-zombie
  1133. */
  1134. pcoiNow = pcoiFirst;
  1135. while (pcoiNow != NULL) {
  1136. if (TypeFromHandle(pcoiNow->hConv) != HTYPE_ZOMBIE_CONVERSATION) {
  1137. goto Out;
  1138. }
  1139. pcoiNow = pcoiNow->next;
  1140. }
  1141. DebugBreak();
  1142. Out:
  1143. ;
  1144. }
  1145. #endif // TESTING
  1146. ValidateAllConvLists();
  1147. ORPATH(0x800);
  1148. /*
  1149. * In any case remove hConvList references from client conversation.
  1150. */
  1151. if (pcoi->state & ST_CLIENT) {
  1152. #ifdef TESTING
  1153. /*
  1154. * Verify that the hConvList that is being removed, doesn't reference
  1155. * this window.
  1156. */
  1157. if (((PCL_CONV_INFO)pcoi)->hConvList && !cActiveInList) {
  1158. BOOL fFound = FALSE;
  1159. pcl = (PCONVLIST)GetHandleData((HANDLE)((PCL_CONV_INFO)pcoi)->hConvList);
  1160. for (i = 0; i < pcl->chwnd; i++) {
  1161. if (pcl->ahwnd[i] == pcoi->hwndConv) {
  1162. fFound = TRUE;
  1163. break;
  1164. }
  1165. }
  1166. UserAssert(!fFound);
  1167. }
  1168. #endif // TESTING
  1169. ((PCL_CONV_INFO)pcoi)->hConvList = 0;
  1170. pcoi->state &= ~ST_INLIST;
  1171. }
  1172. /*
  1173. * last one out turns out the lights.
  1174. */
  1175. if (pcoiFirst == NULL) {
  1176. /*
  1177. * If the pcoi list is empty, this window can go away.
  1178. */
  1179. LeaveDDECrit;
  1180. NtUserDestroyWindow(pcoi->hwndConv);
  1181. EnterDDECrit;
  1182. }
  1183. }
  1184. /***************************************************************************\
  1185. * FreeConversationResources
  1186. *
  1187. * Description:
  1188. * Used when: Client window is disconnected by app, Server window is
  1189. * disconnected by either side, or when a conversation is disconnected
  1190. * at Uninitialize time.
  1191. *
  1192. * This function releases all resources held by the pcoi and unlinks it
  1193. * from its host window pcoi chian. pcoi is freed once this return s.
  1194. *
  1195. * History:
  1196. * 12-21-91 sanfords Created.
  1197. \***************************************************************************/
  1198. VOID FreeConversationResources(
  1199. PCONV_INFO pcoi)
  1200. {
  1201. PADVISE_LINK paLink;
  1202. PDDE_MESSAGE_QUEUE pdmq;
  1203. PXACT_INFO pxi;
  1204. CheckDDECritIn;
  1205. /*
  1206. * Don't free resources on locked conversations.
  1207. */
  1208. if (pcoi->cLocks > 0) {
  1209. pcoi->state |= ST_FREE_CONV_RES_NOW;
  1210. return;
  1211. }
  1212. /*
  1213. * Don't free resources if a synchronous transaction is in effect!
  1214. */
  1215. pxi = pcoi->pxiOut;
  1216. while (pxi != NULL) {
  1217. if (pxi->flags & XIF_SYNCHRONOUS) {
  1218. /*
  1219. * This conversation is in a synchronous transaction.
  1220. * Shutdown the modal loop FIRST, then call this when
  1221. * the loop exits.
  1222. */
  1223. PostMessage(pcoi->hwndConv, WM_TIMER, TID_TIMEOUT, 0);
  1224. pcoi->state |= ST_FREE_CONV_RES_NOW;
  1225. return;
  1226. }
  1227. pxi = pxi->next;
  1228. }
  1229. /*
  1230. * If this is an Intra-Process conversation that hasn't yet received
  1231. * a terminate message, make it a zombie. We will call this routine
  1232. * again once the terminate arrives or when WaitForZombieTerminate() has
  1233. * timed out waiting.
  1234. */
  1235. if (pcoi->state & ST_INTRA_PROCESS && !(pcoi->state & ST_TERMINATE_RECEIVED)) {
  1236. DestroyHandle((HANDLE)pcoi->hConv);
  1237. pcoi->hConv = (HCONV)CreateHandle((ULONG_PTR)pcoi, HTYPE_ZOMBIE_CONVERSATION,
  1238. InstFromHandle(pcoi->hConv));
  1239. UnlinkConvFromOthers(pcoi, TRUE);
  1240. return;
  1241. }
  1242. /*
  1243. * remove any transactions left in progress
  1244. */
  1245. while (pcoi->pxiOut != NULL) {
  1246. (pcoi->pxiOut->pfnResponse)(pcoi->pxiOut, 0, 0);
  1247. }
  1248. /*
  1249. * Throw away any incoming queued DDE messages.
  1250. */
  1251. while (pcoi->dmqOut != NULL) {
  1252. pdmq = pcoi->dmqOut;
  1253. DumpDDEMessage(!(pcoi->state & ST_INTRA_PROCESS), pdmq->msg, pdmq->lParam);
  1254. pcoi->dmqOut = pcoi->dmqOut->next;
  1255. if (pcoi->dmqOut == NULL) {
  1256. pcoi->dmqIn = NULL;
  1257. }
  1258. DDEMLFree(pdmq);
  1259. }
  1260. //
  1261. // Remove all link info
  1262. //
  1263. paLink = pcoi->aLinks;
  1264. while (pcoi->cLinks) {
  1265. if (pcoi->state & ST_CLIENT) {
  1266. MONLINK(pcoi->pcii, FALSE, paLink->wType & XTYPF_NODATA,
  1267. pcoi->laService, pcoi->laTopic,
  1268. LocalToGlobalAtom(paLink->laItem),
  1269. paLink->wFmt, FALSE,
  1270. (HCONV)pcoi->hwndPartner, (HCONV)pcoi->hwndConv);
  1271. } else {
  1272. MONLINK(pcoi->pcii, FALSE, paLink->wType & XTYPF_NODATA,
  1273. pcoi->laService, pcoi->laTopic,
  1274. LocalToGlobalAtom(paLink->laItem),
  1275. paLink->wFmt, TRUE,
  1276. (HCONV)pcoi->hwndConv, (HCONV)pcoi->hwndPartner);
  1277. }
  1278. if (!(pcoi->state & ST_CLIENT)) {
  1279. DeleteLinkCount(pcoi->pcii, paLink->pLinkCount);
  1280. }
  1281. DeleteAtom(paLink->laItem); // link structure copy
  1282. paLink++;
  1283. pcoi->cLinks--;
  1284. }
  1285. if (pcoi->aLinks) {
  1286. DDEMLFree(pcoi->aLinks);
  1287. }
  1288. //
  1289. // free atoms associated with this conv
  1290. //
  1291. DeleteAtom(pcoi->laService);
  1292. DeleteAtom(pcoi->laTopic);
  1293. if (pcoi->laServiceRequested) {
  1294. DeleteAtom(pcoi->laServiceRequested);
  1295. }
  1296. UnlinkConvFromOthers(pcoi, FALSE);
  1297. /*
  1298. * invalidate app's conversation handle
  1299. */
  1300. DestroyHandle((HANDLE)pcoi->hConv);
  1301. DDEMLFree(pcoi);
  1302. }
  1303. BOOL WaitForZombieTerminate(
  1304. HANDLE hData)
  1305. {
  1306. PCONV_INFO pcoi;
  1307. MSG msg;
  1308. HWND hwnd;
  1309. BOOL fTerminated;
  1310. DWORD fRet = 0;
  1311. CheckDDECritOut;
  1312. EnterDDECrit;
  1313. fTerminated = FALSE;
  1314. while ((pcoi = (PCONV_INFO)ValidateCHandle(hData,
  1315. HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(hData))) != NULL &&
  1316. !(pcoi->state & ST_TERMINATE_RECEIVED)) {
  1317. hwnd = pcoi->hwndConv;
  1318. LeaveDDECrit;
  1319. while (PeekMessage(&msg, hwnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) {
  1320. DispatchMessage(&msg);
  1321. if (msg.message == WM_DDE_TERMINATE) {
  1322. fTerminated = TRUE;
  1323. }
  1324. }
  1325. if (!fTerminated) {
  1326. fRet = MsgWaitForMultipleObjectsEx(0, NULL, 100, QS_POSTMESSAGE, 0);
  1327. if (fRet == 0xFFFFFFFF) {
  1328. RIPMSG0(RIP_WARNING, "WaitForZombieTerminate: I give up - faking terminate.");
  1329. ProcessTerminateMsg(pcoi, pcoi->hwndPartner);
  1330. EnterDDECrit;
  1331. return(FALSE);
  1332. }
  1333. }
  1334. EnterDDECrit;
  1335. }
  1336. LeaveDDECrit;
  1337. return(TRUE);
  1338. }