home *** CD-ROM | disk | FTP | other *** search
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *\
- * Spy.c *
- * Windows Spy Program *
- * Public Domain *
- * Written by Michael Geary *
-
- Modified for Windows 3.0 by Dennis Chuah
- chuah@stargate.elec.canterbury.ac.nz
- chuahdc@stargate.elec.canterbury.ac.nz
-
- Modifications I made:
- Minor modifications to this file
- Changed a function (Paint) to use more the standard va_args
- Deleted an include line in SPY.RC
- Converted the Windows 2.0 icon file to 3.0 (and changed a few of
- its colours as well).
- What I did not do:
- Made intensive tests on this port.
- Guarantee that it would work on your machine. (In fact I will
- *NOT* even guarantee that you can compile it.) This is a
- 10-minute hack so don't expect miracles. I compiled it
- using Borland C++, using the small model - all functions
- exported.
- Changed any of its algorithm. Some of it may not work for
- Windows 3.0.
-
- If you cannot run/compile this - tough. I included the original
- Windows 2.0 source so you can hack it if you like.
-
- Disclaimer: By using this hack, you are accepting that I will
- NOT be held responsible for any loss or damage resulting
- from the use or misuse of this program.
-
- If you have a problem, you can either;
- a) Contact me. I don't plan to support this program but try
- me anyway - if I have the time and the knowledge, I will
- try and help you.
- b) Contact the original author. He is probably the person to
- ask if you have a problem with the algorithm. I merely
- ported it to Windows 3.0.
-
- *** Happy hacking ***
-
- * This program "spies" on all the windows that are currently open in your *
- * Windows session, and displays a window containing all the information it *
- * can find out about those windows. You can scroll through this window *
- * using either the mouse or keyboard to view the information about the *
- * various windows. The "New Spy Mission" menu item re-captures the latest *
- * information. This menu item is on the System menu so you can trigger it *
- * even if the Spy window is iconic. *
- \* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- #define LINT_ARGS
- #include <windows.h>
- #include <stdio.h>
- #include <stdarg.h> /* Dennis: Added this include file */
- #include "spy.h"
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* The display for a single window looks like this in collapsed mode:
- *
- * {Child|Popup|TopLevel} window HHHH {class} (L,T;R,B) "title"
- *
- * or like this in expanded mode:
- *
- * {Child|Popup|TopLevel} window handle: HHHH
- * Class name: {class name}
- * Window title: {title text}
- * Parent window handle: HHHH
- * Class function, window function: HHHH:HHHH, HHHH:HHHH
- * Class module handle, Window instance handle: HHHH, HHHH
- * Class extra alloc, Window extra alloc: DDDDD, DDDDD
- * Class style, Window style: HHHH, HHHHHHHH
- * Menu handle: HHHH -or- Control ID: DDDDD
- * Brush, Cursor, Icon handles: HHHH, HHHH, HHHH
- * Window rectangle: Left=DDDDD, Top=DDDDD, Right=DDDDD, Bottom=DDDDD
- * Client rectangle: Left=DDDDD, Top=DDDDD, Right=DDDDD, Bottom=DDDDD
- * {blank line}
- *
- * Total number of lines for one window display: 13
- */
-
- #define LINES_PER_WINDOW 13
- #define WINDOW_WIDTH 120
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* The INFO structure contains all the information we gather up about each
- * window we are spying on. We allocate an array of INFO structures in the
- * global heap, with one entry for each window in the system.
- */
-
- #define CLASSMAX 30
- #define TITLEMAX 50
-
- typedef struct {
- HWND winHWnd; /* Window handle */
- char winClass[CLASSMAX]; /* Class name */
- HBRUSH winBkgdBrush; /* Background brush handle */
- HCURSOR winCursor; /* Cursor handle */
- HICON winIcon; /* Icon handle */
- HANDLE winClassModule; /* Module handle for owner of class */
- WORD winWndExtra; /* Extra data allocated for each window */
- WORD winClsExtra; /* Extra data allocated in class itself */
- WORD winClassStyle; /* Class style word */
- FARPROC winClassProc; /* Window function declared for class */
- HANDLE winInstance; /* Instance handle for window owner */
- HWND winHWndParent; /* Parent window handle */
- char winTitle[TITLEMAX]; /* Window title or content string */
- WORD winControlID; /* Control ID or menu handle */
- FARPROC winWndProc; /* Window function, usually = class fun. */
- DWORD winStyle; /* Style doubleword for window (WS_...) */
- RECT winWindowRect; /* Window rectangle (screen-relative) */
- RECT winClientRect; /* Client rectangle within window rect. */
- } INFO;
-
- typedef HANDLE HINFO; /* Handle to array of INFO structures */
- typedef INFO huge * LPINFO; /* Far pointer to same when locked down */
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* The CsrScroll array is used for implementing keyboard scrolling. By
- * looking up the keystroke in this array, we get the equivalent scroll
- * bar message.
- */
-
- #define VK_MIN_CURSOR VK_PRIOR
- #define VK_MAX_CURSOR VK_DOWN
-
- struct {
- char csBar; /* Which scroll bar this key is equivalent to */
- char csMsg; /* The scroll message for this key */
- } CsrScroll[] = {
- { SB_VERT, SB_PAGEUP }, /* VK_PRIOR (PgUp) */
- { SB_VERT, SB_PAGEDOWN }, /* VK_NEXT (PgDn) */
- { SB_VERT, SB_BOTTOM }, /* VK_END (End) */
- { SB_VERT, SB_TOP }, /* VK_HOME (Home) */
- { SB_HORZ, SB_LINEUP }, /* VK_LEFT (left arrow) */
- { SB_VERT, SB_LINEUP }, /* VK_UP (up arrow) */
- { SB_HORZ, SB_LINEDOWN }, /* VK_RIGHT (right arrow) */
- { SB_VERT, SB_LINEDOWN } /* VK_DOWN (down arrow) */
- };
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Static variables
- */
-
- HANDLE hInstance; /* Our instance handle */
- HINFO hInfo; /* Global handle to INFO array structure */
- LPINFO lpInfo; /* Far pointer to INFO, when locked down */
- int nWindows; /* Total number of windows in system */
- DWORD dwInfoSize; /* Size of entire INFO array in bytes */
- FARPROC lpprocCountWindow; /* ProcInstance for CountWindow */
- FARPROC lpprocSpyOnWindow; /* ProcInstance for SpyOnWindow */
- BOOL bInitted = FALSE; /* TRUE when initialization completed */
- BOOL bExpand = FALSE; /* Expanded display mode? */
- BOOL bUpdate = FALSE;
- int nLinesPerWindow = 1; /* 1 or LINES_PER_WINDOW */
- int nCharSizeX; /* Width of a character in pixels */
- int nCharSizeY; /* Height of a character in pixels */
- int nExtLeading; /* # pixels vertical space between chars */
- int nPaintX; /* For Paint function: X coordinate */
- int nPaintY; /* For Paint function: Y coordinate */
- HDC hdcPaint; /* For Paint function: hDC to paint into */
- char szClass[10]; /* Our window class name */
- char szTitle[40]; /* Our window title */
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Declare full templates for all our functions. This gives us strong type
- * checking on our functions.
- */
-
- BOOL FAR PASCAL CountWindow( HWND, long );
- int DoScrollMsg( HWND, int, WORD, int );
- void HomeScrollBars( HWND, BOOL );
- HWND Initialize( HANDLE, int );
-
- /* Dennis: Changed this function */
- void cdecl Paint( char *, ...);
- void PaintWindow( HWND );
- void SetScrollBars( HWND );
- void SetScrollBar1( HWND, int, int );
- BOOL SpyOnAllWindows( HWND );
- BOOL FAR PASCAL SpyOnWindow( HWND, long );
- long FAR PASCAL SpyWndProc( HWND, unsigned, WORD, LONG );
- int PASCAL WinMain( HANDLE, HANDLE, LPSTR, int );
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Enumeration function to count the number of windows in the system. Called
- * once for each window, via EnumWindows and recursively via EnumChildWindows.
- * The lTopLevel parameter tells us which kind of call it is.
- */
-
- BOOL FAR PASCAL CountWindow( hWnd, lTopLevel )
- HWND hWnd; /* Window handle for this window */
- long lTopLevel; /* 1=top level window, 0=child window */
- {
- /* Count the window */
- dwInfoSize += sizeof(INFO);
- ++nWindows;
-
- /* If this is a top level window (or popup), count its children */
- if( lTopLevel )
- EnumChildWindows( hWnd, lpprocCountWindow, 0L );
-
- return TRUE; /* TRUE to continue enumeration */
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Process a scroll bar message. Calculates the distance to scroll based on
- * the scroll bar range and the message code. Limits the scroll to the actual
- * range of the scroll bar. Sets the new scroll bar thumb position and
- * scrolls the window by the necessary amount. Note that the scroll bar
- * ranges are set in terms of number of characters, while the window scrolling
- * is done by a number of pixels. Returns the distance scrolled in chars.
- */
-
- int DoScrollMsg( hWnd, nBar, wCode, nThumb )
- HWND hWnd; /* Window handle to scroll */
- int nBar; /* Which scroll bar: SB_HORZ or SB_VERT */
- WORD wCode; /* The scroll bar message code */
- int nThumb; /* Thumb position for SB_THUMBPOSITION */
- {
- int nOld; /* Previous scroll bar position */
- int nDiff; /* Amount to change scroll bar by */
- int nMin; /* Minimum value of scroll bar range */
- int nMax; /* Maximum value of scroll bar range */
- int nPageSize; /* Size of our window in characters */
- RECT rect; /* Client rectangle for our window */
-
- /* Get old scroll position and scroll range */
- nOld = GetScrollPos( hWnd, nBar );
- GetScrollRange( hWnd, nBar, &nMin, &nMax );
-
- /* Quit if there is nowhere to scroll to (see SetScrollBars) */
- if( nMax == MAXINT )
- return 0;
-
- /* Calculate page size, horizontal or vertical as needed */
- GetClientRect( hWnd, &rect );
- if( nBar == SB_HORZ )
- nPageSize = (rect.right - rect.left) / nCharSizeX;
- else
- nPageSize = (rect.bottom - rect.top) / nCharSizeY;
-
- /* Select the amount to scroll by, based on the scroll message */
- switch( wCode ) {
-
- case SB_LINEUP:
- nDiff = -1;
- break;
-
- case SB_LINEDOWN:
- nDiff = 1;
- break;
-
- case SB_PAGEUP:
- nDiff = -nPageSize;
- break;
-
- case SB_PAGEDOWN:
- nDiff = nPageSize;
- break;
-
- case SB_THUMBPOSITION:
- nDiff = nThumb - nOld;
- break;
-
- case SB_TOP:
- nDiff = -30000; /* Kind of a kludge but it works... */
- break;
-
- case SB_BOTTOM:
- nDiff = 30000;
- break;
-
- default:
- return 0;
- }
-
- /* Limit scroll destination to nMin..nMax */
- if( nDiff < nMin - nOld )
- nDiff = nMin - nOld;
-
- if( nDiff > nMax - nOld )
- nDiff = nMax - nOld;
-
- if( nDiff == 0 )
- return 0; /* Return if net effect is nothing */
-
- /* OK, now we can set the new scroll bar position and scroll the window */
- SetScrollPos( hWnd, nBar, nOld + nDiff, TRUE );
-
- ScrollWindow(
- hWnd,
- nBar == SB_HORZ ? -nDiff*nCharSizeX : 0,
- nBar == SB_HORZ ? 0 : -nDiff*nCharSizeY,
- NULL,
- NULL
- );
-
- /* Force an immediate update for cleaner appearance */
- UpdateWindow( hWnd );
-
- return nDiff;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Set both scroll bars to the home position (0)
- */
-
- void HomeScrollBars( hWnd, bRedraw )
- HWND hWnd; /* Window handle */
- BOOL bRedraw; /* TRUE if scroll bars should be redrawn */
- {
- SetScrollPos( hWnd, SB_HORZ, 0, bRedraw );
- SetScrollPos( hWnd, SB_VERT, 0, bRedraw );
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Initialize the application. Some of the initialization is different
- * depending on whether this is the first instance or a subsequent instance.
- * For example, we register our window class only in the first instance.
- * Returns TRUE if initialization succeeded, FALSE if failed.
- */
-
- HWND Initialize( hPrevInst, nCmdShow )
- HANDLE hPrevInst; /* Previous instance handle, 0 if first */
- int nCmdShow; /* Parameter from WinMain for ShowWindow */
- {
- WNDCLASS Class; /* Class structure for RegisterClass */
- HWND hWnd; /* Our window handle */
- HDC hDC; /* Display context for our window */
- TEXTMETRIC Metrics; /* Text metrics for System font */
- HMENU hMenu; /* Menu handle of system menu */
-
- if( ! hPrevInst ) {
- /* Initialization for first instance only */
-
- /* Load strings from resource file */
- LoadString( hInstance, IDS_CLASS, szClass, sizeof(szClass) );
- LoadString( hInstance, IDS_TITLE, szTitle, sizeof(szTitle) );
-
- /* Register our window class */
- Class.style = CS_HREDRAW | CS_VREDRAW;
- Class.lpfnWndProc = SpyWndProc;
- Class.cbClsExtra = 0;
- Class.cbWndExtra = 0;
- Class.hInstance = hInstance;
- Class.hIcon = LoadIcon( hInstance, szClass );
- Class.hCursor = LoadCursor( NULL, IDC_ARROW );
- Class.hbrBackground = COLOR_WINDOW + 1;
- Class.lpszMenuName = szClass;
- Class.lpszClassName = szClass;
-
- if( ! RegisterClass( &Class ) )
- return FALSE;
-
- } else {
- /* Initialization for subsequent instances only */
-
- /* Copy data from previous instance */
- GetInstanceData( hPrevInst, szClass, sizeof(szClass) );
- GetInstanceData( hPrevInst, szTitle, sizeof(szTitle) );
- }
-
- /* Initialization for every instance */
-
- /* Set up ProcInstance pointers for our Enumerate functions */
- lpprocCountWindow = MakeProcInstance( CountWindow, hInstance );
- lpprocSpyOnWindow = MakeProcInstance( SpyOnWindow, hInstance );
- if( ! lpprocCountWindow || ! lpprocSpyOnWindow )
- return FALSE;
-
- /* Allocate our INFO structure with nothing really allocated yet */
- hInfo = GlobalAlloc( GMEM_MOVEABLE, 1L );
- if( ! hInfo )
- return FALSE;
-
- /* Create our tiled window but don't display it yet */
- /* Dennis: changed this */
- hWnd = CreateWindow(
- szClass, /* Class name */
- szTitle, /* Window title */
- WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, /* Window style */
- CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT,
- NULL, /* Parent hWnd (none for top-level) */
- NULL, /* Menu handle */
- hInstance, /* Owning instance handle */
- NULL /* Parameter to pass in WM_CREATE (none) */
- );
-
- /* Initialize scroll bars - Windows doesn't do this for us */
- HomeScrollBars( hWnd, FALSE );
-
- /* Calculate character size for system font */
- hDC = GetDC( hWnd );
- GetTextMetrics( hDC, &Metrics );
- ReleaseDC( hWnd, hDC );
- nExtLeading = Metrics.tmExternalLeading;
- nCharSizeX = Metrics.tmMaxCharWidth;
- nCharSizeY = Metrics.tmHeight + Metrics.tmExternalLeading;
-
- /* Make the window visible before grabbing spy info, so it's included */
- ShowWindow( hWnd, nCmdShow );
-
- /* Now grab the spy information */
- if( ! SpyOnAllWindows( hWnd ) )
- return FALSE;
-
- if (!SetTimer (hWnd, 1, 5000, (FARPROC) NULL))
- MessageBox (hWnd, "Cannot find a free system timer:\n"
- "Display will not update automatically.",
- "Window Spy:",
- MB_OK | MB_APPLMODAL | MB_ICONINFORMATION);
-
- /* Got all the information, update our display */
- UpdateWindow( hWnd );
-
- /* Make note that initialization is complete. This is checked in our
- * routine that handles WM_SIZE to eliminate some jitter on startup */
- bInitted = TRUE;
- return hWnd;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Format and paint a line of text. szFormat and Args are just as in a
- * sprintf() call (Args is a variable number of arguments). The global
- * variables nPaintX and nPaintY tell where to paint the line. We increment
- * nPaintY to the next line after painting.
- * Note the 'cdecl' declaration. This forces this function to use the
- * standard C calling sequence, which is necessary with a variable number
- * of parameters.
- */
-
- /* Dennis: Changed this function to use the more standard va_args
- construct.
- */
- void cdecl Paint(char *szFormat, ... )
- /* Format string as used in printf() */
- /* Zero or more parameters, as in printf */
- {
- va_list argptr;
- int nLength; /* Length of formatted string */
- char Buf[160]; /* Buffer to format string into */
-
- va_start (argptr, szFormat);
- nLength = vsprintf( Buf, szFormat, argptr );
- va_end(argptr);
-
- TextOut( hdcPaint, nPaintX, nPaintY+nExtLeading, Buf, nLength );
- nPaintY += nCharSizeY;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Paints our window or any portion of it that needs painting.
- * The BeginPaint call sets up a structure that tells us what rectangle of the
- * window to paint, along with other information for the painting process.
- * First, erase the background area if necessary.
- * Then, calculate the index into the INFO array to start with, based on the
- * painting rectangle and the scroll bar position, and lock down the INFO.
- * Finally, loop through the INFO array, painting the text for each entry.
- * Quit when we run out of entries or hit the bottom of the paint rectangle.
- */
-
- void PaintWindow( hWnd )
- HWND hWnd; /* Window handle to paint */
- {
- PAINTSTRUCT ps; /* Paint structure set up by BeginPaint */
- DWORD rgbOldTextColor; /* Old text color (so we can restore it) */
- DWORD rgbOldBkColor; /* Old background color */
- int nWin; /* Index into INFO array */
- int X; /* X position for paint calculation */
- int Y; /* Y position for paint calculation */
- PSTR pTypeName; /* Pointer to "Child", etc. string */
-
- /* Tell Windows we're painting, set up the paint structure. */
- BeginPaint( hWnd, &ps );
-
- /* Store display context in global for Paint function */
- /* Dennis: This is probably not necessary again, since BeginPaint
- returns the a handle to the window's client device
- context, but as it is legal, I'll leave it alone.
- */
- hdcPaint = ps.hdc;
-
- /* Set up proper background and text colors and save old values */
- rgbOldBkColor = SetBkColor( ps.hdc, GetSysColor( COLOR_WINDOW ) );
- rgbOldTextColor = SetTextColor( ps.hdc, GetSysColor( COLOR_WINDOWTEXT ) );
- /* Calculate horizontal paint position based on scroll bar position */
- X = ( 1 - GetScrollPos( hWnd, SB_HORZ ) ) * nCharSizeX;
-
- /* Calculate index into INFO array and vertical paint position, based on
- * scroll bar position and top of painting rectangle */
- Y = GetScrollPos( hWnd, SB_VERT );
- nWin = ( ps.rcPaint.top / nCharSizeY + Y ) / nLinesPerWindow;
- nPaintY = ( nWin * nLinesPerWindow - Y ) * nCharSizeY;
-
- /* Lock down INFO array and set lpInfo pointing to first entry to paint */
- lpInfo = (LPINFO)GlobalLock( hInfo );
- lpInfo += nWin;
-
- /* Loop through INFO entries, painting each one until we run out of entries
- * or until we are past the bottom of the paint rectangle. We don't worry
- * much about painting outside the rectangle - Windows will clip for us. */
- while( nWin < nWindows && nPaintY < ps.rcPaint.bottom )
- {
- /* Set X position and indent child windows, also set up pTypeName */
- nPaintX = X;
- if( lpInfo->winStyle & WS_CHILD ) {
- nPaintX += nCharSizeX * ( bExpand ? 4 : 2 );
- pTypeName = "Child";
- } else if( lpInfo->winStyle & WS_ICONIC ) {
- pTypeName = "Icon ";
- } else if( lpInfo->winStyle & WS_POPUP ) {
- pTypeName = "Popup";
- } else {
- pTypeName = "Top Level";
- }
-
- if( ! bExpand ) {
-
- /* Paint the one-liner */
- Paint(
- "%s window %04X {%Fs} (%d,%d;%d,%d) \"%Fs\"",
- pTypeName,
- lpInfo->winHWnd,
- lpInfo->winClass,
- lpInfo->winWindowRect.left,
- lpInfo->winWindowRect.top,
- lpInfo->winWindowRect.right,
- lpInfo->winWindowRect.bottom,
- lpInfo->winTitle
- );
-
- } else {
-
- /* Paint the expanded form, first the window handle */
- Paint(
- "%s window handle: %04X",
- pTypeName,
- lpInfo->winHWnd
- );
-
- /* Paint the rest of the info, indented two spaces farther over */
- nPaintX += nCharSizeX * 2;
-
- Paint( "Class name: %Fs", lpInfo->winClass );
- Paint( "Window title: %Fs", lpInfo->winTitle );
- Paint( "Parent window handle: %04X", lpInfo->winHWndParent );
- Paint(
- "Class function, Window function: %p, %p",
- lpInfo->winClassProc,
- lpInfo->winWndProc
- );
- Paint(
- "Class module handle, Window instance handle: %04X, %04X",
- lpInfo->winClassModule,
- lpInfo->winInstance
- );
- Paint(
- "Class extra alloc, Window extra alloc: %d, %d",
- lpInfo->winClsExtra,
- lpInfo->winWndExtra
- );
- Paint(
- "Class style, Window style: %04X, %08lX",
- lpInfo->winClassStyle,
- lpInfo->winStyle
- );
- Paint(
- lpInfo->winStyle & WS_CHILD ? "Control ID: %d" :
- "Menu handle: %04X",
- lpInfo->winControlID
- );
- Paint(
- "Brush, Cursor, Icon handles: %04X, %04X, %04X",
- lpInfo->winBkgdBrush,
- lpInfo->winCursor,
- lpInfo->winIcon
- );
- Paint(
- "Window rectangle: Left=%4d, Top=%4d, Right=%4d, Bottom=%4d",
- lpInfo->winWindowRect.left,
- lpInfo->winWindowRect.top,
- lpInfo->winWindowRect.right,
- lpInfo->winWindowRect.bottom
- );
- Paint(
- "Client rectangle: Left=%4d, Top=%4d, Right=%4d, Bottom=%4d",
- lpInfo->winClientRect.left,
- lpInfo->winClientRect.top,
- lpInfo->winClientRect.right,
- lpInfo->winClientRect.bottom
- );
-
- /* Make a blank line - it's already erased, so just increment Y */
- nPaintY += nCharSizeY;
- }
-
- /* Increment to next INFO entry */
- ++nWin;
- ++lpInfo;
- }
-
- /* Unlock the INFO array */
- GlobalUnlock( hInfo );
-
- /* Restore old colors */
- SetBkColor( ps.hdc, rgbOldBkColor );
- SetTextColor( ps.hdc, rgbOldTextColor );
-
- /* Tell Windows we're done painting */
- EndPaint( hWnd, &ps );
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Set horizontal and vertical scroll bars, based on the window size and the
- * number of INFO entries. The scroll bar ranges are set to give a total
- * width of WINDOW_WIDTH and a total height equal to the number of lines of
- * information available. For example, if there are 130 lines of information
- * and the window height is 10 characters, the vertical scroll range is set
- * to 120 (130-10). This lets you scroll through everything and still have
- * a full window of information at the bottom. (Unlike, say, Windows Write,
- * where if you scroll to the bottom you have a blank screen.)
- */
-
- void SetScrollBars( hWnd )
- HWND hWnd; /* Window handle */
- {
- RECT rect; /* The window's client rectangle */
-
- GetClientRect( hWnd, &rect );
-
- SetScrollBar1(
- hWnd, SB_HORZ,
- WINDOW_WIDTH - rect.right / nCharSizeX
- );
-
- SetScrollBar1(
- hWnd, SB_VERT,
- nWindows * nLinesPerWindow - rect.bottom / nCharSizeY
- );
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Set one scroll bar's maximum range. We always set the minimum to zero,
- * although Windows allows other values. There is one case we handle
- * specially. If you set a scroll bar range to minimum==maximum (maximum =
- * zero for us), Windows does not actually set the range, but instead turns
- * off the scroll bar completely, changing the window style by turning off
- * the WS_HSCROLL or WS_VSCROLL bit. For example, this is how the MS-DOS
- * Executive makes its scroll bars appear and disappear. This behavior is
- * fine if you take it into account in your programming in two ways. First,
- * whenever you do a GetScrollRange you must first check the window style to
- * see if that scroll bar still exists, because you will *not* get the correct
- * answer from GetScrollRange if it has been removed. Second, you must be
- * prepared to get some extra WM_SIZE messages, because your client area
- * changes size when the scroll bars appear and disappear. This can cause
- * some sloppy looking screen painting. We take a different approach, always
- * keeping the scroll bars visible. If the scroll bar range needs to be set
- * to zero, instead we set it to MAXINT so the bar remains visible. Then, in
- * DoScrollMessage we check for this case and return without scrolling.
- */
-
- void SetScrollBar1( hWnd, nBar, nMax )
- HWND hWnd; /* Window handle */
- int nBar; /* Which scroll bar: SB_HORZ or SB_VERT */
- int nMax; /* Value to set maximum range to */
- {
- int nOldMin; /* Previous minimum value (always 0) */
- int nOldMax; /* Previous maximum value */
-
- /* Check for a negative or zero range and set our special case flag.
- * Also, set the thumb position to zero in this case. */
- if( nMax <= 0 ) {
- nMax = MAXINT;
- DoScrollMsg( hWnd, nBar, SB_THUMBPOSITION, 0 );
- }
-
- /* Find out the previous range, and set it if it has changed */
- GetScrollRange( hWnd, nBar, &nOldMin, &nOldMax );
- if( nMax != nOldMax )
- SetScrollRange( hWnd, nBar, 0, nMax, TRUE );
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Loop through all windows in the system and gather up information for the
- * INFO structure for each. Use the EnumWindows and EnumChildWindows
- * functions to loop through them. We actually loop through them twice:
- * first, to simply count them so we can allocate global memory for the
- * INFO structure, and again to actually fill in the structure. After
- * gathering up the information, we invalidate our window, which will cause
- * a WM_PAINT message to be posted, so it will get repainted.
- */
-
- BOOL SpyOnAllWindows( hWnd )
- HWND hWnd; /* Window handle */
- {
- /* Calculate the number of windows and amount of memory needed */
- nWindows = 0;
- dwInfoSize = 0;
- EnumWindows( lpprocCountWindow, 1L );
-
- /* Allocate the memory, complain if we couldn't get it */
- hInfo = GlobalReAlloc( hInfo, dwInfoSize, GMEM_MOVEABLE );
- if( ! hInfo ) {
- nWindows = 0;
- dwInfoSize = 0;
- GlobalDiscard( hInfo );
- MessageBox(
- GetActiveWindow(),
- "Insufficient memory!!",
- NULL,
- MB_OK | MB_ICONHAND
- );
- PostQuitMessage( 0 );
- return FALSE;
- }
-
- /* Lock down the memory and fill in the information, then unlock it */
- lpInfo = (LPINFO)GlobalLock( hInfo );
- EnumWindows( lpprocSpyOnWindow, 1L );
- GlobalUnlock( hInfo );
-
- /* Set the scroll bars based on new window count, repaint our window */
- // SetScrollBars( hWnd );
- // HomeScrollBars( hWnd, TRUE );
- InvalidateRect( hWnd, NULL, TRUE );
-
- return TRUE;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Enumeration function to gather up the information for a single window and
- * store it in the INFO array entry pointed to by lpInfo. Increment lpInfo
- * to the next entry afterward. Called once for each window, via EnumWindows
- * for each top level and popup window, and recursively via EnumChildWindows
- * for child windows. The lTopLevel parameter tells which kind of call it is.
- */
-
- BOOL FAR PASCAL SpyOnWindow( hWnd, lTopLevel )
- HWND hWnd; /* Window handle */
- long lTopLevel; /* 1=top level window, 0=child window */
- {
- /* Gather up this window's information */
- lpInfo->winHWnd = hWnd;
- GetClassName( hWnd, lpInfo->winClass, CLASSMAX );
- lpInfo->winClass[ CLASSMAX - 1 ] = 0;
- lpInfo->winInstance = GetWindowWord( hWnd, GWW_HINSTANCE );
- lpInfo->winHWndParent = GetParent( hWnd );
- GetWindowText( hWnd, lpInfo->winTitle, TITLEMAX );
- lpInfo->winTitle[ TITLEMAX - 1 ] = 0;
- lpInfo->winControlID = GetWindowWord( hWnd, GWW_ID );
- lpInfo->winWndProc = (FARPROC)GetWindowLong( hWnd, GWL_WNDPROC );
- lpInfo->winStyle = GetWindowLong( hWnd, GWL_STYLE );
- GetClientRect( hWnd, &lpInfo->winClientRect );
- GetWindowRect( hWnd, &lpInfo->winWindowRect );
-
- /* Gather up class information */
- lpInfo->winBkgdBrush = GetClassWord( hWnd, GCW_HBRBACKGROUND );
- lpInfo->winCursor = GetClassWord( hWnd, GCW_HCURSOR );
- lpInfo->winIcon = GetClassWord( hWnd, GCW_HICON );
- lpInfo->winClassModule = GetClassWord( hWnd, GCW_HMODULE );
- lpInfo->winWndExtra = GetClassWord( hWnd, GCW_CBWNDEXTRA );
- lpInfo->winClsExtra = GetClassWord( hWnd, GCW_CBCLSEXTRA );
- lpInfo->winClassStyle = GetClassWord( hWnd, GCW_STYLE );
- lpInfo->winClassProc = (FARPROC)GetClassLong( hWnd, GCL_WNDPROC );
-
- /* Move on to next entry in table */
- ++lpInfo;
-
- /* If it's a top level window, get its children too */
- if( lTopLevel )
- EnumChildWindows( hWnd, lpprocSpyOnWindow, 0L );
-
- return TRUE; /* TRUE to continue enumeration */
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Window function for our main window. All messages for our window are sent
- * to this function. For messages that we do not handle here, we call
- * DefWindowProc, which performs Windows' default processing for a message.
- */
-
- long FAR PASCAL SpyWndProc( hWnd, wMsg, wParam, lParam )
- HWND hWnd; /* Window handle */
- unsigned wMsg; /* Message number */
- WORD wParam; /* Word parameter for the message */
- LONG lParam; /* Long parameter for the message */
- {
- RECT rect; /* A rectangle */
-
- switch( wMsg ) {
-
- /* Menu command message - process the command */
- case WM_COMMAND:
- if( LOWORD(lParam) )
- break; /* not a command */
- switch( wParam ) {
- case CMD_UPDATE:
- bUpdate = !bUpdate;
- CheckMenuItem (GetMenu (hWnd), CMD_UPDATE,
- MF_BYCOMMAND | (bUpdate ? MF_CHECKED : MF_UNCHECKED));
- return 0;
- case CMD_EXPAND:
- bExpand = ! bExpand;
- nLinesPerWindow = ( bExpand ? LINES_PER_WINDOW : 1 );
- CheckMenuItem(
- GetMenu( hWnd ),
- CMD_EXPAND,
- bExpand ? MF_CHECKED : MF_UNCHECKED
- );
- InvalidateRect( hWnd, NULL, TRUE );
- HomeScrollBars( hWnd, FALSE );
- SetScrollBars( hWnd );
- return 0L;
- case CMD_SPY:
- SpyOnAllWindows( hWnd );
- return 0L;
- case CMD_EXIT:
- PostMessage (hWnd, WM_CLOSE, 0, 0L);
- return 0;
- default:
- break;
- }
- break;
-
- /* Dennis: Added this line to interface with the timer */
- case WM_TIMER:
- if (!bUpdate) break;
- SpyOnAllWindows (hWnd);
- return 0;
-
- /* Destroy-window message - time to quit the application */
- case WM_DESTROY:
- PostQuitMessage( 0 );
- return 0L;
-
- /* Horizontal scroll message - scroll the window */
- case WM_HSCROLL:
- DoScrollMsg( hWnd, SB_HORZ, wParam, (int)lParam );
- return 0L;
-
- /* Key-down message - handle cursor keys, ignore other keys */
- case WM_KEYDOWN:
- if( wParam >= VK_MIN_CURSOR && wParam <= VK_MAX_CURSOR ) {
- DoScrollMsg(
- hWnd,
- CsrScroll[ wParam - VK_MIN_CURSOR ].csBar,
- CsrScroll[ wParam - VK_MIN_CURSOR ].csMsg,
- 0
- );
- }
- return 0L;
-
- /* Paint message - repaint all or part of our window */
- case WM_PAINT:
- PaintWindow( hWnd );
- return 0L;
-
- /* Size message - recalculate our scroll bars to take the new size
- * into account, but only if initialization has been completed. There
- * are several superfluous WM_SIZE messages sent during initialization,
- * and it looks ugly if we repaint the scroll bars for all these. */
- case WM_SIZE:
- if( bInitted )
- SetScrollBars( hWnd );
- return 0L;
-
- /* Vertical scroll message - scroll the window */
- case WM_VSCROLL:
- DoScrollMsg( hWnd, SB_VERT, wParam, (int)lParam );
- return 0L;
-
- /* For all other messages, we pass them on to DefWindowProc */
- default:
- break;
- }
- return DefWindowProc( hWnd, wMsg, wParam, lParam );
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- /* Application main program. Not much is done here - we just initialize
- * the application, putting up our window, and then we go into the typical
- * message dispatching loop that every Windows application has.
- */
-
- /* Dennis: Added this pragma to avoid the Parameter is never used warning
- */
- #pragma argsused
- int PASCAL WinMain( hInst, hPrevInst, lpszCmdLine, nCmdShow )
- HANDLE hInst; /* Our instance handle */
- HANDLE hPrevInst; /* Previous instance of this application */
- LPSTR lpszCmdLine; /* Pointer to any command line params */
- int nCmdShow; /* Parameter to use for first ShowWindow */
- {
- MSG msg; /* Message structure */
- HWND hWnd;
-
- /* Save our instance handle in static variable */
- hInstance = hInst;
-
- /* Initialize application, quit if any errors */
- if( ! (hWnd = Initialize( hPrevInst, nCmdShow)) )
- return 1;
-
- /* Main message processing loop. Get each message, then translate keyboard
- * messages, and finally dispatch each message to its window function. */
- while( GetMessage( &msg, NULL, 0, 0 ) ) {
- TranslateMessage( &msg );
- DispatchMessage( &msg );
- }
-
- KillTimer (hWnd, 1);
-
- return msg.wParam;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-