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.
 
 
 
 
 
 

2539 lines
76 KiB

/****************************** Module Header *******************************
* Module Name: ddetrack.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module handles tracking of DDE conversations for use in emulating
* DDE shared memory.
*
* History:
* 9-3-91 sanfords Created
* 21-Jan-1992 IanJa ANSI/Unicode netralized (null op)
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
PPUBOBJ gpPublicObjectList;
#define TRACE_DDE(str) TAGMSG0(DBGTAG_DDE, str)
#define TRACE_DDE1(s, a) TAGMSG1(DBGTAG_DDE, (s), (a))
#define TRACE_DDE2(s, a, b) TAGMSG2(DBGTAG_DDE, (s), (a), (b))
#define TRACE_DDE3(s, a, b, c) TAGMSG3(DBGTAG_DDE, (s), (a), (b), (c))
BOOL NewConversation(PDDECONV *ppdcNewClient, PDDECONV *ppdcNewServer,
PWND pwndClient, PWND pwndServer);
PDDECONV FindDdeConv(PWND pwndProp, PWND pwndPartner);
BOOL AddConvProp(PWND pwndUs, PWND pwndThem, DWORD flags, PDDECONV pdcNew,
PDDECONV pdcPartner);
FNDDERESPONSE xxxUnexpectedServerPost;
FNDDERESPONSE xxxUnexpectedClientPost;
FNDDERESPONSE xxxAdvise;
FNDDERESPONSE xxxAdviseAck;
FNDDERESPONSE xxxAdviseData;
FNDDERESPONSE xxxAdviseDataAck;
DWORD Unadvise(PDDECONV pDdeConv);
FNDDERESPONSE xxxUnadviseAck;
DWORD Request(PDDECONV pDdeConv);
FNDDERESPONSE xxxRequestAck;
FNDDERESPONSE xxxPoke;
FNDDERESPONSE xxxPokeAck;
FNDDERESPONSE xxxExecute;
FNDDERESPONSE xxxExecuteAck;
DWORD SpontaneousTerminate(PDWORD pmessage, PDDECONV pDdeConv);
FNDDERESPONSE DupConvTerminate;
HANDLE AnticipatePost(PDDECONV pDdeConv, FNDDERESPONSE fnResponse,
HANDLE hClient, HANDLE hServer, PINTDDEINFO pIntDdeInfo, DWORD flags);
PXSTATE Createpxs(FNDDERESPONSE fnResponse, HANDLE hClient, HANDLE hServer,
PINTDDEINFO pIntDdeInfo, DWORD flags);
DWORD AbnormalDDEPost(PDDECONV pDdeConv, DWORD message);
DWORD xxxCopyDdeIn(HANDLE hSrc, PDWORD pflags, PHANDLE phDirect, PINTDDEINFO *ppi);
DWORD xxxCopyAckIn(PDWORD pmessage, LPARAM *plParam, PDDECONV pDdeConv, PINTDDEINFO *ppIntDdeInfo);
HANDLE xxxCopyDDEOut(PINTDDEINFO pIntDdeInfo, PHANDLE phDirect);
BOOL FreeListAdd(PDDECONV pDdeConv, HANDLE hClient, DWORD flags);
VOID xxxFreeListFree(PFREELIST pfl);
VOID PopState(PDDECONV pDdeConv);
PDDECONV UnlinkConv(PDDECONV pDdeConv);
VOID FreeDDEHandle(PDDECONV pDdeConv, HANDLE hClient, DWORD flags);
DWORD ClientFreeDDEHandle(HANDLE hClient, DWORD flags);
DWORD ClientGetDDEFlags(HANDLE hClient, DWORD flags);
DWORD xxxClientCopyDDEIn1(HANDLE hClient, DWORD flags, PINTDDEINFO *ppi);
HANDLE xxxClientCopyDDEOut1(PINTDDEINFO pIntDdeInfo);
DWORD xxxClientCopyDDEOut2(PINTDDEINFO pIntDdeInfo);
PPUBOBJ IsObjectPublic(HANDLE hObj);
BOOL AddPublicObject(UINT format, HANDLE hObj, W32PID pid);
BOOL RemovePublicObject(UINT format, HANDLE hObj);
BOOL GiveObject(UINT format, HANDLE hObj, W32PID pid);
/*
* The Big Picture:
*
* When a WM_DDE_ACK message is SENT, it implies the begining of a DDE
* Conversation. The tracking layer creates DDECONV structure for each
* window in volved in the conversation and cross links the structures.
* Thus a unique window pair identifies a conversation. Each window has
* its DDECONV structure attached to it via a private property.
*
* As DDE messages are posted, the tracking layer copies data into the
* CSR server side of USER into a INTDDEINFO structure. This structure
* contains flags which direct how the data is to be freed when the
* time comes. This info is placed within an XSTATE structure along
* with context infomation. A pointer to the XSTATE structure is
* placed in the lParam of the message and the MSB of message is set
* for special processing when the message is recieved on the other side.
*
* If the message posted requires a responding message to follow the DDE
* protocol, a XSTATE structure is created and attached to DDECONV
* structure associated with the window that is expected to post the message.
* The XSTATE structure directs the tracking layer so that it knows the
* context of the message when it is posted and also includes any
* information needed for proper freeing of extra DDE data.
*
* When the message is extracted from the queue either by a hook, peek,
* or by GetMessage, the id is checked to see if it lies in the special
* range. If so, the XSTATE structure pointed to by the lParam is
* operated on. This causes the data to be copied from the CSR server
* side of USER to the target process context. Once this is done, the
* XSTATE structure may or may not be freed depending on flags and
* the message is restored to a proper DDE message form ready to be
* used by the target process. Since the message id is changed back,
* subsequent peeks or hooks to the message will not result in duplicated
* processing of the message.
*
* During the course of come transactions it becomes evident that an object
* on the opposite side process needs to be freed. This is done
* asynchronously by inserting the object that needs freeing along with
* associated flags into a freeing list which is tied to the DDECONV
* structure associated with the window on the opposite side. Whenever
* a DDE messages is posted, this freeing list is checked and processed.
*
* When a WM_DDE_TERMINATE message is finally recieved, flags are set
* in the DDECONV structure indicating that the conversation is terminating.
* This alters the way the mapping layer handles DDE messages posted.
* When the responding side posts a WM_DDE_TERMINATE, the DDECONV structures
* and all associated information is freed and unlinked from the windows
* concerned.
*
* Should a DDE window get destroyed before proper termination, the
* xxxDDETrackWindowDying function is called to make sure proper termination
* is done prior to the window being destroyed.
*/
/************************************************************************
* xxxDDETrackSendHook
*
* Called when a DDE message is passed to SendMessage().
*
* Returns fSendOk.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
BOOL xxxDDETrackSendHook(
PWND pwndTo,
DWORD message,
WPARAM wParam,
LPARAM lParam)
{
PWND pwndServer;
PDDECONV pdcNewClient, pdcNewServer;
if (MonitorFlags & MF_SENDMSGS) {
DDEML_MSG_HOOK_DATA dmhd;
dmhd.cbData = 0; // Initiate and Ack sent messages have no data.
dmhd.uiLo = LOWORD(lParam); // they arn't packed either.
dmhd.uiHi = HIWORD(lParam);
xxxMessageEvent(pwndTo, message, wParam, lParam, MF_SENDMSGS, &dmhd);
}
if (PtiCurrent()->ppi == GETPWNDPPI(pwndTo)) {
/*
* Skip monitoring of all intra-process conversations.
*/
return TRUE;
}
if (message != WM_DDE_ACK) {
if (message == WM_DDE_INITIATE) {
return TRUE; // this is cool
}
return FALSE;
}
pwndServer = ValidateHwnd((HWND)wParam);
if (pwndServer == NULL) {
return FALSE;
}
pdcNewServer = FindDdeConv(pwndServer, pwndTo);
if (pdcNewServer != NULL) {
RIPMSG2(RIP_WARNING,
"DDE protocol violation - non-unique window pair (%#p:%#p)",
PtoH(pwndTo), PtoH(pwndServer));
/*
* Duplicate Conversation case:
* Don't allow the ACK to pass, post a terminate to the server
* to shut down the duplicate on his end.
*/
AnticipatePost(pdcNewServer, DupConvTerminate, NULL, NULL, NULL, 0);
_PostMessage(pwndServer, WM_DDE_TERMINATE, (WPARAM)PtoH(pwndTo), 0);
return FALSE;
}
if (!NewConversation(&pdcNewClient, &pdcNewServer, pwndTo, pwndServer)) {
return FALSE;
}
TRACE_DDE2("%#p->%#p DDE Conversation started", PtoH(pwndTo), wParam);
return TRUE;
}
/************************************************************************
* AddConvProp
*
* Helper for xxxDDETrackSendHook - associates a new DDECONV struct with
* a window and initializes it.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
BOOL AddConvProp(
PWND pwndUs,
PWND pwndThem,
DWORD flags,
PDDECONV pdcNew,
PDDECONV pdcPartner)
{
PDDECONV pDdeConv;
PDDEIMP pddei;
pDdeConv = (PDDECONV)_GetProp(pwndUs, PROP_DDETRACK, PROPF_INTERNAL);
Lock(&(pdcNew->snext), pDdeConv);
Lock(&(pdcNew->spwnd), pwndUs);
Lock(&(pdcNew->spwndPartner), pwndThem);
/*
* Assert to catch stress bug.
*/
UserAssert(pdcPartner != (PDDECONV)(-1));
Lock(&(pdcNew->spartnerConv), pdcPartner);
pdcNew->spxsIn = NULL;
pdcNew->spxsOut = NULL;
pdcNew->flags = flags;
pddei = (PDDEIMP)_GetProp((flags & CXF_IS_SERVER) ?
pwndThem : pwndUs, PROP_DDEIMP, PROPF_INTERNAL);
if (pddei != NULL) { // This can be NULL if a bad WOW app has been
pddei->cRefConv++; // allowed through for compatability.
}
pdcNew->pddei = pddei;
HMLockObject(pdcNew); // lock for property
InternalSetProp(pwndUs, PROP_DDETRACK, pdcNew, PROPF_INTERNAL);
return TRUE;
}
/************************************************************************
* UnlinkConv
*
* Unlinks a DDECONV structure from the property list it is associated with.
*
* returns pDdeConv->snext
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
PDDECONV UnlinkConv(
PDDECONV pDdeConv)
{
PDDECONV pdcPrev, pdcT, pDdeConvNext;
/*
* Already unlinked
*/
if (pDdeConv->spwnd == NULL) {
return NULL;
}
TRACE_DDE1("UnlinkConv(%#p)", pDdeConv);
pdcT = (PDDECONV)_GetProp(pDdeConv->spwnd,
PROP_DDETRACK, PROPF_INTERNAL);
if (pdcT == NULL) {
return NULL; // already unlinked
}
pdcPrev = NULL;
while (pdcT != pDdeConv) {
pdcPrev = pdcT;
pdcT = pdcT->snext;
if (pdcT == NULL) {
return NULL; // already unlinked
}
}
if (pdcPrev == NULL) {
if (pDdeConv->snext == NULL) {
// last one out removes the property
InternalRemoveProp(pDdeConv->spwnd, PROP_DDETRACK, PROPF_INTERNAL);
} else {
// head conv unlinked - update prop
InternalSetProp(pDdeConv->spwnd, PROP_DDETRACK, pDdeConv->snext,
PROPF_INTERNAL);
}
} else {
Lock(&(pdcPrev->snext), pDdeConv->snext);
}
pDdeConvNext = Unlock(&(pDdeConv->snext));
HMUnlockObject(pDdeConv); // unlock for property detachment
return pDdeConvNext;
}
/************************************************************************
* xxxDDETrackPostHook
*
* Hook function for handling posted DDE messages.
*
* returns post action code - DO_POST, FAKE_POST, FAIL_POST.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
DWORD xxxDDETrackPostHook(
PUINT pmessage,
PWND pwndTo,
WPARAM wParam,
LPARAM *plParam,
BOOL fSent)
{
PWND pwndFrom;
PDDECONV pDdeConv = NULL;
DWORD dwRet;
TL tlpDdeConv;
PFREELIST pfl, *ppfl;
DWORD MFlag;
CheckLock(pwndTo);
MFlag = fSent ? MF_SENDMSGS : MF_POSTMSGS;
if (MonitorFlags & MFlag) {
DDEML_MSG_HOOK_DATA dmhd;
switch (*pmessage ) {
case WM_DDE_DATA:
case WM_DDE_POKE:
case WM_DDE_ADVISE:
case WM_DDE_EXECUTE:
case WM_DDE_ACK:
ClientGetDDEHookData(*pmessage, *plParam, &dmhd);
break;
default:
// WM_DDE_REQUEST
// WM_DDE_TERMINATE
// WM_DDE_UNADVISE
dmhd.cbData = 0;
dmhd.uiLo = LOWORD(*plParam);
dmhd.uiHi = HIWORD(*plParam);
}
xxxMessageEvent(pwndTo, *pmessage, wParam, *plParam, MFlag,
&dmhd);
}
if (PtiCurrent()->ppi == GETPWNDPPI(pwndTo)) {
/*
* skip all intra-process conversation tracking.
*/
dwRet = DO_POST;
goto Exit;
}
if (*pmessage == WM_DDE_INITIATE) {
RIPMSG2(RIP_WARNING,
"DDE Post failed (%#p:%#p) - WM_DDE_INITIATE posted",
wParam, PtoH(pwndTo));
dwRet = FAIL_POST;
goto Exit;
}
pwndFrom = ValidateHwnd((HWND)wParam);
if (pwndFrom == NULL) {
/*
* This is a post AFTER a window has been destroyed. This is not
* expected except in the case where xxxDdeTrackWindowDying()
* is posting a cleanup terminate.
*/
dwRet = *pmessage == WM_DDE_TERMINATE ? DO_POST : FAKE_POST;
goto Exit;
}
/*
* locate conversation info.
*/
pDdeConv = FindDdeConv(pwndFrom, pwndTo);
if (pDdeConv == NULL) {
if (*pmessage != WM_DDE_TERMINATE &&
(GETPTI(pwndFrom)->TIF_flags & TIF_16BIT) &&
(pwndTo->head.rpdesk == pwndFrom->head.rpdesk)) {
/*
* If a WOW app bypasses initiates and posts directly to
* a window on the same desktop, let it sneak by here.
*
* This allows some evil apps such as OpenEngine and CA-Cricket
* to get away with murder.
*
* TERMINATES out of the blue however may be due to an app
* posting its WM_DDE_TERMINATE after it has destroyed its
* window. Since window destruction would have generated the
* TERMINATE already, don't let it through here.
*/
NewConversation(&pDdeConv, NULL, pwndFrom, pwndTo);
}
if (pDdeConv == NULL) {
RIPMSG2(RIP_VERBOSE, "Can't find DDE conversation for (%#p:%#p).",
wParam, PtoH(pwndTo));
dwRet = *pmessage == WM_DDE_TERMINATE ? FAKE_POST : FAIL_POST;
goto Exit;
}
}
if (fSent && pDdeConv->spartnerConv->spxsOut != NULL &&
!(GETPTI(pwndFrom)->dwCompatFlags2 & GACF2_DDENOSYNC) ) {
/*
* Sent DDE messages will not work if any posted DDE messages are
* in the queue because this will violate the message ordering rule.
*/
RIPMSG0(RIP_VERBOSE,
"Sent DDE message failed - queue contains a previous post.");
dwRet = FAIL_POST;
goto Exit;
}
/*
* The tracking layer never did allow multiple threads to handle
* the same DDE conversation but win95 shipped and some apps
* got out there that did just this. We will let it slide for
* 4.0 apps only so that when they rev their app, they will see
* that they were wrong.
*/
if (PtiCurrent() != GETPTI(pDdeConv) &&
LOWORD(PtiCurrent()->dwExpWinVer) != VER40) {
RIPERR0(ERROR_WINDOW_OF_OTHER_THREAD,
RIP_ERROR,
"Posting DDE message from wrong thread!");
dwRet = FAIL_POST;
goto Exit;
}
ThreadLockAlways(pDdeConv, &tlpDdeConv);
/*
* If the handle we're using is in the free list, remove it
*/
ppfl = &pDdeConv->pfl;
while (*ppfl != NULL) {
if ((*ppfl)->h == (HANDLE)*plParam) {
/* Let's stop to check this out */
UserAssert((*ppfl)->h == (HANDLE)*plParam);
*ppfl = (*ppfl)->next;
} else {
ppfl = &(*ppfl)->next;
}
}
pfl = pDdeConv->pfl;
pDdeConv->pfl = NULL;
xxxFreeListFree(pfl);
if (*pmessage != WM_DDE_TERMINATE &&
(pDdeConv->flags & (CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED))) {
dwRet = FAKE_POST;
goto UnlockExit;
}
if (pDdeConv->spxsOut == NULL) {
if (pDdeConv->flags & CXF_IS_SERVER) {
dwRet = xxxUnexpectedServerPost((PDWORD)pmessage, plParam, pDdeConv);
} else {
dwRet = xxxUnexpectedClientPost((PDWORD)pmessage, plParam, pDdeConv);
}
} else {
dwRet = (pDdeConv->spxsOut->fnResponse)(pmessage, plParam, pDdeConv);
}
UnlockExit:
ThreadUnlock(&tlpDdeConv);
Exit:
if (dwRet == FAKE_POST && !((PtiCurrent())->TIF_flags & TIF_INCLEANUP)) {
/*
* We faked the post so do a client side cleanup here so that we
* don't make it appear there is a leak in the client app.
*/
DWORD flags = XS_DUMPMSG;
/*
* The XS_DUMPMSG tells FreeDDEHandle to also free the atoms
* associated with the data - since a faked post would make the app
* think that the receiver was going to cleanup the atoms.
* It also tells FreeDDEHandle to pay attention to the
* fRelease bit when freeing the data - this way, loaned data
* won't be destroyed.
*/
switch (*pmessage & 0xFFFF) {
case WM_DDE_UNADVISE:
case WM_DDE_REQUEST:
goto DumpMsg;
case WM_DDE_ACK:
flags |= XS_PACKED;
goto DumpMsg;
case WM_DDE_ADVISE:
flags |= XS_PACKED | XS_HIHANDLE;
goto DumpMsg;
case WM_DDE_DATA:
case WM_DDE_POKE:
flags |= XS_DATA | XS_LOHANDLE | XS_PACKED;
goto DumpMsg;
case WM_DDE_EXECUTE:
flags |= XS_EXECUTE;
// fall through
DumpMsg:
if (pDdeConv != NULL) {
TRACE_DDE("xxxDdeTrackPostHook: dumping message...");
FreeDDEHandle(pDdeConv, (HANDLE)*plParam, flags);
dwRet = FAILNOFREE_POST;
}
}
}
#if DBG
if (fSent) {
TraceDdeMsg(*pmessage, (HWND)wParam, PtoH(pwndTo), MSG_SENT);
} else {
TraceDdeMsg(*pmessage, (HWND)wParam, PtoH(pwndTo), MSG_POST);
}
if (dwRet == FAKE_POST) {
TRACE_DDE("...FAKED!");
} else if (dwRet == FAIL_POST) {
TRACE_DDE("...FAILED!");
} else if (dwRet == FAILNOFREE_POST) {
TRACE_DDE("...FAILED, DATA FREED!");
}
#endif // DBG
return dwRet;
}
VOID xxxCleanupDdeConv(
PWND pwndProp)
{
PDDECONV pDdeConv;
Restart:
CheckCritIn();
pDdeConv = (PDDECONV)_GetProp(pwndProp, PROP_DDETRACK, PROPF_INTERNAL);
while (pDdeConv != NULL) {
if ((pDdeConv->flags & (CXF_IS_SERVER | CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED))
== (CXF_IS_SERVER | CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED) &&
(pDdeConv->spartnerConv->flags & CXF_TERMINATE_POSTED)) {
/*
* clean up client side objects on this side
*/
BOOL fUnlockDdeConv;
TL tlpDdeConv;
RIPMSG1(RIP_VERBOSE, "xxxCleanupDdeConv %p", pDdeConv);
fUnlockDdeConv = (pDdeConv->pfl != NULL);
if (fUnlockDdeConv) {
PFREELIST pfl;
ThreadLockAlways(pDdeConv, &tlpDdeConv);
pfl = pDdeConv->pfl;
pDdeConv->pfl = NULL;
xxxFreeListFree(pfl);
}
FreeDdeConv(pDdeConv->spartnerConv);
FreeDdeConv(pDdeConv);
if (fUnlockDdeConv) {
ThreadUnlock(&tlpDdeConv);
}
/*
* Take it back from the top. The list might have changed
* if we left the critical section
*/
goto Restart;
}
pDdeConv = pDdeConv->snext;
}
}
/************************************************************************
* xxxDDETrackGetMessageHook
*
* This routine is used to complete an inter-process copy from the
* CSRServer context to the target context. pmsg->lParam is a
* pxs that is used to obtain the pIntDdeInfo needed to
* complete the copy. The pxs is either filled with the target side
* direct handle or is freed depending on the message and its context.
*
* The XS_FREEPXS bit of the flags field of the pxs tells this function
* to free the pxs when done.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
VOID xxxDDETrackGetMessageHook(
PMSG pmsg)
{
PXSTATE pxs;
HANDLE hDirect;
DWORD flags;
BOOL fUnlockDdeConv;
TL tlpDdeConv, tlpxs;
TraceDdeMsg(pmsg->message, (HWND)pmsg->wParam, pmsg->hwnd, MSG_RECV);
if (pmsg->message == WM_DDE_TERMINATE) {
PWND pwndFrom, pwndTo;
PDDECONV pDdeConv;
pwndTo = ValidateHwnd(pmsg->hwnd);
/*
* We should get the pwnd even if the partner is destroyed in order
* to clean up the DDE objects now. Exiting now would work, but would
* leave the conversation objects locked and present until the To window
* gets destroyed, which seems excessive.
*/
pwndFrom = RevalidateCatHwnd((HWND)pmsg->wParam);
if (pwndTo == NULL) {
TRACE_DDE("TERMINATE ignored, invalid window(s).");
return;
} else if (pwndFrom == NULL) {
CleanupAndExit:
/*
* Do this only for appcompat
*/
if (GetAppCompatFlags2(VERMAX) & GACF2_DDE) {
xxxCleanupDdeConv(pwndTo);
} else {
TRACE_DDE("TERMINATE ignored, invalid window(s).");
}
return;
}
/*
* locate conversation info.
*/
pDdeConv = FindDdeConv(pwndTo, pwndFrom);
if (pDdeConv == NULL) {
/*
* Must be a harmless extra terminate.
*/
TRACE_DDE("TERMINATE ignored, conversation not found.");
return;
}
if (pDdeConv->flags & CXF_TERMINATE_POSTED &&
pDdeConv->spartnerConv->flags & CXF_TERMINATE_POSTED) {
/*
* clean up client side objects on this side
*/
fUnlockDdeConv = FALSE;
if (pDdeConv->pfl != NULL) {
PFREELIST pfl;
fUnlockDdeConv = TRUE;
ThreadLockAlways(pDdeConv, &tlpDdeConv);
pfl = pDdeConv->pfl;
pDdeConv->pfl = NULL;
xxxFreeListFree(pfl);
}
TRACE_DDE2("DDE conversation (%#p:%#p) closed",
(pDdeConv->flags & CXF_IS_SERVER) ? pmsg->wParam : (ULONG_PTR)pmsg->hwnd,
(pDdeConv->flags & CXF_IS_SERVER) ? (ULONG_PTR)pmsg->hwnd : pmsg->wParam);
FreeDdeConv(pDdeConv->spartnerConv);
FreeDdeConv(pDdeConv);
if (fUnlockDdeConv) {
ThreadUnlock(&tlpDdeConv);
}
}
goto CleanupAndExit;
}
pxs = (PXSTATE)HMValidateHandleNoRip((HANDLE)pmsg->lParam, TYPE_DDEXACT);
if (pxs == NULL) {
/*
* The posting window has died and the pxs was freed so this
* message shouldn't be bothered with...map to WM_NULL.
*/
pmsg->lParam = 0;
pmsg->message = WM_NULL;
return;
}
flags = pxs->flags;
ThreadLockAlways(pxs, &tlpxs);
pmsg->lParam = (LPARAM)xxxCopyDDEOut(pxs->pIntDdeInfo, &hDirect);
if (pmsg->lParam == (LPARAM)NULL) {
/*
* Turn this message into a terminate - we failed to copy the
* message data out which implies we are too low on memory
* to continue the conversation. Shut it down now before
* other problems pop up that this failure will cause.
*/
pmsg->message = WM_DDE_TERMINATE;
RIPMSG0(RIP_WARNING, "DDETrack: couldn't copy data out, terminate faked.");
}
if (ThreadUnlock(&tlpxs) == NULL) {
return;
}
if (flags & XS_FREEPXS) {
FreeDdeXact(pxs);
return;
}
/*
* The only reason XS_FREEPXS isn't set is because we don't know which
* side frees the data till an ACK comes back, thus one of the client
* handles in pxs is already set via xxxDDETrackPostHook(). The one thats
* not yet set gets set here.
*/
if (pxs->hClient == NULL) {
TRACE_DDE1("Saving %#p into hClient", hDirect);
pxs->hClient = hDirect;
} else {
TRACE_DDE1("Saving %#p into hServer.", hDirect);
pxs->hServer = hDirect;
}
}
/************************************************************************
* xxxDDETrackWindowDying
*
* Called when a window with PROP_DDETRACK is destroyed.
*
* This posts a terminate to the partner window and sets up for proper
* terminate post fake from other end.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
VOID xxxDDETrackWindowDying(
PWND pwnd,
PDDECONV pDdeConv)
{
TL tlpDdeConv, tlpDdeConvNext;
UNREFERENCED_PARAMETER(pwnd);
CheckLock(pwnd);
CheckLock(pDdeConv);
TRACE_DDE2("xxxDDETrackWindowDying(%#p, %#p)", PtoH(pwnd), pDdeConv);
while (pDdeConv != NULL) {
PFREELIST pfl;
/*
* If there are any active conversations for this window
* start termination if not already started.
*/
if (!(pDdeConv->flags & CXF_TERMINATE_POSTED)) {
/*
* Win9x doesn't do any tracking. This breaks some apps that
* destroy the window first and then post the terminate. The
* other side gets two terminates.
*/
if (!(GACF2_NODDETRKDYING & GetAppCompatFlags2(VER40))
|| (pDdeConv->spwndPartner == NULL)
|| !(GACF2_NODDETRKDYING
& GetAppCompatFlags2ForPti(GETPTI(pDdeConv->spwndPartner), VER40))) {
/*
* CXF_TERMINATE_POSTED would have been set if the window had died.
*/
_PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE,
(WPARAM)PtoH(pDdeConv->spwnd), 0);
// pDdeConv->flags |= CXF_TERMINATE_POSTED; set by PostHookProc
} else {
RIPMSG2(RIP_WARNING, "xxxDDETrackWindowDying(GACF2_NODDETRKDYING) not posting terminate from %#p to %#p\r\n",
pwnd, pDdeConv->spwndPartner);
}
}
/*
* now fake that the other side already posted a terminate since
* we will be gone.
*/
pDdeConv->spartnerConv->flags |=
CXF_TERMINATE_POSTED | CXF_PARTNER_WINDOW_DIED;
ThreadLock(pDdeConv->snext, &tlpDdeConvNext);
ThreadLockAlways(pDdeConv, &tlpDdeConv);
pfl = pDdeConv->pfl;
pDdeConv->pfl = NULL;
if (pDdeConv->flags & CXF_PARTNER_WINDOW_DIED) {
ThreadUnlock(&tlpDdeConv);
/*
* he's already gone, free up conversation tracking data
*/
FreeDdeConv(pDdeConv->spartnerConv);
FreeDdeConv(pDdeConv);
} else {
UnlinkConv(pDdeConv);
ThreadUnlock(&tlpDdeConv);
}
xxxFreeListFree(pfl);
pDdeConv = ThreadUnlock(&tlpDdeConvNext);
}
}
/************************************************************************
* xxxUnexpectedServerPost
*
* Handles Server DDE messages not anticipated. (ie spontaneous or abnormal)
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
DWORD xxxUnexpectedServerPost(
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
switch (*pmessage) {
case WM_DDE_TERMINATE:
return SpontaneousTerminate(pmessage, pDdeConv);
case WM_DDE_DATA:
return xxxAdviseData(pmessage, plParam, pDdeConv);
case WM_DDE_ACK:
/*
* Could be an extra NACK due to timeout problems, just fake it.
*/
TRACE_DDE("xxxUnexpectedServerPost: dumping ACK data...");
FreeDDEHandle(pDdeConv, (HANDLE)*plParam, XS_PACKED);
return FAILNOFREE_POST;
case WM_DDE_ADVISE:
case WM_DDE_UNADVISE:
case WM_DDE_REQUEST:
case WM_DDE_POKE:
case WM_DDE_EXECUTE:
return AbnormalDDEPost(pDdeConv, *pmessage);
}
return 0;
}
/************************************************************************
* xxxUnexpectedClientPost
*
*
* Handles Client DDE messages not anticipated. (ie spontaneous or abnormal)
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
DWORD xxxUnexpectedClientPost(
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
switch (*pmessage) {
case WM_DDE_TERMINATE:
return SpontaneousTerminate(pmessage, pDdeConv);
case WM_DDE_ACK:
/*
* Could be an extra NACK due to timeout problems, just fake it.
*/
TRACE_DDE("xxxUnexpectedClientPost: dumping ACK data...");
FreeDDEHandle(pDdeConv, (HANDLE)*plParam, XS_PACKED);
return FAILNOFREE_POST;
case WM_DDE_DATA:
return AbnormalDDEPost(pDdeConv, *pmessage);
case WM_DDE_ADVISE:
return xxxAdvise(pmessage, plParam, pDdeConv);
case WM_DDE_UNADVISE:
return Unadvise(pDdeConv);
case WM_DDE_REQUEST:
return Request(pDdeConv);
case WM_DDE_POKE:
return xxxPoke(pmessage, plParam, pDdeConv);
case WM_DDE_EXECUTE:
return xxxExecute(pmessage, plParam, pDdeConv);
}
return 0;
}
/************************************************************************
* ADVISE TRANSACTION PROCESSING *
\***********************************************************************/
DWORD xxxAdvise( // Spontaneous Client transaction = WM_DDE_ADVISE
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
PINTDDEINFO pIntDdeInfo;
HANDLE hDirect;
DWORD flags, dwRet;
CheckLock(pDdeConv);
TRACE_DDE("xxxAdvise");
flags = XS_PACKED | XS_LOHANDLE;
dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
if (dwRet == DO_POST) {
UserAssert(pIntDdeInfo != NULL);
*pmessage |= MSGFLAG_DDE_MID_THUNK;
*plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxAdviseAck,
hDirect, NULL, pIntDdeInfo, flags);
if (*plParam == 0) {
dwRet = FAILNOFREE_POST;
}
}
return dwRet;
}
/*
* If its inter-process:
*
* xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_ADVISE
* is received. pIntDdeInfo is then freed. The hServer handle is saved into the
* pxs structure pointed to by lParam is a direct data structure since
* packed DDE messages are always assumed to have the packing handle freed.
*/
DWORD xxxAdviseAck( // Server response to advise - WM_DDE_ACK expected
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
PXSTATE pxsFree;
PINTDDEINFO pIntDdeInfo;
DWORD dwRet;
CheckLock(pDdeConv);
if (*pmessage != WM_DDE_ACK) {
return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
}
TRACE_DDE("xxxAdviseAck");
dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
if (dwRet != DO_POST) {
return dwRet;
}
UserAssert(pIntDdeInfo != NULL);
pxsFree = pDdeConv->spxsOut;
if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) {
/*
* positive ack implies server accepted the hOptions data - free from
* client at postmessage time.
*/
TRACE_DDE("xxxAdviseAck: +ACK delayed freeing data from client");
FreeListAdd(pDdeConv->spartnerConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED);
} else {
// Shouldn't this be freed directly?
TRACE_DDE("xxxAdviseAck: -ACK delayed freeing data from server");
FreeListAdd(pDdeConv, pxsFree->hServer, pxsFree->flags & ~XS_PACKED);
}
PopState(pDdeConv);
return DO_POST;
}
/************************************************************************
* ADVISE DATA TRANSACTION PROCESSING *
\***********************************************************************/
DWORD xxxAdviseData( // spontaneous from server - WM_DDE_DATA
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
DWORD flags, dwRet;
PINTDDEINFO pIntDdeInfo;
HANDLE hDirect;
PXSTATE pxs;
CheckLock(pDdeConv);
TRACE_DDE("xxxAdviseData");
flags = XS_PACKED | XS_LOHANDLE | XS_DATA;
dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
if (dwRet == DO_POST) {
UserAssert(pIntDdeInfo != NULL);
TRACE_DDE1("xxxAdviseData: wStatus = %x",
((PDDE_DATA)(pIntDdeInfo + 1))->wStatus);
if (!(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & (DDE_FACK | DDE_FRELEASE))) {
RIPMSG0(RIP_ERROR, "DDE protocol violation - no RELEASE or ACK bit set - setting RELEASE.");
((PDDE_DATA)(pIntDdeInfo + 1))->wStatus |= DDE_FRELEASE;
}
if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FRELEASE) {
/*
* giving it away
*/
if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) {
RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object.");
UserFreePool(pIntDdeInfo);
return FAILNOFREE_POST;
}
if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
pIntDdeInfo->hIndirect,
(W32PID)(GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid))) {
flags |= XS_GIVEBACKONNACK;
}
flags |= XS_FRELEASE;
} else {
/*
* on loan
*/
if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
pIntDdeInfo->hIndirect,
(W32PID)(GETPTI(pDdeConv->spwnd)->ppi->W32Pid))) {
flags |= XS_PUBLICOBJ;
}
}
*pmessage |= MSGFLAG_DDE_MID_THUNK;
if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FACK) {
*plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv,
xxxAdviseDataAck, NULL, hDirect, pIntDdeInfo, flags);
} else {
TRACE_DDE("xxxAdviseData: dumping non Ackable data...");
UserAssert(hDirect != (HANDLE)*plParam);
FreeDDEHandle(pDdeConv, hDirect, flags & ~XS_PACKED);
pxs = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS);
if (pxs != NULL) {
pxs->head.pti = GETPTI(pDdeConv->spwndPartner);
}
*plParam = (LPARAM)PtoH(pxs);
}
if (*plParam == 0) {
dwRet = FAILNOFREE_POST;
}
}
return dwRet;
}
/*
* If its inter-process:
*
* xxxDDETrackGetMessageHook() completes the copy from pIntDdeInfo when WM_DDE_DATA
* is received. pIntDdeInfo is then freed. The hServer handle saved into the
* pxs structure pointed to by lParam is a directdata structure since
* packed DDE messages are always assumed to have the packing handle freed
* by the receiving app.
* For the !fAckReq case, the pxs is freed due to the XS_FREEPXS flag.
*/
DWORD xxxAdviseDataAck( // Client response to advise data - WM_DDE_ACK expected
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
PXSTATE pxsFree;
PINTDDEINFO pIntDdeInfo;
DWORD dwRet;
CheckLock(pDdeConv);
/*
* This is also used for request data ack processing.
*/
if (*pmessage != WM_DDE_ACK) {
return xxxUnexpectedClientPost(pmessage, plParam, pDdeConv);
}
TRACE_DDE("xxxAdviseDataAck");
dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
if (dwRet != DO_POST) {
return dwRet;
}
UserAssert(pIntDdeInfo != NULL);
pxsFree = pDdeConv->spxsOut;
TRACE_DDE3("xxxAdviseDataAck:pxs.hClient(%#p), hServer(%#p), wStatus(%x)",
pxsFree->hClient, pxsFree->hServer, pIntDdeInfo->DdePack.uiLo);
if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) {
/*
* positive ack implies client accepted the data - free from
* server at postmessage time iff FRELEASE was set in data msg.
*/
if (pxsFree->flags & XS_FRELEASE) {
TRACE_DDE("xxxAdviseDataAck: +ACK delayed server data free");
FreeListAdd(pDdeConv->spartnerConv, pxsFree->hServer,
pxsFree->flags & ~XS_PACKED);
} else {
/*
* Ack w/out fRelease bit means client is done with data.
*/
TRACE_DDE1("xxxAdviseDataAck: Freeing %#p. (+ACK)",
pxsFree->hClient);
UserAssert(pxsFree->hClient != (HANDLE)*plParam);
FreeDDEHandle(pDdeConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED);
}
} else {
TRACE_DDE1("xxxAdviseDataAck: Freeing %#p. (-ACK)",
pxsFree->hClient);
FreeDDEHandle(pDdeConv, pxsFree->hClient, pxsFree->flags & ~XS_PACKED);
UserAssert(pxsFree->hClient != (HANDLE)*plParam);
}
PopState(pDdeConv);
return DO_POST;
}
/************************************************************************
* UNADVISE TRANSACTION PROCESSING *
\***********************************************************************/
DWORD Unadvise( // Spontaneous client transaction = WM_DDE_UNADVISE
PDDECONV pDdeConv)
{
TRACE_DDE("Unadvise");
if (AnticipatePost(pDdeConv->spartnerConv, xxxUnadviseAck, NULL, NULL, NULL, 0)) {
return DO_POST;
} else {
return FAIL_POST;
}
}
DWORD xxxUnadviseAck( // Server response to unadvise - WM_DDE_ACK expected
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
DWORD dwRet;
PINTDDEINFO pIntDdeInfo;
CheckLock(pDdeConv);
if (*pmessage != WM_DDE_ACK) {
return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
}
TRACE_DDE("xxxUnadviseAck");
dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
if (dwRet != DO_POST) {
return dwRet;
}
UserAssert(pIntDdeInfo != NULL);
PopState(pDdeConv);
return DO_POST;
}
/************************************************************************
* REQUEST TRANSACTION PROCESSING *
\***********************************************************************/
DWORD Request( // Spontaneous Client transaction - WM_DDE_REQUEST
PDDECONV pDdeConv)
{
TRACE_DDE("Request");
if (AnticipatePost(pDdeConv->spartnerConv, xxxRequestAck, NULL, NULL, NULL, 0)) {
return DO_POST;
} else {
return FAIL_POST;
}
}
DWORD xxxRequestAck( // Server response - WM_DDE_ACK or WM_DDE_DATA expected
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
PXSTATE pxsFree;
DWORD flags;
PINTDDEINFO pIntDdeInfo;
HANDLE hDirect;
DWORD dwStatus, dwRet;
CheckLock(pDdeConv);
TRACE_DDE("xxxRequestAck or xxxAdviseData");
switch (*pmessage) {
case WM_DDE_DATA:
/*
* This is very close to advise data handling - the only catch
* is that if the fRequest bit is clear this IS advise data.
*/
flags = XS_PACKED | XS_LOHANDLE | XS_DATA;
dwStatus = ClientGetDDEFlags((HANDLE)*plParam, flags);
if (!(dwStatus & DDE_FREQUESTED)) {
/*
* Its NOT a request Ack - it must be advise data
*/
return xxxAdviseData(pmessage, plParam, pDdeConv);
}
pxsFree = pDdeConv->spxsOut;
dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
if (dwRet == DO_POST) {
UserAssert(pIntDdeInfo != NULL);
if (!(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & (DDE_FACK | DDE_FRELEASE))) {
RIPMSG0(RIP_ERROR, "DDE protocol violation - no RELEASE or ACK bit set - setting RELEASE.");
((PDDE_DATA)(pIntDdeInfo + 1))->wStatus |= DDE_FRELEASE;
}
if (dwStatus & DDE_FRELEASE) {
/*
* giving it away
*/
if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) {
RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object.");
UserFreePool(pIntDdeInfo);
return FAILNOFREE_POST;
}
if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
pIntDdeInfo->hIndirect,
(W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid)) {
flags |= XS_GIVEBACKONNACK;
}
flags |= XS_FRELEASE;
} else {
/*
* on loan
*/
if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
pIntDdeInfo->hIndirect,
(W32PID)GETPTI(pDdeConv->spwnd)->ppi->W32Pid)) {
flags |= XS_PUBLICOBJ;
}
}
*pmessage |= MSGFLAG_DDE_MID_THUNK;
if (dwStatus & DDE_FACK) {
*plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv,
xxxAdviseDataAck, NULL, hDirect, pIntDdeInfo, flags);
} else {
TRACE_DDE("xxxRequestAck: Delayed freeing non-ackable request data");
FreeListAdd(pDdeConv, hDirect, flags & ~XS_PACKED);
pxsFree = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS);
if (pxsFree != NULL) {
pxsFree->head.pti = GETPTI(pDdeConv->spwndPartner);
}
*plParam = (LPARAM)PtoH(pxsFree);
}
if (*plParam != 0) {
PopState(pDdeConv);
} else {
dwRet = FAILNOFREE_POST;
}
}
return dwRet;
case WM_DDE_ACK: // server NACKs request
dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
if (dwRet != DO_POST) {
return dwRet;
}
UserAssert(pIntDdeInfo != NULL);
PopState(pDdeConv);
return DO_POST;
default:
return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
}
}
/************************************************************************
* POKE TRANSACTION PROCESSING *
\***********************************************************************/
DWORD xxxPoke( // spontaneous client transaction - WM_DDE_POKE
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
DWORD flags, dwRet;
PINTDDEINFO pIntDdeInfo;
HANDLE hDirect;
CheckLock(pDdeConv);
TRACE_DDE("xxxPoke");
flags = XS_PACKED | XS_LOHANDLE | XS_DATA;
dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
if (dwRet == DO_POST) {
UserAssert(pIntDdeInfo != NULL);
if (((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FRELEASE) {
/*
* giving it away
*/
if (IsObjectPublic(pIntDdeInfo->hIndirect) != NULL) {
RIPMSG0(RIP_ERROR, "DDE Protocol violation - giving away a public GDI object.");
UserFreePool(pIntDdeInfo);
return FAILNOFREE_POST;
}
if (GiveObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
pIntDdeInfo->hIndirect,
(W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid)) {
flags |= XS_GIVEBACKONNACK;
}
flags |= XS_FRELEASE;
} else {
/*
* on loan
*/
/*
* fAck bit is ignored and assumed on.
*/
if (AddPublicObject(((PDDE_DATA)(pIntDdeInfo + 1))->wFmt,
pIntDdeInfo->hIndirect,
(W32PID)GETPTI(pDdeConv->spwnd)->ppi->W32Pid)) {
flags |= XS_PUBLICOBJ;
}
}
*pmessage |= MSGFLAG_DDE_MID_THUNK;
*plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxPokeAck,
hDirect, NULL, pIntDdeInfo, flags);
if (*plParam == 0) {
dwRet = FAILNOFREE_POST;
}
}
return dwRet;
}
/*
* If its inter-process:
*
* xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_ADVISE
* is received. pIntDdeInfo is then freed. The hServer handle saved into the
* pxs structure pointer to by lParam is a directdata structure since
* packed DDE messages are always assumed to have the packing handle freed
* by the receiving app.
* For the !fAckReq case, the pxs is also freed due to the XS_FREEPXS flag.
*/
DWORD xxxPokeAck( // Server response to poke data - WM_DDE_ACK expected
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
PXSTATE pxsFree;
PINTDDEINFO pIntDdeInfo;
DWORD dwRet;
CheckLock(pDdeConv);
if (*pmessage != WM_DDE_ACK) {
return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
}
TRACE_DDE("xxxPokeAck");
dwRet = xxxCopyAckIn(pmessage, plParam, pDdeConv, &pIntDdeInfo);
if (dwRet != DO_POST) {
return dwRet;
}
UserAssert(pIntDdeInfo != NULL);
pxsFree = pDdeConv->spxsOut;
if (pIntDdeInfo->DdePack.uiLo & DDE_FACK) {
// positive ack implies server accepted the data - free from
// client at postmessage time iff fRelease was set in poke message.
if (pxsFree->flags & XS_FRELEASE) {
TRACE_DDE("xxxPokeAck: delayed freeing client data");
FreeListAdd(pDdeConv->spartnerConv, pxsFree->hClient,
pxsFree->flags & ~XS_PACKED);
}
} else {
// Nack means that sender is responsible for freeing it.
// We must free it in the receiver's context for him.
TRACE_DDE("xxxPokeAck: freeing Nacked data");
UserAssert(pxsFree->hServer != (HANDLE)*plParam);
FreeDDEHandle(pDdeConv, pxsFree->hServer, pxsFree->flags & ~XS_PACKED);
}
PopState(pDdeConv);
return DO_POST;
}
/************************************************************************
* EXECUTE TRANSACTION PROCESSING *
\***********************************************************************/
DWORD xxxExecute( // spontaneous client transaction - WM_DDE_EXECUTE
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
DWORD flags, dwRet;
PINTDDEINFO pIntDdeInfo;
HANDLE hDirect;
CheckLock(pDdeConv);
TRACE_DDE("xxxExecute");
flags = XS_EXECUTE;
if (!TestWF(pDdeConv->spwnd, WFANSIPROC) &&
!TestWF(pDdeConv->spwndPartner, WFANSIPROC)) {
flags |= XS_UNICODE;
}
dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, &hDirect, &pIntDdeInfo);
if (dwRet == DO_POST) {
UserAssert(pIntDdeInfo != NULL);
*pmessage |= MSGFLAG_DDE_MID_THUNK;
*plParam = (LPARAM)AnticipatePost(pDdeConv->spartnerConv, xxxExecuteAck,
hDirect, NULL, pIntDdeInfo, flags);
/*
* Check for != 0 to make sure the AnticipatePost() succeeded.
*/
if (*plParam != 0) {
/*
* In the execute case it is likely that the postee will want to activate
* itself and come on top (OLE 1.0 is an example). In this case, allow
* both the postee and the poster to foreground activate for the next
* activate (poster because it will want to activate itself again
* probably, once the postee is done.)
*/
GETPTI(pDdeConv->spwnd)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
TAGMSG1(DBGTAG_FOREGROUND, "xxxExecute set TIF %#p", GETPTI(pDdeConv->spwnd));
GETPTI(pDdeConv->spwndPartner)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
TAGMSG1(DBGTAG_FOREGROUND, "xxxExecute set TIF %#p", GETPTI(pDdeConv->spwndPartner));
} else {
dwRet = FAILNOFREE_POST;
}
}
return dwRet;
}
/*
* xxxDDETrackGetMessageHook() fills in hServer from pIntDdeInfo when WM_DDE_EXECUTE
* is received. pIntDdeInfo is then freed.
*/
DWORD xxxExecuteAck( // Server response to execute data - WM_DDE_ACK expected
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
PXSTATE pxsFree;
PINTDDEINFO pi;
DWORD flags = XS_PACKED | XS_FREESRC | XS_EXECUTE;
DWORD dwRet;
CheckLock(pDdeConv);
if (*pmessage != WM_DDE_ACK) {
return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
}
TRACE_DDE("xxxExecuteAck");
dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, NULL, &pi);
if (dwRet == DO_POST) {
UserAssert(pi != NULL);
/*
* the server must respond to the execute with an ack containing the
* same handle it was given.
*/
pi->DdePack.uiHi = (ULONG_PTR)pDdeConv->spxsOut->hClient;
pi->hDirect = NULL;
pi->cbDirect = 0;
*pmessage |= MSGFLAG_DDE_MID_THUNK;
pxsFree = Createpxs(NULL, NULL, NULL, pi, XS_PACKED | XS_FREEPXS);
if (pxsFree != NULL) {
pxsFree->head.pti = GETPTI(pDdeConv->spwndPartner);
}
*plParam = (LPARAM)PtoH(pxsFree);
if (*plParam != 0) {
PopState(pDdeConv);
} else {
dwRet = FAILNOFREE_POST;
}
}
return dwRet;
}
/************************************************************************
* TERMINATE TRANSACTION PROCESSING *
\***********************************************************************/
DWORD SpontaneousTerminate(
PDWORD pmessage,
PDDECONV pDdeConv)
{
TRACE_DDE("SpontaneousTerminate");
if (pDdeConv->flags & CXF_TERMINATE_POSTED) {
return FAKE_POST;
} else {
pDdeConv->flags |= CXF_TERMINATE_POSTED;
*pmessage |= MSGFLAG_DDE_MID_THUNK;
return DO_POST;
}
}
/*
* The xxxDDETrackGetMessageHook() function restores the *pmessage value.
* Unless a spontaneous terminate from the other app has already
* arrived, it will note that CXF_TERMINATE_POSTED is NOT set on
* both sides so no action is taken.
*/
/************************************************************************
* DUPLICATE CONVERSATION TERMINATION *
\***********************************************************************/
/*
* This routine is called when a DDE server window sent a WM_DDE_ACK
* message to a client window which is already engaged in a conversation
* with that server window. We swallow the ACK and post a terminate to
* the server window to shut this conversation down. When the server
* posts the terminate, this function is called to basically fake
* a sucessful post. Thus the client is never bothered while the
* errant server thinks the conversation was connected and then
* imediately terminated.
*/
DWORD DupConvTerminate( // WM_DDE_TERMINATE expected
PDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv)
{
CheckLock(pDdeConv);
TRACE_DDE("DupConvTerminate");
if (*pmessage != WM_DDE_TERMINATE) {
return xxxUnexpectedServerPost(pmessage, plParam, pDdeConv);
}
PopState(pDdeConv);
return FAKE_POST;
}
/************************************************************************
* HELPER ROUTINES FOR TRANSACTION TRACKING *
\***********************************************************************/
/************************************************************************
* AnticipatePost
*
* Allocates, fills and links XSTATE structures.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
HANDLE AnticipatePost(
PDDECONV pDdeConv,
FNDDERESPONSE fnResponse,
HANDLE hClient,
HANDLE hServer,
PINTDDEINFO pIntDdeInfo,
DWORD flags)
{
PXSTATE pxs;
pxs = Createpxs(fnResponse, hClient, hServer, pIntDdeInfo, flags);
if (pxs != NULL) {
pxs->head.pti = pDdeConv->head.pti;
if (pDdeConv->spxsOut == NULL) {
UserAssert(pDdeConv->spxsIn == NULL);
Lock(&(pDdeConv->spxsOut), pxs);
Lock(&(pDdeConv->spxsIn), pxs);
} else {
UserAssert(pDdeConv->spxsIn != NULL);
Lock(&(pDdeConv->spxsIn->snext), pxs);
Lock(&(pDdeConv->spxsIn), pxs);
}
#if 0
{
int i;
HANDLEENTRY *phe;
for (i = 0, phe = gSharedInfo.aheList;
i <= (int)giheLast;
i++) {
if (phe[i].bType == TYPE_DDEXACT) {
UserAssert(((PXSTATE)(phe[i].phead))->snext != pDdeConv->spxsOut);
}
if (phe[i].bType == TYPE_DDECONV &&
(PDDECONV)phe[i].phead != pDdeConv) {
UserAssert(((PDDECONV)(phe[i].phead))->spxsOut != pDdeConv->spxsOut);
UserAssert(((PDDECONV)(phe[i].phead))->spxsIn != pDdeConv->spxsOut);
}
}
}
#endif
}
return PtoH(pxs);
}
/************************************************************************
* Createpxs
*
* Allocates and fills XSTATE structures.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
PXSTATE Createpxs(
FNDDERESPONSE fnResponse,
HANDLE hClient,
HANDLE hServer,
PINTDDEINFO pIntDdeInfo,
DWORD flags)
{
PXSTATE pxs;
pxs = HMAllocObject(PtiCurrent(), NULL, TYPE_DDEXACT, sizeof(XSTATE));
if (pxs == NULL) {
#if DBG
RIPMSG0(RIP_WARNING, "Unable to alloc DDEXACT");
#endif
return NULL;
}
pxs->snext = NULL;
pxs->fnResponse = fnResponse;
pxs->hClient = hClient;
pxs->hServer = hServer;
pxs->pIntDdeInfo = pIntDdeInfo;
pxs->flags = flags;
ValidatePublicObjectList();
UserAssert(pxs->head.cLockObj == 0);
return pxs;
}
/************************************************************************
* AbnormalDDEPost
*
* This is the catch-all routine for wierd cases
*
* returns post action code - DO_POST, FAKE_POST, FAIL_POST.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
DWORD AbnormalDDEPost(
PDDECONV pDdeConv,
DWORD message)
{
#if DBG
if (message != WM_DDE_TERMINATE) {
RIPMSG2(RIP_WARNING,
"DDE Post failed (%#p:%#p) - protocol violation.",
PtoH(pDdeConv->spwnd), PtoH(pDdeConv->spwndPartner));
}
#endif // DBG
// shutdown this conversation by posting a terminate on
// behalf of this guy, then fail all future posts but
// fake a successful terminate.
if (!(pDdeConv->flags & CXF_TERMINATE_POSTED)) {
_PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE,
(WPARAM)PtoH(pDdeConv->spwnd), 0);
// pDdeConv->flags |= CXF_TERMINATE_POSTED; Set by post hook proc
}
return message == WM_DDE_TERMINATE ? FAKE_POST : FAIL_POST;
}
/************************************************************************
* NewConversation
*
* Worker function used to create a saimese pair of DDECONV structures.
*
* Returns fCreateOk
*
* History:
* 11-5-92 sanfords Created
\***********************************************************************/
BOOL NewConversation(
PDDECONV *ppdcNewClient,
PDDECONV *ppdcNewServer,
PWND pwndClient,
PWND pwndServer)
{
PDDECONV pdcNewClient;
PDDECONV pdcNewServer;
pdcNewClient = HMAllocObject(GETPTI(pwndClient), NULL,
TYPE_DDECONV, sizeof(DDECONV));
if (pdcNewClient == NULL) {
return FALSE;
}
pdcNewServer = HMAllocObject(GETPTI(pwndServer), NULL,
TYPE_DDECONV, sizeof(DDECONV));
if (pdcNewServer == NULL) {
HMFreeObject(pdcNewClient); // we know it's not locked.
return FALSE;
}
AddConvProp(pwndClient, pwndServer, 0, pdcNewClient, pdcNewServer);
AddConvProp(pwndServer, pwndClient, CXF_IS_SERVER, pdcNewServer,
pdcNewClient);
if (ppdcNewClient != NULL) {
*ppdcNewClient = pdcNewClient;
}
if (ppdcNewServer != NULL) {
*ppdcNewServer = pdcNewServer;
}
return TRUE;
}
/************************************************************************
* FindDdeConv
*
* Locates the pDdeConv associated with pwndProp, and pwndPartner.
* Only searches pwndProp's property list.
*
* History:
* 3-31-91 sanfords Created
\***********************************************************************/
PDDECONV FindDdeConv(
PWND pwndProp,
PWND pwndPartner)
{
PDDECONV pDdeConv;
pDdeConv = (PDDECONV)_GetProp(pwndProp, PROP_DDETRACK, PROPF_INTERNAL);
while (pDdeConv != NULL && pDdeConv->spwndPartner != pwndPartner) {
pDdeConv = pDdeConv->snext;
}
return pDdeConv;
}
/************************************************************************
* xxxCopyAckIn
*
* A common occurance helper function
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
DWORD xxxCopyAckIn(
LPDWORD pmessage,
LPARAM *plParam,
PDDECONV pDdeConv,
PINTDDEINFO * ppIntDdeInfo)
{
PINTDDEINFO pIntDdeInfo;
DWORD flags, dwRet;
PXSTATE pxs;
CheckLock(pDdeConv);
flags = XS_PACKED | XS_FREESRC;
dwRet = xxxCopyDdeIn((HANDLE)*plParam, &flags, NULL, ppIntDdeInfo);
if (dwRet == DO_POST) {
UserAssert(*ppIntDdeInfo != NULL);
pIntDdeInfo = *ppIntDdeInfo;
if (pDdeConv->spxsOut->flags & XS_GIVEBACKONNACK &&
!(((PDDE_DATA)(pIntDdeInfo + 1))->wStatus & DDE_FACK)) {
GiveObject(((PDDE_DATA)(pDdeConv->spxsOut->pIntDdeInfo + 1))->wFmt,
pDdeConv->spxsOut->pIntDdeInfo->hIndirect,
(W32PID)GETPTI(pDdeConv->spwndPartner)->ppi->W32Pid);
}
if (pDdeConv->spxsOut->flags & XS_PUBLICOBJ) {
RemovePublicObject(((PDDE_DATA)(pDdeConv->spxsOut->pIntDdeInfo + 1))->wFmt,
pDdeConv->spxsOut->pIntDdeInfo->hIndirect);
pDdeConv->spxsOut->flags &= ~XS_PUBLICOBJ;
}
pxs = Createpxs(NULL, NULL, NULL, pIntDdeInfo, flags | XS_FREEPXS);
if (pxs != NULL) {
pxs->head.pti = GETPTI(pDdeConv->spwndPartner);
}
*plParam = (LPARAM)PtoH(pxs);
if (*plParam == 0) {
return FAILNOFREE_POST;
}
*pmessage |= MSGFLAG_DDE_MID_THUNK;
}
return dwRet;
}
/************************************************************************
* FreeListAdd
*
* Adds a CSR Client handle to the free list associated with pDdeConv.
* This allows us to make sure stuff is freed that isn't in a context
* we have access at the time we know it must be freed.
*
* returns fSuccess
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
BOOL FreeListAdd(
PDDECONV pDdeConv,
HANDLE hClient,
DWORD flags)
{
PFREELIST pfl;
pfl = (PFREELIST)UserAllocPool(sizeof(FREELIST), TAG_DDE1);
if (!pfl) {
return FALSE;
}
TRACE_DDE2("FreeListAdd: %x for thread %x.", hClient,
GETPTIID(pDdeConv->head.pti));
pfl->h = hClient;
pfl->flags = flags;
pfl->next = pDdeConv->pfl;
pDdeConv->pfl = pfl;
return TRUE;
}
/************************************************************************
* FreeDDEHandle
*
* Frees contents DDE client side handle - delayed free if a WOW process.
*
* History:
* 7-28-94 sanfords Created
\***********************************************************************/
VOID FreeDDEHandle(
PDDECONV pDdeConv,
HANDLE hClient,
DWORD flags)
{
if (PtiCurrent()->TIF_flags & TIF_16BIT) {
TRACE_DDE1("FreeDDEHandle: (WOW hack) delayed Freeing %#p.", hClient);
FreeListAdd(pDdeConv, hClient, flags);
} else {
TRACE_DDE1("FreeDDEHandle: Freeing %#p.", hClient);
ClientFreeDDEHandle(hClient, flags);
}
}
/************************************************************************
* xxxFreeListFree
*
* Frees contents of the free list associated with pDdeConv.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
VOID FreeListFree(
PFREELIST pfl)
{
PFREELIST pflPrev;
CheckCritIn();
UserAssert(pfl != NULL);
while (pfl != NULL) {
pflPrev = pfl;
pfl = pfl->next;
UserFreePool(pflPrev);
}
}
VOID xxxFreeListFree(
PFREELIST pfl)
{
PFREELIST pflPrev;
BOOL fInCleanup;
TL tlPool;
CheckCritIn();
if (pfl == NULL) {
return;
}
fInCleanup = (PtiCurrent())->TIF_flags & TIF_INCLEANUP;
while (pfl != NULL) {
ThreadLockPoolCleanup(PtiCurrent(), pfl, &tlPool, FreeListFree);
if (!fInCleanup) {
TRACE_DDE1("Freeing %#p from free list.\n", pfl->h);
ClientFreeDDEHandle(pfl->h, pfl->flags);
}
ThreadUnlockPoolCleanup(PtiCurrent(), &tlPool);
pflPrev = pfl;
pfl = pfl->next;
UserFreePool(pflPrev);
}
}
/************************************************************************
* PopState
*
* Frees spxsOut from pDdeConv and handles empty queue case.
*
* History:
* 9-3-91 sanfords Created
\***********************************************************************/
VOID PopState(
PDDECONV pDdeConv)
{
PXSTATE pxsNext, pxsFree;
TL tlpxs;
UserAssert(pDdeConv->spxsOut != NULL);
#if 0
{
int i;
HANDLEENTRY *phe;
for (i = 0, phe = gSharedInfo.aheList;
i <= giheLast;
i++) {
if (phe[i].bType == TYPE_DDEXACT) {
UserAssert(((PXSTATE)(phe[i].phead))->snext != pDdeConv->spxsOut);
}
}
}
#endif
UserAssert(!(pDdeConv->spxsOut->flags & XS_FREEPXS));
UserAssert(pDdeConv->spxsIn != NULL);
UserAssert(pDdeConv->spxsIn->snext == NULL);
ThreadLockAlways(pDdeConv->spxsOut, &tlpxs); // hold it fast
pxsNext = pDdeConv->spxsOut->snext;
pxsFree = Lock(&(pDdeConv->spxsOut), pxsNext); // lock next into head
if (pxsNext == NULL) {
UserAssert(pDdeConv->spxsIn == pxsFree);
Unlock(&(pDdeConv->spxsIn)); // queue is empty.
} else {
Unlock(&(pxsFree->snext)); // clear next ptr
}
pxsFree = ThreadUnlock(&tlpxs); // undo our lock
if (pxsFree != NULL) {
FreeDdeXact(pxsFree); // cleanup.
}
}
VOID FreeDdeConv(
PDDECONV pDdeConv)
{
TRACE_DDE1("FreeDdeConv(%#p)", pDdeConv);
if (!(pDdeConv->flags & CXF_TERMINATE_POSTED) &&
!HMIsMarkDestroy(pDdeConv->spwndPartner)) {
_PostMessage(pDdeConv->spwndPartner, WM_DDE_TERMINATE,
(WPARAM)PtoH(pDdeConv->spwnd), 0);
// pDdeConv->flags |= CXF_TERMINATE_POSTED; set by PostHookProc
}
if (pDdeConv->spartnerConv != NULL &&
GETPTI(pDdeConv)->TIF_flags & TIF_INCLEANUP) {
/*
* Fake that the other side already posted a terminate.
* This prevents vestigal dde structures from hanging
* around after thread cleanup if the conversation structure
* is destroyed before the associated window.
*/
pDdeConv->spartnerConv->flags |= CXF_TERMINATE_POSTED;
}
UnlinkConv(pDdeConv);
if (pDdeConv->pddei != NULL) {
pDdeConv->pddei->cRefConv--;
if (pDdeConv->pddei->cRefConv == 0 && pDdeConv->pddei->cRefInit == 0) {
SeDeleteClientSecurity(&pDdeConv->pddei->ClientContext);
UserFreePool(pDdeConv->pddei);
}
pDdeConv->pddei = NULL;
}
Unlock(&(pDdeConv->spartnerConv));
Unlock(&(pDdeConv->spwndPartner));
Unlock(&(pDdeConv->spwnd));
if (!HMMarkObjectDestroy((PHEAD)pDdeConv))
return;
while (pDdeConv->spxsOut) {
PopState(pDdeConv);
}
HMFreeObject(pDdeConv);
}
/***************************************************************************\
* xxxCopyDdeIn
*
* Description:
* Copies DDE data from the CSR client to the CSR server side.
* Crosses the CSR barrier as many times as is needed to get all the data
* through the CSR window.
*
* History:
* 11-1-91 sanfords Created.
\***************************************************************************/
DWORD xxxCopyDdeIn(
HANDLE hSrc,
PDWORD pflags,
PHANDLE phDirect,
PINTDDEINFO *ppi)
{
DWORD dwRet;
PINTDDEINFO pi;
dwRet = xxxClientCopyDDEIn1(hSrc, *pflags, ppi);
pi = *ppi;
TRACE_DDE2(*pflags & XS_FREESRC ?
"Copying in and freeing %#p(%#p)" :
"Copying in %#p(%#p)",
hSrc, pi ? pi->hDirect : 0);
if (dwRet == DO_POST) {
UserAssert(*ppi != NULL);
*pflags = pi->flags;
TRACE_DDE3("xxxCopyDdeIn: uiLo=%x, uiHi=%x, hDirect=%#p",
pi->DdePack.uiLo, pi->DdePack.uiHi, pi->hDirect);
if (phDirect != NULL) {
*phDirect = pi->hDirect;
}
}
#if DBG
else {
RIPMSG0(RIP_WARNING, "Unable to alloc DDE INTDDEINFO");
}
#endif
return dwRet;
}
/***********************************************************************\
* xxxCopyDDEOut
*
* Returns: the apropriate client side handle for lParam or NULL on
* failure. (Since only TERMINATES should have 0 here)
*
* 11/7/1995 Created SanfordS
\***********************************************************************/
HANDLE xxxCopyDDEOut(
PINTDDEINFO pi,
PHANDLE phDirect) // receives the target client side GMEM handle.
{
HANDLE hDst;
TRACE_DDE3("xxxCopyDDEOut: cbDirect=%x, cbIndirect=%x, flags=%x",
pi->cbDirect, pi->cbIndirect, pi->flags);
hDst = xxxClientCopyDDEOut1(pi);
TRACE_DDE3("xxxCopyDDEOut: uiLo=%x, uiHi=%x, hResult=%#p",
pi->DdePack.uiLo, pi->DdePack.uiHi, hDst);
if (hDst != NULL) {
if (phDirect != NULL) {
TRACE_DDE1("xxxCopyDDEOut: *phDirect=%#p", pi->hDirect);
*phDirect = pi->hDirect;
}
}
return hDst;
}
/*
* This API is used to set the QOS associated with a potential DDE client window.
* It should be called prior to sending a WM_DDE_INITIATE message and the qos set
* will hold until the WM_DDE_INITIATE send or broadcast returns.
*/
BOOL _DdeSetQualityOfService(
PWND pwndClient,
CONST PSECURITY_QUALITY_OF_SERVICE pqosNew,
PSECURITY_QUALITY_OF_SERVICE pqosOld)
{
PSECURITY_QUALITY_OF_SERVICE pqosUser;
PSECURITY_QUALITY_OF_SERVICE pqosAlloc = NULL;
BOOL fRet;
/*
* ASSUME: calling process is owner of pwndClient - ensured in thunk.
*/
pqosUser = (PSECURITY_QUALITY_OF_SERVICE)InternalRemoveProp(pwndClient,
PROP_QOS, PROPF_INTERNAL);
if (pqosUser == NULL) {
if (RtlEqualMemory(pqosNew, &gqosDefault, sizeof(SECURITY_QUALITY_OF_SERVICE))) {
return TRUE; // no PROP_QOS property implies default QOS
}
pqosAlloc = (PSECURITY_QUALITY_OF_SERVICE)UserAllocPoolZInit(
sizeof(SECURITY_QUALITY_OF_SERVICE), TAG_DDE2);
if (pqosAlloc == NULL) {
return FALSE; // memory allocation failure - can't change from default
}
pqosUser = pqosAlloc;
}
*pqosOld = *pqosUser;
*pqosUser = *pqosNew;
fRet = InternalSetProp(pwndClient, PROP_QOS, pqosUser, PROPF_INTERNAL);
if ((fRet == FALSE) && (pqosAlloc != NULL)) {
UserFreePool(pqosAlloc);
}
return fRet;
}
/*
* This is a private API for NetDDE's use. It extracts the QOS associated with an
* active DDE conversation. Intra-process conversations always are set to the default
* QOS.
*/
BOOL _DdeGetQualityOfService(
PWND pwndClient,
PWND pwndServer,
PSECURITY_QUALITY_OF_SERVICE pqos)
{
PDDECONV pDdeConv;
PSECURITY_QUALITY_OF_SERVICE pqosClient;
if (pwndServer == NULL) {
/*
* Special case to support DDEML-RAW conversations that need to get
* the QOS prior to initiation completion.
*/
pqosClient = _GetProp(pwndClient, PROP_QOS, PROPF_INTERNAL);
if (pqosClient == NULL) {
*pqos = gqosDefault;
} else {
*pqos = *pqosClient;
}
return TRUE;
}
if (GETPWNDPPI(pwndClient) == GETPWNDPPI(pwndServer)) {
*pqos = gqosDefault;
return TRUE;
}
pDdeConv = FindDdeConv(pwndClient, pwndServer);
if (pDdeConv == NULL) {
return FALSE;
}
if (pDdeConv->pddei == NULL) {
return FALSE;
}
*pqos = pDdeConv->pddei->qos;
return TRUE;
}
BOOL _ImpersonateDdeClientWindow(
PWND pwndClient,
PWND pwndServer)
{
PDDECONV pDdeConv;
NTSTATUS Status;
/*
* Locate token used in the conversation
*/
pDdeConv = FindDdeConv(pwndClient, pwndServer);
if (pDdeConv == NULL || pDdeConv->pddei == NULL)
return FALSE;
/*
* Stick the token into the dde server thread
*/
Status = SeImpersonateClientEx(&pDdeConv->pddei->ClientContext,
PsGetCurrentThread());
if (!NT_SUCCESS(Status)) {
RIPNTERR0(Status, RIP_VERBOSE, "");
return FALSE;
}
return TRUE;
}
VOID FreeDdeXact(
PXSTATE pxs)
{
if (!HMMarkObjectDestroy(pxs)) {
return;
}
#if 0
{
int i;
HANDLEENTRY *phe;
for (i = 0, phe = gSharedInfo.aheList; i <= giheLast; i++) {
if (phe[i].bType == TYPE_DDEXACT) {
UserAssert(((PXSTATE)(phe[i].phead))->snext != pxs);
} else if (phe[i].bType == TYPE_DDECONV) {
UserAssert(((PDDECONV)(phe[i].phead))->spxsOut != pxs);
UserAssert(((PDDECONV)(phe[i].phead))->spxsIn != pxs);
}
}
}
UserAssert(pxs->head.cLockObj == 0);
UserAssert(pxs->snext == NULL);
#endif
if (pxs->pIntDdeInfo != NULL) {
/*
* free any server-side GDI objects
*/
if (pxs->pIntDdeInfo->flags & (XS_METAFILEPICT | XS_ENHMETAFILE)) {
GreDeleteServerMetaFile(pxs->pIntDdeInfo->hIndirect);
}
if (pxs->flags & XS_PUBLICOBJ) {
RemovePublicObject(((PDDE_DATA)(pxs->pIntDdeInfo + 1))->wFmt,
pxs->pIntDdeInfo->hIndirect);
pxs->flags &= ~XS_PUBLICOBJ;
}
UserFreePool(pxs->pIntDdeInfo);
}
HMFreeObject(pxs);
ValidatePublicObjectList();
}
PPUBOBJ IsObjectPublic(
HANDLE hObj)
{
PPUBOBJ ppo;
for (ppo = gpPublicObjectList; ppo != NULL; ppo = ppo->next) {
if (ppo->hObj == hObj) {
break;
}
}
return ppo;
}
BOOL AddPublicObject(
UINT format,
HANDLE hObj,
W32PID pid)
{
PPUBOBJ ppo;
switch (format) {
case CF_BITMAP:
case CF_DSPBITMAP:
case CF_PALETTE:
break;
default:
return FALSE;
}
ppo = IsObjectPublic(hObj);
if (ppo == NULL) {
ppo = UserAllocPool(sizeof(PUBOBJ), TAG_DDE4);
if (ppo == NULL) {
return FALSE;
}
ppo->count = 1;
ppo->hObj = hObj;
ppo->pid = pid;
ppo->next = gpPublicObjectList;
gpPublicObjectList = ppo;
GiveObject(format, hObj, OBJECT_OWNER_PUBLIC);
} else {
ppo->count++;
}
return TRUE;
}
BOOL RemovePublicObject(
UINT format,
HANDLE hObj)
{
PPUBOBJ ppo, ppoPrev;
switch (format) {
case CF_BITMAP:
case CF_DSPBITMAP:
case CF_PALETTE:
break;
default:
return FALSE;
}
for (ppoPrev = NULL, ppo = gpPublicObjectList;
ppo != NULL;
ppoPrev = ppo, ppo = ppo->next) {
if (ppo->hObj == hObj) {
break;
}
}
if (ppo == NULL) {
UserAssert(FALSE);
return FALSE;
}
ppo->count--;
if (ppo->count == 0) {
GiveObject(format, hObj, ppo->pid);
if (ppoPrev != NULL) {
ppoPrev->next = ppo->next;
} else {
gpPublicObjectList = ppo->next;
}
UserFreePool(ppo);
}
return TRUE;
}
BOOL
GiveObject(
UINT format,
HANDLE hObj,
W32PID pid)
{
switch (format) {
case CF_BITMAP:
case CF_DSPBITMAP:
GreSetBitmapOwner(hObj, pid);
return TRUE;
case CF_PALETTE:
GreSetPaletteOwner(hObj, pid);
return TRUE;
default:
return FALSE;
}
}
#if DBG
VOID ValidatePublicObjectList()
{
PPUBOBJ ppo;
int i, count;
HANDLEENTRY *phe;
for (count = 0, ppo = gpPublicObjectList;
ppo != NULL;
ppo = ppo->next) {
count += ppo->count;
}
for (i = 0, phe = gSharedInfo.aheList;
i <= (int)giheLast;
i++) {
if (phe[i].bType == TYPE_DDEXACT) {
if (((PXSTATE)(phe[i].phead))->flags & XS_PUBLICOBJ) {
UserAssert(((PXSTATE)(phe[i].phead))->pIntDdeInfo != NULL);
UserAssert(IsObjectPublic(((PXSTATE)
(phe[i].phead))->pIntDdeInfo->hIndirect) != NULL);
count--;
}
}
}
UserAssert(count == 0);
}
VOID TraceDdeMsg(
UINT msg,
HWND hwndFrom,
HWND hwndTo,
UINT code)
{
LPSTR szMsg, szType;
msg = msg & 0xFFFF;
switch (msg) {
case WM_DDE_INITIATE:
szMsg = "INITIATE";
break;
case WM_DDE_TERMINATE:
szMsg = "TERMINATE";
break;
case WM_DDE_ADVISE:
szMsg = "ADVISE";
break;
case WM_DDE_UNADVISE:
szMsg = "UNADVISE";
break;
case WM_DDE_ACK:
szMsg = "ACK";
break;
case WM_DDE_DATA:
szMsg = "DATA";
break;
case WM_DDE_REQUEST:
szMsg = "REQUEST";
break;
case WM_DDE_POKE:
szMsg = "POKE";
break;
case WM_DDE_EXECUTE:
szMsg = "EXECUTE";
break;
default:
szMsg = "BOGUS";
UserAssert(msg >= WM_DDE_FIRST && msg <= WM_DDE_LAST);
break;
}
switch (code) {
case MSG_SENT:
szType = "[sent]";
break;
case MSG_POST:
szType = "[posted]";
break;
case MSG_RECV:
szType = "[received]";
break;
case MSG_PEEK:
szType = "[peeked]";
break;
default:
szType = "[bogus]";
UserAssert(FALSE);
break;
}
RIPMSG4(RIP_VERBOSE,
"%#p->%#p WM_DDE_%s %s",
hwndFrom, hwndTo, szMsg, szType);
}
#endif //DBG