📄 vxdmon.c
字号:
/******************************************************************************
*
* VxdMon - VxD Device Monitor
*
* Copyright (c) 1996 Mark Russinovich and Bryce Cogswell
*
* You have the right to take this code and use it in whatever way you
* wish.
*
* PROGRAM: VxdMon.c
*
* PURPOSE: Communicates with the VxdMon VxD to display performance
* information virtual device activity.
*
******************************************************************************/
#include <windows.h> // includes basic windows functionality
#include <commctrl.h> // includes the common control header
#include <stdio.h>
#include <string.h>
#include "resource.h"
#include "../vxd/vxdmon.h"
// Variables/definitions for the VxD that performs the actual monitoring.
#define VXD_NAME "\\\\.\\VXDMHLP.VXD"
static HANDLE vxd_handle = INVALID_HANDLE_VALUE;
// White space in services.dat and profile.dat
#define ISWHITE(c) ( (c)==' ' || (c)=='\t' || (c)=='\n' || (c)=='\r' )
// Indicate whether a service is hooked or not, or for higher levels of tree, whether
// sub-items are hooked or not. These values correspond to the ImageList for the
// selection tree.
enum {
HOOK_NO = 0, // Not hooked
HOOK_YES = 1, // Hooked
HOOK_PART = 2, // Subset of subitems hooked
};
// Structure used to define each hookable service. The set of services is defined
// by the services.dat file.
struct service {
DWORD Ordinal; // VxD and service number
char * Name; // Name of service
HTREEITEM hTree; // Pointer to item in service-selection tree
BOOL Hooked; // Whether service is currently hooked
struct service * Next; // Next service pointer
};
// The global list of hookable services
struct service * ServiceList = NULL;
// Variables for reading statistics from our VxD
#define MAX_SERVICE 2000
// Buffer into which VxD can copy statistics
struct vxdmon_stats Stats[ MAX_SERVICE ];
// Current fraction of buffer filled
DWORD numStats;
// Application instance handle
HINSTANCE hInst;
// General buffer for storing temporary strings
static char msgbuf[ 200 ];
// Root of selection tree
HTREEITEM hSelectRoot;
// Image list for selection tree
HIMAGELIST hSelectImageList;
// Image list for ancestor/descendant trees
HIMAGELIST hCallImageList;
// General cursor manipulation
HCURSOR hSaveCursor;
HCURSOR hHourGlass;
// name of stats file
char szFileName[256];
BOOL GotFile = FALSE; // Do we have a valide file name
// name of help file
char szHelpFileName[] = "VXDMON.HLP";
// name of call graph file
char CallFileName[256];
// global status variables
BOOL ProfileChanged = FALSE; // new hook settings
BOOL IgnoreUncalled = TRUE; // Ignore services never called
BOOL Overhead = TRUE; // Compensate for hooking overhead
DWORD OverheadCycles = 0; // Overhead incurred by VxD monitoring code
// Potential states of call-tree items.
// These correspond to the call-tree image list.
enum {
CALL_NONE = 0,
CALL_UP = 1,
CALL_DOWN = 2,
};
// Which service are we currently displaying a call tree for?
struct vxdmon_stats * CallTreeStat;
BOOL CallTreeDown = FALSE; // tree grows up or down?
BOOL ResetStatsOnUpdate = TRUE;
// procs
long APIENTRY MainWndProc( HWND, UINT, UINT, LONG );
long APIENTRY TreeWndProc( HWND, UINT, UINT, LONG );
long APIENTRY CallWndProc( HWND, UINT, UINT, LONG );
BOOL APIENTRY About( HWND, UINT, UINT, LONG );
//functions
BOOL InitApplication( HANDLE );
HWND InitInstance( HANDLE, int );
HWND CreateListView( HWND );
LRESULT NotifyHandler( HWND, UINT, WPARAM, LPARAM );
int CALLBACK ListViewCompareProc( LPARAM, LPARAM, LPARAM );
HWND CreateTreeView( HWND hWndParent );
BOOL AddTreeViewItems( HWND hwndTree );
HTREEITEM AddOneTreeViewItem( HWND hwndTree, HTREEITEM hParent, HTREEITEM hInsAfter,
LPSTR szText, DWORD lParam );
BOOL DefaultTreeSelections( HWND hwndTree );
BOOL HookServices( HWND hTree, HTREEITEM hItem );
POINT ClickPoint( HWND hWnd );
BOOL AddCallTreeItems( HWND hTree, HTREEITEM Parent, struct vxdmon_stats * stats, int depth );
void WriteDefaultTreeSelections( HWND hTree, HTREEITEM hItem );
void CreateCallTree( HWND hWnd, struct vxdmon_stats * item, BOOL calldown );
BOOL GetFileName( HWND hWnd, char *FileName, char *Filter, char *Ext );
void SaveStatisticsData( HWND hWnd, HWND hWndListView );
void RefreshStatistics( HWND hWnd, HWND hWndListView, int SortItem );
/******************************************************************************
*
* FUNCTION: Abort:
*
* PURPOSE: Handles emergency exit conditions.
*
*****************************************************************************/
void Abort( HWND hWnd, char * Msg )
{
MessageBox( hWnd, Msg, "VxdMon", MB_OK );
PostQuitMessage( 1 );
}
/******************************************************************************
*
* FUNCTION: StringDup:
*
* PURPOSE: Convenience function for duplicating a string into heap-allocated memory.
*
******************************************************************************/
char * StringDup( const char * str )
{
char * new = LocalAlloc( LPTR, strlen(str)+1 );
strcpy( new, str );
return new;
}
/******************************************************************************
*
* FUNCTION: LookupService
*
* PURPOSE: Searches the list of services defined by services.dat for a particular ordinal.
*
******************************************************************************/
struct service * LookupService( DWORD Ordinal )
{
struct service * p = ServiceList;
while ( p && p->Ordinal != Ordinal )
p = p->Next;
return p;
}
/******************************************************************************
*
* FUNCTION: NewService
*
* PURPOSE: Allocates space for and initializes a new service.
* Used while reading the services.dat file.
*
******************************************************************************/
struct service * NewService( DWORD Ordinal, const char * Name )
{
struct service * New = LocalAlloc( LPTR, sizeof *New );
// Initialize info for new service
New->Ordinal = Ordinal;
New->Name = StringDup( Name );
// Add to list of services
New->Next = ServiceList;
ServiceList = New;
// Return newly created service
return New;
}
/******************************************************************************
*
* FUNCTION: ServiceName
*
* PURPOSE: Convenience function for both searching for a service by ordinal, and then
* returning the name of the service.
*
******************************************************************************/
char * ServiceName( DWORD ord )
{
struct service * s = LookupService( ord );
if ( s )
return s->Name;
else
return "???";
}
/****************************************************************************
*
* FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
*
* PURPOSE: calls initialization function, processes message loop
*
****************************************************************************/
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
MSG msg;
HWND hWnd;
HANDLE hAccel ;
if ( ! InitApplication( hInstance ) )
return FALSE;
/* Perform initializations that apply to a specific instance */
if ( (hWnd = InitInstance( hInstance, nCmdShow )) == NULL )
return FALSE;
// load menu accelerators
hAccel = LoadAccelerators ( hInstance, "Accelerators") ;
/* Acquire and dispatch messages until a WM_QUIT message is received. */
while ( GetMessage( &msg, NULL, 0, 0 ) ) {
if (!TranslateAccelerator (hWnd, hAccel, &msg)) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return msg.wParam;
}
/****************************************************************************
*
* FUNCTION: InitApplication(HANDLE)
*
* PURPOSE: Initializes window data and registers window class
*
****************************************************************************/
BOOL InitApplication( HANDLE hInstance ) /* current instance */
{
WNDCLASS wc;
/* Fill in window class structure with parameters that describe the */
/* main (statistics) window. */
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, "APPICON" );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = GetStockObject( /*WHITE_BRUSH*/ LTGRAY_BRUSH );
wc.lpszMenuName = "LISTMENU";
wc.lpszClassName = "VxDMonClass";
if ( ! RegisterClass( &wc ) )
return FALSE;
/* Fill in window class structure with parameters that describe the */
/* service-selection tree view window. */
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)TreeWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, "TREEICON" );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = GetStockObject( /*WHITE_BRUSH*/ LTGRAY_BRUSH );
wc.lpszMenuName = "TREEMENU";
wc.lpszClassName = "VxDMonTreeClass";
if ( ! RegisterClass( &wc ) )
return FALSE;
/* Fill in window class structure with parameters that describe the */
/* call tree window. */
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)CallWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(DWORD); // reserve memory for tree handle
wc.hInstance = hInstance;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = GetStockObject( /*WHITE_BRUSH*/ LTGRAY_BRUSH );
wc.lpszMenuName = "CALLMENU";
// register call-down class
wc.lpszClassName = "VxDMonCallDownClass";
wc.hIcon = LoadIcon( hInstance, "CALLEE" );
if ( ! RegisterClass( &wc ) )
return FALSE;
// register call-up class
wc.lpszClassName = "VxDMonCallUpClass";
wc.hIcon = LoadIcon( hInstance, "CALLER" );
if ( ! RegisterClass( &wc ) )
return FALSE;
return TRUE;
}
/****************************************************************************
*
* FUNCTION: InitInstance(HANDLE, int)
*
* PURPOSE: Saves instance handle and creates main window
*
****************************************************************************/
HWND InitInstance( HANDLE hInstance, int nCmdShow )
{
HWND hWndMain;
hInst = hInstance;
hWndMain = CreateWindow( "VxDMonClass", "VxD Monitor",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL );
/* If window could not be created, return "failure" */
if ( ! hWndMain )
return NULL;
/* Make the window visible; update its client area; and return "success" */
ShowWindow( hWndMain, nCmdShow );
UpdateWindow( hWndMain );
return hWndMain;
}
/****************************************************************************
*
* FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
*
* PURPOSE: Processes messages for the statistics window.
*
****************************************************************************/
LONG APIENTRY MainWndProc( HWND hWnd, UINT message, UINT wParam, LONG lParam)
{
static HWND hTree;
static HWND hWndListView;
static int SortItem = -1;
DWORD row, statcmd;
LV_HITTESTINFO htInfo;
DWORD nb;
LV_ITEM Item;
switch ( message ) {
case WM_CREATE:
// get hourglass icon ready
hHourGlass = LoadCursor( NULL, IDC_WAIT );
// Create the listview within the main window
hWndListView = CreateListView( hWnd );
if ( hWndListView == NULL )
MessageBox( NULL, "Listview not created!", NULL, MB_OK );
// open the handle to the VXD
vxd_handle = CreateFile( VXD_NAME, 0, 0, NULL,
0, FILE_FLAG_DELETE_ON_CLOSE, NULL );
if ( vxd_handle == INVALID_HANDLE_VALUE ) {
wsprintf( msgbuf, "Opening %s: error %d", VXD_NAME,
GetLastError( ) );
Abort( hWnd, msgbuf );
}
// Have VxD compute overhead of service hooking
// Do this before hooking any services
if ( ! DeviceIoControl( vxd_handle, VXDMON_getoverhead,
NULL, 0, &OverheadCycles, sizeof(DWORD),
&nb, NULL ) )
{
MessageBox( hWnd, "Couldn't get monitoring overhead", NULL, MB_OK );
OverheadCycles = 0;
}
// Create the service selection tree view, but don't show it yet.
hTree = CreateWindow(
"VxDMonTreeClass", "Hook Selection", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInst, NULL );
if ( !hTree ) {
wsprintf( msgbuf, "Treeview not created: Error %d", GetLastError() );
MessageBox( NULL, msgbuf, NULL, MB_OK );
}
// Create and fill image list for call tree view
hCallImageList = ImageList_Create( 16, 16, ILC_MASK, 2, 1 );
ImageList_AddIcon( hCallImageList, LoadIcon( hInst, "SELECTED" ));
ImageList_AddIcon( hCallImageList, LoadIcon( hInst, "CALLER" ));
ImageList_AddIcon( hCallImageList, LoadIcon( hInst, "CALLEE" ));
// Initialize check marks on menu items
CheckMenuItem( GetMenu( hWnd ), IDM_RESETONUPDATE,
MF_BYCOMMAND | (ResetStatsOnUpdate?MF_CHECKED:MF_UNCHECKED) );
break;
case WM_NOTIFY:
// Make sure its intended for us
if ( wParam == ID_LISTVIEW ) {
NM_LISTVIEW * pNm = (NM_LISTVIEW *)lParam;
switch ( pNm->hdr.code ) {
case LVN_BEGINLABELEDIT:
// Don't allow editing of service information
return TRUE;
case LVN_COLUMNCLICK:
// post hourglass icon
SetCapture( hWnd );
hSaveCursor = SetCursor(hHourGlass);
// The user clicked a column header - sort by this criterion.
ListView_SortItems( pNm->hdr.hwndFrom, ListViewCompareProc,
(LPARAM)pNm->iSubItem );
SortItem = pNm->iSubItem;
// notify user that operation is done
SetCursor( hSaveCursor );
ReleaseCapture();
break;
case NM_DBLCLK:
case NM_RDBLCLK:
// On double click pull up call-tree view for item
htInfo.pt = ClickPoint( hWndListView );
// Determine service clicked upon
row = ListView_HitTest( hWndListView, &htInfo );
if ( row != (DWORD)-1 && htInfo.flags & LVHT_ONITEMLABEL ) {
// Create call graph for item
LV_ITEM Item;
// Get additional information about service clicked on
Item.mask = LVIF_PARAM;
Item.iItem = row;
Item.iSubItem = 0;
if ( ! ListView_GetItem( hWndListView, &Item ) )
return 0;
// Create the call tree window
CreateCallTree( hWnd,
(struct vxdmon_stats *) Item.lParam,
pNm->hdr.code == NM_DBLCLK );
}
break;
}
}
return 0;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case IDM_TREEVIEW:
/* Make the service selection window visible and update its client area */
ShowWindow( hTree, SW_SHOWNORMAL );
BringWindowToTop( hTree );
UpdateWindow( hTree );
return TRUE;
// stats related commands to send to VxD
case IDM_ZEROSTATS:
// Zero information on screen
for ( row = 0; row < numStats; ++row ) {
Stats[row].Enter = 0;
Stats[row].Exit = 0;
Stats[row].Time = 0;
}
// Have VxD likewise zero information
if ( ! DeviceIoControl( vxd_handle, VXDMON_zerostats,
NULL, 0, NULL, 0, NULL, NULL ) )
{
Abort( hWnd, "Couldn't access VxD" );
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -