home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / ddeml / dmgdde.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-22  |  16.2 KB  |  510 lines

  1. /****************************** Module Header ******************************\
  2. * Module Name: DMGDDE.C
  3. *
  4. * This module contains functions used for interfacing with DDE structures
  5. * and such.
  6. *
  7. * Created:  12/23/88    sanfords
  8. *
  9. * Copyright (c) 1988, 1989  Microsoft Corporation
  10. \***************************************************************************/
  11. #include "ddemlp.h"
  12.  
  13. /***************************** Private Function ****************************\
  14. * timeout()
  15. *
  16. * This routine creates a timer for hwndTimeout.  It then runs a modal loop
  17. * which will exit once the WM_TIMER message is received by hwndTimeout.
  18. * hwndTimeout can be any window that doesn't use timers itself with TID_TIMEOUT
  19. * or TID_ABORT since its window proc doesn't need to do
  20. * anything for this to work.  Only the client and server windows use these
  21. * so were cool.
  22. * Only one timeout window is allowed per thread.  This is checked by the
  23. * pai passed in.
  24. *
  25. * Returns fSuccess, ie TRUE if TID_TIMEOUT was received before TID_ABORT.
  26. *
  27. * PUBDOC START
  28. * Synchronous client transaction modal loops:
  29. *
  30. * During Synchronous transactions, a client application will enter a modal
  31. * loop while waiting for the server to respond to the request.  If an
  32. * application wishes to filter messages to the modal loop, it may do so
  33. * by setting a message filter tied to MSGF_DDE.  Applications should
  34. * be aware however that the DDE modal loop processes private messages
  35. * in the WM_USER range, WM_DDE messages, and WM_TIMER messages with timer IDs
  36. * using the TID_ constants defined in ddeml.h.
  37. * These messages must not be filtered by an application!!!
  38. *
  39. * PUBDOC END
  40. *
  41. * History:
  42. *   Created     sanfords    12/19/88
  43. \***************************************************************************/
  44. BOOL timeout(pai, ulTimeout, hwndTimeout)
  45. PAPPINFO pai;
  46. ULONG ulTimeout;
  47. HWND hwndTimeout;
  48. {
  49.     QMSG qmsg;
  50.  
  51.     SemEnter();
  52.     if (pai->hwndTimer) {
  53.         pai->LastError = DMGERR_REENTRANCY;
  54.         AssertF(FALSE, "Recursive timeout call");
  55.         SemLeave();
  56.         return(FALSE);
  57.     }
  58.     pai->hwndTimer = hwndTimeout;
  59.     SemLeave();
  60.  
  61.     WinStartTimer(DMGHAB, hwndTimeout, TID_TIMEOUT, (USHORT)ulTimeout);
  62.  
  63.     WinGetMsg(DMGHAB, &qmsg, (HWND)NULL, 0, 0);
  64.  
  65.     /*
  66.      * stay in modal loop until a timeout happens.
  67.      */
  68.     while (qmsg.hwnd != hwndTimeout ||
  69.             qmsg.msg != WM_TIMER ||
  70.             (LOUSHORT(qmsg.mp1) != TID_TIMEOUT &&
  71.             LOUSHORT(qmsg.mp1) != TID_ABORT)) {
  72.             
  73.         if (!WinCallMsgFilter(DMGHAB, &qmsg, MSGF_DDE))
  74.             WinDispatchMsg(DMGHAB, &qmsg);
  75.             
  76.         WinGetMsg(DMGHAB, &qmsg, (HWND)NULL, 0, 0);
  77.     }
  78.     
  79.     WinStopTimer(DMGHAB, hwndTimeout, TID_TIMEOUT);
  80.     SemEnter();
  81.     pai->hwndTimer = 0;
  82.     SemLeave();
  83.     /*
  84.      * post a callback check incase we blocked callbacks due to being
  85.      * in a timeout.
  86.      */
  87.     WinPostMsg(pai->hwndDmg, UM_CHECKCBQ, (MPARAM)pai, 0L);
  88.     return(LOUSHORT(qmsg.mp1) == TID_TIMEOUT);
  89. }
  90.  
  91.  
  92. /***************************** Private Function ****************************\
  93. *
  94. *  Based on pii, this sends an INITIATE message to either an exact
  95. *  target window (hwndSend), a target frame window (hwndFrame) or to all
  96. *  top level frames (both hwnds are NULL).  It fills in pci info as apropriate.
  97. *  Note that pii->pCC must NOT be NULL and is assumed to be properly set.
  98. *
  99. *  Returns FALSE if SendDDEInit failed.
  100. *  On success pci->ci.xad.state is CONVST_CONNECTED.
  101. *
  102. * History:
  103. *   created 12/21/88        sanfords
  104. \***************************************************************************/
  105. BOOL ClientInitiate(hwnd, pii, pci)
  106. HWND hwnd;
  107. PINITINFO pii;
  108. PCLIENTINFO pci;
  109. {
  110.     BOOL fRet = TRUE;
  111.  
  112.     if (pii->pCC->cb < sizeof(CONVCONTEXT))
  113.         return(FALSE);
  114.         
  115.     SemEnter();
  116.     /*
  117.      * we need to set this info BEFORE we do the synchronous initiate
  118.      * so the INITIATEACK msg is done correctly.
  119.      */
  120.     pci->ci.xad.state = CONVST_INIT1;
  121.     pci->ci.xad.LastError = DMGERR_NO_ERROR;
  122.     pci->ci.hszServerApp = pii->hszAppName;
  123.     pci->ci.hszTopic = pii->hszTopic;
  124.     pci->ci.cc.cb = sizeof(CONVCONTEXT);
  125.     CopyBlock((PBYTE)&pii->pCC->fsContext, (PBYTE)&pci->ci.cc.fsContext,
  126.         sizeof(CONVCONTEXT) - sizeof(USHORT));
  127.     pci->ci.hwndFrame = pii->hwndFrame;
  128.     SemLeave();
  129.     
  130.     fRet = SendDDEInit(hwnd,
  131.             WinIsWindow(DMGHAB, pii->hwndSend) ? pii->hwndSend : pii->hwndFrame,
  132.             pci);
  133.     SemEnter();
  134.     /*
  135.      * If we failed to initiate directly with the server, try the frame.
  136.      */
  137.     if (!fRet && WinIsWindow(DMGHAB, pii->hwndSend) &&
  138.             WinIsWindow(DMGHAB, pii->hwndFrame)) {
  139.         SemLeave();
  140.         fRet = SendDDEInit(hwnd, pii->hwndFrame, pci);
  141.         if (fRet) {
  142.             /*
  143.              * OK, client is locked in so he wont go away on a terminate
  144.              * from a random window. If the new server is not the same
  145.              * window as the origonal, send it a terminate so it can
  146.              * go away nicely.
  147.              */
  148.             if (pii->hwndSend != pci->ci.hwndPartner) 
  149.                 WinSendMsg(pii->hwndSend, WM_DDE_TERMINATE, 0L, 0L);
  150.         }
  151.         SemEnter();
  152.         
  153.     }
  154.     if (!fRet) 
  155.         pci->ci.xad.state = CONVST_NULL;
  156.     else {
  157.         /*
  158.          * successful initiate means we want to keep these around awhile.
  159.          * removed at window closing time.
  160.          */
  161.         IncHszCount(pci->ci.hszServerApp);
  162.         IncHszCount(pci->ci.hszTopic);
  163.     }
  164.     SemLeave();
  165.     return(fRet);
  166. }
  167.  
  168.  
  169.  
  170. /***************************** Private Function ****************************\
  171. * Allocates and sends a WM_DDE_INITIATE message to hwndTo.  Any failures
  172. * cause FALSE to be returned.  If hwndTo is NULL, performs equivalent of
  173. * WinDdeInitiate2().
  174. *
  175. * History:
  176. *   created     12/22/88        sanfords
  177. *   2/2/89  sanfords    added SEG_GETABLE during monitoring.
  178. \***************************************************************************/
  179. BOOL SendDDEInit(hwndFrom, hwndTo, pci)
  180. HWND hwndFrom;
  181. HWND hwndTo;
  182. PCLIENTINFO pci;
  183. {
  184.     PID pidTo;
  185.     TID tid;
  186.     SEL sel;
  187.     PDDEINIT pddeinit;
  188.     HENUM henum;
  189.     ULONG ul;
  190.     USHORT cchApp, cchTopic;
  191.     PSZ pszApp, pszTopic;
  192.     BOOL fEnumerating;  /* set if extra acks are ok */
  193.  
  194.     SemCheckOut();
  195.  
  196.     if (hwndTo == NULL) {
  197.         /*
  198.          * Call on self for all top level frame windows until we are connected.
  199.          * (if enumerating, do em all anyway.)
  200.          */
  201.         fEnumerating = WinQueryWindow(hwndFrom, QW_PARENT, FALSE) !=
  202.                 pci->ci.pai->hwndDmg;
  203.         if (henum = WinBeginEnumWindows(HWND_DESKTOP)) {
  204.             while ((hwndTo = WinGetNextWindow(henum)) &&
  205.                     (fEnumerating || pci->ci.xad.state == CONVST_INIT1)) {
  206.                 if (hwndTo != pci->ci.pai->hwndFrame &&
  207.                         (ul = (ULONG)WinSendMsg(hwndTo, WM_QUERYFRAMEINFO, 0L, 0L)) &&
  208.                         (ul & FI_FRAME))
  209.                     SendDDEInit(hwndFrom, hwndTo, pci);
  210.             }
  211.             WinEndEnumWindows(henum);
  212.         }
  213.         return(TRUE);
  214.     }
  215.     
  216.     if (WinQueryWindowProcess(hwndTo, &pidTo, &tid) == NULL)
  217.         return(FALSE);
  218.  
  219.     SemEnter();
  220.     pszApp = pszFromHsz(pci->ci.hszServerApp, &cchApp);
  221.     pszTopic = pszFromHsz(pci->ci.hszTopic, &cchTopic);
  222.     if (DosAllocSeg(sizeof(DDEINIT) + sizeof(CONVCONTEXT) + cchApp + cchTopic,
  223.                 &sel, SEG_GIVEABLE) != 0) {
  224.         SemLeave();
  225.         return(FALSE);
  226.     }
  227.     pddeinit = MAKEP(sel, 0);
  228.     pddeinit->cb = sizeof(DDEINIT);
  229.     pddeinit->offConvContext = sizeof(DDEINIT);
  230.     pddeinit->pszAppName = (PSZ)pddeinit + sizeof(DDEINIT) + sizeof(CONVCONTEXT);
  231.     pddeinit->pszTopic = pddeinit->pszAppName + cchApp;
  232.     CopyBlock((PBYTE)&pci->ci.cc, (PBYTE)DDEI_PCONVCONTEXT(pddeinit), sizeof(CONVCONTEXT));
  233.     CopyBlock((PBYTE)pszApp, (PBYTE)pddeinit->pszAppName, cchApp);
  234.     CopyBlock((PBYTE)pszTopic, (PBYTE)pddeinit->pszTopic, cchTopic);
  235.     FarFreeMem(hheapDmg, pszApp, cchApp);
  236.     FarFreeMem(hheapDmg, pszTopic, cchTopic);
  237.     SemLeave();
  238.  
  239.     if (DosGiveSeg(sel, pidTo, &sel) != 0) {
  240.         DosFreeSeg(sel);
  241.         return(FALSE);
  242.     }
  243.  
  244.     WinSendMsg(hwndTo, WM_DDE_INITIATE, (MPARAM)hwndFrom, pddeinit);
  245.     if (pidTo != pci->ci.pai->pid)
  246.         DosFreeSeg(sel);
  247.     return(TRUE);
  248. }
  249.  
  250.  
  251.  
  252. /***************************** Private Function ****************************\
  253. *
  254. *  Alocates and fills in a MYDDES. if pai == 0, the MYDDES is considered
  255. * unowned.
  256. *
  257. * History:  created     1/4/89  sanfords
  258. * 10/18/89  sanfords Added hack so that if usFmt==DDEFMT_TEXT and hszItem==0L,
  259. *                    the data and item strings are one.
  260. *                    (This allows for excel EXEC compatibility)
  261. *   2/2/89  sanfords Added GETABLE during monitoring.
  262. *  6/13/90  sanfords Altered to not expand hszItem at this point.
  263. \***************************************************************************/
  264. PDDESTRUCT AllocDDESel(fsStatus, usFmt, hszItem, cbData, pai)
  265. USHORT fsStatus;
  266. USHORT usFmt;
  267. HSZ hszItem;
  268. ULONG cbData;
  269. PAPPINFO pai;
  270. {
  271.     PMYDDES pmyddes = NULL;
  272.     ULONG cbTotal;
  273.     ULONG cchItem;
  274.     SEL sel;
  275.  
  276.     SemEnter();
  277.     cchItem = DdeGetHszString(hszItem, NULL, 0L) + 1L;
  278.  
  279.     /*
  280.      * This hack makes execs conform to EXCELs way.
  281.      */
  282.     if (!hszItem && usFmt == DDEFMT_TEXT)
  283.         cchItem = 0L;
  284.  
  285.     cbTotal = sizeof(MYDDES) + cchItem + cbData + 1;
  286.     if (cbTotal <= 0xFFFF) {
  287.         if (DosAllocSeg((USHORT)cbTotal, &sel, SEG_GIVEABLE) != 0)
  288.             goto allocDdeExit;
  289.     } else {
  290.         if (DosAllocHuge((USHORT)(cbTotal >> 16), (USHORT)cbTotal, &sel,
  291.                 0, SEG_GIVEABLE) != 0)
  292.             goto allocDdeExit;
  293.     }
  294.  
  295.     pmyddes = MAKEP(sel, 0);
  296.     pmyddes->cbData = cbData;
  297.     pmyddes->fsStatus = fsStatus;
  298.     pmyddes->usFormat = usFmt;
  299.     pmyddes->offszItemName = sizeof(MYDDES);
  300.     pmyddes->offabData = sizeof(MYDDES) + (USHORT)cchItem;
  301.     pmyddes->ulRes1 = 0L;
  302.     pmyddes->magic = MYDDESMAGIC;
  303.     pmyddes->hszItem = hszItem;
  304.     pmyddes->pai = pai;
  305.     pmyddes->fs = 0;
  306.     *DDES_PABDATA((PDDESTRUCT)pmyddes) = '\0'; /* in case data is never placed */
  307.     *DDES_PSZITEMNAME((PDDESTRUCT)pmyddes) = '\0';  /* we expand this at post time if necessary */
  308.  
  309. allocDdeExit:
  310.     SemLeave();
  311.     return((PDDESTRUCT)pmyddes);
  312. }
  313.  
  314.  
  315.  
  316.  
  317. /***************************** Private Function ****************************\
  318. * This routine returns the hwnd of a newly created and connected DDE
  319. * client or NULL if failure.
  320. *
  321. * History:  created     1/6/89  sanfords
  322. \***************************************************************************/
  323. HCONV GetDDEClientWindow(hConvList, hwndFrame, hwndSend, hszApp, hszTopic, pCC)
  324. HCONVLIST hConvList;
  325. HWND hwndFrame;
  326. HWND hwndSend;
  327. HSZ hszApp;
  328. HSZ hszTopic;
  329. PCONVCONTEXT pCC;
  330. {
  331.     HCONV hConv;
  332.     INITINFO ii;
  333.     CONVCONTEXT cc;
  334.  
  335.     SemCheckOut();
  336.     
  337.     hConv = WinCreateWindow(hConvList, SZCLIENTCLASS, "", 0L,
  338.             0, 0, 0, 0, (HWND)NULL, HWND_TOP, WID_CLIENT, 0L, 0L);
  339.             
  340.     if (hConv == NULL)
  341.         return(NULL);
  342.         
  343.     ii.hszTopic = hszTopic;
  344.     ii.hszAppName = hszApp;
  345.     ii.hwndSend = hwndSend;
  346.     ii.hwndFrame = hwndFrame;
  347.     if (pCC == NULL) {
  348.         pCC = &cc;
  349.         cc.cb = sizeof(CONVCONTEXT);
  350.         cc.fsContext = 0;
  351.         /*##LATER - may want to use process codepage instead */
  352.         cc.usCodepage = syscc.codepage;
  353.         cc.idCountry = syscc.country;
  354.     }
  355.     if (pCC->usCodepage == 0) 
  356.         pCC->usCodepage = syscc.codepage;
  357.     if (pCC->idCountry == 0) 
  358.         pCC->idCountry = syscc.country;
  359.         
  360.     ii.pCC = pCC;
  361.     WinSendMsg(hConv, UMCL_INITIATE, (MPARAM)&ii, 0L);
  362.     
  363.     if (!((USHORT)WinSendMsg(hConv, UM_QUERY, (MPARAM)Q_STATUS, 0L) &
  364.             ST_CONNECTED)) {
  365.         WinDestroyWindow(hConv);
  366.         return(NULL);
  367.     }
  368.     return(hConv);
  369. }
  370.  
  371.  
  372.  
  373. /***************************** Private Function ****************************\
  374. * This routine institutes a callback directly if psi->fEnableCB is set
  375. * and calls QReply to complete the transaction,
  376. * otherwise it places the data into the queue for processing.
  377. *
  378. * Since hDmgData may be freed by the app at any time once the callback is
  379. * issued, we cannot depend on it being there for QReply.  Therefore we
  380. * save all the pertinant data in the queue along with it.
  381. *
  382. * Returns fSuccess.
  383. *
  384. * History:
  385. *   Created     9/12/89    Sanfords
  386. \***************************************************************************/
  387. BOOL MakeCallback(pai, hConv, hszTopic, hszItem, usFmt, usType, hDmgData,
  388.     msg, fsStatus, hConvClient)
  389. PAPPINFO pai;
  390. HCONV hConv;
  391. HSZ hszTopic;
  392. HSZ hszItem;
  393. USHORT usFmt;
  394. USHORT usType;
  395. HDMGDATA hDmgData;
  396. USHORT msg;
  397. USHORT fsStatus;
  398. HCONV hConvClient;
  399. {
  400.     PCBLI pcbli;
  401.  
  402.     SemEnter();
  403.     
  404.     if (!(pcbli = (PCBLI)NewLstItem(pai->plstCB, ILST_LAST))) {
  405.         pai->LastError = DMGERR_MEMORY_ERROR;
  406.         SemLeave();
  407.         return(FALSE);
  408.     }
  409.     pcbli->hConv = hConv;
  410.     pcbli->hszTopic = hszTopic;
  411.     pcbli->hszItem = hszItem;
  412.     pcbli->usFmt = usFmt;
  413.     pcbli->usType = usType;
  414.     pcbli->hDmgData = hDmgData;
  415.     pcbli->msg = msg;
  416.     pcbli->fsStatus = fsStatus;
  417.     pcbli->hConvPartner = hConvClient;
  418.     
  419.     if (pai->fEnableCB && !pai->hwndTimer) {
  420.         SemLeave();
  421.         WinPostMsg(pai->hwndDmg, UM_CHECKCBQ, (MPARAM)pai, 0L);
  422.     } else
  423.         SemLeave();
  424.     
  425.     return(TRUE);
  426. }
  427.  
  428.  
  429.  
  430. /*************************************************************************\
  431. * Attempts to post a DDE message to hwndTo.  Properly frees up pmyddes
  432. * if afCmd has MDPM_FREEHDATA set.  We do not add pmyddes to the target
  433. * thread list since we assume that will be done at the receiving end
  434. * if necessary.
  435. *
  436. * Returns fSuccess.
  437. *
  438. * 6/12/90 sanfords  Created
  439. * 6/13/90 sanfords  Made it convert hszItem to a string at this point
  440. *                   only if hwndTo is not a local guy.
  441. \*************************************************************************/
  442. BOOL MyDdePostMsg(
  443. HWND hwndTo,
  444. HWND hwndFrom,
  445. USHORT msg,
  446. PMYDDES pmyddes,
  447. PAPPINFO paiFrom,
  448. USHORT afCmd)
  449. {
  450.     PID pid;
  451.     TID tid;
  452.     SEL selR;
  453.     BOOL fRet;
  454.     PFNWP pfnwpTo;
  455.  
  456.     if (!WinQueryWindowProcess(hwndTo, &pid, &tid))
  457.         return FALSE;
  458.  
  459.     pfnwpTo = (PFNWP)WinQueryWindowPtr(hwndTo, QWP_PFNWP);
  460.     if (cMonitor || (pfnwpTo != ServerWndProc && pfnwpTo != ClientWndProc)) {
  461.         /*
  462.          * its not local - expand hszItem if necessary - always
  463.          * expand if a monitor is installed.
  464.          */
  465.         if (CheckSel(SELECTOROF(pmyddes)) >= sizeof(MYDDES) &&
  466.                 pmyddes->magic == MYDDESMAGIC &&
  467.                 pmyddes->hszItem &&
  468.                 !(pmyddes->fs & HDATA_PSZITEMSET)) {
  469.             pmyddes->fs |= HDATA_PSZITEMSET;
  470.             QueryHszName(pmyddes->hszItem, DDES_PSZITEMNAME(pmyddes),
  471.                     pmyddes->offabData - pmyddes->offszItemName);    
  472.         }
  473.     }
  474.     /*
  475.      * Don't try to share seg with ourselves.
  476.      */
  477.     if (paiFrom->pid != pid) {
  478.         selR = SELECTOROF(pmyddes);
  479.         if (DosGiveSeg(SELECTOROF(pmyddes), pid, &selR))
  480.             return FALSE;
  481.         if (afCmd & MDPM_FREEHDATA) 
  482.             FreeData(pmyddes, paiFrom);
  483.     } else {
  484.         /*
  485.          * just remove hData from our thread list
  486.          */
  487.         if (afCmd & MDPM_FREEHDATA && !(pmyddes->fs & HDATA_APPOWNED))
  488.             FindPileItem(paiFrom->pHDataPile, CmpULONG, (PBYTE)&pmyddes,
  489.                     FPI_DELETE);
  490.     }
  491.     fRet = (BOOL)WinPostMsg(hwndTo, msg, (MPARAM)hwndFrom, (MPARAM)pmyddes);
  492.     if (!fRet) {
  493.         /*
  494.          * make sure this is freed if it is supposed to be - this covers
  495.          * the case where the target is of the same process and only
  496.          * these two threads are registered.
  497.          */
  498.         
  499.         tid = paiFrom->tid;
  500.         do {
  501.             if (FindPileItem(paiFrom->pHDataPile, CmpULONG, (PBYTE)&pmyddes,
  502.                     FPI_COUNT))
  503.                 return(FALSE);  /* there is another thread that has this */
  504.             paiFrom = paiFrom->nextThread;
  505.         } while (paiFrom->tid != tid);
  506.         DosFreeSeg(SELECTOROF(pmyddes));
  507.     }
  508.     return(fRet);
  509. }
  510.