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 // Include header files as needed #include #include #include // 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] 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ÄÂÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄ]ÄÁÄÄÄÂÄÄÄÂÄÄÄ ÀÄÄÙ ÀÄ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) -> 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 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 -