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.
852 lines
26 KiB
852 lines
26 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: ddemlwp.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* DDE Manager client side window procedures
|
|
*
|
|
* Created: 11/3/91 Sanford Staab
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
VOID ProcessDDEMLInitiate(PCL_INSTANCE_INFO pcii, HWND hwndClient,
|
|
GATOM aServer, GATOM aTopic);
|
|
|
|
/***************************************************************************\
|
|
* DDEMLMotherWndProc
|
|
*
|
|
* Description:
|
|
* Handles WM_DDE_INITIATE messages for DDEML and holds all the other windows
|
|
* for a DDEML instance.
|
|
*
|
|
* History:
|
|
* 12-29-92 sanfords Created.
|
|
\***************************************************************************/
|
|
LRESULT DDEMLMotherWndProc(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
switch (message) {
|
|
case UM_REGISTER:
|
|
case UM_UNREGISTER:
|
|
return(ProcessRegistrationMessage(hwnd, message, wParam, lParam));
|
|
|
|
case WM_DDE_INITIATE:
|
|
ProcessDDEMLInitiate((PCL_INSTANCE_INFO)GetWindowLongPtr(hwnd, GWLP_PCI),
|
|
(HWND)wParam, (ATOM)LOWORD(lParam), (ATOM)HIWORD(lParam));
|
|
return(0);
|
|
|
|
}
|
|
return(DefWindowProc(hwnd, message, wParam, lParam));
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* ProcessDDEMLInitiate
|
|
*
|
|
* Description:
|
|
*
|
|
* WM_DDE_INITIATE messages are processed here.
|
|
*
|
|
* History:
|
|
* 12-29-92 sanfords Created.
|
|
\***************************************************************************/
|
|
VOID ProcessDDEMLInitiate(
|
|
PCL_INSTANCE_INFO pcii,
|
|
HWND hwndClient,
|
|
GATOM aServer,
|
|
GATOM aTopic)
|
|
{
|
|
CONVCONTEXT cc = {
|
|
sizeof(CONVCONTEXT),
|
|
0,
|
|
0,
|
|
CP_WINANSI,
|
|
0L,
|
|
0L,
|
|
{
|
|
sizeof(SECURITY_QUALITY_OF_SERVICE),
|
|
SecurityImpersonation,
|
|
SECURITY_STATIC_TRACKING,
|
|
TRUE
|
|
}
|
|
};
|
|
BOOL flags = ST_INLIST;
|
|
BOOL fWild;
|
|
HDDEDATA hData;
|
|
HWND hwndServer;
|
|
PSERVER_LOOKUP psl;
|
|
PHSZPAIR php;
|
|
HSZPAIR hp[2];
|
|
LATOM laService, laFree1 = 0;
|
|
LATOM laTopic, laFree2 = 0;
|
|
PSVR_CONV_INFO psi;
|
|
LATOM *plaNameService;
|
|
PWND pwndClient;
|
|
PCLS pcls;
|
|
|
|
if (pcii == NULL) {
|
|
return; // we aren't done being initiated yet.
|
|
}
|
|
|
|
EnterDDECrit;
|
|
|
|
if (pcii->afCmd & CBF_FAIL_CONNECTIONS || !IsWindow(hwndClient)) {
|
|
goto Exit;
|
|
}
|
|
|
|
pwndClient = ValidateHwnd(hwndClient);
|
|
if (pwndClient == NULL) goto Exit;
|
|
|
|
pcls = (PCLS)REBASEALWAYS(pwndClient, pcls);
|
|
if (!TestWF(pwndClient, WFANSIPROC)) {
|
|
if (pcls->atomClassName == gpsi->atomSysClass[ICLS_DDEMLCLIENTW]) {
|
|
flags |= ST_ISLOCAL;
|
|
}
|
|
} else {
|
|
if (pcls->atomClassName == gpsi->atomSysClass[ICLS_DDEMLCLIENTA]) {
|
|
flags |= ST_ISLOCAL;
|
|
}
|
|
}
|
|
|
|
if (flags & ST_ISLOCAL) {
|
|
/*
|
|
* Make sure other guy allows self-connections if that's what this is.
|
|
*/
|
|
if (pcii->hInstServer == (HANDLE)GetWindowLongPtr(hwndClient, GWLP_SHINST)) {
|
|
if (pcii->afCmd & CBF_FAIL_SELFCONNECTIONS) {
|
|
goto Exit;
|
|
}
|
|
flags |= ST_ISSELF;
|
|
}
|
|
|
|
GetConvContext(hwndClient, (LONG *)&cc);
|
|
if (GetWindowLong(hwndClient, GWL_CONVSTATE) & CLST_SINGLE_INITIALIZING) {
|
|
flags &= ~ST_INLIST;
|
|
}
|
|
} else {
|
|
NtUserDdeGetQualityOfService(hwndClient, NULL, &cc.qos);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* Server window creation is minimized by only creating one window per
|
|
* Instance/Service/Topic set. This should be all that is needed and
|
|
* duplicate connections (ie where the server/client window pair is identical
|
|
* to another conversation) should not happen. However, if some dumb
|
|
* server app attempts to create a duplicate conversation by having
|
|
* duplicate service/topic pairs passed back from a XTYP_WILD_CONNECT
|
|
* callback we will not honor the request.
|
|
*
|
|
* The INSTANCE_INFO structure holds a pointer to an array of SERVERLOOKUP
|
|
* structures each entry of which references the hwndServer that supports
|
|
* all conversations on that service/topic pair. The hwndServer windows
|
|
* in turn have window words that reference the first member in a linked
|
|
* list of SVR_CONV_INFO structures, one for each conversation on that
|
|
* service/topic pair.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
laFree1 = laService = GlobalToLocalAtom(aServer);
|
|
laFree2 = laTopic = GlobalToLocalAtom(aTopic);
|
|
|
|
plaNameService = pcii->plaNameService;
|
|
if (!laService && pcii->afCmd & APPCMD_FILTERINITS && *plaNameService == 0) {
|
|
/*
|
|
* no WILDCONNECTS to servers with no registered names while filtering.
|
|
*/
|
|
goto Exit;
|
|
}
|
|
if ((pcii->afCmd & APPCMD_FILTERINITS) && laService) {
|
|
/*
|
|
* if we can't find the aServer in this instance's service name
|
|
* list, don't bother the server.
|
|
*/
|
|
while (*plaNameService != 0 && *plaNameService != laService) {
|
|
plaNameService++;
|
|
}
|
|
if (*plaNameService == 0) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
hp[0].hszSvc = NORMAL_HSZ_FROM_LATOM(laService);
|
|
hp[0].hszTopic = NORMAL_HSZ_FROM_LATOM(laTopic);
|
|
hp[1].hszSvc = 0;
|
|
hp[1].hszTopic = 0;
|
|
fWild = !laService || !laTopic;
|
|
|
|
hData = DoCallback(pcii,
|
|
(WORD)(fWild ? XTYP_WILDCONNECT : XTYP_CONNECT),
|
|
0,
|
|
(HCONV)0,
|
|
hp[0].hszTopic,
|
|
hp[0].hszSvc,
|
|
(HDDEDATA)0,
|
|
flags & ST_ISLOCAL ? (ULONG_PTR)&cc : 0,
|
|
(DWORD)(flags & ST_ISSELF) ? 1 : 0);
|
|
|
|
if (!hData) {
|
|
goto Exit;
|
|
}
|
|
|
|
if (fWild) {
|
|
php = (PHSZPAIR)DdeAccessData(hData, NULL);
|
|
if (php == NULL) {
|
|
goto Exit;
|
|
}
|
|
} else {
|
|
php = hp;
|
|
}
|
|
|
|
while (php->hszSvc && php->hszTopic) {
|
|
|
|
psi = (PSVR_CONV_INFO)DDEMLAlloc(sizeof(SVR_CONV_INFO));
|
|
if (psi == NULL) {
|
|
break;
|
|
}
|
|
|
|
laService = LATOM_FROM_HSZ(php->hszSvc);
|
|
laTopic = LATOM_FROM_HSZ(php->hszTopic);
|
|
|
|
hwndServer = 0;
|
|
if (pcii->cServerLookupAlloc) {
|
|
int i;
|
|
/*
|
|
* See if there already exists a server window for this
|
|
* aServer/aTopic pair
|
|
*/
|
|
for (i = pcii->cServerLookupAlloc; i; i--) {
|
|
if (pcii->aServerLookup[i - 1].laService == laService &&
|
|
pcii->aServerLookup[i - 1].laTopic == laTopic) {
|
|
PSVR_CONV_INFO psiT;
|
|
PCONV_INFO pcoi;
|
|
|
|
hwndServer = pcii->aServerLookup[i - 1].hwndServer;
|
|
/*
|
|
* Now make sure this window isn't someone
|
|
* trying to create a second conversation from the
|
|
* same client window that is already talking to
|
|
* our existing server window.
|
|
*/
|
|
psiT = (PSVR_CONV_INFO)GetWindowLongPtr(hwndServer, GWLP_PSI);
|
|
for (pcoi = &psiT->ci; pcoi != NULL; pcoi = pcoi->next) {
|
|
if (pcoi->hwndPartner == hwndClient) {
|
|
hwndServer = NULL;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hwndServer == 0) {
|
|
|
|
// no server window exists - make one.
|
|
|
|
LeaveDDECrit;
|
|
if (pcii->flags & IIF_UNICODE) {
|
|
hwndServer = CreateWindowW((LPWSTR)(gpsi->atomSysClass[ICLS_DDEMLSERVERW]),
|
|
L"",
|
|
WS_CHILD,
|
|
0, 0, 0, 0,
|
|
pcii->hwndMother,
|
|
(HMENU)0,
|
|
0,
|
|
(LPVOID)NULL);
|
|
} else {
|
|
hwndServer = CreateWindowA((LPSTR)(gpsi->atomSysClass[ICLS_DDEMLSERVERA]),
|
|
"",
|
|
WS_CHILD,
|
|
0, 0, 0, 0,
|
|
pcii->hwndMother,
|
|
(HMENU)0,
|
|
0,
|
|
(LPVOID)NULL);
|
|
}
|
|
EnterDDECrit;
|
|
|
|
if (hwndServer == 0) {
|
|
DDEMLFree(psi);
|
|
break;
|
|
}
|
|
// SetWindowLongPtr(hwndServer, GWLP_PSI, (LONG)NULL); // Zero init.
|
|
|
|
// put the window into the lookup list
|
|
|
|
if (pcii->aServerLookup == NULL) {
|
|
psl = (PSERVER_LOOKUP)DDEMLAlloc(sizeof(SERVER_LOOKUP));
|
|
} else {
|
|
psl = (PSERVER_LOOKUP)DDEMLReAlloc(pcii->aServerLookup,
|
|
sizeof(SERVER_LOOKUP) * (pcii->cServerLookupAlloc + 1));
|
|
}
|
|
if (psl == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ProcessDDEMLInitiate:hwndServer (%x) destroyed due to low memory.", hwndServer);
|
|
NtUserDestroyWindow(hwndServer);
|
|
DDEMLFree(psi);
|
|
break;
|
|
}
|
|
|
|
IncLocalAtomCount(laService); // for SERVER_LOOKUP
|
|
psl[pcii->cServerLookupAlloc].laService = laService;
|
|
IncLocalAtomCount(laTopic); // for SERVER_LOOKUP
|
|
psl[pcii->cServerLookupAlloc].laTopic = laTopic;
|
|
psl[pcii->cServerLookupAlloc].hwndServer = hwndServer;
|
|
pcii->aServerLookup = psl;
|
|
pcii->cServerLookupAlloc++;
|
|
// DumpServerLookupTable("After addition:", hwndServer, psl, pcii->cServerLookupAlloc);
|
|
}
|
|
|
|
psi->ci.next = (PCONV_INFO)GetWindowLongPtr(hwndServer, GWLP_PSI);
|
|
SetWindowLongPtr(hwndServer, GWLP_PSI, (LONG_PTR)psi);
|
|
psi->ci.pcii = pcii;
|
|
// psi->ci.hUser = 0;
|
|
psi->ci.hConv = (HCONV)CreateHandle((ULONG_PTR)psi,
|
|
HTYPE_SERVER_CONVERSATION, InstFromHandle(pcii->hInstClient));
|
|
psi->ci.laService = laService;
|
|
IncLocalAtomCount(laService); // for server window
|
|
psi->ci.laTopic = laTopic;
|
|
IncLocalAtomCount(laTopic); // for server window
|
|
psi->ci.hwndPartner = hwndClient;
|
|
psi->ci.hwndConv = hwndServer;
|
|
psi->ci.state = (WORD)(flags | ST_CONNECTED | pcii->ConvStartupState);
|
|
SetCommonStateFlags(hwndClient, hwndServer, &psi->ci.state);
|
|
psi->ci.laServiceRequested = laFree1;
|
|
IncLocalAtomCount(psi->ci.laServiceRequested); // for server window
|
|
// psi->ci.pxiIn = NULL;
|
|
// psi->ci.pxiOut = NULL;
|
|
// psi->ci.dmqIn = NULL;
|
|
// psi->ci.dmqOut = NULL;
|
|
// psi->ci.aLinks = NULL;
|
|
// psi->ci.cLinks = 0;
|
|
// psi->ci.cLocks = 0;
|
|
|
|
LeaveDDECrit;
|
|
CheckDDECritOut;
|
|
SendMessage(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
|
|
MAKELONG(LocalToGlobalAtom(laService), LocalToGlobalAtom(laTopic)));
|
|
EnterDDECrit;
|
|
|
|
if (!(pcii->afCmd & CBF_SKIP_CONNECT_CONFIRMS)) {
|
|
DoCallback(pcii,
|
|
(WORD)XTYP_CONNECT_CONFIRM,
|
|
0,
|
|
psi->ci.hConv,
|
|
(HSZ)laTopic,
|
|
(HSZ)laService,
|
|
(HDDEDATA)0,
|
|
0,
|
|
(flags & ST_ISSELF) ? 1L : 0L);
|
|
}
|
|
|
|
MONCONV((PCONV_INFO)psi, TRUE);
|
|
|
|
if (!(flags & ST_INLIST)) {
|
|
break; // our partner's only gonna take the first one anyway.
|
|
}
|
|
php++;
|
|
}
|
|
|
|
if (fWild) {
|
|
DdeUnaccessData(hData);
|
|
InternalFreeDataHandle(hData, FALSE);
|
|
}
|
|
|
|
Exit:
|
|
DeleteAtom(laFree1);
|
|
DeleteAtom(laFree2);
|
|
LeaveDDECrit;
|
|
return;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* DDEMLClientWndProc
|
|
*
|
|
* Description:
|
|
* Handles DDE client messages for DDEML.
|
|
*
|
|
* History:
|
|
* 11-12-91 sanfords Created.
|
|
\***************************************************************************/
|
|
LRESULT DDEMLClientWndProc(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PCL_CONV_INFO pci, pciNew;
|
|
LONG lState;
|
|
LRESULT lRet = 0;
|
|
PWND pwnd;
|
|
PCLS pcls;
|
|
|
|
EnterDDECrit;
|
|
|
|
pci = (PCL_CONV_INFO)GetWindowLongPtr(hwnd, GWLP_PCI);
|
|
UserAssert(pci == NULL || pci->ci.hwndConv == hwnd);
|
|
|
|
switch (message) {
|
|
case WM_DDE_ACK:
|
|
lState = GetWindowLong(hwnd, GWL_CONVSTATE);
|
|
if (lState != CLST_CONNECTED) {
|
|
|
|
// Initiation mode
|
|
|
|
pciNew = (PCL_CONV_INFO)DDEMLAlloc(sizeof(CL_CONV_INFO));
|
|
if (pciNew == NULL ||
|
|
(pci != NULL && lState == CLST_SINGLE_INITIALIZING)) {
|
|
PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0);
|
|
goto Exit;
|
|
}
|
|
|
|
// PCL_CONV_INFO initialization
|
|
|
|
pciNew->ci.pcii = ValidateInstance((HANDLE)GetWindowLongPtr(hwnd, GWLP_CHINST));
|
|
|
|
if (pciNew->ci.pcii == NULL) {
|
|
DDEMLFree(pciNew);
|
|
goto Exit;
|
|
}
|
|
|
|
pciNew->ci.next = (PCONV_INFO)pci; // pci may be NULL
|
|
//
|
|
// Seting GWLP_PCI gives feedback to ConnectConv() which issued
|
|
// the WM_DDE_INITIATE message.
|
|
//
|
|
SetWindowLongPtr(hwnd, GWLP_PCI, (LONG_PTR)pciNew);
|
|
// pciNew->hUser = 0; // Zero init.
|
|
|
|
// BUG: If this fails we can have some nasty problems
|
|
pciNew->ci.hConv = (HCONV)CreateHandle((ULONG_PTR)pciNew,
|
|
HTYPE_CLIENT_CONVERSATION, InstFromHandle(pciNew->ci.pcii->hInstClient));
|
|
|
|
pciNew->ci.laService = GlobalToLocalAtom(LOWORD(lParam)); // pci copy
|
|
GlobalDeleteAtom(LOWORD(lParam));
|
|
pciNew->ci.laTopic = GlobalToLocalAtom(HIWORD(lParam)); // pci copy
|
|
GlobalDeleteAtom(HIWORD(lParam));
|
|
pciNew->ci.hwndPartner = (HWND)wParam;
|
|
pciNew->ci.hwndConv = hwnd;
|
|
pciNew->ci.state = (WORD)(ST_CONNECTED | ST_CLIENT |
|
|
pciNew->ci.pcii->ConvStartupState);
|
|
SetCommonStateFlags(hwnd, (HWND)wParam, &pciNew->ci.state);
|
|
|
|
pwnd = ValidateHwnd((HWND)wParam);
|
|
|
|
if (pwnd == NULL) goto Exit;
|
|
pcls = (PCLS)REBASEALWAYS(pwnd, pcls);
|
|
|
|
if (!TestWF(pwnd, WFANSIPROC)) {
|
|
if (pcls->atomClassName == gpsi->atomSysClass[ICLS_DDEMLSERVERW]) {
|
|
pciNew->ci.state |= ST_ISLOCAL;
|
|
}
|
|
} else {
|
|
if (pcls->atomClassName == gpsi->atomSysClass[ICLS_DDEMLSERVERA]) {
|
|
pciNew->ci.state |= ST_ISLOCAL;
|
|
}
|
|
}
|
|
|
|
// pciNew->ci.laServiceRequested = 0; // Set by InitiateEnumerationProc()
|
|
// pciNew->ci.pxiIn = 0;
|
|
// pciNew->ci.pxiOut = 0;
|
|
// pciNew->ci.dmqIn = 0;
|
|
// pciNew->ci.dmqOut = 0;
|
|
// pciNew->ci.aLinks = NULL;
|
|
// pciNew->ci.cLinks = 0;
|
|
// pciNew->ci.cLocks = 0;
|
|
goto Exit;
|
|
}
|
|
// fall through to handle posted messages here.
|
|
|
|
case WM_DDE_DATA:
|
|
ProcessAsyncDDEMsg((PCONV_INFO)pci, message, (HWND)wParam, lParam);
|
|
goto Exit;
|
|
|
|
case WM_DDE_TERMINATE:
|
|
case WM_DESTROY:
|
|
{
|
|
ProcessTerminateMsg((PCONV_INFO)pci, (HWND)wParam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
lRet = DefWindowProc(hwnd, message, wParam, lParam);
|
|
|
|
Exit:
|
|
LeaveDDECrit;
|
|
return (lRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* DDEMLServerWndProc
|
|
*
|
|
* Description:
|
|
* Handles DDE server messages.
|
|
*
|
|
* History:
|
|
* 11-12-91 sanfords Created.
|
|
\***************************************************************************/
|
|
LRESULT DDEMLServerWndProc(
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PSVR_CONV_INFO psi;
|
|
LRESULT lRet = 0;
|
|
|
|
EnterDDECrit;
|
|
|
|
psi = (PSVR_CONV_INFO)GetWindowLongPtr(hwnd, GWLP_PSI);
|
|
UserAssert(psi == NULL || psi->ci.hwndConv == hwnd);
|
|
|
|
switch (message) {
|
|
case WM_DDE_REQUEST:
|
|
case WM_DDE_POKE:
|
|
case WM_DDE_ADVISE:
|
|
case WM_DDE_EXECUTE:
|
|
case WM_DDE_ACK:
|
|
case WM_DDE_UNADVISE:
|
|
ProcessAsyncDDEMsg((PCONV_INFO)psi, message, (HWND)wParam, lParam);
|
|
goto Exit;
|
|
|
|
case WM_DDE_TERMINATE:
|
|
case WM_DESTROY:
|
|
ProcessTerminateMsg((PCONV_INFO)psi, (HWND)wParam);
|
|
break;
|
|
}
|
|
lRet = DefWindowProc(hwnd, message, wParam, lParam);
|
|
Exit:
|
|
LeaveDDECrit;
|
|
return (lRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* ProcessTerminateMsg
|
|
*
|
|
* Description:
|
|
* Handles WM_DDE_TERMINATE messages for both sides.
|
|
*
|
|
* History:
|
|
* 11-26-91 sanfords Created.
|
|
\***************************************************************************/
|
|
PCONV_INFO ProcessTerminateMsg(
|
|
PCONV_INFO pcoi,
|
|
HWND hwndFrom)
|
|
{
|
|
while (pcoi != NULL && pcoi->hwndPartner != hwndFrom) {
|
|
pcoi = pcoi->next;
|
|
}
|
|
if (pcoi != NULL) {
|
|
pcoi->state |= ST_TERMINATE_RECEIVED;
|
|
ShutdownConversation(pcoi, TRUE);
|
|
}
|
|
return (pcoi);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* ProcessAsyncDDEMsg
|
|
*
|
|
* Description:
|
|
* Handles incoming DDE messages by either calling ProcessSyncDDEMessage()
|
|
* if the conversation is able to handle callbacks, or by queuing the
|
|
* incoming message into the conversations message queue. Doing this
|
|
* allows simpler code in that no message is processed unless the code
|
|
* can perform synchronous callbacks.
|
|
*
|
|
* History:
|
|
* 11-26-91 sanfords Created.
|
|
\***************************************************************************/
|
|
VOID ProcessAsyncDDEMsg(
|
|
PCONV_INFO pcoi,
|
|
UINT msg,
|
|
HWND hwndFrom,
|
|
LPARAM lParam)
|
|
{
|
|
PDDE_MESSAGE_QUEUE pdmq;
|
|
#if DBG
|
|
HWND hwndT = pcoi->hwndConv;
|
|
#endif // DBG
|
|
|
|
while (pcoi != NULL && pcoi->hwndPartner != hwndFrom) {
|
|
pcoi = pcoi->next;
|
|
}
|
|
if (pcoi == NULL) {
|
|
RIPMSG3(RIP_WARNING,
|
|
"Bogus DDE message %x received from %x by %x. Dumping.",
|
|
msg, hwndFrom, hwndT);
|
|
DumpDDEMessage(FALSE, msg, lParam);
|
|
return ;
|
|
}
|
|
if (pcoi->state & ST_CONNECTED) {
|
|
|
|
if (pcoi->dmqOut == NULL &&
|
|
!(pcoi->state & ST_BLOCKED)
|
|
// && !PctiCurrent()->cInDDEMLCallback
|
|
) {
|
|
|
|
if (ProcessSyncDDEMessage(pcoi, msg, lParam)) {
|
|
return; // not blocked, ok to return.
|
|
}
|
|
}
|
|
|
|
// enter into queue
|
|
|
|
pdmq = DDEMLAlloc(sizeof(DDE_MESSAGE_QUEUE));
|
|
if (pdmq == NULL) {
|
|
|
|
// insufficient memory - we can't process this msg - we MUST
|
|
// terminate.
|
|
|
|
if (pcoi->state & ST_CONNECTED) {
|
|
PostMessage(pcoi->hwndPartner, WM_DDE_TERMINATE,
|
|
(WPARAM)pcoi->hwndConv, 0);
|
|
pcoi->state &= ~ST_CONNECTED;
|
|
}
|
|
DumpDDEMessage(!(pcoi->state & ST_INTRA_PROCESS), msg, lParam);
|
|
return ;
|
|
}
|
|
pdmq->pcoi = pcoi;
|
|
pdmq->msg = msg;
|
|
pdmq->lParam = lParam;
|
|
pdmq->next = NULL;
|
|
|
|
// dmqOut->next->next->next->dmqIn->NULL
|
|
|
|
if (pcoi->dmqIn != NULL) {
|
|
pcoi->dmqIn->next = pdmq;
|
|
}
|
|
pcoi->dmqIn = pdmq;
|
|
if (pcoi->dmqOut == NULL) {
|
|
pcoi->dmqOut = pcoi->dmqIn;
|
|
}
|
|
pcoi->cLocks++;
|
|
CheckForQueuedMessages(pcoi);
|
|
pcoi->cLocks--;
|
|
if (pcoi->cLocks == 0 && pcoi->state & ST_FREE_CONV_RES_NOW) {
|
|
FreeConversationResources(pcoi);
|
|
}
|
|
} else {
|
|
DumpDDEMessage(!(pcoi->state & ST_INTRA_PROCESS), msg, lParam);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* CheckForQueuedMessages
|
|
*
|
|
* Description:
|
|
* Handles processing of DDE messages held in the given conversaion's
|
|
* DDE message queue.
|
|
*
|
|
* Returns: fProcessed.
|
|
*
|
|
* History:
|
|
* 11-12-91 sanfords Created.
|
|
\***************************************************************************/
|
|
BOOL CheckForQueuedMessages(
|
|
PCONV_INFO pcoi)
|
|
{
|
|
PDDE_MESSAGE_QUEUE pdmq;
|
|
BOOL fRet = FALSE;
|
|
PCLIENTINFO pci;
|
|
|
|
CheckDDECritIn;
|
|
|
|
if (pcoi->state & ST_PROCESSING) { // recursion prevention
|
|
return(FALSE);
|
|
}
|
|
|
|
UserAssert(pcoi->cLocks);
|
|
|
|
pci = GetClientInfo();
|
|
|
|
pcoi->state |= ST_PROCESSING;
|
|
while (!(pcoi->state & ST_BLOCKED) &&
|
|
pcoi->dmqOut != NULL &&
|
|
!pci->cInDDEMLCallback) {
|
|
pci->CI_flags |= CI_PROCESSING_QUEUE;
|
|
if (ProcessSyncDDEMessage(pcoi, pcoi->dmqOut->msg, pcoi->dmqOut->lParam)) {
|
|
fRet = TRUE;
|
|
pdmq = pcoi->dmqOut;
|
|
pcoi->dmqOut = pcoi->dmqOut->next;
|
|
if (pcoi->dmqOut == NULL) {
|
|
pcoi->dmqIn = NULL;
|
|
}
|
|
DDEMLFree(pdmq);
|
|
}
|
|
pci->CI_flags &= ~CI_PROCESSING_QUEUE;
|
|
}
|
|
pcoi->state &= ~ST_PROCESSING;
|
|
return(fRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* DumpDDEMessage
|
|
*
|
|
* Description:
|
|
* Used to clean up resources referenced by DDE messages that for some
|
|
* reason could not be processed.
|
|
*
|
|
* History:
|
|
* 11-12-91 sanfords Created.
|
|
\***************************************************************************/
|
|
VOID DumpDDEMessage(
|
|
BOOL fFreeData,
|
|
UINT msg,
|
|
LPARAM lParam)
|
|
{
|
|
UINT_PTR uiLo, uiHi;
|
|
|
|
RIPMSG2(RIP_WARNING, "Dump DDE msg %x lParam %x", msg, lParam);
|
|
|
|
switch (msg) {
|
|
case WM_DDE_ACK:
|
|
case WM_DDE_DATA:
|
|
case WM_DDE_POKE:
|
|
case WM_DDE_ADVISE:
|
|
UnpackDDElParam(msg, lParam, &uiLo, &uiHi);
|
|
switch (msg) {
|
|
case WM_DDE_DATA:
|
|
case WM_DDE_POKE:
|
|
if (uiLo) {
|
|
if (fFreeData) {
|
|
FreeDDEData((HANDLE)uiLo, FALSE, TRUE);
|
|
}
|
|
GlobalDeleteAtom((ATOM)uiHi);
|
|
}
|
|
break;
|
|
|
|
case WM_DDE_ADVISE:
|
|
if (uiLo) {
|
|
if (fFreeData) {
|
|
FreeDDEData((HANDLE)uiLo, FALSE, TRUE);
|
|
}
|
|
GlobalDeleteAtom((ATOM)uiHi);
|
|
}
|
|
break;
|
|
|
|
case WM_DDE_ACK:
|
|
// could be EXEC Ack - cant know what to do exactly.
|
|
break;
|
|
}
|
|
FreeDDElParam(msg, lParam);
|
|
break;
|
|
|
|
case WM_DDE_EXECUTE:
|
|
if (fFreeData) {
|
|
WOWGLOBALFREE((HANDLE)lParam);
|
|
}
|
|
break;
|
|
|
|
case WM_DDE_REQUEST:
|
|
case WM_DDE_UNADVISE:
|
|
GlobalDeleteAtom((ATOM)HIWORD(lParam));
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* ProcessSyncDDEMessage
|
|
*
|
|
* Description:
|
|
* Handles processing of a received DDE message. TRUE is returned if
|
|
* the message was handled. FALSE implies CBR_BLOCK.
|
|
*
|
|
* History:
|
|
* 11-19-91 sanfords Created.
|
|
\***************************************************************************/
|
|
BOOL ProcessSyncDDEMessage(
|
|
PCONV_INFO pcoi,
|
|
UINT msg,
|
|
LPARAM lParam)
|
|
{
|
|
BOOL fNotBlocked = TRUE;
|
|
PCL_INSTANCE_INFO pcii;
|
|
ENABLE_ENUM_STRUCT ees;
|
|
BOOL fRet;
|
|
|
|
CheckDDECritIn;
|
|
|
|
/*
|
|
* lock the conversation so its resources don't go away till we are
|
|
* done with them. This function could generate a callback which could
|
|
* disconnect the conversation.
|
|
*/
|
|
pcoi->cLocks++;
|
|
|
|
if (pcoi->state & ST_BLOCKNEXT) {
|
|
pcoi->state ^= ST_BLOCKNEXT | ST_BLOCKED;
|
|
}
|
|
if (pcoi->state & ST_BLOCKALLNEXT) {
|
|
ees.pfRet = &fRet;
|
|
ees.wCmd = EC_DISABLE;
|
|
ees.wCmd2 = 0;
|
|
EnumChildWindows(pcoi->pcii->hwndMother, (WNDENUMPROC)EnableEnumProc,
|
|
(LPARAM)&ees);
|
|
}
|
|
|
|
if (pcoi->state & ST_CONNECTED) {
|
|
if (pcoi->pxiOut == NULL) {
|
|
if (pcoi->state & ST_CLIENT) {
|
|
fNotBlocked = SpontaneousClientMessage((PCL_CONV_INFO)pcoi, msg, lParam);
|
|
} else {
|
|
fNotBlocked = SpontaneousServerMessage((PSVR_CONV_INFO)pcoi, msg, lParam);
|
|
}
|
|
} else {
|
|
UserAssert(pcoi->pxiOut->hXact == (HANDLE)0 ||
|
|
ValidateCHandle(pcoi->pxiOut->hXact, HTYPE_TRANSACTION,
|
|
HINST_ANY)
|
|
== (ULONG_PTR)pcoi->pxiOut);
|
|
fNotBlocked = (pcoi->pxiOut->pfnResponse)(pcoi->pxiOut, msg, lParam);
|
|
}
|
|
} else {
|
|
DumpDDEMessage(!(pcoi->state & ST_INTRA_PROCESS), msg, lParam);
|
|
}
|
|
if (!fNotBlocked) {
|
|
pcoi->state |= ST_BLOCKED;
|
|
pcoi->state &= ~ST_BLOCKNEXT;
|
|
}
|
|
|
|
pcii = pcoi->pcii; // save this incase unlocking makes pcoi go away.
|
|
|
|
pcoi->cLocks--;
|
|
if (pcoi->cLocks == 0 && pcoi->state & ST_FREE_CONV_RES_NOW) {
|
|
FreeConversationResources(pcoi);
|
|
}
|
|
|
|
/*
|
|
* Because callbacks are capable of blocking DdeUninitialize(), we check
|
|
* before exit to see if it needs to be called.
|
|
*/
|
|
if (pcii->afCmd & APPCMD_UNINIT_ASAP &&
|
|
!(pcii->flags & IIF_IN_SYNC_XACT) &&
|
|
!pcii->cInDDEMLCallback) {
|
|
DdeUninitialize(HandleToUlong(pcii->hInstClient));
|
|
return(FALSE);
|
|
}
|
|
return (fNotBlocked);
|
|
}
|