Example #1
0
/***************************************************************************\
* 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);
}
Example #2
0
UINT InternalDdeInitialize(
LPDWORD pidInst,
PFNCALLBACK pfnCallback,
DWORD afCmd,
BOOL fUnicode)
{
    UINT uiRet = DMLERR_MEMORY_ERROR;
    register PCL_INSTANCE_INFO pcii;

    if (afCmd & APPCLASS_MONITOR) {
        afCmd |= CBF_MONMASK;
    }

    if (afCmd & APPCMD_CLIENTONLY) {
        afCmd |= CBF_FAIL_CONNECTIONS;
    }

    EnterDDECrit;

    if (*pidInst != 0) {
        pcii = ValidateInstance((HANDLE)LongToHandle( *pidInst ));
        if (pcii == NULL) {
            uiRet = DMLERR_INVALIDPARAMETER;
            goto Exit;
        }

        // only allow certain bits to be changed on reinitialize call

        pcii->afCmd = (pcii->afCmd & ~(CBF_MASK | MF_MASK)) |
                (afCmd & (CBF_MASK | MF_MASK));

        LeaveDDECrit;
        NtUserUpdateInstance(pcii->hInstServer, &pcii->MonitorFlags, afCmd);
        return (DMLERR_NO_ERROR);
    }

    pcii = (PCL_INSTANCE_INFO)DDEMLAlloc(sizeof(CL_INSTANCE_INFO));
    if (pcii == NULL) {
        uiRet = DMLERR_MEMORY_ERROR;
        goto Exit;
    }

    pcii->plaNameService = (LATOM *)DDEMLAlloc(sizeof(LATOM));
    if (pcii->plaNameService == NULL) {
        uiRet = DMLERR_MEMORY_ERROR;
        goto Backout3;
    }
    // *pcii->plaNameService = 0; // zero init takes care of this
    pcii->cNameServiceAlloc = 1;


    /*
     * Flag this window as being create from a diff hmod as the app so
     * hotkeys don't take it as the first window created in the app and
     * assign it as the hotkey.
     */
    pcii->hwndMother =  _CreateWindowEx(0, (LPTSTR)(gpsi->atomSysClass[ICLS_DDEMLMOTHER]), L"",
            WS_POPUP, 0, 0, 0, 0, (HWND)0,
            (HMENU)0, 0, (LPVOID)NULL, CW_FLAGS_DIFFHMOD);

    if (pcii->hwndMother == 0) {
        uiRet = DMLERR_SYS_ERROR;
        goto Backout2;
    }
    SetWindowLongPtr(pcii->hwndMother, GWLP_INSTANCE_INFO, (LONG_PTR)pcii);

    pcii->afCmd = afCmd | APPCMD_FILTERINITS;
    pcii->pfnCallback = pfnCallback;
    // pcii->LastError = DMLERR_NO_ERROR; // zero init
    pcii->tid = GetCurrentThreadId();
    // pcii->aServerLookup = NULL;          // zero init
    // pcii->cServerLookupAlloc = 0;        // zero init
    // pcii->ConvStartupState = 0;          // zero init - Not blocked.
    // pcii->flags = 0;                     // zero init
    // pcii->cInDDEMLCallback = 0;          // zero init
    // pcii->pLinkCounts = NULL;            // zero init

    // Do this last when the client side is ready for whatever events
    // flying around may come charging in.

    LeaveDDECrit;
    uiRet = NtUserDdeInitialize(&pcii->hInstServer,
                            &pcii->hwndEvent,
                            &pcii->MonitorFlags,
                            pcii->afCmd,
                            pcii);
    EnterDDECrit;

    if (uiRet != DMLERR_NO_ERROR) {
Backout:
        NtUserDestroyWindow(pcii->hwndMother);
Backout2:
        DDEMLFree(pcii->plaNameService);
Backout3:
        DDEMLFree(pcii);
        goto Exit;
    }
    pcii->hInstClient = AddInstance(pcii->hInstServer);
    *pidInst = HandleToUlong(pcii->hInstClient);
    if (pcii->hInstClient == 0) {
        LeaveDDECrit;
        NtUserCallOneParam((ULONG_PTR)pcii->hInstServer, SFI__CSDDEUNINITIALIZE);
        EnterDDECrit;
        uiRet = DMLERR_MEMORY_ERROR;
        goto Backout;
    }
    SetHandleData(pcii->hInstClient, (ULONG_PTR)pcii);

    pcii->next = pciiList;
    pciiList = pcii;
    if (fUnicode) {
        pcii->flags |= IIF_UNICODE;
    }
    uiRet = DMLERR_NO_ERROR;

