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.
 
 
 
 
 
 

740 lines
22 KiB

/****************************** 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));
}
}