Annotation of mstools/samples/ddeml/client/dde.c, revision 1.1

1.1     ! root        1: /***************************************************************************
        !             2:  *                                                                         *
        !             3:  *  MODULE      : dde.c                                                    *
        !             4:  *                                                                         *
        !             5:  *  PURPOSE     : Contains routines for handling of DDE interaction with   *
        !             6:  *                DDEML.                                                   *
        !             7:  *                                                                         *
        !             8:  ***************************************************************************/
        !             9: #include "client.h"
        !            10: #include <string.h>
        !            11: #include <memory.h>
        !            12: #include "infoctrl.h"
        !            13: 
        !            14: CHAR szT[100];
        !            15: 
        !            16: /****************************************************************************
        !            17:  *                                                                          *
        !            18:  *  FUNCTION   : CreateXactionWindow()                                      *
        !            19:  *                                                                          *
        !            20:  *  PURPOSE    : Creates a transaction window for the given transaction     *
        !            21:  *               under the given conversation window.                       *
        !            22:  *                                                                          *
        !            23:  *  RETURNS    : TRUE  - If successful.                                     *
        !            24:  *               FALSE - otherwise.                                         *
        !            25:  *                                                                          *
        !            26:  ****************************************************************************/
        !            27: HWND CreateXactionWindow(
        !            28: HWND hwndMDI,
        !            29: XACT *pxact)
        !            30: {
        !            31:     PSTR pszFmt, pszItem;
        !            32:     PSTR pData;
        !            33:     HWND hwnd;
        !            34: 
        !            35:     pszItem = GetHSZName(pxact->hszItem);
        !            36:     pszFmt = GetFormatName(pxact->wFmt);
        !            37:     pData = GetTextData(pxact->hDdeData);
        !            38: 
        !            39:     /*
        !            40:      *   �type/opts������� ITEM ���������������retĿ    GWL_USER=pxact
        !            41:      *   �                                         �
        !            42:      *   �                                         �
        !            43:      *   �                                         �
        !            44:      *   �                                         �
        !            45:      *   �                 DATA                    �
        !            46:      *   �                                         �
        !            47:      *   �                                         �
        !            48:      *   �                                         �
        !            49:      *   �                                         �
        !            50:      *   �state/error����� FORMAT ����������Result��
        !            51:      */
        !            52:     hwnd = CreateInfoCtrl((LPSTR)pData,
        !            53:             (INT)SendMessage(hwndMDI, UM_GETNEXTCHILDX, 0, 0L),
        !            54:             (INT)SendMessage(hwndMDI, UM_GETNEXTCHILDY, 0, 0L),
        !            55:             200, 100, hwndMDI, hInst,
        !            56:             Type2String(pxact->wType, pxact->fsOptions), pszItem, NULL,
        !            57:             "Starting", (LPSTR)pszFmt, NULL,
        !            58:             ICSTY_SHOWFOCUS, 0, (DWORD)(LPSTR)pxact);
        !            59:     MyFree(pszItem);
        !            60:     MyFree(pszFmt);
        !            61:     MyFree(pData);
        !            62:     return(hwnd);
        !            63: }
        !            64: 
        !            65: 
        !            66: 
        !            67: 
        !            68: /****************************************************************************
        !            69:  *                                                                          *
        !            70:  *  FUNCTION   : ProcessTransaction()                                       *
        !            71:  *                                                                          *
        !            72:  *  PURPOSE    : Processes synchronous transactions entirely and starts     *
        !            73:  *               async transactions.  Transaction attempts result in a      *
        !            74:  *               transaction window being created which displays the state  *
        !            75:  *               or results of the transaction.  (the callback function     *
        !            76:  *               updates these windows as it gets calls) Transaction        *
        !            77:  *               windows stay around until abandoned by the user or until   *
        !            78:  *               the conversation is disconnected.  Advise Data and Advise  *
        !            79:  *               Stop transactions are special.  We don't create a new      *
        !            80:  *               window if the associated advise start transaction window   *
        !            81:  *               can be found.                                              *
        !            82:  *                                                                          *
        !            83:  *  RETURNS    : TRUE  - If successful.                                     *
        !            84:  *               FALSE - otherwise.                                         *
        !            85:  *                                                                          *
        !            86:  ****************************************************************************/
        !            87: BOOL ProcessTransaction(
        !            88: XACT *pxact)
        !            89: {
        !            90:     CONVINFO ci;
        !            91:     HWND hwndInfoCtrl = 0;
        !            92: 
        !            93:     /* create transaction window to show we tried (except in ADVSTOP case) */
        !            94: 
        !            95:     pxact = (XACT *)memcpy(MyAlloc(sizeof(XACT)), (PSTR)pxact, sizeof(XACT));
        !            96:     ci.cb = sizeof(CONVINFO);
        !            97:     DdeQueryConvInfo(pxact->hConv, QID_SYNC, &ci); // ci.hUser==hConv
        !            98:     if (pxact->wType == XTYP_ADVSTOP) {
        !            99:         hwndInfoCtrl = FindAdviseChild((HWND)ci.hUser, pxact->hszItem,
        !           100:                 pxact->wFmt);
        !           101:         if (hwndInfoCtrl) {
        !           102:             SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UL,
        !           103:                     (DWORD)(LPSTR)Type2String(pxact->wType, pxact->fsOptions));
        !           104:             DdeFreeStringHandle(idInst, pxact->hszItem);
        !           105:         }
        !           106:     }
        !           107:     /*
        !           108:      * If we still need to create a transaction window, do so here.
        !           109:      */
        !           110:     if (!hwndInfoCtrl) {
        !           111:         hwndInfoCtrl = CreateXactionWindow((HWND)ci.hUser, pxact);
        !           112:         if (!hwndInfoCtrl) {
        !           113:             MyFree(pxact);
        !           114:             return 0;
        !           115:         }
        !           116:         SetFocus(hwndInfoCtrl);
        !           117:     }
        !           118:     /*
        !           119:      * Disable callbacks for this conversation now if the XOPT_DISABLEFIRST
        !           120:      * option is set.  This tests disabling asynchronous transactions
        !           121:      * before they are completed.
        !           122:      */
        !           123:     if (pxact->fsOptions & XOPT_DISABLEFIRST)
        !           124:         DdeEnableCallback(idInst, pxact->hConv, EC_DISABLE);
        !           125:     /*
        !           126:      * Adjust the timeout for asynchronous transactions.
        !           127:      */
        !           128:     if (pxact->fsOptions & XOPT_ASYNC)
        !           129:         pxact->ulTimeout = TIMEOUT_ASYNC;
        !           130: 
        !           131:     /*
        !           132:      * start transaction with DDEML here
        !           133:      */
        !           134:     pxact->ret = DdeClientTransaction((LPBYTE)pxact->hDdeData, 0xFFFFFFFF,
        !           135:             pxact->hConv, pxact->hszItem, pxact->wFmt,
        !           136:             pxact->wType,
        !           137:             pxact->ulTimeout, (LPDWORD)&pxact->Result);
        !           138: 
        !           139:     /*
        !           140:      * show return value in transaction window
        !           141:      */
        !           142:     wsprintf(szT, "ret=%lx", pxact->ret);
        !           143:     SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UR, (DWORD)(LPSTR)szT);
        !           144: 
        !           145:     /*
        !           146:      * show result or ID value in transaction window
        !           147:      */
        !           148:     wsprintf(szT, pxact->fsOptions & XOPT_ASYNC ? "ID=%ld" :
        !           149:             "result=0x%lx", pxact->Result);
        !           150:     SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LR, (DWORD)(LPSTR)szT);
        !           151: 
        !           152:     if ((pxact->fsOptions & XOPT_ASYNC) && pxact->ret) {
        !           153:         /*
        !           154:          * asynchronous successful start - link transaction to window.
        !           155:          */
        !           156:         DdeSetUserHandle(pxact->hConv, pxact->Result, (DWORD)hwndInfoCtrl);
        !           157: 
        !           158:         /*
        !           159:          * Abandon started async transaction after initiated if
        !           160:          * XOPT_ABANDONAFTERSTART is chosen.  This tests the mid-transaction
        !           161:          * abandoning code.
        !           162:          */
        !           163:         if (pxact->fsOptions & XOPT_ABANDONAFTERSTART)
        !           164:             DdeAbandonTransaction(idInst, pxact->hConv, pxact->Result);
        !           165:         /*
        !           166:          * show actual status
        !           167:          */
        !           168:         ci.cb = sizeof(CONVINFO);
        !           169:         DdeQueryConvInfo(pxact->hConv, pxact->Result, &ci);
        !           170:         SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LL,
        !           171:                 (DWORD)(LPSTR)State2String(ci.wConvst));
        !           172:     } else {
        !           173:         /*
        !           174:          * Synchronous transactions are completed already so pass on to
        !           175:          * CompleteTransaction right away.
        !           176:          */
        !           177:         CompleteTransaction(hwndInfoCtrl, pxact);
        !           178:     }
        !           179:     return TRUE;
        !           180: }
        !           181: 
        !           182: 
        !           183: 
        !           184: 
        !           185: 
        !           186: /****************************************************************************
        !           187:  *                                                                          *
        !           188:  *  FUNCTION   : CompleteTransaction()                                      *
        !           189:  *                                                                          *
        !           190:  *  PURPOSE    : This handles completed synchronous and asynchronous        *
        !           191:  *               transactions as well as failed attempted transactions.     *
        !           192:  *                                                                          *
        !           193:  *  RETURNS    : TRUE  - If successful.                                     *
        !           194:  *               FALSE - otherwise.                                         *
        !           195:  *                                                                          *
        !           196:  ****************************************************************************/
        !           197: VOID CompleteTransaction(
        !           198: HWND hwndInfoCtrl,
        !           199: XACT *pxact)
        !           200: {
        !           201:     PSTR psz;
        !           202: 
        !           203:     if (pxact->ret) {
        !           204:         /*
        !           205:          * Successful transaction case
        !           206:          */
        !           207:         SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LL,
        !           208:                 (DWORD)(LPSTR)"Completed");
        !           209: 
        !           210:         if (pxact->wType == XTYP_REQUEST) {
        !           211:             /*
        !           212:              * Show resulting data
        !           213:              */
        !           214:             psz = GetTextData((HDDEDATA)pxact->ret);
        !           215:             SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_CENTER,
        !           216:                     (DWORD)(LPSTR)psz);
        !           217:             MyFree(psz);
        !           218:             /*
        !           219:              * free returned data since it is displayed.
        !           220:              */
        !           221:             DdeFreeDataHandle(pxact->ret);
        !           222:             pxact->ret = 0L;
        !           223:             SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UR, NULL);
        !           224:         }
        !           225:     } else {
        !           226:         /*
        !           227:          * failed - show error result.
        !           228:          */
        !           229:         SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LL,
        !           230:                 (DWORD)(LPSTR)Error2String(DdeGetLastError(idInst)));
        !           231:     }
        !           232:     pxact->fsOptions |= XOPT_COMPLETED;
        !           233: }
        !           234: 
        !           235: 
        !           236: 
        !           237: 
        !           238: /****************************************************************************
        !           239:  *                                                                          *
        !           240:  *  FUNCTION   : DdeCallback()                                              *
        !           241:  *                                                                          *
        !           242:  *  PURPOSE    : This handles all callbacks from the DDEML.  This handles   *
        !           243:  *               updating of the associated conversation and any special    *
        !           244:  *               testing cases such as blocking callbacks etc.              *
        !           245:  *                                                                          *
        !           246:  *               For the most part, clients only handle advise data and     *
        !           247:  *               asynchronous transaction completion here.                  *
        !           248:  *                                                                          *
        !           249:  *  RETURNS    : Results vary depending on transaction type.                *
        !           250:  *                                                                          *
        !           251:  ****************************************************************************/
        !           252: HDDEDATA CALLBACK DdeCallback(
        !           253: UINT wType,
        !           254: UINT wFmt,
        !           255: HCONV hConv,
        !           256: HSZ hsz1,
        !           257: HSZ hsz2,
        !           258: HDDEDATA hData,
        !           259: DWORD lData1,
        !           260: DWORD lData2)
        !           261: {
        !           262:     HWND hwnd;
        !           263:     CONVINFO ci;
        !           264:     XACT *pxact;
        !           265: 
        !           266:     if (hConv) {
        !           267:         /*
        !           268:          * update conversation status if it changed.
        !           269:          */
        !           270:         MYCONVINFO *pmci;
        !           271: 
        !           272:         ci.cb = sizeof(CONVINFO);
        !           273:         if (!DdeQueryConvInfo(hConv, QID_SYNC, &ci) || (!IsWindow((HWND)ci.hUser))) {
        !           274:             /*
        !           275:              * This conversation does not yet have a corresponding MDI window
        !           276:              * or is disconnected.
        !           277:              */
        !           278:             return 0;
        !           279:         }
        !           280:         if (pmci = (MYCONVINFO *)GetWindowLong((HWND)ci.hUser, 0)) {
        !           281:             if (pmci->ci.wStatus != ci.wStatus ||
        !           282:                     pmci->ci.wConvst != ci.wConvst ||
        !           283:                     pmci->ci.wLastError != ci.wLastError) {
        !           284:                 /*
        !           285:                  * Things have changed, updated the conversation window.
        !           286:                  */
        !           287:                 InvalidateRect((HWND)ci.hUser, NULL, TRUE);
        !           288:             }
        !           289:             if (ci.wConvst & ST_INLIST) {
        !           290:                 /*
        !           291:                  * update the associated list window (if any) as well.
        !           292:                  */
        !           293:                 if (hwnd = FindListWindow(ci.hConvList))
        !           294:                     InvalidateRect(hwnd, NULL, TRUE);
        !           295:             }
        !           296:         }
        !           297:     }
        !           298: 
        !           299:     /*
        !           300:      * handle special block on next callback option here.  This demonstrates
        !           301:      * the CBR_BLOCK feature.
        !           302:      */
        !           303:     if (fBlockNextCB && !(wType & XTYPF_NOBLOCK)) {
        !           304:         fBlockNextCB = FALSE;
        !           305:         return(CBR_BLOCK);
        !           306:     }
        !           307: 
        !           308:     /*
        !           309:      * handle special termination here.  This demonstrates that at any time
        !           310:      * a client can drop a conversation.
        !           311:      */
        !           312:     if (fTermNextCB && hConv && wType != XTYP_DISCONNECT) {
        !           313:         fTermNextCB = FALSE;
        !           314:         MyDisconnect(hConv);
        !           315:         return(0);
        !           316:     }
        !           317: 
        !           318:     /*
        !           319:      * Now we begin sort out what to do.
        !           320:      */
        !           321:     switch (wType) {
        !           322:     case XTYP_REGISTER:
        !           323:     case XTYP_UNREGISTER:
        !           324:         /*
        !           325:          * This is where the client would insert code to keep track of
        !           326:          * what servers are available.  This could cause the initiation
        !           327:          * of some conversations.
        !           328:          */
        !           329:         break;
        !           330: 
        !           331:     case XTYP_DISCONNECT:
        !           332:         if (fAutoReconnect) {
        !           333:             /*
        !           334:              * attempt a reconnection
        !           335:              */
        !           336:             if (hConv = DdeReconnect(hConv)) {
        !           337:                 AddConv(ci.hszServiceReq, ci.hszTopic, hConv, FALSE);
        !           338:                 return 0;
        !           339:             }
        !           340:         }
        !           341: 
        !           342:         /*
        !           343:          * update conv window to show its new state.
        !           344:          */
        !           345:         SendMessage((HWND)ci.hUser, UM_DISCONNECTED, 0, 0);
        !           346:         return 0;
        !           347:         break;
        !           348: 
        !           349:     case XTYP_ADVDATA:
        !           350:         /*
        !           351:          * data from an active advise loop (from a server)
        !           352:          */
        !           353:         Delay(wDelay);
        !           354:         hwnd = FindAdviseChild((HWND)ci.hUser, hsz2, wFmt);
        !           355:         if (!IsWindow(hwnd)) {
        !           356:             PSTR pszItem, pszFmt;
        !           357:             /*
        !           358:              * AdviseStart window is gone, make a new one.
        !           359:              */
        !           360:             pxact = (XACT *)MyAlloc(sizeof(XACT));
        !           361:             pxact->wType = wType;
        !           362:             pxact->hConv = hConv;
        !           363:             pxact->wFmt = wFmt;
        !           364:             pxact->hszItem = hsz2;
        !           365:             DdeKeepStringHandle(idInst, hsz2);
        !           366: 
        !           367:             pszItem = GetHSZName(hsz2);
        !           368:             pszFmt = GetFormatName(wFmt);
        !           369: 
        !           370:             hwnd = CreateInfoCtrl(NULL,
        !           371:                     (INT)SendMessage((HWND)ci.hUser, UM_GETNEXTCHILDX, 0, 0L),
        !           372:                     (INT)SendMessage((HWND)ci.hUser, UM_GETNEXTCHILDY, 0, 0L),
        !           373:                     200, 100,
        !           374:                     (HWND)ci.hUser, hInst,
        !           375:                     Type2String(wType, 0), (LPSTR)pszItem, NULL,
        !           376:                     NULL, (LPSTR)pszFmt, NULL,
        !           377:                     ICSTY_SHOWFOCUS, 0, (DWORD)(LPSTR)pxact);
        !           378: 
        !           379:             MyFree(pszFmt);
        !           380:             MyFree(pszItem);
        !           381: 
        !           382:             if (!IsWindow(hwnd))
        !           383:                 return(DDE_FNOTPROCESSED);
        !           384:         }
        !           385:         if (!hData) {
        !           386:             /*
        !           387:              * XTYPF_NODATA case - request the info. (we do this synchronously
        !           388:              * for simplicity)
        !           389:              */
        !           390:             hData = DdeClientTransaction(NULL, 0L, hConv, hsz2, wFmt,
        !           391:                     XTYP_REQUEST, DefTimeout, NULL);
        !           392:         }
        !           393:         if (hData) {
        !           394:             PSTR pData;
        !           395:             /*
        !           396:              * Show incomming data on corresponding transaction window.
        !           397:              */
        !           398:             pData = GetTextData(hData);
        !           399:             SendMessage(hwnd, ICM_SETSTRING, ICSID_CENTER, (DWORD)(LPSTR)pData);
        !           400:             MyFree(pData);
        !           401:             DdeFreeDataHandle(hData);
        !           402:         }
        !           403:         SendMessage(hwnd, ICM_SETSTRING, ICSID_LL, (DWORD)(LPSTR)"Advised");
        !           404:         return(DDE_FACK);
        !           405:         break;
        !           406: 
        !           407:     case XTYP_XACT_COMPLETE:
        !           408:         /*
        !           409:          * An asynchronous transaction has completed.  Show the results.
        !           410:          *
        !           411:          * ...unless the XOPT_BLOCKRESULT is chosen.
        !           412:          */
        !           413: 
        !           414:         ci.cb = sizeof(CONVINFO);
        !           415:         if (DdeQueryConvInfo(hConv, lData1, &ci) &&
        !           416:                 IsWindow((HWND)ci.hUser) &&
        !           417:                 (pxact = (XACT *)GetWindowLong((HWND)ci.hUser, GWL_USER))) {
        !           418: 
        !           419:             if (pxact->fsOptions & XOPT_BLOCKRESULT) {
        !           420:                 pxact->fsOptions &= ~XOPT_BLOCKRESULT;
        !           421:                 return(CBR_BLOCK);
        !           422:             }
        !           423: 
        !           424:             pxact->Result = lData2;
        !           425:             pxact->ret = hData;
        !           426:             CompleteTransaction((HWND)ci.hUser, pxact);
        !           427:         }
        !           428:         break;
        !           429:     }
        !           430: }
        !           431: 
        !           432: 
        !           433: 
        !           434: 
        !           435: 
        !           436: 
        !           437: 
        !           438: /****************************************************************************
        !           439:  *                                                                          *
        !           440:  *  FUNCTION   : FindAdviseChild()                                          *
        !           441:  *                                                                          *
        !           442:  *  PURPOSE    : Search through the child windows of hwndMDI for an info    *
        !           443:  *               ctrl that has the same Item and format and is an           *
        !           444:  *               ADVSTART ADVSTOP or ADVDATA transaction window.            *
        !           445:  *                                                                          *
        !           446:  *               We use these to show the associated advise data.           *
        !           447:  *                                                                          *
        !           448:  *  RETURNS    : The transaction window handle or 0 on failure.             *
        !           449:  *                                                                          *
        !           450:  ****************************************************************************/
        !           451: HWND FindAdviseChild(
        !           452: HWND hwndMDI,
        !           453: HSZ hszItem,
        !           454: DWORD wFmt)
        !           455: {
        !           456:     HWND hwnd, hwndStart;
        !           457:     XACT *pxact;
        !           458: 
        !           459:     if (!IsWindow(hwndMDI))
        !           460:         return 0;
        !           461: 
        !           462:     hwnd = hwndStart = GetWindow(hwndMDI, GW_CHILD);
        !           463:     while (hwnd && IsChild(hwndMDI, hwnd)) {
        !           464:         pxact = (XACT *)GetWindowLong(hwnd, GWL_USER);
        !           465:         if (pxact &&
        !           466:                 (pxact)->wFmt == wFmt &&
        !           467:                 (pxact)->hszItem == hszItem &&
        !           468:                 (
        !           469:                     ((pxact->wType & XTYP_ADVSTART) == XTYP_ADVSTART) ||
        !           470:                     (pxact->wType == XTYP_ADVSTOP) ||
        !           471:                     (pxact->wType == XTYP_ADVDATA)
        !           472:                 )
        !           473:            ) {
        !           474:             return(hwnd);
        !           475:         }
        !           476:         hwnd = GetWindow(hwnd, GW_HWNDNEXT);
        !           477:         if (hwnd == hwndStart)
        !           478:             return 0;
        !           479:     }
        !           480:     return 0;
        !           481: }
        !           482: 
        !           483: 
        !           484: 
        !           485: /****************************************************************************
        !           486:  *                                                                          *
        !           487:  *  FUNCTION   : FindListWindow()                                           *
        !           488:  *                                                                          *
        !           489:  *  PURPOSE    : Locates the list window associated with this conversation  *
        !           490:  *               list.                                                      *
        !           491:  *                                                                          *
        !           492:  *  RETURNS    : The window handle of the list window or 0 on failure.      *
        !           493:  *                                                                          *
        !           494:  ****************************************************************************/
        !           495: HWND FindListWindow(
        !           496: HCONVLIST hConvList)
        !           497: {
        !           498:     HWND hwnd;
        !           499:     MYCONVINFO *pmci;
        !           500: 
        !           501:     hwnd = GetWindow(hwndMDIClient, GW_CHILD);
        !           502:     while (hwnd) {
        !           503:         if (GetWindowLong(hwnd, GWL_WNDPROC) == (LONG)MDIChildWndProc) {
        !           504:             pmci = (MYCONVINFO *)GetWindowLong(hwnd, 0);
        !           505:             if (pmci != NULL && pmci->fList && pmci->hConv == hConvList)
        !           506:                 return(hwnd);
        !           507:         }
        !           508:         hwnd = GetWindow(hwnd, GW_HWNDNEXT);
        !           509:     }
        !           510:     return 0;
        !           511: }
        !           512: 
        !           513: 
        !           514: 
        !           515: 
        !           516: /****************************************************************************
        !           517:  *                                                                          *
        !           518:  *  FUNCTION   : GetTextData()                                              *
        !           519:  *                                                                          *
        !           520:  *  PURPOSE    : Allocates and returns a pointer to the data contained in   *
        !           521:  *               hData.  This assumes that hData points to text data and    *
        !           522:  *               will properly handle huge text data by leaving out the     *
        !           523:  *               middle of the string and placing the size of the string    *
        !           524:  *               into this string portion.                                  *
        !           525:  *                                                                          *
        !           526:  *  RETURNS    : A pointer to the allocated string.                         *
        !           527:  *                                                                          *
        !           528:  ****************************************************************************/
        !           529: PSTR GetTextData(
        !           530: HDDEDATA hData)
        !           531: {
        !           532:     PSTR psz;
        !           533:     DWORD cb;
        !           534: 
        !           535: #define CBBUF  1024
        !           536: 
        !           537:     if (hData == NULL) {
        !           538:         return(NULL);
        !           539:     }
        !           540: 
        !           541:     cb = DdeGetData(hData, NULL, 0, 0);
        !           542:     if (!hData || !cb)
        !           543:         return NULL;
        !           544: 
        !           545:     if (cb > CBBUF) {                // possibly HUGE object!
        !           546:         psz = MyAlloc(CBBUF);
        !           547:         DdeGetData(hData, psz, CBBUF - 46, 0L);
        !           548:         wsprintf(&psz[CBBUF - 46], "<---Size=%ld", cb);
        !           549:     } else {
        !           550:         psz = MyAlloc((DWORD)cb);
        !           551:         DdeGetData(hData, (LPBYTE)psz, cb, 0L);
        !           552:     }
        !           553:     return psz;
        !           554: #undef CBBUF
        !           555: }
        !           556: 
        !           557: 
        !           558: 
        !           559: 
        !           560: 
        !           561: 
        !           562: 
        !           563: /****************************************************************************
        !           564:  *                                                                          *
        !           565:  *  FUNCTION   : MyGetClipboardFormatName()                                 *
        !           566:  *                                                                          *
        !           567:  *  PURPOSE    : Properly retrieves the string associated with a clipboard  *
        !           568:  *               format.  If the format does not have a string associated   *
        !           569:  *               with it, the string #dddd is returned.                     *
        !           570:  *                                                                          *
        !           571:  *  RETURNS    : The number of characters copied into lpstr or 0 on error.  *
        !           572:  *                                                                          *
        !           573:  ****************************************************************************/
        !           574: INT MyGetClipboardFormatName(
        !           575: DWORD fmt,
        !           576: LPSTR lpstr,
        !           577: INT cbMax)
        !           578: {
        !           579:     if (fmt < 0xc000) {
        !           580:         // predefined or integer format - just get the atom string
        !           581:         // wierdly enough, GetClipboardFormatName() doesn't support this.
        !           582:        return(GlobalGetAtomName((ATOM)fmt, lpstr, cbMax));
        !           583:     } else {
        !           584:         return(GetClipboardFormatName(fmt, lpstr, cbMax));
        !           585:     }
        !           586: }
        !           587: 
        !           588: 
        !           589: 
        !           590: 
        !           591: 
        !           592: /****************************************************************************
        !           593:  *                                                                          *
        !           594:  *  FUNCTION   : GetFormatName()                                            *
        !           595:  *                                                                          *
        !           596:  *  PURPOSE    : allocates and returns a pointer to a string representing   *
        !           597:  *               a format.  Use MyFree() to free this string.               *
        !           598:  *                                                                          *
        !           599:  *  RETURNS    : The number of characters copied into lpstr or 0 on error.  *
        !           600:  *                                                                          *
        !           601:  ****************************************************************************/
        !           602: PSTR GetFormatName(
        !           603: DWORD wFmt)
        !           604: {
        !           605:     PSTR psz;
        !           606:     DWORD cb;
        !           607: 
        !           608:     if (wFmt == 1) {
        !           609:         psz = MyAlloc(8);
        !           610:         strcpy(psz, "CF_TEXT");
        !           611:         return psz;
        !           612:     }
        !           613:     psz = MyAlloc(255);
        !           614:     *psz = '\0';
        !           615:     cb = GetClipboardFormatName(wFmt, psz, 255) + 1;
        !           616:     return((PSTR)LocalReAlloc((HANDLE)psz, cb, LMEM_MOVEABLE));
        !           617: }
        !           618: 
        !           619: 
        !           620: 
        !           621: 
        !           622: /****************************************************************************
        !           623:  *                                                                          *
        !           624:  *  FUNCTION   : MyDisconnect()                                             *
        !           625:  *                                                                          *
        !           626:  *  PURPOSE    : Disconnects the given conversation after updating the      *
        !           627:  *               associated conversation window.                            *
        !           628:  *                                                                          *
        !           629:  *  RETURNS    : TRUE on success, FALSE on failuer.                         *
        !           630:  *                                                                          *
        !           631:  ****************************************************************************/
        !           632: BOOL MyDisconnect(
        !           633: HCONV hConv)
        !           634: {
        !           635:     CONVINFO ci;
        !           636:     HWND hwnd;
        !           637:     // before we disconnect, invalidate the associated list window - if
        !           638:     // applicable.
        !           639: 
        !           640:     ci.cb = sizeof(CONVINFO);
        !           641: 
        !           642:     if (DdeQueryConvInfo(hConv, QID_SYNC, &ci) && ci.hConvList &&
        !           643:             (hwnd = FindListWindow(ci.hConvList)))
        !           644:         InvalidateRect(hwnd, NULL, TRUE);
        !           645:     return(DdeDisconnect(hConv));
        !           646: }
        !           647: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.