



Online document


             PMM  OS/2 Presentation Manager Monitor Version 1.0

                          J. Salvador Amoros, 1999




                            Table of Contents
                            



 1. PMM  OS/2 Presentation Manager Monitor . .  1
 2. Installing and Using PMM . . . . . . . . .  1
    Installation Procedure . . . . . . . . . .  2
    How to Use PMM in an Application . . . . .  2
    Considerations About Debuggers . . . . . .  4
 3. Using Hooks with PMM . . . . . . . . . . .  5
 4. Subclassing Windows when Using PMM . . . .  6
 5. Messages Traced by PMM . . . . . . . . . . 10
 6. The PMM Interface  . . . . . . . . . . . . 25
    List of Functions  . . . . . . . . . . . . 25
    List of Errors and Warnings  . . . . . . . 51
       Errors Returned by Functions  . . . . . 51
       Errors Occurring when Using PMM . . . . 53
       Warnings Occurring when Using PMM . . . 54
 7. PMM Message Trace Format . . . . . . . . . 55
 8. Notes About PMM  . . . . . . . . . . . . . 59
 9. Errors Detected in the Documentation . . . 61
10. PMM Limits . . . . . . . . . . . . . . . . 62
11. Tools Used in Creating PMM . . . . . . . . 62
12. Acknowledgments  . . . . . . . . . . . . . 63
13. Disclaimer . . . . . . . . . . . . . . . . 63
14. Trademarks . . . . . . . . . . . . . . . . 63
















                                     i



        1. PMM  OS/2 Presentation Manager Monitor
        


        PMM is a learning and debugging tool aimed to show the flow of
        messages produced in a Presentation Manager (PM) application.
        PMM monitors messages received by windows, writing them to a file.
        Messages posted to a queue or a window and messages sent via
        WinSendMsg or through a pointer are traced.  Messages are
        interpreted, formatted and shown as they occur in an application.
        PMM gives you information about:

        -  The message stream
        -  The attributes of the destination window of a message
        -  The parameters of a message
        -  How a message reached the window procedure
        -  The return value of a message

        PMM is a tool that works inside your application.  It is not a
        separate program running in the operating system.  The PMM interface
        is a set of functions that you must call from your code.  You
        control what messages to trace, how to trace them, when to trace
        them and other important aspects of messages.

        You use PMM by creating a trace session in your program and
        customizing it to your learning/debugging needs.  You can start and
        stop tracing messages from inside your code as well as from the
        keyboard.  To help debugging, you can write text to the trace file
        at any point in your code and at any time.

        PM messages are divided into groups.  You can select one or more
        groups of messages, to selectively trace the messages that you are
        interested in.  You can trace messages related to one or more PM
        controls and you can control most of the message information that
        will be shown in the trace file.



        2. Installing and Using PMM
        


        To install and use PMM, you will need:

        1. OS/2 2.1 or higher.
        2. A C/C++ compiler.
        3. The "#include" files PMMPOS2.H and PMM.H.
        4. The library file PMM.LIB.
        5. The dynamic link library PMM.DLL.





                                   - 1 -



        Installation Procedure
        

        1. Copy the dynamic link library PMM.DLL to any directory listed in
           the LIBPATH environment variable.
        2. Copy the library file PMM.LIB to any directory listed in the LIB
           environment variable.
        3. Copy the include files PMMPOS2.H and PMM.H to any directory you
           choose.  Unless the directory is listed in the INCLUDE
           environment variable, you will need to use a path when including
           them.
        4. If you have modified your CONFIG.SYS file you may need to reboot
           OS/2 to activate the changes.

        Here is an example.  Let's assume that you decide to place PMM in
        the directory C:\PMM.  Do the following:

        1. Create the directory
        2. Copy all files included in the PMM package to this directory
        3. Add C:\PMM to your LIBPATH environment variable:

           LIBPATH=C:\IBMWF21\DLL;C:\PMM;

        4. Add C:\PMM to your LIB environment variable:

           SET LIB=C:\TOOLKT21\OS2LIB;C:\IBMCPP\LIB;C:\PMM;

        5. Add C:\PMM to your INCLUDE environment variable:

           SET INCLUDE=C:\TOOLKT21\C\OS2H;C:\IBMCPP\INCLUDE;C:\PMM;

        6. Reboot OS/2 to activate the changes


        How to Use PMM in an Application
        

        Follow these steps:

        1. Include the file PMMPOS2.H immediately before the line that
           includes OS2.H.
        2. Include the file PMM.H at any point after the line that
           includes OS2.H.
        3. Code the functions needed to create a trace session, to start
           tracing, to customize PMM, etc., as shown later in this section.
           If you use hooks or subclass windows, you must read carefully the
           sections "Using Hooks with PMM," and "Subclassing Windows when
           Using PMM," in this manual.
        4. Link your program with the library PMM.LIB.
        5. Compile and run your program.




                                   - 2 -



        Example:

        // Conditional compilation. Activate/deactivate PMM easily
        #define USE_PMM  1

        // Define some constants needed in your program
        #define INCL_WININPUT
        #define INCL_WINWINDOWMGR

        // Include this file immediately before including "os2.h"
        #if USE_PMM
           #include "pmmpos2.h"
        #endif

        #include <os2.h>

        // Include header files as needed
        #include <stdio.h>
        #include <string.h>
        #include <stdlib.h>

        // Include the "main" PMM file
        #if USE_PMM
           #include "pmm.h"
        #endif

        int main( int argc, char * argv[] )
        {
           HAB hab;
           HMQ hmq;
           QMSG qmsg;

        #if USE_PMM
           HPMMSESSION hpmms;
           PMMRET pmmr;
        #endif

           hab = WinInitialize( 0 );
           if ( !hab )
              return 1; /* Error */

           hmq = WinCreateMsgQueue( hab, 0 );
           if ( !hmq )
           {
              WinTerminate( hab );
              return 2; /* Error */
           }

           // Return codes from PMM are not tested in this example,
           // they should be tested




                                   - 3 -



           // Create a trace session and start tracing
        #if USE_PMM
           pmmr = PMMCreateTraceSession( &hpmms, hab, "pmm.log" );
           pmmr = PMMStartTracing( hpmms );
        #endif

           // Initialize resources
           // Create the main window

           while( WinGetMsg( hab, &qmsg, 0, 0, 0 ) )
              WinDispatchMsg( hab, &qmsg );

           // Destroy the main window if it exists
           // Free resources

           // Stop tracing and destroy the trace session
        #if USE_PMM
           pmmr = PMMStopTracing( hpmms );
           pmmr = PMMDestroyTraceSession( hpmms );
        #endif

           WinDestroyMsgQueue( hmq );

           WinTerminate( hab );

           return 0; /* Success */
        } // End of main


        Considerations About Debuggers
        

        You can use any debugger when using PMM.  Debuggers, in general,
        intercept exceptions produced in an application and, when one is
        detected, let you choose the next action to be performed.  Then you
        can, for instance, investigate the cause of the exception or run the
        registered exception handlers.  PMM tests all pointers involved in
        a message and will report an access violation exception when a
        memory address is inaccessible.  At this point you should run the
        registered exception handlers to inform PMM to handle the exception;
        execution will continue.  PMM will display the inaccessible pointer
        in the message trace file.

        See the function PMMShowPointers in the section "The PMM Interface."










                                   - 4 -



        3. Using Hooks with PMM
        


        You can skip this section if your application doesn't use send
        message hooks or input hooks.

        PMM uses hooks and subclassing to keep track of all messages
        occurring in an application.  Currently, PMM uses a send message
        hook and an input hook installed in an application message queue.
        No system hooks are used.  Hooks are called on a FIFO basis, that
        is, the most recently installed hook is called first.  Given this,
        when using hooks with PMM you need to be aware of the following
        facts:

        - PMM introduces some messages in the message stream of an
          application
        - PMM temporarily alters messages sent by an application to windows
          of another process.

        Therefore, in a send message hook an application should:

        - ignore some messages introduced by PMM
        - process the unaltered messages, i.e. the messages received in the
          hook as if the application were not using PMM.

        An application does this by using the functions PMMQueryIfIgnoreMsg
        and PMMSMHQueryMsg.  See the example code in the function
        PMMSMHQueryMsg.

        A send message hook is installed when an application calls
        PMMCreateTraceSession.  From this point on, any send message hook,
        whether installed *before* or installed *after* calling
        PMMCreateTraceSession, may receive messages introduced by PMM or
        messages modified by PMM.  The send message hook is uninstalled when
        an application calls PMMDestroyTraceSession.

        If an application installs a send message hook and/or an input hook
        after calling PMMCreateTraceSession, the calling order of the
        hook(s) will be: the hook(s) installed by the application followed
        by the hook(s) installed by PMMCreateTraceSession.  In this case
        note that:

        - an application may modify any value in the structures received in
          the hooks: SMHSTRUCT and QMSG
        - in an input hook, an application may need not to pass on the
          message to the next hook in the chain or to the application.

        Assuming this,

        - PMM will "receive" and trace any message modified by the



                                   - 5 -



          application's send message hook.  The unaltered message (before
          the application send message hook) cannot be traced
        - PMM will not trace a message that is not passed on in an
          input hook
        - PMM intercepts the WM_TRANSLATEACCEL and the WM_CHAR messages in
          order to start and stop tracing through the keyboard.  An
          application using hooks may modify or not pass on these messages.
          Depending on the changes, the PMM logic to start and stop tracing
          may not work.



        4. Subclassing Windows when Using PMM
        


        You can skip this section if your application doesn't subclass
        windows.

        An application may receive messages sent by other applications in
        the system.  An example is the DM_PRINTOBJECT message.  As
        documentation states, this message is sent to a source application
        that supports the DRM_PRINT rendering method when objects are
        dropped on a printer object.  Also, as mentioned in the
        documentation when describing the SendMsgHook function, the send
        message hook function is called *only* in the context of the sender,
        i.e. if the sender has a queue hook installed it is called, but if
        the receiver has a queue hook installed it is not called.  That is,
        *not* all messages that a window receives pass through a hook.

        If the message trace has to be correct, i.e. intercept and show
        *all* messages received by a window, the only real solution to this
        problem is to subclass every window traced.  This is what PMM does.
        If a trace session has been created, PMM subclasses each window on
        the first message that it intercepts for that window, and
        unsubclasses it when the window or the trace session is destroyed.
        An application may subclass freely a window when using PMM since
        PMM maintains a linked list of window procedures and sends the
        messages to the appropriate window procedure.  To intercept all
        messages that a window receives, PMM makes sure that the current
        window procedure of a window is always a "PMM window procedure";
        then the PMM window procedure sends the message to the "real"
        (class or application) window procedure.

        The PMM include file PMM.H creates some macros redefining
        WinSubclassWindow as PMMSubclassWindow, WinSetWindowPtr as
        PMMSetWindowPtr and WinQueryWindowPtr as PMMQueryWindowPtr.
        By default, an application will use these macros when including
        the file PMM.H.  See the functions PMMSubclassWindow,
        PMMSetWindowPtr and PMMQueryWindowPtr.




                                   - 6 -



        An example follows about subclassing:

        1. Assume that a PMM trace session has been created
        2. The application creates the window 'W'.  The window procedure
           of 'W' is, at create time, 'pfnwpApp0'
        3. PMM intercepts the WM_CREATE message for the window 'W' and
           subclasses the window with the window procedure 'pfnwpPMM0'.
           The window procedures of 'W' are:

           pfnwpApp0 -> pfnwpPMM0

           where 'pfnwpPMM0' is the current window procedure of 'W'

        4. The application subclasses the window 'W' with the window
           procedure 'pfnwpApp1'.  The old window procedure returned to the
           application is 'pfnwpPMM0'.  The window procedures of 'W' are:

           pfnwpApp0 -> pfnwpPMM0 -> pfnwpApp1

           Now, we have two cases:

           4.1 The application has used the PMMSubclassWindow function to
               subclass the window.  PMM knows that a subclassing has been
               made and subclasses the window again.  The window procedures
               of 'W' are:

               pfnwpApp0 -> pfnwpPMM0 -> pfnwpApp1 -> pfnwpPMM1

               From now on, all messages will be intercepted and shown in
               the trace file as they were received in the window procedure.

           4.2 The application has not used the PMMSubclassWindow function
               to subclass the window.  PMM doesn't know that a subclassing
               has been made and does nothing.  The window procedures of 'W'
               do not change:

               pfnwpApp0 -> pfnwpPMM0 -> pfnwpApp1 (same as before)

               Suppose that a message is sent to the window 'W'.  We have:

               4.2.1 The message is sent using a pointer.  For this example,
                     it must be 'pfnwpApp1'.  We have two possibilities:

                     4.2.1.1 The message is processed by 'pfnwpApp1', i.e.
                             not passed to the old window procedure.  The
                             window procedures of 'W' remain:

                             pfnwpApp0 -> pfnwpPMM0 -> pfnwpApp1

                             Since PMM is not aware that a subclassing has
                             been made, this message will not appear in the



                                   - 7 -



                             trace file.

                     4.2.1.2 'pfnwpApp1' passes the message back to the old
                             window procedure, which is 'pfnwpPMM0'.  PMM
                             subclasses 'W' with 'pfnwpPMM1' and sends the
                             message to 'pfnwpApp0'.  Now, the window
                             procedures of 'W' are:

                             pfnwpApp0 -> pfnwpPMM0 -> pfnwpApp1 -> pfnwpPMM1

                             'pfnwpApp1' may modify the message before
                             passing it back to the old window procedure.
                             The message, whether modified or not, is shown
                             in the trace file.  From now on, all messages
                             will be intercepted and shown in the trace file
                             as they were received in the window procedure.

               4.2.2 The message is sent or posted using WinSendMsg or
                     WinPostMsg.  PMM intercepts the message, subclasses
                     'W' with 'pfnwpPMM1' and sends the message to
                     'pfnwpApp0'.  The window procedures of 'W' are:

                     pfnwpApp0 -> pfnwpPMM0 -> pfnwpApp1 -> pfnwpPMM1

                     All messages will be intercepted and shown in the trace
                     file as they were received in the window procedure.

        Note that, in the case illustrated by 4.2.1.1 above, a message will
        not be traced.  An application may avoid this by using, whenever
        possible, the function PMMSubclassWindow or the combination
        PMMQueryWindowPtr/PMMSetWindowPtr.

        Another example will clarify further the way PMM handles
        subclassing.  Assume that a window has the following chain of
        window procedures:

        pfnwpApp0 -> pfnwpPMM0 -> pfnwpApp1 -> pfnwpPMM1

        A message is sent or posted to that window using WinSendMessage,
        WinPostMsg or through a pointer.  The message will arrive at
        'pfnwpPMM1', which is the end of the chain of window procedures
        associated with the window.  'pfnwpPMM1' logs the message, and
        passes it on to 'pfnwpApp1', which may at its option pass the
        message on to 'pfnwpPMM0'.  In 'pfnwpPMM0', the message is logged
        again if 'pfnwpApp1' has changed the message.  In any event,
        'pfnwpPMM0' then passes the message on to the original (create
        time) window procedure, 'pfnwpApp0'.

        Regarding an application, subclassing has several implications:

        - A window may have one or more window procedures, each one of them



                                   - 8 -



          responding to some specific messages and passing the others to
          another window procedure.  For a window, OS/2 has only a pointer
          to the "current" window procedure; that is, OS/2 doesn't maintain
          a list of window procedures when an application is subclassing a
          window.  PMM cannot know the "history" of a window before a trace
          session has been created. PMM knows only the last window procedure
          that has been assigned to a window (when it is created or when is
          subclassed) and, starting from this window procedure, maintains a
          list of window procedures.  All this adds up to the following:
          some messages may not be traced if an application subclasses
          windows and then creates a trace session.

        - A window subclassed after calling PMMCreateTraceSession must be
          unsubclassed, if it exists, before calling PMMDestroyTraceSession.

        - There is a limit on the number of times that an application can
          subclass a window.  See the section "PMM Limits."  Note, however,
          that for practical purposes no such a limit exists.

        - When not using PMM, given this sequence of calls:

          pfnwpB = WinSubclassWindow( hwnd, pfnwpA );
          pfnwpC = WinSubclassWindow( hwnd, pfnwpB );

          'pfnwpA' is equal to 'pfnwpC', at end of execution.

          This is not true when using PMM.  Suppose that an application
          executes this code:

          /*
          Assume that a trace session has been created.
          PMM has subclassed 'hwnd' with 'pfnwpPMM0' (internal to PMM)
          before the aplication uses WinSubclassWindow.  We have:

          pfnwpDefault -> pfnwpPMM0

          The following code subclasses 'hwnd' with
          a new window procedure: 'pfnwpA'.
          The returned old window procedure is 'pfnwpB'.
          */

          pfnwpB = WinSubclassWindow( hwnd, pfnwpA );

          /*
          At this point, if an application uses PMMSubclassWindow, the
          window is subclassed with a new window procedure: 'pfnwpPMM1'
          (internal to PMM).  We have:

          pfnwpDefault -> pfnwpPMM0 -> pfnwpA -> pfnwpPMM1

          If an application does not use PMMSubclassWindow the window is



                                   - 9 -



          subclassed with 'pfnwpA'.  We have:

          pfnwpDefault -> pfnwpPMM0 -> pfnwpA
          */

          /* This will generate a WM_SETWINDOWPARAMS message */
          WinSetWindowText( hwnd, "sample" );
          /*
          At this point, if the application used PMMSubclassWindow, PMM does
          nothing.  If the application did not use PMMSubclassWindow, the
          window is now subclassed with a new window procedure: 'pfnwpPMM1'.
          In either case, we have:

          pfnwpDefault -> pfnwpPMM0 -> pfnwpA -> pfnwpPMM1
          */

          /* Undo the subclassing */
          pfnwpC = WinSubclassWindow( hwnd, pfnwpB );
          /*
          If an application uses PMMSubclassWindow, PMM will undo the
          subclassing: now 'hwnd' has the same window procedure that it had
          before any subclassing has been done.  The final situation is:

          pfnwpDefault -> pfnwpPMM0

          which is correct.  At this point, however, 'pfnwpA' is *not* equal
          to 'pfnwpC'.  'pfnwpC' is the window procedure that the window had
          before undoing the subclassing, i.e. 'pfnwpPMM1', not the window
          procedure that the window had before doing the first subclassing,
          i.e. 'pfnwpPMM0'.
          */



        5. Messages Traced by PMM
        


        All the PM messages are divided into groups, and a group can have
        subgroups.  PMM considers the following groups and subgroups and
        traces the following messages:

        - Group: Window messages.
          The following messages are traced:

          WM_ACTIVATE
          WM_ADJUSTWINDOWPOS
          WM_CALCVALIDRECTS
          WM_CLOSE
          WM_COMMAND
          WM_CREATE



                                  - 10 -



          WM_DESTROY
          WM_ENABLE
          WM_HELP
          WM_INITDLG
          WM_MATCHMNEMONIC
          WM_MOVE
          WM_NULL
          WM_PACTIVATE
          WM_PAINT
          WM_PPAINT
          WM_PRESPARAMCHANGED
          WM_PSETFOCUS
          WM_PSIZE
          WM_QUERYDLGCODE
          WM_QUERYWINDOWPARAMS
          WM_QUIT
          WM_SAVEAPPLICATION
          WM_SETFOCUS
          WM_SETSELECTION
          WM_SETWINDOWPARAMS
          WM_SHOW
          WM_SIZE
          WM_SUBSTITUTESTRING
          WM_SYSCOMMAND

        - Group: messages related to PM standard controls.
          This group has subgroups.  Below each subgroup are the messages
          that PMM traces:

          - Subgroup: messages related to the Frame control.
            The following messages are traced:

            WM_ADJUSTFRAMEPOS
            WM_CALCFRAMERECT
            WM_ERASEBACKGROUND
            WM_ERROR
            WM_FLASHWINDOW
            WM_FOCUSCHANGE
            WM_FORMATFRAME
            WM_MINMAXFRAME
            WM_OWNERPOSCHANGE
            WM_QUERYACCELTABLE
            WM_QUERYBORDERSIZE
            WM_QUERYFOCUSCHAIN
            WM_QUERYFRAMECTLCOUNT
            WM_QUERYFRAMEINFO
            WM_QUERYHELPINFO
            WM_QUERYICON
            WM_QUERYTRACKINFO
            WM_SETACCELTABLE
            WM_SETBORDERSIZE



                                  - 11 -



            WM_SETHELPINFO
            WM_SETICON
            WM_TRACKFRAME
            WM_TRANSLATEACCEL
            WM_TRANSLATEMNEMONIC (See Note)*
            WM_UPDATEFRAME
            WM_WINDOWPOSCHANGED

          *Note: The WM_TRANSLATEMNEMONIC message doesn't appear in the
          toolkit include files.  Its value is 195 (hexadecimal).

          - Subgroup: messages related to the Combo Box control.
            The following messages are traced:

            CBM_HILITE
            CBM_ISLISTSHOWING
            CBM_SHOWLIST
            WM_CONTROL and WM_PCONTROL with these notifications:

               CBN_EFCHANGE
               CBN_EFSCROLL
               CBN_ENTER
               CBN_LBSCROLL
               CBN_LBSELECT
               CBN_MEMERROR
               CBN_SHOWLIST
               and unknown notifications

          - Subgroup: messages related to the Button control.
            The following messages are traced:

            BM_CLICK
            BM_QUERYCHECK
            BM_QUERYCHECKINDEX
            BM_QUERYHILITE
            BM_SETCHECK
            BM_SETDEFAULT
            BM_SETHILITE
            WM_CONTROL and WM_PCONTROL with these notifications:

               BN_CLICKED
               BN_DBLCLICKED
               BN_PAINT
               and unknown notifications

          - Subgroup: messages related to the Menu control.
            The following messages are traced:

            MM_DELETEITEM
            MM_ENDMENUMODE
            MM_INSERTITEM



                                  - 12 -



            MM_ISITEMVALID
            MM_ITEMIDFROMPOSITION
            MM_ITEMPOSITIONFROMID
            MM_QUERYDEFAULTITEMID
            MM_QUERYITEM
            MM_QUERYITEMATTR
            MM_QUERYITEMCOUNT
            MM_QUERYITEMRECT
            MM_QUERYITEMTEXT
            MM_QUERYITEMTEXTLENGTH
            MM_QUERYSELITEMID
            MM_REMOVEITEM
            MM_SELECTITEM
            MM_SETDEFAULTITEMID
            MM_SETITEM
            MM_SETITEMATTR
            MM_SETITEMHANDLE
            MM_SETITEMTEXT
            MM_STARTMENUMODE
            WM_DRAWITEM
            WM_INITMENU
            WM_MEASUREITEM
            WM_MENUEND
            WM_MENUSELECT
            WM_NEXTMENU

          - Subgroup: messages related to the Static control.
            The following messages are traced:

            SM_QUERYHANDLE
            SM_SETHANDLE

          - Subgroup: messages related to the Entry Field control.
            The following messages are traced:

            EM_CLEAR
            EM_COPY
            EM_CUT
            EM_PASTE
            EM_QUERYCHANGED
            EM_QUERYFIRSTCHAR
            EM_QUERYREADONLY
            EM_QUERYSEL
            EM_SETFIRSTCHAR
            EM_SETINSERTMODE
            EM_SETREADONLY
            EM_SETSEL
            EM_SETTEXTLIMIT
            WM_CONTROL and WM_PCONTROL with these notifications:

               EN_CHANGE



                                  - 13 -



               EN_INSERTMODETOGGLE
               EN_KILLFOCUS
               EN_MEMERROR
               EN_OVERFLOW
               EN_SCROLL
               EN_SETFOCUS
               and unknown notifications

          - Subgroup: messages related to the List Box control.
            The following messages are traced:

            LM_DELETEALL
            LM_DELETEITEM
            LM_INSERTITEM
            LM_QUERYITEMCOUNT
            LM_QUERYITEMHANDLE
            LM_QUERYITEMTEXT
            LM_QUERYITEMTEXTLENGTH
            LM_QUERYSELECTION
            LM_QUERYTOPINDEX
            LM_SEARCHSTRING
            LM_SELECTITEM
            LM_SETITEMHANDLE
            LM_SETITEMHEIGHT
            LM_SETITEMTEXT
            LM_SETTOPINDEX
            WM_CONTROL and WM_PCONTROL with these notifications:

               LN_ENTER
               LN_KILLFOCUS
               LN_SCROLL
               LN_SELECT
               LN_SETFOCUS
               and unknown notifications

            WM_DRAWITEM
            WM_MEASUREITEM

          - Subgroup: messages related to the Scroll Bar control.
            The following messages are traced:

            SBM_QUERYPOS
            SBM_QUERYRANGE
            SBM_SETPOS
            SBM_SETSCROLLBAR
            SBM_SETTHUMBSIZE
            WM_HSCROLL
            WM_VSCROLL

          - Subgroup: Messages related to the Title Bar control.
            The following messages are traced:



                                  - 14 -



            TBM_QUERYHILITE
            TBM_SETHILITE

          - Subgroup: messages related to the Multi-Line Entry Field
            control.
            The following messages are traced:

            MLM_CHARFROMLINE
            MLM_CLEAR
            MLM_COPY
            MLM_CUT
            MLM_DELETE
            MLM_DISABLEREFRESH
            MLM_ENABLEREFRESH
            MLM_EXPORT
            MLM_FORMAT
            MLM_IMPORT
            MLM_INSERT
            MLM_LINEFROMCHAR
            MLM_PASTE
            MLM_QUERYBACKCOLOR
            MLM_QUERYCHANGED
            MLM_QUERYFIRSTCHAR
            MLM_QUERYFONT
            MLM_QUERYFORMATLINELENGTH
            MLM_QUERYFORMATRECT
            MLM_QUERYFORMATTEXTLENGTH
            MLM_QUERYIMPORTEXPORT
            MLM_QUERYLINECOUNT
            MLM_QUERYLINELENGTH
            MLM_QUERYREADONLY
            MLM_QUERYSEL
            MLM_QUERYSELTEXT
            MLM_QUERYTABSTOP
            MLM_QUERYTEXTCOLOR
            MLM_QUERYTEXTLENGTH
            MLM_QUERYTEXTLIMIT
            MLM_QUERYUNDO
            MLM_QUERYWRAP
            MLM_RESETUNDO
            MLM_SEARCH
            MLM_SETBACKCOLOR
            MLM_SETCHANGED
            MLM_SETFIRSTCHAR
            MLM_SETFONT
            MLM_SETFORMATRECT
            MLM_SETIMPORTEXPORT
            MLM_SETREADONLY
            MLM_SETSEL
            MLM_SETTABSTOP
            MLM_SETTEXTCOLOR



                                  - 15 -



            MLM_SETTEXTLIMIT
            MLM_SETWRAP
            MLM_UNDO
            WM_CONTROL and WM_PCONTROL with these notifications:

               MLN_CHANGE
               MLN_CLPBDFAIL
               MLN_HSCROLL
               MLN_KILLFOCUS
               MLN_MARGIN
               MLN_MEMERROR
               MLN_OVERFLOW
               MLN_PIXHORZOVERFLOW
               MLN_PIXVERTOVERFLOW
               MLN_SEARCHPAUSE
               MLN_SETFOCUS
               MLN_TEXTOVERFLOW
               MLN_UNDOOVERFLOW
               MLN_VSCROLL
               and unknown notifications

          - Subgroup: messages related to the AppStat control.

            No messages are traced.

          - Subgroup: messages related to the KbdStat control.

            No messages are traced.

          - Subgroup: messages related to the Pecic control.

            No messages are traced.

          - Subgroup: messages related to the DBE_KKPopup control.

            No messages are traced.

          - Subgroup: messages related to the Spin Button control.
            The following messages are traced:

            SPBM_OVERRIDESETLIMITS
            SPBM_QUERYLIMITS
            SPBM_QUERYVALUE
            SPBM_SETARRAY
            SPBM_SETCURRENTVALUE
            SPBM_SETLIMITS
            SPBM_SETMASTER
            SPBM_SETTEXTLIMIT
            SPBM_SPINDOWN
            SPBM_SPINUP




                                  - 16 -



            WM_CONTROL and WM_PCONTROL with these notifications:

               SPBN_CHANGE
               SPBN_DOWNARROW
               SPBN_ENDSPIN
               SPBN_KILLFOCUS
               SPBN_SETFOCUS
               SPBN_UPARROW
               and unknown notifications

          - Subgroup: messages related to the Container control.
            The following messages are traced:

            CM_ALLOCDETAILFIELDINFO
            CM_ALLOCRECORD
            CM_ARRANGE
            CM_CLOSEEDIT
            CM_COLLAPSETREE
            CM_ERASERECORD
            CM_EXPANDTREE
            CM_FILTER
            CM_FREEDETAILFIELDINFO
            CM_FREERECORD
            CM_HORZSCROLLSPLITWINDOW
            CM_INSERTDETAILFIELDINFO
            CM_INSERTRECORD
            CM_INVALIDATEDETAILFIELDINFO
            CM_INVALIDATERECORD
            CM_OPENEDIT
            CM_PAINTBACKGROUND
            CM_QUERYCNRINFO
            CM_QUERYDETAILFIELDINFO
            CM_QUERYDRAGIMAGE
            CM_QUERYRECORD
            CM_QUERYRECORDEMPHASIS
            CM_QUERYRECORDFROMRECT
            CM_QUERYRECORDINFO
            CM_QUERYRECORDRECT
            CM_QUERYVIEWPORTRECT
            CM_REMOVEDETAILFIELDINFO
            CM_REMOVERECORD
            CM_SCROLLWINDOW
            CM_SEARCHSTRING
            CM_SETCNRINFO
            CM_SETRECORDEMPHASIS
            CM_SORTRECORD
            WM_CONTROL and WM_PCONTROL with these notifications:

               CN_BEGINEDIT
               CN_COLLAPSETREE
               CN_CONTEXTMENU



                                  - 17 -



               CN_DRAGAFTER
               CN_DRAGLEAVE
               CN_DRAGOVER
               CN_DROP
               CN_DROPHELP
               CN_EMPHASIS
               CN_ENDEDIT
               CN_ENTER
               CN_EXPANDTREE
               CN_HELP
               CN_INITDRAG
               CN_KILLFOCUS
               CN_QUERYDELTA
               CN_REALLOCPSZ
               CN_SCROLL
               CN_SETFOCUS
               and unknown notifications

            WM_DRAWITEM

          - Subgroup: messages related to the Slider control.
            The following messages are traced:

            SLM_ADDDETENT
            SLM_QUERYDETENTPOS
            SLM_QUERYSCALETEXT
            SLM_QUERYSLIDERINFO
            SLM_QUERYTICKPOS
            SLM_QUERYTICKSIZE
            SLM_REMOVEDETENT
            SLM_SETSCALETEXT
            SLM_SETSLIDERINFO
            SLM_SETTICKSIZE
            WM_CONTROL and WM_PCONTROL with these notifications:

               SLN_CHANGE
               SLN_KILLFOCUS
               SLN_SETFOCUS
               SLN_SLIDERTRACK
               and unknown notifications

            WM_DRAWITEM

          - Subgroup: messages related to the Value Set control.
            The following messages are traced:

            VM_QUERYITEM
            VM_QUERYITEMATTR
            VM_QUERYMETRICS
            VM_QUERYSELECTEDITEM
            VM_SELECTITEM



                                  - 18 -



            VM_SETITEM
            VM_SETITEMATTR
            VM_SETMETRICS
            WM_CONTROL and WM_PCONTROL with these notifications:

               VN_DRAGLEAVE
               VN_DRAGOVER
               VN_DROP
               VN_DROPHELP
               VN_ENTER
               VN_HELP
               VN_INITDRAG
               VN_KILLFOCUS
               VN_SELECT
               VN_SETFOCUS
               and unknown notifications

            WM_DRAWITEM

          - Subgroup: messages related to the Notebook control.
            The following messages are traced:

            BKM_CALCPAGERECT
            BKM_DELETEPAGE
            BKM_INSERTPAGE
            BKM_INVALIDATETABS
            BKM_QUERYPAGECOUNT
            BKM_QUERYPAGEDATA
            BKM_QUERYPAGEID
            BKM_QUERYPAGESTYLE
            BKM_QUERYPAGEWINDOWHWND
            BKM_QUERYSTATUSLINETEXT
            BKM_QUERYTABBITMAP
            BKM_QUERYTABTEXT
            BKM_SETDIMENSIONS
            BKM_SETNOTEBOOKCOLORS
            BKM_SETPAGEDATA
            BKM_SETPAGEWINDOWHWND
            BKM_SETSTATUSLINETEXT
            BKM_SETTABBITMAP
            BKM_SETTABTEXT
            BKM_TURNTOPAGE
            WM_CONTROL and WM_PCONTROL with these notifications:

               BKN_HELP
               BKN_NEWPAGESIZE
               BKN_PAGEDELETED
               BKN_PAGESELECTED
               and unknown notifications

            WM_DRAWITEM



                                  - 19 -



          - Subgroup: Other messages.

            In this group are some WM_CONTROL, WM_PCONTROL, WM_MEASUREITEM
            and WM_DRAWITEM messages that are erroneous, undocumented or
            cannot be interpreted.

            - Regarding WM_CONTROL and WM_PCONTROL:

              WM_CONTROL messages are sent by a window to notify its owner
              of significant events.  Upon receiving one of them, they can
              also be sent by a frame window to notify their client of the
              same event.  WM_PCONTROL messages are posted to the
              application queue.  A window whose class is not a:

              Button
              Combo Box
              Container
              Entry Field
              List Box
              Multi-Line Entry Field
              Notebook
              Slider
              Spin Button
              Value Set

              generates a message traced in this group.  Since no
              notification is defined for a window of such a class, the
              parameters of the WM_CONTROL or WM_PCONTROL message cannot
              be interpreted.

            - Regarding WM_MEASUREITEM:

              When a window which is not a:

                 List Box
                 Menu

              sends a WM_MEASUREITEM to its owner, the WM_MEASUREITEM
              message is traced in this group because the second message
              parameter cannot be interpreted.

            - Regarding WM_DRAWITEM:

              When a window which is not a:

                 Container
                 List Box
                 Menu
                 Notebook
                 Slider
                 Value Set



                                  - 20 -



              sends a WM_DRAWITEM to its owner, the WM_DRAWITEM message is
              traced in this group because the second message parameter
              cannot be interpreted.

        - Group: Keyboard messages.
          The following messages are traced:

          WM_CHAR
          WM_JOURNALNOTIFY
          WM_VIOCHAR (See Note)*

          *Note: The parameters of the WM_VIOCHAR message are undocumented.

        - Group: Mouse messages.
          The following messages are traced:

             WM_BUTTON1CLICK
             WM_BUTTON1DBLCLK
             WM_BUTTON1DOWN
             WM_BUTTON1UP
             WM_BUTTON2CLICK
             WM_BUTTON2DBLCLK
             WM_BUTTON2DOWN
             WM_BUTTON2UP
             WM_BUTTON3CLICK
             WM_BUTTON3DBLCLK
             WM_BUTTON3DOWN
             WM_BUTTON3UP
             WM_CHORD (See Note)*
             WM_CONTROLPOINTER
             WM_HITTEST
             WM_MOUSEMAP
             WM_MOUSEMOVE

          *Note: The first parameter of the WM_CHORD message is
          undocumented. This message occurs when the operator presses both
          button one and button two on the pointing device.

        - Group: Clipboard messages.
          The following messages are traced:

             WM_DESTROYCLIPBOARD
             WM_DRAWCLIPBOARD
             WM_HSCROLLCLIPBOARD
             WM_PAINTCLIPBOARD
             WM_RENDERALLFMTS
             WM_RENDERFMT
             WM_SIZECLIPBOARD
             WM_VSCROLLCLIPBOARD





                                  - 21 -



        - Group: Dynamic Data Exchange messages.
          The following messages are traced:

             WM_DDE_ACK
             WM_DDE_ADVISE
             WM_DDE_DATA
             WM_DDE_EXECUTE
             WM_DDE_INITIATE
             WM_DDE_INITIATEACK
             WM_DDE_POKE
             WM_DDE_REQUEST
             WM_DDE_TERMINATE
             WM_DDE_UNADVISE

        - Group: Help messages.
          The following messages are traced:

             HM_ACTIONBAR_COMMAND
             HM_CONTROL
             HM_CREATE_HELP_TABLE
             HM_DISMISS_WINDOW
             HM_DISPLAY_HELP
             HM_ERROR
             HM_EXT_HELP
             HM_EXT_HELP_UNDEFINED
             HM_HELPSUBITEM_NOT_FOUND
             HM_HELP_CONTENTS
             HM_HELP_INDEX
             HM_INFORM
             HM_INVALIDATE_DDF_DATA
             HM_KEYS_HELP
             HM_LOAD_HELP_TABLE
             HM_NOTIFY
             HM_QUERY
             HM_QUERY_DDF_DATA
             HM_QUERY_KEYS_HELP
             HM_REPLACE_HELP_FOR_HELP
             HM_SET_ACTIVE_WINDOW
             HM_SET_COVERPAGE_SIZE
             HM_SET_HELP_LIBRARY_NAME
             HM_SET_HELP_WINDOW_TITLE
             HM_SET_OBJCOM_WINDOW
             HM_SET_SHOW_PANEL_ID
             HM_SET_USERDATA
             HM_TUTORIAL
             HM_UPDATE_OBJCOM_WINDOW_CHAIN

        - Group: Direct Manipulation (Drag & Drop) messages.
          The following messages are traced:

             DM_DISCARDOBJECT



                                  - 22 -



             DM_DRAGERROR
             DM_DRAGFILECOMPLETE
             DM_DRAGLEAVE
             DM_DRAGOVER
             DM_DRAGOVERNOTIFY
             DM_DROP
             DM_DROPHELP
             DM_EMPHASIZETARGET
             DM_ENDCONVERSATION
             DM_FILERENDERED
             DM_PRINT
             DM_PRINTOBJECT
             DM_RENDER
             DM_RENDERCOMPLETE
             DM_RENDERFILE
             DM_RENDERPREPARE
             WM_BEGINDRAG
             WM_BUTTON1MOTIONEND
             WM_BUTTON1MOTIONSTART
             WM_BUTTON2MOTIONEND
             WM_BUTTON2MOTIONSTART
             WM_BUTTON3MOTIONEND
             WM_BUTTON3MOTIONSTART
             WM_ENDDRAG

        - Group: Double-Byte Character Set messages.
          The following messages are traced:

             WM_DBE_KKCPARAMS
             WM_DBE_SETAPPLSTAT
             WM_QUERYCONVERTPOS

          and all other messages, not appearing in the above list, in the
          range from WM_DBCSFIRST to WM_DBCSLAST.  The messages that do not
          have a name are traced as "(DBCS?) MsgNumber", where MsgNumber is
          shown in hexadecimal and decimal.

          The messages traced are those defined in the toolkit include
          files.

        - Group: Pen messages.

          No pen message is defined in Presentation Manager. Messages
          falling in the range WM_PENFIRST thru WM_PENLAST will be traced
          and named as "(PEN?) MsgNumber".

        - Group: MultiMedia messages.

          Multimedia messages are not interpreted in the current version
          of PMM.  Messages falling in the range WM_MMPMFIRST thru
          WM_MMPMLAST will be traced and named as "(MM?) MsgNumber".



                                  - 23 -



        - Group: System messages.
          The following messages are traced:

             PL_ALTERED
             WM_APPTERMINATENOTIFY
             WM_PSYSCOLORCHANGE
             WM_REALIZEPALETTE
             WM_SYSCOLORCHANGE
             WM_SYSVALUECHANGED

        - Group: Miscellaneous messages.
          The following messages are traced:

           WM_BEGINSELECT
           WM_CONTEXTMENU
           WM_ENDSELECT
           WM_OPEN
           WM_SEM1
           WM_SEM2
           WM_SEM3
           WM_SEM4
           WM_SINGLESELECT
           WM_TEXTEDIT
           WM_TIMER

        - Group: File Dialog messages.
          The following messages are traced:

             FDM_ERROR
             FDM_FILTER
             FDM_VALIDATE

        - Group: Font Dialog messages.
          The following messages are traced:

             FNTM_COLORCHANGED (See Note)*
             FNTM_FACENAMECHANGED
             FNTM_FILTERLIST
             FNTM_POINTSIZECHANGED
             FNTM_STYLECHANGED
             FNTM_UPDATEPREVIEW

          *Note: The parameters of the FNTM_COLORCHANGED message are
          undocumented.

        - Group: Reserved messages.
          The following messages are traced:

             0x0054
             0x005a
             0x041a



                                  - 24 -



             0x041b
             0x041c
             0x041d
             0x041e
             0x041f

        - Group: Undocumented messages.
          Messages that do not belong to any of the above groups are traced.
          All of these messages are undocumented.  Also, included in this
          group are the following three messages, whose name is known, but
          not their parameters or usage:

            PM_INVALIDATECELL       = WM_USER + 1000 (decimal)
            WM_CONTROLHEAP          = 39 (hexadecimal)
            WM_OTHERWINDOWDESTROYED = 3 (hexadecimal)

        - Group: User messages.
          User messages, i.e. messages greater than or equal to the WM_USER
          constant (excluding the File Dialog messages, the Font Dialog
          messages and the PM_INVALIDATECELL message).



        6. The PMM Interface
        


        This section describes the PMM interface to an application.


        List of Functions
        


        PMMCreateTraceSession
        

        This function creates a trace session.  A message queue must exist
        before invoking this function.  Windows associated with the message
        queue created by the calling thread will be traced.  A line is
        written to the trace file indicating that a trace session has been
        created.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           PSZ          pszTraceFileName = "pmm.log";

           pmmr = PMMCreateTraceSession( &hpmms, hab, pszTraceFileName );




                                  - 25 -



        Parameters:

           hpmms (HPMMSESSION) - output
              Session handle returned by the function.  Unaltered if the
              function fails.

           hab (HAB) - input
              Anchor-block handle.

           pszTraceFileName (PSZ) - input
              Address of an ASCIIZ string with the path and filename of the
              file into which the trace information will be written.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMECannotQueryOS2Version
              PMMECannotRunInThisOS2Version
              PMMEMultipleSessionsNotAllowed
              PMMECannotQueryDesktopWindow
              PMMECannotQueryObjectWindow
              PMMENotEnoughMemory
              PMMECannotRegisterInternalClass
              PMMECannotCreateInternalWindow
              PMMECannotSetSendMsgHook
              PMMECannotSetInputMsgHook
              PMMECannotOpenTraceFile
              PMMEWriteFailed
              PMMECannotCloseTraceFile


        PMMStartTracing
        

        This function opens the trace file and starts tracing messages.  A
        line is written to the trace file indicating that tracing has been
        started.  The trace file is opened using DosOpen.  If the file does
        not exist, it is created; if the file exists, its contents are
        preserved and the trace information is appended at the end of the
        file.  Other applications cannot write to the file while the file is
        open.  This file is write-only.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;

           pmmr = PMMStartTracing( hpmms );





                                  - 26 -



        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMEAlreadyTracing
              PMMECannotOpenTraceFile
              PMMEWriteFailed


        PMMStopTracing
        

        This function stops tracing messages.  A line is written to the
        trace file indicating that tracing has been stopped.  The trace file
        is closed and ready to be examined.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;

           pmmr = PMMStopTracing( hpmms );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMENotTracingNow
              PMMEWriteFailed
              PMMECannotCloseTraceFile








                                  - 27 -



        PMMDestroyTraceSession
        

        This function destroys a trace session.  A line is written to the
        trace file indicating that a trace session has been destroyed.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;

           pmmr = PMMDestroyTraceSession( hpmms );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMEWriteFailed
              PMMECannotCloseTraceFile
              PMMECannotReleaseInputMsgHook
              PMMECannotReleaseSendMsgHook
              PMMECannotDestroyInternalWindow
              PMMECannotOpenTraceFile


        PMMQueryVersion
        

        This function queries the current version of PMM.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           ULONG        ulVersion;

           pmmr = PMMQueryVersion( hpmms, &ulVersion );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.



                                  - 28 -



           ulVersion (ULONG) - output
              Current version of PMM.  The major version is returned in the
              higher 16 bits, the minor version in the lower 16 bits.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Notes:
           Useful to determine the functionality that is currently supported
           by PMM.


        PMMQueryTraceFileHandle
        

        This function retrieves the handle of the trace file.  An
        application may write any text to the trace file using the OS/2 API
        DosWrite, with the handle returned from this call.  Since the trace
        file is opened by PMMStartTracing and closed by PMMStopTracing, you
        must be tracing at the time this function is invoked.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           HFILE        hTraceFile;

           pmmr = PMMQueryTraceFileHandle( hpmms, &hTraceFile );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           hTraceFile (HFILE) - output
              Handle of the trace file.  Unaltered if the function fails.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMENotTracingNow





                                  - 29 -



        Notes:
           See the functions PMMStartTracing and PMMStopTracing.


        PMMSetMsgGroupsToTrace
        

        For tracing purposes, all the PM messages are divided into
        categories or groups, according to functionality.  This function
        sets the message groups to trace.  A line is written to the trace
        file when this function is called, indicating what groups are
        currently being traced.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           ULONG        ulMask;
           ULONG        ulFlags;

           pmmr = PMMSetMsgGroupsToTrace( hpmms, ulMask, ulFlags );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           ulMask (ULONG) - input
              The mask is formed by combining zero or more constants in a
              logical OR operation.  Its use is described in the ulFlags
              section, below.  The following constants, defined in PMM.H,
              may be used in the mask:

                 PMMTMG_WINDOW
                 PMMTMG_CONTROLS
                 PMMTMG_KEYBOARD
                 PMMTMG_MOUSE
                 PMMTMG_CLIPBOARD
                 PMMTMG_DDE
                 PMMTMG_HELP
                 PMMTMG_DIRECT_MANIP
                 PMMTMG_DBCS
                 PMMTMG_PEN
                 PMMTMG_MULTIMEDIA
                 PMMTMG_SYSTEM
                 PMMTMG_OTHER
                 PMMTMG_FILE_DIALOG
                 PMMTMG_FONT_DIALOG
                 PMMTMG_RESERVED
                 PMMTMG_UNDOCUMENTED



                                  - 30 -



                 PMMTMG_USER
                 PMMTMG_ALL

           ulFlags (ULONG) - input
              The ulFlags parameter is formed by combining zero or more
              constants in a logical OR operation.  If the corresponding
              value in the mask is set, values present in this parameter
              will be interpreted as TRUE (trace this group of messages)
              while their absence will be interpreted as FALSE (do not
              trace this group of messages).  If a value is not present
              in the parameter ulMask, the corresponding value in the
              parameter ulFlags will be ignored.  The same constants used
              in the parameter ulMask may be used.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMECannotOpenTraceFile
              PMMEWriteFailed
              PMMECannotCloseTraceFile

        Default values at startup:
           PMMTMG_ALL for ulMask.  All flags will be processed.
           PMMTMG_ALL for ulFlags.  All message groups will be traced.

        Notes:
           Undefined values in the parameters ulMask and ulFlags are
           ignored.  Because more groups may be added in the future, an
           application should not use undefined values.


        PMMSetControlsToTrace
        

        Messages related to PM controls are organized in groups.  These
        groups belong to the more general group of 'Controls'.  This
        function sets the PM controls to trace.  For this function to have
        any effect, the flag PMMTMG_CONTROLS (mentioned in the function
        PMMSetMsgGroupsToTrace) must be set to trace the messages related
        to one or more controls.  A line is written to the trace file when
        this function is invoked, indicating which controls are currently
        being traced.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           ULONG        ulMask;



                                  - 31 -



           ULONG        ulFlags;

           pmmr = PMMSetControlsToTrace( hpmms, ulMask, ulFlags );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           ulMask (ULONG) - input
              The mask is formed by combining zero or more constants in a
              logical OR operation.  Its use is described in the ulFlags
              section, below.  The following constants, defined in PMM.H,
              may be used in the mask:

                 PMMTCO_FRAME
                 PMMTCO_COMBOBOX
                 PMMTCO_BUTTON
                 PMMTCO_MENU
                 PMMTCO_STATIC
                 PMMTCO_ENTRYFIELD
                 PMMTCO_LISTBOX
                 PMMTCO_SCROLLBAR
                 PMMTCO_TITLEBAR
                 PMMTCO_MLE
                 PMMTCO_APPSTAT
                 PMMTCO_KBDSTAT
                 PMMTCO_PECIC
                 PMMTCO_DBE_KKPOPUP
                 PMMTCO_SPINBUTTON
                 PMMTCO_CONTAINER
                 PMMTCO_SLIDER
                 PMMTCO_VALUESET
                 PMMTCO_NOTEBOOK
                 PMMTCO_OTHER
                 PMMTCO_ALL

           ulFlags (ULONG) - input
              The ulFlags parameter is formed by combining zero or more
              constants in a logical OR operation.  If the corresponding
              value in the mask is set, values present in this parameter
              will be interpreted as TRUE (trace this group of messages)
              while their absence will be interpreted as FALSE (do not
              trace this group of messages).  If a value is not present
              in the parameter ulMask, the corresponding value in the
              parameter ulFlags will be ignored.  The same constants used
              in the parameter ulMask may be used.






                                  - 32 -



        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMECannotOpenTraceFile
              PMMEWriteFailed
              PMMECannotCloseTraceFile

        Default values at startup:
           PMMTCO_ALL for ulMask.  All flags will be processed.
           PMMTCO_ALL for ulFlags.  All messages corresponding to the above
           list of controls will be traced.

        Notes:
           Undefined values in the parameters ulMask and ulFlags are
           ignored.  Because more groups may be added in the future, an
           application should not use undefined values.


        PMMShowWindowText
        

        This function controls whether PMM should show the text of a window
        in a message.  This is useful for identifying windows.  Square
        brackets denote optional items.  The window text is shown in this
        format:

           "WindowText"[a][t]

        where:

        - 'WindowText' is the text of the window.
        - The suffix 'a' means (a)ltered, i.e. the original window text has
          been altered by PMM.  Some windows have control characters like
          CR, LF in their text. Showing the control characters in a text
          file produces confusion since the trace line splits into several
          parts. The suffix indicates that all HT, LF, CR and SUB characters
          have been converted into spaces.
        - The suffix 't' means (t)rimmed, i.e. the window text has been
          trimmed.  The maximum text length shown is 20 characters.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowWindowText( hpmms, bShow );



                                  - 33 -



        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show window text indicator:
              TRUE
                 Show the window text.
              FALSE
                 Do not show the window text.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Default value at startup:
           The window text will be shown.

        Notes:
           Some windows do not have a "Text" property.  The window text is
           shown if the window has this property and the text is not an
           empty string.  If the text contains embedded double quotes, which
           are used as a text delimiter, the embedded double quotes are
           simply displayed.  For instance, the following window text has
           unbalanced quotes and is correct:

              "Viewing "It is a Won"t


        PMMShowClassName
        

        This function controls whether PMM should show the class name of a
        window in a message.  This is useful for identifying some windows
        that do not have text.  Square brackets denote optional items.  The
        class name is shown in this format:

           (ClassName)[t][u]

        where:

        - 'ClassName' is the name of the class.  The following literals are
          used to identify standard PM classes:

             Frame
             ComboBox



                                  - 34 -



             Button
             Menu
             Static
             EntryField
             ListBox
             ScrollBar
             TitleBar
             MLE
             AppStat
             KbdStat
             Pecic
             DBE_KKPopUp
             SpinButton
             Container
             Slider
             ValueSet
             Notebook
        - The suffix 't' means (t)rimmed, i.e. the class name has been
          trimmed.  The maximum class name length shown is 20 characters.
        - The suffix 'u' means (u)ser.  All classes that are not in the
          above list are considered user defined, whether they are system
          defined or user defined.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowClassName( hpmms, bShow );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show class name indicator:
              TRUE
                 Show the class name.
              FALSE
                 Do not show the class name.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle



                                  - 35 -



        Default value at startup:
           The class name will be shown.

        Notes:
           You can register, for instance, a class named "ListBox".  The
           suffix 'u' is intended to resolve any ambiguity between standard
           PM classes and user defined classes.


        PMMShowWindowID
        

        This function controls whether PMM should show the identifier (ID)
        of a window in a message.  If the window or control has a predefined
        identifier, like FID_MENU, it will be shown; otherwise the window
        identifier, a number, will be shown.  This is useful for identifying
        some windows that do not have text.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowWindowID( hpmms, bShow );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show window ID indicator:
              TRUE
                 Show the window ID.
              FALSE
                 Do not show the window ID.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Default value at startup:
           The window ID will not be shown.





                                  - 36 -



        Notes:
           A window ID is always considered as a 16 bit signed number, in
           the range -32768 to 32767.


        PMMShowPointers
        

        This function controls whether PMM should show the pointers and
        string handles that are used in a message.  This is useful for
        checking that pointers point to the intended objects.

        PMM tests all pointers and string handles used in a message, whether
        they are to be shown or not.  PMM was designed to not introduce side
        effects to an application.  All pointers involved in a message are
        tested since printing the value they point to would produce a
        protection violation.

        Testing a pointer means to make sure the object pointed to can be
        accessed.  For a string object, the "object size" is considered as
        "all the characters up to the '\0' (included);" for all other
        objects the object size is the size defined in PM include files.

        Pointer names are displayed beginning with 'p' or 'ap'.  'p' stands
        for (p)ointer, 'a' for (a)rray.  String handles begin with 'hstr'.
        A descriptive name follows the prefix.  Pointer values are shown in
        hexadecimal, string handles in decimal.

        A pointer or string handle is shown using the format below.  One of
        a list of items enclosed in braces appears always.  Square brackets
        denote optional items.  Vertical bars separating items indicate that
        one of the items will appear.  '->' is used as a continuation mark.
        The format is:

           {p | ap | hstr}DescriptiveName: [0xnnnnnnnn | NULL | 0] ->
              [(Not allocated) | (Not accessible) | (Invalid) | (Size?)] ->
              [(Out)]

        where:

        - '(Not allocated)' can be shown for any generic pointer (except
          with pointers to a DRAGINFO structure).
        - '(Not accessible)' can be shown for pointers that point to a
          DRAGINFO structure (tested with DrgAccessDraginfo).
        - '(Invalid)' can be shown for string handles.
        - '(Size?) can be shown for pointers to a string if the string size
          used in the message is zero.  In this case the pointer cannot be
          tested for accessibility.

        If a pointer or string handle is "invalid" for some reason, PMM
        shows its name and value, regardless of the setting of this



                                  - 37 -



        function.  This is done to inform you that the value(s) pointed to
        cannot be printed and that there is a potential problem with this
        pointer.

        Some message parameters are defined as output, so they are pointers
        to an object.  The parameter output value is printed on return from
        the message handler.  Failing to mention the parameter in the
        message call would produce confusion when reading the message trace,
        since the parameter would be missing.  To avoid this, PMM ignores
        the setting of this function; that is, on an output parameter the
        pointer name is always printed, possibly followed of the pointer
        value, and followed by the literal '(Out)'.  Example ('->' is used
        as a continuation mark, ellipsis indicates that some information is
        not shown):

        2147483839 (Container)  CM_QUERYCNRINFO  pCnrInfo: (Out)  ->
           Bytes to copy: 92  Sent
        2147483839 (Container)  CM_QUERYCNRINFO  Returns Bytes ->
           copied: 92  [CNRINFO: cb: 92 pSortRecord: NULL ...  ->
           xVertSplitbar: -1<No splitbar>]

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowPointers( hpmms, bShow );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show pointers indicator:
              TRUE
                 Show the pointers and string handles.
              FALSE
                 Do not show the pointers and string handles.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle





                                  - 38 -



        Default value at startup:
           Pointers and string handles will not be shown.

        Notes:
           For purposes of this function, string handles are considered to
           be pointers, even though they are not.

           The following behavior, though rare, may occur:

           Pointers to objects and pointers inside objects are always
           tested before the message arrives at the destination window.  It
           may occur that, when sending a message, one of the parameters of
           the message is a pointer, which points to an object that has more
           pointers inside it, and so on.  All these pointers are tested
           before the final message call is done.  The destination window
           cannot modify the parameters of the message (passed by value) but
           it can modify the pointers inside objects to point to
           inaccessible objects.  After returning from a message call, PMM
           does not retest the pointers inside objects.


        PMMShowAllArrayItems
        

        This function controls whether PMM should show all the array items
        when arrays appear in messages.  By default, PMM will not show all
        array items, i.e. it will show a maximum of five array items,
        either:

        - the first five, if they exist, or
        - the first two and the last two, if the array has more than five
          items.

        If the second form is used, an ellipsis (...) is placed between the
        first two items and the last two, to indicate that there are items
        not shown.  An array item is identified by its name and by an index,
        zero based.  The index, following the "C" syntax, is enclosed
        between square brackets.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowAllArrayItems( hpmms, bShow );

        Parameters:

           hpmms (HPMMSESSION) - input



                                  - 39 -



              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show all array items indicator:
              TRUE
                 Show all array items.
              FALSE
                 Do not show all array items, only some.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Default value at startup:
           Not all array items will be shown, only some.


        PMMShowAllLinkedListItems
        

        This function controls whether PMM should show all the linked list
        items when linked lists appear in messages.  By default, PMM will
        not show all linked list items, i.e. it will show a maximum of five
        linked list items, either:

        - the first five, if they exist, or
        - the first two and the last two, if the linked list has more than
          five items.

        If the second form is used, an ellipsis (...) is placed between
        the first two items and the last two, to indicate that there are
        items not shown.  A linked list item is identified by its name and
        by an index, zero based.  The index is enclosed between forward
        slashes.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowAllLinkedListItems( hpmms, bShow );

        Parameters:

           hpmms (HPMMSESSION) - input



                                  - 40 -



              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show all linked list items indicator:
              TRUE
                 Show all linked list items.
              FALSE
                 Do not show all linked list items, only some.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Default value at startup:
           Not all linked list items will be shown, only some.


        PMMShowFullMsgInfo
        

        Sometimes, in order to show the maximum information for the
        messages being traced, PMM needs to send a message to a window.
        Such a message wouldn't have been sent if the application were not
        using PMM, i.e. the message does not belong to the "normal"
        application message stream.  For instance, to interpret the return
        value of a VM_QUERYITEM message, PMM needs to know the VIA_*
        attribute of the value set.  A VM_QUERYITEMATTR is sent to the
        value set.  This guarantees that the message is properly interpreted
        and gives the maximum information for a message.

        To obtain a "clean" message stream, or if you are experiencing any
        trouble with messages, you can turn off this option.

        This option is on by default because, for most applications, the
        setting has not proved to cause undesirable effects.

        The following messages, which are considered internal, are sent by
        PMM to an application:

           WM_QUERYWINDOWPARAMS
           CM_QUERYCNRINFO
           MM_QUERYITEM
           VM_QUERYITEMATTR

        You can always see when the above messages are sent by turning on
        the option to show internal messages (See PMMShowInternalMessages).




                                  - 41 -



        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowFullMsgInfo( hpmms, bShow );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show full message information indicator:
              TRUE
                 Show full information for messages being traced.
              FALSE
                 Do not show full information for messages being traced.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Default value at startup:
           Full message information will be shown.

        Notes:
           See PMMShowWindowText and PMMShowInternalMessages.


        PMMShowInternalMessages
        

        PMM sends messages to windows to query the window text, and to get
        some information to fully interpret a message.  These messages are
        called "internal", since they do not belong to the application
        message stream.  This function controls whether PMM should show
        these messages in the trace file.  PMM may send the following
        messages to an application:

           WM_QUERYWINDOWPARAMS
           CM_QUERYCNRINFO
           MM_QUERYITEM
           VM_QUERYITEMATTR




                                  - 42 -



        In the trace file, an internal message is flagged with an initial
        'i' and a final comment indicating the message source. The message
        is shown above the message that has generated it (since it occurs
        before).  Also, it is shown with the same indentation that the
        message that has generated it.  Messages generated by internal
        messages, also considered internal, are indented as usual, one level
        to the right.  An example follows (the '->' means that the next line
        is to be interpreted as part of the current one):

        ...
        i 2147483922 (Frame) 1  WM_QUERYWINDOWPARAMS  [WNDPARAMS: ->
           fsStatus: WPM_TEXT WPM_CCHTEXT cchText: 22 pszText: ->
           0x006e000c (Out)]  Sent by PMM
          i 2147483923 (TitleBar) FID_TITLEBAR  WM_QUERYWINDOWPARAMS  ->
             [WNDPARAMS: fsStatus: WPM_TEXT WPM_CCHTEXT cchText: 22 ->
             pszText: 0x006e000c (Out)]  Sent int.
          i 2147483923 (TitleBar) FID_TITLEBAR  WM_QUERYWINDOWPARAMS  ->
             Returns: Success  [WNDPARAMS: fsStatus: WPM_TEXT WPM_CCHTEXT ->
             cchText: 5 Text: "Style"]i
        i 2147483922 (Frame) 1  WM_QUERYWINDOWPARAMS  Returns: ->
           Success  [WNDPARAMS: fsStatus: WPM_TEXT WPM_CCHTEXT cchText: 5 ->
           Text: "Style"]i
        (Below is the message return that has generated the above lines)
        2147483922 "Style" (Frame) 1  WM_SETWINDOWPARAMS  ->
           Returns: Success
        ...

        In most cases you will not be interested in seeing internal
        messages.  However, this function is useful to:

        - see when internal messages are sent and why.  In the previous
          example, on returning from a WM_SETWINDOWPARAMS call, PMM must
          query the window text since it has (possibly) changed.
        - identify some (rare) cases when sending an internal message
          produces an exception, because the destination window is
          unprepared to respond to the message at that time.  If this
          situation arises, depending on the message, you should turn off
          the appropriate option: PMMShowWindowText or PMMShowFullMsgInfo.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bShow;

           bShow = TRUE;
           pmmr = PMMShowInternalMessages( hpmms, bShow );

        Parameters:

           hpmms (HPMMSESSION) - input



                                  - 43 -



              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bShow (BOOL) - input
              Show internal messages indicator:
              TRUE
                 Show internal messages.
              FALSE
                 Do not show internal messages.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Default value at startup:
           Internal messages will not be shown.

        Notes:
           See PMMShowWindowText.


        PMMDefineStartStopTracingKeys
        

        You can start and stop tracing at any time and at any point in your
        application by using the keyboard.  PMM uses a key to start tracing,
        and another key to stop tracing.  These keys are, by default, F11 to
        start tracing and F12 to stop tracing, since they are rarely used by
        applications.  If your application does use F11 or F12, you can use
        this function to define other keys to start and/or stop tracing.
        You can define the start key only, the stop key only, or both keys
        at the same time.

        Function Syntax:

           ('->' is used as a continuation mark).

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           USHORT       usStartKey;
           USHORT       usStopKey;

           pmmr = PMMDefineStartStopTracingKeys( hpmms, usStartKey, ->
              usStopKey );

        Parameters:

           hpmms (HPMMSESSION) - input



                                  - 44 -



              Session handle returned by a previous call to
              PMMCreateTraceSession.

           usStartKey (USHORT) - input
              Key to start tracing.  One of the following constants:
                 VK_F2
                 VK_F3
                 VK_F4
                 VK_F5
                 VK_F6
                 VK_F7
                 VK_F8
                 VK_F9
                 VK_F11
                 VK_F12
              as defined by Presentation Manager.
              Pass a 0 (zero) to leave this key unchanged.

           usStopKey (USHORT) - input
              Key to stop tracing.  Use the same constants as defined in the
              usStartKey parameter.
              Pass a 0 (zero) to leave this key unchanged.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMEKeyNotDefinable
              PMMEKeysCannotBeTheSame
              PMMEKeyAlreadyDefined

        Default value at startup:
           The key to start tracing is F11.  The key to stop tracing is F12.

        Notes:
           See PMMStartTracing and PMMStopTracing.
           F1 and F10 are not allowed since they are defined by the system.


        PMMQueryIfIgnoreMsg
        

        PMM introduces some messages in an application message stream.
        Messages are introduced as a result of:

        - creating some internal windows
        - querying the window text and other attributes of a window
        - re-sending some messages to a window pertaining to another
          process.



                                  - 45 -



        These messages do not belong to the application message stream and
        should be ignored.

        If you are using hooks of type HK_SENDMSG, you must use this
        function in your hook handler to determine which messages belong in
        the data stream you are watching.  This will protect your code from
        receiving messages that your application doesn't generate.  Only
        this type of hook needs to be protected.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           BOOL         bIgnore;

           pmmr = PMMQueryIfIgnoreMsg( hpmms, &bIgnore );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           bIgnore (PBOOL) - output
              Indicates if the application should ignore the message
              received in the hook.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle

        Notes:
           If you use this function, you need to use also the function
           PMMSMHQueryMsg.

           PMM uses queue hooks only, not system hooks.  You cannot use PMM
           together with software that uses hooks (or you suspect that it
           uses hooks) if you do not have access to the source code.  If you
           use PMM with such software, the results are unpredictable.

        Example:
           See the example in the function PMMSMHQueryMsg.


        PMMSMHQueryMsg
        

        In order to interpret all messages correctly PMM must alter



                                  - 46 -



        temporarily the messages sent by your application to windows of
        another process.  This is by design.  If you are using hooks of type
        HK_SENDMSG you must use this function in your hook handler to
        determine whether PMM has changed the message you have just
        received.  Any other type of hook does not need this function.
        If the message has been changed, this function tells you the message
        that you should process, as it was before PMM changed it.

        Function Syntax:

           PMMRET       pmmr;
           HPMMSESSION  hpmms;
           PBOOL        pbChanged;
           PSMHSTRUCT   psmh;
           BOOL         bChanged;
           SMHSTRUCT    smh;

           pbChanged = &bChanged;
           psmh = &smh;
           pmmr = PMMSMHQueryMsg( hpmms, pbChanged, psmh );

        Parameters:

           hpmms (HPMMSESSION) - input
              Session handle returned by a previous call to
              PMMCreateTraceSession.

           pbChanged (PBOOL) - output
              Indicates if the message has been changed by PMM.  If the
              message has not been changed, the structure pointed to by the
              psmh parameter is not altered.

           psmh (PSMHSTRUCT) - output
              If the message has been changed by PMM, this structure
              contains the original values received in the send message
              hook, i.e. the values that an application should process.

        Return Values:
           Success:
              PMMESuccess
           Error: one of the following:
              PMMETraceSessionNotCreated
              PMMEInvalidHandle
              PMMEInvalidPointer

        Notes:
           Don't pass the same pointer that you have received as the second
           parameter in the hook (psmh in the example) to this function.
           This would produce an error and the structure SMHSTRUCT would not
           be updated, since this would lead to an erroneous message trace.
           Don't modify any of the values pointed to by the psmh pointer.



                                  - 47 -



           This would produce an erroneous message trace. See
           PMMQueryIfIgnoreMsg.

        Example:

           VOID EXPENTRY MySendMsgHook(   HAB hab
                                        , PSMHSTRUCT psmh
                                        , BOOL fInterTask )
           {
              PMMRET     pmmr;
              BOOL       bIgnore;
              BOOL       bChanged;
              SMHSTRUCT  rSMH;

              // Let's assume that hpmms is a global variable
              // defined elsewhere in the application
              pmmr = PMMQueryIfIgnoreMsg( hpmms, &bIgnore );
              if ( pmmr == PMMESuccess )
              {
                 // The trace session has been created,
                 // check whether we should ignore the message
                 if ( bIgnore )
                    return;

                 pmmr = PMMSMHQueryMsg( hpmms, &bChanged, &rSMH );
                 if ( bChanged )
                 {
                    // Changed, so we use the values in
                    // the rSMH structure
                    psmh = &rSMH;
                 }
              }
              else
              {
                 // The trace session hasn't been created,
                 // so the message couldn't have been altered.
                 // Nothing to do here
              }

              // From now on, psmh points to the correct message that
              // we should process
              // Normal code here

           } //end MySendMsgHook


        PMMSubclassWindow
        

        This function behaves almost exactly as the PM WinSubclassWindow
        function.  Note that the PMM include file PMM.H redefines



                                  - 48 -



        WinSubclassWindow as PMMSubclassWindow, so an application will use
        this function instead of WinSubclassWindow.  This function calls
        WinSubclassWindow using the same parameters being passed to it and
        returns the same value as returned by WinSubclassWindow.  Before
        returning, if a PMM trace session exists, it notifies PMM that a new
        subclassing has been made, so as to keep track immediately of a new
        window procedure.

        See the section "Subclassing Windows when Using PMM," above.

        Function Syntax:

           HWND   hwnd;
           PFNWP  pNewWindowProc;
           PFNWP  pOldWindowProc;

           pOldWindowProc = PMMSubclassWindow( hwnd, pNewWindowProc );

        Parameters:

           hwnd (HWND) - input
              Handle of window that is being subclassed.

           pNewWindowProc (PFNWP) - input
              New window procedure.

        Return Values:

           pOldWindowProc (PFNWP) - return
              Old window procedure.  Previous window procedure belonging
              to hwnd.

              If this function fails, 0L is returned.


        PMMSetWindowPtr
        

        This function behaves almost exactly as the PM WinSetWindowPtr
        function.  Note that the PMM include file PMM.H redefines
        WinSetWindowPtr as PMMSetWindowPtr, so an application will use this
        function instead of WinSetWindowPtr.  This function calls
        WinSetWindowPtr using the same parameters being passed to it and
        returns the same value as returned by WinSetWindowPtr.  Before
        returning, if a PMM trace session exists and the lb parameter is
        QWP_PFNWP, it notifies PMM that a new subclassing has been made, so
        as to keep track immediately of a new window procedure.

        See the section "Subclassing Windows when Using PMM."





                                  - 49 -



        Function Syntax:

           HWND   hwnd;
           LONG   lb;
           PVOID  pp;
           BOOL   fSuccess;

           fSuccess = PMMSetWindowPtr( hwnd, lb, pp );

        Parameters:

           hwnd (HWND) - input
              Window handle.

           lb (LONG) - input
              Zero-based index into the window words.  The units of b are
              bytes.  Valid values are zero through (cbWindowData - 4),
              where cbWindowData is the parameter in WinRegisterClass that
              specifies the number of bytes available for
              application-defined storage.

              The value QWP_PFNWP can be used as the index for the address
              of the window procedure for the window.

           pp (PVOID) - input
              Pointer value to store in the window words.

        Return Values:

           fSuccess (BOOL) - return
              Success indicator:
              TRUE
                 Successful completion
              FALSE
                 Error occurred.


        PMMQueryWindowPtr
        

        This function is included for completeness and for future expansion
        of PMM.  It behaves exactly as the PM WinQueryWindowPtr function.
        Note that the PMM include file PMM.H redefines WinQueryWindowPtr as
        PMMQueryWindowPtr, so an application will use this function instead
        of WinQueryWindowPtr.

        See the section "Subclassing Windows when Using PMM."

        Function Syntax:

           HWND   hwnd;



                                  - 50 -



           LONG   index;
           PVOID  pp;

           pp = PMMQueryWindowPtr( hwnd, index );

        Parameters:

           hwnd (HWND) - input
              Window handle which has the pointer to retrieve.

           index (LONG) - input
              Index.  Zero-based index of the pointer value to retrieve.
              The units of index are bytes.  Valid values are zero through
              (cbWindowData - 4), where cbWindowData is the parameter in
              WinRegisterClass that specifies the number of bytes available
              for application-defined storage.

              The value QWP_PFNWP can be used for the address of the
              window's window procedure.

        Return Values:

           pp (PVOID) - return
              Pointer value.
              NULL
                 Error occurred.
              Other
                 Pointer value.


        List of Errors and Warnings
        


        Errors Returned by Functions
        

        PMMESuccess
           The function has completed sucessfully.
        PMMECannotQueryOS2Version
           The current OS/2 version cannot be obtained.  PMM currently
           supports the OS/2 versions 2.1, 3.0 and 4.0.
        PMMECannotRunInThisOS2Version
           Your OS/2 version isn't 2.1, 3.0 or 4.0.  PMM cannot run in any
           other version.
        PMMEMultipleSessionsNotAllowed
           An application has attempted to create more than one PMM trace
           session.  This functionality is not supported.
        PMMECannotQueryDesktopWindow
           PMM has tried to query the desktop window handle and the function
           has failed.




                                  - 51 -



        PMMECannotQueryObjectWindow
           PMM has tried to query the desktop object window handle and the
           function has failed.
        PMMENotEnoughMemory
           A request to allocate memory has failed.
        PMMECannotRegisterInternalClass
           PMM uses a window, whose class is "PMMWorkingWindow", to perform
           most of its functions.  The class couldn't be registered.
        PMMECannotCreateInternalWindow
           PMM uses a window to perform most of its functions. The window
           couldn't be created.
        PMMECannotSetSendMsgHook
           PMM uses a queue hook to intercept messages sent by the
           WinSendMsg function.  The hook couldn't be set.
        PMMECannotSetInputMsgHook
           PMM uses a queue hook to intercept messages that are being posted
           to an application queue.  The hook couldn't be set.
        PMMECannotOpenTraceFile
           The trace file couldn't be opened.
        PMMEWriteFailed
           Writing to the trace file has failed.  A common error is that the
           disk is full.
        PMMECannotCloseTraceFile
           The trace file couldn't be closed.
        PMMETraceSessionNotCreated
           No trace session has been created.
        PMMEInvalidHandle
           An invalid trace session handle has been passed to a function.
        PMMEAlreadyTracing
           The application attempted to start tracing and PMM was already
           tracing.
        PMMENotTracingNow
           The application attempted to stop tracing and PMM was not
           tracing.
        PMMECannotReleaseInputMsgHook
           PMM uses a queue hook to intercept messages that are being posted
           to an application queue.  The hook couldn't be released.
        PMMECannotReleaseSendMsgHook
           PMM uses a queue hook to intercept messages sent by the
           WinSendMsg function.  The hook couldn't be released.
        PMMECannotDestroyInternalWindow
           PMM uses a window to perform most of its functions.  The window
           couldn't be destroyed.
        PMMEKeyNotDefinable
           The application attempted to define a key that isn't definable.
           See the definable keys in the function
           PMMDefineStartStopTracingKeys.
        PMMEKeysCannotBeTheSame
           The application attempted to define the same key to start and
           stop tracing.



                                  - 52 -



        PMMEKeyAlreadyDefined
           The application attempted to define a key to start/stop tracing
           and this key was already defined.
        PMMEInvalidPointer
           The application is using a send message hook and has invoked the
           function PMMSMHQueryMsg passing to it the pointer to a SMHSTRUCT
           object that has received as the second parameter in the send
           message hook function. This is not allowed.  See the notes in the
           function PMMSMHQueryMsg.


        Errors Occurring when Using PMM
        

        These errors may occur at any time when running an application and
        using PMM.  All are critical, that is, PMM will write a message in
        the trace file (if possible), will stop tracing and will destroy the
        current trace session.

        PMMECritWriteFailed

           Error text:

           "PMM: Error 1001: Writing to disk failed. Cannot continue
           tracing"

           Writing to the trace file has failed.  Since that the basic
           function of PMM is to trace messages and write them to disk,
           PMM cannot continue.

        PMMECritNotEnoughMemory

           Error text:

           "PMM: Error 1002: Not enough memory. Cannot continue tracing"

           PMM allocates memory while running, if necessary.  The memory
           couldn't be allocated, so PMM cannot continue.

        PMMECritCannotSubclassWindow

           Error text:

           "PMM: Error 1003: Cannot subclass a window. Cannot continue
           tracing"

           PMM subclasses windows as needed to keep track of all messages
           occurring in an application.  There is a limit to the number of
           times that an application can subclass a window (see PMM limits).
           This message indicates that this limit has been reached.




                                  - 53 -



        PMMECritTooManyNestedMsgCalls

           Error text:

           "PMM: Error 1004: Too many nested message calls. Cannot continue
           tracing"

           PMM maintains an internal structure to keep track of all messages
           occurring in an application.  There is a limit to the number of
           messages that this structure can hold (see PMM limits).  This
           limit should be sufficient for virtually every application;
           however, an (erroneous) infinite recursion procedure could lead
           to this error.


        Warnings Occurring when Using PMM
        

        These warnings do not prevent PMM to continuing to do its functions.
        They are reported to the user by writing a message to the trace
        file.

        PMMWInvalidWindow

            Warning text:

            "PMM: Warning 5001: A message has been sent through a
            pointer to an invalid window. Address called: a.
            Message: hwnd: h msg: m mp1: mp1 mp2: mp2.
            The message will be ignored"

            This indicates that the application sent a message to a window
            using a pointer, which is supposed to point to a window
            procedure of the window, and the window doesn't exist. This is
            probably an application error.

        PMMWInvalidWindowProc

            Warning text:

            "PMM: Warning 5002: A message has been sent through a
            pointer using an address that is not a window procedure
            address of the window w. Address called: a.
            Message: hwnd: h msg: m mp1: mp1 mp2: mp2.
            The message will be ignored"

            PMM has intercepted a call to a window procedure that doesn't
            belong to the actual window procedures of the window being
            passed in the call.  The message cannot perform its intended
            function.  This is probably an application error.




                                  - 54 -



        7. PMM Message Trace Format
        


        The following diagrams use the "railroad" syntax.  The following
        points show how to read them:

        - Read the format diagrams from left to right, from top to bottom,
          following the path of the line.

          The  symbol indicates the beginning of the information being
          described.

          The  symbol indicates that the information is continued on the
          next line.

          The  symbol indicates that the information is continued from
          the previous line.

          The  symbol indicates the end of the information.


        In the following diagrams an item represents a part of the
        information that PMM shows.

        - Items that always appear are shown on the horizontal line (the
          main path).

          hWnd

        - Optional items appear below the main path.

          
                          WindowId

        - If PMM shows you an item, choosing from a set of two or more
          items, the set of items appears vertically, in a stack.

          If one of the items is always shown, one item in the stack appears
          on the main path.

            Sent
                           DispatchedĴ
                           Posted to queue

          If showing one of the items is optional, the entire stack appears
          below the main path.

          
                          by PMMĴ
                          int. 



                                  - 55 -



          The item that is the default appears above the main path.

                          "WindowText"Ŀ
          

        - An arrow returning to the left above the main line indicates an
          item that can be repeated.

                          Item: ItemValueĿ
          



        This is the format of a message as shown by PMM:


        Message Call:
        

                                    "WindowText"Ŀ
                                                  a t 
        Indent.hWnd
                     i 

             (ClassName)Ŀ
                           t u 
        
                                            O.  WindowId

          MessageName
                               Param1     Param2

          Sent
                       by PMMĴ       It: n         
                       int.                          
              DispatchedĴ
                                        fs: PM_NOREMOVEĴ
              Posted to queue


        Message Return:
        

                                    "WindowText"Ŀ
                                                  a t 
        Indent.hWnd
                     i 







                                  - 56 -



             (ClassName)Ŀ
                           t u 
        
                                            O.  WindowId

                                            Item: ItemValueĿ
          MessageName  Returns
                                           : RetValue

        
                OutParam1     OutParam2


        where:

        - 'Indent.' is the indentation showing the call and return nesting
          of messages.
        - 'i' means that this is an internal message.
        - 'hWnd' is the destination window handle of a message.
        - 'WindowText' is the window text of the destination window.  If
          the window doesn't have text or the text is a zero length string,
          the quotes are not shown.
        - 'a' means that the text has been altered.
        - 't' means that the text has been trimmed.
        - 'ClassName' is the class name of the destination window.
        - 'u' means that this is an user class.
        - 'O.' means that this is an object window.
        - 'WindowId' is the window identifier.
        - 'MessageName' is the name of the message.
        - 'Param1' is the first parameter of a message.  All values and
          objects being passed in the first parameter of a message are
          interpreted and displayed.
        - 'Param2' is the second parameter of a message.  All values and
          objects being passed in the second parameter of a message are
          interpreted and displayed.
        - 'Sent' means that the message has been sent (using WinSendMsg or
          using a pointer).
        - 'Dispatched' means that the message has been retrieved from the
          queue and dispatched by WinDispatchMsg.
        - 'Posted to queue' means that the message has been posted to the
          queue and the message will not be dispatched by WinDispatchMsg
          (because the window handle is NULL; or it is a WM_QUIT message;
          or the message is not being removed from the queue).
        - 'by PMM' means that the message has been sent by PMM, i.e. it is
          internal.
        - 'int.' means internally, i.e. the message has been sent from
          inside an internal message.
        - 'It: n' means intertask.  This item appears if the message has
          been sent between tasks.  If the item does not appear the message
          has been sent within a task (intratask).
        - 'fs: PM_NOREMOVE' are the message removal options received in the



                                  - 57 -



          third parameter of the input hook.  This item appears only if the
          message hasn't been removed from the queue, which is unusual.
        - 'RetValue' is the value returned by a message, given that the
          message name is clear and self-explanatory.
        - 'Item: ItemValue' is a brief description of what a message
          returns, plus the value returned.
        - 'OutParam1' is the first parameter of a message, given that it is
          an Input/Output or Output parameter.
        - 'OutParam2' is the second parameter of a message, given that it is
          an Input/Output or Output parameter.


        C structures are shown in this way:

            Ŀ
        [StructName:
                               [ai]Ĵ
                               /lle/

            Ŀ   Ŀ
         VarName: VarValue]
                                 <Meaning>           i


        where:

        - 'StructName' is the structure name as defined in PM include files.
        - 'ai' is the array index of the structure.  The square brackets
          around 'ai' indicate that the structure is an array item.
        - 'lle' is the ith element of a linked list of structures.  The
          slashes around 'lle' indicate that the structure is a linked
          list element.
        - 'VarName' is the variable name.
        - 'VarValue' is the value of the variable.
        - 'Meaning' is a brief description of what the variable value means,
          i.e. how the window should or will interpret the value.
        - 'i' means incomplete, i.e. not all struct variables are shown.
          This can be caused, for instance, because this is a call and some
          variables are output variables or because some variable values do
          not have meaningful values at the time the call is being made.
          (You may see the trace generated for the message CM_SETCNRINFO.)

        Initial and final square brackets may appear more than once,
        indicating the structure nesting.  For instance, the beginning and
        end of a structure contained inside another structure are shown,
        respectively, as '[[' and ']]'.








                                  - 58 -



        8. Notes About PMM
        


        When examples are given, the arrow indicates that the next line
        continues from the current one.  Ellipsis, unless stated otherwise,
        indicates that some information is not shown.

        1. Any message parameter defined as "Reserved," which should have
           a NULL value, is not shown, except when its value is not NULL.

        2. PMM interprets only "as much as defined in the documentation" in
           message parameters, structure variables and return values.  For
           instance, the parameter 1 in the WM_TIMER message is defined as a
           timer id and a timer id uses only the lower 16 bits of the
           parameter.  No attempt is made to test and interpret the higher
           16 bits.  Note that if an application uses "empty" bits a message
           may fail or produce unexpected results.

        3. Every variable or item defined as having a boolean type is tested
           against zero (0), meaning FALSE, and against non-zero, meaning
           TRUE.  The variable value is shown as FALSE, TRUE or it is
           decoded to some meaning.  If the variable value is not zero (0)
           or one (1), PMM appends the literal "(Value: n)" to the variable
           value, where 'n' is the real value of the variable.
           Example:

           2147484008 (Menu)  MM_QUERYITEMRECT  Item id: 300 Include ->
              submenus: FALSE  pRectl: 0x000b7e28 (Out)  Sent
           2147484008 (Menu)  MM_QUERYITEMRECT  ->
              Returns: TRUE(Value: 2147484008)<Item found>  ->
              Rectl: (58,20)-(133,1)

        4. Pointer values and undefined flags are shown in hexadecimal.
           Hexadecimal numbers are denoted by the prefix '0x'.
           Here is an example of an undefined flag:

           2147484457 (Style)u  WM_CHAR  Flags: KC_VIRTUALKEY KC_SCANCODE ->
              KC_KEYUP KC_LONEKEY 0x1000 Repeat count: 1 ...
           2147484457 (Style)u  WM_CHAR  Returns: FALSE<Message ignored>

           0x1000 is not defined in the PM include files.

        5. Some "strings," those susceptible to have binary data, are shown
           in hexadecimal.  Every character of the string is translated
           into 2 hexadecimal characters.  This translation is denoted by
           the suffix "(h)".
           Example:






                                  - 59 -



           2147484120 (DDE-Sample)u  WM_DDE_EXECUTE  hwndServer: ->
              2147484139  [DDESTRUCT: cbData: 9 [fsStatus: DDE_FACKREQ ->
              DDE_FAPPSTATUS: 0] usFormat: CF_TEXT offszItemName: 12 ->
              Item name: "Quote" offabData: 18 ->
              Data: 5b434c4f534528295d(h)="[CLOSE()]"]  Dispatched
           2147484120 (DDE-Sample)u  WM_DDE_EXECUTE  Returns

        6. The following is a table of abbreviations used in PMM:

           Abbreviation         Meaning
           ------------         -------

           accel                accelerator
           app                  application
           attr                 attribute
           coor                 coordinate
           id                   identifier
           ipt                  insertion point
           PDCIP                Pointing device capture in progress
           rectl                rectangle

        7. To avoid confusion, if a structure contains more than one
           structure of the same type and the contained structures are not
           an array, every contained structure is identified by the variable
           name beside its name.  An asterisk may appear before the variable
           name, denoting 'the contents of'.
           Example:

           2147484101 (Container) 30  CM_QUERYCNRINFO  pCnrInfo: (Out)  ->
              Bytes to copy: 92  Sent
           2147484101 (Container) 30  CM_QUERYCNRINFO  Returns Bytes ->
              copied: 92  [CNRINFO: cb: 92 pSortRecord: NULL ->
              *pFieldInfoLast: [[FIELDINFO: cb: 32 ...]] ->
              *pFieldInfoObject: [[FIELDINFO: cb: 32 ...]] ->
              ...]

        8. If a message has one or more output parameters and returns an
           error, the output parameters are always shown, even if they are
           not meaningful.
           Example:

           2147484113 (Menu) O. SC_SYSMENU  MM_QUERYITEM  Item id: -1 ->
              Include submenus: FALSE  pMenuItem: 0x00082380 (Output)  Sent
           2147484113 (Menu) O. SC_SYSMENU  MM_QUERYITEM  ->
              Returns: Error  [MENUITEM: iPosition: 0 afStyle: ->
              MIS_BITMAP MIS_SUBMENU afAttribute: 0 id: SC_SYSMENU ->
              hwndSubMenu: 2147484113 hItem: 67108870]

        10. When the absence of some flag implies another action or meaning
            and no constant exists for this action or meaning, PMM may
            "create" a constant showing the intended action.  An exclamation



                                  - 60 -



            point (!) will be appended to this undefined constant.
            Example:

            2147484094 (ListBox)  DM_DRAGFILECOMPLETE  File name: ->
               "TEST.TXT"  Flags: DF_COPY! DF_SOURCE DF_SUCCESSFUL  Sent
            2147484094 (ListBox)  DM_DRAGFILECOMPLETE  Returns: 0

            The operation is not a move (if it were the flag would have been
            DF_MOVE), so it is a copy.  Note that DF_COPY is not defined as
            a constant in the PM include files.

            This interpretation is done on some messages only.  Names have
            been selected that are easy to interpret.

        11. PMM detects automatically the File Dialog messages and the Font
            Dialog messages when sent to these dialog windows, and
            differentiates them from user messages with the same value.

        12. The function WinCreateMsgQueue creates an object window whose
            class is "#32767".  This window, like any other window,
            receives messages.  Some of them are:

            When the window is being created:
               WM_CREATE
               WM_ADJUSTWINDOWPOS

            When the window is being destroyed:
               WM_ADJUSTWINDOWPOS
               WM_WINDOWPOSCHANGED
               WM_SHOW
               WM_DESTROY

            Additionally, it may receive messages like this:
               WM_FOCUSCHANGE

            PMM does not trace the messages occurring at create or destroy
            time for this window.



        9. Errors Detected in the Documentation
        


        1. DM_PRINTOBJECT.  The documentation states that the first
           parameter (param1) in the message DM_PRINTOBJECT is a pointer to
           a DRAGINFO structure.  This is incorrect.  param1 is a pointer to
           a DRAGITEM structure.

        2. DM_DRAGOVER.  The documentation states that, for a modified drag
           operation, the field usOperation in the structure DRAGINFO must



                                  - 61 -



           have a value greater (>) than DO_UNKNOWN for an operation defined
           by an application.  When explaining the return values of this
           message it states that usDrop must be greater than or equal (>=)
           to DO_UNKNOWN.  PMM considers values greater than or equal to
           DO_UNKNOWN as application defined operations.

        3. HM_QUERY.  The parameters usmessageid and usselectionid do not
           appear in the documented order:

           param1
              USHORT usmessageid
              USHORT usselectionid

           The correct order is:

           param1
              USHORT usselectionid
              USHORT usmessageid

           PMM shows the correct order.

        4. HM_QUERY.  The constant HMQW_VIEWEDPAGES used in the variable
           usmessageid doesn't exist in the toolkit include files.  The
           correct constant is HMQW_VIEWPAGES.



        10. PMM Limits
        


        The following are the PMM limits:

        Number of PMM sessions running in OS/2 (different tasks): no limit.
        Number of PMM sessions per task: 1.
        Number of PM message queues per session: 1.
        Number of windows handled per session: no limit.
        Number of times that an application can subclass a window: 20.
        Number of nested messages that a window can receive: 200.



        11. Tools Used in Creating PMM
        


        PMM has been written using the following tools:

        The IBM C/C++ Tools Version 2.01.
        The IBM Developer's Toolkit for OS/2 Version 2.1.




                                  - 62 -



        PMM has been tested on OS/2 Version 2.1, 3.0 and 4.0.  No patches
        have been added to any of these versions of OS/2.



        12. Acknowledgments
        

        My special thanks to B.D. (name withheld), David Johnston, Jon
        Saxton, Martin Schaffoener and Charles Wangersky, who reviewed
        the documentation and offered valuable comments and suggestions
        about this program.  I hope they know how much I appreciate
        their fine work.



        13. Disclaimer
        

        PMM is distributed "as is."  No warranty of any kind is expressed
        or implied.  You use it at your own risk.  The author will not be
        liable for data loss, damages, loss of profits or any other kind
        of loss while using this software.



        14. Trademarks
        

        The following terms used in this manual are trademarks or service
        marks of IBM Corporation.

        IBM
        OS/2
        Presentation Manager



















                                  - 63 -


