示例#1
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);
}
示例#2
0
/***************************************************************************\
* 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);
}
示例#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);
}
示例#4
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;
    }
}