Exit:
    LeaveDDECrit;
    return (uiRet);
}
Example #3
0
/***************************************************************************\
* DdeUninitialize (DDEML API)
*
* Description:
* Shuts down a DDEML instance and frees all associated resources.
*
* History:
* 11-12-91 sanfords Created.
\***************************************************************************/
BOOL DdeUninitialize(
DWORD idInst)
{
    PCL_INSTANCE_INFO pcii, pciiPrev;
    BOOL fRet = FALSE;

    CheckDDECritOut;
    EnterDDECrit;

    pcii = ValidateInstance((HANDLE)LongToHandle( idInst ));
    if (pcii == NULL) {
        BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
        goto Exit;
    }

    /*
     * If this thread is in the middle of a synchronous transaction or
     * a callback, we need to back out of those first.
     */
    if ((pcii->flags & IIF_IN_SYNC_XACT) || pcii->cInDDEMLCallback) {
        pcii->afCmd |= APPCMD_UNINIT_ASAP;
        fRet = TRUE;
        goto Exit;
    }

    ApplyFunctionToObjects(HTYPE_CONVERSATION_LIST, InstFromHandle(pcii->hInstClient),
            (PFNHANDLEAPPLY)DdeDisconnectList);
    ApplyFunctionToObjects(HTYPE_CLIENT_CONVERSATION, InstFromHandle(pcii->hInstClient),
            (PFNHANDLEAPPLY)DdeDisconnect);
    ApplyFunctionToObjects(HTYPE_SERVER_CONVERSATION, InstFromHandle(pcii->hInstClient),
            (PFNHANDLEAPPLY)DdeDisconnect);
    ApplyFunctionToObjects(HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(pcii->hInstClient),
            (PFNHANDLEAPPLY)WaitForZombieTerminate);
    ApplyFunctionToObjects(HTYPE_DATA_HANDLE, InstFromHandle(pcii->hInstClient),
            (PFNHANDLEAPPLY)ApplyFreeDataHandle);

    LeaveDDECrit;
    NtUserCallOneParam((ULONG_PTR)pcii->hInstServer, SFI__CSDDEUNINITIALIZE);
    NtUserDestroyWindow(pcii->hwndMother);
    EnterDDECrit;

    DDEMLFree(pcii->plaNameService);
    DestroyInstance(pcii->hInstClient);

    // unlink pcii from pciiList

    if (pciiList == pcii) {
        pciiList = pciiList->next;
    } else {
        for (pciiPrev = pciiList; pciiPrev != NULL && pciiPrev->next != pcii;
                pciiPrev = pciiPrev->next) {
            ;
        }
        if (pciiPrev != NULL) {
            pciiPrev->next = pcii->next;
        }
    }
    DDEMLFree(pcii);
    fRet = TRUE;

Exit:
    LeaveDDECrit;
    return (fRet);
}
Example #4
0
/***************************************************************************\
* DoCallback
*
* Description:
* Performs a synchronous callback to the given instance's callback proc.
*
* History:
* 11-12-91 sanfords Created.
\***************************************************************************/
HDDEDATA DoCallback(
PCL_INSTANCE_INFO pcii,
WORD wType,
WORD wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hData,
DWORD dw1,
DWORD dw2)
{
    HDDEDATA hDataRet;
    PCLIENTINFO pci;

    CheckDDECritIn;


    /*
     * Zombie conversations don't generate callbacks!
     */
    if (hConv && TypeFromHandle(hConv) == HTYPE_ZOMBIE_CONVERSATION) {
        return(0);
    }

    pci = GetClientInfo();
    pci->cInDDEMLCallback++;

    pcii->cInDDEMLCallback++;
    pci->hDdemlCallbackInst = pcii->hInstClient;
    LeaveDDECrit;
    CheckDDECritOut;

    hDataRet = (*pcii->pfnCallback)((UINT)wType, (UINT)wFmt, hConv, hsz1, hsz2,
            hData, dw1, dw2);

    EnterDDECrit;
    pcii->cInDDEMLCallback--;
    pci->cInDDEMLCallback--;

    if (!(pcii->afCmd & APPCLASS_MONITOR) && pcii->MonitorFlags & MF_CALLBACKS) {
        PEVENT_PACKET pep;

        pep = (PEVENT_PACKET)DDEMLAlloc(sizeof(EVENT_PACKET) - sizeof(DWORD) +
                sizeof(MONCBSTRUCT));
        if (pep != NULL) {

            pep->EventType =    MF_CALLBACKS;
            pep->fSense =       TRUE;
            pep->cbEventData =  sizeof(MONCBSTRUCT);

#define pcbs ((MONCBSTRUCT *)&pep->Data)
            pcbs->cb =      sizeof(MONCBSTRUCT);
            pcbs->dwTime =  NtGetTickCount();
            pcbs->hTask =   (HANDLE)pcii->tid;
            pcbs->dwRet =   (DWORD)hDataRet;
            pcbs->wType =   wType;
            pcbs->wFmt =    wFmt;
            pcbs->hConv =   hConv;
            pcbs->hsz1 =    (HSZ)LocalToGlobalAtom(LATOM_FROM_HSZ(hsz1));
            pcbs->hsz2 =    (HSZ)LocalToGlobalAtom(LATOM_FROM_HSZ(hsz2));
            pcbs->hData =   hData;
            pcbs->dwData1 = dw1;
            pcbs->dwData2 = dw2;
            if (((wType == XTYP_CONNECT) || (wType == XTYP_WILDCONNECT)) && dw1) {
                RtlCopyMemory(&pcbs->cc, (PVOID)dw1, sizeof(CONVCONTEXT));
            }

            LeaveDDECrit;

                if (wType & XCLASS_DATA) {
                    if (hDataRet && hDataRet != CBR_BLOCK) {
                        pcbs->cbData = DdeGetData(hDataRet, (LPBYTE)pcbs->Data, 32, 0);
                    }
                } else if (hData) {
                    pcbs->cbData = DdeGetData(hData, (LPBYTE)pcbs->Data, 32, 0);
                }

                Event(pep);

            EnterDDECrit;

            GlobalDeleteAtom(LATOM_FROM_HSZ(pcbs->hsz1));
            GlobalDeleteAtom(LATOM_FROM_HSZ(pcbs->hsz2));
            DDEMLFree(pep);
#undef pcbs
        }
    }
    return (hDataRet);
}
Example #5
0
/***************************************************************************\
* 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);
                }
            }
        }
    }
Example #6
0
/***************************************************************************\
* DdeConnectList (DDEML API)
*
* Description:
* Initiates DDE conversations with multiple servers or adds unique servers
* to an existing conversation list.
*
* History:
* 11-12-91 sanfords Created.
\***************************************************************************/
HCONVLIST DdeConnectList(
    DWORD idInst,
    HSZ hszService,
    HSZ hszTopic,
    HCONVLIST hConvList,
    PCONVCONTEXT pCC)
{
    PCL_INSTANCE_INFO pcii;
    PCONV_INFO pcoi, pcoiNew, pcoiExisting, pcoiNext;
    HCONVLIST hConvListRet = 0;
    HWND hwndTarget = 0;
    LATOM aNormalSvcName = 0;
    PCONVLIST pcl = NULL;
    HCONVLIST hConvListOld;
    int i;

    CheckDDECritOut;

    EnterDDECrit;

    if (!ValidateConnectParameters((HANDLE)idInst, &pcii, &hszService, hszTopic,
            &aNormalSvcName, &pCC, &hwndTarget, hConvList)) {
        goto Exit;
    }

    ValidateConvList(hConvList);

    hConvListOld = hConvList;
    pcoi = (PCONV_INFO)ConnectConv(pcii,
            LATOM_FROM_HSZ(hszService),
            LATOM_FROM_HSZ(hszTopic),
            hwndTarget,
            (pcii->afCmd & (CBF_FAIL_SELFCONNECTIONS | CBF_FAIL_CONNECTIONS)) ?
                pcii->hwndMother : 0,
            pCC,
            hConvListOld,
            CLST_MULT_INITIALIZING);

    if (pcoi == NULL) {
        /*
         * no new connections made
         */
        SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED);
        hConvListRet = hConvListOld;
        goto Exit;
    }

    /*
     * allocate or reallocate the hConvList hwnd list for later addition
     * If we already have a valid list, reuse the handle so we don't have
     * to alter the preexisting pcoi->hConvList values.
     */
    if (hConvListOld == 0) {
        pcl = (PCONVLIST)DDEMLAlloc(sizeof(CONVLIST));
        if (pcl == NULL) {
            SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
            DisconnectConv(pcoi);
            goto Exit;
        }
        // pcl->chwnd = 0; LPTR zero inits.

        hConvList = (HCONVLIST)CreateHandle((DWORD)pcl,
                HTYPE_CONVERSATION_LIST, InstFromHandle(pcii->hInstClient));
        if (hConvList == 0) {
            DDEMLFree(pcl);
            SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
            DisconnectConv(pcoi);
            goto Exit;
        }
    } else {
        pcl = (PCONVLIST)GetHandleData((HANDLE)hConvList);
        pcl = DDEMLReAlloc(pcl, sizeof(CONVLIST) + sizeof(HWND) * pcl->chwnd);
        if (pcl == NULL) {
            SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
            hConvListRet = hConvListOld;
            DisconnectConv(pcoi);
            goto Exit;
        }
        SetHandleData((HANDLE)hConvList, (DWORD)pcl);
    }

    ValidateConvList(hConvListOld);

    if (hConvListOld) {
        /*
         * remove duplicates from new conversations
         *
         * Although we tried to prevent duplicates from happening
         * within the initiate enumeration code, wild initiates or
         * servers responding with different service names than
         * requested could cause duplicates.
         */

        /* For each client window... */

        for (i = 0; i < pcl->chwnd; i++) {

        /* For each existing conversation in that window... */

            for (pcoiExisting = (PCONV_INFO)
                        GetWindowLong(pcl->ahwnd[i], GWL_PCI);
                    pcoi != NULL && pcoiExisting != NULL;
                    pcoiExisting = pcoiExisting->next) {

                if (!(pcoiExisting->state & ST_CONNECTED))
                    continue;

        /* For each new conversation... */

                for (pcoiNew = pcoi; pcoiNew != NULL; pcoiNew = pcoiNext) {

                    pcoiNext = pcoiNew->next;

        /* see if the new conversation duplicates the existing one */

                    if (!(pcoiNew->state & ST_CONNECTED))
                        continue;

                    UserAssert(((PCL_CONV_INFO)pcoiExisting)->hwndReconnect);
                    UserAssert(((PCL_CONV_INFO)pcoiNew)->hwndReconnect);

                    if (((PCL_CONV_INFO)pcoiExisting)->hwndReconnect ==
                                ((PCL_CONV_INFO)pcoiNew)->hwndReconnect &&
                            pcoiExisting->laTopic == pcoiNew->laTopic &&
                            pcoiExisting->laService == pcoiNew->laService) {
                        /*
                         * duplicate conversation - disconnection causes an unlink
                         */
                        if (pcoiNew == pcoi) {
                            /*
                             * We are freeing up the head of the list,
                             * Reset the head to the next guy.
                             */
                            pcoi = pcoiNext;
                        }
                        ValidateConvList(hConvList);
                        ShutdownConversation(pcoiNew, FALSE);
                        ValidateConvList(hConvList);
                        break;
                    }
                }
            }
        }

        for (pcoiExisting = pcoi; pcoiExisting != NULL; pcoiExisting = pcoiExisting->next) {
            /*
             * if these are all zombies - we DONT want to link it in!
             * This is possible because ShutdownConversation() leaves the critical section
             * and could allow responding terminates to come through.
             */
            if (pcoiExisting->state & ST_CONNECTED) {
                goto FoundOne;
            }
        }
        pcoi = NULL;    // abandon this guy - he will clean up in time.
FoundOne:
        /*
         * add new pcoi (if any are left) hwnd to ConvList hwnd list.
         */
        if (pcoi != NULL) {
            UserAssert(pcoi->hwndConv);
            pcl->ahwnd[pcl->chwnd] = pcoi->hwndConv;
            pcl->chwnd++;
            hConvListRet = hConvList;
        } else {
            hConvListRet = hConvListOld;
            if (!hConvListOld) {
                DestroyHandle((HANDLE)hConvList);
            }
        }


    } else {    // no hConvListOld

        UserAssert(pcoi->hwndConv);
        pcl->ahwnd[0] = pcoi->hwndConv;
        pcl->chwnd = 1;
        hConvListRet = hConvList;
    }

    if (pcoi != NULL) {
        /*
         * set hConvList field for all remaining new conversations.
         */
        UserAssert(hConvListRet);
        for (pcoiNew = pcoi; pcoiNew != NULL; pcoiNew = pcoiNew->next) {
            if (pcoiNew->state & ST_CONNECTED) {
                ((PCL_CONV_INFO)pcoiNew)->hConvList = hConvListRet;
            }
        }
    }

