Esempio n. 1
0
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CreateConv()   AE: Taken from DDEML sample app             *
 *                                                                          *
 *  PURPOSE    :                                                            *
 *                                                                          *
 *  RETURNS    :                                                            *
 *                                                                          *
 ****************************************************************************/
HCONV CConv::CreateConv(DWORD idInst,HSZ hszApp,HSZ hszTopic,BOOL fList,WORD *pError)
{
    HCONV hConv;
    HWND hwndConv = 0;
    CONVINFO ci;

    hConv = DdeConnect(idInst, hszApp, hszTopic, 0);
    if (hConv) {
        if (fList) {
            ci.hszSvcPartner = hszApp;
            ci.hszTopic = hszTopic;
        } else {
            ci.cb = sizeof(CONVINFO);
        DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci);
        }
 //       hwndConv = AddConv(ci.hszSvcPartner, ci.hszTopic, hConv, fList);
        // HSZs get freed when window dies.
    }
/*    if (!hwndConv) {
        if (pError != NULL) {
            *pError = DdeGetLastError(m_idInst);
        }
    }*/
    return(hConv);
}
Esempio n. 2
0
/******************************************************************
 *		DdeQueryConvInfo (DDEML.9)
 *
 */
UINT16 WINAPI DdeQueryConvInfo16(HCONV hConv, DWORD idTransaction,
                                 LPCONVINFO16 lpConvInfo)
{
    CONVINFO    ci32;
    CONVINFO16  ci16;
    UINT        ret;

    ci32.cb = sizeof(ci32);
    ci32.ConvCtxt.cb = sizeof(ci32.ConvCtxt);

    ret = DdeQueryConvInfo(hConv, idTransaction, &ci32);
    if (ret == 0) return 0;

    ci16.hUser = ci32.hUser;
    ci16.hConvPartner = ci32.hConvPartner;
    ci16.hszSvcPartner = ci32.hszSvcPartner;
    ci16.hszServiceReq = ci32.hszServiceReq;
    ci16.hszTopic = ci32.hszTopic;
    ci16.hszItem = ci32.hszItem;
    ci16.wFmt = ci32.wFmt;
    ci16.wType = ci32.wType;
    ci16.wStatus = ci32.wStatus;
    ci16.wConvst = ci32.wConvst;
    ci16.wLastError = ci32.wLastError;
    ci16.hConvList = ci32.hConvList;

    map3216_conv_context(&ci16.ConvCtxt, &ci32.ConvCtxt);

    memcpy(lpConvInfo, &ci16, lpConvInfo->cb);
    return lpConvInfo->cb;
}
Esempio n. 3
0
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : MyDisconnect()                                             *
 *                                                                          *
 *  PURPOSE    : Disconnects the given conversation after updating the      *
 *               associated conversation window.                            *
 *                                                                          *
 *  RETURNS    : TRUE on success, FALSE on failuer.                         *
 *                                                                          *
 ****************************************************************************/
