home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / win_sdk / dde / servdde.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-01  |  16.7 KB  |  613 lines

  1. /****************************************************************************
  2.  
  3.     MODULE: SERVDDE.C
  4.  
  5.     PURPOSE: Processes incoming and outgoing DDE messages
  6.  
  7.  
  8. ****************************************************************************/
  9.  
  10. #include "windows.h"
  11.  
  12. #include "dde.h"
  13. #include "server.h"
  14. #include <string.h>
  15.  
  16. #define DEFAULT_ACK_TIME_OUT_MILLISEC 10000
  17. static int nAckTimeOut;
  18.  
  19. static BOOL   bTerminating = FALSE;
  20.  
  21. int  NEAR GetDocIndexGivenName(char*);
  22. int  NEAR GetItemNumber(char*);
  23.  
  24.  
  25.  
  26.  
  27. /****************************************************************************
  28.  
  29.     FUNCTION: DDEWndProc
  30.  
  31.     PURPOSE:  Handles all DDE messages received by the server application.
  32.  
  33. ****************************************************************************/
  34. long FAR PASCAL DDEWndProc(hwnd, message, wParam, lParam)
  35.     HWND      hwnd;
  36.     unsigned  message;
  37.     WORD      wParam;
  38.     LONG      lParam;
  39. {
  40.     switch (message)
  41.     {
  42.  
  43.         case WM_DDE_ACK:
  44.             ServerAcknowledge(hwnd, (HWND)wParam, lParam);
  45.         return (0L);
  46.  
  47.     case WM_TIMER:     /* time out on waiting for ACK in response */
  48.              /* to WM_DDE_DATA sent by this server        */
  49.  
  50.         ServerAcknowledge(hwnd, (HWND)wParam, 0L); /* simulates NACK */
  51.         return (0L);
  52.  
  53.         case WM_DDE_ADVISE:
  54.             ServerAdvise(hwnd, (HWND)wParam, lParam);
  55.         return (0L);
  56.  
  57.         case WM_DDE_POKE:
  58.             ServerPoke(hwnd, (HWND)wParam, lParam);
  59.         return (0L);
  60.  
  61.         case WM_DDE_TERMINATE:
  62.             ServerTerminate(hwnd, (HWND)wParam);
  63.         return (0L);
  64.  
  65.         case WM_DDE_UNADVISE:
  66.             ServerUnadvise(hwnd, (HWND)wParam, lParam);
  67.         return (0L);
  68.  
  69.         case WM_DDE_REQUEST:
  70.             ServerRequest(hwnd, (HWND)wParam, lParam);
  71.         return (0L);
  72.  
  73.     case WM_DDE_EXECUTE:
  74.         ServerExecute(hwnd, (HWND)wParam, (HANDLE)HIWORD(lParam));
  75.         return (0L);
  76.  
  77.     default:
  78.           return (DefWindowProc(hwnd, message, wParam, lParam));
  79.     }
  80. }
  81.  
  82.  
  83.  
  84. /****************************************************************************
  85.  
  86.     FUNCTION: GetItemNumber
  87.  
  88.     PURPOSE:  Get server control i.d. (1, 2, or 3) given item name.
  89.  
  90. ****************************************************************************/
  91. int NEAR GetItemNumber(szItem)
  92.     char * szItem;
  93. {
  94.     int nItem;
  95.  
  96.     if (!strcmpi(szItem, "ITEM1"))
  97.         nItem = 1;
  98.     else if (!strcmpi(szItem, "ITEM2"))
  99.         nItem = 2;
  100.     else if (!strcmpi(szItem, "ITEM3"))
  101.         nItem = 3;
  102.     else
  103.         nItem = 0;
  104.     return (nItem);
  105. }
  106.  
  107.  
  108.  
  109. /****************************************************************************
  110.  
  111.     FUNCTION: InitAckTimeOut
  112.  
  113.     PURPOSE:  Get DDE timeout value from win.ini.  Value is in milliseconds.
  114.  
  115. ****************************************************************************/
  116. void InitAckTimeOut(void)
  117. {
  118.  
  119.    /* Finds value in win.ini section corresponding to application name */
  120.  
  121.    nAckTimeOut = GetPrivateProfileInt("Server",
  122.                    "DdeTimeOut",
  123.                    DEFAULT_ACK_TIME_OUT_MILLISEC,
  124.                                "server.ini");
  125.    return;
  126. }
  127.  
  128.  
  129.  
  130. /****************************************************************************
  131.  
  132.     FUNCTION: SendData
  133.  
  134.     PURPOSE:  Send data to client.
  135.  
  136. ****************************************************************************/
  137. void SendData(hwndServerDDE, hwndClientDDE, szItemName, szItemValue,
  138.                    bDeferUpdate, bAckRequest) 
  139.     HWND  hwndServerDDE;
  140.     HWND  hwndClientDDE;
  141.     char * szItemName;
  142.     char * szItemValue;
  143.     BOOL   bDeferUpdate;
  144.     BOOL   bAckRequest;
  145. {
  146.     ATOM          atomItem;
  147.     HANDLE        hData;
  148.     DDEDATA FAR * lpData;
  149.     int           nItem;
  150.  
  151.     if (bDeferUpdate)
  152.     {
  153.         atomItem = GlobalAddAtom((LPSTR)szItemName);
  154.     /* notify client with null data since advise was set up for */
  155.     /* deferred update                        */
  156.     if (!PostMessage(hwndClientDDE,
  157.                 WM_DDE_DATA,
  158.         hwndServerDDE,
  159.         MAKELONG(0, atomItem)))
  160.         {
  161.             GlobalDeleteAtom(atomItem);
  162.         }
  163.         return;
  164.     }
  165.  
  166.     /* Allocate size of DDE data header, plus the data:  a string,  */
  167.     /* <CR> <LR> <NULL>.  The byte for the string null terminator */
  168.     /* is counted by DDEDATA.Value[1].                   */
  169.  
  170.     if (!(hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 
  171.                   (LONG)sizeof(DDEDATA) +lstrlen(szItemValue) + 2)))
  172.         return;
  173.     if (!(lpData = (DDEDATA FAR*)GlobalLock(hData)))
  174.     {
  175.     GlobalFree(hData);
  176.         return;
  177.     }
  178.  
  179.     lpData->fAckReq = bAckRequest;
  180.     lpData->cfFormat = CF_TEXT;
  181.     lstrcpy((LPSTR)lpData->Value, (LPSTR)szItemValue);
  182.     /* each line of CF_TEXT data is terminated by CR/LF */
  183.     lstrcat((LPSTR)lpData->Value, (LPSTR)"\r\n");
  184.     GlobalUnlock(hData);
  185.     atomItem = GlobalAddAtom((LPSTR)szItemName);
  186.     if (!PostMessage(hwndClientDDE,
  187.             WM_DDE_DATA,
  188.         hwndServerDDE,
  189.             MAKELONG(hData, atomItem)))
  190.     {
  191.         GlobalFree(hData);
  192.         GlobalDeleteAtom(atomItem);
  193.     return;
  194.     }
  195.     if (bAckRequest)
  196.     {
  197.     SetTimer(hwndServerDDE, hwndClientDDE, nAckTimeOut, NULL);
  198.     nItem = GetItemNumber(szItemName);
  199.     /* hData is to be deleted if not read by client for some reason */
  200.     CheckOutSentData(hwndServerDDE, nItem, atomItem, hData);
  201.     }
  202.     return;
  203. }
  204.  
  205.  
  206.  
  207. /****************************************************************************
  208.  
  209.     FUNCTION: SendTerminate
  210.  
  211.     PURPOSE:  Post terminate message and indicate that conversation is
  212.           in process ot being terminated.
  213.  
  214. ****************************************************************************/
  215. void SendTerminate(hwndServerDDE, hwndClientDDE)
  216.     HWND  hwndServerDDE;
  217.     HWND  hwndClientDDE;
  218. {
  219.     SetConvInTerminateState(hwndServerDDE);
  220.     PostMessage(hwndClientDDE, WM_DDE_TERMINATE, hwndServerDDE, 0L);
  221.     return;
  222. }
  223.  
  224.  
  225.  
  226. /****************************************************************************
  227.  
  228.     FUNCTION: ServerAcknowledge
  229.  
  230.     PURPOSE:  Called when server application receives ACK or NACK, or
  231.           when server receives time out waiting for response to
  232.           WM_DDE_DATA.
  233.  
  234. ****************************************************************************/
  235. void ServerAcknowledge(hwndServerDDE, hwndClientDDE, lParam)
  236.     HWND  hwndServerDDE;
  237.     HWND  hwndClientDDE;
  238.     LONG  lParam;
  239. {
  240.     char szItemName[ITEM_NAME_MAX_SIZE+1];
  241.     int  nItem;
  242.  
  243.     KillTimer(hwndServerDDE, hwndClientDDE);
  244.  
  245.     if (!(LOWORD(lParam) & 0x8000))
  246.     {
  247.         GlobalGetAtomName(HIWORD(lParam), szItemName, ITEM_NAME_MAX_SIZE);
  248.         nItem = GetItemNumber(szItemName);
  249.     GlobalFreeSentData(hwndServerDDE, nItem);
  250.     MessageBox(hwndMain,
  251.             "DDE send data failed",
  252.             "Server",
  253.             MB_ICONEXCLAMATION | MB_OK);
  254.     }
  255.     if (HIWORD(lParam))    /* 0 if time-out, so don't try to delete */
  256.     GlobalDeleteAtom(HIWORD(lParam));
  257.     return;
  258. }
  259.  
  260.  
  261.  
  262. /****************************************************************************
  263.  
  264.     FUNCTION: ServerAdvise
  265.  
  266.     PURPOSE:  Called when server application receives WM_DDE_ADVISE message.
  267.  
  268. ****************************************************************************/
  269. void ServerAdvise(hwndServerDDE, hwndClientDDE, lParam)
  270.     HWND  hwndServerDDE;
  271.     HWND  hwndClientDDE;
  272.     LONG  lParam;
  273. {
  274.     HANDLE          hDDEAdviseOptions;
  275.     DDEADVISE FAR * lpDDEAdviseOptions;
  276.     ATOM            atomItem;
  277.     char            szItem[ITEM_NAME_MAX_SIZE+1];
  278.     int             nItem;
  279.  
  280.     hDDEAdviseOptions = LOWORD(lParam);
  281.     atomItem = HIWORD(lParam);
  282.  
  283.     GlobalGetAtomName(atomItem, szItem, ITEM_NAME_MAX_SIZE);
  284.  
  285.     if (!(nItem = GetItemNumber(szItem))
  286.     || !AddAdvise(hwndServerDDE, hDDEAdviseOptions, atomItem, nItem))
  287.     {
  288.     PostMessage(hwndClientDDE,
  289.             WM_DDE_ACK,
  290.         hwndServerDDE,
  291.             MAKELONG(0, atomItem)); /* negative acknowledgement */
  292.         return;
  293.     }
  294.     PostMessage(hwndClientDDE,
  295.         WM_DDE_ACK,
  296.     hwndServerDDE,
  297.         MAKELONG(0x8000, atomItem)); /* positive acknowledgement */
  298.     return;
  299. }
  300.  
  301.  
  302.  
  303. /****************************************************************************
  304.  
  305.     FUNCTION: ServerExecute
  306.  
  307.     PURPOSE:  Called when server application receives WM_DDE_EXECUTE message.
  308.  
  309. ****************************************************************************/
  310. void ServerExecute(hwndServerDDE, hwndClientDDE, hCommand)
  311.     HWND    hwndServerDDE;
  312.     HWND    hwndClientDDE;
  313.     HANDLE  hCommand;
  314. {
  315.     LPSTR   lpstrCommand;
  316.     char    szExecuteString[EXECUTE_STRING_MAX_SIZE+1];
  317.  
  318.     if (!(lpstrCommand = GlobalLock(hCommand)))
  319.     {
  320.     PostMessage(hwndClientDDE,
  321.             WM_DDE_ACK,
  322.         hwndServerDDE,
  323.         MAKELONG(0, hCommand)); /* negative acknowledgement */
  324.         return;
  325.     }
  326.     if (lstrlen(lpstrCommand) > EXECUTE_STRING_MAX_SIZE)
  327.     lpstrCommand[EXECUTE_STRING_MAX_SIZE] = 0;
  328.     lstrcpy(szExecuteString, lpstrCommand);
  329.     GlobalUnlock(hCommand);
  330.     PostMessage(hwndClientDDE,
  331.     WM_DDE_ACK,
  332.     hwndServerDDE,
  333.     MAKELONG(0x8000, hCommand)); /* positive acknowledgement */
  334.  
  335.     MessageBox(hwndMain,
  336.     szExecuteString,
  337.     "Server Received Execute Command",
  338.     MB_OK);
  339.     return;
  340. }
  341.  
  342.  
  343.  
  344.  
  345. /****************************************************************************
  346.  
  347.     FUNCTION: ServerInitiate
  348.  
  349.     PURPOSE:  Called when server application receives WM_DDE_INITIATE message.
  350.  
  351. ****************************************************************************/
  352. void ServerInitiate(hwndClientDDE, lParam)
  353.     HWND  hwndClientDDE;
  354.     LONG  lParam;
  355. {
  356.     HWND  hwndServerDDE;
  357.     ATOM  atomApplicationRcvd;
  358.     ATOM  atomTopicRcvd;
  359.     ATOM  atomApplicationReturn;
  360.     ATOM  atomTopicReturn;
  361.     char  szApplication[APP_MAX_SIZE+1];
  362.     char  szTopic[TOPIC_MAX_SIZE+1];
  363.  
  364.     if (!(hwndServerDDE = CreateWindow(
  365.         "ServerDDEWndClass",
  366.         "ServerDDE",
  367.         WS_CHILD,    /* not visible */
  368.         0, 0, 0, 0, /* no position or dimensions */
  369.         hwndMain,    /* parent */
  370.         NULL,    /* no menu */
  371.         hInst,
  372.         NULL)))
  373.     {
  374.     return;
  375.     }
  376.  
  377.     if (atomApplicationRcvd = LOWORD(lParam))
  378.         GlobalGetAtomName(atomApplicationRcvd, szApplication, APP_MAX_SIZE);
  379.     if (atomApplicationRcvd && strcmpi(szApplication,"SERVER"))
  380.     { /* if application was specified but it wasn't "server" */
  381.         return; 
  382.     }
  383.     if (atomTopicRcvd = HIWORD(lParam))
  384.     {
  385.         GlobalGetAtomName(atomTopicRcvd, szTopic, TOPIC_MAX_SIZE);
  386.         if (strcmpi(szTopic, szDocName))
  387.             return;
  388.     }
  389.     if (AddConv(hwndServerDDE, hwndClientDDE))
  390.     {
  391.         atomApplicationReturn = GlobalAddAtom("SERVER");
  392.         atomTopicReturn = GlobalAddAtom(szDocName);
  393.     if (!SendMessage(hwndClientDDE,
  394.                 WM_DDE_ACK, 
  395.         hwndServerDDE,
  396.                 MAKELONG(atomApplicationReturn, atomTopicReturn)))
  397.         {
  398.             GlobalDeleteAtom(atomApplicationReturn);
  399.             GlobalDeleteAtom(atomTopicReturn);
  400.         }
  401.     }
  402.     return;
  403. }
  404.  
  405.  
  406.  
  407. /****************************************************************************
  408.  
  409.     FUNCTION: ServerPoke
  410.  
  411.     PURPOSE:  Called when server application receives WM_DDE_POKE message.
  412.  
  413. ****************************************************************************/
  414. void ServerPoke(hwndServerDDE, hwndClientDDE, lParam)
  415.     HWND  hwndServerDDE;
  416.     HWND  hwndClientDDE;
  417.     LONG  lParam;
  418. {
  419.     HANDLE        hPokeData;
  420.     DDEPOKE FAR * lpPokeData;
  421.     ATOM          atomItem;
  422.     int           nItem;
  423.     char          szItemName[ITEM_NAME_MAX_SIZE+1];
  424.     char          szItemValue[ITEM_VALUE_MAX_SIZE+1];
  425.     BOOL          bRelease;
  426.     char        * pcCarriageReturn;
  427.  
  428.  
  429.     hPokeData = LOWORD(lParam);
  430.     atomItem = HIWORD(lParam);
  431.     
  432.     GlobalGetAtomName(atomItem, szItemName, ITEM_NAME_MAX_SIZE);
  433.     if (!(lpPokeData = (DDEPOKE FAR *)GlobalLock(hPokeData))
  434.         || lpPokeData->cfFormat != CF_TEXT
  435.         || !(nItem = GetItemNumber(szItemName)))
  436.     {
  437.     PostMessage(hwndClientDDE,
  438.            WM_DDE_ACK, 
  439.        hwndServerDDE,
  440.            MAKELONG(0, atomItem)); /* negative acknowledgement */
  441.     return;
  442.     }
  443.  
  444.     lstrcpy(szItemValue, lpPokeData->Value);
  445.     if (pcCarriageReturn = strchr(szItemValue, '\r')) 
  446.         *pcCarriageReturn = 0;  /* remove CR/LF */
  447.     SetDlgItemText(hwndMain, nItem, szItemValue);
  448.     MaybeAdviseData(nItem);
  449.  
  450.     /* Save value of fRelease, since pointer may be invalidated by */
  451.     /*    GlobalUnlock()                          */
  452.     bRelease = lpPokeData->fRelease;
  453.     GlobalUnlock(hPokeData);
  454.  
  455.     if (bRelease)
  456.     {
  457.         GlobalFree(hPokeData);
  458.     }
  459.  
  460.     /* Since we are re-using the item atom, we should not delete it */
  461.     /* if PostMessage fails:  the client should delete the atom     */
  462.     /* when it gets a time-out on the expected ACK.            */
  463.     PostMessage(hwndClientDDE,
  464.     WM_DDE_ACK,
  465.     hwndServerDDE,
  466.     MAKELONG(0x8000, atomItem));  /* positive acknowledgement */
  467.     return;
  468. }
  469.  
  470.  
  471.  
  472. /****************************************************************************
  473.  
  474.     FUNCTION: ServerRequest
  475.  
  476.     PURPOSE:  Called when server application receives WM_DDE_REQUEST message.
  477.  
  478. ****************************************************************************/
  479. void ServerRequest(hwndServerDDE, hwndClientDDE, lParam)
  480.     HWND  hwndServerDDE;
  481.     HWND  hwndClientDDE;
  482.     LONG  lParam;
  483. {
  484.     char szItem[ITEM_NAME_MAX_SIZE+1];
  485.     char szItemValue[ITEM_VALUE_MAX_SIZE+1];
  486.     int  nItem;
  487.  
  488.     GlobalGetAtomName(HIWORD(lParam), szItem, ITEM_NAME_MAX_SIZE);
  489.     if (!(nItem = GetItemNumber(szItem))
  490.     || (LOWORD(lParam) != CF_TEXT)) /* this app supports only CF_TEXT */
  491.     {
  492.     PostMessage(hwndClientDDE,
  493.             WM_DDE_ACK,
  494.         hwndServerDDE,
  495.             MAKELONG(0, HIWORD(lParam))); /* NACK */
  496.         return;
  497.     }
  498.     if (!GetDlgItemText(hwndMain, nItem, szItemValue, ITEM_VALUE_MAX_SIZE))
  499.     {
  500.     strcpy(szItemValue," ");
  501.     }
  502.     /* send now, don't defer, and don't ask for ACK */
  503.     SendData(hwndServerDDE, hwndClientDDE, szItem, szItemValue, FALSE, FALSE);
  504.     GlobalDeleteAtom(HIWORD(lParam));
  505.     return;
  506. }
  507.  
  508.  
  509. /****************************************************************************
  510.  
  511.     FUNCTION: ServerTerminate
  512.  
  513.     PURPOSE:  Called when server application receives WM_DDE_TERMINATE message.
  514.  
  515. ****************************************************************************/
  516. void ServerTerminate(hwndServerDDE, hwndClientDDE)
  517.     HWND  hwndServerDDE;
  518.     HWND  hwndClientDDE;
  519. {
  520.  
  521.     if (!IsConvInTerminateState(hwndClientDDE))
  522.     { /* Client has requested terminate: respond with terminate */
  523.     PostMessage(hwndClientDDE, WM_DDE_TERMINATE, hwndServerDDE, 0L);
  524.     }
  525.  
  526.     RemoveConv(hwndServerDDE);
  527.     DestroyWindow(hwndServerDDE);
  528.     return;
  529. }
  530.  
  531.  
  532.  
  533. /****************************************************************************
  534.  
  535.     FUNCTION: ServerUnadvise
  536.  
  537.     PURPOSE:  Called when server application receives WM_DDE_UNADIVSE message.
  538.  
  539. ****************************************************************************/
  540. void ServerUnadvise(hwndServerDDE, hwndClientDDE, lParam)
  541.     HWND  hwndServerDDE;
  542.     HWND  hwndClientDDE;
  543.     LONG  lParam;
  544. {
  545.     char szItem[ITEM_NAME_MAX_SIZE+1];
  546.     int  nItem;
  547.     BOOL bSuccess;
  548.    
  549.     if (HIWORD(lParam))
  550.     {
  551.         GlobalGetAtomName(HIWORD(lParam), szItem, ITEM_NAME_MAX_SIZE);
  552.         nItem = GetItemNumber(szItem);
  553.     bSuccess = RemoveAdvise(hwndServerDDE, nItem);
  554.     }
  555.     else
  556.     {   /* HIWORD(lParam)==0 means remove all advises */   
  557.     bSuccess = RemoveAdvise(hwndServerDDE, 0);
  558.     }
  559.     if (bSuccess)
  560.     {
  561.     PostMessage(hwndClientDDE,
  562.             WM_DDE_ACK, 
  563.         hwndServerDDE,
  564.             MAKELONG(0x8000, HIWORD(lParam))); /* positive ack */
  565.     }
  566.     else
  567.     {
  568.     PostMessage(hwndClientDDE,
  569.             WM_DDE_ACK, 
  570.         hwndServerDDE,
  571.             MAKELONG(0, HIWORD(lParam))); /* negative ack */
  572.     }
  573.     return;
  574. }
  575.  
  576. /****************************************************************************
  577.  
  578.     FUNCTION: TerminateConversations
  579.  
  580.     PURPOSE:  Processes WM_DESTROY message, terminates all conversations.
  581.  
  582. ****************************************************************************/
  583. void TerminateConversations()
  584. {
  585.    HWND  hwndServerDDE;
  586.    LONG  lTimeOut;
  587.    MSG   msg;
  588.  
  589.  
  590.    /* Terminate each active conversation */
  591.    hwndServerDDE = NULL;
  592.    while (hwndServerDDE = GetNextConv(hwndServerDDE))
  593.    {
  594.     SendTerminate(hwndServerDDE, GetHwndClientDDE(hwndServerDDE));
  595.    }
  596.  
  597.    /* Wait for all conversations to terminate OR for time out */
  598.    lTimeOut = GetTickCount() + (LONG)nAckTimeOut;
  599.    while (PeekMessage(&msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE))
  600.    {
  601.          DispatchMessage (&msg);
  602.      if (msg.message == WM_DDE_TERMINATE)
  603.      {
  604.          if (!AtLeastOneConvActive())
  605.          break;
  606.      }
  607.          if (GetTickCount() > lTimeOut)
  608.              break;
  609.    }
  610.  
  611.    return;
  612. }
  613.