windows-nt/Source/XPSP1/NT/base/mvdm/wow16/ddeml/dmgmem.c
2020-09-26 16:20:57 +08:00

645 lines
16 KiB
C

/****************************** Module Header ******************************\
* Module Name: DMGMEM.C
*
* DDE Manager memory management functions.
*
* Created: 5/31/90 Rich Gartland
*
* This module contains routines which mimic memory management functions
* used by the OS/2 version of the DDEMGR library. Some are emulations
* of OS/2 calls, and others emulate DDEMGR macros built on OS/2 calls.
* Old function new function
* --------------------------------------
* WinCreateHeap DmgCreateHeap
* WinDestroyHeap DmgDestroyHeap
* FarAllocMem FarAllocMem
* FarFreeMem FarFreeMem
*
* Copyright (c) 1990, Aldus Corporation
\***************************************************************************/
#include "ddemlp.h"
#include <memory.h>
#ifdef DEBUG
#define GML_FREE 1
#define GML_ALLOC 2
#define MAX_CLOGS 500
#define STKTRACE_LEN 3
typedef struct _GMLOG {
HGLOBAL h;
WORD flags; // GML_
WORD msg;
WORD cLocks;
WORD stktrace[STKTRACE_LEN];
WORD stktracePrev[STKTRACE_LEN];
} GMLOG, far * LPGMLOG;
GMLOG gmlog[MAX_CLOGS];
WORD cGmLogs = 0;
int TraceApiLevel = 0;
VOID TraceApiIn(
LPSTR psz)
{
char szT[10];
wsprintf(szT, "%2d | ", TraceApiLevel);
TraceApiLevel++;
OutputDebugString(szT);
OutputDebugString(psz);
if (bDbgFlags & DBF_STOPONTRACE) {
DebugBreak();
}
}
VOID TraceApiOut(
LPSTR psz)
{
char szT[10];
TraceApiLevel--;
wsprintf(szT, "%2d | ", TraceApiLevel);
OutputDebugString(szT);
OutputDebugString(psz);
if (bDbgFlags & DBF_STOPONTRACE) {
DebugBreak();
}
}
VOID DumpGmObject(
LPGMLOG pgmlog)
{
char szT[100];
wsprintf(szT,
"\n\rh=%4x flags=%4x msg=%4x stacks:\n\r%04x %04x %04x %04x %04x\n\r%04x %04x %04x %04x %04x",
pgmlog->h,
pgmlog->flags,
pgmlog->msg,
pgmlog->stktrace[0],
pgmlog->stktrace[1],
pgmlog->stktrace[2],
pgmlog->stktrace[3],
pgmlog->stktrace[4],
pgmlog->stktracePrev[0],
pgmlog->stktracePrev[1],
pgmlog->stktracePrev[2],
pgmlog->stktracePrev[3],
pgmlog->stktracePrev[4]
);
OutputDebugString(szT);
}
HGLOBAL LogGlobalReAlloc(
HGLOBAL h,
DWORD cb,
UINT flags)
{
HGLOBAL hRet;
WORD i;
hRet = GlobalReAlloc(h, cb, flags);
if (bDbgFlags & DBF_LOGALLOCS && h != hRet) {
if (hRet != NULL) {
for (i = 0; i < cGmLogs; i++) {
if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
gmlog[i].flags = GML_FREE;
hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
sizeof(WORD) * STKTRACE_LEN);
StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
}
if ((gmlog[i].h & 0xFFFE) == (hRet & 0xFFFE)) {
gmlog[i].flags = GML_ALLOC;
hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
sizeof(WORD) * STKTRACE_LEN);
StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
return(hRet);
}
}
if (cGmLogs >= MAX_CLOGS) {
OutputDebugString("\n\rGlobal logging table overflow.");
DumpGlobalLogs();
DebugBreak();
return(hRet);
}
gmlog[cGmLogs].flags = GML_ALLOC;
gmlog[cGmLogs].msg = 0;
gmlog[cGmLogs].h = hRet;
gmlog[cGmLogs].cLocks = 0;
hmemcpy(gmlog[cGmLogs].stktracePrev, gmlog[cGmLogs].stktrace,
sizeof(WORD) * STKTRACE_LEN);
StkTrace(STKTRACE_LEN, gmlog[cGmLogs].stktrace);
cGmLogs++;
}
}
return(hRet);
}
HGLOBAL LogGlobalAlloc(
UINT flags,
DWORD cb)
{
HGLOBAL hRet;
WORD i;
hRet = GlobalAlloc(flags, cb);
if (bDbgFlags & DBF_LOGALLOCS) {
if (hRet != NULL) {
for (i = 0; i < cGmLogs; i++) {
if ((gmlog[i].h & 0xFFFE) == (hRet & 0xFFFE)) {
gmlog[i].flags = GML_ALLOC;
hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
sizeof(WORD) * STKTRACE_LEN);
StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
return(hRet);
}
}
if (cGmLogs >= MAX_CLOGS) {
OutputDebugString("\n\rGlobal logging table overflow.");
DumpGlobalLogs();
DebugBreak();
return(hRet);
}
gmlog[cGmLogs].flags = GML_ALLOC;
gmlog[cGmLogs].msg = 0;
gmlog[cGmLogs].h = hRet;
gmlog[cGmLogs].cLocks = 0;
hmemcpy(gmlog[cGmLogs].stktracePrev, gmlog[cGmLogs].stktrace,
sizeof(WORD) * STKTRACE_LEN);
StkTrace(STKTRACE_LEN, gmlog[cGmLogs].stktrace);
cGmLogs++;
}
}
return(hRet);
}
void FAR * LogGlobalLock(
HGLOBAL h)
{
WORD i;
if (bDbgFlags & DBF_LOGALLOCS) {
for (i = 0; i < cGmLogs; i++) {
if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
break;
}
}
if (i < cGmLogs) {
gmlog[i].cLocks++;
if (gmlog[i].flags == GML_FREE) {
DumpGmObject(&gmlog[i]);
OutputDebugString("\n\rGlobalLock will fail.");
DebugBreak();
}
}
}
return(GlobalLock(h));
}
BOOL LogGlobalUnlock(
HGLOBAL h)
{
WORD i;
if (bDbgFlags & DBF_LOGALLOCS) {
for (i = 0; i < cGmLogs; i++) {
if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
break;
}
}
if (i < cGmLogs) {
if (gmlog[i].cLocks == 0 || gmlog[i].flags == GML_FREE) {
DumpGmObject(&gmlog[i]);
OutputDebugString("\n\rGlobalUnlock will fail.");
DebugBreak();
}
gmlog[i].cLocks--;
}
}
return(GlobalUnlock(h));
}
HGLOBAL LogGlobalFree(
HGLOBAL h)
{
WORD i;
if (bDbgFlags & DBF_LOGALLOCS) {
for (i = 0; i < cGmLogs; i++) {
if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
if (gmlog[i].flags == GML_FREE) {
DumpGmObject(&gmlog[i]);
OutputDebugString("\n\rFreeing free object.\n\r");
DebugBreak();
}
gmlog[i].flags = GML_FREE;
hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
sizeof(WORD) * STKTRACE_LEN);
StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
return(GlobalFree(h));
}
}
OutputDebugString("\n\rGlobal object being freed not found in logs.");
DebugBreak();
}
return(GlobalFree(h));
}
VOID LogDdeObject(
UINT msg,
LONG lParam)
{
HGLOBAL h;
WORD i;
char szT[100];
if (bDbgFlags & DBF_LOGALLOCS) {
switch (msg & 0x0FFF) {
case WM_DDE_DATA:
case WM_DDE_POKE:
case WM_DDE_ADVISE:
case 0:
h = LOWORD(lParam);
break;
case WM_DDE_EXECUTE:
h = HIWORD(lParam);
break;
default:
return;
}
if (h == 0) {
return;
}
for (i = 0; i < cGmLogs; i++) {
if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
if (gmlog[i].flags == GML_FREE) {
DumpGmObject(&gmlog[i]);
wsprintf(szT, "\n\rLogging free DDE Object! [%4x]\n\r", msg);
OutputDebugString(szT);
DebugBreak();
}
if (msg & 0xFFF) {
gmlog[i].msg = msg;
} else {
gmlog[i].msg = (gmlog[i].msg & 0x0FFF) | msg;
}
break;
}
}
}
}
VOID DumpGlobalLogs()
{
WORD i;
char szT[100];
if (bDbgFlags & DBF_LOGALLOCS) {
wsprintf(szT, "\n\rDumpGlobalLogs - cGmLogs = %d", cGmLogs);
OutputDebugString(szT);
for (i = 0; i < cGmLogs; i++) {
if (gmlog[i].flags == GML_ALLOC) {
DumpGmObject(&gmlog[i]);
}
}
wsprintf(szT, "\n\rDDEML CS=%04x\n\r", HIWORD((LPVOID)DumpGlobalLogs));
OutputDebugString(szT);
}
}
#endif // DEBUG
/***************************** Private Function ****************************\
*
* Creates a new heap and returns a handle to it.
* Returns NULL on error.
*
*
* History:
* Created 5/31/90 Rich Gartland
\***************************************************************************/
HANDLE DmgCreateHeap(wSize)
WORD wSize;
{
HANDLE hMem;
DWORD dwSize;
dwSize = wSize;
/* Allocate the memory from a global data segment */
if (!(hMem = GLOBALALLOC(GMEM_MOVEABLE, dwSize)))
return(NULL);
/* use LocalInit to establish heap mgmt structures in the seg */
if (!LocalInit(hMem, NULL, wSize - 1)) {
GLOBALFREE(hMem);
return(NULL);
}
return(hMem);
}
/***************************** Private Function ****************************\
*
* Destroys a heap previously created with DmgCreateHeap.
* Returns nonzero on error.
*
*
* History:
* Created 5/31/90 Rich Gartland
\***************************************************************************/
HANDLE DmgDestroyHeap(hheap)
HANDLE hheap;
{
/* now free the block and return the result (NULL if success) */
return(GLOBALFREE(hheap));
}
/*
* Attempts to recover from memory allocation errors.
*
* Returns fRetry - ok to attempt reallocation.
*/
BOOL ProcessMemError(
HANDLE hheap)
{
PAPPINFO pai;
// first locate what instance this heap is assocaited with
SEMENTER();
pai = pAppInfoList;
while (pai && pai->hheapApp != hheap) {
pai = pai->next;
}
if (!pai) {
SEMLEAVE();
return(FALSE); // not associated with an instance, no recourse.
}
/*
* Free our emergency reserve memory and post a message to our master
* window to handle heap cleanup.
*/
if (pai->lpMemReserve) {
FarFreeMem(pai->lpMemReserve);
pai->lpMemReserve = NULL;
MONERROR(pai, DMLERR_LOW_MEMORY);
DoCallback(pai, NULL, 0, 0, 0, XTYP_ERROR, NULL, DMLERR_LOW_MEMORY, 0L);
SEMLEAVE();
if (!PostMessage(pai->hwndDmg, UM_FIXHEAP, 0, (LONG)(LPSTR)pai)) {
SETLASTERROR(pai, DMLERR_SYS_ERROR);
return(FALSE);
}
return(TRUE);
}
return(FALSE); // no reserve memory, were dead bud.
}
/***************************** Private Function ****************************\
*
* Allocates a new block of a given size from a heap.
* Returns NULL on error, far pointer to the block otherwise.
*
*
* History:
* Created 5/31/90 Rich Gartland
\***************************************************************************/
LPVOID FarAllocMem(hheap, wSize)
HANDLE hheap;
WORD wSize;
{
LPSTR lpMem;
PSTR pMem;
WORD wSaveDS;
/* lock the handle to get a far pointer */
lpMem = (LPSTR)GLOBALPTR(hheap);
if (!lpMem)
return(NULL);
do {
/* Do some magic here using the segment selector, to switch our
* ds to the heap's segment. Then, our LocalAlloc will work fine.
*/
wSaveDS = SwitchDS(HIWORD(lpMem));
/* Allocate the block */
// Note: if you remove the LMEM_FIXED flag you will break the handle
// validation in DdeFreeDataHandle & get a big handle leak!!
pMem = (PSTR)LocalAlloc((WORD)LPTR, wSize); // LPTR = fixed | zeroinit
SwitchDS(wSaveDS);
} while (pMem == NULL && ProcessMemError(hheap));
#ifdef WATCHHEAPS
if (pMem) {
LogAlloc((DWORD)MAKELONG(pMem, HIWORD(lpMem)), wSize,
RGB(0xff, 0, 0), hInstance);
}
#endif
/* set up the far return value, based on the success of LocalAlloc */
return (LPSTR)(pMem ? MAKELONG(pMem, HIWORD(lpMem)) : NULL);
}
/***************************** Private Function ****************************\
*
* Frees a block of a given size from a heap.
* Returns NULL on success, far pointer to the block otherwise.
*
*
* History:
* Created 5/31/90 Rich Gartland
\***************************************************************************/
void FarFreeMem(
LPVOID lpMem)
{
WORD wSaveDS;
#ifdef WATCHHEAPS
WORD sz;
#endif
/* Do some magic here using the segment selector, to switch our
* ds to the heap's segment. Then, our LocalFree will work fine.
*/
wSaveDS = SwitchDS(HIWORD(lpMem));
#ifdef WATCHHEAPS
sz = LocalSize((LOWORD((DWORD)lpMem)));
#endif
/* Free the block */
LocalFree(LocalHandle(LOWORD((DWORD)lpMem)));
SwitchDS(wSaveDS);
#ifdef WATCHHEAPS
LogAlloc((DWORD)lpMem, sz, RGB(0x80, 0x80, 0x80), hInstance);
#endif
}
int FAR PASCAL WEP (int);
int FAR PASCAL LibMain(HANDLE, WORD, WORD, LPCSTR);
#pragma alloc_text(INIT_TEXT,LibMain,WEP)
/***************************** Private Function ****************************\
*
* Does some initialization for the DLL. Called from LibEntry.asm
* Returns 1 on success, 0 otherwise.
*
*
* History:
* Created 6/5/90 Rich Gartland
\***************************************************************************/
int FAR PASCAL LibMain (hI, wDS, cbHS, lpszCL)
HANDLE hI; /* instance handle */
WORD wDS; /* data segment */
WORD cbHS; /* heapsize */
LPCSTR lpszCL; /* command line */
{
extern ATOM gatomDDEMLMom;
extern ATOM gatomDMGClass;
#if 0
/* We won't unlock the data segment, as typically happens here */
/* Init the semaphore -- probably just a stub now */
SEMINIT();
#endif
/* set up the global instance handle variable */
hInstance = hI;
/* set up class atoms. Note we use RegisterWindowMessage because
* it comes from the same user atom table used for class atoms.
*/
gatomDDEMLMom = RegisterWindowMessage("DDEMLMom");
gatomDMGClass = RegisterWindowMessage("DMGClass");
return(1);
}
VOID RegisterClasses()
{
WNDCLASS cls;
cls.hIcon = NULL;
cls.hCursor = NULL;
cls.lpszMenuName = NULL;
cls.hbrBackground = NULL;
cls.style = 0; // CS_GLOBALCLASS
cls.hInstance = hInstance;
cls.cbClsExtra = 0;
cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
cls.lpszClassName = SZCLIENTCLASS;
cls.lpfnWndProc = (WNDPROC)ClientWndProc;
RegisterClass(&cls);
// cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
cls.lpszClassName = SZSERVERCLASS;
cls.lpfnWndProc = (WNDPROC)ServerWndProc;
RegisterClass(&cls);
// cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
cls.lpszClassName = SZDMGCLASS;
cls.lpfnWndProc = (WNDPROC)DmgWndProc;
RegisterClass(&cls);
cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD) + sizeof(WORD);
cls.lpszClassName = SZCONVLISTCLASS;
cls.lpfnWndProc = (WNDPROC)ConvListWndProc;
RegisterClass(&cls);
cls.cbWndExtra = sizeof(VOID FAR *);
cls.lpszClassName = SZMONITORCLASS;
cls.lpfnWndProc = (WNDPROC)MonitorWndProc;
RegisterClass(&cls);
cls.cbWndExtra = sizeof(VOID FAR *);
cls.lpszClassName = SZFRAMECLASS;
cls.lpfnWndProc = (WNDPROC)subframeWndProc;
RegisterClass(&cls);
#ifdef WATCHHEAPS
cls.cbWndExtra = 0;
cls.lpszClassName = SZHEAPWATCHCLASS;
cls.lpfnWndProc = DefWindowProc;
cls.hCursor = LoadCursor(NULL, IDC_ARROW);
cls.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&cls);
#endif // WATCHHEAPS
}
#if 0
VOID UnregisterClasses()
{
UnregisterClass(SZCLIENTCLASS, hInstance);
UnregisterClass(SZSERVERCLASS, hInstance);
UnregisterClass(SZDMGCLASS, hInstance);
UnregisterClass(SZCONVLISTCLASS, hInstance);
UnregisterClass(SZMONITORCLASS, hInstance);
UnregisterClass(SZFRAMECLASS, hInstance);
#ifdef WATCHHEAPS
UnregisterClass(SZHEAPWATCHCLASS, hInstance);
#endif
}
#endif
/***************************** Private Function ****************************\
*
* Does the termination for the DLL.
* Returns 1 on success, 0 otherwise.
*
*
* History:
* Created 6/5/90 Rich Gartland
\***************************************************************************/
int FAR PASCAL WEP (nParameter)
int nParameter;
{
if (nParameter == WEP_SYSTEM_EXIT) {
/* DdeUninitialize(); */
return(1);
} else {
if (nParameter == WEP_FREE_DLL) {
/* DdeUninitialize(); */
return(1);
}
}
}