Exit:
    if (aNormalSvcName) {
        DeleteAtom(aNormalSvcName);
    }
    ValidateConvList(hConvListRet);
    LeaveDDECrit;
    return (hConvListRet);
}
Example #7
0
/***************************************************************************\
* FreeConversationResources
*
* Description:
* Used when: Client window is disconnected by app, Server window is
* disconnected by either side, or when a conversation is disconnected
* at Uninitialize time.
*
* This function releases all resources held by the pcoi and unlinks it
* from its host window pcoi chian. pcoi is freed once this return s.
*
* History:
* 12-21-91 sanfords Created.
\***************************************************************************/
VOID FreeConversationResources(
    PCONV_INFO pcoi)
{
    PADVISE_LINK paLink;
    PDDE_MESSAGE_QUEUE pdmq;
    PXACT_INFO pxi;

    CheckDDECritIn;

    /*
     * Don't free resources on locked conversations.
     */
    if (pcoi->cLocks > 0) {
        pcoi->state |= ST_FREE_CONV_RES_NOW;
        return;
    }

    /*
     * Don't free resources if a synchronous transaction is in effect!
     */
    pxi = pcoi->pxiOut;
    while (pxi != NULL) {
        if (pxi->flags & XIF_SYNCHRONOUS) {
            /*
             * This conversation is in a synchronous transaction.
             * Shutdown the modal loop FIRST, then call this when
             * the loop exits.
             */
            PostMessage(pcoi->hwndConv, WM_TIMER, TID_TIMEOUT, 0);
            pcoi->state |= ST_FREE_CONV_RES_NOW;
            return;
        }
        pxi = pxi->next;
    }

    /*
     * If this is an Intra-Process conversation that hasn't yet received
     * a terminate message, make it a zombie.  We will call this routine
     * again once the terminate arrives or when WaitForZombieTerminate() has
     * timed out waiting.
     */
    if (pcoi->state & ST_INTRA_PROCESS && !(pcoi->state & ST_TERMINATE_RECEIVED)) {
        DestroyHandle((HANDLE)pcoi->hConv);
        pcoi->hConv = (HCONV)CreateHandle((DWORD)pcoi, HTYPE_ZOMBIE_CONVERSATION,
                InstFromHandle(pcoi->hConv));
        UnlinkConvFromOthers(pcoi, TRUE);
        return;
    }

    /*
     * remove any transactions left in progress
     */
    while (pcoi->pxiOut != NULL) {
        (pcoi->pxiOut->pfnResponse)(pcoi->pxiOut, 0, 0);
    }

    /*
     * Throw away any incomming queued DDE messages.
     */
    while (pcoi->dmqOut != NULL) {

        pdmq = pcoi->dmqOut;
        DumpDDEMessage(!(pcoi->state & ST_INTRA_PROCESS), pdmq->msg, pdmq->lParam);
        pcoi->dmqOut = pcoi->dmqOut->next;
        if (pcoi->dmqOut == NULL) {
            pcoi->dmqIn = NULL;
        }
        DDEMLFree(pdmq);
    }

    //
    // Remove all link info
    //
    paLink = pcoi->aLinks;
    while (pcoi->cLinks) {
        if (pcoi->state & ST_CLIENT) {
            MONLINK(pcoi->pcii, FALSE, paLink->wType & XTYPF_NODATA,
                    pcoi->laService, pcoi->laTopic,
                    LocalToGlobalAtom(paLink->laItem),
                    paLink->wFmt, FALSE,
                    (HCONV)pcoi->hwndPartner, (HCONV)pcoi->hwndConv);
        } else {
            MONLINK(pcoi->pcii, FALSE, paLink->wType & XTYPF_NODATA,
                    pcoi->laService, pcoi->laTopic,
                    LocalToGlobalAtom(paLink->laItem),
                    paLink->wFmt, TRUE,
                    (HCONV)pcoi->hwndConv, (HCONV)pcoi->hwndPartner);
        }
        if (!(pcoi->state & ST_CLIENT)) {
            DeleteLinkCount(pcoi->pcii, paLink->pLinkCount);
        }
        DeleteAtom(paLink->laItem); // link structure copy
        paLink++;
        pcoi->cLinks--;
    }
    if (pcoi->aLinks) {
        DDEMLFree(pcoi->aLinks);
    }

    //
    // free atoms associated with this conv
    //
    DeleteAtom(pcoi->laService);
    DeleteAtom(pcoi->laTopic);
    if (pcoi->laServiceRequested) {
        DeleteAtom(pcoi->laServiceRequested);
    }

    UnlinkConvFromOthers(pcoi, FALSE);

    /*
     * invalidate app's conversation handle
     */
    DestroyHandle((HANDLE)pcoi->hConv);

    DDEMLFree(pcoi);
}
Example #8
0
/***************************************************************************\
* UnlinkConvFromOthers
*
* Description:
*
* Helper function to handle ugly cross dependency removal.  If we are
* unlinking a conversation that is going zombie, fGoingZombie is TRUE;
*
* Conversations that are going zombie are in phase 1 of a 2 phase unlink.
* Phase 1 unlinks do not remove the pcoi from its hwnd's list.
* All unlinks should result in:
*   pcoi->hConvList = 0;
*   hConvList/aServerLookup no longer refrences pcoi->hwndConv unless
*       one of the pcoi's related to hwndConv is still active.
*
*
* History:
*  3-2-92 sanfords Created.
\***************************************************************************/
VOID UnlinkConvFromOthers(
PCONV_INFO pcoi,
BOOL gGoingZombie)
{
    PCONV_INFO pcoiPrev, pcoiFirst, pcoiNow;
    PCONVLIST pcl;
    int i, cActiveInList = 0;
#ifdef TESTING
    DWORD path = 0;
#define ORPATH(x) path |= x;
#else
#define ORPATH(x)
#endif // TESTING

    CheckDDECritIn;

    /*
     * Scan pcoi linked list to get key pointers.
     */
    pcoiPrev = NULL;
    pcoiFirst = pcoiNow = (PCONV_INFO)GetWindowLong(pcoi->hwndConv, GWL_PCI);

#ifdef TESTING
    /*
     * verify that pcoi is in the conv list for this window.
     */
    while (pcoiNow != NULL) {
        if (pcoiNow == pcoi) {
            goto FoundIt;
        }
        pcoiNow = pcoiNow->next;
    }
    DebugBreak();
FoundIt:
    pcoiNow = pcoiFirst;
#endif // TESTING

    UserAssert(pcoiFirst);
    while (pcoiNow != NULL) {
        if (TypeFromHandle(pcoiNow->hConv) != HTYPE_ZOMBIE_CONVERSATION) {
            ORPATH(1);
            cActiveInList++;
        }
        if (pcoiNow->next == pcoi) {
            pcoiPrev = pcoiNow;
        }
        pcoiNow = pcoiNow->next;
    }

    ValidateAllConvLists();

    /*
     * Unlink conversation unless its going Zombie.
     */
    if (!gGoingZombie) {
        ORPATH(2);
        if (TypeFromHandle(pcoi->hConv) != HTYPE_ZOMBIE_CONVERSATION) {
            ORPATH(4);
            cActiveInList--;
        }

        if (pcoiPrev == NULL) {
            ORPATH(8);
            pcoiFirst = pcoi->next;
            SetWindowLong(pcoi->hwndConv, GWL_PCI, (LONG)pcoiFirst);
        } else {
            pcoiPrev->next = pcoi->next;
        }
    }

    UserAssert(pcoiFirst != NULL || !cActiveInList);

    if (cActiveInList == 0) {
        ORPATH(0x10);
        if (pcoi->state & ST_CLIENT) {
            ORPATH(0x20);
            if (((PCL_CONV_INFO)pcoi)->hConvList) {
                /*
                 * Remove pcoi's hwnd from its hConvList.
                 */
                pcl = (PCONVLIST)GetHandleData((HANDLE)((PCL_CONV_INFO)pcoi)->hConvList);
                for (i = 0; i < pcl->chwnd; i++) {
                    if (pcl->ahwnd[i] == pcoi->hwndConv) {
                        ORPATH(0x40);
                        pcl->chwnd--;
                        UserAssert(pcl->ahwnd[pcl->chwnd]);
                        pcl->ahwnd[i] = pcl->ahwnd[pcl->chwnd];
                        ValidateConvList(((PCL_CONV_INFO)pcoi)->hConvList);
                        break;
                    }
                }
                ORPATH(0x80);
            }
        } else {  // SERVER
            /*
             * remove server window from the service/topic lookup table.
             */
            ORPATH(0x100);
            for (i = 0; i < pcoi->pcii->cServerLookupAlloc; i++) {
                if (pcoi->pcii->aServerLookup[i].hwndServer == pcoi->hwndConv) {
                    ORPATH(0x200);
                    if (--(pcoi->pcii->cServerLookupAlloc)) {
                        ORPATH(0x400);
                        pcoi->pcii->aServerLookup[i] =
                                pcoi->pcii->aServerLookup[pcoi->pcii->cServerLookupAlloc];
                    } else {
                        DDEMLFree(pcoi->pcii->aServerLookup);
                        pcoi->pcii->aServerLookup = NULL;
                    }
                    break;
                }
            }
        }
    }
#ifdef TESTING
      else {
        /*
         * make sure at this point we have at least one non-zombie
         */
        pcoiNow = pcoiFirst;
        while (pcoiNow != NULL) {
            if (TypeFromHandle(pcoiNow->hConv) != HTYPE_ZOMBIE_CONVERSATION) {
                goto Out;
            }
            pcoiNow = pcoiNow->next;
        }
        DebugBreak();
Out:
        ;
    }
#endif // TESTING

    ValidateAllConvLists();
    ORPATH(0x800);

    /*
     * In any case remove hConvList references from client conversation.
     */
    if (pcoi->state & ST_CLIENT) {
#ifdef TESTING
        /*
         * Verify that the hConvList that is being removed, doesn't reference
         * this window.
         */
        if (((PCL_CONV_INFO)pcoi)->hConvList && !cActiveInList) {
            BOOL fFound = FALSE;

            pcl = (PCONVLIST)GetHandleData((HANDLE)((PCL_CONV_INFO)pcoi)->hConvList);
            for (i = 0; i < pcl->chwnd; i++) {
                if (pcl->ahwnd[i] == pcoi->hwndConv) {
                    fFound = TRUE;
                    break;
                }
            }
            UserAssert(!fFound);
        }
#endif // TESTING
        ((PCL_CONV_INFO)pcoi)->hConvList = 0;
        pcoi->state &= ~ST_INLIST;
    }

    /*
     * last one out turns out the lights.
     */
    if (pcoiFirst == NULL) {
        /*
         * If the pcoi list is empty, this window can go away.
         */
        LeaveDDECrit;
        NtUserDestroyWindow(pcoi->hwndConv);
        EnterDDECrit;
    }
}