home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / ddjmag / ddj9103.zip / NET_WIN3.ASC < prev    next >
Text File  |  1991-02-15  |  43KB  |  1,453 lines

  1. _NETWORKING WITH WINDOWS 3_
  2. by Mike Klein
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* MEGAPHON.H */
  8.  
  9. #define MAX_CONNECTIONS 100
  10. #define MAX_MESSAGE_LEN  56
  11.  
  12. #define IDT_MESSAGETIMER 100
  13.  
  14. #define IDC_USERLISTBOXTITLE    100
  15. #define IDC_USERLISTBOX         101
  16. #define IDC_SERVERCOMBOBOXTITLE 102
  17. #define IDC_SERVERCOMBOBOX      103
  18. #define IDC_MESSAGEEDITBOX      104
  19. #define IDC_SENDBUTTON          105
  20. #define IDC_SETTINGSBUTTON      106
  21. #define IDC_EXITBUTTON          107
  22.  
  23. #define IDC_ACCEPTMESSAGES    100
  24. #define IDC_ICONIZEMESSAGES   101
  25. #define IDC_ONLYATTACHEDUSERS 102
  26. #define IDC_ALLUSERSINBINDERY 103
  27.  
  28. #define IDC_USERNAME  100
  29. #define IDC_STATION   101
  30. #define IDC_NODE      102
  31. #define IDC_FULLNAME  103
  32. #define IDC_LOGINTIME 104
  33. #define IDC_NETWORK   105
  34.  
  35. #define IDC_REPLYEDITBOX 100
  36. #define IDC_REPLYBUTTON  101
  37. #define IDC_SAVEBUTTON   102
  38.  
  39. #define IDM_EXIT        200
  40. #define IDM_ABOUT       201
  41. #define IDM_REFRESH     220
  42.  
  43.  
  44. int  PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);
  45.  
  46. LONG FAR PASCAL MainWndProc(HWND, unsigned, WORD, LONG);
  47. LONG FAR PASCAL UserInfo(HWND, unsigned, WORD, LONG);
  48. LONG FAR PASCAL MessageHandler(HWND, unsigned, WORD, LONG);
  49. BOOL FAR PASCAL About(HWND, unsigned, WORD, LONG);
  50. BOOL FAR PASCAL Settings(HWND, unsigned, WORD, LONG);
  51.  
  52. BOOL PASCAL InitNetStuff(VOID);
  53. VOID PASCAL EnableOrDisableSendButton(VOID);
  54. VOID PASCAL SendNetWareMessageToUsers(VOID);
  55. VOID PASCAL ShowUserInformation(VOID);
  56.  
  57.  
  58.  
  59.  
  60. [LISTING TWO]
  61.  
  62. /*****************************************************************************
  63.  
  64.     PROGRAM: Megaphone
  65.     AUTHOR : Mike Klein
  66.     VERSION: 1.0
  67.     FILE   : megaphon.exe
  68.     CREATED: 10-25-90
  69.  
  70.     REQUIREMENTS: Windows 3.x and a Novell NetWare 2.1x or compatible network
  71.  
  72.     PURPOSE     : Messaging and simple information system for Novell NetWare.
  73.                   Allows quick replies to messages from coworkers and
  74.                         miscellaneous login information about them.
  75.  
  76. *****************************************************************************/
  77.  
  78.  
  79. #define NOCOMM                                                                                      
  80.  
  81.  
  82. #include <windows.h>
  83. #include <direct.h>
  84. #include <stdlib.h>
  85. #include <string.h>
  86. #include <time.h>
  87.  
  88. #include <nwbindry.h>
  89. #include <nwconn.h>
  90. #include <nwdir.h>
  91. #include <nwmsg.h>
  92. #include <nwwrkenv.h>
  93.  
  94. #include "megaphon.h"
  95.  
  96.  
  97. HANDLE hInstMegaphone;          /* Original instance of Megaphone           */
  98.  
  99. /* These are handles to commonly accessed controls in different dialogs     */
  100.  
  101. HWND hWndCurrent;        /* handle to currently active window on screen     */
  102. HWND hDlgMegaphone;      /* handle to Megaphone dialog window               */
  103. HWND hWndUserListBox;
  104. HWND hWndServerComboBox;
  105. HWND hWndMessageEditBox;
  106. HWND hWndSendButton;
  107.  
  108. /* Set up some additional global variables to commonly used NetWare stuff   */
  109.  
  110. WORD DefaultConnectionID;
  111. BYTE ServerName[48];
  112.  
  113. WORD UserConnectionNum;
  114. BYTE UserName[48];
  115. BYTE UserLoginTime[7];
  116.  
  117. WORD SelUserConnectionNum;
  118. BYTE SelUserNetworkAddr[4];
  119. BYTE SelUserNodeAddr[6];
  120. BYTE SelUserName[48];
  121. BYTE SelUserFullName[48];
  122. BYTE SelUserLoginTime[7];
  123.  
  124. BOOL AcceptMessages = TRUE;
  125. BOOL IconizeMessages = FALSE;
  126. BOOL AllUsers = FALSE;
  127.  
  128. BYTE Text[100];
  129.  
  130.  
  131. /*****************************************************************************
  132.  
  133.     FUNCTION: WinMain
  134.  
  135.     PURPOSE : Calls initialization function, processes message loop
  136.  
  137. *****************************************************************************/
  138.  
  139. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine,
  140.     int nCmdShow)
  141. {
  142.     WNDCLASS wc;
  143.     MSG      msg;
  144.  
  145.     if(!hPrevInstance)                    /* Other instances of app running? */
  146.     {
  147.         hInstMegaphone = hInstance;        /* Remember original instance      */
  148.  
  149.         /* Fill in window class structure with parameters that describe the   */
  150.         /* main window.                                                       */
  151.  
  152.         wc.style         = CS_DBLCLKS;     /* Process double click msgs       */
  153.         wc.lpfnWndProc   = MainWndProc;    /* Function to retrieve msgs for   */
  154.                                          /* windows of this class.          */
  155.         wc.cbClsExtra    = 0;              /* No per-class extra data.        */
  156.         wc.cbWndExtra    = DLGWINDOWEXTRA; /* Set becuase we used the CLASS   */
  157.                                          /* statement in dialog box         */
  158.         wc.hInstance     = hInstance;      /* Application that owns the class.*/
  159.         wc.hIcon         = LoadIcon(hInstance, "Megaphone");
  160.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  161.         wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  162.         wc.lpszMenuName  = "Megaphone";
  163.         wc.lpszClassName = "Megaphone";
  164.  
  165.         if(!RegisterClass(&wc))
  166.             return(FALSE);
  167.  
  168.         /* Fill in window class structure with parameters that describe the   */
  169.         /* message window.                                                    */
  170.  
  171.         wc.style         = NULL;           /* Process double click msgs       */
  172.         wc.lpfnWndProc   = MessageHandler;
  173.         wc.cbClsExtra    = 0;              /* No per-class extra data.        */
  174.         wc.cbWndExtra    = DLGWINDOWEXTRA; /* Set becuase we used the CLASS   */
  175.                                          /* statement in dialog box         */
  176.         wc.hInstance     = hInstance;      /* Application that owns the class.*/
  177.         wc.hIcon         = LoadIcon(hInstance, "Message");
  178.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  179.         wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  180.         wc.lpszMenuName  = NULL;
  181.         wc.lpszClassName = "Message";
  182.  
  183.         if(!RegisterClass(&wc))
  184.             return(FALSE);
  185.  
  186.         /* Fill in window class structure with parameters that describe the   */
  187.         /* userinfo window.                                                   */
  188.  
  189.         wc.style         = NULL;           /* Process double click msgs       */
  190.         wc.lpfnWndProc   = UserInfo;
  191.         wc.cbClsExtra    = 0;              /* No per-class extra data.        */
  192.         wc.cbWndExtra    = DLGWINDOWEXTRA; /* Set becuase we used the CLASS   */
  193.                                          /* statement in dialog box         */
  194.         wc.hInstance     = hInstance;      /* Application that owns the class.*/
  195.         wc.hIcon         = LoadIcon(hInstance, "User");
  196.         wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  197.         wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  198.         wc.lpszMenuName  = NULL;
  199.         wc.lpszClassName = "User";
  200.  
  201.         if(!RegisterClass(&wc))
  202.             return(FALSE);
  203.  
  204.         /* Create the main dialog window Megaphone, get window handles to     */
  205.         /* several of the controls, send the message edit box a message to    */
  206.         /* limit itself to MAX_MESSAGE_LEN characters, and set the system     */
  207.         /* font (mono-spaced) for server combo box and user list box.         */
  208.  
  209.         hDlgMegaphone = CreateDialog(hInstance, "Megaphone", NULL, 0L);
  210.  
  211.         hWndUserListBox     = GetDlgItem(hDlgMegaphone, IDC_USERLISTBOX);
  212.         hWndServerComboBox  = GetDlgItem(hDlgMegaphone, IDC_SERVERCOMBOBOX);
  213.         hWndMessageEditBox  = GetDlgItem(hDlgMegaphone, IDC_MESSAGEEDITBOX);
  214.         hWndSendButton      = GetDlgItem(hDlgMegaphone, IDC_SENDBUTTON);
  215.  
  216.         SendMessage(hWndMessageEditBox, EM_LIMITTEXT, MAX_MESSAGE_LEN - 1, 0L);
  217.         SendMessage(hWndUserListBox, WM_SETFONT,
  218.             GetStockObject(SYSTEM_FIXED_FONT), FALSE);
  219.         SendMessage(hWndServerComboBox, WM_SETFONT,
  220.             GetStockObject(SYSTEM_FIXED_FONT), FALSE);
  221.  
  222.         /* Finally, show the Megaphone dialog box                             */
  223.  
  224.         ShowWindow(hDlgMegaphone, nCmdShow);
  225.         UpdateWindow(hDlgMegaphone);
  226.  
  227.         /* Initialize the network stuff, and fill in list boxes               */
  228.  
  229.         InitNetStuff();
  230.     }
  231.     else
  232.     {
  233.         /* If there was another instance of Megaphone running, then switch to */
  234.         /* it by finding any window of class = "Megaphone". Then, if it's an  */
  235.         /* icon, open the window, otherwise just make it active.              */
  236.  
  237.         hDlgMegaphone = FindWindow("Megaphone", NULL);
  238.         if(IsIconic(hDlgMegaphone))
  239.             ShowWindow(hDlgMegaphone, SW_SHOWNORMAL);
  240.         SetActiveWindow(hDlgMegaphone);
  241.  
  242.         return(FALSE);
  243.     }
  244.  
  245.     /* Acquire and dispatch messages until a WM_QUIT message is received.    */
  246.     /* The window handle hWndCurrent points to the currently active window,  */
  247.     /* and is used to identify and process keystrokes going to any modeless  */
  248.     /* dialog box.                                                           */
  249.  
  250.     while(GetMessage(&msg, NULL, NULL, NULL))
  251.         if(hWndCurrent == NULL || !IsDialogMessage(hWndCurrent, &msg))
  252.         {
  253.             TranslateMessage(&msg);
  254.             DispatchMessage(&msg);
  255.         }
  256. }
  257.  
  258.  
  259. /*****************************************************************************
  260.  
  261.     FUNCTION: MainWndProc
  262.  
  263.     PURPOSE :  Processes messages for Megaphone dialog box
  264.  
  265. *****************************************************************************/
  266.  
  267. long FAR PASCAL MainWndProc(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  268. {
  269.     FARPROC lpProc;            /* Far procedure ptr to be used for About box */
  270.  
  271.     HWND    hWndTemp;
  272.     HWND    hDlgMessage;
  273.  
  274.     BYTE *ptr;
  275.     int  Index = 100;
  276.  
  277.     BYTE MessageCaption[100];
  278.     BYTE MessageDate[9];
  279.     BYTE MessageTime[9];
  280.  
  281.     switch(wMsg)
  282.     {
  283.         case WM_COMMAND              :
  284.  
  285.             switch(wParam)
  286.             {
  287.                 /* When wParam == 1, return was pressed in either the list box, */
  288.                 /* combo box, check boxes, or edit control.                     */
  289.  
  290.                 case 1                  :
  291.  
  292.                     /* Find out the current control (window) and process ENTER   */
  293.                     /* key accordingly.                                          */
  294.  
  295.                     switch(GetDlgCtrlID(GetFocus()))
  296.                     {
  297.                         case IDC_USERLISTBOX    :
  298.  
  299.                             ShowUserInformation();
  300.                             break;
  301.  
  302.                         case IDC_SERVERCOMBOBOX :
  303.  
  304.                             SendMessage(hWndServerComboBox, WM_KILLFOCUS, NULL, 0L);
  305.                             SendMessage(hWndServerComboBox, WM_SETFOCUS, NULL, 0L);
  306.                             break;
  307.  
  308.                         case IDC_MESSAGEEDITBOX :
  309.  
  310.                             if(IsWindowEnabled(hWndSendButton))
  311.                             {
  312.                                 SendMessage(hWndSendButton, WM_LBUTTONDOWN, 0, 0L);
  313.                                 SendMessage(hWndSendButton, WM_LBUTTONUP, 0, 0L);
  314.                                 SendMessage(hDlgMegaphone, WM_NEXTDLGCTL,
  315.                                     hWndMessageEditBox, TRUE);
  316.                             }
  317.                             else
  318.                             {
  319.                                 MessageBeep(0);
  320.                                 MessageBox(hDlgMegaphone, "You need a message and a user(s)",
  321.                                     "ERROR", MB_ICONEXCLAMATION | MB_OK);
  322.                             }
  323.                             break;
  324.  
  325.                         default                 :
  326.  
  327.                             break;
  328.                     }
  329.                     break;
  330.  
  331.                 case IDC_USERLISTBOX         :
  332.  
  333.                     if(HIWORD(lParam) == LBN_DBLCLK)
  334.                     {
  335.                         /* Restore the list box item's selection state. If it     */
  336.                         /* isn't flagged, then flag it, and vice versa.           */
  337.  
  338.                         Index = (int) SendMessage(hWndUserListBox, LB_GETCURSEL, 0, 0L);
  339.                         if(SendMessage(hWndUserListBox, LB_GETSEL, Index, 0L))
  340.                             SendMessage(hWndUserListBox, LB_SETSEL, FALSE, Index);
  341.                         else
  342.                             SendMessage(hWndUserListBox, LB_SETSEL, TRUE, Index);
  343.  
  344.                         ShowUserInformation();
  345.                     }
  346.                     else
  347.                         EnableOrDisableSendButton();
  348.  
  349.                     break;
  350.  
  351.                 case IDC_SERVERCOMBOBOX      :
  352.  
  353.                     if(HIWORD(lParam) == CBN_SELCHANGE)
  354.                     {
  355.                         if((Index = (int) SendMessage(hWndServerComboBox, CB_GETCURSEL,
  356.                             0, 0L)) == CB_ERR)
  357.                             break;
  358.  
  359.                         SendMessage(hWndServerComboBox, CB_GETLBTEXT, Index,
  360.                             (LONG) (LPSTR) ServerName);
  361.  
  362.                         if(!GetConnectionID(ServerName, &DefaultConnectionID))
  363.                         {
  364.                             SetPreferredConnectionID(DefaultConnectionID);
  365.                             InitNetStuff();
  366.                         }
  367.                     }
  368.                     break;
  369.  
  370.                 case IDC_MESSAGEEDITBOX      :
  371.  
  372.                     EnableOrDisableSendButton();
  373.                     break;
  374.  
  375.                 case IDC_SENDBUTTON          :
  376.  
  377.                     if(HIWORD(lParam) == BN_CLICKED)
  378.                         SendNetWareMessageToUsers();
  379.                     break;
  380.  
  381.                 case IDM_EXIT                :
  382.                 case IDC_EXITBUTTON          :
  383.  
  384.                     SendMessage(hDlgMegaphone, WM_CLOSE, 0, 0L);
  385.                     break;
  386.  
  387.                 case IDM_ABOUT               :
  388.  
  389.                     lpProc = MakeProcInstance(About, hInstMegaphone);
  390.                     DialogBox(hInstMegaphone, "About", hWnd, lpProc);
  391.                     FreeProcInstance(lpProc);
  392.                     break;
  393.  
  394.                 case IDM_REFRESH             :
  395.  
  396.                     InitNetStuff();
  397.                     break;
  398.  
  399.                 case IDC_SETTINGSBUTTON      :
  400.  
  401.                     lpProc = MakeProcInstance(Settings, hInstMegaphone);
  402.                     DialogBox(hInstMegaphone, "Settings", hWnd, lpProc);
  403.                     FreeProcInstance(lpProc);
  404.                     break;
  405.  
  406.                 default                      :
  407.  
  408.                     break;
  409.             }
  410.  
  411.             break;
  412.  
  413.         case WM_TIMER                :
  414.  
  415.             /* This is the Windows timer for retrieving messages that goes off */
  416.             /* every five seconds.                                             */
  417.  
  418.             GetBroadcastMessage(Text);
  419.  
  420.             if(*Text)
  421.             {
  422.                 /* Create the message reply dialog box and limit the edit box   */
  423.                 /* to NetWare's limit of 56 or so characters.                   */
  424.  
  425.                 hDlgMessage = CreateDialog(hInstMegaphone, "Message",
  426.                     hDlgMegaphone, 0L);
  427.  
  428.                 SendDlgItemMessage(hDlgMessage, IDC_REPLYEDITBOX, EM_LIMITTEXT,
  429.                     MAX_MESSAGE_LEN - 1, 0L);
  430.  
  431.                 /* Parse the incoming string of 'username[station#]message'     */
  432.  
  433.                 if((ptr = strchr(Text, '[')) == NULL)
  434.                 {
  435.                     /* If the incoming message isn't formatted by NetWare's      */
  436.                     /* SEND command, SESSION program, or Megaphone, then we      */
  437.                     /* can't use the REPLY button, so disable it.                */
  438.  
  439.                     SelUserName[0] = '\0';
  440.                     SelUserConnectionNum = 0;
  441.                     EnableWindow(GetDlgItem(hDlgMessage, IDC_REPLYBUTTON), FALSE);
  442.                 }
  443.                 else
  444.                 {
  445.                     /* Pull up the user name and connection#, and message, which */
  446.                     /* is right after the ']'.                                   */
  447.  
  448.                     strncpy(SelUserName, Text, ptr - Text);
  449.                     SelUserName[ptr - Text] = '\0';
  450.                     SelUserConnectionNum = atoi(ptr + 1);
  451.                     if((ptr = strchr(Text, ']')) != NULL)
  452.                         lstrcpy((LPSTR) Text, (LPSTR) (ptr + 1));
  453.  
  454.                     /* Check again to see if we pulled up a valid Conn#. If we   */
  455.                     /* didn't, then disable the REPLY button.                    */
  456.  
  457.                     if(SelUserConnectionNum < 1 || SelUserConnectionNum > 255)
  458.                         EnableWindow(GetDlgItem(hDlgMessage, IDC_REPLYBUTTON), FALSE);
  459.                 }
  460.  
  461.                 /* Put the retrieved message in the dialog's edit box           */
  462.                 
  463.                 SetDlgItemText(hDlgMessage, IDC_REPLYEDITBOX, Text);
  464.  
  465.                 /* Record the date and time that the message came in at and     */
  466.                 /* make it reflected in the message caption.                    */
  467.  
  468.                 _strdate(MessageDate);
  469.                 _strtime(MessageTime);
  470.                 wsprintf(MessageCaption, "%s %s %s", (LPSTR) SelUserName,
  471.                     (LPSTR) MessageDate, (LPSTR) MessageTime);
  472.                 SetWindowText(hDlgMessage, MessageCaption);
  473.  
  474.                 /* Finally, show (or minimize) the completed message dialog box */
  475.                 
  476.                 if(IconizeMessages)
  477.                     ShowWindow(hDlgMessage, SW_SHOWMINNOACTIVE);
  478.                 else
  479.                     ShowWindow(hDlgMessage, SW_SHOWNORMAL);
  480.  
  481.                 MessageBeep(0);
  482.             }
  483.  
  484.             return(0L);
  485.  
  486.         case WM_CLOSE                :
  487.  
  488.             /* Check before closing the main window if there are any           */
  489.             /* outstanding messages that haven't been closed.                  */
  490.  
  491.             if(hWndTemp = FindWindow((LPSTR) "Message", NULL))
  492.             {
  493.                 if(MessageBox(hDlgMegaphone,
  494.                     "Quit without disposing of/reading messages?",
  495.                     "Messages Outstanding", MB_YESNO | MB_APPLMODAL |
  496.                     MB_ICONEXCLAMATION | MB_DEFBUTTON2) == IDYES)
  497.                 {
  498.                     DestroyWindow(hDlgMegaphone);
  499.                 }
  500.                 else
  501.                 {
  502.                     ShowWindow(hWndTemp, SW_SHOWNORMAL);
  503.                     SetActiveWindow(hWndTemp);
  504.                 }
  505.             }
  506.             else
  507.                 DestroyWindow(hDlgMegaphone);
  508.  
  509.             return(0L);
  510.  
  511.         case WM_SETFOCUS             :
  512.  
  513.             if(IsWindowEnabled(hWndMessageEditBox))
  514.                 SendMessage(hDlgMegaphone, WM_NEXTDLGCTL, hWndMessageEditBox, TRUE);
  515.             else
  516.                 SendMessage(hDlgMegaphone, WM_NEXTDLGCTL,
  517.                     GetDlgItem(hDlgMegaphone, IDC_EXITBUTTON), TRUE);
  518.  
  519.             return(0L);
  520.  
  521.         case WM_ACTIVATE             :
  522.  
  523.             hWndCurrent = (wParam == NULL) ? NULL : hWnd;
  524.             break;
  525.  
  526.         case WM_DESTROY              :
  527.  
  528.             PostQuitMessage(0);
  529.             return(0L);
  530.  
  531.         default                      :
  532.  
  533.             break;
  534.  
  535.     }
  536.     return(DefDlgProc(hWnd, wMsg, wParam, lParam));
  537. }
  538.  
  539.  
  540. /*****************************************************************************
  541.  
  542.     FUNCTION: SendNetWareMessageToUsers
  543.  
  544.     PURPOSE : Do I really need to explain this one?
  545.  
  546. *****************************************************************************/
  547.  
  548. VOID PASCAL SendNetWareMessageToUsers(VOID)
  549. {
  550.     BYTE Message[MAX_MESSAGE_LEN];
  551.     WORD ConnectionsToSend[MAX_CONNECTIONS];
  552.     BYTE ResultList[MAX_CONNECTIONS];
  553.     int  NumUsers;
  554.     int  i, j;
  555.  
  556.     /* Get text inside message edit box and format message so it includes    */
  557.     /* the username, connection#, and message. The first two fields are      */
  558.     /* needed for replying back since there's nothing in NetWare's messaging */
  559.     /* facility to tell you who sent the message.                            */
  560.  
  561.     GetDlgItemText(hDlgMegaphone, IDC_MESSAGEEDITBOX, (LPSTR) Text, MAX_MESSAGE_LEN);
  562.  
  563.     wsprintf(Message, "%s[%d]%s", (LPSTR) UserName, UserConnectionNum,
  564.         (LPSTR) Text);
  565.  
  566.     /* Get total number of users in list box and check to see if they've     */
  567.     /* been selected or not. If they have, get their Connection# and put it  */
  568.     /* in the ConnectionsToSend array.                                       */
  569.  
  570.     NumUsers = (int) SendMessage(hWndUserListBox, LB_GETCOUNT, 0, 0L);
  571.     
  572.     for(i = j = 0; i < NumUsers; i++)
  573.         if(SendMessage(hWndUserListBox, LB_GETSEL, i, 0L))
  574.         {
  575.             SendMessage(hWndUserListBox, LB_GETTEXT, i, (LONG) (LPSTR) Text);
  576.             ConnectionsToSend[j++] = atoi(&Text[18]);
  577.         }
  578.  
  579.     /* Send the message to users in the array.                               */
  580.  
  581.     SendBroadcastMessage(Message, ConnectionsToSend, ResultList, j);
  582.  
  583.     /* Scan through the ResultList array checking for messages that had      */
  584.     /* problems. Selecting OK will continue to check the status of the other */
  585.     /* messages, where selecting CANCEL from the message box will abort the  */
  586.     /* send status checking altogether.                                      */
  587.  
  588.     for(i = 0; i < j; i++)
  589.         switch(ResultList[i])
  590.         {
  591.             case 0xfc :
  592.  
  593.                 wsprintf(Text, "Message to Connection %d", ConnectionsToSend[i]);
  594.                 if(MessageBox(hDlgMegaphone,
  595.                     "Message not sent - User already has message pending",
  596.                     Text, MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
  597.                 {
  598.                     i = j;
  599.                 }
  600.                 break;
  601.  
  602.             case 0xfd :
  603.  
  604.                 wsprintf(Text, "Message to Connection %d", ConnectionsToSend[i]);
  605.                 if(MessageBox(hDlgMegaphone,
  606.                     "Message not sent - Invalid connection number",
  607.                     Text, MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
  608.                 {
  609.                     i = j;
  610.                 }
  611.                 break;
  612.  
  613.             case 0xff :
  614.  
  615.                 wsprintf(Text, "Message to Connection %d", ConnectionsToSend[i]);
  616.                 if(MessageBox(hDlgMegaphone,
  617.                     "Message not sent - User has blocking turned on",
  618.                     Text, MB_OKCANCEL | MB_ICONEXCLAMATION) == IDCANCEL)
  619.                 {
  620.                     i = j;
  621.                 }
  622.                 break;
  623.  
  624.             default   :
  625.  
  626.                 break;
  627.         }
  628. }
  629.  
  630.  
  631. /*****************************************************************************
  632.  
  633.     FUNCTION: EnableOrDisableSendButton
  634.  
  635.     PURPOSE : Based on a message being in the edit box and at least one
  636.               selected user, the send button is enabled or disabled
  637.  
  638. *****************************************************************************/
  639.  
  640. VOID PASCAL EnableOrDisableSendButton(VOID)
  641. {
  642.     /* Check to see if at least one user is selected and at least a one      */
  643.     /* character message in the edit box. If there is, then enable the SEND  */
  644.     /* button and thicken it to make it the default response when ENTER is   */
  645.     /* pressed.                                                              */
  646.  
  647.     if(SendMessage(hWndUserListBox, LB_GETSELCOUNT, 0, 0L) &&
  648.         SendMessage(hWndMessageEditBox, EM_LINELENGTH, -1, 0L))
  649.     {
  650.         EnableWindow(hWndSendButton, TRUE);
  651.     }
  652.     else
  653.     {
  654.         EnableWindow(hWndSendButton, FALSE);
  655.     }
  656. }
  657.  
  658.  
  659. /*****************************************************************************
  660.  
  661.     FUNCTION: InitNetStuff
  662.  
  663.     PURPOSE : Initialize network connections and fill in combo and list boxes
  664.  
  665. *****************************************************************************/
  666.  
  667. BOOL PASCAL InitNetStuff(VOID)
  668. {
  669.     HCURSOR hOldCursor;
  670.  
  671.     WORD NumberOfConnections;
  672.     WORD NumberOfServers;
  673.  
  674.     int  Index;
  675.     BYTE DirHandle;
  676.  
  677.     BYTE TempServerName[48];
  678.     WORD ObjectType;
  679.     WORD ConnID;
  680.     WORD ConnectionList[MAX_CONNECTIONS];
  681.     BYTE SearchObjectName[48] = "*";
  682.     BYTE ObjectName[48];
  683.     long ObjectID;
  684.     BYTE ObjectHasProperties;
  685.     BYTE ObjectFlag;
  686.     BYTE ObjectSecurity;
  687.  
  688.     /* Check to see if a connection has been made to any server              */
  689.  
  690.     if(UserConnectionNum = GetConnectionNumber())
  691.         if(!GetConnectionInformation(UserConnectionNum, UserName, &ObjectType,
  692.             &ObjectID, UserLoginTime))
  693.             if(*UserName)
  694.             {
  695.                 /* If we have a preferred connection ID, then were supposed to  */
  696.                 /* use it for all of our requests. If we don't, then check to   */
  697.                 /* see if we're sitting on a local drive (bit 0 or 1 not set).  */
  698.                 /* If we are, then set the default connection ID to that of the */
  699.                 /* primary server. If we're sitting on a network drive, then    */
  700.                 /* requests go to the associated server.                        */
  701.  
  702.                 if(GetPreferredConnectionID())
  703.                     DefaultConnectionID = GetPreferredConnectionID();
  704.                 else
  705.                 {
  706.                     if(!(GetDriveInformation((BYTE) (_getdrive() - 1), &ConnID,
  707.                         &DirHandle) & 3))
  708.                     {
  709.                         DefaultConnectionID = GetPrimaryConnectionID();
  710.                     }
  711.                     SetPreferredConnectionID(DefaultConnectionID);
  712.                 }
  713.  
  714.                 /* Set NetWare's message mode so that Megaphone can poll for       */
  715.                 /* messages instead of automatically having them sent to the       */
  716.                 /* station.                                                        */
  717.                 
  718.                 EnableBroadcasts();
  719.                 SetBroadcastMode(3);
  720.  
  721.                 /* Set up a Windows timer so that every 5 seconds, the server is   */
  722.                 /* polled for waiting messages.                                    */
  723.  
  724.                 SetTimer(hDlgMegaphone, IDT_MESSAGETIMER, 5000, NULL);
  725.  
  726.                 EnableWindow(GetDlgItem(hDlgMegaphone, IDC_SETTINGSBUTTON), TRUE);
  727.             }
  728.  
  729.     if(!UserConnectionNum)
  730.     {
  731.         EnableWindow(GetDlgItem(hDlgMegaphone, IDC_SETTINGSBUTTON), FALSE);
  732.         MessageBox(hDlgMegaphone, "Must be logged into a NetWare server",
  733.             "ERROR - NO USERS", MB_ICONSTOP | MB_OK);
  734.         return(FALSE);
  735.     }
  736.  
  737.     /* Now that we've established a network connection, let's fill in the    */
  738.     /* drop-down combo box with file servers and the list box with users of  */
  739.     /* whatever the node's preferred server is.                              */
  740.  
  741.     /* Turn off re-drawing of the list box so it doesn't flicker, reset the  */
  742.     /* contents of both boxes, capture and intercept all mouse activity, and */
  743.     /* turn the cursor into an hourglass.                                    */
  744.  
  745.     SendMessage(hWndUserListBox, WM_SETREDRAW, FALSE, 0L);
  746.     SendMessage(hWndUserListBox, LB_RESETCONTENT, 0, 0L);
  747.     SendMessage(hWndServerComboBox, CB_RESETCONTENT, 0, 0L);
  748.     SetCapture(hDlgMegaphone);
  749.     hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  750.  
  751.     /* Scan through the possible ConnectionID#'s (1-8) and see what file     */
  752.     /* servers are attached, if any are, and put them in the combo box.      */
  753.  
  754.     for(ConnID = 1; ConnID < 9; ++ConnID)
  755.     {
  756.         GetFileServerName(ConnID, TempServerName);
  757.         if(*TempServerName)
  758.             SendMessage(hWndServerComboBox, CB_ADDSTRING, NULL,
  759.                 (LONG) (LPSTR) TempServerName);
  760.     }
  761.  
  762.     /* Get default server                                                    */
  763.  
  764.     GetFileServerName(DefaultConnectionID, ServerName);
  765.  
  766.     /* Search the NetWare bindery for active user connections, putting       */
  767.     /* them into the list box                                                */
  768.  
  769.     ObjectID = -1;
  770.     while(!ScanBinderyObject(SearchObjectName, OT_USER, &ObjectID, ObjectName,
  771.         &ObjectType, &ObjectHasProperties, &ObjectFlag, &ObjectSecurity))
  772.     {
  773.         GetObjectConnectionNumbers(ObjectName, OT_USER, &NumberOfConnections,
  774.             ConnectionList, MAX_CONNECTIONS);
  775.  
  776.         /* If there are multiple connections for a single user then we        */
  777.         /* have to make sure and get all of them.                             */
  778.  
  779.         if(!NumberOfConnections)
  780.         {
  781.             if(AllUsers)
  782.             {
  783.                 wsprintf(Text, "[%s]", (LPSTR) ObjectName);
  784.                 SendMessage(hWndUserListBox, LB_ADDSTRING, NULL, (LONG) (LPSTR) Text);
  785.             }
  786.         }
  787.         else
  788.             for(Index = 0; Index < (int) NumberOfConnections; ++Index)
  789.             {
  790.                 if(UserConnectionNum == ConnectionList[Index])
  791.                     wsprintf(Text, "%-16.16s *%3d", (LPSTR) ObjectName, ConnectionList[Index]);
  792.                 else
  793.                     wsprintf(Text, "%-17.17s %3d", (LPSTR) ObjectName, ConnectionList[Index]);
  794.                 SendMessage(hWndUserListBox, LB_ADDSTRING, NULL, (LONG) (LPSTR) Text);
  795.             }
  796.     }
  797.  
  798.     /* Turn re-drawing for the list box back on and make the first item in   */
  799.     /* the server combo box and user list box the default.                   */
  800.  
  801.     InvalidateRect(hWndUserListBox, NULL, TRUE);
  802.     SendMessage(hWndUserListBox, LB_SETSEL, 0, 0L);
  803.     SendMessage(hWndUserListBox, WM_SETREDRAW, TRUE, 0L);
  804.  
  805.     /* Select the default server in the server combo box                     */
  806.  
  807.     SendMessage(hWndServerComboBox, CB_SELECTSTRING, -1, (LONG) (LPSTR) ServerName);
  808.  
  809.     /* Add the # of servers and users to the caption on the server and list  */
  810.     /* boxes.                                                                */
  811.  
  812.     NumberOfConnections = (int) SendMessage(hWndUserListBox,    LB_GETCOUNT, 0, 0L);
  813.     wsprintf(Text, "%d &Users on %s", NumberOfConnections, (LPSTR) ServerName);
  814.     SetDlgItemText(hDlgMegaphone, IDC_USERLISTBOXTITLE, (LPSTR) Text);
  815.  
  816.     NumberOfServers = (int) SendMessage(hWndServerComboBox, CB_GETCOUNT, 0, 0L);
  817.     wsprintf(Text, "%d Ser&vers", NumberOfServers);
  818.     SetDlgItemText(hDlgMegaphone, IDC_SERVERCOMBOBOXTITLE, (LPSTR) Text);
  819.  
  820.     /* Restore mouse activity, set the cursor back to normal, and initially  */
  821.     /* disable the Send button.                                              */
  822.  
  823.     ReleaseCapture();
  824.     SetCursor(hOldCursor);
  825.     EnableOrDisableSendButton();
  826.  
  827.     return(TRUE);
  828. }
  829.  
  830.  
  831. /*****************************************************************************
  832.  
  833.     FUNCTION: About
  834.  
  835.     PURPOSE : Processes messages for About box
  836.  
  837. *****************************************************************************/
  838.  
  839. BOOL FAR PASCAL About(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  840. {
  841.     switch(wMsg)
  842.     {
  843.         case WM_INITDIALOG :
  844.  
  845.             return(TRUE);
  846.  
  847.         case WM_COMMAND    :
  848.  
  849.             if(wParam == IDOK || wParam == IDCANCEL)
  850.             {
  851.                 EndDialog(hWnd, TRUE);
  852.                 return(TRUE);
  853.             }
  854.             break;
  855.  
  856.         default            :
  857.  
  858.             break;
  859.     }
  860.     return(FALSE);
  861. }
  862.  
  863.  
  864. /*****************************************************************************
  865.  
  866.     FUNCTION: Settings
  867.  
  868.     PURPOSE : Processes messages for Settings window
  869.  
  870. *****************************************************************************/
  871.  
  872. BOOL FAR PASCAL Settings(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  873. {
  874.     switch(wMsg)
  875.     {
  876.         case WM_INITDIALOG :
  877.  
  878.             CheckDlgButton(hWnd, IDC_ACCEPTMESSAGES, AcceptMessages);
  879.             CheckDlgButton(hWnd, IDC_ICONIZEMESSAGES, IconizeMessages);
  880.  
  881.             if(AllUsers)
  882.                 CheckRadioButton(hWnd, IDC_ALLUSERSINBINDERY,
  883.                     IDC_ALLUSERSINBINDERY, IDC_ALLUSERSINBINDERY);
  884.             else
  885.                 CheckRadioButton(hWnd, IDC_ONLYATTACHEDUSERS,
  886.                     IDC_ONLYATTACHEDUSERS, IDC_ONLYATTACHEDUSERS);
  887.  
  888.             break;
  889.  
  890.         case WM_COMMAND    :
  891.  
  892.             switch(wParam)
  893.             {
  894.                  case IDC_ACCEPTMESSAGES    :
  895.  
  896.                     if(IsDlgButtonChecked(hWnd, IDC_ACCEPTMESSAGES))
  897.                     {
  898.                         EnableBroadcasts();
  899.                         SetTimer(hDlgMegaphone, IDT_MESSAGETIMER, 5000, NULL);
  900.                         AcceptMessages = TRUE;
  901.                     }
  902.                     else
  903.                     {
  904.                         DisableBroadcasts();
  905.                         KillTimer(hDlgMegaphone, IDT_MESSAGETIMER);
  906.                         AcceptMessages = FALSE;
  907.                     }
  908.  
  909.                     break;
  910.  
  911.                 case IDC_ICONIZEMESSAGES    :
  912.  
  913.                     if(IsDlgButtonChecked(hWnd, IDC_ICONIZEMESSAGES))
  914.                         IconizeMessages = TRUE;
  915.                     else
  916.                         IconizeMessages = FALSE;
  917.  
  918.                     break;
  919.  
  920.                 case IDC_ONLYATTACHEDUSERS :
  921.  
  922.                     AllUsers = FALSE;
  923.                     InitNetStuff();
  924.                     break;
  925.  
  926.                 case IDC_ALLUSERSINBINDERY :
  927.  
  928.                     AllUsers = TRUE;
  929.                     InitNetStuff();
  930.                     break;
  931.  
  932.                 case IDOK                  :
  933.                 case IDCANCEL              :
  934.  
  935.                     EndDialog(hWnd, TRUE);
  936.                     return(TRUE);
  937.  
  938.                 default            :
  939.  
  940.                     break;
  941.             }
  942.     }
  943.     return(FALSE);
  944. }
  945.  
  946.  
  947. /*****************************************************************************
  948.  
  949.     FUNCTION: MessageHandler
  950.  
  951.     PURPOSE : Processes messages for user message dialog box/window
  952.  
  953. *****************************************************************************/
  954.  
  955. long FAR PASCAL MessageHandler(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  956. {
  957.     BYTE Message[MAX_MESSAGE_LEN];
  958.     WORD ConnectionsToSend[1];
  959.     BYTE ResultList[1];
  960.  
  961.     switch(wMsg)
  962.     {
  963.         case WM_COMMAND  :
  964.  
  965.             switch(wParam)
  966.             {
  967.                 case 1               :
  968.  
  969.                     /* A '1' is generated when ENTER is pressed while in a       */
  970.                     /* control in a dialog box and there's no default button     */
  971.                     /* defined. This is to trap the ENTER key when in the reply  */
  972.                     /* edit box. We'll simulate the pressing of the REPLY button */
  973.  
  974.                     if(IsWindowEnabled(GetDlgItem(hWnd, IDC_REPLYBUTTON)))
  975.                     {
  976.                         SendMessage(GetDlgItem(hWnd, IDC_REPLYBUTTON),
  977.                             WM_LBUTTONDOWN, 0, 0L);
  978.                         SendMessage(GetDlgItem(hWnd, IDC_REPLYBUTTON),
  979.                             WM_LBUTTONUP, 0, 0L);
  980.                     }
  981.                     else
  982.                     {
  983.                         MessageBeep(0);
  984.                         MessageBox(hWnd, "You cannot reply to this message",
  985.                             "ERROR", MB_ICONEXCLAMATION | MB_OK);
  986.                     }
  987.                     break;
  988.  
  989.                 case IDC_SAVEBUTTON  :
  990.  
  991.                     /* "Save" the message by iconizing it                        */
  992.  
  993.                     CloseWindow(hWnd);
  994.                     break;
  995.  
  996.                 case IDC_REPLYBUTTON :
  997.  
  998.                     /* Get text from edit box located in message dialog box      */
  999.  
  1000.                     GetDlgItemText(hWnd, IDC_REPLYEDITBOX, (LPSTR) Text,
  1001.                         MAX_MESSAGE_LEN);
  1002.  
  1003.                     /* Set up my connection# to send to, format the message, and */
  1004.                     /* send it to the user.                                      */
  1005.  
  1006.                     ConnectionsToSend[0] = SelUserConnectionNum;
  1007.                     wsprintf(Message, "%s[%d]%s", (LPSTR) SelUserName,
  1008.                         SelUserConnectionNum, (LPSTR) Text);
  1009.  
  1010.                     SendBroadcastMessage(Message, ConnectionsToSend, ResultList, 1);
  1011.  
  1012.                     /* Possible results of sending a message                     */
  1013.  
  1014.                     switch(ResultList[0])
  1015.                     {
  1016.                         case 0xfc :
  1017.  
  1018.                             wsprintf(Text, "Message to Connection %d",
  1019.                                 ConnectionsToSend[0]);
  1020.                             MessageBox(hDlgMegaphone,
  1021.                                 "Message not sent - User already has message pending",
  1022.                                 Text, MB_OK | MB_ICONEXCLAMATION);
  1023.                             break;
  1024.  
  1025.                         case 0xfd :
  1026.  
  1027.                             wsprintf(Text, "Message to Connection %d",
  1028.                                 ConnectionsToSend[0]);
  1029.                             MessageBox(hDlgMegaphone,
  1030.                                 "Message not sent - Invalid connection number",
  1031.                                 Text, MB_OK | MB_ICONEXCLAMATION);
  1032.     
  1033.                             break;
  1034.  
  1035.                         case 0xff :
  1036.     
  1037.                             wsprintf(Text, "Message to Connection %d",
  1038.                                 ConnectionsToSend[0]);
  1039.                             MessageBox(hDlgMegaphone,
  1040.                                 "Message not sent - User has blocking turned on",
  1041.                                 Text, MB_OK | MB_ICONEXCLAMATION);
  1042.     
  1043.                             break;
  1044.  
  1045.                         default   :
  1046.  
  1047.                             break;
  1048.                     }
  1049.  
  1050.                     /* Get rid of the message reply dialog box/window            */
  1051.  
  1052.                     DestroyWindow(hWnd);
  1053.                     return(0L);
  1054.  
  1055.                 case IDCANCEL        :
  1056.  
  1057.                     DestroyWindow(hWnd);
  1058.                     return(0L);
  1059.  
  1060.                 default              :
  1061.  
  1062.                     break;
  1063.             }
  1064.             break;
  1065.  
  1066.         case WM_CLOSE         :
  1067.  
  1068.             DestroyWindow(hWnd);
  1069.             return(0L);
  1070.  
  1071.         case WM_SETFOCUS      :
  1072.  
  1073.             /* Set the focus to the edit control.                              */
  1074.  
  1075.             SendMessage(hWnd, WM_NEXTDLGCTL, GetDlgItem(hWnd, IDC_REPLYEDITBOX),
  1076.                 TRUE);
  1077.  
  1078.             return(0L);
  1079.  
  1080.         case WM_ACTIVATE      :
  1081.  
  1082.             hWndCurrent = (wParam == NULL) ? NULL : hWnd;
  1083.             break;
  1084.  
  1085.         default          :
  1086.  
  1087.             break;
  1088.     }
  1089.     return(DefDlgProc(hWnd, wMsg, wParam, lParam));
  1090. }
  1091.  
  1092.  
  1093. /*****************************************************************************
  1094.  
  1095.     FUNCTION: ShowUserInformation
  1096.  
  1097.     PURPOSE : Shows user information on current or double-clicked entry
  1098.  
  1099. *****************************************************************************/
  1100.  
  1101. VOID PASCAL ShowUserInformation(VOID)
  1102. {
  1103.     int Index;
  1104.     BYTE *ptr;
  1105.  
  1106.     HWND hDlgUserInfo;
  1107.  
  1108.     WORD ObjectType;
  1109.     long ObjectID;
  1110.     WORD SocketNum;
  1111.     BYTE PropertyValue[128];
  1112.     BYTE MoreSegments;
  1113.     BYTE PropertyFlags;
  1114.  
  1115.     /* Get an index to the user name underneath the cursor,   */
  1116.     /* and then get the user's connection number so we can    */
  1117.     /* retrieve NetWare information on him/her.               */
  1118.  
  1119.     Index = (int) SendMessage(hWndUserListBox, LB_GETCURSEL, 0, 0L);
  1120.     SendMessage(hWndUserListBox, LB_GETTEXT, Index, (LONG) (LPSTR) Text);
  1121.  
  1122.     /* If entry in list box doesn't have a connection #, then we need to get */
  1123.     /* the login name by parsing the list box string, we can't use a call to */
  1124.     /* GetConnectionInformation().                                           */
  1125.  
  1126.     memset(SelUserLoginTime, '\0', 7);
  1127.     memset(SelUserNetworkAddr, '\0', 4);
  1128.     memset(SelUserNodeAddr, '\0', 6);
  1129.     SelUserFullName[0] = '\0';
  1130.     SelUserConnectionNum = 0;
  1131.  
  1132.     if(Text[0] == '[')
  1133.     {
  1134.         ptr = strchr(Text, ']');
  1135.         strncpy(SelUserName, Text + 1, ptr - Text - 1);
  1136.         SelUserName[ptr - Text - 1] = '\0';
  1137.     }
  1138.     else
  1139.     {
  1140.         ptr = strchr(Text, ' ');
  1141.         strncpy(SelUserName, Text, ptr - Text);
  1142.         SelUserConnectionNum = atoi(&Text[18]);
  1143.         SelUserName[ptr - Text] = '\0';
  1144.  
  1145.         /* We can get connection info only for users that are logged in to a  */
  1146.         /* server. So, get the user name and login time, network and node     */
  1147.         /* address, and full name for specified connection#.                  */
  1148.  
  1149.         GetConnectionInformation(SelUserConnectionNum, SelUserName, &ObjectType,
  1150.             &ObjectID, SelUserLoginTime);
  1151.  
  1152.         GetInternetAddress(SelUserConnectionNum, SelUserNetworkAddr,
  1153.             SelUserNodeAddr, &SocketNum);
  1154.     }
  1155.  
  1156.     if(!ReadPropertyValue(SelUserName, OT_USER, "IDENTIFICATION", 1,
  1157.         PropertyValue, &MoreSegments, &PropertyFlags))
  1158.     {
  1159.         wsprintf(SelUserFullName, "%s", (LPSTR) PropertyValue);
  1160.     }
  1161.  
  1162.     /* Create userinfo dialog box and change caption to the   */
  1163.     /* user's login name.                                     */
  1164.  
  1165.     hDlgUserInfo = CreateDialog(hInstMegaphone, "UserInfo", hDlgMegaphone, 0L);
  1166.     SetWindowText(hDlgUserInfo, SelUserName);
  1167.  
  1168.     /* Initialize the user info dialog box by changing */
  1169.     /* the values of different static text fields to   */
  1170.     /* reflect acquired user information               */
  1171.  
  1172.     wsprintf(Text, ": %s", (LPSTR) SelUserName);
  1173.     SetDlgItemText(hDlgUserInfo, IDC_USERNAME, (LPSTR) Text);
  1174.  
  1175.     wsprintf(Text, ": %d", SelUserConnectionNum);
  1176.     SetDlgItemText(hDlgUserInfo, IDC_STATION, (LPSTR) Text);
  1177.  
  1178.     wsprintf(Text, ": %s", (LPSTR) SelUserFullName);
  1179.     SetDlgItemText(hDlgUserInfo, IDC_FULLNAME, (LPSTR) Text);
  1180.  
  1181.     wsprintf(Text, ": %02d/%02d/%02d %02d:%02d:%02d",
  1182.         SelUserLoginTime[1], SelUserLoginTime[2], SelUserLoginTime[0],
  1183.         SelUserLoginTime[3], SelUserLoginTime[4], SelUserLoginTime[5]);
  1184.     SetDlgItemText(hDlgUserInfo, IDC_LOGINTIME, (LPSTR) Text);
  1185.  
  1186.     wsprintf(Text, ": %02X%02X%02X%02X",
  1187.         SelUserNetworkAddr[0], SelUserNetworkAddr[1],
  1188.         SelUserNetworkAddr[2], SelUserNetworkAddr[3]);
  1189.     SetDlgItemText(hDlgUserInfo, IDC_NETWORK, (LPSTR) Text);
  1190.  
  1191.     wsprintf(Text, ": %02X%02X%02X%02X%02X%02X",
  1192.         SelUserNodeAddr[0], SelUserNodeAddr[1], SelUserNodeAddr[2],
  1193.         SelUserNodeAddr[3], SelUserNodeAddr[4], SelUserNodeAddr[5]);
  1194.     SetDlgItemText(hDlgUserInfo, IDC_NODE, (LPSTR) Text);
  1195.  
  1196.     ShowWindow(hDlgUserInfo, SW_SHOWNORMAL);
  1197. }
  1198.  
  1199.  
  1200. /*****************************************************************************
  1201.  
  1202.     FUNCTION: UserInfo
  1203.  
  1204.     PURPOSE : Processes messages for user info box
  1205.  
  1206. *****************************************************************************/
  1207.  
  1208. long FAR PASCAL UserInfo(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
  1209. {
  1210.     switch(wMsg)
  1211.     {
  1212.         case WM_COMMAND :
  1213.  
  1214.             if(wParam == IDOK || wParam == IDCANCEL)
  1215.             {
  1216.                 DestroyWindow(hWnd);
  1217.                 return(0L);
  1218.             }
  1219.             break;
  1220.  
  1221.         case WM_CLOSE   :
  1222.  
  1223.             DestroyWindow(hWnd);
  1224.             return(0L);
  1225.  
  1226.         case WM_ACTIVATE      :
  1227.  
  1228.             hWndCurrent = (wParam == NULL) ? NULL : hWnd;
  1229.             break;
  1230.  
  1231.         default         :
  1232.  
  1233.             break;
  1234.     }
  1235.     return(DefDlgProc(hWnd, wMsg, wParam, lParam));
  1236. }
  1237.  
  1238.  
  1239. [LISTING THREE]
  1240.  
  1241. #include "windows.h"
  1242. #include "megaphon.h"
  1243.  
  1244.  
  1245. Megaphone ICON MEGAPHON.ICO
  1246. Message   ICON MESSAGE.ICO
  1247. User      ICON USER.ICO
  1248.  
  1249.  
  1250. Megaphone MENU
  1251. BEGIN
  1252.     POPUP "&File"
  1253.     BEGIN
  1254.         MENUITEM "&Exit",      IDM_EXIT
  1255.         MENUITEM SEPARATOR
  1256.         MENUITEM "&About ...", IDM_ABOUT
  1257.     END
  1258.     MENUITEM "&Refresh!", IDM_REFRESH
  1259. END
  1260.  
  1261.  
  1262. Megaphone DIALOG 65, 75, 165, 139
  1263. CLASS     "Megaphone"
  1264. CAPTION   "Megaphone - NetWare Intercom"
  1265. STYLE     WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX
  1266. BEGIN
  1267.     CONTROL "Megaphone", -1, "static",
  1268.         SS_ICON | WS_CHILD, 24, 6, 0, 0
  1269.     CONTROL "&Users", IDC_USERLISTBOXTITLE, "static",
  1270.         SS_LEFTNOWORDWRAP | WS_CHILD, 65, 2, 95, 9
  1271.     CONTROL "", IDC_USERLISTBOX,    "listbox",
  1272.         LBS_STANDARD | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP |
  1273.         WS_CHILD,
  1274.         65, 12, 95, 71
  1275.     CONTROL "Ser&vers", IDC_SERVERCOMBOBOXTITLE, "static",
  1276.         SS_LEFTNOWORDWRAP | WS_CHILD,    5, 23, 55, 9
  1277.     CONTROL "", IDC_SERVERCOMBOBOX, "combobox",
  1278.         CBS_HASSTRINGS | CBS_SORT | CBS_DROPDOWNLIST |
  1279.         WS_VSCROLL | WS_TABSTOP | WS_CHILD,
  1280.         5, 33, 55, 63
  1281.     CONTROL "&Message", -1, "static", SS_LEFT | WS_CHILD,
  1282.         5, 80, 55, 9
  1283.     CONTROL "", IDC_MESSAGEEDITBOX, "edit",
  1284.         ES_LEFT | ES_AUTOHSCROLL | ES_UPPERCASE | WS_BORDER | WS_TABSTOP | WS_CHILD,
  1285.         5, 90, 155, 12
  1286.     CONTROL "&Send", IDC_SENDBUTTON, "button",
  1287.         BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD,
  1288.         5, 110, 45, 15
  1289.     CONTROL "Se&ttings", IDC_SETTINGSBUTTON, "button",
  1290.         BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD,
  1291.         60, 110, 45, 15
  1292.     CONTROL "&Exit", IDC_EXITBUTTON, "button",
  1293.         BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD,
  1294.         115, 110, 45, 15
  1295. END
  1296.  
  1297.  
  1298. Message DIALOG 100, 100, 170, 55
  1299. CAPTION "Message"
  1300. CLASS   "Message"
  1301. STYLE   WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX
  1302. BEGIN
  1303.     CONTROL "",        IDC_REPLYEDITBOX, "edit",
  1304.         ES_LEFT | ES_AUTOHSCROLL | ES_UPPERCASE | WS_BORDER |
  1305.         WS_TABSTOP | WS_CHILD, 5, 10, 155, 12
  1306.     CONTROL "&Reply",  IDC_REPLYBUTTON,  "button",
  1307.         BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 5, 30, 45, 15
  1308.     CONTROL "&Cancel", IDCANCEL,         "button",
  1309.         BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 60, 30, 45, 15
  1310.     CONTROL "&Save",   IDC_SAVEBUTTON,    "button",
  1311.         BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 115, 30, 45, 15
  1312. END
  1313.  
  1314.  
  1315. UserInfo DIALOG 68, 54, 145, 79
  1316. CAPTION  "User Information"
  1317. CLASS    "User"
  1318. STYLE    WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX
  1319. BEGIN
  1320.     CONTROL "User",       -1,           "static",
  1321.         SS_LEFTNOWORDWRAP | WS_CHILD, 42, 3, 18, 9
  1322.     CONTROL ":",          IDC_USERNAME,  "static",
  1323.         SS_LEFTNOWORDWRAP | WS_CHILD, 60, 3, 82, 9
  1324.     CONTROL "Stn",        -1,           "static",
  1325.         SS_LEFTNOWORDWRAP | WS_CHILD, 42, 12, 18, 9
  1326.     CONTROL ":",          IDC_STATION,   "static",
  1327.         SS_LEFTNOWORDWRAP | WS_CHILD, 60, 12, 77, 9
  1328.     CONTROL "Node",       -1,           "static",
  1329.         SS_LEFTNOWORDWRAP | WS_CHILD, 42, 21, 18, 9
  1330.     CONTROL ":",          IDC_NODE,      "static",
  1331.         SS_LEFTNOWORDWRAP | WS_CHILD, 60, 21, 77, 9
  1332.     CONTROL "Full Name",  -1,           "static",
  1333.         SS_LEFTNOWORDWRAP | WS_CHILD, 3, 30, 39, 9
  1334.     CONTROL ":",          IDC_FULLNAME,  "static",
  1335.         SS_LEFTNOWORDWRAP | WS_CHILD, 42, 30, 95, 9
  1336.     CONTROL "Login Time", -1,           "static",
  1337.         SS_LEFTNOWORDWRAP | WS_CHILD, 3, 39, 39, 9
  1338.     CONTROL ":",          IDC_LOGINTIME, "static",
  1339.         SS_LEFTNOWORDWRAP | WS_CHILD, 42, 39, 95, 9
  1340.     CONTROL "Network",    -1,           "static",
  1341.         SS_LEFTNOWORDWRAP | WS_CHILD, 3, 48, 39, 9
  1342.     CONTROL ":",          IDC_NETWORK,   "static",
  1343.         SS_LEFTNOWORDWRAP | WS_CHILD, 42, 48, 95, 9
  1344.     CONTROL "User",       -1,           "static",
  1345.         SS_ICON | WS_CHILD,           11, 6, 15, 15
  1346.     DEFPUSHBUTTON "OK", IDOK, 39, 60, 45, 15
  1347. END
  1348.  
  1349.  
  1350. Settings DIALOG 11, 21, 175, 65
  1351. CAPTION  "Settings"
  1352. STYLE    WS_POPUPWINDOW | WS_CAPTION
  1353. BEGIN
  1354.     CONTROL "&Incoming Messages", -1, "button",
  1355.         BS_GROUPBOX | WS_CHILD, 5, 5, 75, 35
  1356.     CONTROL "Accept", IDC_ACCEPTMESSAGES, "button",
  1357.         BS_AUTOCHECKBOX | WS_TABSTOP | WS_CHILD, 10, 15, 60, 10
  1358.     CONTROL "Iconize", IDC_ICONIZEMESSAGES, "button",
  1359.         BS_AUTOCHECKBOX | WS_TABSTOP | WS_CHILD, 10, 25, 60, 10
  1360.     CONTROL "&Users to scan", -1, "button",
  1361.         BS_GROUPBOX | WS_CHILD, 85, 5, 85, 35
  1362.     CONTROL "Attached users only", IDC_ONLYATTACHEDUSERS, "button",
  1363.         BS_AUTORADIOBUTTON | WS_CHILD, 90, 15, 75, 10
  1364.     CONTROL "Include unattached", IDC_ALLUSERSINBINDERY, "button",
  1365.         BS_AUTORADIOBUTTON | WS_CHILD, 90, 25, 75, 10
  1366.     CONTROL "&OK", IDOK, "button",
  1367.         BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 55, 45, 55, 15
  1368. END
  1369.  
  1370.  
  1371. About   DIALOG 22, 17, 110, 80
  1372. CAPTION "About"
  1373. STYLE   WS_POPUPWINDOW | WS_CAPTION
  1374. BEGIN
  1375.     CTEXT "Megaphone - NetWare Intercom" -1,  0,  5, 110,  8
  1376.     CTEXT "Version 1.0"                  -1,  0, 14, 110,  8
  1377.     CTEXT "by Mike Klein"                -1,  0, 22, 110,  8
  1378.     ICON  "User"                         -1, 13, 35,   0,  0
  1379.     ICON  "Megaphone"                    -1, 48, 35,   0,  0
  1380.     ICON  "Message"                      -1, 82, 35,   0,  0
  1381.     DEFPUSHBUTTON "OK"                 IDOK, 33, 60,  45, 15
  1382. END
  1383.  
  1384.  
  1385.  
  1386. [LISTING FOUR]
  1387.  
  1388. ; module-definition file for Megaphone -- used by LINK.EXE
  1389.  
  1390. NAME         Megaphone     ; application's module name
  1391. DESCRIPTION  'Megaphone - NetWare Intercom'
  1392. EXETYPE      WINDOWS       ; required for all Windows applications
  1393. STUB         'WINSTUB.EXE' ; Generates error message if application
  1394.                ; is run without Windows
  1395.  
  1396. ;CODE can be moved in memory and discarded/reloaded
  1397. CODE  PRELOAD MOVEABLE DISCARDABLE
  1398.  
  1399. ;DATA must be MULTIPLE if program can be invoked more than once
  1400. DATA  PRELOAD MOVEABLE MULTIPLE
  1401.  
  1402. HEAPSIZE     1024
  1403. STACKSIZE    5120       ; recommended minimum for Windows applications
  1404.  
  1405. ; All functions that will be called by any Windows routine
  1406. ; MUST be exported.
  1407.  
  1408. EXPORTS
  1409.     MainWndProc    @1
  1410.     About          @2
  1411.     UserInfo       @3
  1412.     MessageHandler @4
  1413.     Settings       @5
  1414.  
  1415.  
  1416.  
  1417. [LISTING FIVE]
  1418.  
  1419. # Standard Windows make file.  The utility MAKE.EXE compares the
  1420. # creation date of the file to the left of the colon with the file(s)
  1421. # to the right of the colon.  If the file(s) on the right are newer
  1422. # then the file on the left, Make will execute all of the command lines
  1423. # following this line that are indented by at least one tab or space.
  1424. # Any valid MS-DOS command line may be used.
  1425.  
  1426. # This line allows NMAKE to work as well
  1427.  
  1428. all: megaphon.exe
  1429.  
  1430. # Update the resource if necessary
  1431.  
  1432. megaphon.res: megaphon.rc megaphon.h megaphon.ico
  1433.     rc -r megaphon.rc
  1434.  
  1435. # Update the object file if necessary
  1436.  
  1437. megaphon.obj: megaphon.c megaphon.h
  1438.     cl -W4 -c -AS -Gsw -Oad -Zp megaphon.c
  1439.  
  1440. # Update the executable file if necessary, and if so, add the resource back in.
  1441.  
  1442. megaphon.exe: megaphon.obj megaphon.def
  1443.     link /NOD megaphon,,, libw slibcew snit, megaphon.def
  1444.     rc megaphon.res
  1445.  
  1446. # If the .res file is new and the .exe file is not, update the resource.
  1447. # Note that the .rc file can be updated without having to either 
  1448. # compile or link the file.
  1449.  
  1450. megaphon.exe: megaphon.res
  1451.     rc megaphon.res
  1452.  
  1453.