BOOL MyDisconnect(
HCONV hConv)
{
    CONVINFO ci;
    HWND hwnd;
    // before we disconnect, invalidate the associated list window - if
    // applicable.

    ci.cb = sizeof(CONVINFO);
    
    if (DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci) && ci.hConvList &&
            (hwnd = FindListWindow(ci.hConvList)))
        InvalidateRect(hwnd, NULL, TRUE);
    return(DdeDisconnect(hConv));
}
Esempio n. 4
0
HDDEDATA CALLBACK Application::DdeCallback( 
	UINT uType,       // transaction type 
	UINT uFmt,        // clipboard data format 
	HCONV hconv,      // handle to conversation 
	HSZ hsz1,         // handle to string 
	HSZ hsz2,         // handle to string 
	HDDEDATA hdata,   // handle to global memory object 
	DWORD dwData1,    // transaction-specific data 
	DWORD dwData2    // transaction-specific data 
)
{
#ifdef _DEBUG
	WCHAR sz1[256];
	g_ddeInst->QueryString(hsz1, sz1, _countof(sz1));

	WCHAR sz2[256];
	g_ddeInst->QueryString(hsz2, sz2, _countof(sz2));
#endif

    switch (uType)
    {
	case XTYP_CONNECT:
		{
			bool clientIsServer = !!dwData2;

			if (hsz2 == Application::dde_service_name && hsz1 == Application::dde_system)
			{
				return (HDDEDATA)TRUE;
			}

           return (HDDEDATA) NULL; 
		}
		break;

	case XTYP_CONNECT_CONFIRM:
		{
			HCONV hConversation = hconv;
			bool clientIsServer = !!dwData2;
			// no return value
			return 0;
		}
		break;

        case XTYP_REGISTER: 
        case XTYP_UNREGISTER: 
			//
            return (HDDEDATA) NULL; 
 
        case XTYP_ADVDATA: 
			//
            return (HDDEDATA) DDE_FACK; 
 
        case XTYP_XACT_COMPLETE: 
            
            // 
            
            return (HDDEDATA) NULL; 
 
        case XTYP_DISCONNECT:
			{
            
				CONVINFO convinfo;
				convinfo.cb = sizeof(convinfo);
				UINT nbytes = DdeQueryConvInfo(hconv, QID_SYNC, &convinfo);
            // 
            
				return (HDDEDATA) NULL; 
			}

		case XTYP_EXECUTE:
			{
				// free datahandle
				DdeDataHandle data(hdata);	// done in dtor
				DWORD size = data.GetSize();

				byte buffer[4096];
				DWORD cb = data.GetData(buffer, sizeof(buffer));
				WCHAR* str = (WCHAR*)buffer;

				Gui::Application::get_Current()->DdeExecute(str);
				/*
				if (!wcsncmp(str, "Open"))
				{
					return (HDDEDATA)DDE_FACK;
				}
				else
				*/
				return (HDDEDATA)DDE_FACK;
			}
			break;

        default: 
            return (HDDEDATA) NULL; 
    } 
}
Esempio n. 5
0
HDDEDATA W_CALLBACK KapDDECallBack(WORD wTran, WORD wFmt, HCONV hConv,
				   HSZ hsz1, HSZ hsz2, HDDEDATA hData,
				   DWORD dwData1, DWORD dwData2)
{
    switch (wTran) {
      case XTYP_ADVSTART:
      case XTYP_ADVSTOP:
      {
          BOOL bRes = FALSE;
    
          if (wFmt == CF_TEXT)
          {
              char *cl;
              
              if (!DdeQueryString(dwDDEInst, hsz2, return_buffer, 
                                  RET_BUFFER_LEN, CP_WINANSI))
                  return (HDDEDATA) FALSE;
              
              cl = strchr(return_buffer, ':');
              if (cl)
              {
                  DDEINFO ddeInfo;
                  ATOMID idName;
                  WORD wType;
                  
                  cl[0] = '\0';
                  idName = KppAddAtom(return_buffer);
                  ddeInfo.idSlot = KppAddAtom(cl + 1);
                  ddeInfo.idObj = KppGetObjectId(idName, &wType);
                  ddeInfo.idApp = ddeInfo.idItem = NULLID;
                  ddeInfo.idTopic = HszToAtom(hsz1);
                  ddeInfo.hConv = hConv;
                  
                  if (ddeInfo.idObj)
                  {
                      UnwindProtect(cleanup1);
                      requests++;
                      switch (wTran) {
                        case XTYP_ADVSTART:
                            if (CreateLink(&ddeInfo))
                                bRes = TRUE;
                            break;
                        case XTYP_ADVSTOP:
                            if (CloseServerLink(&ddeInfo, idName))
                                bRes = TRUE;
                            break;
                      }
                    cleanup1:
                      requests--;
                      EndProtect();
                  }
              }
          }

          return (HDDEDATA) bRes;                  
      }

      case XTYP_EXECUTE:
      {
          DWORD dwLen;
          LPBYTE lpByte = DdeAccessData(hData, &dwLen);
          
          if (lpByte)
          {
              BOOL bFree = FALSE;
              LPBYTE lpCopy;

              if (dwLen < RET_BUFFER_LEN)
              {
                  strcpy(return_buffer, lpByte);
                  lpCopy = return_buffer;
              }
              else
              {
                  lpCopy = strdup(lpByte);
                  bFree = TRUE;
              }
              DdeUnaccessData(hData);
          
              if (lpCopy)
              {
                  UnwindProtect(cleanup2);
                  requests++;
                  if (!KppEvalExpString(lpCopy))
                      KppPostKappaErrorMessageCB();
                cleanup2:
                  requests--;
                  if (bFree)
                      free(lpCopy);
                  EndProtect();
                  
                  return (HDDEDATA) DDE_FACK;
              }
          }
           
          return (HDDEDATA) DDE_FNOTPROCESSED;
      }
          
      case XTYP_CONNECT:
          if (DdeQueryString(dwDDEInst, hsz1, return_buffer, 
                             RET_BUFFER_LEN, CP_WINANSI))
          {
              char *dot = strrchr(return_buffer, '.');

              if (dot)
                  dot[0] = '\0';
              
              if (!stricmp(DDETopicName, return_buffer) ||
#ifdef MULTI
                  !stricmp(DDEKappaName, return_buffer) ||
                  S_ILOC == 0 &&
#endif
                  !stricmp("KAPPA", return_buffer))
                  return TRUE;
          }
          
          return (HDDEDATA) FALSE;
          
      case XTYP_DISCONNECT:
          UnwindProtect(cleanup3);
          requests++;
          DeleteDDETasks(hConv);
        cleanup3:
          requests--;
          EndProtect();
          return (HDDEDATA) NULL;
          
      case XTYP_WILDCONNECT:
      {
          HSZPAIR hszPair[3];
              
          hszPair[0].hszSvc = 
              DdeCreateStringHandle(dwDDEInst, DDEAppName, CP_WINANSI);
          hszPair[0].hszTopic = 
              DdeCreateStringHandle(dwDDEInst, DDETopicName, CP_WINANSI);
          hszPair[1].hszSvc = 
              DdeCreateStringHandle(dwDDEInst, DDEAppName, CP_WINANSI);
          hszPair[1].hszTopic = 
              DdeCreateStringHandle(dwDDEInst, DDEKappaName, CP_WINANSI);
          hszPair[2].hszSvc = hszPair[2].hszTopic = NULL;
          
          return DdeCreateDataHandle(dwDDEInst, (LPVOID) hszPair,
                                     sizeof(HSZPAIR) * 3, 0, 
                                     hszPair[0].hszSvc, CF_TEXT, 0);
      }
          
      case XTYP_POKE:
      {
          UINT flag = DDE_FNOTPROCESSED;
          
          if (wFmt == CF_TEXT &&
              DdeQueryString(dwDDEInst, hsz2, return_buffer, 
                             RET_BUFFER_LEN, CP_WINANSI))              
          {
              ATOMID idSlot;
              OBJECTID idObj;
              
              UnwindProtect(cleanup4);
              requests++;
              idObj = ObjSlotFromItem(return_buffer, &idSlot);
              if (idObj && StoreData(lpIDs->idNull, hData, idObj, idSlot))
                  flag = DDE_FACK;
            cleanup4:
              requests--;
              EndProtect();
          }

          return (HDDEDATA) flag;
      }
          
      case XTYP_REQUEST:
      case XTYP_ADVREQ:
          hData = (HDDEDATA) DDE_FNOTPROCESSED;
          if (wFmt == CF_TEXT &&
              DdeQueryString(dwDDEInst, hsz2, return_buffer, 
                             RET_BUFFER_LEN, CP_WINANSI))              
          {
              ATOMID idSlot;
              OBJECTID idObj;
              
              UnwindProtect(cleanup5);
              requests++;
              idObj = ObjSlotFromItem(return_buffer, &idSlot);
              if (idObj)
              {
                  BOOL bMulti = FALSE;
                  ITEMID idValue =
                      Kpp_Get_SlotAnyValue(OBJECT_TYPE(idObj),
                                           idObj, idSlot, (LPWORD) &bMulti);
                  GLOBALHANDLE hMem = NULL;
                  LPBYTE lpBytes = NULL;
                  DWORD dwLen = ValueToString(idValue, bMulti, 
                                              &hMem, &lpBytes);
                  
                  if (dwLen)
                  {
                      hData = DdeCreateDataHandle(dwDDEInst, lpBytes, dwLen,
                                                  0, hsz2, CF_TEXT, 0);
                      if (hMem)
                      {
                          GLOBALUNLOCK(hMem);
                          GLOBALFREE(hMem);
                      }
                      if (!hData)
                          hData = (HDDEDATA) DDE_FNOTPROCESSED;
                  }
              }
            cleanup5:
              requests--;
              EndProtect();
          }
          return hData;              
        
      case XTYP_REGISTER:
      {
          ATOMID idApp = HszToAtom(hsz2);
          
          UnwindProtect(cleanup6);
          requests++;
          if (idApp)
          {
              WORD wType;
              OBJECTID idService = KppGetObjectId(idApp, &wType);
              
              if (!idService)
              {
                  idService = KppMakeCO(OBJECT, idApp, idDDEService);
                  wType = OBJECT;
              }
              if (idService)
              {
                  if (DdeQueryString(dwDDEInst, hsz1, return_buffer, 
                                     RET_BUFFER_LEN, CP_WINANSI))
                      Kpp_Set_SlotValue(wType, idService, Slot(idService),
                                        KppAddAtom(return_buffer), EXPATOM);
                  else
                      Kpp_Set_SlotValue(wType, idService, Slot(idService),
                                        lpIDs->idNull, EXPATOM);
              }
          }
        cleanup6:
          requests--;
          EndProtect();
          
          return (HDDEDATA) NULL;
      }
        
      case XTYP_ADVDATA:
          UnwindProtect(cleanup7);
          requests++;
          if (wFmt == CF_TEXT)
          {
              CONVINFO ci;
              ATOMID idApp, idItem, idName;
              OBJECTID idLink;
              
              memset(&ci, 0, sizeof(CONVINFO));
              ci.cb = sizeof(CONVINFO);
              DdeQueryConvInfo(hConv, QID_SYNC, &ci);
              idApp = HszToAtom(ci.hszSvcPartner);
              idItem = HszToAtom(hsz2);
              idName = LinkName(idApp, idItem);
              idLink = FindLink(idName);
              
              if (idLink)
              {
                  WORD wDestType;
                  ATOMID idDest = Kpp_Get_SlotValue(OBJECT, idLink,
                                                    Slot(idDDEObject));
                  ATOMID idSlot = Kpp_Get_SlotValue(OBJECT, idLink,
                                                    Slot(idDDESlot));
                  OBJECTID idDestObj = KppGetObjectId(idDest, &wDestType);
              
                  StoreData(lpIDs->idNull, hData, idDestObj, idSlot);
              }
          }
        cleanup7:
          requests--;
          EndProtect();
          
          return (HDDEDATA) DDE_FACK;
          
      case XTYP_XACT_COMPLETE:
      {
          char name[20];
          OBJECTID idTask;
          ATOMID idName;
          WORD wType;
          
          UnwindProtect(cleanup8);
          requests++;
          task_name(name, hConv, dwData1);
          idName = KppAddAtom(name);
          idTask = KppGetObjectId(idName, &wType);
          
          if (idTask)
          {
              CONVINFO ci;

              memset(&ci, 0, sizeof(CONVINFO));
              ci.cb = sizeof(CONVINFO);
              DdeQueryConvInfo(hConv, dwData1, &ci);
          
              switch (ci.wType) {
                case XTYP_REQUEST:
                    if (wFmt == CF_TEXT)
                    {
                        WORD wDestType;
                        ATOMID idDest = Kpp_Get_SlotValue(wType, idTask, 
                                                          Slot(idDDEObject));
                        ATOMID idSlot = Kpp_Get_SlotValue(wType, idTask, 
                                                          Slot(idDDESlot));
                        OBJECTID idDestObj = KppGetObjectId(idDest, 
                                                            &wDestType);
              
                        StoreData(lpIDs->idNull, hData, idDestObj, idSlot);
                        DdeDisconnect(hConv);              
                    }
                    break;
                    
                case XTYP_POKE:
                case XTYP_EXECUTE:
                    DdeDisconnect(hConv);              
                    break;
                    
                case (XTYP_ADVSTART | XTYPF_ACKREQ):
                {
                    ATOMID idDest =
                        Kpp_Get_SlotValue(wType, idTask, Slot(idDDEObject));
                    WORD wDestType;
                    DDEINFO ddeInfo;

                    ddeInfo.hConv = hConv;
                    ddeInfo.idApp = Kpp_Get_SlotValue(wType, idTask, 
                                                      Slot(idService));
                    ddeInfo.idTopic = Kpp_Get_SlotValue(wType, idTask, 
                                                        Slot(idTopic));
                    ddeInfo.idItem = Kpp_Get_SlotValue(wType, idTask, 
                                                       Slot(idItem));
                    ddeInfo.idObj = KppGetObjectId(idDest, &wDestType);
                    ddeInfo.idSlot = Kpp_Get_SlotValue(wType, idTask, 
                                                       Slot(idDDESlot));
              
                    CreateLink(&ddeInfo);
                    break;
                }
              }

              DeleteDDETask(lpIDs->idNull, wType, idTask, (LPVOID) &hConv);
          }
        cleanup8:
          requests--;
          EndProtect();
          
          return (HDDEDATA) NULL;
      }
          
      default:
          return (HDDEDATA) NULL;
    }
}
Esempio n. 6
0
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ProcessTransaction()                                       *
 *                                                                          *
 *  PURPOSE    : Processes synchronous transactions entirely and starts     *
 *               async transactions.  Transaction attempts result in a      *
 *               transaction window being created which displays the state  *
 *               or results of the transaction.  (the callback function     *
 *               updates these windows as it gets calls) Transaction        *
 *               windows stay around until abandoned by the user or until   *
 *               the conversation is disconnected.  Advise Data and Advise  *
 *               Stop transactions are special.  We don't create a new      *
 *               window if the associated advise start transaction window   *
 *               can be found.                                              *
 *                                                                          *
 *  RETURNS    : TRUE  - If successful.                                     *
 *               FALSE - otherwise.                                         *
 *                                                                          *
 ****************************************************************************/
