home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 11 / 11.iso / m / m248 / 4.ddi / EDIT.C_ / EDIT.C
Encoding:
C/C++ Source or Header  |  1993-02-01  |  11.8 KB  |  516 lines

  1. /*
  2.  
  3.     EDIT.C -- Sample Application DDE Server
  4.     Copyright 1987-1991 Authorware Inc.
  5.   
  6.     Revision History
  7.  
  8.         7/25/91    -    Initial version
  9.  
  10.  
  11.     General notes:
  12.  
  13.         This application is a sample server application for demonstrating a
  14.         DDE converstation with APW.  The server only handles cold link DDE
  15.         communication.  
  16.  
  17.             The application name is APWServer
  18.             The topic name is            EditInfo
  19.             The item name is            EI
  20.  
  21.         This is the only topic and item supported by this server.  The data that
  22.         is generated by this request is the text from the edit control which
  23.         covers the client area of the main window.  The server can handle 
  24.         multiple clients at one time (each DDE link is given its own window and
  25.         the client window handle is stored in the extra bytes at the end of
  26.         the window handle).
  27.  
  28.         For information on DDE see:
  29.  
  30.             Microsoft (R) Windows SDK 3.0
  31.             Reference Manual Volume 2
  32.  
  33.             Programming for Windows by Charles Petzold 
  34.             Microsoft Press (R)
  35.             Second Edition.
  36.             
  37. */
  38. #include <string.h>
  39. #include "windows.h"
  40. #include "dde.h"
  41. #include "edit.h"
  42.  
  43. #define DDE_TIMEOUT    3000
  44.  
  45. // Defines for cbWndExtra bytes on the window class.
  46. #define CLIENTWND        0        // Handle to the client window
  47.  
  48. #define VALID_WINDOW(w) ((w) && IsWindow(w))    // Make NULL an invalid window
  49.  
  50. // Static globals
  51. static char    szServerClass[]     = "edit.server";        // class name
  52. static char    szMenu[]                = "EditCntlMenu";        // menu name
  53. static HANDLE hInst                = 0;                        // instance handle
  54. static HWND hEditWnd                = 0;                        // handle to edit window
  55. static HWND hWndMain                = 0;                        // handle to main window
  56.  
  57.  
  58. // Server Communication variables for the APPLICATION, TOPIC and ITEM supported
  59. static char    APWServer[]            = "APWServer";
  60. static char szTopic[]            = "EditInfo";
  61. static char szItem[]                = "EI";
  62.  
  63. static BOOL NEAR PASCAL DDERequest( HWND server, HWND client, WORD cfFormat, ATOM aItem );
  64. static BOOL NEAR PASCAL DDEInitialize( HWND parent, HWND client, ATOM a, ATOM t );
  65. static BOOL NEAR PASCAL DDEPostDataMessage(HWND server, HWND client );
  66. static BOOL NEAR PASCAL InitInstance( HANDLE hInstance, short nCmdShow );
  67. static BOOL NEAR PASCAL InitApplication( HANDLE hInstance );
  68.          long FAR  PASCAL ServerProc( HWND hWnd, WORD message, WORD wParam, LONG lParam );
  69.          BOOL FAR  PASCAL About( HWND hDlg, unsigned message, WORD wParam, LONG lParam);
  70.          long FAR  PASCAL MainWndProc( HWND hWnd, unsigned message, WORD wParam, LONG lParam);
  71.          int  FAR  PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, short nCmdShow);
  72.  
  73.  
  74. int FAR PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, short nCmdShow)
  75. /*
  76.     Application entry point.  Does initialization and the main event loop.
  77. */
  78. {
  79.     MSG msg;
  80.     FARPROC    fp;
  81.  
  82.     // Initialize only for the first instance
  83.     if (!hPrevInstance)
  84.         if (!InitApplication(hInstance))
  85.             return 0;
  86.  
  87.     // Initialize every instance
  88.     if (!InitInstance(hInstance, nCmdShow))
  89.         return 0;
  90.  
  91.     // Main message loop
  92.     while (GetMessage(&msg, NULL, NULL, NULL)) 
  93.     {
  94.         TranslateMessage(&msg);
  95.         DispatchMessage(&msg); 
  96.     }
  97.  
  98.     return msg.wParam;
  99. }
  100.  
  101.  
  102. static BOOL NEAR PASCAL InitApplication( HANDLE hInstance )
  103. /*
  104.     Initialization for the first instance of the application.
  105.  
  106.     Returns:
  107.  
  108.         TRUE    - success
  109.         FALSE - failure
  110. */
  111. {
  112.     WNDCLASS    wc;
  113.  
  114.  
  115.     // Main window class
  116.     wc.style              =    NULL;
  117.     wc.lpfnWndProc      =    MainWndProc;
  118.     wc.cbClsExtra      =    0;
  119.     wc.cbWndExtra      =    0;
  120.     wc.hInstance          =    hInstance;
  121.     wc.hIcon              =    LoadIcon(NULL, IDI_APPLICATION);
  122.     wc.hCursor          =    LoadCursor(NULL, IDC_ARROW);
  123.     wc.hbrBackground  =    GetStockObject(WHITE_BRUSH); 
  124.     wc.lpszMenuName     =    szMenu;
  125.     wc.lpszClassName  =    APWServer;
  126.  
  127.     if (RegisterClass(&wc) == 0)
  128.         return FALSE;
  129.  
  130.  
  131.     /*
  132.         Server window class. The Extra bytes at the end of the window contain
  133.         the client window handle.
  134.     */
  135.     wc.lpfnWndProc      =    ServerProc;
  136.     wc.cbWndExtra      =    sizeof (short);
  137.     wc.hIcon              =    NULL;
  138.     wc.hCursor          =    NULL;
  139.     wc.hbrBackground  =    NULL;
  140.     wc.lpszMenuName     =    NULL;
  141.     wc.lpszClassName  =    szServerClass;
  142.  
  143.     if (RegisterClass(&wc) == 0)
  144.         return FALSE;
  145.  
  146.     return TRUE;
  147. }
  148.  
  149.  
  150. static BOOL NEAR PASCAL InitInstance( HANDLE hInstance, short nCmdShow )
  151. /*
  152.     Main initialization routine for every instance of the application.
  153.  
  154.     Returns:
  155.  
  156.         TRUE    - success
  157.         FALSE - failure
  158. */
  159. {
  160.     RECT                Rect;
  161.  
  162.     hInst = hInstance;
  163.  
  164.     // Create the main window
  165.     hWndMain = CreateWindow(APWServer,
  166.         "Sample Server Window for APW",
  167.         WS_OVERLAPPEDWINDOW,
  168.         CW_USEDEFAULT,
  169.         CW_USEDEFAULT,
  170.         CW_USEDEFAULT,
  171.         CW_USEDEFAULT,
  172.         NULL,
  173.         NULL,
  174.         hInstance,
  175.         NULL);
  176.  
  177.     if (!hWndMain)
  178.         return FALSE;
  179.  
  180.     GetClientRect(hWndMain, (LPRECT) &Rect);
  181.  
  182.     // Create a child edit window the size of the client rect of the main window
  183.     hEditWnd = CreateWindow("Edit",
  184.         "",
  185.         WS_CHILD | WS_VISIBLE | ES_MULTILINE,
  186.         0,
  187.         0,
  188.         (Rect.right-Rect.left),
  189.         30,
  190.         hWndMain,
  191.         IDC_EDIT,                    // Child control i.d.
  192.         hInst,
  193.         NULL);
  194.  
  195.  
  196.     if (!hEditWnd) 
  197.     {
  198.         DestroyWindow(hWndMain);
  199.         return NULL;
  200.     }
  201.  
  202.     // Set the initial text in the edit control
  203.     SetWindowText(hEditWnd, "This is a sample \"server\" application that understands DDE protocol.  You can now return to Authorware and proceed.");
  204.  
  205.     // Show the main window
  206.     ShowWindow(hWndMain, nCmdShow);
  207.     UpdateWindow(hWndMain);
  208.  
  209.     return TRUE;
  210. }
  211.  
  212.  
  213. long FAR PASCAL MainWndProc( HWND hWnd, unsigned message, WORD wParam, LONG lParam)
  214. /*
  215.     This is the main window procedure for the top level window.
  216. */
  217. {
  218.     FARPROC        lpProcAbout;
  219.     PAINTSTRUCT    ps;
  220.  
  221.     switch (message)
  222.     {
  223.     case WM_COMMAND:
  224.         switch (wParam)
  225.         {
  226.         case IDM_ABOUT:
  227.             if ((lpProcAbout = MakeProcInstance(About, hInst)) != 0L)
  228.             {
  229.                 DialogBox(hInst, "AboutBox", hWnd, lpProcAbout);
  230.                 FreeProcInstance(lpProcAbout);
  231.             }
  232.             break;
  233.  
  234.         case IDM_EXIT:
  235.             DestroyWindow(hWnd);
  236.             break;
  237.  
  238.         } 
  239.         break;
  240.  
  241.     case WM_SETFOCUS:
  242.         if (hEditWnd)
  243.             SetFocus (hEditWnd);
  244.         break;
  245.  
  246.     case WM_SIZE:
  247.         if (hEditWnd)
  248.             MoveWindow(hEditWnd, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
  249.         break;
  250.  
  251.     case WM_DESTROY:
  252.         PostQuitMessage(0);
  253.         break;
  254.  
  255.     case WM_DDE_INITIATE:
  256.         if (DDEInitialize(hWnd, wParam, LOWORD(lParam), HIWORD(lParam)))
  257.             break;
  258.  
  259.         // No break here - if Initialize request ignored use DefWindowProc
  260.  
  261.     default:
  262.         return DefWindowProc(hWnd, message, wParam, lParam);
  263.     }
  264.  
  265.     return NULL;
  266. }
  267.  
  268.  
  269. BOOL FAR PASCAL About( HWND hDlg, unsigned message, WORD wParam, LONG lParam)
  270. /*
  271.     This is the about dialog procedure handler.
  272. */
  273. {
  274.     switch (message) 
  275.     {
  276.     case WM_INITDIALOG:
  277.         return TRUE;
  278.  
  279.     case WM_COMMAND:
  280.         if (wParam == IDOK || wParam == IDCANCEL) 
  281.         {
  282.             EndDialog(hDlg, TRUE);
  283.             return TRUE;
  284.         }
  285.         break;
  286.     }
  287.     return FALSE;
  288. }
  289.  
  290.  
  291. long FAR PASCAL ServerProc( HWND hWnd, WORD message, WORD wParam, LONG lParam )
  292. /*
  293.     This is the message handler for the server window. Only WM_DDE_REQUEST
  294.     and WM_DDE_TERMINATE messages are handled by this server.
  295. */
  296. {
  297.     HWND            hWndClient;
  298.     DWORD            dwTime;
  299.     MSG            msg;
  300.  
  301.     switch (message)
  302.     {
  303.     case WM_DDE_REQUEST:
  304.         DDERequest(hWnd, wParam, LOWORD(lParam), HIWORD(lParam));
  305.         break;
  306.  
  307.     case WM_DDE_TERMINATE:
  308.         PostMessage(wParam, WM_DDE_TERMINATE, hWnd, 0L);
  309.         DestroyWindow(hWnd);
  310.         break;
  311.  
  312.     case WM_CLOSE:
  313.         hWndClient = GetWindowWord(hWnd, CLIENTWND);
  314.         if (VALID_WINDOW(hWndClient))
  315.         {
  316.             PostMessage(hWndClient, WM_DDE_TERMINATE, hWnd, 0L);
  317.  
  318.             // Request the client to terminate and wait for a response if recieved
  319.             dwTime = GetCurrentTime();
  320.             while(GetCurrentTime() - dwTime < DDE_TIMEOUT)
  321.                 if (PeekMessage(&msg, hWnd, WM_DDE_TERMINATE,
  322.                         WM_DDE_TERMINATE, PM_REMOVE))
  323.                         break;
  324.         }
  325.  
  326.         DestroyWindow(hWnd);
  327.         break;
  328.  
  329.     default:
  330.         return DefWindowProc(hWnd, message, wParam, lParam);
  331.     }
  332.  
  333.     return 0L;
  334. }
  335.  
  336.  
  337. static BOOL NEAR PASCAL DDEPostDataMessage(HWND server, HWND client )
  338. /*
  339.     This function gets the text from the edit control and sends it via dde
  340.     to the client window. It does not require the client to send an ACK back.
  341.     It is the responsiblity of the caller to free memory.
  342.  
  343.     Returns:
  344.  
  345.         TRUE    - data sent
  346.         FALSE - data not sent.
  347. */
  348. {
  349.     ATOM                aItem;
  350.     DDEDATA FAR     *Ack_ptr;
  351.     GLOBALHANDLE     ddeData;
  352.     MSG                 msg;
  353.     BOOL                rv = FALSE;
  354.     short                len;
  355.  
  356.     if ((aItem = GlobalAddAtom(szItem)) != 0)
  357.     {
  358.         // Get the length of the text from the edit control window
  359.         len = SendMessage(hEditWnd, WM_GETTEXTLENGTH, 0, 0L);
  360.  
  361.         // Allocate a buffer for the text
  362.         if ((ddeData = GlobalAlloc(GHND | GMEM_DDESHARE, (DWORD)sizeof(DDEDATA)+len+1)) != 0)
  363.         {
  364.             Ack_ptr = (DDEDATA FAR *)GlobalLock(ddeData);
  365.  
  366.             Ack_ptr->fResponse = TRUE;
  367.             Ack_ptr->cfFormat = CF_TEXT;
  368.  
  369.             // Let the client release the memory
  370.             Ack_ptr->fRelease = TRUE;
  371.             Ack_ptr->fAckReq = TRUE;
  372.  
  373.             // Get the text from the control
  374.             GetWindowText(hEditWnd, Ack_ptr->Value, len+1);
  375.             GlobalUnlock(ddeData);
  376.  
  377.             // Post the data to the client
  378.             if (!PostMessage(client, WM_DDE_DATA, server, MAKELONG(ddeData, aItem)))
  379.             {
  380.                 GlobalFree(ddeData);
  381.                 GlobalDeleteAtom(aItem);
  382.             }
  383.             else
  384.                 rv = TRUE;
  385.         }
  386.         else
  387.             GlobalDeleteAtom(aItem);
  388.     }
  389.  
  390.     return rv;
  391. }
  392.  
  393.  
  394. static BOOL NEAR PASCAL DDEInitialize( HWND parent, HWND client, ATOM a, ATOM t )
  395. /*
  396.     Handle the WM_DDE_INITIALIZE message.
  397.  
  398.     parent        - Server window parent
  399.     client        - Client window
  400.     a            - Atom for the Application name.
  401.     t                - Atom for the Topic name.
  402.  
  403.     Returns:
  404.  
  405.         TRUE    -    handled request
  406.         FALSE -  ignored request
  407. */
  408. {
  409.     ATOM        aApp=0, aTop=0;
  410.     HWND        hWndServer;
  411.     BOOL        rv = FALSE;
  412.  
  413.  
  414.     // Don't act on incomplete information
  415.     if (a == NULL || t == NULL)
  416.         return rv;
  417.  
  418.     // Add the Server atoms - only 1 atom with the same name is allowed.
  419.     // thus if the passed in atoms are the same, the initialize request
  420.     // is for us. - Remember duplicate adds increment the reference count!
  421.  
  422.     if ((aApp = GlobalAddAtom(APWServer)) != 0)
  423.     {
  424.         if ((aTop = GlobalAddAtom(szTopic)) != 0)
  425.         {
  426.             // Is the application name the same?
  427.             if (a == aApp)
  428.             {
  429.                 // Reference count should be decremented
  430.                 GlobalDeleteAtom(aApp);
  431.                 aApp = 0;
  432.  
  433.                 // Is the topic the same?
  434.                 if (t == aTop)
  435.                 {
  436.                     // Reference count should be decremented
  437.                     GlobalDeleteAtom(aTop);
  438.                     aTop = 0;
  439.  
  440.                     hWndServer = CreateWindow(szServerClass, NULL, WS_CHILD, 0, 0, 
  441.                                             0, 0, parent, NULL, hInst, NULL);
  442.  
  443.                     // Set the client window handle in CLIENTWND
  444.                     SetWindowWord(hWndServer, CLIENTWND, client);
  445.  
  446.                     // Let the client cleanup the atoms it passed in.
  447.                     SendMessage(client, WM_DDE_ACK, hWndServer, MAKELONG(a,t));
  448.                     rv = TRUE;
  449.                 }
  450.             }
  451.         }
  452.     }
  453.  
  454.     // Cleanup on error
  455.     if (rv == FALSE)
  456.     {
  457.         if (aApp)
  458.             GlobalDeleteAtom(aApp);
  459.         if (aTop)
  460.             GlobalDeleteAtom(aTop);
  461.     }
  462.  
  463.     return rv;
  464. }
  465.  
  466.  
  467. static BOOL NEAR PASCAL DDERequest( HWND server, HWND client, WORD cfFormat, ATOM aItem )
  468. /*
  469.     Handle the WM_DDE_REQUEST message.
  470.  
  471.     server        - Server window
  472.     client        - Client window
  473.     cfFormat       - Format of the data requested - we only support CF_TEXT.
  474.     aItem            - Atom for the item.
  475.  
  476.     Returns:
  477.  
  478.         TRUE    -    handled request
  479.         FALSE -  ignored request
  480. */
  481. {
  482.     WORD        wStatus;
  483.     char        szRequestedItem[10];
  484.     DDEACK    ddeAck;
  485.  
  486.     if (cfFormat == CF_TEXT && aItem != 0)
  487.     {
  488.         // Get the item atom name
  489.         GlobalGetAtomName(aItem, szRequestedItem, sizeof(szRequestedItem));
  490.  
  491.         // Is it the same as our item name. - We only support szRequestedItem
  492.         if (strcmp(szRequestedItem, szItem) == NULL)
  493.         {
  494.             GlobalDeleteAtom(aItem);
  495.             if (DDEPostDataMessage(server, client))
  496.                 return TRUE;
  497.         }
  498.     }
  499.     
  500.     // No match - negative acknowledgement
  501.  
  502.     ddeAck.bAppReturnCode = 0;
  503.     ddeAck.reserved = 0;
  504.     ddeAck.fBusy = FALSE;
  505.     ddeAck.fAck = FALSE;
  506.     
  507.     wStatus = *(WORD *)&ddeAck;
  508.     
  509.     if (!PostMessage(client, WM_DDE_ACK, server, MAKELONG(wStatus, aItem)))
  510.         if (aItem)
  511.             GlobalDeleteAtom(aItem);
  512.     
  513.     return FALSE;
  514. }
  515.  
  516.