/***************************************************************************\ * DdeDisconnect (DDEML API) * * Description: * Terminates a conversation. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ BOOL DdeDisconnect( HCONV hConv) { BOOL fRet = FALSE; PCONV_INFO pcoi; PCL_INSTANCE_INFO pcii; CheckDDECritOut; EnterDDECrit; pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_CLIENT_CONVERSATION, HINST_ANY); if (pcoi == NULL) { pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_SERVER_CONVERSATION, HINST_ANY); } if (pcoi == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } pcii = PciiFromHandle((HANDLE)hConv); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } if (pcoi->state & ST_CONNECTED) { ShutdownConversation(pcoi, FALSE); } fRet = TRUE; Exit: LeaveDDECrit; return (fRet); }
/***************************************************************************\ * DdeImpersonateClient() * * Description: * Does security impersonation for DDEML server apps. * This API should only be called with server side hConvs; * * History: * 5-4-92 sanfords Created. \***************************************************************************/ BOOL DdeImpersonateClient( HCONV hConv) { PCONV_INFO pcoi; PCL_INSTANCE_INFO pcii; BOOL fRet = FALSE; EnterDDECrit; pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_SERVER_CONVERSATION, HINST_ANY); if (pcoi == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } pcii = PciiFromHandle((HANDLE)hConv); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } fRet = NtUserImpersonateDdeClientWindow(pcoi->hwndPartner, pcoi->hwndConv); Exit: LeaveDDECrit; return (fRet); }
/***************************************************************************\ * ValidateInstance * * Description: * Verifies the current validity of an instance handle - which is a server * side handle that also references a client side data structure (pcii). * * History: * 11-19-91 sanfords Created. \***************************************************************************/ PCL_INSTANCE_INFO ValidateInstance( HANDLE hInstClient) { PCL_INSTANCE_INFO pcii; pcii = (PCL_INSTANCE_INFO)ValidateCHandle(hInstClient, HTYPE_INSTANCE, HINST_ANY); if (pcii != NULL) { if (pcii->tid != GetCurrentThreadId() || pcii->hInstClient != hInstClient) { return (NULL); } } return (pcii); }
/***************************************************************************\ * DdeDisconnectList (DDEML API) * * Description: * Terminates all conversations in a conversation list and frees the list. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ BOOL DdeDisconnectList( HCONVLIST hConvList) { BOOL fRet = FALSE; PCL_INSTANCE_INFO pcii; PCONVLIST pcl; PCONV_INFO pcoi, pcoiNext; int i; CheckDDECritOut; EnterDDECrit; pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList, HTYPE_CONVERSATION_LIST, HINST_ANY); if (pcl == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } ValidateConvList(hConvList); pcii = PciiFromHandle((HANDLE)hConvList); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } for(i = pcl->chwnd - 1; i >= 0; i--) { pcoi = (PCONV_INFO)GetWindowLong(pcl->ahwnd[i], GWL_PCI); while (pcoi != NULL && pcoi->state & ST_CONNECTED) { pcoiNext = pcoi->next; ShutdownConversation(pcoi, FALSE); // may unlink pcoi! pcoi = pcoiNext; } } DestroyHandle((HANDLE)hConvList); DDEMLFree(pcl); fRet = TRUE; Exit: LeaveDDECrit; return (fRet); }
BOOL WaitForZombieTerminate( HANDLE hData) { PCONV_INFO pcoi; MSG msg; HWND hwnd; BOOL fTerminated; DWORD fRet = 0; CheckDDECritOut; EnterDDECrit; fTerminated = FALSE; while ((pcoi = (PCONV_INFO)ValidateCHandle(hData, HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(hData))) != NULL && !(pcoi->state & ST_TERMINATE_RECEIVED)) { hwnd = pcoi->hwndConv; LeaveDDECrit; while (PeekMessage(&msg, hwnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) { DispatchMessage(&msg); if (msg.message == WM_DDE_TERMINATE) { fTerminated = TRUE; } } if (!fTerminated) { fRet = MsgWaitForMultipleObjectsEx(0, NULL, 100, QS_POSTMESSAGE, 0); if (fRet == 0xFFFFFFFF) { RIPMSG0(RIP_WARNING, "WaitForZombieTerminate: I give up - faking terminate."); ProcessTerminateMsg(pcoi, pcoi->hwndPartner); EnterDDECrit; return(FALSE); } } EnterDDECrit; } LeaveDDECrit; return(TRUE); }
/***************************************************************************\ * DdeEnableCallback (DDEML API) * * Description: * Turns on and off asynchronous callbacks (BLOCKABLE). * * History: * 11-12-91 sanfords Created. \***************************************************************************/ BOOL DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd) { BOOL fRet = FALSE; PCL_INSTANCE_INFO pcii; PCONV_INFO pcoi; ENABLE_ENUM_STRUCT ees; EnterDDECrit; pcii = (PCL_INSTANCE_INFO)ValidateInstance((HANDLE)idInst); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } switch (wCmd) { case EC_QUERYWAITING: case EC_DISABLE: case EC_ENABLEONE: case EC_ENABLEALL: break; default: SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; } if (hConv) { pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_CLIENT_CONVERSATION, InstFromHandle(idInst)); if (pcoi == NULL) { pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_SERVER_CONVERSATION, InstFromHandle(idInst)); } if (pcoi == NULL) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; } pcoi->cLocks++; fRet = SetEnableState(pcoi, wCmd); switch (wCmd) { case EC_ENABLEALL: case EC_ENABLEONE: CheckForQueuedMessages(pcoi); } pcoi->cLocks--; if (pcoi->cLocks == 0 && pcoi->state & ST_FREE_CONV_RES_NOW) { FreeConversationResources(pcoi); } } else { if (wCmd == EC_ENABLEONE) { wCmd = EC_ENABLEONEOFALL; } switch (wCmd) { case EC_ENABLEONEOFALL: pcii->ConvStartupState = ST_BLOCKNEXT | ST_BLOCKALLNEXT; break; case EC_DISABLE: pcii->ConvStartupState = ST_BLOCKED; break; case EC_ENABLEALL: pcii->ConvStartupState = 0; break; } ees.pfRet = &fRet; ees.wCmd = wCmd; switch (wCmd) { case EC_ENABLEALL: ees.wCmd2 = EC_CHECKQUEUE; break; case EC_ENABLEONEOFALL: ees.wCmd2 = EC_CHECKQUEUEONCE; break; default: ees.wCmd2 = 0; } EnumChildWindows(pcii->hwndMother, (WNDENUMPROC)EnableEnumProc, (LONG)&ees); } Exit: LeaveDDECrit; return (fRet); }
/***************************************************************************\ * DdeQueryNextServer (DDEML API) * * Description: * Enumerates conversations within a list. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ HCONV DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev) { HCONV hConvRet = 0; PCONVLIST pcl; HWND *phwnd; int i; PCL_CONV_INFO pci; PCL_INSTANCE_INFO pcii; EnterDDECrit; pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList, HTYPE_CONVERSATION_LIST, HINST_ANY); if (pcl == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } if (!pcl->chwnd) { // empty list goto Exit; } pcii = PciiFromHandle((HANDLE)hConvList); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } pcii->LastError = DMLERR_NO_ERROR; do { hConvRet = 0; if (hConvPrev == 0) { pci = (PCL_CONV_INFO)GetWindowLong(pcl->ahwnd[0], GWL_PCI); if (pci == NULL) { goto Exit; // Must have all conversations zombied. } hConvPrev = hConvRet = pci->ci.hConv; continue; } pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConvPrev, HTYPE_CLIENT_CONVERSATION, InstFromHandle(hConvList)); if (pci == NULL) { pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConvPrev, HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(hConvList)); if (pci == NULL) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); break; } else { goto ZombieSkip; } } if (pci->hConvList != hConvList) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); break; } ZombieSkip: if (pci->ci.next == NULL) { /* * end of list for this window, go to next window */ for (phwnd = pcl->ahwnd, i = 0; (i + 1) < pcl->chwnd; i++) { if (phwnd[i] == pci->ci.hwndConv) { pci = (PCL_CONV_INFO)GetWindowLong(phwnd[i + 1], GWL_PCI); if (pci == NULL) { break; } hConvPrev = hConvRet = pci->ci.hConv; break; } } } else { hConvPrev = hConvRet = pci->ci.next->hConv; // next conv for this window. } } while (hConvRet && TypeFromHandle(hConvRet) == HTYPE_ZOMBIE_CONVERSATION); Exit: LeaveDDECrit; return (hConvRet); }
/***************************************************************************\ * InitiateEnumerationProc (FILE LOCAL) * * Description: * Function used via EnumWindows to enumerate all server window candidates * during DDE initiation. The enumeration allows DDEML to know what * window WM_DDE_INITIATE was sent to so that it can be remembered for * possible reconnection later. (The window that receives the WM_DDE_INITIATE * message is not necessarily going to be the server window.) * * History: * 11-1-91 sanfords Created. \***************************************************************************/ BOOL InitiateEnumerationProc( HWND hwndTarget, PINIT_ENUM pie) { PCL_CONV_INFO pci; CheckDDECritOut; if (hwndTarget == pie->hwndSkip) { return (TRUE); } if (pie->hConvList && pie->laTopic && pie->laServiceRequested) { /* * Head off duplicates BEFORE we send the WM_DDE_INITIATE messages! */ PCONVLIST pcl; PCONV_INFO pcoiExisting; int i; EnterDDECrit; /* * We revalidate hConvList here because we left the critical section. */ pcl = (PCONVLIST)ValidateCHandle((HANDLE)pie->hConvList, HTYPE_CONVERSATION_LIST, HINST_ANY); if (pcl != NULL) { for (i = 0; i < pcl->chwnd; i++) { for (pcoiExisting = (PCONV_INFO)GetWindowLong(pcl->ahwnd[i], GWL_PCI); pcoiExisting != NULL; pcoiExisting = pcoiExisting->next) { if (pcoiExisting->state & ST_CONNECTED && ((PCL_CONV_INFO)pcoiExisting)->hwndReconnect == hwndTarget && pcoiExisting->laTopic == pie->laTopic && pcoiExisting->laService == pie->laServiceRequested) { LeaveDDECrit; return(TRUE); } } } } LeaveDDECrit; } CheckDDECritOut; SendMessage(hwndTarget, WM_DDE_INITIATE, (DWORD)pie->hwndClient, pie->lParam); EnterDDECrit; // // During the initiate process, any acks received cause more pci's // to become linked together under the same hwndClient. Once // the SendMessage() returns, we set the parts of the new pci's // that hold initiate context information. // pci = (PCL_CONV_INFO)GetWindowLong(pie->hwndClient, GWL_PCI); if (pci == NULL) { LeaveDDECrit; return (TRUE); } while (pci != NULL) { if (pci->hwndReconnect == 0) { // this one needs updating pci->hwndReconnect = hwndTarget; if (pie->laServiceRequested) { pci->ci.laServiceRequested = pie->laServiceRequested; IncLocalAtomCount(pie->laServiceRequested); // pci copy } } if (pie->clst == CLST_SINGLE_INITIALIZING) { break; } pci = (PCL_CONV_INFO)pci->ci.next; } LeaveDDECrit; return (pie->clst == CLST_MULT_INITIALIZING); }
/***************************************************************************\ * ValidateConnectParameters * * Description: * worker function to handle common validation code. * * Note that paNormalSvcName is set to the atom value created upon extracting * a normal HSZ from an InstanceSpecific HSZ. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ BOOL ValidateConnectParameters( HANDLE hInst, PCL_INSTANCE_INFO *ppcii, // set if valid hInst HSZ *phszService, // altered if InstSpecific HSZ HSZ hszTopic, LATOM *plaNormalSvcName, // set to atom that needs freeing when done PCONVCONTEXT *ppCC, // set to point to DefConvContext if NULL HWND *phwndTarget, // set if hszService is InstSpecific HCONVLIST hConvList) { DWORD hszType; BOOL fError = FALSE; *ppcii = ValidateInstance(hInst); if (*ppcii == NULL) { return (FALSE); } hszType = ValidateHSZ(*phszService); if (hszType == HSZT_INVALID || ValidateHSZ(hszTopic) == HSZT_INVALID) { SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER); return (FALSE); } if (hszType == HSZT_INST_SPECIFIC) { *phwndTarget = ParseInstSpecificAtom(LATOM_FROM_HSZ(*phszService), plaNormalSvcName); if (*plaNormalSvcName == 0) { SetLastDDEMLError(*ppcii, DMLERR_SYS_ERROR); return (FALSE); } *phszService = NORMAL_HSZ_FROM_LATOM(*plaNormalSvcName); } if (*ppCC == NULL) { *ppCC = &DefConvContext; if ((*ppcii)->flags & IIF_UNICODE) { (*ppCC)->iCodePage = CP_WINUNICODE; } else { (*ppCC)->iCodePage = CP_WINANSI; } } else try { if ((*ppCC)->cb > sizeof(CONVCONTEXT)) { SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER); fError = TRUE; } else if ((*ppCC)->cb < sizeof(CONVCONTEXT)) { TempConvContext = DefConvContext; /* * we can use this static temp because we are synchronized. */ RtlCopyMemory(&TempConvContext, *ppCC, (*ppCC)->cb); *ppCC = &TempConvContext; } } except(EXCEPTION_EXECUTE_HANDLER) { SetLastDDEMLError(*ppcii, DMLERR_INVALIDPARAMETER); fError = TRUE; } if (fError) { return(FALSE); } if (hConvList != 0 && !ValidateCHandle((HANDLE)hConvList, HTYPE_CONVERSATION_LIST, (DWORD)InstFromHandle((*ppcii)->hInstClient))) { return (FALSE); } return (TRUE); }
/***************************************************************************\ * DdeReconnect (DDEML API) * * Description: * Attempts to reconnect an externally (from the server) terminated * client side conversation. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ HCONV DdeReconnect( HCONV hConv) { PCL_INSTANCE_INFO pcii; PCL_CONV_INFO pci, pciNew; HCONV hConvRet = 0; CONVCONTEXT cc; EnterDDECrit; pcii = PciiFromHandle((HANDLE)hConv); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_CLIENT_CONVERSATION, HINST_ANY); if (pci == NULL) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; } if (pci->ci.state & ST_CONNECTED) { goto Exit; } GetConvContext(pci->ci.hwndConv, (LONG *)&cc); pciNew = ConnectConv(pcii, pci->ci.laService, pci->ci.laTopic, pci->hwndReconnect, 0, &cc, 0, CLST_SINGLE_INITIALIZING); if (pciNew == NULL) { SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED); goto Exit; } else { hConvRet = pciNew->ci.hConv; if (pci->ci.cLinks) { PXACT_INFO pxi; int iLink; PADVISE_LINK paLink; /* * reestablish advise links */ for (paLink = pci->ci.aLinks, iLink = pci->ci.cLinks; iLink; paLink++, iLink--) { pxi = (PXACT_INFO)DDEMLAlloc(sizeof(XACT_INFO)); if (pxi == NULL) { break; // abort relinking } pxi->pcoi = (PCONV_INFO)pciNew; pxi->gaItem = LocalToGlobalAtom(paLink->laItem); // pxi copy pxi->wFmt = paLink->wFmt; pxi->wType = (WORD)((paLink->wType >> 12) | XTYP_ADVSTART); if (ClStartAdvise(pxi)) { pxi->flags |= XIF_ABANDONED; } else { GlobalDeleteAtom(pxi->gaItem); DDEMLFree(pxi); } } } }
BOOL ValidateConvList( HCONVLIST hConvList) { PCONVLIST pcl; PCL_CONV_INFO pci; PXACT_INFO pxi; int i; BOOL fMatch; if (hConvList == 0) { return(TRUE); } pcl = (PCONVLIST)ValidateCHandle((HANDLE)hConvList, HTYPE_CONVERSATION_LIST, HINST_ANY); for (i = 0; i < pcl->chwnd; i++) { /* * all windows in the list are valid */ if (!IsWindow(pcl->ahwnd[i])) { DebugBreak(); } pci = (PCL_CONV_INFO)GetWindowLong(pcl->ahwnd[i], GWL_PCI); /* * All windows have at least one convinfo associated with them. */ if (pci == NULL) { DebugBreak(); } fMatch = FALSE; while (pci != NULL) { /* * All non-zombie conversations have hConvList set correctly. */ if (pci->hConvList != hConvList && TypeFromHandle(pci->ci.hConv) != HTYPE_ZOMBIE_CONVERSATION) { DebugBreak(); } /* * All conversations have hConvList clear or set correctly. */ if (pci->hConvList != 0 && pci->hConvList != hConvList) { DebugBreak(); } /* * At least 1 of the conversations references the list */ if (pci->hConvList == hConvList) { fMatch = TRUE; } for (pxi = pci->ci.pxiOut; pxi; pxi = pxi->next) { if ((PCL_CONV_INFO)pxi->pcoi != pci) { DebugBreak(); } } pci = (PCL_CONV_INFO)pci->ci.next; } if (!fMatch) { /* * At least 1 of the conversations references the list */ DebugBreak; } } return(TRUE); }