/**************************************************************************** * * * 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); }
/****************************************************************** * 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; }
/**************************************************************************** * * * 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)); }
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; } }
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; } }
/**************************************************************************** * * * 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; }
/**************************************************************************** * * * 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; } }