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.

2345 lines
70 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: ddeml.C
  3. *
  4. * DDE Manager main module - Contains all exported ddeml functions.
  5. *
  6. * Created: 12/12/88 Sanford Staab
  7. *
  8. * Copyright (c) 1988, 1989 Microsoft Corporation
  9. * 4/5/89 sanfords removed need for hwndFrame registration parameter
  10. * 6/5/90 sanfords Fixed callbacks so they are blocked during
  11. * timeouts.
  12. * Fixed SendDDEInit allocation bug.
  13. * Added hApp to ConvInfo structure.
  14. * Allowed QueryConvInfo() to work on server hConvs.
  15. * 11/29/90 sanfords eliminated SendDDEInit()
  16. *
  17. \***************************************************************************/
  18. #include "ddemlp.h"
  19. #include "verddeml.h"
  20. /****** Globals *******/
  21. HANDLE hInstance = 0; // initialized by LoadProc
  22. HANDLE hheapDmg = 0; // main DLL heap
  23. PAPPINFO pAppInfoList = NULL; // registered app/thread data list
  24. PPILE pDataInfoPile = NULL; // Data handle tracking pile
  25. PPILE pLostAckPile = NULL; // Ack tracking pile
  26. WORD hwInst = 1; // used to validate stuff.
  27. CONVCONTEXT CCDef = { sizeof(CONVCONTEXT), 0, 0, CP_WINANSI, 0L, 0L }; // default context.
  28. char szNull[] = "";
  29. char szT[20];
  30. WORD cMonitor = 0; // number of registered monitors
  31. FARPROC prevMsgHook = NULL; // used for hook links
  32. FARPROC prevCallHook = NULL; // used for hook links
  33. ATOM gatomDDEMLMom = 0;
  34. ATOM gatomDMGClass = 0;
  35. DWORD ShutdownTimeout;
  36. DWORD ShutdownRetryTimeout;
  37. LPMQL gMessageQueueList = NULL; // see PostDdeMessage();
  38. #ifdef DEBUG
  39. int bDbgFlags = 0;
  40. #endif
  41. /****** class strings ******/
  42. char SZFRAMECLASS[] = "DMGFrame";
  43. char SZDMGCLASS[] = "DMGClass";
  44. char SZCLIENTCLASS[] = "DMGClientClass";
  45. char SZSERVERCLASS[] = "DMGServerClass";
  46. char SZMONITORCLASS[] = "DMGMonitorClass";
  47. char SZCONVLISTCLASS[] = "DMGHoldingClass";
  48. char SZHEAPWATCHCLASS[] = "DMGHeapWatchClass";
  49. #ifdef DEBUG
  50. WORD cAtoms = 0; // for debugging hszs!
  51. #endif
  52. // PROGMAN HACK!!!!
  53. // This is here so DDEML works properly with PROGMAN 3.0 which incorrectly
  54. // deletes its initiate-ack atoms after sending its ack.
  55. ATOM aProgmanHack = 0;
  56. /*
  57. * maps XTYP_CONSTANTS to filter flags
  58. */
  59. DWORD aulmapType[] = {
  60. 0L, // nothing
  61. 0L, // XTYP_ADVDATA
  62. 0L, // XTYP_ADVREQ
  63. CBF_FAIL_ADVISES, // XTYP_ADVSTART
  64. 0L, // XTYP_ADVSTOP
  65. CBF_FAIL_EXECUTES, // XTYP_EXECUTE
  66. CBF_FAIL_CONNECTIONS, // XTYP_CONNECT
  67. CBF_SKIP_CONNECT_CONFIRMS, // XTYP_CONNECT_CONFIRM
  68. 0L, // XTYP_MONITOR
  69. CBF_FAIL_POKES, // XTYP_POKE
  70. CBF_SKIP_REGISTRATIONS, // XTYP_REGISTER
  71. CBF_FAIL_REQUESTS, // XTYP_REQUEST
  72. CBF_SKIP_DISCONNECTS, // XTYP_DISCONNECT
  73. CBF_SKIP_UNREGISTRATIONS, // XTYP_UNREGISTER
  74. CBF_FAIL_CONNECTIONS, // XTYP_WILDCONNECT
  75. 0L, // XTYP_XACT_COMPLETE
  76. };
  77. UINT EXPENTRY DdeInitialize(
  78. LPDWORD pidInst,
  79. PFNCALLBACK pfnCallback,
  80. DWORD afCmd,
  81. DWORD ulRes)
  82. {
  83. WORD wRet;
  84. #ifdef DEBUG
  85. if (!hheapDmg) {
  86. bDbgFlags = GetProfileInt("DDEML", "DebugFlags", 0);
  87. }
  88. #endif
  89. TRACEAPIIN((szT, "DdeInitialize(%lx(->%lx), %lx, %lx, %lx)\n",
  90. pidInst, *pidInst, pfnCallback, afCmd, ulRes));
  91. if (ulRes != 0L) {
  92. wRet = DMLERR_INVALIDPARAMETER;
  93. } else {
  94. wRet = Register(pidInst, pfnCallback, afCmd);
  95. }
  96. TRACEAPIOUT((szT, "DdeInitialize:%x\n", wRet));
  97. return(wRet);
  98. }
  99. DWORD Myatodw(LPCSTR psz)
  100. {
  101. DWORD dwRet = 0;
  102. if (psz == NULL) {
  103. return(0);
  104. }
  105. while (*psz) {
  106. dwRet = (dwRet << 1) + (dwRet << 3) + (*psz - '0');
  107. psz++;
  108. }
  109. return(dwRet);
  110. }
  111. WORD Register(
  112. LPDWORD pidInst,
  113. PFNCALLBACK pfnCallback,
  114. DWORD afCmd)
  115. {
  116. PAPPINFO pai = 0L;
  117. SEMENTER();
  118. if (afCmd & APPCLASS_MONITOR) {
  119. if (cMonitor == MAX_MONITORS) {
  120. return(DMLERR_DLL_USAGE);
  121. }
  122. // ensure monitors only get monitor callbacks.
  123. afCmd |= CBF_MONMASK;
  124. }
  125. if ((pai = (PAPPINFO)(*pidInst)) != NULL) {
  126. if (pai->instCheck != HIWORD(*pidInst)) {
  127. return(DMLERR_INVALIDPARAMETER);
  128. }
  129. /*
  130. * re-registration - only allow CBF_ and MF_ flags to be altered
  131. */
  132. pai->afCmd = (pai->afCmd & ~(CBF_MASK | MF_MASK)) |
  133. (afCmd & (CBF_MASK | MF_MASK));
  134. return(DMLERR_NO_ERROR);
  135. }
  136. if (!hheapDmg) {
  137. // Read in any alterations to the zombie terminate timeouts
  138. GetProfileString("DDEML", "ShutdownTimeout", "3000", szT, 20);
  139. ShutdownTimeout = Myatodw(szT);
  140. if (!ShutdownTimeout) {
  141. ShutdownTimeout = 3000;
  142. }
  143. GetProfileString("DDEML", "ShutdownRetryTimeout", "30000", szT, 20);
  144. ShutdownRetryTimeout = Myatodw(szT);
  145. if (!ShutdownRetryTimeout) {
  146. ShutdownRetryTimeout = 30000;
  147. }
  148. // PROGMAN HACK!!!!
  149. aProgmanHack = GlobalAddAtom("Progman");
  150. /* UTTER GREASE to fool the pile routines into making a local pile */
  151. hheapDmg = HIWORD((LPVOID)(&pDataInfoPile));
  152. RegisterClasses();
  153. }
  154. if (!pDataInfoPile) {
  155. if (!(pDataInfoPile = CreatePile(hheapDmg, sizeof(DIP), 8))) {
  156. goto Abort;
  157. }
  158. }
  159. if (!pLostAckPile) {
  160. if (!(pLostAckPile = CreatePile(hheapDmg, sizeof(LAP), 8))) {
  161. goto Abort;
  162. }
  163. }
  164. pai = (PAPPINFO)(DWORD)FarAllocMem(hheapDmg, sizeof(APPINFO));
  165. if (pai == NULL) {
  166. goto Abort;
  167. }
  168. if (!(pai->hheapApp = DmgCreateHeap(4096))) {
  169. FarFreeMem((LPSTR)pai);
  170. pai = 0L;
  171. goto Abort;
  172. }
  173. /*
  174. * We NEVER expect a memory allocation failure here because we just
  175. * allocated the heap.
  176. */
  177. pai->next = pAppInfoList;
  178. pai->pfnCallback = pfnCallback;
  179. // pai->pAppNamePile = NULL; LMEM_ZEROINIT
  180. pai->pHDataPile = CreatePile(pai->hheapApp, sizeof(HDDEDATA), 32);
  181. pai->pHszPile = CreatePile(pai->hheapApp, sizeof(ATOM), 16);
  182. // pai->plstCBExceptions = NULL; LMEM_ZEROINIT
  183. // pai->hwndSvrRoot = 0; may never need it LMEM_ZEROINIT
  184. pai->plstCB = CreateLst(pai->hheapApp, sizeof(CBLI));
  185. pai->afCmd = afCmd | APPCMD_FILTERINITS;
  186. pai->hTask = GetCurrentTask();
  187. // pai->hwndDmg = LMEM_ZEROINIT
  188. // pai->hwndFrame = LMEM_ZEROINIT
  189. // pai->hwndMonitor = LMEM_ZEROINIT
  190. // pai->hwndTimer = 0; LMEM_ZEROINIT
  191. // pai->LastError = DMLERR_NO_ERROR; LMEM_ZEROINIT
  192. // pai->wFlags = 0;
  193. // pai->fEnableOneCB = FALSE; LMEM_ZEROINIT
  194. // pai->cZombies = 0; LMEM_ZEROINIT
  195. // pai->cInProcess = 0; LMEM_ZEROINIT
  196. pai->instCheck = ++hwInst;
  197. pai->pServerAdvList = CreateLst(pai->hheapApp, sizeof(ADVLI));
  198. pai->lpMemReserve = FarAllocMem(pai->hheapApp, CB_RESERVE);
  199. pAppInfoList = pai;
  200. *pidInst = (DWORD)MAKELONG((WORD)pai, pai->instCheck);
  201. // NB We pass a pointer to pai in this CreateWindow because
  202. // 32bit MFC has a habit of subclassing our dde windows so this
  203. // param ends up getting thunked and since it's not really
  204. // a pointer things get a bit broken by the thunks.
  205. if ((pai->hwndDmg = CreateWindow(
  206. SZDMGCLASS,
  207. szNull,
  208. WS_OVERLAPPED,
  209. 0, 0, 0, 0,
  210. (HWND)NULL,
  211. (HMENU)NULL,
  212. hInstance,
  213. &pai)) == 0L) {
  214. goto Abort;
  215. }
  216. if (pai->afCmd & APPCLASS_MONITOR) {
  217. pai->afCmd |= CBF_MONMASK; // monitors only get MONITOR and REGISTER callbacks!
  218. if ((pai->hwndMonitor = CreateWindow(
  219. SZMONITORCLASS,
  220. szNull,
  221. WS_OVERLAPPED,
  222. 0, 0, 0, 0,
  223. (HWND)NULL,
  224. (HMENU)NULL,
  225. hInstance,
  226. &pai)) == 0L) {
  227. goto Abort;
  228. }
  229. if (++cMonitor == 1) {
  230. prevMsgHook = SetWindowsHook(WH_GETMESSAGE, (FARPROC)DdePostHookProc);
  231. prevCallHook = SetWindowsHook(WH_CALLWNDPROC, (FARPROC)DdeSendHookProc);
  232. }
  233. } else if (afCmd & APPCMD_CLIENTONLY) {
  234. /*
  235. * create an invisible top-level frame for initiates. (if server ok)
  236. */
  237. afCmd |= CBF_FAIL_ALLSVRXACTIONS;
  238. } else {
  239. if ((pai->hwndFrame = CreateWindow(
  240. SZFRAMECLASS,
  241. szNull,
  242. WS_POPUP,
  243. 0, 0, 0, 0,
  244. (HWND)NULL,
  245. (HMENU)NULL,
  246. hInstance,
  247. &pai)) == 0L) {
  248. goto Abort;
  249. }
  250. }
  251. // SetMessageQueue(200);
  252. SEMLEAVE();
  253. return(DMLERR_NO_ERROR);
  254. Abort:
  255. SEMLEAVE();
  256. if (pai) {
  257. DdeUninitialize((DWORD)(LPSTR)pai);
  258. }
  259. return(DMLERR_SYS_ERROR);
  260. }
  261. LRESULT FAR PASCAL TermDlgProc(
  262. HWND hwnd,
  263. UINT msg,
  264. WPARAM wParam,
  265. LPARAM lParam)
  266. {
  267. switch (msg) {
  268. case WM_INITDIALOG:
  269. return(TRUE);
  270. case WM_COMMAND:
  271. switch (wParam) {
  272. case IDABORT:
  273. case IDRETRY:
  274. case IDIGNORE:
  275. EndDialog(hwnd, wParam);
  276. return(0);
  277. }
  278. break;
  279. }
  280. return(0);
  281. }
  282. /***************************** Public Function ****************************\
  283. * PUBDOC START
  284. * BOOL EXPENTRY DdeUninitialize(void);
  285. * This unregisters the application from the DDEMGR. All DLL resources
  286. * associated with the application are destroyed.
  287. *
  288. * PUBDOC END
  289. *
  290. * History:
  291. * Created 12/14/88 Sanfords
  292. \***************************************************************************/
  293. BOOL EXPENTRY DdeUninitialize(
  294. DWORD idInst)
  295. {
  296. register PAPPINFO pai;
  297. PAPPINFO paiT;
  298. ATOM a;
  299. DWORD hData;
  300. MSG msg;
  301. extern VOID DumpGlobalLogs(VOID);
  302. TRACEAPIIN((szT, "DdeUninitialize(%lx)\n", idInst));
  303. pai = (PAPPINFO)LOWORD(idInst);
  304. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  305. TRACEAPIOUT((szT, "DdeUninitialize:0\n"));
  306. return(FALSE);
  307. }
  308. pai->LastError = DMLERR_NO_ERROR;
  309. /*
  310. * This is a hack to catch apps that call DdeUninitialize while within
  311. * a synchronous transaction modal loop.
  312. */
  313. pai->wFlags |= AWF_UNINITCALLED;
  314. if (pai->wFlags & AWF_INSYNCTRANSACTION) {
  315. TRACEAPIOUT((szT, "DdeUninitialize:1\n"));
  316. return(TRUE);
  317. }
  318. /*
  319. * inform others of DeRegistration
  320. */
  321. if (pai->pAppNamePile != NULL) {
  322. DdeNameService(idInst, (HSZ)NULL, (HSZ)NULL, DNS_UNREGISTER);
  323. }
  324. /*
  325. * Let any lagging dde activity die down.
  326. */
  327. while (EmptyDDEPostQ()) {
  328. Yield();
  329. while (PeekMessage((MSG FAR *)&msg, (HWND)NULL,
  330. WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) {
  331. DispatchMessage((MSG FAR *)&msg);
  332. Yield();
  333. }
  334. for (paiT = pAppInfoList; paiT != NULL; paiT = paiT->next) {
  335. if (paiT->hTask == pai->hTask) {
  336. CheckCBQ(paiT);
  337. }
  338. }
  339. }
  340. // Let all windows left begin to self destruct.
  341. ChildMsg(pai->hwndDmg, UM_DISCONNECT, ST_PERM2DIE, 0L, FALSE);
  342. if (ShutdownTimeout && pai->cZombies) {
  343. WORD wRet;
  344. WORD hiTimeout;
  345. /*
  346. * This ugly mess is here to prevent DDEML from closing down and
  347. * destroying windows that are not properly terminated. Any
  348. * windows waiting on WM_DDE_TERMINATE messages set the cZombies
  349. * count. If there are any left we go into a modal loop till
  350. * things clean up. This should, in most cases happen fairly
  351. * quickly.
  352. */
  353. hiTimeout = HIWORD(ShutdownTimeout);
  354. SetTimer(pai->hwndDmg, TID_SHUTDOWN, LOWORD(ShutdownTimeout), NULL);
  355. TRACETERM((szT, "DdeUninitialize: Entering terminate modal loop. cZombies=%d[%x:%x]\n",
  356. ((LPAPPINFO)pai)->cZombies,
  357. HIWORD(&((LPAPPINFO)pai)->cZombies),
  358. LOWORD(&((LPAPPINFO)pai)->cZombies)));
  359. while (pai->cZombies > 0) {
  360. Yield(); // give other apps a chance to post terminates.
  361. GetMessage(&msg, (HWND)NULL, 0, 0xffff);
  362. if (msg.message == WM_TIMER && msg.wParam == TID_SHUTDOWN &&
  363. msg.hwnd == pai->hwndDmg) {
  364. if (hiTimeout--) {
  365. SetTimer(pai->hwndDmg, TID_SHUTDOWN, 0xFFFF, NULL);
  366. } else {
  367. FARPROC lpfn;
  368. KillTimer(pai->hwndDmg, TID_SHUTDOWN);
  369. if (!pai->cZombies) {
  370. break;
  371. }
  372. TRACETERM((szT,
  373. "DdeUninitialize Zombie hangup: pai=%x:%x\n",
  374. HIWORD((LPAPPINFO)pai), (WORD)(pai)));
  375. /*
  376. * If the partner window died in any remaining zombie
  377. * windows, get them shut down.
  378. */
  379. ChildMsg(pai->hwndDmg, UM_DISCONNECT, ST_CHECKPARTNER, 0L, FALSE);
  380. if (pai->cZombies > 0) {
  381. lpfn = MakeProcInstance((FARPROC)TermDlgProc, hInstance);
  382. wRet = DialogBox(hInstance, "TermDialog", (HWND)NULL, lpfn);
  383. FreeProcInstance(lpfn);
  384. if (wRet == IDABORT || wRet == -1) {
  385. pai->cZombies = 0;
  386. break; // ignore zombies!
  387. }
  388. if (wRet == IDRETRY) {
  389. hiTimeout = HIWORD(ShutdownRetryTimeout);
  390. SetTimer(pai->hwndDmg, TID_SHUTDOWN,
  391. LOWORD(ShutdownRetryTimeout), NULL);
  392. }
  393. // IDIGNORE - loop forever!
  394. }
  395. }
  396. }
  397. // app should already be shut-down so we don't bother with
  398. // accelerator or menu translations.
  399. DispatchMessage(&msg);
  400. /*
  401. * tell all instances in this task to process their
  402. * callbacks so we can clear our queue.
  403. */
  404. EmptyDDEPostQ();
  405. for (paiT = pAppInfoList; paiT != NULL; paiT = paiT->next) {
  406. if (paiT->hTask == pai->hTask) {
  407. CheckCBQ(paiT);
  408. }
  409. }
  410. }
  411. }
  412. #if 0 // don't need this anymore
  413. if (pai->hwndTimer) {
  414. pai->wTimeoutStatus |= TOS_ABORT;
  415. PostMessage(pai->hwndTimer, WM_TIMER, TID_TIMEOUT, 0);
  416. // if this fails, no big deal because it means the queue is full
  417. // and the modal loop will catch our TOS_ABORT quickly.
  418. // We need to do this in case no activity is happening in the
  419. // modal loop.
  420. }
  421. #endif
  422. if (pai->hwndMonitor) {
  423. DmgDestroyWindow(pai->hwndMonitor);
  424. if (!--cMonitor) {
  425. UnhookWindowsHook(WH_GETMESSAGE, (FARPROC)DdePostHookProc);
  426. UnhookWindowsHook(WH_CALLWNDPROC, (FARPROC)DdeSendHookProc);
  427. }
  428. }
  429. UnlinkAppInfo(pai);
  430. DmgDestroyWindow(pai->hwndDmg);
  431. DmgDestroyWindow(pai->hwndFrame);
  432. while (PopPileSubitem(pai->pHDataPile, (LPBYTE)&hData))
  433. FreeDataHandle(pai, hData, FALSE);
  434. DestroyPile(pai->pHDataPile);
  435. while (PopPileSubitem(pai->pHszPile, (LPBYTE)&a)) {
  436. MONHSZ(a, MH_CLEANUP, pai->hTask);
  437. FreeHsz(a);
  438. }
  439. DestroyPile(pai->pHszPile);
  440. DestroyPile(pai->pAppNamePile);
  441. DestroyLst(pai->pServerAdvList);
  442. DmgDestroyHeap(pai->hheapApp);
  443. pai->instCheck--; // make invalid on later attempts to reinit.
  444. FarFreeMem((LPSTR)pai);
  445. /* last one out.... trash the data info heap */
  446. if (!pAppInfoList) {
  447. #ifdef DEBUG
  448. DIP dip;
  449. AssertF(!PopPileSubitem(pDataInfoPile, (LPBYTE)&dip),
  450. "leftover APPOWNED handles");
  451. #endif
  452. DestroyPile(pDataInfoPile);
  453. DestroyPile(pLostAckPile);
  454. pDataInfoPile = NULL;
  455. pLostAckPile = NULL;
  456. AssertFW(cAtoms == 0, "DdeUninitialize() - leftover atoms");
  457. // PROGMAN HACK!!!!
  458. GlobalDeleteAtom(aProgmanHack);
  459. // CLOSEHEAPWATCH();
  460. }
  461. #ifdef DEBUG
  462. DumpGlobalLogs();
  463. #endif
  464. TRACEAPIOUT((szT, "DdeUninitialize:1\n"));
  465. return(TRUE);
  466. }
  467. HCONVLIST EXPENTRY DdeConnectList(
  468. DWORD idInst,
  469. HSZ hszSvcName,
  470. HSZ hszTopic,
  471. HCONVLIST hConvList,
  472. PCONVCONTEXT pCC)
  473. {
  474. PAPPINFO pai;
  475. HWND hConv, hConvNext, hConvNew, hConvLast;
  476. HWND hConvListNew;
  477. PCLIENTINFO pciOld, pciNew;
  478. TRACEAPIIN((szT, "DdeConnectList(%lx, %lx, %lx, %lx, %lx)\n",
  479. idInst, hszSvcName, hszTopic, hConvList, pCC));
  480. pai = (PAPPINFO)idInst;
  481. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  482. TRACEAPIOUT((szT, "DdeConnectList:0\n"));
  483. return(0L);
  484. }
  485. pai->LastError = DMLERR_NO_ERROR;
  486. if (hConvList && !ValidateHConv(hConvList)) {
  487. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  488. TRACEAPIOUT((szT, "DdeConnectList:0\n"));
  489. return(0L);
  490. }
  491. /*
  492. * destroy any dead old clients
  493. */
  494. if ((HWND)hConvList && (hConv = GetWindow((HWND)hConvList, GW_CHILD))) {
  495. do {
  496. hConvNext = GetWindow((HWND)hConv, GW_HWNDNEXT);
  497. pciOld = (PCLIENTINFO)GetWindowLong(hConv, GWL_PCI);
  498. if (!(pciOld->ci.fs & ST_CONNECTED)) {
  499. SetParent(hConv, pai->hwndDmg);
  500. Disconnect(hConv, ST_PERM2DIE, pciOld);
  501. }
  502. } while (hConv = hConvNext);
  503. }
  504. // create a new list window
  505. if ((hConvListNew = CreateWindow(
  506. SZCONVLISTCLASS,
  507. szNull,
  508. WS_CHILD,
  509. 0, 0, 0, 0,
  510. pai->hwndDmg,
  511. (HMENU)NULL,
  512. hInstance,
  513. &pai)) == NULL) {
  514. SETLASTERROR(pai, DMLERR_SYS_ERROR);
  515. TRACEAPIOUT((szT, "DdeConnectList:0\n"));
  516. return(0L);
  517. }
  518. // Make all possible connections to new list window
  519. hConvNew = GetDDEClientWindow(pai, hConvListNew, HIWORD(hszSvcName), LOWORD(hszSvcName), LOWORD(hszTopic), pCC);
  520. /*
  521. * If no new hConvs created, return old list.
  522. */
  523. if (hConvNew == NULL) {
  524. // if no old hConvs as well, destroy all and return NULL
  525. if ((HWND)hConvList && GetWindow((HWND)hConvList, GW_CHILD) == NULL) {
  526. SendMessage((HWND)hConvList, UM_DISCONNECT,
  527. ST_PERM2DIE, 0L);
  528. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  529. TRACEAPIOUT((szT, "DdeConnectList:0\n"));
  530. return(NULL);
  531. }
  532. // else just return old list (- dead convs)
  533. if (hConvList == NULL) {
  534. DestroyWindow(hConvListNew);
  535. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  536. }
  537. TRACEAPIOUT((szT, "DdeConnectList:%lx\n", hConvList));
  538. return(hConvList);
  539. }
  540. /*
  541. * remove duplicates from the new list
  542. */
  543. if ((HWND)hConvList && (hConv = GetWindow((HWND)hConvList, GW_CHILD))) {
  544. // go throuch old list...
  545. do {
  546. pciOld = (PCLIENTINFO)GetWindowLong(hConv, GWL_PCI);
  547. /*
  548. * destroy any new clients that are duplicates of the old ones.
  549. */
  550. hConvNew = GetWindow(hConvListNew, GW_CHILD);
  551. hConvLast = GetWindow(hConvNew, GW_HWNDLAST);
  552. while (hConvNew) {
  553. if (hConvNew == hConvLast) {
  554. hConvNext = NULL;
  555. } else {
  556. hConvNext = GetWindow(hConvNew, GW_HWNDNEXT);
  557. }
  558. pciNew = (PCLIENTINFO)GetWindowLong(hConvNew, GWL_PCI);
  559. if (pciOld->ci.aServerApp == pciNew->ci.aServerApp &&
  560. pciOld->ci.aTopic == pciNew->ci.aTopic &&
  561. pciOld->ci.hwndFrame == pciNew->ci.hwndFrame) {
  562. /*
  563. * assume same app, same topic, same hwndFrame is a duplicate.
  564. *
  565. * Move dieing window out of the list since it
  566. * dies asynchronously and will still be around
  567. * after this API exits.
  568. */
  569. SetParent(hConvNew, pai->hwndDmg);
  570. Disconnect(hConvNew, ST_PERM2DIE,
  571. (PCLIENTINFO)GetWindowLong(hConvNew, GWL_PCI));
  572. }
  573. hConvNew = hConvNext;
  574. }
  575. hConvNext = GetWindow(hConv, GW_HWNDNEXT);
  576. if (hConvNext && (GetParent(hConvNext) != (HWND)hConvList)) {
  577. hConvNext = NULL;
  578. }
  579. /*
  580. * move the unique old client to the new list
  581. */
  582. SetParent(hConv, hConvListNew);
  583. } while (hConv = hConvNext);
  584. // get rid of the old list
  585. SendMessage((HWND)hConvList, UM_DISCONNECT, ST_PERM2DIE, 0L);
  586. }
  587. /*
  588. * If none are left, fail because no conversations were established.
  589. */
  590. if (GetWindow(hConvListNew, GW_CHILD) == NULL) {
  591. SendMessage(hConvListNew, UM_DISCONNECT, ST_PERM2DIE, 0L);
  592. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  593. TRACEAPIOUT((szT, "DdeConnectList:0\n"));
  594. return(NULL);
  595. } else {
  596. TRACEAPIOUT((szT, "DdeConnectList:%lx\n", MAKEHCONV(hConvListNew)));
  597. return(MAKEHCONV(hConvListNew));
  598. }
  599. }
  600. HCONV EXPENTRY DdeQueryNextServer(
  601. HCONVLIST hConvList,
  602. HCONV hConvPrev)
  603. {
  604. HWND hwndMaybe;
  605. PAPPINFO pai;
  606. TRACEAPIIN((szT, "DdeQueryNextServer(%lx, %lx)\n",
  607. hConvList, hConvPrev));
  608. if (!ValidateHConv(hConvList)) {
  609. pai = NULL;
  610. while (pai = GetCurrentAppInfo(pai)) {
  611. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  612. }
  613. TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
  614. return NULL;
  615. }
  616. pai = EXTRACTHCONVLISTPAI(hConvList);
  617. pai->LastError = DMLERR_NO_ERROR;
  618. if (hConvPrev == NULL) {
  619. TRACEAPIOUT((szT, "DdeQueryNextServer:%lx\n",
  620. MAKEHCONV(GetWindow((HWND)hConvList, GW_CHILD))));
  621. return MAKEHCONV(GetWindow((HWND)hConvList, GW_CHILD));
  622. } else {
  623. if (!ValidateHConv(hConvPrev)) {
  624. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  625. TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
  626. return NULL;
  627. }
  628. hwndMaybe = GetWindow((HWND)hConvPrev, GW_HWNDNEXT);
  629. if (!hwndMaybe) {
  630. TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
  631. return NULL;
  632. }
  633. // make sure it's got the same parent and isn't the first child
  634. // ### maybe this code can go - I'm not sure how GW_HWNDNEXT acts. SS
  635. if (GetParent(hwndMaybe) == (HWND)hConvList &&
  636. hwndMaybe != GetWindow((HWND)hConvList, GW_CHILD)) {
  637. TRACEAPIOUT((szT, "DdeQueryNextServer:%lx\n", MAKEHCONV(hwndMaybe)));
  638. return MAKEHCONV(hwndMaybe);
  639. }
  640. TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
  641. return NULL;
  642. }
  643. }
  644. BOOL EXPENTRY DdeDisconnectList(
  645. HCONVLIST hConvList)
  646. {
  647. PAPPINFO pai;
  648. TRACEAPIIN((szT, "DdeDisconnectList(%lx)\n", hConvList));
  649. if (!ValidateHConv(hConvList)) {
  650. pai = NULL;
  651. while (pai = GetCurrentAppInfo(pai)) {
  652. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  653. }
  654. TRACEAPIOUT((szT, "DdeDisconnectList:0\n"));
  655. return(FALSE);
  656. }
  657. pai = EXTRACTHCONVLISTPAI(hConvList);
  658. pai->LastError = DMLERR_NO_ERROR;
  659. SendMessage((HWND)hConvList, UM_DISCONNECT, ST_PERM2DIE, 0L);
  660. TRACEAPIOUT((szT, "DdeDisconnectList:1\n"));
  661. return(TRUE);
  662. }
  663. HCONV EXPENTRY DdeConnect(
  664. DWORD idInst,
  665. HSZ hszSvcName,
  666. HSZ hszTopic,
  667. PCONVCONTEXT pCC)
  668. {
  669. PAPPINFO pai;
  670. HWND hwnd;
  671. TRACEAPIIN((szT, "DdeConnect(%lx, %lx, %lx, %lx)\n",
  672. idInst, hszSvcName, hszTopic, pCC));
  673. pai = (PAPPINFO)idInst;
  674. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  675. TRACEAPIOUT((szT, "DdeConnect:0\n"));
  676. return(FALSE);
  677. }
  678. pai->LastError = DMLERR_NO_ERROR;
  679. if (pCC && pCC->cb != sizeof(CONVCONTEXT)) {
  680. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  681. TRACEAPIOUT((szT, "DdeConnect:0\n"));
  682. return(0);
  683. }
  684. hwnd = GetDDEClientWindow(pai, pai->hwndDmg, (HWND)HIWORD(hszSvcName),
  685. LOWORD(hszSvcName), LOWORD(hszTopic), pCC);
  686. if (hwnd == 0) {
  687. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  688. }
  689. TRACEAPIOUT((szT, "DdeConnect:%lx\n", MAKEHCONV(hwnd)));
  690. return(MAKEHCONV(hwnd));
  691. }
  692. BOOL EXPENTRY DdeDisconnect(
  693. HCONV hConv)
  694. {
  695. PAPPINFO pai;
  696. PCLIENTINFO pci;
  697. TRACEAPIIN((szT, "DdeDisconnect(%lx)\n", hConv));
  698. if (!ValidateHConv(hConv)) {
  699. pai = NULL;
  700. while (pai = GetCurrentAppInfo(pai)) {
  701. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  702. }
  703. TRACEAPIOUT((szT, "DdeDisconnect:0\n"));
  704. return(FALSE);
  705. }
  706. pai = EXTRACTHCONVPAI(hConv);
  707. pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
  708. if (pai->cInProcess) {
  709. // do asynchronously if this is called within a callback
  710. if (!PostMessage((HWND)hConv, UM_DISCONNECT, ST_PERM2DIE, (LONG)pci)) {
  711. SETLASTERROR(pai, DMLERR_SYS_ERROR);
  712. TRACEAPIOUT((szT, "DdeDisconnect:0\n"));
  713. return(FALSE);
  714. }
  715. } else {
  716. Disconnect((HWND)hConv, ST_PERM2DIE, pci);
  717. }
  718. TRACEAPIOUT((szT, "DdeDisconnect:1\n"));
  719. return(TRUE);
  720. }
  721. HCONV EXPENTRY DdeReconnect(
  722. HCONV hConv)
  723. {
  724. HWND hwnd;
  725. PAPPINFO pai;
  726. PCLIENTINFO pci;
  727. TRACEAPIIN((szT, "DdeReconnect(%lx)\n", hConv));
  728. if (!ValidateHConv(hConv)) {
  729. pai = NULL;
  730. while (pai = GetCurrentAppInfo(pai)) {
  731. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  732. }
  733. TRACEAPIOUT((szT, "DdeReconnect:0\n"));
  734. return(FALSE);
  735. }
  736. pai = EXTRACTHCONVPAI(hConv);
  737. pai->LastError = DMLERR_NO_ERROR;
  738. pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
  739. // The dyeing window MUST be a client to reconnect.
  740. if (!(pci->ci.fs & ST_CLIENT)) {
  741. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  742. TRACEAPIOUT((szT, "DdeReconnect:0\n"));
  743. return(FALSE);
  744. }
  745. hwnd = GetDDEClientWindow(pai, pai->hwndDmg, pci->ci.hwndFrame,
  746. pci->ci.aServerApp, pci->ci.aTopic, &pci->ci.CC);
  747. if (hwnd == 0) {
  748. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  749. TRACEAPIOUT((szT, "DdeReconnect:0\n"));
  750. return(FALSE);
  751. }
  752. if (pci->ci.fs & ST_INLIST) {
  753. SetParent(hwnd, GetParent((HWND)hConv));
  754. }
  755. if (pci->ci.fs & ST_ADVISE) {
  756. DWORD result;
  757. PADVLI pali, paliNext;
  758. // recover advise loops here
  759. for (pali = (PADVLI)pci->pClientAdvList->pItemFirst; pali; pali = paliNext) {
  760. paliNext = (PADVLI)pali->next;
  761. if (pali->hwnd == (HWND)hConv) {
  762. XFERINFO xi;
  763. xi.pulResult = &result;
  764. xi.ulTimeout = (DWORD)TIMEOUT_ASYNC;
  765. xi.wType = XTYP_ADVSTART |
  766. (pali->fsStatus & (XTYPF_NODATA | XTYPF_ACKREQ));
  767. xi.wFmt = pali->wFmt;
  768. xi.hszItem = (HSZ)pali->aItem;
  769. xi.hConvClient = MAKEHCONV(hwnd);
  770. xi.cbData = 0;
  771. xi.hDataClient = NULL;
  772. ClientXferReq(&xi, hwnd,
  773. (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI));
  774. }
  775. }
  776. }
  777. TRACEAPIOUT((szT, "DdeReconnect:%lx\n", MAKEHCONV(hwnd)));
  778. return(MAKEHCONV(hwnd));
  779. }
  780. UINT EXPENTRY DdeQueryConvInfo(
  781. HCONV hConv,
  782. DWORD idTransaction,
  783. PCONVINFO pConvInfo)
  784. {
  785. PCLIENTINFO pci;
  786. PAPPINFO pai;
  787. PXADATA pxad;
  788. PCQDATA pqd;
  789. BOOL fClient;
  790. WORD cb;
  791. CONVINFO ci;
  792. SEMCHECKOUT();
  793. TRACEAPIIN((szT, "DdeQueryConvInfo(%lx, %lx, %lx(->cb=%lx))\n",
  794. hConv, idTransaction, pConvInfo, pConvInfo->cb));
  795. if (!ValidateHConv(hConv) ||
  796. !(pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI))) {
  797. pai = NULL;
  798. while (pai = GetCurrentAppInfo(pai)) {
  799. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  800. }
  801. TRACEAPIOUT((szT, "DdeQueryConvInfo:0\n"));
  802. return(FALSE);
  803. }
  804. pai = pci->ci.pai;
  805. pai->LastError = DMLERR_NO_ERROR;
  806. /*
  807. * This check attempts to prevent improperly coded apps from
  808. * crashing due to having not initialized the cb field.
  809. */
  810. if (pConvInfo->cb > sizeof(CONVINFO) || pConvInfo->cb == 0) {
  811. pConvInfo->cb = sizeof(CONVINFO) -
  812. sizeof(HWND) - // for new hwnd field
  813. sizeof(HWND); // for new hwndPartner field
  814. }
  815. fClient = (BOOL)SendMessage((HWND)hConv, UM_QUERY, Q_CLIENT, 0L);
  816. if (idTransaction == QID_SYNC || !fClient) {
  817. pxad = &pci->ci.xad;
  818. } else {
  819. if (pci->pQ != NULL && (pqd = (PCQDATA)Findqi(pci->pQ, idTransaction))) {
  820. pxad = &pqd->xad;
  821. } else {
  822. SETLASTERROR(pai, DMLERR_UNFOUND_QUEUE_ID);
  823. TRACEAPIOUT((szT, "DdeQueryConvInfo:0\n"));
  824. return(FALSE);
  825. }
  826. }
  827. SEMENTER();
  828. ci.cb = sizeof(CONVINFO);
  829. ci.hConvPartner = (IsWindow((HWND)pci->ci.hConvPartner) &&
  830. ((pci->ci.fs & (ST_ISLOCAL | ST_CONNECTED)) == (ST_ISLOCAL | ST_CONNECTED)))
  831. ? pci->ci.hConvPartner : NULL;
  832. ci.hszSvcPartner = fClient ? pci->ci.aServerApp : 0;
  833. ci.hszServiceReq = pci->ci.hszSvcReq;
  834. ci.hszTopic = pci->ci.aTopic;
  835. ci.wStatus = pci->ci.fs;
  836. ci.ConvCtxt = pci->ci.CC;
  837. if (fClient) {
  838. ci.hUser = pxad->hUser;
  839. ci.hszItem = pxad->pXferInfo->hszItem;
  840. ci.wFmt = pxad->pXferInfo->wFmt;
  841. ci.wType = pxad->pXferInfo->wType;
  842. ci.wConvst = pxad->state;
  843. ci.wLastError = pxad->LastError;
  844. } else {
  845. ci.hUser = pci->ci.xad.hUser;
  846. ci.hszItem = NULL;
  847. ci.wFmt = 0;
  848. ci.wType = 0;
  849. ci.wConvst = pci->ci.xad.state;
  850. ci.wLastError = pci->ci.pai->LastError;
  851. }
  852. ci.hConvList = (pci->ci.fs & ST_INLIST) ?
  853. MAKEHCONV(GetParent((HWND)hConv)) : 0;
  854. cb = min(sizeof(CONVINFO), (WORD)pConvInfo->cb);
  855. ci.hwnd = (HWND)hConv;
  856. ci.hwndPartner = (HWND)pci->ci.hConvPartner;
  857. hmemcpy((LPBYTE)pConvInfo, (LPBYTE)&ci, cb);
  858. pConvInfo->cb = cb;
  859. SEMLEAVE();
  860. TRACEAPIOUT((szT, "DdeQueryConvInfo:%x\n", cb));
  861. return(cb);
  862. }
  863. BOOL EXPENTRY DdeSetUserHandle(
  864. HCONV hConv,
  865. DWORD id,
  866. DWORD hUser)
  867. {
  868. PAPPINFO pai;
  869. PCLIENTINFO pci;
  870. PXADATA pxad;
  871. PCQDATA pqd;
  872. TRACEAPIIN((szT, "DdeSetUserHandle(%lx, %lx, %lx)\n",
  873. hConv, id, hUser));
  874. if (!ValidateHConv(hConv)) {
  875. pai = NULL;
  876. while (pai = GetCurrentAppInfo(pai)) {
  877. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  878. }
  879. TRACEAPIOUT((szT, "DdeSetUserHandle:0\n"));
  880. return(FALSE);
  881. }
  882. pai = EXTRACTHCONVPAI(hConv);
  883. pai->LastError = DMLERR_NO_ERROR;
  884. SEMCHECKOUT();
  885. pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
  886. if (!pci) {
  887. Error:
  888. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  889. TRACEAPIOUT((szT, "DdeSetUserHandle:0\n"));
  890. return(FALSE);
  891. }
  892. pxad = &pci->ci.xad;
  893. if (id != QID_SYNC) {
  894. if (!SendMessage((HWND)hConv, UM_QUERY, Q_CLIENT, 0)) {
  895. goto Error;
  896. }
  897. if (pci->pQ != NULL && (pqd = (PCQDATA)Findqi(pci->pQ, id))) {
  898. pxad = &pqd->xad;
  899. } else {
  900. SETLASTERROR(pai, DMLERR_UNFOUND_QUEUE_ID);
  901. TRACEAPIOUT((szT, "DdeSetUserHandle:0\n"));
  902. return(FALSE);
  903. }
  904. }
  905. pxad->hUser = hUser;
  906. TRACEAPIOUT((szT, "DdeSetUserHandle:1\n"));
  907. return(TRUE);
  908. }
  909. BOOL EXPENTRY DdePostAdvise(
  910. DWORD idInst,
  911. HSZ hszTopic,
  912. HSZ hszItem)
  913. {
  914. PAPPINFO pai;
  915. PSERVERINFO psi = NULL;
  916. register PADVLI pali;
  917. PADVLI paliPrev, paliEnd, paliMove;
  918. TRACEAPIIN((szT, "DdePostAdvise(%lx, %lx, %lx)\n",
  919. idInst, hszTopic, hszItem));
  920. pai = (PAPPINFO)idInst;
  921. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  922. TRACEAPIOUT((szT, "DdePostAdvise:0\n"));
  923. return(FALSE);
  924. }
  925. pai->LastError = DMLERR_NO_ERROR;
  926. if (pai->afCmd & APPCMD_CLIENTONLY) {
  927. SETLASTERROR(pai, DMLERR_DLL_USAGE);
  928. TRACEAPIOUT((szT, "DdePostAdvise:0\n"));
  929. return(FALSE);
  930. }
  931. paliPrev = NULL;
  932. paliEnd = NULL;
  933. paliMove = NULL;
  934. pali = (PADVLI)pai->pServerAdvList->pItemFirst;
  935. while (pali && pali != paliMove) {
  936. if ((!hszItem || pali->aItem == (ATOM)hszItem) &&
  937. (!hszTopic || pali->aTopic == (ATOM)hszTopic)) {
  938. /*
  939. * Advise loops are tricky because of the desireable FACKREQ feature
  940. * of DDE. The advise loop list holds information in its fsStatus
  941. * field to maintain the state of the advise loop.
  942. *
  943. * if the ADVST_WAITING bit is set, the server is still waiting for
  944. * the client to give it the go-ahead for more data with an
  945. * ACK message on this item. (FACKREQ is set) Without a go-ahead,
  946. * the server will not send any more advise data to the client but
  947. * will instead set the ADVST_CHANGED bit which will cause another
  948. * WM_DDE_DATA message to be sent to the client as soon as the
  949. * go-ahead ACK is received. This keeps the client up to date
  950. * but never overloads it.
  951. */
  952. if (pali->fsStatus & ADVST_WAITING) {
  953. /*
  954. * if the client has not yet finished with the last data
  955. * we gave him, just update the advise loop status
  956. * instead of sending data now.
  957. */
  958. pali->fsStatus |= ADVST_CHANGED;
  959. goto NextLink;
  960. }
  961. psi = (PSERVERINFO)GetWindowLong(pali->hwnd, GWL_PCI);
  962. if (pali->fsStatus & DDE_FDEFERUPD) {
  963. /*
  964. * In the nodata case, we don't bother the server. Just
  965. * pass the client an apropriate DATA message.
  966. */
  967. IncHszCount(pali->aItem); // message copy
  968. #ifdef DEBUG
  969. cAtoms--; // don't count this add
  970. #endif
  971. PostDdeMessage(&psi->ci, WM_DDE_DATA, pali->hwnd,
  972. MAKELONG(0, pali->aItem), 0, 0);
  973. } else {
  974. PostServerAdvise(pali->hwnd, psi, pali, CountAdvReqLeft(pali));
  975. }
  976. if (pali->fsStatus & DDE_FACKREQ && pali->next) {
  977. /*
  978. * In order to know what ack goes with what data sent out, we
  979. * place any updated advise loops at the end of the list so
  980. * that acks associated with them are found last. ie First ack
  981. * back goes with oldest data out.
  982. */
  983. // Unlink
  984. if (paliPrev) {
  985. paliPrev->next = pali->next;
  986. } else {
  987. pai->pServerAdvList->pItemFirst = (PLITEM)pali->next;
  988. }
  989. // put on the end
  990. if (paliEnd) {
  991. paliEnd->next = (PLITEM)pali;
  992. paliEnd = pali;
  993. } else {
  994. for (paliEnd = pali;
  995. paliEnd->next;
  996. paliEnd = (PADVLI)paliEnd->next) {
  997. }
  998. paliEnd->next = (PLITEM)pali;
  999. paliMove = paliEnd = pali;
  1000. }
  1001. pali->next = NULL;
  1002. if (paliPrev) {
  1003. pali = (PADVLI)paliPrev->next;
  1004. } else {
  1005. pali = (PADVLI)pai->pServerAdvList->pItemFirst;
  1006. }
  1007. continue;
  1008. }
  1009. }
  1010. NextLink:
  1011. paliPrev = pali;
  1012. pali = (PADVLI)pali->next;
  1013. }
  1014. TRACEAPIOUT((szT, "DdePostAdvise:1\n"));
  1015. return(TRUE);
  1016. }
  1017. /*
  1018. * History: 4/18/91 sanfords - now always frees any incomming data handle
  1019. * thats not APPOWNED regardless of error case.
  1020. */
  1021. HDDEDATA EXPENTRY DdeClientTransaction(
  1022. LPBYTE pData,
  1023. DWORD cbData,
  1024. HCONV hConv,
  1025. HSZ hszItem,
  1026. UINT wFmt,
  1027. UINT wType,
  1028. DWORD ulTimeout,
  1029. LPDWORD pulResult)
  1030. {
  1031. PAPPINFO pai;
  1032. PCLIENTINFO pci;
  1033. HDDEDATA hData, hDataBack, hRet = 0;
  1034. SEMCHECKOUT();
  1035. TRACEAPIIN((szT, "DdeClientTransaction(%lx, %lx, %lx, %lx, %x, %x, %lx, %lx)\n",
  1036. pData, cbData, hConv, hszItem, wFmt, wType, ulTimeout, pulResult));
  1037. if (!ValidateHConv(hConv)) {
  1038. pai = NULL;
  1039. while (pai = GetCurrentAppInfo(pai)) {
  1040. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1041. }
  1042. goto FreeErrExit;
  1043. }
  1044. pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
  1045. pai = pci->ci.pai;
  1046. /*
  1047. * Don't let transactions happen if we are shutting down
  1048. * or are already doing a sync transaction.
  1049. */
  1050. if ((ulTimeout != TIMEOUT_ASYNC && pai->wFlags & AWF_INSYNCTRANSACTION) ||
  1051. pai->wFlags & AWF_UNINITCALLED) {
  1052. SETLASTERROR(pai, DMLERR_REENTRANCY);
  1053. goto FreeErrExit;
  1054. }
  1055. pci->ci.pai->LastError = DMLERR_NO_ERROR;
  1056. if (!(pci->ci.fs & ST_CONNECTED)) {
  1057. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  1058. goto FreeErrExit;
  1059. }
  1060. // If local, check filters first
  1061. if (pci->ci.fs & ST_ISLOCAL) {
  1062. PAPPINFO paiServer;
  1063. PSERVERINFO psi;
  1064. // we can do this because the app heaps are in global shared memory
  1065. psi = (PSERVERINFO)GetWindowLong((HWND)pci->ci.hConvPartner, GWL_PCI);
  1066. if (!psi) {
  1067. // SERVER DIED! - simulate a terminate received.
  1068. Terminate((HWND)hConv, (HWND)pci->ci.hConvPartner, pci);
  1069. SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
  1070. goto FreeErrExit;
  1071. }
  1072. paiServer = psi->ci.pai;
  1073. if (paiServer->afCmd & aulmapType[(wType & XTYP_MASK) >> XTYP_SHIFT]) {
  1074. SETLASTERROR(pai, DMLERR_NOTPROCESSED);
  1075. FreeErrExit:
  1076. if ((wType == XTYP_POKE || wType == XTYP_EXECUTE) && cbData == -1 &&
  1077. !(LOWORD((DWORD)pData) & HDATA_APPOWNED)) {
  1078. FREEEXTHDATA(pData);
  1079. }
  1080. TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
  1081. return(0);
  1082. }
  1083. }
  1084. pai = pci->ci.pai;
  1085. switch (wType) {
  1086. case XTYP_POKE:
  1087. case XTYP_EXECUTE:
  1088. // prepair the outgoing handle
  1089. if (cbData == -1L) { // handle given, not pointer
  1090. hData = ((LPEXTDATAINFO)pData)->hData;
  1091. if (!(LOWORD(hData) & HDATA_APPOWNED)) {
  1092. FREEEXTHDATA(pData);
  1093. }
  1094. if (!(hData = DllEntry(&pci->ci, hData))) {
  1095. TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
  1096. return(0);
  1097. }
  1098. pData = (LPBYTE)hData; // place onto stack for pass on to ClientXferReq.
  1099. } else { // pointer given, create handle from it.
  1100. if (!(pData = (LPBYTE)PutData(pData, cbData, 0, LOWORD(hszItem), wFmt, 0, pai))) {
  1101. SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
  1102. TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
  1103. return(0);
  1104. }
  1105. }
  1106. hData = (HDDEDATA)pData; // used to prevent compiler over-optimization.
  1107. case XTYP_REQUEST:
  1108. case XTYP_ADVSTART:
  1109. case XTYP_ADVSTART | XTYPF_NODATA:
  1110. case XTYP_ADVSTART | XTYPF_ACKREQ:
  1111. if (wType != XTYP_EXECUTE && !hszItem) {
  1112. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1113. TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
  1114. return(0);
  1115. }
  1116. case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
  1117. if (wType != XTYP_EXECUTE && !wFmt) {
  1118. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1119. TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
  1120. return(0);
  1121. }
  1122. case XTYP_ADVSTOP:
  1123. pai->LastError = DMLERR_NO_ERROR; // reset before start.
  1124. if (ulTimeout == TIMEOUT_ASYNC) {
  1125. hRet = (HDDEDATA)ClientXferReq((PXFERINFO)&pulResult, (HWND)hConv, pci);
  1126. } else {
  1127. pai->wFlags |= AWF_INSYNCTRANSACTION;
  1128. hDataBack = (HDDEDATA)ClientXferReq((PXFERINFO)&pulResult, (HWND)hConv, pci);
  1129. pai->wFlags &= ~AWF_INSYNCTRANSACTION;
  1130. if ((wType & XCLASS_DATA) && hDataBack) {
  1131. LPEXTDATAINFO pedi;
  1132. //if (AddPileItem(pai->pHDataPile, (LPBYTE)&hDataBack, CmpHIWORD) == API_ERROR) {
  1133. // SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
  1134. // goto ReturnPoint;
  1135. //}
  1136. // use app heap so any leftovers at Uninitialize time go away.
  1137. pedi = (LPEXTDATAINFO)FarAllocMem(pai->hheapApp, sizeof(EXTDATAINFO));
  1138. if (pedi) {
  1139. pedi->pai = pai;
  1140. pedi->hData = hDataBack;
  1141. } else {
  1142. SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
  1143. }
  1144. hRet = (HDDEDATA)pedi;
  1145. goto ReturnPoint;
  1146. } else if (hDataBack) {
  1147. hRet = TRUE;
  1148. }
  1149. }
  1150. goto ReturnPoint;
  1151. }
  1152. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1153. ReturnPoint:
  1154. if (pai->wFlags & AWF_UNINITCALLED) {
  1155. pai->wFlags &= ~AWF_UNINITCALLED;
  1156. DdeUninitialize(MAKELONG((WORD)pai, pai->instCheck));
  1157. }
  1158. TRACEAPIOUT((szT, "DdeClientTransaction:%lx\n", hRet));
  1159. return(hRet);
  1160. }
  1161. /***************************** Public Function ****************************\
  1162. * PUBDOC START
  1163. * WORD EXPENTRY DdeGetLastError(void)
  1164. *
  1165. * This API returns the most recent error registered by the DDE manager for
  1166. * the current thread. This should be called anytime a DDE manager API
  1167. * returns in a failed state.
  1168. *
  1169. * returns an error code which corresponds to a DMLERR_ constant found in
  1170. * ddeml.h. This error code may be passed on to DdePostError() to
  1171. * show the user the reason for the error.
  1172. *
  1173. * PUBDOC END
  1174. *
  1175. * History:
  1176. * Created 12/14/88 Sanfords
  1177. \***************************************************************************/
  1178. UINT EXPENTRY DdeGetLastError(
  1179. DWORD idInst)
  1180. {
  1181. register PAPPINFO pai;
  1182. register WORD err = DMLERR_DLL_NOT_INITIALIZED;
  1183. TRACEAPIIN((szT, "DdeGetLastError(%lx)\n", idInst));
  1184. pai = (PAPPINFO)idInst;
  1185. if (pai) {
  1186. if (pai->instCheck != HIWORD(idInst)) {
  1187. TRACEAPIOUT((szT, "DdeGetLastError:%x [bad instance]\n",
  1188. DMLERR_INVALIDPARAMETER));
  1189. return(DMLERR_INVALIDPARAMETER);
  1190. }
  1191. err = pai->LastError;
  1192. pai->LastError = DMLERR_NO_ERROR;
  1193. }
  1194. TRACEAPIOUT((szT, "DdeGetLastError:%x\n", err));
  1195. return(err);
  1196. }
  1197. /*\
  1198. * Data Handles:
  1199. *
  1200. * Control flags:
  1201. *
  1202. * HDCF_APPOWNED
  1203. * Only the app can free this in the apps PID/TID context.
  1204. * SET - when DdeCreateDataHandle is called with this flag given.
  1205. * The hData is Logged at this time.
  1206. *
  1207. * HDCF_READONLY - set by ClientXfer and callback return.
  1208. * The app cannot add data to handles in this state.
  1209. * SET - when ClientXfer is entered
  1210. * SET - when callback is left
  1211. *
  1212. * The DLL can free:
  1213. * any hData EXCEPT those hDatas which are
  1214. * APPOWNED where PIDcurrent == PIDowner.
  1215. *
  1216. * any unfreed logged hDatas are freed at unregistration time.
  1217. *
  1218. * The APP can free:
  1219. * any logged hData.
  1220. *
  1221. * Logging points: ClientXfer return, CheckQueue return, PutData(APPOWNED).
  1222. *
  1223. * WARNING:
  1224. *
  1225. * Apps with multiple thread registration that talk to themselves
  1226. * must not free hDatas until all threads are done with them.
  1227. *
  1228. \*/
  1229. /***************************** Public Function ****************************\
  1230. * PUBDOC START
  1231. * HDDEDATA EXPENTRY DdeCreateDataHandle(pSrc, cb, cbOff, hszItem, wFmt, afCmd)
  1232. * LPBYTE pSrc;
  1233. * DWORD cb;
  1234. * DWORD cbOff;
  1235. * HSZ hszItem;
  1236. * WORD wFmt;
  1237. * WORD afCmd;
  1238. *
  1239. * This api allows a server application to create a hData apropriate
  1240. * for return from its call-back function.
  1241. * The passed in data is stored into the hData which is
  1242. * returned on success. Any portions of the data handle not filled are
  1243. * undefined. afCmd contains any of the HDATA_ constants described below:
  1244. *
  1245. * HDATA_APPOWNED
  1246. * This declares the created data handle to be the responsability of
  1247. * the application to free it. Application owned data handles may
  1248. * be returned from the callback function multiple times. This allows
  1249. * a server app to be able to support many clients without having to
  1250. * recopy the data for each request.
  1251. *
  1252. * NOTES:
  1253. * If an application expects this data handle to hold >64K of data via
  1254. * DdeAddData(), it should specify a cb + cbOff to be as large as
  1255. * the object is expected to get to avoid unnecessary data copying
  1256. * or reallocation by the DLL.
  1257. *
  1258. * if psrc==NULL, no actual data copying takes place.
  1259. *
  1260. * Data handles given to an application via the DdeMgrClientXfer() or
  1261. * DdeMgrCheckQueue() functions are the responsability of the client
  1262. * application to free and MUST NOT be returned from the callback
  1263. * function as server data!
  1264. *
  1265. * PUBDOC END
  1266. *
  1267. * History:
  1268. * Created 12/14/88 Sanfords
  1269. \***************************************************************************/
  1270. HDDEDATA EXPENTRY DdeCreateDataHandle(
  1271. DWORD idInst,
  1272. LPBYTE pSrc,
  1273. DWORD cb,
  1274. DWORD cbOff,
  1275. HSZ hszItem,
  1276. UINT wFmt,
  1277. UINT afCmd)
  1278. {
  1279. PAPPINFO pai;
  1280. HDDEDATA hData;
  1281. TRACEAPIIN((szT, "DdeCreateDataHandle(%lx, %lx, %lx, %lx, %lx, %x, %x)\n",
  1282. idInst, pSrc, cb, cbOff, hszItem, wFmt, afCmd));
  1283. pai = (PAPPINFO)idInst;
  1284. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  1285. TRACEAPIOUT((szT, "DdeCreateDataHandle:0\n"));
  1286. return(0);
  1287. }
  1288. pai->LastError = DMLERR_NO_ERROR;
  1289. if (afCmd & ~(HDATA_APPOWNED)) {
  1290. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1291. TRACEAPIOUT((szT, "DdeCreateDataHandle:0\n"));
  1292. return(0L);
  1293. }
  1294. hData = PutData(pSrc, cb, cbOff, LOWORD(hszItem), wFmt, afCmd, pai);
  1295. if (hData) {
  1296. LPEXTDATAINFO pedi;
  1297. // use app heap so any leftovers at Uninitialize time go away.
  1298. pedi = (LPEXTDATAINFO)FarAllocMem(pai->hheapApp, sizeof(EXTDATAINFO));
  1299. if (pedi) {
  1300. pedi->pai = pai;
  1301. pedi->hData = hData;
  1302. }
  1303. hData = (HDDEDATA)(DWORD)pedi;
  1304. }
  1305. TRACEAPIOUT((szT, "DdeCreateDataHandle:%lx\n", hData));
  1306. return(hData);
  1307. }
  1308. HDDEDATA EXPENTRY DdeAddData(
  1309. HDDEDATA hData,
  1310. LPBYTE pSrc,
  1311. DWORD cb,
  1312. DWORD cbOff)
  1313. {
  1314. PAPPINFO pai;
  1315. HDDEDATA FAR * phData;
  1316. DIP newDip;
  1317. HANDLE hd, hNewData;
  1318. LPEXTDATAINFO pedi;
  1319. TRACEAPIIN((szT, "DdeAddData(%lx, %lx, %lx, %lx)\n",
  1320. hData, pSrc, cb, cbOff));
  1321. if (!hData)
  1322. goto DdeAddDataError;
  1323. pedi = (LPEXTDATAINFO)hData;
  1324. pai = pedi->pai;
  1325. pai->LastError = DMLERR_NO_ERROR;
  1326. hData = pedi->hData;
  1327. /* if the datahandle is bogus, abort */
  1328. hd = hNewData = HIWORD(hData);
  1329. if (!hd || (LOWORD(hData) & HDATA_READONLY)) {
  1330. DdeAddDataError:
  1331. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1332. TRACEAPIOUT((szT, "DdeAddData:0\n"));
  1333. return(0L);
  1334. }
  1335. /*
  1336. * we need this check in case the owning app is trying to reallocate
  1337. * after giving the hData away. (his copy of the handle would not have
  1338. * the READONLY flag set)
  1339. */
  1340. phData = (HDDEDATA FAR *)FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, 0);
  1341. if (!phData || LOWORD(*phData) & HDATA_READONLY) {
  1342. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1343. TRACEAPIOUT((szT, "DdeAddData:0\n"));
  1344. return(0L);
  1345. }
  1346. /* HACK ALERT!
  1347. * make sure the first two words req'd by windows dde is there,
  1348. * that is if the data isn't from an execute
  1349. */
  1350. if (!(LOWORD(hData) & HDATA_EXEC)) {
  1351. cbOff += 4L;
  1352. }
  1353. if (GlobalSize(hd) < cb + cbOff) {
  1354. /*
  1355. * need to grow the block before putting new data in...
  1356. */
  1357. if (!(hNewData = GLOBALREALLOC(hd, cb + cbOff, GMEM_MOVEABLE))) {
  1358. /*
  1359. * We can't grow the seg. Try allocating a new one.
  1360. */
  1361. if (!(hNewData = GLOBALALLOC(GMEM_MOVEABLE | GMEM_DDESHARE,
  1362. cb + cbOff))) {
  1363. /* failed.... die */
  1364. SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
  1365. TRACEAPIOUT((szT, "DdeAddData:0\n"));
  1366. return(0);
  1367. } else {
  1368. /*
  1369. * got a new block, now copy data and trash old one
  1370. */
  1371. CopyHugeBlock(GLOBALPTR(hd), GLOBALPTR(hNewData), GlobalSize(hd));
  1372. GLOBALFREE(hd); // objects flow through - no need to free.
  1373. }
  1374. }
  1375. if (hNewData != hd) {
  1376. /* if the handle is different and in piles, update data piles */
  1377. if (FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE)) {
  1378. DIP *pDip;
  1379. HDDEDATA hdT;
  1380. // replace entry in global data info pile.
  1381. if (pDip = (DIP *)(DWORD)FindPileItem(pDataInfoPile, CmpWORD, (LPBYTE)&hd, 0)) {
  1382. newDip.hData = hNewData;
  1383. newDip.hTask = pDip->hTask;
  1384. newDip.cCount = pDip->cCount;
  1385. newDip.fFlags = pDip->fFlags;
  1386. FindPileItem(pDataInfoPile, CmpWORD, (LPBYTE)&hd, FPI_DELETE);
  1387. /* following assumes addpileitem will not fail...!!! */
  1388. AddPileItem(pDataInfoPile, (LPBYTE)&newDip, CmpWORD);
  1389. }
  1390. hdT = (HDDEDATA)MAKELONG(newDip.fFlags, hNewData);
  1391. AddPileItem(pai->pHDataPile, (LPBYTE)&hdT, CmpHIWORD);
  1392. }
  1393. hData = MAKELONG(LOWORD(hData), hNewData);
  1394. }
  1395. }
  1396. if (pSrc) {
  1397. CopyHugeBlock(pSrc, HugeOffset(GLOBALLOCK(HIWORD(hData)), cbOff), cb);
  1398. }
  1399. pedi->hData = hData;
  1400. TRACEAPIOUT((szT, "DdeAddData:%lx\n", pedi));
  1401. return((HDDEDATA)pedi);
  1402. }
  1403. DWORD EXPENTRY DdeGetData(hData, pDst, cbMax, cbOff)
  1404. HDDEDATA hData;
  1405. LPBYTE pDst;
  1406. DWORD cbMax;
  1407. DWORD cbOff;
  1408. {
  1409. PAPPINFO pai;
  1410. DWORD cbSize;
  1411. BOOL fExec = TRUE;
  1412. TRACEAPIIN((szT, "DdeGetData(%lx, %lx, %lx, %lx)\n",
  1413. hData, pDst, cbMax, cbOff));
  1414. //
  1415. // Check for NULL.
  1416. // Packard Bell Navigator passes NULL at startup. In 3.1 we'd
  1417. // maybe trash our local heap using ds:0. But now touching pai will
  1418. // fault since it's a far pointer and 0:0 is bad.
  1419. //
  1420. // Also makes your system stabler.
  1421. //
  1422. if (!hData)
  1423. goto DdeGetDataError;
  1424. pai = EXTRACTHDATAPAI(hData);
  1425. pai->LastError = DMLERR_NO_ERROR;
  1426. hData = ((LPEXTDATAINFO)hData)->hData;
  1427. cbSize = GlobalSize(HIWORD(hData));
  1428. /* HACK ALERT!
  1429. * make sure the first two words req'd by windows dde is there,
  1430. * as long as it's not execute data
  1431. */
  1432. if (!(LOWORD(hData) & HDATA_EXEC)) {
  1433. cbOff += 4;
  1434. fExec = FALSE;
  1435. }
  1436. if (cbOff >= cbSize)
  1437. {
  1438. DdeGetDataError:
  1439. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1440. TRACEAPIOUT((szT, "DdeGetData:0\n"));
  1441. return(0L);
  1442. }
  1443. cbMax = min(cbMax, cbSize - cbOff);
  1444. if (pDst == NULL) {
  1445. TRACEAPIOUT((szT, "DdeGetData:%lx\n", fExec ? cbSize : cbSize - 4));
  1446. return(fExec ? cbSize : cbSize - 4);
  1447. } else {
  1448. CopyHugeBlock(HugeOffset(GLOBALLOCK(HIWORD(hData)), cbOff),
  1449. pDst, cbMax);
  1450. TRACEAPIOUT((szT, "DdeGetData:%lx\n", cbMax));
  1451. return(cbMax);
  1452. }
  1453. }
  1454. LPBYTE EXPENTRY DdeAccessData(
  1455. HDDEDATA hData,
  1456. LPDWORD pcbDataSize)
  1457. {
  1458. PAPPINFO pai;
  1459. DWORD offset;
  1460. LPBYTE lpRet;
  1461. TRACEAPIIN((szT, "DdeAccessData(%lx, %lx)\n",
  1462. hData, pcbDataSize));
  1463. if (!hData)
  1464. goto DdeAccessDataError;
  1465. pai = EXTRACTHDATAPAI(hData);
  1466. pai->LastError = DMLERR_NO_ERROR;
  1467. hData = ((LPEXTDATAINFO)hData)->hData;
  1468. if (HIWORD(hData) && (HIWORD(hData) != 0xFFFF) ) {
  1469. /* messed around here getting past the first two words, which
  1470. * aren't even there if this is execute data
  1471. */
  1472. offset = (LOWORD(hData) & HDATA_EXEC) ? 0L : 4L;
  1473. if (pcbDataSize) {
  1474. *pcbDataSize = GlobalSize(HIWORD(hData)) - offset;
  1475. }
  1476. lpRet = (LPBYTE)GLOBALLOCK(HIWORD(hData)) + offset;
  1477. TRACEAPIOUT((szT, "DdeAccessData:%lx\n", lpRet));
  1478. return(lpRet);
  1479. }
  1480. DdeAccessDataError:
  1481. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1482. TRACEAPIOUT((szT, "DdeAccessData:0\n"));
  1483. return(0L);
  1484. }
  1485. BOOL EXPENTRY DdeUnaccessData(
  1486. HDDEDATA hData)
  1487. {
  1488. PAPPINFO pai;
  1489. TRACEAPIIN((szT, "DdeUnaccessData(%lx)\n", hData));
  1490. //
  1491. // BOGUS -- we should set last error and RIP also.
  1492. //
  1493. if (hData)
  1494. {
  1495. pai = EXTRACTHDATAPAI(hData);
  1496. pai->LastError = DMLERR_NO_ERROR;
  1497. }
  1498. TRACEAPIOUT((szT, "DdeUnaccessData:1\n"));
  1499. return(TRUE);
  1500. }
  1501. // Diamond Multimedia Kit 5000 creates a non-app-owned data handle,
  1502. // uses it in a client transaction (which free's it) and then
  1503. // calls DDEFreeDataHandle which can fault (depending on what junk
  1504. // gets left behind). To handle this we validate the data handle
  1505. // before doing anything else.
  1506. BOOL HDdeData_Validate(HDDEDATA hData)
  1507. {
  1508. WORD wSaveDS;
  1509. UINT nRet;
  1510. // we better check HIWORD(hData) before we try to stuff it into ds
  1511. if(IsBadReadPtr((LPCSTR)hData, 1)) {
  1512. #ifdef DEBUG
  1513. OutputDebugString("DDEML: Invalid HDDEDATA.\n\r");
  1514. #endif
  1515. return(FALSE);
  1516. }
  1517. wSaveDS = SwitchDS(HIWORD(hData));
  1518. // Use the validation layer to check the handle
  1519. // We can call LocalSize with the near ptr as the handle because:
  1520. // 1. The HDDEDATA was allocated with LPTR (LMEM_FIXED | LMEM_ZEROINIT)
  1521. // 2. Local mem that is alloc'd LMEM_FIXED, the offset is the handle
  1522. // 3. We don't want to call LocalHandle to get the handle because it has
  1523. // no parameter vailidation & blows up for bad handles
  1524. nRet = LocalSize((HANDLE)LOWORD(hData));
  1525. SwitchDS(wSaveDS);
  1526. #ifdef DEBUG
  1527. if (!nRet) {
  1528. OutputDebugString("DDEML: Invalid HDDEDATA.\n\r");
  1529. }
  1530. #endif
  1531. return nRet;
  1532. }
  1533. BOOL EXPENTRY DdeFreeDataHandle(
  1534. HDDEDATA hData)
  1535. {
  1536. PAPPINFO pai;
  1537. LPEXTDATAINFO pedi;
  1538. TRACEAPIIN((szT, "DdeFreeDataHandle(%lx)\n", hData));
  1539. pedi = (LPEXTDATAINFO)hData;
  1540. if ( !pedi || !HDdeData_Validate(hData) ) {
  1541. TRACEAPIOUT((szT, "DdeFreeDataHandle:1\n"));
  1542. return(TRUE);
  1543. }
  1544. pai = EXTRACTHDATAPAI(hData);
  1545. pai->LastError = DMLERR_NO_ERROR;
  1546. if (!(LOWORD(pedi->hData) & HDATA_NOAPPFREE)) {
  1547. FreeDataHandle(pedi->pai, pedi->hData, FALSE);
  1548. FarFreeMem((LPSTR)pedi);
  1549. }
  1550. TRACEAPIOUT((szT, "DdeFreeDataHandle:2\n"));
  1551. return(TRUE);
  1552. }
  1553. /***************************************************************************\
  1554. * PUBDOC START
  1555. * HSZ management notes:
  1556. *
  1557. * HSZs are used in this DLL to simplify string handling for applications
  1558. * and for inter-process communication. Since many applications use a
  1559. * fixed set of Application/Topic/Item names, it is convenient to convert
  1560. * them to HSZs and allow quick comparisons for lookups. This also frees
  1561. * the DLL up from having to constantly provide string buffers for copying
  1562. * strings between itself and its clients.
  1563. *
  1564. * HSZs are the same as atoms except they have no restrictions on length or
  1565. * number and are 32 bit values. They are case preserving and can be
  1566. * compared directly for case sensitive comparisons or via DdeCmpStringHandles()
  1567. * for case insensitive comparisons.
  1568. *
  1569. * When an application creates an HSZ via DdeCreateStringHandle() or increments its
  1570. * count via DdeKeepStringHandle() it is essentially claiming the HSZ for
  1571. * its own use. On the other hand, when an application is given an
  1572. * HSZ from the DLL via a callback, it is using another application's HSZ
  1573. * and should not free that HSZ via DdeFreeStringHandle().
  1574. *
  1575. * The DLL insures that during the callback any HSZs given will remain
  1576. * valid for the duration of the callback.
  1577. *
  1578. * If an application wishes to keep that HSZ to use for itself as a
  1579. * standard for future comparisons, it should increment its count so that,
  1580. * should the owning application free it, the HSZ will not become invalid.
  1581. * This also prevents an HSZ from changing its value. (ie, app A frees it
  1582. * and then app B creates a new one that happens to use the same HSZ code,
  1583. * then app C, which had the HSZ stored all along (but forgot to increment
  1584. * its count) now is holding a handle to a different string.)
  1585. *
  1586. * Applications may free HSZs they have created or incremented at any time
  1587. * by calling DdeFreeStringHandle().
  1588. *
  1589. * The DLL internally increments HSZ counts while in use so that they will
  1590. * not be destroyed until both the DLL and all applications concerned are
  1591. * through with them.
  1592. *
  1593. * IT IS THE APPLICATIONS RESPONSIBILITY TO PROPERLY CREATE AND FREE HSZs!!
  1594. *
  1595. * PUBDOC END
  1596. \***************************************************************************/
  1597. HSZ EXPENTRY DdeCreateStringHandle(
  1598. DWORD idInst,
  1599. LPCSTR psz,
  1600. int iCodePage)
  1601. {
  1602. #define pai ((PAPPINFO)idInst)
  1603. ATOM a;
  1604. TRACEAPIIN((szT, "DdeCreateStringHandle(%lx, %s, %x)\n",
  1605. idInst, psz, iCodePage));
  1606. if (pai == NULL | pai->instCheck != HIWORD(idInst)) {
  1607. TRACEAPIOUT((szT, "DdeCreateStringHandle:0\n"));
  1608. return(0);
  1609. }
  1610. pai->LastError = DMLERR_NO_ERROR;
  1611. if (psz == NULL || *psz == '\0') {
  1612. TRACEAPIOUT((szT, "DdeCreateStringHandle:0\n"));
  1613. return(0);
  1614. }
  1615. if (iCodePage == 0 || iCodePage == CP_WINANSI || iCodePage == GetKBCodePage()) {
  1616. SEMENTER();
  1617. a = FindAddHsz((LPSTR)psz, TRUE);
  1618. SEMLEAVE();
  1619. MONHSZ(a, MH_CREATE, pai->hTask);
  1620. if (AddPileItem(pai->pHszPile, (LPBYTE)&a, NULL) == API_ERROR) {
  1621. SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
  1622. a = 0;
  1623. }
  1624. TRACEAPIOUT((szT, "DdeCreateStringHandle:%x\n", a));
  1625. return((HSZ)a);
  1626. } else {
  1627. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1628. TRACEAPIOUT((szT, "DdeCreateStringHandle:0\n"));
  1629. return(0);
  1630. }
  1631. #undef pai
  1632. }
  1633. BOOL EXPENTRY DdeFreeStringHandle(
  1634. DWORD idInst,
  1635. HSZ hsz)
  1636. {
  1637. PAPPINFO pai;
  1638. ATOM a = LOWORD(hsz);
  1639. BOOL fRet;
  1640. TRACEAPIIN((szT, "DdeFreeStringHandle(%lx, %lx)\n",
  1641. idInst, hsz));
  1642. pai = (PAPPINFO)idInst;
  1643. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  1644. TRACEAPIOUT((szT, "DdeFreeStringHandle:0\n"));
  1645. return(FALSE);
  1646. }
  1647. pai->LastError = DMLERR_NO_ERROR;
  1648. MONHSZ(a, MH_DELETE, pai->hTask);
  1649. FindPileItem(pai->pHszPile, CmpWORD, (LPBYTE)&a, FPI_DELETE);
  1650. fRet = FreeHsz(a);
  1651. TRACEAPIOUT((szT, "DdeFreeStringHandle:%x\n", fRet));
  1652. return(fRet);
  1653. }
  1654. BOOL EXPENTRY DdeKeepStringHandle(
  1655. DWORD idInst,
  1656. HSZ hsz)
  1657. {
  1658. PAPPINFO pai;
  1659. ATOM a = LOWORD(hsz);
  1660. BOOL fRet;
  1661. TRACEAPIIN((szT, "DdeKeepStringHandle(%lx, %lx)\n",
  1662. idInst, hsz));
  1663. pai = (PAPPINFO)idInst;
  1664. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  1665. TRACEAPIOUT((szT, "DdeKeepStringHandle:0\n"));
  1666. return(FALSE);
  1667. }
  1668. pai->LastError = DMLERR_NO_ERROR;
  1669. MONHSZ(a, MH_KEEP, pai->hTask);
  1670. AddPileItem(pai->pHszPile, (LPBYTE)&a, NULL);
  1671. fRet = IncHszCount(a);
  1672. TRACEAPIOUT((szT, "DdeKeepStringHandle:%x\n", fRet));
  1673. return(fRet);
  1674. }
  1675. DWORD EXPENTRY DdeQueryString(
  1676. DWORD idInst,
  1677. HSZ hsz,
  1678. LPSTR psz,
  1679. DWORD cchMax,
  1680. int iCodePage)
  1681. {
  1682. PAPPINFO pai;
  1683. DWORD dwRet;
  1684. TRACEAPIIN((szT, "DdeQueryString(%lx, %lx, %lx, %lx, %x)\n",
  1685. idInst, hsz, psz, cchMax, iCodePage));
  1686. pai = (PAPPINFO)idInst;
  1687. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  1688. TRACEAPIOUT((szT, "DdeQueryString:0\n"));
  1689. return(FALSE);
  1690. }
  1691. pai->LastError = DMLERR_NO_ERROR;
  1692. if (iCodePage == 0 || iCodePage == CP_WINANSI || iCodePage == GetKBCodePage()) {
  1693. if (psz) {
  1694. if (hsz) {
  1695. dwRet = QueryHszName(hsz, psz, (WORD)cchMax);
  1696. TRACEAPIOUT((szT, "DdeQueryString:%lx(%s)\n", dwRet, psz));
  1697. return(dwRet);
  1698. } else {
  1699. *psz = '\0';
  1700. TRACEAPIOUT((szT, "DdeQueryString:0\n"));
  1701. return(0);
  1702. }
  1703. } else if (hsz) {
  1704. dwRet = QueryHszLength(hsz);
  1705. TRACEAPIOUT((szT, "DdeQueryString:%lx\n", dwRet));
  1706. return(dwRet);
  1707. } else {
  1708. TRACEAPIOUT((szT, "DdeQueryString:0\n"));
  1709. return(0);
  1710. }
  1711. } else {
  1712. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1713. TRACEAPIOUT((szT, "DdeQueryString:0\n"));
  1714. return(0);
  1715. }
  1716. }
  1717. int EXPENTRY DdeCmpStringHandles(
  1718. HSZ hsz1,
  1719. HSZ hsz2)
  1720. {
  1721. int iRet;
  1722. TRACEAPIIN((szT, "DdeCmpStringHandles(%lx, %lx)\n",
  1723. hsz1, hsz2));
  1724. if (hsz2 > hsz1) {
  1725. iRet = -1;
  1726. } else if (hsz2 < hsz1) {
  1727. iRet = 1;
  1728. } else {
  1729. iRet = 0;
  1730. }
  1731. TRACEAPIOUT((szT, "DdeCmpStringHandles:%x\n", iRet));
  1732. return(iRet);
  1733. }
  1734. BOOL EXPENTRY DdeAbandonTransaction(
  1735. DWORD idInst,
  1736. HCONV hConv,
  1737. DWORD idTransaction)
  1738. {
  1739. PAPPINFO pai;
  1740. TRACEAPIIN((szT, "DdeAbandonTransaction(%lx, %lx, %lx)\n",
  1741. idInst, hConv, idTransaction));
  1742. pai = (PAPPINFO)idInst;
  1743. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  1744. TRACEAPIOUT((szT, "DdeAbandonTransaction:0\n"));
  1745. return(FALSE);
  1746. }
  1747. pai->LastError = DMLERR_NO_ERROR;
  1748. if ((hConv && !ValidateHConv(hConv)) || idTransaction == QID_SYNC) {
  1749. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1750. TRACEAPIOUT((szT, "DdeAbandonTransaction:0\n"));
  1751. return(FALSE);
  1752. }
  1753. if (hConv == NULL) {
  1754. // do all conversations!
  1755. register HWND hwnd;
  1756. register HWND hwndLast;
  1757. if (!(hwnd = GetWindow(pai->hwndDmg, GW_CHILD))) {
  1758. TRACEAPIOUT((szT, "DdeAbandonTransaction:1\n"));
  1759. return(TRUE);
  1760. }
  1761. hwndLast = GetWindow(hwnd, GW_HWNDLAST);
  1762. do {
  1763. AbandonTransaction(hwnd, pai, idTransaction, TRUE);
  1764. if (hwnd == hwndLast) {
  1765. break;
  1766. }
  1767. hwnd = GetWindow(hwnd, GW_HWNDNEXT);
  1768. } while (TRUE);
  1769. } else {
  1770. BOOL fRet;
  1771. fRet = AbandonTransaction((HWND)hConv, pai, idTransaction, TRUE);
  1772. TRACEAPIOUT((szT, "DdeAbandonTransaction:%x\n", fRet));
  1773. return(fRet);
  1774. }
  1775. TRACEAPIOUT((szT, "DdeAbandonTransaction:1\n"));
  1776. return(TRUE);
  1777. }
  1778. BOOL AbandonTransaction(
  1779. HWND hwnd,
  1780. PAPPINFO pai,
  1781. DWORD id,
  1782. BOOL fMarkOnly)
  1783. {
  1784. PCLIENTINFO pci;
  1785. PCQDATA pcqd;
  1786. WORD err;
  1787. SEMCHECKOUT();
  1788. SEMENTER();
  1789. pci = (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI);
  1790. if (!pci->ci.fs & ST_CLIENT) {
  1791. err = DMLERR_INVALIDPARAMETER;
  1792. failExit:
  1793. SETLASTERROR(pai, err);
  1794. SEMLEAVE();
  1795. SEMCHECKOUT();
  1796. return(FALSE);
  1797. }
  1798. do {
  1799. /*
  1800. * HACK: id == 0 -> all ids so we cycle
  1801. */
  1802. pcqd = (PCQDATA)Findqi(pci->pQ, id);
  1803. if (!pcqd) {
  1804. if (id) {
  1805. err = DMLERR_UNFOUND_QUEUE_ID;
  1806. goto failExit;
  1807. }
  1808. break;
  1809. }
  1810. if (fMarkOnly) {
  1811. pcqd->xad.fAbandoned = TRUE;
  1812. if (!id) {
  1813. while (pcqd = (PCQDATA)FindNextQi(pci->pQ, (PQUEUEITEM)pcqd,
  1814. FALSE)) {
  1815. pcqd->xad.fAbandoned = TRUE;
  1816. }
  1817. break;
  1818. }
  1819. } else {
  1820. if (pcqd->xad.pdata && pcqd->xad.pdata != 1 &&
  1821. !FindPileItem(pai->pHDataPile, CmpHIWORD,
  1822. (LPBYTE)&pcqd->xad.pdata, 0)) {
  1823. FreeDDEData(LOWORD(pcqd->xad.pdata), pcqd->xad.pXferInfo->wFmt);
  1824. }
  1825. /*
  1826. * Decrement the use count we incremented when the client started
  1827. * this transaction.
  1828. */
  1829. FreeHsz(LOWORD(pcqd->XferInfo.hszItem));
  1830. Deleteqi(pci->pQ, MAKEID(pcqd));
  1831. }
  1832. } while (!id);
  1833. SEMLEAVE();
  1834. SEMCHECKOUT();
  1835. return(TRUE);
  1836. }
  1837. BOOL EXPENTRY DdeEnableCallback(
  1838. DWORD idInst,
  1839. HCONV hConv,
  1840. UINT wCmd)
  1841. {
  1842. PAPPINFO pai;
  1843. BOOL fRet;
  1844. TRACEAPIIN((szT, "DdeEnableCallback(%lx, %lx, %x)\n",
  1845. idInst, hConv, wCmd));
  1846. pai = (PAPPINFO)idInst;
  1847. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  1848. TRACEAPIOUT((szT, "DdeEnableCallback:0\n"));
  1849. return(FALSE);
  1850. }
  1851. pai->LastError = DMLERR_NO_ERROR;
  1852. if ((hConv && !ValidateHConv(hConv)) ||
  1853. (wCmd & ~(EC_ENABLEONE | EC_ENABLEALL |
  1854. EC_DISABLE | EC_QUERYWAITING))) {
  1855. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1856. TRACEAPIOUT((szT, "DdeEnableCallback:0\n"));
  1857. return(FALSE);
  1858. }
  1859. SEMCHECKOUT();
  1860. if (wCmd & EC_QUERYWAITING) {
  1861. PCBLI pli;
  1862. int cWaiting = 0;
  1863. SEMENTER();
  1864. for (pli = (PCBLI)pai->plstCB->pItemFirst;
  1865. pli && cWaiting < 2;
  1866. pli = (PCBLI)pli->next) {
  1867. if (hConv || pli->hConv == hConv) {
  1868. cWaiting++;
  1869. }
  1870. }
  1871. SEMLEAVE();
  1872. fRet = cWaiting > 1 || (cWaiting == 1 && pai->cInProcess == 0);
  1873. TRACEAPIOUT((szT, "DdeEnableCallback:%x\n", fRet));
  1874. return(fRet);
  1875. }
  1876. /*
  1877. * We depend on the fact that EC_ constants relate to ST_ constants.
  1878. */
  1879. if (hConv == NULL) {
  1880. if (wCmd & EC_DISABLE) {
  1881. pai->wFlags |= AWF_DEFCREATESTATE;
  1882. } else {
  1883. pai->wFlags &= ~AWF_DEFCREATESTATE;
  1884. }
  1885. ChildMsg(pai->hwndDmg, UM_SETBLOCK, wCmd, 0, FALSE);
  1886. } else {
  1887. SendMessage((HWND)hConv, UM_SETBLOCK, wCmd, 0);
  1888. }
  1889. if (!(wCmd & EC_DISABLE)) {
  1890. // This is synchronous! Fail if we made this from within a callback.
  1891. if (pai->cInProcess) {
  1892. SETLASTERROR(pai, DMLERR_REENTRANCY);
  1893. TRACEAPIOUT((szT, "DdeEnableCallback:0\n"));
  1894. return(FALSE);
  1895. }
  1896. SendMessage(pai->hwndDmg, UM_CHECKCBQ, 0, (DWORD)(LPSTR)pai);
  1897. }
  1898. TRACEAPIOUT((szT, "DdeEnableCallback:1\n"));
  1899. return(TRUE); // TRUE implies the callback queue is free of unblocked calls.
  1900. }
  1901. HDDEDATA EXPENTRY DdeNameService(
  1902. DWORD idInst,
  1903. HSZ hsz1,
  1904. HSZ hsz2,
  1905. UINT afCmd)
  1906. {
  1907. PAPPINFO pai;
  1908. PPILE panp;
  1909. TRACEAPIIN((szT, "DdeNameService(%lx, %lx, %lx, %x)\n",
  1910. idInst, hsz1, hsz2, afCmd));
  1911. pai = (PAPPINFO)idInst;
  1912. if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
  1913. TRACEAPIOUT((szT, "DdeNameService:0\n"));
  1914. return(FALSE);
  1915. }
  1916. pai->LastError = DMLERR_NO_ERROR;
  1917. if (afCmd & DNS_FILTERON) {
  1918. pai->afCmd |= APPCMD_FILTERINITS;
  1919. }
  1920. if (afCmd & DNS_FILTEROFF) {
  1921. pai->afCmd &= ~APPCMD_FILTERINITS;
  1922. }
  1923. if (afCmd & (DNS_REGISTER | DNS_UNREGISTER)) {
  1924. if (pai->afCmd & APPCMD_CLIENTONLY) {
  1925. SETLASTERROR(pai, DMLERR_DLL_USAGE);
  1926. TRACEAPIOUT((szT, "DdeNameService:0\n"));
  1927. return(FALSE);
  1928. }
  1929. panp = pai->pAppNamePile;
  1930. if (hsz1 == NULL) {
  1931. if (afCmd & DNS_REGISTER) {
  1932. /*
  1933. * registering NULL is not allowed!
  1934. */
  1935. SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
  1936. TRACEAPIOUT((szT, "DdeNameService:0\n"));
  1937. return(FALSE);
  1938. }
  1939. /*
  1940. * unregistering NULL is just like unregistering each
  1941. * registered name.
  1942. *
  1943. * 10/19/90 - made this a synchronous event so that hsz
  1944. * can be freed by calling app after this call completes
  1945. * without us having to keep a copy around forever.
  1946. */
  1947. while (PopPileSubitem(panp, (LPBYTE)&hsz1)) {
  1948. RegisterService(FALSE, (GATOM)hsz1, pai->hwndFrame);
  1949. FreeHsz(LOWORD(hsz1));
  1950. }
  1951. TRACEAPIOUT((szT, "DdeNameService:1\n"));
  1952. return(TRUE);
  1953. }
  1954. if (afCmd & DNS_REGISTER) {
  1955. if (panp == NULL) {
  1956. panp = pai->pAppNamePile =
  1957. CreatePile(pai->hheapApp, sizeof(HSZ), 8);
  1958. }
  1959. IncHszCount(LOWORD(hsz1));
  1960. AddPileItem(panp, (LPBYTE)&hsz1, NULL);
  1961. } else { // DNS_UNREGISTER
  1962. FindPileItem(panp, CmpDWORD, (LPBYTE)&hsz1, FPI_DELETE);
  1963. }
  1964. // see 10/19/90 note above.
  1965. RegisterService(afCmd & DNS_REGISTER ? TRUE : FALSE, (GATOM)hsz1,
  1966. pai->hwndFrame);
  1967. if (afCmd & DNS_UNREGISTER) {
  1968. FreeHsz(LOWORD(hsz1));
  1969. }
  1970. TRACEAPIOUT((szT, "DdeNameService:1\n"));
  1971. return(TRUE);
  1972. }
  1973. TRACEAPIOUT((szT, "DdeNameService:0\n"));
  1974. return(0L);
  1975. }