|
|
/****************************** Module Header ******************************\
* Module Name: ddetrack.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * client sied DDE tracking routines * * 10-22-91 sanfords created \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#if defined(BUILD_WOW6432)
#define DDEDATA_WITH_HANDLE_SIZE (sizeof (DDEDATA_WOW6432))
#else
#define DDEDATA_WITH_HANDLE_SIZE (sizeof (DDE_DATA))
#endif
DWORD _ClientCopyDDEIn1( HANDLE hClient, // client handle to dde data or ddepack data
PINTDDEINFO pi) // info for transfer
{ PBYTE pData; DWORD flags;
//
// zero out everything but the flags
//
flags = pi->flags; RtlZeroMemory(pi, sizeof(INTDDEINFO)); pi->flags = flags; USERGLOBALLOCK(hClient, pData);
if (pData == NULL) { // bad hClient
RIPMSG0(RIP_WARNING, "_ClientCopyDDEIn1:GlobalLock failed."); return (FAIL_POST); }
if (flags & XS_PACKED) {
if (UserGlobalSize(hClient) < sizeof(DDEPACK)) { /*
* must be a low memory condition. fail. */ return(FAIL_POST); }
pi->DdePack = *(PDDEPACK)pData; USERGLOBALUNLOCK(hClient); UserGlobalFree(hClient); // packed data handles are not WOW matched.
hClient = NULL;
if (!(flags & (XS_LOHANDLE | XS_HIHANDLE))) { if (flags & XS_EXECUTE && flags & XS_FREESRC) { /*
* free execute ACK data */ WOWGLOBALFREE((HANDLE)pi->DdePack.uiHi); } return (DO_POST); // no direct data
}
if (flags & XS_LOHANDLE) { pi->hDirect = (HANDLE)pi->DdePack.uiLo; } else { pi->hDirect = (HANDLE)pi->DdePack.uiHi; }
if (pi->hDirect == 0) { return (DO_POST); // must be warm link
}
USERGLOBALLOCK(pi->hDirect, pi->pDirect); if (pi->pDirect == NULL) { RIPMSG1(RIP_ERROR, "_ClientCopyDDEIn1:GlobalLock failed for hDirect %p.",pi->hDirect); return FAILNOFREE_POST; } pData = pi->pDirect; pi->cbDirect = (UINT)UserGlobalSize(pi->hDirect);
} else { // not packed - must be execute data or we wouldn't be called
UserAssert(flags & XS_EXECUTE);
pi->cbDirect = (UINT)UserGlobalSize(hClient); pi->hDirect = hClient; pi->pDirect = pData; hClient = NULL; }
if (flags & XS_DATA) { PDDE_DATA pDdeData = (PDDE_DATA)pData;
/*
* Assert that the hClient has been freed. If not this code will return * the wrong thing on failure */ UserAssert(flags & XS_PACKED);
//
// check here for indirect data
//
switch (pDdeData->wFmt) { case CF_BITMAP: case CF_DSPBITMAP: //
// Imediately following the dde data header is a bitmap handle.
//
UserAssert(pi->cbDirect >= DDEDATA_WITH_HANDLE_SIZE); pi->hIndirect = (HANDLE)pDdeData->Data; if (pi->hIndirect == 0) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEIn1:GdiConvertBitmap failed"); return(FAILNOFREE_POST); } // pi->cbIndirect = 0; // zero init.
// pi->pIndirect = NULL; // zero init.
pi->flags |= XS_BITMAP; break;
case CF_DIB: //
// Imediately following the dde data header is a global data handle
// to the DIB bits.
//
UserAssert(pi->cbDirect >= DDEDATA_WITH_HANDLE_SIZE); pi->flags |= XS_DIB; pi->hIndirect = (HANDLE)pDdeData->Data; USERGLOBALLOCK(pi->hIndirect, pi->pIndirect); if (pi->pIndirect == NULL) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEIn1:CF_DIB GlobalLock failed."); return (FAILNOFREE_POST); } pi->cbIndirect = (UINT)UserGlobalSize(pi->hIndirect); break;
case CF_PALETTE: UserAssert(pi->cbDirect >= DDEDATA_WITH_HANDLE_SIZE); pi->hIndirect = (HANDLE) pDdeData->Data; if (pi->hIndirect == 0) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEIn1:GdiConvertPalette failed."); return(FAILNOFREE_POST); } // pi->cbIndirect = 0; // zero init.
// pi->pIndirect = NULL; // zero init.
pi->flags |= XS_PALETTE; break;
case CF_DSPMETAFILEPICT: case CF_METAFILEPICT: //
// This format holds a global data handle which contains
// a METAFILEPICT structure that in turn contains
// a GDI metafile.
//
UserAssert(pi->cbDirect >= DDEDATA_WITH_HANDLE_SIZE); pi->hIndirect = GdiConvertMetaFilePict((HANDLE)pDdeData->Data); if (pi->hIndirect == 0) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEIn1:GdiConvertMetaFilePict failed"); return(FAILNOFREE_POST); } // pi->cbIndirect = 0; // zero init.
// pi->pIndirect = NULL; // zero init.
pi->flags |= XS_METAFILEPICT; break;
case CF_ENHMETAFILE: case CF_DSPENHMETAFILE: UserAssert(pi->cbDirect >= DDEDATA_WITH_HANDLE_SIZE); pi->hIndirect = GdiConvertEnhMetaFile((HENHMETAFILE)pDdeData->Data); if (pi->hIndirect == 0) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEIn1:GdiConvertEnhMetaFile failed"); return(FAILNOFREE_POST); } // pi->cbIndirect = 0; // zero init.
// pi->pIndirect = NULL; // zero init.
pi->flags |= XS_ENHMETAFILE; break; } }
return (DO_POST); }
/*
* unlocks and frees DDE data pointers as appropriate */ VOID _ClientCopyDDEIn2( PINTDDEINFO pi) { if (pi->cbDirect) { USERGLOBALUNLOCK(pi->hDirect); if (pi->flags & XS_FREESRC) { WOWGLOBALFREE(pi->hDirect); } }
if (pi->cbIndirect) { USERGLOBALUNLOCK(pi->hIndirect); if (pi->flags & XS_FREESRC) { WOWGLOBALFREE(pi->hIndirect); } } }
/*
* returns fHandleValueChanged. */ BOOL FixupDdeExecuteIfNecessary( HGLOBAL *phCommands, BOOL fNeedUnicode) { UINT cbLen; UINT cbSrc = (UINT)GlobalSize(*phCommands); LPVOID pstr; HGLOBAL hTemp; BOOL fHandleValueChanged = FALSE;
USERGLOBALLOCK(*phCommands, pstr);
if (cbSrc && pstr != NULL) { BOOL fIsUnicodeText; #ifdef ISTEXTUNICODE_WORKS
int flags;
flags = (IS_TEXT_UNICODE_UNICODE_MASK | IS_TEXT_UNICODE_REVERSE_MASK | (IS_TEXT_UNICODE_NOT_UNICODE_MASK & (~IS_TEXT_UNICODE_ILLEGAL_CHARS)) | IS_TEXT_UNICODE_NOT_ASCII_MASK); fIsUnicodeText = RtlIsTextUnicode(pstr, cbSrc - 2, &flags); #else
fIsUnicodeText = ((cbSrc >= sizeof(WCHAR)) && (((LPSTR)pstr)[1] == '\0')); #endif
if (!fIsUnicodeText && fNeedUnicode) { LPWSTR pwsz; /*
* Contents needs to be UNICODE. */ cbLen = strlen(pstr) + 1; cbSrc = min(cbSrc, cbLen); pwsz = UserLocalAlloc(HEAP_ZERO_MEMORY, cbSrc * sizeof(WCHAR)); if (pwsz != NULL) { if (NT_SUCCESS(RtlMultiByteToUnicodeN( pwsz, cbSrc * sizeof(WCHAR), NULL, (PCHAR)pstr, cbSrc))) { USERGLOBALUNLOCK(*phCommands); if ((hTemp = GlobalReAlloc( *phCommands, cbSrc * sizeof(WCHAR), GMEM_MOVEABLE)) != NULL) { fHandleValueChanged = (hTemp != *phCommands); *phCommands = hTemp; USERGLOBALLOCK(*phCommands, pstr); pwsz[cbSrc - 1] = L'\0'; wcscpy(pstr, pwsz); } } UserLocalFree(pwsz); } } else if (fIsUnicodeText && !fNeedUnicode) { LPSTR psz; /*
* Contents needs to be ANSI. */ cbLen = (wcslen(pstr) + 1) * sizeof(WCHAR); cbSrc = min(cbSrc, cbLen); psz = UserLocalAlloc(HEAP_ZERO_MEMORY, cbSrc); if (psz != NULL) { if (NT_SUCCESS(RtlUnicodeToMultiByteN( psz, cbSrc, NULL, (PWSTR)pstr, cbSrc))) { USERGLOBALUNLOCK(*phCommands); if ((hTemp = GlobalReAlloc( *phCommands, cbSrc / sizeof(WCHAR), GMEM_MOVEABLE)) != NULL) { fHandleValueChanged = (hTemp != *phCommands); *phCommands = hTemp; USERGLOBALLOCK(*phCommands, pstr); UserAssert(pstr); psz[cbSrc - 1] = '\0'; strcpy(pstr, psz); } } UserLocalFree(psz); } } USERGLOBALUNLOCK(*phCommands); } return(fHandleValueChanged); }
/*
* Allocates and locks global handles as appropriate in preperation * for thunk copying. */ HANDLE _ClientCopyDDEOut1( PINTDDEINFO pi) { HANDLE hDdePack = NULL; PDDEPACK pDdePack = NULL;
if (pi->flags & XS_PACKED) { /*
* make a wrapper for the data */ hDdePack = UserGlobalAlloc(GMEM_DDESHARE | GMEM_FIXED, sizeof(DDEPACK)); pDdePack = (PDDEPACK)hDdePack; if (pDdePack == NULL) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEOut1:Couldn't allocate DDEPACK"); return (NULL); } *pDdePack = pi->DdePack; }
if (pi->cbDirect) { pi->hDirect = UserGlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, pi->cbDirect); if (pi->hDirect == NULL) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEOut1:Couldn't allocate hDirect"); if (hDdePack) { UserGlobalFree(hDdePack); } return (NULL); }
USERGLOBALLOCK(pi->hDirect, pi->pDirect); UserAssert(pi->pDirect);
// fixup packed data reference to direct data
if (pDdePack != NULL) { if (pi->flags & XS_LOHANDLE) { pDdePack->uiLo = (UINT_PTR)pi->hDirect; UserAssert((ULONG_PTR)pDdePack->uiLo == (ULONG_PTR)pi->hDirect); } else if (pi->flags & XS_HIHANDLE) { pDdePack->uiHi = (UINT_PTR)pi->hDirect; UserAssert((ULONG_PTR)pDdePack->uiHi == (ULONG_PTR)pi->hDirect); } }
if (pi->cbIndirect) { pi->hIndirect = UserGlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, pi->cbIndirect); if (pi->hIndirect == NULL) { RIPMSG0(RIP_WARNING, "_ClientCopyDDEOut1:Couldn't allocate hIndirect"); USERGLOBALUNLOCK(pi->hDirect); UserGlobalFree(pi->hDirect); if (hDdePack) { UserGlobalFree(hDdePack); } return (NULL); } USERGLOBALLOCK(pi->hIndirect, pi->pIndirect); UserAssert(pi->pIndirect); } }
if (hDdePack) { return (hDdePack); } else { return (pi->hDirect); } }
/*
* Fixes up internal poniters after thunk copy and unlocks handles. */ BOOL _ClientCopyDDEOut2( PINTDDEINFO pi) { BOOL fSuccess = TRUE; /*
* done with copies - now fixup indirect references */ if (pi->hIndirect) { PDDE_DATA pDdeData = (PDDE_DATA)pi->pDirect;
switch (pDdeData->wFmt) { case CF_BITMAP: case CF_DSPBITMAP: case CF_PALETTE: pDdeData->Data = (KERNEL_PVOID)pi->hIndirect; fSuccess = (pDdeData->Data != NULL); break;
case CF_METAFILEPICT: case CF_DSPMETAFILEPICT: pDdeData->Data = (KERNEL_PVOID)GdiCreateLocalMetaFilePict(pi->hIndirect); fSuccess = (pDdeData->Data != NULL); break;
case CF_DIB: pDdeData->Data = (KERNEL_PVOID)pi->hIndirect; fSuccess = (pDdeData->Data != NULL); USERGLOBALUNLOCK(pi->hIndirect); break;
case CF_ENHMETAFILE: case CF_DSPENHMETAFILE: pDdeData->Data = (KERNEL_PVOID)GdiCreateLocalEnhMetaFile(pi->hIndirect); fSuccess = (pDdeData->Data != NULL); break;
default: RIPMSG0(RIP_WARNING, "_ClientCopyDDEOut2:Unknown format w/indirect data."); fSuccess = FALSE; USERGLOBALUNLOCK(pi->hIndirect); } }
UserAssert(pi->hDirect); // if its null, we didn't need to call this function.
USERGLOBALUNLOCK(pi->hDirect); if (pi->flags & XS_EXECUTE) { /*
* Its possible that in RAW DDE cases where the app allocated the * execute data as non-moveable, we have a different hDirect * than we started with. This needs to be noted and passed * back to the server. (Very RARE case) */ FixupDdeExecuteIfNecessary(&pi->hDirect, pi->flags & XS_UNICODE); } return fSuccess; }
/*
* This routine is called by the tracking layer when it frees DDE objects * on behalf of a client. This cleans up the LOCAL objects associated * with the DDE objects. It should NOT remove truely global objects such * as bitmaps or palettes except in the XS_DUMPMSG case which is for * faked Posts. */
#if DBG
/*
* Help track down a bug where I suspect the xxxFreeListFree is * freeing a handle already freed by some other means which has * since been reallocated and is trashing the client heap. (SAS) */ HANDLE DDEHandleLastFreed = 0; #endif
BOOL _ClientFreeDDEHandle( HANDLE hDDE, DWORD flags) { PDDEPACK pDdePack; HANDLE hNew;
if (flags & XS_PACKED) { pDdePack = (PDDEPACK)hDDE; if (pDdePack == NULL) { return (FALSE); } if (flags & XS_LOHANDLE) { hNew = (HANDLE)pDdePack->uiLo; } else { hNew = (HANDLE)pDdePack->uiHi;
} WOWGLOBALFREE(hDDE); hDDE = hNew;
}
/*
* Do a range check and call GlobalFlags to validate, just to prevent heap checking * from complaining during the GlobalSize call. * Is this leaking atoms?? */ if ((hDDE <= (HANDLE)0xFFFF) || (GlobalFlags(hDDE) == GMEM_INVALID_HANDLE) || !GlobalSize(hDDE)) { /*
* There may be cases where apps improperly freed stuff * when they shouldn't have so make sure this handle * is valid by the time it gets here. * * See SvSpontAdvise; it posts a message with an atom in uiHi. Then from _PostMessage * in the kernel side, we might end up here. So it's not only for apps... */ return(FALSE); }
if (flags & XS_DUMPMSG) { if (flags & XS_PACKED) { if (!IS_PTR(hNew)) { GlobalDeleteAtom(LOWORD((ULONG_PTR)hNew)); if (!(flags & XS_DATA)) { return(TRUE); // ACK
} } } else { if (!(flags & XS_EXECUTE)) { GlobalDeleteAtom(LOWORD((ULONG_PTR)hDDE)); // REQUEST, UNADVISE
return(TRUE); } } } if (flags & XS_DATA) { // POKE, DATA
#if DBG
DDEHandleLastFreed = hDDE; #endif
FreeDDEData(hDDE, (flags & XS_DUMPMSG) ? FALSE : TRUE, // fIgnorefRelease
(flags & XS_DUMPMSG) ? TRUE : FALSE); // fDestroyTruelyGlobalObjects
} else { // ADVISE, EXECUTE
#if DBG
DDEHandleLastFreed = hDDE; #endif
WOWGLOBALFREE(hDDE); // covers ADVISE case (fmt but no data)
} return (TRUE); }
DWORD _ClientGetDDEFlags( HANDLE hDDE, DWORD flags) { PDDEPACK pDdePack; PWORD pw; HANDLE hData; DWORD retval = 0;
pDdePack = (PDDEPACK)hDDE; if (pDdePack == NULL) { return (0); }
if (flags & XS_DATA) { if (pDdePack->uiLo) { hData = (HANDLE)pDdePack->uiLo; USERGLOBALLOCK(hData, pw); if (pw != NULL) { retval = (DWORD)*pw; // first word is hData is wStatus
USERGLOBALUNLOCK(hData); } } } else { retval = (DWORD)pDdePack->uiLo; }
return (retval); }
FUNCLOG3(LOG_GENERAL, LPARAM, APIENTRY, PackDDElParam, UINT, msg, UINT_PTR, uiLo, UINT_PTR, uiHi) LPARAM APIENTRY PackDDElParam( UINT msg, UINT_PTR uiLo, UINT_PTR uiHi) { PDDEPACK pDdePack; HANDLE h;
switch (msg) { case WM_DDE_EXECUTE: return((LPARAM)uiHi);
case WM_DDE_ACK: case WM_DDE_ADVISE: case WM_DDE_DATA: case WM_DDE_POKE: h = UserGlobalAlloc(GMEM_DDESHARE | GMEM_FIXED, sizeof(DDEPACK)); pDdePack = (PDDEPACK)h; if (pDdePack == NULL) { return(0); } pDdePack->uiLo = uiLo; pDdePack->uiHi = uiHi; return((LPARAM)h);
default: return(MAKELONG((WORD)uiLo, (WORD)uiHi)); } }
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, UnpackDDElParam, UINT, msg, LPARAM, lParam, PUINT_PTR, puiLo, PUINT_PTR, puiHi) BOOL APIENTRY UnpackDDElParam( UINT msg, LPARAM lParam, PUINT_PTR puiLo, PUINT_PTR puiHi) { PDDEPACK pDdePack;
switch (msg) { case WM_DDE_EXECUTE: if (puiLo != NULL) { *puiLo = 0L; } if (puiHi != NULL) { *puiHi = (UINT_PTR)lParam; } return(TRUE);
case WM_DDE_ACK: case WM_DDE_ADVISE: case WM_DDE_DATA: case WM_DDE_POKE: pDdePack = (PDDEPACK)lParam; if (pDdePack == NULL || !GlobalHandle(pDdePack)) { if (puiLo != NULL) { *puiLo = 0L; } if (puiHi != NULL) { *puiHi = 0L; } return(FALSE); } if (puiLo != NULL) { *puiLo = pDdePack->uiLo; } if (puiHi != NULL) { *puiHi = pDdePack->uiHi; } return(TRUE);
default: if (puiLo != NULL) { *puiLo = (UINT)LOWORD(lParam); } if (puiHi != NULL) { *puiHi = (UINT)HIWORD(lParam); } return(TRUE); } }
FUNCLOG2(LOG_GENERAL, BOOL, APIENTRY, FreeDDElParam, UINT, msg, LPARAM, lParam) BOOL APIENTRY FreeDDElParam( UINT msg, LPARAM lParam) { switch (msg) { case WM_DDE_ACK: case WM_DDE_ADVISE: case WM_DDE_DATA: case WM_DDE_POKE: /*
* Do a range check and call GlobalFlags to validate, * just to prevent heap checking from complaining */ if ((lParam > (LPARAM)0xFFFF) && GlobalFlags((HANDLE)lParam) != GMEM_INVALID_HANDLE) { if (GlobalHandle((HANDLE)lParam)) return(UserGlobalFree((HANDLE)lParam) == NULL); }
default: return(TRUE); } }
FUNCLOG5(LOG_GENERAL, LPARAM, APIENTRY, ReuseDDElParam, LPARAM, lParam, UINT, msgIn, UINT, msgOut, UINT_PTR, uiLo, UINT_PTR, uiHi) LPARAM APIENTRY ReuseDDElParam( LPARAM lParam, UINT msgIn, UINT msgOut, UINT_PTR uiLo, UINT_PTR uiHi) { PDDEPACK pDdePack;
switch (msgIn) { case WM_DDE_ACK: case WM_DDE_DATA: case WM_DDE_POKE: case WM_DDE_ADVISE: //
// Incoming message was packed...
//
switch (msgOut) { case WM_DDE_EXECUTE: FreeDDElParam(msgIn, lParam); return((LPARAM)uiHi);
case WM_DDE_ACK: case WM_DDE_ADVISE: case WM_DDE_DATA: case WM_DDE_POKE: /*
* This must be a valid handle */ UserAssert(GlobalFlags((HANDLE)lParam) != GMEM_INVALID_HANDLE); UserAssert(GlobalSize((HANDLE)lParam) == sizeof(DDEPACK)); //
// Actual cases where lParam can be reused.
//
pDdePack = (PDDEPACK)lParam; if (pDdePack == NULL) { return(0); // the only error case
} pDdePack->uiLo = uiLo; pDdePack->uiHi = uiHi; return(lParam);
default: FreeDDElParam(msgIn, lParam); return(MAKELONG((WORD)uiLo, (WORD)uiHi)); }
default: //
// Incoming message was not packed ==> PackDDElParam()
//
return(PackDDElParam(msgOut, uiLo, uiHi)); } }
|