BOOL ProcessTransaction(
XACT *pxact)
{
    CONVINFO ci;
    HWND hwndInfoCtrl = 0;
    
    /* create transaction window to show we tried (except in ADVSTOP case) */
    
    pxact = (XACT *)memcpy(MyAlloc(sizeof(XACT)), (PSTR)pxact, sizeof(XACT));
    ci.cb = sizeof(CONVINFO);
    DdeQueryConvInfo(pxact->hConv, (DWORD)QID_SYNC, &ci); // ci.hUser==hConv
    if (pxact->wType == XTYP_ADVSTOP) {
        hwndInfoCtrl = FindAdviseChild((HWND)ci.hUser, pxact->hszItem,
                pxact->wFmt);
        if (hwndInfoCtrl) {
            SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UL,
                    (DWORD)(LPSTR)Type2String(pxact->wType, pxact->fsOptions));
            DdeFreeStringHandle(idInst, pxact->hszItem);
        }
    }
    /*
     * If we still need to create a transaction window, do so here.
     */
    if (!hwndInfoCtrl) {
        hwndInfoCtrl = CreateXactionWindow((HWND)ci.hUser, pxact);
        if (!hwndInfoCtrl) {
            MyFree(pxact);
            return 0;
        }
        SetFocus(hwndInfoCtrl);
    }
    /*
     * Disable callbacks for this conversation now if the XOPT_DISABLEFIRST
     * option is set.  This tests disabling asynchronous transactions
     * before they are completed.
     */
    if (pxact->fsOptions & XOPT_DISABLEFIRST) 
        DdeEnableCallback(idInst, pxact->hConv, EC_DISABLE);
    /*
     * Adjust the timeout for asynchronous transactions.
     */
    if (pxact->fsOptions & XOPT_ASYNC)
	pxact->ulTimeout = (DWORD)TIMEOUT_ASYNC;

    /*
     * start transaction with DDEML here
     */
    pxact->ret = DdeClientTransaction((LPBYTE)pxact->hDdeData, (DWORD)-1,
            pxact->hConv, pxact->hszItem, pxact->wFmt,
            pxact->wType,
            pxact->ulTimeout, (LPDWORD)&pxact->Result);
            
    /*
     * show return value in transaction window
     */
    wsprintf(szT, "ret=%lx", pxact->ret);
    SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UR, (DWORD)(LPSTR)szT);

    /*
     * show result or ID value in transaction window
     */
    wsprintf(szT, pxact->fsOptions & XOPT_ASYNC ? "ID=%ld" :
            "result=0x%lx", pxact->Result);
    SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LR, (DWORD)(LPSTR)szT);
    
    if ((pxact->fsOptions & XOPT_ASYNC) && pxact->ret) {
        /*
         * asynchronous successful start - link transaction to window.
         */
        DdeSetUserHandle(pxact->hConv, pxact->Result, (DWORD)hwndInfoCtrl);

        /*
         * Abandon started async transaction after initiated if
         * XOPT_ABANDONAFTERSTART is chosen.  This tests the mid-transaction
         * abandoning code.
         */
        if (pxact->fsOptions & XOPT_ABANDONAFTERSTART) 
            DdeAbandonTransaction(idInst, pxact->hConv, pxact->Result);
        /*
         * show actual status
         */
        ci.cb = sizeof(CONVINFO);
        DdeQueryConvInfo(pxact->hConv, pxact->Result, &ci);
        SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LL,
                (DWORD)(LPSTR)State2String(ci.wConvst));
    } else {
        /*
         * Synchronous transactions are completed already so pass on to
         * CompleteTransaction right away.
         */
        CompleteTransaction(hwndInfoCtrl, pxact);
    }
    return TRUE;
}
Esempio n. 7
0
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DdeCallback()                                              *
 *                                                                          *
 *  PURPOSE    : This handles all callbacks from the DDEML.  This handles   *
 *               updating of the associated conversation and any special    *
 *               testing cases such as blocking callbacks etc.              *
 *                                                                          *
 *               For the most part, clients only handle advise data and     *
 *               asynchronous transaction completion here.                  *
 *                                                                          *
 *  RETURNS    : Results vary depending on transaction type.                *
 *                                                                          *
 ****************************************************************************/
