home *** CD-ROM | disk | FTP | other *** search
/ CICA 1992 November / CICA_MS_Windows_CD-ROM_Walnut_Creek_November_1992.iso / win3 / programr / textview / trace.c < prev    next >
C/C++ Source or Header  |  1991-06-13  |  17KB  |  573 lines

  1. /*****************************************************************************
  2.  
  3.     trace.c
  4.     -------
  5.  
  6.     This module is an example of how you could use the TextView DLL to add
  7.     a trace system to your application. The code here manages the 'Trace'
  8.     menu set up in the application's main window, and also contains a
  9.     routine that can be called to write a message to the trace window with
  10.     an arbitrary number of arguments.
  11.  
  12.     Copyright (c) Alan Phillips 1991
  13.  
  14.     This source may be freely used and adapted for use in non-commercial
  15.     applications. Those wishing to include it, and the TextView DLL in
  16.     commercial or ShareWare packages should first obtain the written agreement
  17.     of the author.
  18.  
  19.     The source has been edited using a tab width of 4 characters.
  20.  
  21. *****************************************************************************/
  22.  
  23. #include    "stdhead.h"
  24. #include    "menu.h"
  25.  
  26. #include    <stdarg.h>
  27.  
  28. /*****************************************************************************
  29.  
  30.     Local Procedures
  31.     ----------------
  32.  
  33. *****************************************************************************/
  34.  
  35. static    void    handle_file_menu(HWND,WORD);
  36. static    void    window_closed(HWND);
  37.  
  38. /*****************************************************************************
  39.  
  40.     Local Data
  41.     ----------
  42.  
  43. *****************************************************************************/
  44.  
  45. static    FARPROC    lpMenuHandler;        /* instance of menu handler function */
  46. static    HFONT    hFont;                /* handle to font used */
  47.  
  48.  
  49. /*****************************************************************************
  50.  
  51.     start_tracing
  52.     -------------
  53.  
  54.     This routine is called when the user clicks 'start tracing' in the
  55.     main window's 'Trace' menu. If a trace window does not already exist
  56.     it creates one, updating the menu accordingly. Otherwise, it simply
  57.     sets the application's 'tracing' flag to TRUE so that the trace() routine
  58.     will actually record messages
  59.  
  60.     start_tracing(hWnd)
  61.  
  62.     HWND        hWnd;                Handle to main window
  63.  
  64. *****************************************************************************/
  65.  
  66. void    start_tracing(HWND hWnd)
  67.  
  68. {
  69.     HMENU    hMenu;                    /* handle to main menu window */
  70.  
  71.     /* If we have a trace window already, just set the 'tracing' flag to
  72.     *  be TRUE and adjust the menu a bit
  73.     */
  74.  
  75.     if ( hTraceWnd != NULL )
  76.     {
  77.         tracing    = TRUE;
  78.         EnableMenuItem(GetMenu(hWnd),IDM_TRACE_OFF,MF_ENABLED|MF_BYCOMMAND);
  79.         EnableMenuItem(GetMenu(hWnd),IDM_TRACE_ON,MF_GRAYED|MF_BYCOMMAND);
  80.         return;
  81.     }
  82.  
  83.     /* We don't have a trace window, so we'll create one. If you want to use
  84.     *  your own font in the window, you need to define OWN_FONT above, and
  85.     *  alter the arguments to the CreateFont function here as required
  86.     */
  87.  
  88. #ifdef    OWN_FONT
  89.     hFont    =    CreateFont(    18,
  90.                             0,
  91.                             0,
  92.                             0,
  93.                             700,
  94.                             FALSE,
  95.                             FALSE,
  96.                             FALSE,
  97.                             ANSI_CHARSET,
  98.                             OUT_DEFAULT_PRECIS,
  99.                             CLIP_DEFAULT_PRECIS,
  100.                             DEFAULT_QUALITY,
  101.                             DEFAULT_PITCH | FF_DONTCARE,
  102.                             "Helv");
  103.  
  104.     if ( hFont == NULL )
  105.         message("Cannot create font",NULL,MB_ICONSTOP);        
  106. #endif
  107.  
  108.     /* Set up a procedure instance to our routine that handles clicks in the
  109.     *  trace window's menu. The DLL will call back into that routine to
  110.     *  notify us when the user does things. Note that you must specify this
  111.     *  routine as a procedure instance, and it must be exported in the
  112.     *  application's .DEF file
  113.     */
  114.  
  115.     lpMenuHandler    = MakeProcInstance(menu_handler,hInst);
  116.  
  117.     /* And create the TextView window we'll use for tracing */
  118.  
  119.     hTraceWnd    = TVCreateWindow("TRACE_WINDOW",
  120.                                  "Trace Window",
  121.                                  CW_USEDEFAULT,
  122.                                  CW_USEDEFAULT,
  123.                                  300,
  124.                                  200,
  125.                                  hInst,
  126. #ifdef    OWN_FONT
  127.                                  hFont,
  128. #else
  129.                                  NULL,
  130. #endif
  131.                                  TVS_TIMESTAMP | TVS_VSCROLL | TVS_HSCROLL |
  132.                                     TVS_SYSMENU | TVS_MINIMIZE |
  133.                                     TVS_FILESAVE | TVS_FILESAVEAS |
  134.                                     TVS_FILEPRINT | TVS_SCROLLMENU,
  135.                                  0,
  136.                                  4,
  137.                                  TRW_SIZE,
  138.                                  lpMenuHandler);
  139.  
  140.     /* You should always check that the window has in fact been created. If
  141.     *  you specified inconsistent arguments to the TVCreateWindow call the
  142.     *  DLL would return a NULL handle
  143.     */
  144.                                  
  145.     if ( hTraceWnd == NULL )
  146.     {
  147.         message("Cannot create trace window",NULL,MB_ICONSTOP);
  148.         return;
  149.     }
  150.  
  151.     /* The window now exists. We can now adjust the main window's 'Trace'
  152.     *  menu to make the appropriate items enabled
  153.     */
  154.  
  155.     hMenu    = GetMenu(hWnd);
  156.     EnableMenuItem(hMenu,IDM_TRACE_KILLWND,MF_ENABLED | MF_BYCOMMAND);
  157.     EnableMenuItem(hMenu,IDM_TRACE_OFF,MF_ENABLED | MF_BYCOMMAND);
  158.     EnableMenuItem(hMenu,IDM_TRACE_ON,MF_GRAYED | MF_BYCOMMAND);
  159.     EnableMenuItem(hMenu,IDM_TRACE_RESET,MF_ENABLED | MF_BYCOMMAND);
  160.     EnableMenuItem(hMenu,IDM_TRACE_SHOW,MF_ENABLED | MF_BYCOMMAND);
  161.     EnableMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_ENABLED | MF_BYCOMMAND);
  162.     EnableMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_ENABLED | MF_BYCOMMAND);
  163.     CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_CHECKED|MF_BYCOMMAND);
  164.     EnableMenuItem(hMenu,IDM_TRACE_COPY,MF_ENABLED | MF_BYCOMMAND);
  165.  
  166.     /* And now, with everything set up, we can set our own global flag to
  167.     *  mark that tracing is active. Once this is done, calls to the trace()
  168.     *  routine lower down will actually write to the TextView window
  169.     */
  170.     
  171.     tracing    = TRUE;
  172. }
  173.  
  174. /*****************************************************************************
  175.  
  176.     kill_trace_window
  177.     -----------------
  178.  
  179.     This routine is entered when the user clicks the 'kill window' item in the
  180.     main window's 'Trace' menu. It destroys the TextView window, and resets
  181.     the 'Trace' menu so that inappropriate items are no longer enabled.
  182.  
  183.     stop_tracing(hWnd)
  184.  
  185.     HWND    hWnd;                    Main window handle
  186.  
  187. *****************************************************************************/
  188.  
  189. void    kill_trace_window(HWND hWnd)
  190.  
  191. {
  192.     /* Call the TextView DLL to destroy the window. It's recommended that you
  193.     *  don't simply send a WM_DESTROY message to the handle, as in this case
  194.     *  the DLL will act as if the action was initiated from the system menu
  195.     *  close option, and will call back into the application to tell it
  196.     */
  197.  
  198.     TVDestroyWindow(hTraceWnd);
  199.  
  200.     /* Then call our tidy up routine to mark that tracing has stopped and
  201.     *  bring the 'Trace' menu into line
  202.     */
  203.  
  204.     window_closed(hWnd);
  205.  
  206. }
  207.  
  208.  
  209. /*****************************************************************************
  210.  
  211.     reset_tracing
  212.     -------------
  213.  
  214.     This routine is called when the user clicks the 'reset' item in the
  215.     main window's 'Trace' menu. It calls the TextView DLL to discard all
  216.     the lines stored so far in the trace window.
  217.  
  218.     reset_tracing(hWnd)
  219.  
  220.     HWND    hWnd;                        Handle to main window
  221.  
  222. *****************************************************************************/
  223.  
  224. void    reset_tracing(HWND hWnd)
  225.  
  226. {
  227.     /* Simply call the 'reset window' routine in the TextView DLL to reset
  228.     *  the trace window
  229.     */
  230.     
  231.     TVResetWindow(hTraceWnd);
  232. }
  233.  
  234. /*****************************************************************************
  235.  
  236.     report_trace_status
  237.     -------------------
  238.  
  239.     This routine is entered when the user clicks the 'report status' item in
  240.     the main window's 'Trace' menu. If the global variable hTraceWnd is NULL
  241.     there is no trace window; if not, it calls the TextView DLL to obtain
  242.     details of what the trace window is currently doing.
  243.  
  244.     report_trace_status()
  245.  
  246. *****************************************************************************/
  247.  
  248. void    report_trace_status()
  249.  
  250. {
  251.     TVWSTATUS    stats;                    /* status block for window */
  252.     
  253.     if ( hTraceWnd == NULL )
  254.     {
  255.         /* The global window handle is NULL, so the trace window does not
  256.         *  exist
  257.         */
  258.         
  259.         message("No trace window open","Info",NULL);
  260.         return;
  261.     }
  262.     else
  263.     {
  264.         /* There is a trace window, so we ask the DLL for details about it */
  265.  
  266.         if ( TVGetWindowStatus(hTraceWnd,&stats) == NULL )
  267.             message("Cannot get trace window status",NULL,MB_ICONSTOP);
  268.         else
  269.             message("Tracing is %sactive\nLines stored\t%d/%d\nScroll state\t%s\nRedrawing\t%s",
  270.                     "Info",
  271.                     NULL,
  272.                     (tracing) ? (LPSTR)"" : (LPSTR)"in",
  273.                     stats.nLinesStored,
  274.                     stats.nMaxLines,
  275.                     (stats.nScrollState == TV_SCR_AUTO) ? (LPSTR)"auto"
  276.                                                         : (LPSTR)"manual",
  277.                     (stats.nRedraw) ? (LPSTR)"enabled"
  278.                                     : (LPSTR)"disabled");
  279.                                 
  280.     }
  281. }
  282.  
  283.  
  284. /*****************************************************************************
  285.  
  286.     menu_handler
  287.     -------------
  288.  
  289.     This routine is called by the TextView DLL whenever the user clicks on
  290.     a menu item in the window (including the 'close' option in the system
  291.     menu).
  292.  
  293.     You use a routine such as this to keep the application informed of what
  294.     the user is doing in the TextView window. It's mandatory to have the routine
  295.     if the TextView window has been created with a 'File' menu or can be
  296.     closed from its 'System' menu; otherwise you need only have it if you want
  297.     to keep keep track, for example, of the window's scroll state.
  298.     
  299.     This routine must be in the EXPORT list in the application's .DEF file
  300.     and must be declared FAR PASCAL.
  301.  
  302.     menu_handler(hWnd,nMenuItem)
  303.  
  304.     HWND    hWnd;                    Window handle
  305.     WORD    nMenuItem;                Code for the menu item clicked
  306.  
  307. *****************************************************************************/
  308.  
  309. void    FAR    PASCAL    menu_handler(HWND hWnd,WORD nMenuItem)
  310.  
  311. {
  312.     HMENU    hMenu;                    /* handle to main window menu */
  313.  
  314.     /* The DLL passes back a code indicating the menu item that the user has
  315.     *  clicked on. Here we handle all the possible items for release 1.00.xxx
  316.     *  of the TextView DLL
  317.     */
  318.  
  319.     switch (nMenuItem)
  320.     {
  321.         case TVMI_CLOSE:                /* System menu close */
  322.  
  323.                 /* Call our handler function to clear out the window handle
  324.                 *  and do any other tidying up
  325.                 */
  326.  
  327.                 window_closed(hWnd);
  328.                 break;
  329.  
  330.         case TVMI_FILESAVE:                /* File save */
  331.         case TVMI_FILESAVEAS:            /* File save as */
  332.         case TVMI_FILEPRINT:            /* File print */
  333.  
  334.                 /* Pass this to a function that handles each of the menu
  335.                 *  items
  336.                 */
  337.  
  338.                 handle_file_menu(hWnd,nMenuItem);
  339.                 break;
  340.  
  341.         case TVMI_AUTOSCROLL:            /* Scroll auto */
  342.  
  343.                 /* Adjust the scroll items in our own menu so that they are
  344.                 *  step with the trace window's state
  345.                 */
  346.  
  347.                 hMenu    = GetMenu(hMainWnd);
  348.  
  349.                 CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_CHECKED|MF_BYCOMMAND);
  350.                 CheckMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_UNCHECKED|MF_BYCOMMAND);
  351.                 break;
  352.  
  353.         case TVMI_MANUALSCROLL:            /* Scroll manual */
  354.                 
  355.                 /* Adjust the scroll items in our own menu so that they are
  356.                 *  step with the trace window's state
  357.                 */
  358.  
  359.                 hMenu    = GetMenu(hMainWnd);
  360.  
  361.                 CheckMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_CHECKED|MF_BYCOMMAND);
  362.                 CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_UNCHECKED|MF_BYCOMMAND);
  363.                 break; 
  364.  
  365.         default:                        /* unknown item */
  366.  
  367.                 /* Anything else we don't handle. Later releases of the
  368.                 *  TextView DLL may add further menu items to those processed
  369.                 *  above, so this is not necessarily an error.
  370.                 */
  371.  
  372.                 message("Unknown menu item (%d) clicked",NULL,
  373.                                 MB_ICONSTOP,nMenuItem);
  374.                 break;
  375.     }
  376.  
  377. }
  378.  
  379. /*****************************************************************************
  380.  
  381.     trace
  382.     -----
  383.  
  384.     This routine can be called in your application to write one line to
  385.     the trace window. You pass it a FAR pointer to a null-terminated string,
  386.     and a value    giving the color to use when writing the text. Optionally,
  387.     you can    include arguments to be substituted in the text string with a
  388.     wsprintf call.
  389.  
  390.     Note that you must cast string pointers to LPSTR explicitly if you pass
  391.     them in the optional arguments.
  392.  
  393.     If the trace window does not exist, or if the global variable 'tracing'
  394.     is FALSE, the routine does nothing.
  395.  
  396.     Of course, there are an infinite number of other ways of writing a trace
  397.     routine; this merely demonstrates one possible approach.
  398.  
  399.     The technique used here to handle a variable number of arguments will
  400.     not work from within a DLL.
  401.  
  402.     reply = trace(format,color,...)
  403.  
  404.     BOOL    reply;                TRUE if message was written, else FALSE.
  405.                                 FALSE is returned only if the actual call
  406.                                 to TVOutputText fails
  407.     LPSTR    *format;            Message format string
  408.     COLORREF    color;            Color to use
  409.     ...                            Optional arguments
  410.  
  411. *****************************************************************************/
  412.  
  413. BOOL    trace(LPSTR format,COLORREF color,...)
  414.  
  415. {
  416.     char    buffer[256];                /* text assembly buffer */
  417.     va_list    arg_ptr;                    /* argument list pointer */
  418.  
  419.     /* So that you can control tracing within the program either by destroying
  420.     *  the trace window and setting the handle to NULL, or by setting a
  421.     *  global flag to FALSE to inhibit it, we do something here only if we
  422.     *  are actually supposed to.
  423.     *
  424.     *  (Note that there is another way to control whether something appears
  425.     *  in the trace window. You can call the DLL's TVSuspendWindow function
  426.     *  to mark the window as suspended, and in this state any attempt to
  427.     *  write a line to the window will also be ignored. However, that approach
  428.     *  will always call into the DLL, so that this technique is more efficient)
  429.     */
  430.  
  431.     if ( !tracing || hTraceWnd == NULL )
  432.         return(TRUE);
  433.  
  434.     /* Build the text to include any optional arguments. Note that any string
  435.     *  pointers in the list must have been cast to FAR pointers
  436.     */
  437.  
  438.     va_start(arg_ptr,color);
  439.     wvsprintf(buffer,format,arg_ptr);
  440.  
  441.     /* Call the DLL to write the line to the TextView window. Note that if
  442.     *  the window has been marked as suspended, or if it's in manual scroll
  443.     *  state, the line will be discarded.
  444.     */
  445.  
  446.     TVSetTextColor(hTraceWnd,color);
  447.     return( TVOutputText(hTraceWnd,buffer,lstrlen(buffer)) );
  448. }
  449.  
  450.  
  451. /*****************************************************************************
  452.  
  453.     handle_file_menu
  454.     -----------------
  455.  
  456.     This routine is called from the menu handler function to process
  457.     actions in the file menu. This has been put into a separate function to
  458.     keep the menu handler getting too large.
  459.  
  460.     handle_file_menu(hWnd,type)
  461.  
  462.     HWND    hWnd;            Handle of the TextView window concerned
  463.     WORD    nMenuItem;        Identity of the menu item clicked
  464.  
  465. *****************************************************************************/
  466.  
  467. static    void    handle_file_menu(HWND hWnd,WORD nMenuItem)
  468.  
  469. {
  470.     char    *ptr;                        /* ptr to message text */
  471.     
  472.     /* In this procedure you can take whatever you like. You might choose to
  473.     *  run a dialog to ask the user for a file name; then, using the
  474.     *  TVReturnData function, you could read back all the lines stored for
  475.     *  the window and write them to the file. For saving to file, you could
  476.     *  call the TVSaveWindowToFile function after asking the user for a
  477.     *  file name.
  478.     *
  479.     *  Here we simply put up a message box to report what the user clicked
  480.     *  on, and nothing else. Set up a string to identify the action to start
  481.     *  with...
  482.     */
  483.  
  484.     switch ( nMenuItem )
  485.     {
  486.         case TVMI_FILESAVE:                    /* 'File save' clicked */
  487.  
  488.                     ptr    = "File Save";
  489.                     break;
  490.  
  491.         case TVMI_FILESAVEAS:                /* 'File save as' clicked */
  492.  
  493.                     ptr    = "File Save As";
  494.                     break;
  495.  
  496.         case TVMI_FILEPRINT:                /* 'File Print' clicked */
  497.  
  498.                     ptr    = "File Print";
  499.                     break;
  500.  
  501.         default:                            /* this shouldn't happen... */
  502.  
  503.                     ptr    = "Unknown";
  504.                     break;
  505.     }
  506.  
  507.     /* Now report in a message box */
  508.  
  509.     message("User clicked '%s' menu item","Info",NULL,(LPSTR)ptr);
  510.  
  511. }
  512.  
  513. /*****************************************************************************
  514.  
  515.     window_closed
  516.     -------------
  517.  
  518.     This routine is called from the menu handler function to take the necessary
  519.     steps when the window has been closed. It is also called from the
  520.     application when it decides to close the trace window itself.
  521.     
  522.     window_closed(hWnd)
  523.  
  524.     HWND    hWnd;                    Window handler
  525.  
  526. *****************************************************************************/
  527.  
  528. static    void    window_closed(HWND hWnd)
  529.  
  530. {
  531.     HMENU    hMenu;                    /* handle to main window menu */
  532.  
  533.     /* Set the trace state to be off */
  534.  
  535.     tracing        = FALSE;
  536.  
  537.     /* And set our copy of the trace window handle to NULL */
  538.     
  539.     hTraceWnd    = NULL;
  540.  
  541.     /* Then adjust our trace menu so that the items reflect the fact that there
  542.     *  is now no trace window
  543.     */
  544.     
  545.     hMenu    = GetMenu(hMainWnd);
  546.     EnableMenuItem(hMenu,IDM_TRACE_ON,MF_ENABLED | MF_BYCOMMAND);
  547.     EnableMenuItem(hMenu,IDM_TRACE_KILLWND,MF_GRAYED | MF_BYCOMMAND);
  548.     EnableMenuItem(hMenu,IDM_TRACE_RESET,MF_GRAYED | MF_BYCOMMAND);
  549.     EnableMenuItem(hMenu,IDM_TRACE_SHOW,MF_GRAYED | MF_BYCOMMAND);
  550.     EnableMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_GRAYED | MF_BYCOMMAND);
  551.     EnableMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_GRAYED | MF_BYCOMMAND);
  552.     CheckMenuItem(hMenu,IDM_TRACE_SCR_AUTO,MF_UNCHECKED|MF_BYCOMMAND);
  553.     CheckMenuItem(hMenu,IDM_TRACE_SCR_MAN,MF_UNCHECKED|MF_BYCOMMAND);
  554.     EnableMenuItem(hMenu,IDM_TRACE_COPY,MF_GRAYED | MF_BYCOMMAND);
  555.  
  556.     /* Free the proc instance to the menu handler function, if there is one */
  557.  
  558.     if ( lpMenuHandler != NULL )
  559.         FreeProcInstance(lpMenuHandler);
  560.  
  561.     /* And delete the font we were using if we didn't let TextView use the
  562.     *  default non-proportional system font
  563.     */
  564.  
  565. #ifdef    OWN_FONT
  566.     DeleteObject(hFont);
  567. #endif
  568.                     
  569. }
  570.  
  571.  
  572.  
  573.