/***************************************************************************\ * DdeKeepStringHandle (DDEML API) * * Description: * Increments the use count of an HSZ. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ BOOL DdeKeepStringHandle( DWORD idInst, HSZ hsz) { PCL_INSTANCE_INFO pcii; BOOL fRet = FALSE; EnterDDECrit; pcii = ValidateInstance((HANDLE)LongToHandle( idInst )); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } if (ValidateHSZ(hsz) == HSZT_INVALID) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; } if (LATOM_FROM_HSZ(hsz) == 0) { fRet = TRUE; goto Exit; } MONHSZ(pcii, hsz, MH_KEEP); fRet = IncLocalAtomCount(LATOM_FROM_HSZ(hsz)) ? TRUE : FALSE; Exit: LeaveDDECrit; return (fRet); }
/***************************************************************************\ * DdeNameService (DDEML API) * * Description: * Registers, and Unregisters service names and sets the Initiate filter * state for an instance. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ HDDEDATA DdeNameService( DWORD idInst, HSZ hsz1, // service name HSZ hsz2, // reserved for future enhancements UINT afCmd) // DNS_ flags. { BOOL fRet = TRUE; LATOM *plaNameService; PCL_INSTANCE_INFO pcii; EnterDDECrit; pcii = ValidateInstance((HANDLE)LongToHandle( idInst )); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); fRet = FALSE; goto Exit; } if ((hsz1 && ValidateHSZ(hsz1) == HSZT_INVALID) || hsz2 != 0) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); fRet = FALSE; goto Exit; } if (afCmd & DNS_FILTERON && !(pcii->afCmd & APPCMD_FILTERINITS)) { pcii->afCmd |= APPCMD_FILTERINITS; NtUserUpdateInstance(pcii->hInstServer, &pcii->MonitorFlags, pcii->afCmd); } if (afCmd & DNS_FILTEROFF && (pcii->afCmd & APPCMD_FILTERINITS)) { pcii->afCmd &= ~APPCMD_FILTERINITS; NtUserUpdateInstance(pcii->hInstServer, &pcii->MonitorFlags, pcii->afCmd); } if (afCmd & (DNS_REGISTER | DNS_UNREGISTER)) { GATOM ga; if (pcii->afCmd & APPCMD_CLIENTONLY) { SetLastDDEMLError(pcii, DMLERR_DLL_USAGE); fRet = FALSE; goto Exit; } if (hsz1 == 0) { if (afCmd & DNS_REGISTER) { /* * registering NULL is not allowed! */ SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); fRet = FALSE; goto Exit; } /* * unregistering NULL is just like unregistering each * registered name. * * 10/19/90 - made this a synchronous event so that hsz * can be freed by calling app after this call completes * without us having to keep a copy around forever. */ plaNameService = pcii->plaNameService; while (*plaNameService != 0) { ga = LocalToGlobalAtom(*plaNameService); DeleteAtom(*plaNameService); LeaveDDECrit; RegisterService(FALSE, ga, pcii->hwndMother); EnterDDECrit; GlobalDeleteAtom(ga); plaNameService++; } pcii->cNameServiceAlloc = 1; *pcii->plaNameService = 0; goto Exit; } if (afCmd & DNS_REGISTER) { plaNameService = (LATOM *)DDEMLReAlloc(pcii->plaNameService, sizeof(LATOM) * ++pcii->cNameServiceAlloc); if (plaNameService == NULL) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); pcii->cNameServiceAlloc--; fRet = FALSE; goto Exit; } else { pcii->plaNameService = plaNameService; } IncLocalAtomCount(LATOM_FROM_HSZ(hsz1)); // NameService copy plaNameService[pcii->cNameServiceAlloc - 2] = LATOM_FROM_HSZ(hsz1); plaNameService[pcii->cNameServiceAlloc - 1] = 0; } else { // DNS_UNREGISTER plaNameService = pcii->plaNameService; while (*plaNameService != 0 && *plaNameService != LATOM_FROM_HSZ(hsz1)) { plaNameService++; } if (*plaNameService == 0) { goto Exit; // not found just exit } // // fill empty slot with last entry and fill last entry with 0 // pcii->cNameServiceAlloc--; *plaNameService = pcii->plaNameService[pcii->cNameServiceAlloc - 1]; pcii->plaNameService[pcii->cNameServiceAlloc - 1] = 0; } ga = LocalToGlobalAtom(LATOM_FROM_HSZ(hsz1)); LeaveDDECrit; RegisterService((afCmd & DNS_REGISTER) ? TRUE : FALSE, ga, pcii->hwndMother); EnterDDECrit; GlobalDeleteAtom(ga); } Exit: LeaveDDECrit; return ((HDDEDATA)IntToPtr( fRet )); }
/***************************************************************************\ * 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); }
/***************************************************************************\ * ConnectConv * * Description: * Work function for all Connect cases. * * Method: * * To reduce the number of windows we use and to simplify how client * windows handle multiple WM_DDE_ACK messages during initiation, a * single client window can handle many conversations, each with * a different server window. * * The client window is created and set to a initiation state via the * GWL_CONVSTATE window word. Initiates are then sent to enumerated server * window candidates. * The GWL_CONVSTATE value is used by the DDEML mother windows * to determine if only one or several ACKs are desired to minimize * unnessary message traffic. * * The client window GWL_CONVCONTEXT? window words are also used by * Event Windows to pass context information. * * Note that all client and server windows are children of the mother * window. This reduces the number of top level windows that * WM_DDE_INITIATES need to hit. * * Each WM_DDE_ACK that is received by a client window while in the * initiation state causes it to create a CL_CONV_INFO structure, * partially initialize it, and link it into its list of CL_CONV_INFO * structures. The head of the list is pointed to by the GWL_PCI * client window word. * * After each WM_DDE_INITIALIZE is sent, the GWL_PCI value is checked * to see if it exists and needs initialization to be completed. If * this is the case the init code knows that at least one ACK was * received in response to the WM_DDE_INITIALIZE send. The * initialization of each CL_CONV_INFO struct that needs it is then completed. * * Once the broadcasting of WM_DDE_INITIALIZE is done, the init code * then sets the GWL_CONVSTATE value in the client window to indicate that * initialization is complete. * * Returns: * The head pci to the client window or NULL if no connections made it. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ PCL_CONV_INFO ConnectConv( PCL_INSTANCE_INFO pcii, LATOM laService, LATOM laTopic, HWND hwndTarget, // 0 implies broadcast HWND hwndSkip, // 0 implies no skips - avoids self-connections. PCONVCONTEXT pCC, HCONVLIST hConvList, DWORD clst) { INIT_ENUM ie; PCL_CONV_INFO pci; PCONV_INFO pcoi; GATOM gaService, gaTopic; CheckDDECritIn; if (hwndTarget && hwndTarget == hwndSkip) { return(NULL); } LeaveDDECrit; CheckDDECritOut; if (pcii->flags & IIF_UNICODE) { ie.hwndClient = CreateWindowW((LPWSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTW]), L"", WS_CHILD, 0, 0, 0, 0, pcii->hwndMother, (HMENU)0, (HANDLE)0, (LPVOID)NULL); } else { ie.hwndClient = CreateWindowA((LPSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTA]), "", WS_CHILD, 0, 0, 0, 0, pcii->hwndMother, (HMENU)0, (HANDLE)0, (LPVOID)NULL); } EnterDDECrit; if (ie.hwndClient == 0) { return (NULL); } if (pCC != NULL) { if (!NtUserDdeSetQualityOfService(ie.hwndClient, &(pCC->qos), NULL)) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); goto Error; } } /* * Note that a pci will be created and allocated for each ACK recieved. */ SetConvContext(ie.hwndClient, (LONG *)pCC); SetWindowLong(ie.hwndClient, GWL_CONVSTATE, clst); SetWindowLong(ie.hwndClient, GWL_SHINST, (LONG)pcii->hInstServer); SetWindowLong(ie.hwndClient, GWL_CHINST, (LONG)pcii->hInstClient); gaService = LocalToGlobalAtom(laService); gaTopic = LocalToGlobalAtom(laTopic); ie.lParam = MAKELONG(gaService, gaTopic); if (!hwndTarget) { ie.hwndSkip = hwndSkip; ie.laServiceRequested = laService; ie.laTopic = laTopic; ie.hConvList = hConvList; ie.clst = clst; } LeaveDDECrit; if (hwndTarget) { SendMessage(hwndTarget, WM_DDE_INITIATE, (DWORD)ie.hwndClient, ie.lParam); } else { /* * Send this message to the nddeagnt app first so it can start * the netdde services BEFORE we do an enumeration of windows. * This lets things work the first time. NetDDEAgent caches * service status so this is the fastest way to do this. */ HWND hwndAgent = FindWindowW(SZ_NDDEAGNT_CLASS, SZ_NDDEAGNT_TITLE); if (hwndAgent) { SendMessage(hwndAgent, WM_DDE_INITIATE, (WPARAM)ie.hwndClient, ie.lParam); } EnumWindows((WNDENUMPROC)InitiateEnumerationProc, (LONG)&ie); } EnterDDECrit; /* * hConvList may have been destroyed during the enumeration but we are * done with it now so no need to revalidate. */ #ifdef DEBUG { WCHAR sz[10]; if (gaService && GlobalGetAtomName(gaService, sz, 10) == 0) { RIPMSG1(RIP_ERROR, "Bad Service Atom after Initiate phase: %lX", (DWORD)gaService); } if (gaTopic && GlobalGetAtomName(gaTopic, sz, 10) == 0) { RIPMSG1(RIP_ERROR, "Bad Topic Atom after Initiate phase: %lX", (DWORD)gaTopic); } } #endif // DEBUG GlobalDeleteAtom(gaService); GlobalDeleteAtom(gaTopic); // // Get the first pci allocated when a WM_DDE_ACK was recieved. // pci = (PCL_CONV_INFO)GetWindowLong(ie.hwndClient, GWL_PCI); if (pci == NULL) { Error: LeaveDDECrit; NtUserDestroyWindow(ie.hwndClient); EnterDDECrit; return (NULL); } SetWindowLong(ie.hwndClient, GWL_CONVSTATE, CLST_CONNECTED); if (hwndTarget) { /* * If hwndTarget was NULL, the enumeration proc took care of this. */ pci->hwndReconnect = hwndTarget; UserAssert(pci->ci.next == NULL); pci->ci.laServiceRequested = laService; IncLocalAtomCount(laService); // pci copy } if (pcii->MonitorFlags & MF_CONV) { for (pcoi = (PCONV_INFO)pci; pcoi; pcoi = pcoi->next) { MONCONV(pcoi, TRUE); } } return (pci); }