Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

644 lines
16 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: DMGMEM.C
  3. *
  4. * DDE Manager memory management functions.
  5. *
  6. * Created: 5/31/90 Rich Gartland
  7. *
  8. * This module contains routines which mimic memory management functions
  9. * used by the OS/2 version of the DDEMGR library. Some are emulations
  10. * of OS/2 calls, and others emulate DDEMGR macros built on OS/2 calls.
  11. * Old function new function
  12. * --------------------------------------
  13. * WinCreateHeap DmgCreateHeap
  14. * WinDestroyHeap DmgDestroyHeap
  15. * FarAllocMem FarAllocMem
  16. * FarFreeMem FarFreeMem
  17. *
  18. * Copyright (c) 1990, Aldus Corporation
  19. \***************************************************************************/
  20. #include "ddemlp.h"
  21. #include <memory.h>
  22. #ifdef DEBUG
  23. #define GML_FREE 1
  24. #define GML_ALLOC 2
  25. #define MAX_CLOGS 500
  26. #define STKTRACE_LEN 3
  27. typedef struct _GMLOG {
  28. HGLOBAL h;
  29. WORD flags; // GML_
  30. WORD msg;
  31. WORD cLocks;
  32. WORD stktrace[STKTRACE_LEN];
  33. WORD stktracePrev[STKTRACE_LEN];
  34. } GMLOG, far * LPGMLOG;
  35. GMLOG gmlog[MAX_CLOGS];
  36. WORD cGmLogs = 0;
  37. int TraceApiLevel = 0;
  38. VOID TraceApiIn(
  39. LPSTR psz)
  40. {
  41. char szT[10];
  42. wsprintf(szT, "%2d | ", TraceApiLevel);
  43. TraceApiLevel++;
  44. OutputDebugString(szT);
  45. OutputDebugString(psz);
  46. if (bDbgFlags & DBF_STOPONTRACE) {
  47. DebugBreak();
  48. }
  49. }
  50. VOID TraceApiOut(
  51. LPSTR psz)
  52. {
  53. char szT[10];
  54. TraceApiLevel--;
  55. wsprintf(szT, "%2d | ", TraceApiLevel);
  56. OutputDebugString(szT);
  57. OutputDebugString(psz);
  58. if (bDbgFlags & DBF_STOPONTRACE) {
  59. DebugBreak();
  60. }
  61. }
  62. VOID DumpGmObject(
  63. LPGMLOG pgmlog)
  64. {
  65. char szT[100];
  66. wsprintf(szT,
  67. "\n\rh=%4x flags=%4x msg=%4x stacks:\n\r%04x %04x %04x %04x %04x\n\r%04x %04x %04x %04x %04x",
  68. pgmlog->h,
  69. pgmlog->flags,
  70. pgmlog->msg,
  71. pgmlog->stktrace[0],
  72. pgmlog->stktrace[1],
  73. pgmlog->stktrace[2],
  74. pgmlog->stktrace[3],
  75. pgmlog->stktrace[4],
  76. pgmlog->stktracePrev[0],
  77. pgmlog->stktracePrev[1],
  78. pgmlog->stktracePrev[2],
  79. pgmlog->stktracePrev[3],
  80. pgmlog->stktracePrev[4]
  81. );
  82. OutputDebugString(szT);
  83. }
  84. HGLOBAL LogGlobalReAlloc(
  85. HGLOBAL h,
  86. DWORD cb,
  87. UINT flags)
  88. {
  89. HGLOBAL hRet;
  90. WORD i;
  91. hRet = GlobalReAlloc(h, cb, flags);
  92. if (bDbgFlags & DBF_LOGALLOCS && h != hRet) {
  93. if (hRet != NULL) {
  94. for (i = 0; i < cGmLogs; i++) {
  95. if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
  96. gmlog[i].flags = GML_FREE;
  97. hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
  98. sizeof(WORD) * STKTRACE_LEN);
  99. StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
  100. }
  101. if ((gmlog[i].h & 0xFFFE) == (hRet & 0xFFFE)) {
  102. gmlog[i].flags = GML_ALLOC;
  103. hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
  104. sizeof(WORD) * STKTRACE_LEN);
  105. StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
  106. return(hRet);
  107. }
  108. }
  109. if (cGmLogs >= MAX_CLOGS) {
  110. OutputDebugString("\n\rGlobal logging table overflow.");
  111. DumpGlobalLogs();
  112. DebugBreak();
  113. return(hRet);
  114. }
  115. gmlog[cGmLogs].flags = GML_ALLOC;
  116. gmlog[cGmLogs].msg = 0;
  117. gmlog[cGmLogs].h = hRet;
  118. gmlog[cGmLogs].cLocks = 0;
  119. hmemcpy(gmlog[cGmLogs].stktracePrev, gmlog[cGmLogs].stktrace,
  120. sizeof(WORD) * STKTRACE_LEN);
  121. StkTrace(STKTRACE_LEN, gmlog[cGmLogs].stktrace);
  122. cGmLogs++;
  123. }
  124. }
  125. return(hRet);
  126. }
  127. HGLOBAL LogGlobalAlloc(
  128. UINT flags,
  129. DWORD cb)
  130. {
  131. HGLOBAL hRet;
  132. WORD i;
  133. hRet = GlobalAlloc(flags, cb);
  134. if (bDbgFlags & DBF_LOGALLOCS) {
  135. if (hRet != NULL) {
  136. for (i = 0; i < cGmLogs; i++) {
  137. if ((gmlog[i].h & 0xFFFE) == (hRet & 0xFFFE)) {
  138. gmlog[i].flags = GML_ALLOC;
  139. hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
  140. sizeof(WORD) * STKTRACE_LEN);
  141. StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
  142. return(hRet);
  143. }
  144. }
  145. if (cGmLogs >= MAX_CLOGS) {
  146. OutputDebugString("\n\rGlobal logging table overflow.");
  147. DumpGlobalLogs();
  148. DebugBreak();
  149. return(hRet);
  150. }
  151. gmlog[cGmLogs].flags = GML_ALLOC;
  152. gmlog[cGmLogs].msg = 0;
  153. gmlog[cGmLogs].h = hRet;
  154. gmlog[cGmLogs].cLocks = 0;
  155. hmemcpy(gmlog[cGmLogs].stktracePrev, gmlog[cGmLogs].stktrace,
  156. sizeof(WORD) * STKTRACE_LEN);
  157. StkTrace(STKTRACE_LEN, gmlog[cGmLogs].stktrace);
  158. cGmLogs++;
  159. }
  160. }
  161. return(hRet);
  162. }
  163. void FAR * LogGlobalLock(
  164. HGLOBAL h)
  165. {
  166. WORD i;
  167. if (bDbgFlags & DBF_LOGALLOCS) {
  168. for (i = 0; i < cGmLogs; i++) {
  169. if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
  170. break;
  171. }
  172. }
  173. if (i < cGmLogs) {
  174. gmlog[i].cLocks++;
  175. if (gmlog[i].flags == GML_FREE) {
  176. DumpGmObject(&gmlog[i]);
  177. OutputDebugString("\n\rGlobalLock will fail.");
  178. DebugBreak();
  179. }
  180. }
  181. }
  182. return(GlobalLock(h));
  183. }
  184. BOOL LogGlobalUnlock(
  185. HGLOBAL h)
  186. {
  187. WORD i;
  188. if (bDbgFlags & DBF_LOGALLOCS) {
  189. for (i = 0; i < cGmLogs; i++) {
  190. if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
  191. break;
  192. }
  193. }
  194. if (i < cGmLogs) {
  195. if (gmlog[i].cLocks == 0 || gmlog[i].flags == GML_FREE) {
  196. DumpGmObject(&gmlog[i]);
  197. OutputDebugString("\n\rGlobalUnlock will fail.");
  198. DebugBreak();
  199. }
  200. gmlog[i].cLocks--;
  201. }
  202. }
  203. return(GlobalUnlock(h));
  204. }
  205. HGLOBAL LogGlobalFree(
  206. HGLOBAL h)
  207. {
  208. WORD i;
  209. if (bDbgFlags & DBF_LOGALLOCS) {
  210. for (i = 0; i < cGmLogs; i++) {
  211. if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
  212. if (gmlog[i].flags == GML_FREE) {
  213. DumpGmObject(&gmlog[i]);
  214. OutputDebugString("\n\rFreeing free object.\n\r");
  215. DebugBreak();
  216. }
  217. gmlog[i].flags = GML_FREE;
  218. hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
  219. sizeof(WORD) * STKTRACE_LEN);
  220. StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
  221. return(GlobalFree(h));
  222. }
  223. }
  224. OutputDebugString("\n\rGlobal object being freed not found in logs.");
  225. DebugBreak();
  226. }
  227. return(GlobalFree(h));
  228. }
  229. VOID LogDdeObject(
  230. UINT msg,
  231. LONG lParam)
  232. {
  233. HGLOBAL h;
  234. WORD i;
  235. char szT[100];
  236. if (bDbgFlags & DBF_LOGALLOCS) {
  237. switch (msg & 0x0FFF) {
  238. case WM_DDE_DATA:
  239. case WM_DDE_POKE:
  240. case WM_DDE_ADVISE:
  241. case 0:
  242. h = LOWORD(lParam);
  243. break;
  244. case WM_DDE_EXECUTE:
  245. h = HIWORD(lParam);
  246. break;
  247. default:
  248. return;
  249. }
  250. if (h == 0) {
  251. return;
  252. }
  253. for (i = 0; i < cGmLogs; i++) {
  254. if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
  255. if (gmlog[i].flags == GML_FREE) {
  256. DumpGmObject(&gmlog[i]);
  257. wsprintf(szT, "\n\rLogging free DDE Object! [%4x]\n\r", msg);
  258. OutputDebugString(szT);
  259. DebugBreak();
  260. }
  261. if (msg & 0xFFF) {
  262. gmlog[i].msg = msg;
  263. } else {
  264. gmlog[i].msg = (gmlog[i].msg & 0x0FFF) | msg;
  265. }
  266. break;
  267. }
  268. }
  269. }
  270. }
  271. VOID DumpGlobalLogs()
  272. {
  273. WORD i;
  274. char szT[100];
  275. if (bDbgFlags & DBF_LOGALLOCS) {
  276. wsprintf(szT, "\n\rDumpGlobalLogs - cGmLogs = %d", cGmLogs);
  277. OutputDebugString(szT);
  278. for (i = 0; i < cGmLogs; i++) {
  279. if (gmlog[i].flags == GML_ALLOC) {
  280. DumpGmObject(&gmlog[i]);
  281. }
  282. }
  283. wsprintf(szT, "\n\rDDEML CS=%04x\n\r", HIWORD((LPVOID)DumpGlobalLogs));
  284. OutputDebugString(szT);
  285. }
  286. }
  287. #endif // DEBUG
  288. /***************************** Private Function ****************************\
  289. *
  290. * Creates a new heap and returns a handle to it.
  291. * Returns NULL on error.
  292. *
  293. *
  294. * History:
  295. * Created 5/31/90 Rich Gartland
  296. \***************************************************************************/
  297. HANDLE DmgCreateHeap(wSize)
  298. WORD wSize;
  299. {
  300. HANDLE hMem;
  301. DWORD dwSize;
  302. dwSize = wSize;
  303. /* Allocate the memory from a global data segment */
  304. if (!(hMem = GLOBALALLOC(GMEM_MOVEABLE, dwSize)))
  305. return(NULL);
  306. /* use LocalInit to establish heap mgmt structures in the seg */
  307. if (!LocalInit(hMem, NULL, wSize - 1)) {
  308. GLOBALFREE(hMem);
  309. return(NULL);
  310. }
  311. return(hMem);
  312. }
  313. /***************************** Private Function ****************************\
  314. *
  315. * Destroys a heap previously created with DmgCreateHeap.
  316. * Returns nonzero on error.
  317. *
  318. *
  319. * History:
  320. * Created 5/31/90 Rich Gartland
  321. \***************************************************************************/
  322. HANDLE DmgDestroyHeap(hheap)
  323. HANDLE hheap;
  324. {
  325. /* now free the block and return the result (NULL if success) */
  326. return(GLOBALFREE(hheap));
  327. }
  328. /*
  329. * Attempts to recover from memory allocation errors.
  330. *
  331. * Returns fRetry - ok to attempt reallocation.
  332. */
  333. BOOL ProcessMemError(
  334. HANDLE hheap)
  335. {
  336. PAPPINFO pai;
  337. // first locate what instance this heap is assocaited with
  338. SEMENTER();
  339. pai = pAppInfoList;
  340. while (pai && pai->hheapApp != hheap) {
  341. pai = pai->next;
  342. }
  343. if (!pai) {
  344. SEMLEAVE();
  345. return(FALSE); // not associated with an instance, no recourse.
  346. }
  347. /*
  348. * Free our emergency reserve memory and post a message to our master
  349. * window to handle heap cleanup.
  350. */
  351. if (pai->lpMemReserve) {
  352. FarFreeMem(pai->lpMemReserve);
  353. pai->lpMemReserve = NULL;
  354. MONERROR(pai, DMLERR_LOW_MEMORY);
  355. DoCallback(pai, NULL, 0, 0, 0, XTYP_ERROR, NULL, DMLERR_LOW_MEMORY, 0L);
  356. SEMLEAVE();
  357. if (!PostMessage(pai->hwndDmg, UM_FIXHEAP, 0, (LONG)(LPSTR)pai)) {
  358. SETLASTERROR(pai, DMLERR_SYS_ERROR);
  359. return(FALSE);
  360. }
  361. return(TRUE);
  362. }
  363. return(FALSE); // no reserve memory, were dead bud.
  364. }
  365. /***************************** Private Function ****************************\
  366. *
  367. * Allocates a new block of a given size from a heap.
  368. * Returns NULL on error, far pointer to the block otherwise.
  369. *
  370. *
  371. * History:
  372. * Created 5/31/90 Rich Gartland
  373. \***************************************************************************/
  374. LPVOID FarAllocMem(hheap, wSize)
  375. HANDLE hheap;
  376. WORD wSize;
  377. {
  378. LPSTR lpMem;
  379. PSTR pMem;
  380. WORD wSaveDS;
  381. /* lock the handle to get a far pointer */
  382. lpMem = (LPSTR)GLOBALPTR(hheap);
  383. if (!lpMem)
  384. return(NULL);
  385. do {
  386. /* Do some magic here using the segment selector, to switch our
  387. * ds to the heap's segment. Then, our LocalAlloc will work fine.
  388. */
  389. wSaveDS = SwitchDS(HIWORD(lpMem));
  390. /* Allocate the block */
  391. // Note: if you remove the LMEM_FIXED flag you will break the handle
  392. // validation in DdeFreeDataHandle & get a big handle leak!!
  393. pMem = (PSTR)LocalAlloc((WORD)LPTR, wSize); // LPTR = fixed | zeroinit
  394. SwitchDS(wSaveDS);
  395. } while (pMem == NULL && ProcessMemError(hheap));
  396. #ifdef WATCHHEAPS
  397. if (pMem) {
  398. LogAlloc((DWORD)MAKELONG(pMem, HIWORD(lpMem)), wSize,
  399. RGB(0xff, 0, 0), hInstance);
  400. }
  401. #endif
  402. /* set up the far return value, based on the success of LocalAlloc */
  403. return (LPSTR)(pMem ? MAKELONG(pMem, HIWORD(lpMem)) : NULL);
  404. }
  405. /***************************** Private Function ****************************\
  406. *
  407. * Frees a block of a given size from a heap.
  408. * Returns NULL on success, far pointer to the block otherwise.
  409. *
  410. *
  411. * History:
  412. * Created 5/31/90 Rich Gartland
  413. \***************************************************************************/
  414. void FarFreeMem(
  415. LPVOID lpMem)
  416. {
  417. WORD wSaveDS;
  418. #ifdef WATCHHEAPS
  419. WORD sz;
  420. #endif
  421. /* Do some magic here using the segment selector, to switch our
  422. * ds to the heap's segment. Then, our LocalFree will work fine.
  423. */
  424. wSaveDS = SwitchDS(HIWORD(lpMem));
  425. #ifdef WATCHHEAPS
  426. sz = LocalSize((LOWORD((DWORD)lpMem)));
  427. #endif
  428. /* Free the block */
  429. LocalFree(LocalHandle(LOWORD((DWORD)lpMem)));
  430. SwitchDS(wSaveDS);
  431. #ifdef WATCHHEAPS
  432. LogAlloc((DWORD)lpMem, sz, RGB(0x80, 0x80, 0x80), hInstance);
  433. #endif
  434. }
  435. int FAR PASCAL WEP (int);
  436. int FAR PASCAL LibMain(HANDLE, WORD, WORD, LPCSTR);
  437. #pragma alloc_text(INIT_TEXT,LibMain,WEP)
  438. /***************************** Private Function ****************************\
  439. *
  440. * Does some initialization for the DLL. Called from LibEntry.asm
  441. * Returns 1 on success, 0 otherwise.
  442. *
  443. *
  444. * History:
  445. * Created 6/5/90 Rich Gartland
  446. \***************************************************************************/
  447. int FAR PASCAL LibMain (hI, wDS, cbHS, lpszCL)
  448. HANDLE hI; /* instance handle */
  449. WORD wDS; /* data segment */
  450. WORD cbHS; /* heapsize */
  451. LPCSTR lpszCL; /* command line */
  452. {
  453. extern ATOM gatomDDEMLMom;
  454. extern ATOM gatomDMGClass;
  455. #if 0
  456. /* We won't unlock the data segment, as typically happens here */
  457. /* Init the semaphore -- probably just a stub now */
  458. SEMINIT();
  459. #endif
  460. /* set up the global instance handle variable */
  461. hInstance = hI;
  462. /* set up class atoms. Note we use RegisterWindowMessage because
  463. * it comes from the same user atom table used for class atoms.
  464. */
  465. gatomDDEMLMom = RegisterWindowMessage("DDEMLMom");
  466. gatomDMGClass = RegisterWindowMessage("DMGClass");
  467. return(1);
  468. }
  469. VOID RegisterClasses()
  470. {
  471. WNDCLASS cls;
  472. cls.hIcon = NULL;
  473. cls.hCursor = NULL;
  474. cls.lpszMenuName = NULL;
  475. cls.hbrBackground = NULL;
  476. cls.style = 0; // CS_GLOBALCLASS
  477. cls.hInstance = hInstance;
  478. cls.cbClsExtra = 0;
  479. cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
  480. cls.lpszClassName = SZCLIENTCLASS;
  481. cls.lpfnWndProc = (WNDPROC)ClientWndProc;
  482. RegisterClass(&cls);
  483. // cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
  484. cls.lpszClassName = SZSERVERCLASS;
  485. cls.lpfnWndProc = (WNDPROC)ServerWndProc;
  486. RegisterClass(&cls);
  487. // cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
  488. cls.lpszClassName = SZDMGCLASS;
  489. cls.lpfnWndProc = (WNDPROC)DmgWndProc;
  490. RegisterClass(&cls);
  491. cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD) + sizeof(WORD);
  492. cls.lpszClassName = SZCONVLISTCLASS;
  493. cls.lpfnWndProc = (WNDPROC)ConvListWndProc;
  494. RegisterClass(&cls);
  495. cls.cbWndExtra = sizeof(VOID FAR *);
  496. cls.lpszClassName = SZMONITORCLASS;
  497. cls.lpfnWndProc = (WNDPROC)MonitorWndProc;
  498. RegisterClass(&cls);
  499. cls.cbWndExtra = sizeof(VOID FAR *);
  500. cls.lpszClassName = SZFRAMECLASS;
  501. cls.lpfnWndProc = (WNDPROC)subframeWndProc;
  502. RegisterClass(&cls);
  503. #ifdef WATCHHEAPS
  504. cls.cbWndExtra = 0;
  505. cls.lpszClassName = SZHEAPWATCHCLASS;
  506. cls.lpfnWndProc = DefWindowProc;
  507. cls.hCursor = LoadCursor(NULL, IDC_ARROW);
  508. cls.hbrBackground = GetStockObject(WHITE_BRUSH);
  509. RegisterClass(&cls);
  510. #endif // WATCHHEAPS
  511. }
  512. #if 0
  513. VOID UnregisterClasses()
  514. {
  515. UnregisterClass(SZCLIENTCLASS, hInstance);
  516. UnregisterClass(SZSERVERCLASS, hInstance);
  517. UnregisterClass(SZDMGCLASS, hInstance);
  518. UnregisterClass(SZCONVLISTCLASS, hInstance);
  519. UnregisterClass(SZMONITORCLASS, hInstance);
  520. UnregisterClass(SZFRAMECLASS, hInstance);
  521. #ifdef WATCHHEAPS
  522. UnregisterClass(SZHEAPWATCHCLASS, hInstance);
  523. #endif
  524. }
  525. #endif
  526. /***************************** Private Function ****************************\
  527. *
  528. * Does the termination for the DLL.
  529. * Returns 1 on success, 0 otherwise.
  530. *
  531. *
  532. * History:
  533. * Created 6/5/90 Rich Gartland
  534. \***************************************************************************/
  535. int FAR PASCAL WEP (nParameter)
  536. int nParameter;
  537. {
  538. if (nParameter == WEP_SYSTEM_EXIT) {
  539. /* DdeUninitialize(); */
  540. return(1);
  541. } else {
  542. if (nParameter == WEP_FREE_DLL) {
  543. /* DdeUninitialize(); */
  544. return(1);
  545. }
  546. }
  547. }