HDDEDATA EXPENTRY DdeCallback(
WORD wType,
WORD wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hData,
DWORD lData1,
DWORD lData2)
{
    HWND hwnd;
    CONVINFO ci;
    XACT *pxact;

    if (hConv) {
        /*
         * update conversation status if it changed.
         */
        MYCONVINFO *pmci;
        
        ci.cb = sizeof(CONVINFO);
	if (!DdeQueryConvInfo(hConv,(DWORD) QID_SYNC, &ci) || (!IsWindow((HWND)ci.hUser))) {
            /*
             * This conversation does not yet have a corresponding MDI window
             * or is disconnected.
             */
            return 0;
        }
        if (pmci = (MYCONVINFO *)GetWindowWord((HWND)ci.hUser, 0)) {
            if (pmci->ci.wStatus != ci.wStatus ||
                    pmci->ci.wConvst != ci.wConvst ||
                    pmci->ci.wLastError != ci.wLastError) {
                /*
                 * Things have changed, updated the conversation window.
                 */
                InvalidateRect((HWND)ci.hUser, NULL, TRUE);
            }
            if (ci.wConvst & ST_INLIST) {
                /*
                 * update the associated list window (if any) as well.
                 */
                if (hwnd = FindListWindow(ci.hConvList))
                    InvalidateRect(hwnd, NULL, TRUE);
            }
        }
    }

    /*
     * handle special block on next callback option here.  This demonstrates
     * the CBR_BLOCK feature.
     */
    if (fBlockNextCB && !(wType & XTYPF_NOBLOCK)) {
        fBlockNextCB = FALSE;
        return(CBR_BLOCK);
    }

    /*
     * handle special termination here.  This demonstrates that at any time
     * a client can drop a conversation.
     */
    if (fTermNextCB && hConv && wType != XTYP_DISCONNECT) {
        fTermNextCB = FALSE;
        MyDisconnect(hConv);
        return(0);
    }

    /*
     * Now we begin sort out what to do.
     */
    switch (wType) {
    case XTYP_REGISTER:
    case XTYP_UNREGISTER:
        /*
         * This is where the client would insert code to keep track of
         * what servers are available.  This could cause the initiation
         * of some conversations.
         */
        break;

    case XTYP_DISCONNECT:
        if (fAutoReconnect) {
            /*
             * attempt a reconnection
             */
            if (hConv = DdeReconnect(hConv)) {
                AddConv(ci.hszServiceReq, ci.hszTopic, hConv, FALSE);
                return 0;
            }
        }
        
        /*
         * update conv window to show its new state.
         */
        SendMessage((HWND)ci.hUser, UM_DISCONNECTED, 0, 0);
        return 0;
        break;

    case XTYP_ADVDATA:
        /*
         * data from an active advise loop (from a server)
         */
        Delay(wDelay);
        hwnd = FindAdviseChild((HWND)ci.hUser, hsz2, wFmt);
        if (!IsWindow(hwnd)) {
            PSTR pszItem, pszFmt;
            /*
             * AdviseStart window is gone, make a new one.
             */
            pxact = (XACT *)MyAlloc(sizeof(XACT));
            pxact->wType = wType;
            pxact->hConv = hConv;
            pxact->wFmt = wFmt;
            pxact->hszItem = hsz2;
            DdeKeepStringHandle(idInst, hsz2);
            
            pszItem = GetHSZName(hsz2);
            pszFmt = GetFormatName(wFmt);
            
            hwnd = CreateInfoCtrl(NULL, 
                    (int)SendMessage((HWND)ci.hUser, UM_GETNEXTCHILDX, 0, 0L),
                    (int)SendMessage((HWND)ci.hUser, UM_GETNEXTCHILDY, 0, 0L),
                    200, 100,
                    (HWND)ci.hUser, hInst,
                    Type2String(wType, 0), (LPSTR)pszItem, NULL,
                    NULL, (LPSTR)pszFmt, NULL,
                    ICSTY_SHOWFOCUS, 0, (DWORD)(LPSTR)pxact);
                    
            MyFree(pszFmt);
            MyFree(pszItem);

            if (!IsWindow(hwnd))
                return(DDE_FNOTPROCESSED); 
        }
        if (!hData) {
            /*
             * XTYPF_NODATA case - request the info. (we do this synchronously
             * for simplicity)
             */
            hData = DdeClientTransaction(NULL, 0L, hConv, hsz2, wFmt,
                    XTYP_REQUEST, DefTimeout, NULL);
        }
        if (hData) {
            PSTR pData;
            /*
             * Show incomming data on corresponding transaction window.
             */
            pData = GetTextData(hData);
            SendMessage(hwnd, ICM_SETSTRING, ICSID_CENTER, (DWORD)(LPSTR)pData);
            MyFree(pData);
            DdeFreeDataHandle(hData);
        }
        SendMessage(hwnd, ICM_SETSTRING, ICSID_LL, (DWORD)(LPSTR)"Advised");
        return(DDE_FACK);
        break;
        
    case XTYP_XACT_COMPLETE:
        /*
         * An asynchronous transaction has completed.  Show the results.
         *
         * ...unless the XOPT_BLOCKRESULT is chosen.
         */
        
        ci.cb = sizeof(CONVINFO);
        if (DdeQueryConvInfo(hConv, lData1, &ci) &&
                IsWindow((HWND)ci.hUser) && 
                (pxact = (XACT *)GetWindowWord((HWND)ci.hUser, GWW_WUSER))) {
                
            if (pxact->fsOptions & XOPT_BLOCKRESULT) {
                pxact->fsOptions &= ~XOPT_BLOCKRESULT;
                return(CBR_BLOCK);
            }
            
            pxact->Result = lData2;
            pxact->ret = hData;
            CompleteTransaction((HWND)ci.hUser, pxact);
        }
        break;
    }
}