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