home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Shareware GOLD
/
NuclearComputingVol3No1.cdr
/
other
/
f1398
/
spy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-28
|
36KB
|
871 lines
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *\
* Spy.c *
* Windows Spy Program *
* Public Domain *
* Written by Michael Geary *
* *
* 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 <stdio.h>
#include <stdarg.h>
#include <windows.h>
#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? */
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 PASCAL DoScrollMsg( HWND, int, WORD, int );
void PASCAL HomeScrollBars( HWND, BOOL );
BOOL PASCAL Initialize( HANDLE, int );
void cdecl Paint( char *, ... );
void PASCAL PaintWindow( HWND );
void PASCAL SetScrollBars( HWND );
void PASCAL SetScrollBar1( HWND, int, int );
BOOL PASCAL 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 PASCAL 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 PASCAL 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.
*/
BOOL PASCAL 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 */
int nScreenX;
int nScreenY;
nScreenX = GetSystemMetrics( SM_CXSCREEN );
nScreenY = GetSystemMetrics( SM_CYSCREEN );
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 */
hWnd = CreateWindow(
szClass, /* Class name */
szTitle, /* Window title */
WS_TILEDWINDOW | WS_HSCROLL | WS_VSCROLL, /* Window style */
nScreenX * 1 / 20, /* X: 5% from left */
nScreenY * 1 / 10, /* Y 10% from top */
nScreenX * 9 / 10, /* nWidth: 90% */
nScreenY * 7 / 10, /* nHeight: 70% */
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;
/* 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 TRUE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* 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.
*/
void cdecl Paint( char *szFormat, ... )
/* char * szFormat; - Format string as used in printf() */
{
va_list Args;
int nLength; /* Length of formatted string */
char Buf[160]; /* Buffer to format string into */
va_start(Args, szFormat);
nLength = vsprintf( Buf, szFormat, Args );
TextOut( hdcPaint, nPaintX, nPaintY+nExtLeading, Buf, nLength );
nPaintY += nCharSizeY;
va_end(Args);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* 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 PASCAL 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 */
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 PASCAL 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 PASCAL 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 PASCAL 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_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;
default:
break;
}
break;
/* 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.
*/
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 */
/* Save our instance handle in static variable */
hInstance = hInst;
/* Initialize application, quit if any errors */
if( ! 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 );
}
return msg.wParam;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */