mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1587 lines
39 KiB
1587 lines
39 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Service.c
|
|
|
|
Abstract:
|
|
|
|
This module contains support for creating and displaying lists of
|
|
Services and Drivers
|
|
|
|
Author:
|
|
|
|
David J. Gilman (davegi) 16-Dec-1992
|
|
Gregg R. Acheson (GreggA) 1-Oct-1993
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
|
|
#include "dialogs.h"
|
|
#include "msg.h"
|
|
#include "dlgprint.h"
|
|
#include "service.h"
|
|
#include "svc.h"
|
|
#include "strtab.h"
|
|
#include "strresid.h"
|
|
#include "winmsd.h"
|
|
|
|
#include <string.h>
|
|
#include <tchar.h>
|
|
|
|
|
|
//
|
|
// Structure used to pass information to DisplayServiceDlgProc. Specifically a
|
|
// handle to a SVC object and a pointer to an ENUM_SERVICE_STATUS which contains
|
|
// the status of the service to display.
|
|
//
|
|
|
|
typedef
|
|
struct
|
|
_DISPLAY_SERVICE {
|
|
|
|
DECLARE_SIGNATURE
|
|
|
|
HSVC hSvc;
|
|
LPENUM_SERVICE_STATUS Ess;
|
|
|
|
} DISPLAY_SERVICE, *LPDISPLAY_SERVICE;
|
|
|
|
typedef
|
|
struct
|
|
_SERVICE_DETAILS {
|
|
|
|
TCHAR szDisplayName[128];
|
|
TCHAR szServiceType[64];
|
|
DWORD dwServiceType;
|
|
TCHAR szStartType[64];
|
|
TCHAR szStartName[64];
|
|
TCHAR szCurrentState[64];
|
|
DWORD dwControlsAccepted;
|
|
TCHAR szExitCode[64];
|
|
TCHAR szPathName[MAX_PATH];
|
|
TCHAR szLoadOrderGroup[64];
|
|
TCHAR szServiceDependencies[1024];
|
|
TCHAR szGroupDependencies[1024];
|
|
|
|
} SERVICE_DETAILS, *LPSERVICE_DETAILS;
|
|
|
|
|
|
//
|
|
// Internal Function Prototypes
|
|
//
|
|
|
|
BOOL
|
|
InitializeDriversServicesTab(
|
|
HWND hWnd
|
|
);
|
|
|
|
BOOL
|
|
GetServiceDetails(
|
|
IN LPDISPLAY_SERVICE lpds,
|
|
IN LPSERVICE_DETAILS lpServiceDetails
|
|
);
|
|
|
|
BOOL
|
|
DisplayList(
|
|
IN HWND hWnd,
|
|
IN UINT ServiceType
|
|
);
|
|
|
|
LRESULT
|
|
NotifyHandler( IN HWND hWnd,
|
|
IN UINT uMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
);
|
|
|
|
UINT
|
|
CALLBACK
|
|
ListViewCompareProc(IN LPARAM lParam1,
|
|
IN LPARAM lParam2,
|
|
IN LPARAM lParamSort
|
|
);
|
|
|
|
BOOL
|
|
DisplayServicePropertySheet(
|
|
HWND hWnd,
|
|
LPSERVICE_DETAILS ServiceDetails
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Begin code
|
|
//
|
|
|
|
BOOL
|
|
DevicesAndServicesDetailsProc(
|
|
IN HWND hWnd,
|
|
IN UINT message,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DisplayServiceDlgProc displays the details about the supplied
|
|
service/device.
|
|
|
|
Arguments:
|
|
|
|
Standard DLGPROC entry.
|
|
|
|
Return Value:
|
|
|
|
BOOL - Depending on input message and processing options.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL Success;
|
|
|
|
switch( message ) {
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
LPSERVICE_DETAILS ServiceDetails = ( LPSERVICE_DETAILS ) ( ( LPPROPSHEETPAGE ) lParam)->lParam ;
|
|
|
|
|
|
LPTSTR Dependent;
|
|
UINT i;
|
|
VALUE_ID_MAP ServiceFlags[ ] = {
|
|
|
|
SERVICE_WIN32_OWN_PROCESS, IDC_TEXT_OWN_PROCESS,
|
|
SERVICE_WIN32_SHARE_PROCESS, IDC_TEXT_SHARED_PROCESS,
|
|
SERVICE_KERNEL_DRIVER, IDC_TEXT_KERNEL_DRIVER,
|
|
SERVICE_FILE_SYSTEM_DRIVER, IDC_TEXT_FS_DRIVER,
|
|
SERVICE_INTERACTIVE_PROCESS, IDC_TEXT_INTERACTIVE
|
|
};
|
|
|
|
|
|
//
|
|
// Set the service flag states
|
|
//
|
|
|
|
for( i = 0; i < NumberOfEntries( ServiceFlags ); i++ ) {
|
|
|
|
Success = EnableControl(
|
|
hWnd,
|
|
ServiceFlags[ i ].Id,
|
|
ServiceDetails->dwServiceType
|
|
& ServiceFlags[ i ].Value
|
|
);
|
|
DbgAssert( Success );
|
|
}
|
|
|
|
|
|
//
|
|
// Display the service/device's start type, error control,
|
|
// and start name.
|
|
//
|
|
|
|
|
|
DbgAssert( Success );
|
|
|
|
Success = SetDlgItemText(
|
|
hWnd,
|
|
IDC_EDIT_START_TYPE,
|
|
ServiceDetails->szStartType);
|
|
|
|
DbgAssert( Success );
|
|
|
|
Success = SetDlgItemText(
|
|
hWnd,
|
|
IDC_EDIT_ERROR_CONTROL,
|
|
ServiceDetails->szExitCode);
|
|
|
|
DbgAssert( Success );
|
|
|
|
Success = SetDlgItemText(
|
|
hWnd,
|
|
IDC_EDIT_START_NAME,
|
|
ServiceDetails->szStartName);
|
|
|
|
DbgAssert( Success );
|
|
|
|
//
|
|
// If the service/device has a binary path name display it.
|
|
//
|
|
|
|
Success = SetDlgItemText(
|
|
hWnd,
|
|
IDC_EDIT_PATHNAME,
|
|
ServiceDetails->szPathName);
|
|
|
|
DbgAssert( Success );
|
|
|
|
|
|
//
|
|
// Display the name of the order group.
|
|
//
|
|
|
|
Success = SetDlgItemText(
|
|
hWnd,
|
|
IDC_EDIT_GROUP,
|
|
ServiceDetails->szLoadOrderGroup);
|
|
|
|
DbgAssert( Success );
|
|
|
|
//
|
|
// Traverse the list of service dependencies and display them
|
|
//
|
|
|
|
Dependent = ServiceDetails->szServiceDependencies;
|
|
while(( Dependent != NULL ) && ( Dependent[ 0 ] != TEXT( '\0' ))) {
|
|
|
|
LONG Index;
|
|
|
|
Index = SendDlgItemMessage(
|
|
hWnd,
|
|
IDC_LIST_SERVICE_DEPEND,
|
|
LB_ADDSTRING,
|
|
0,
|
|
( LPARAM ) &Dependent[ 0 ]
|
|
);
|
|
|
|
DbgAssert( Index != LB_ERR );
|
|
|
|
//
|
|
// Get the next dependent from the list of NUL terminated
|
|
// strings (the list itself is further NUL terminated).
|
|
//
|
|
|
|
Dependent += _tcslen( Dependent ) + 1;
|
|
}
|
|
|
|
//
|
|
// Traverse the list of group dependencies and display them
|
|
//
|
|
|
|
Dependent = ServiceDetails->szGroupDependencies;
|
|
while(( Dependent != NULL ) && ( Dependent[ 0 ] != TEXT( '\0' ))) {
|
|
|
|
LONG Index;
|
|
|
|
Index = SendDlgItemMessage(
|
|
hWnd,
|
|
(int ) IDC_LIST_GROUP_DEPEND,
|
|
LB_ADDSTRING,
|
|
0,
|
|
( LPARAM ) &Dependent[ 0 ]
|
|
);
|
|
|
|
DbgAssert( Index != LB_ERR );
|
|
|
|
//
|
|
// Get the next dependent from the list of NUL terminated
|
|
// strings (the list itself is further NUL terminated).
|
|
//
|
|
|
|
Dependent += _tcslen( Dependent ) + 1;
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
DevicesAndServicesDetailsProc2(
|
|
IN HWND hWnd,
|
|
IN UINT message,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DisplayServiceDlgProc displays the details about the supplied
|
|
service/device.
|
|
|
|
Arguments:
|
|
|
|
Standard DLGPROC entry.
|
|
|
|
Return Value:
|
|
|
|
BOOL - Depending on input message and processing options.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
switch( message ) {
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
LPSERVICE_DETAILS ServiceDetails = ( LPSERVICE_DETAILS ) ( ( LPPROPSHEETPAGE ) lParam)->lParam ;
|
|
LPTSTR Dependent;
|
|
|
|
|
|
//
|
|
// Traverse the list of service dependencies and display them
|
|
//
|
|
|
|
Dependent = ServiceDetails->szServiceDependencies;
|
|
while(( Dependent != NULL ) && ( Dependent[ 0 ] != TEXT( '\0' ))) {
|
|
|
|
LONG Index;
|
|
|
|
Index = SendDlgItemMessage(
|
|
hWnd,
|
|
IDC_LIST_SERVICE_DEPEND,
|
|
LB_ADDSTRING,
|
|
0,
|
|
( LPARAM ) &Dependent[ 0 ]
|
|
);
|
|
|
|
DbgAssert( Index != LB_ERR );
|
|
|
|
//
|
|
// Get the next dependent from the list of NUL terminated
|
|
// strings (the list itself is further NUL terminated).
|
|
//
|
|
|
|
Dependent += _tcslen( Dependent ) + 1;
|
|
}
|
|
|
|
//
|
|
// Traverse the list of group dependencies and display them
|
|
//
|
|
|
|
Dependent = ServiceDetails->szGroupDependencies;
|
|
while(( Dependent != NULL ) && ( Dependent[ 0 ] != TEXT( '\0' ))) {
|
|
|
|
LONG Index;
|
|
|
|
Index = SendDlgItemMessage(
|
|
hWnd,
|
|
IDC_LIST_GROUP_DEPEND,
|
|
LB_ADDSTRING,
|
|
0,
|
|
( LPARAM ) &Dependent[ 0 ]
|
|
);
|
|
|
|
DbgAssert( Index != LB_ERR );
|
|
|
|
//
|
|
// Get the next dependent from the list of NUL terminated
|
|
// strings (the list itself is further NUL terminated).
|
|
//
|
|
|
|
Dependent += _tcslen( Dependent ) + 1;
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetServiceDetails(
|
|
IN LPDISPLAY_SERVICE lpds,
|
|
IN LPSERVICE_DETAILS lpServiceDetails
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetServiceDetails gathers the details about the supplied
|
|
service/device.
|
|
|
|
Arguments:
|
|
|
|
lpds - Structure pointing to service
|
|
lpServiceDetails - Structure to recieve service information
|
|
|
|
Return Value:
|
|
|
|
BOOL - True if successful
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL Success;
|
|
LPQUERY_SERVICE_CONFIG SvcConfig;
|
|
LPTSTR Dependent;
|
|
DWORD Count, i, n;
|
|
TCHAR Buffer[ MAX_PATH ];
|
|
|
|
//
|
|
// Retrieve and validate the DISPLAY_SERVICE object.
|
|
//
|
|
|
|
DbgPointerAssert( lpds );
|
|
DbgAssert( CheckSignature( lpds ));
|
|
if( ( lpds == NULL )
|
|
|| ( ! CheckSignature( lpds ))) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize the ServiceDetails structure
|
|
//
|
|
lpServiceDetails->szDisplayName[0] = UNICODE_NULL;
|
|
lpServiceDetails->szServiceType[0] = UNICODE_NULL;
|
|
lpServiceDetails->szStartType[0] = UNICODE_NULL;
|
|
lpServiceDetails->szStartName[0] = UNICODE_NULL;
|
|
lpServiceDetails->szCurrentState[0] = UNICODE_NULL;
|
|
lpServiceDetails->szExitCode[0] = UNICODE_NULL;
|
|
lpServiceDetails->szPathName[0] = UNICODE_NULL;
|
|
lpServiceDetails->szLoadOrderGroup[0] = UNICODE_NULL;
|
|
lpServiceDetails->szServiceDependencies[0] = UNICODE_NULL;
|
|
lpServiceDetails->szGroupDependencies[0] = UNICODE_NULL;
|
|
|
|
//
|
|
// Create a configuration status for this device/service.
|
|
//
|
|
|
|
SvcConfig = ConstructSvcConfig(
|
|
lpds->hSvc,
|
|
lpds->Ess
|
|
);
|
|
|
|
if( SvcConfig == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Store the display name
|
|
//
|
|
lstrcpy( lpServiceDetails->szDisplayName, lpds->Ess->lpDisplayName);
|
|
|
|
//
|
|
// Store the service/device's type, start type, error control,
|
|
// and start name.
|
|
//
|
|
|
|
// store Service Type as string and DWORD
|
|
lpServiceDetails->dwServiceType = SvcConfig->dwServiceType;
|
|
|
|
lstrcpy( lpServiceDetails->szServiceType,
|
|
GetString(
|
|
GetStringId(
|
|
StringTable,
|
|
StringTableCount,
|
|
ServiceType,
|
|
SvcConfig->dwServiceType
|
|
)
|
|
)
|
|
);
|
|
|
|
|
|
//store the start type
|
|
lstrcpy( lpServiceDetails->szStartType,
|
|
GetString(
|
|
GetStringId(
|
|
StringTable,
|
|
StringTableCount,
|
|
ServiceStartType,
|
|
SvcConfig->dwStartType
|
|
)
|
|
)
|
|
);
|
|
|
|
//store the error code
|
|
lstrcpy( lpServiceDetails->szExitCode,
|
|
GetString(
|
|
GetStringId(
|
|
StringTable,
|
|
StringTableCount,
|
|
ServiceErrorControl,
|
|
SvcConfig->dwErrorControl
|
|
)
|
|
)
|
|
);
|
|
|
|
//store the start name
|
|
lstrcpy( lpServiceDetails->szStartName,
|
|
SvcConfig->lpServiceStartName
|
|
);
|
|
|
|
// store Current Status
|
|
lstrcpy( lpServiceDetails->szCurrentState,
|
|
GetString(
|
|
GetStringId(
|
|
StringTable,
|
|
StringTableCount,
|
|
ServiceCurrentState,
|
|
lpds->Ess->ServiceStatus.dwCurrentState
|
|
)
|
|
)
|
|
);
|
|
|
|
//
|
|
// If the service/device has a binary path name, store it.
|
|
//
|
|
|
|
lpServiceDetails->szPathName[0] = UNICODE_NULL;
|
|
|
|
if( ( SvcConfig->lpBinaryPathName != NULL ) &&
|
|
(SvcConfig->lpBinaryPathName[0] != UNICODE_NULL)) {
|
|
|
|
TCHAR Buffer2[ MAX_PATH ];
|
|
HKEY hkey;
|
|
|
|
//
|
|
// If the binary path name's prefix is '\\SystemRoot' replace
|
|
// this with '%SystemRoot%' and expand the environment
|
|
// variable to the real system root. This is needed because
|
|
// services/devices that are started by the I/O system do not
|
|
// use the environment variable form in their name.
|
|
//
|
|
|
|
if( _tcsnicmp(
|
|
SvcConfig->lpBinaryPathName,
|
|
TEXT( "\\SystemRoot" ),
|
|
11 )
|
|
== 0 ) {
|
|
|
|
Count = WFormatMessage(
|
|
Buffer,
|
|
sizeof( Buffer ),
|
|
IDS_FORMAT_SYSTEM_ROOT,
|
|
&SvcConfig->lpBinaryPathName[ 11 ]
|
|
);
|
|
DbgAssert( Count != 0 );
|
|
|
|
//
|
|
// Now everything is in the form %systemroot%\etc....
|
|
// and in Buffer
|
|
//
|
|
|
|
//
|
|
// Use the registry instead of ExpandEnvironmentStrings
|
|
// so this works remotely
|
|
//
|
|
|
|
//
|
|
// open the CurrentVersion key
|
|
//
|
|
|
|
RegOpenKeyEx(_hKeyLocalMachine,
|
|
SZ_CURRENTVERSIONKEY,
|
|
0,
|
|
KEY_READ,
|
|
&hkey);
|
|
|
|
//
|
|
// Read the SystemRoot Value
|
|
//
|
|
|
|
Count = sizeof(Buffer2);
|
|
|
|
if (RegQueryValueEx(hkey,
|
|
SZ_SYSTEMROOT,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) Buffer2,
|
|
&Count) == ERROR_SUCCESS) {
|
|
|
|
|
|
lstrcpy(lpServiceDetails->szPathName, Buffer2);
|
|
lstrcat(lpServiceDetails->szPathName, &Buffer[12]);
|
|
|
|
}
|
|
else{
|
|
// simply copy raw text into field
|
|
lstrcpy(lpServiceDetails->szPathName, Buffer);
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
}
|
|
else{
|
|
|
|
lstrcpy(lpServiceDetails->szPathName, SvcConfig->lpBinaryPathName);
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(lpServiceDetails->szPathName, GetString( IDS_NOT_AVAILABLE ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Store the name of the order group.
|
|
//
|
|
|
|
lstrcpy(lpServiceDetails->szLoadOrderGroup, SvcConfig->lpLoadOrderGroup);
|
|
|
|
//
|
|
// Traverse the list of dependencies and store them in their
|
|
// appropriate group as a series of strings seperated by
|
|
// NULLs and terminated with a double NULL.
|
|
//
|
|
|
|
lpServiceDetails->szServiceDependencies[0] = UNICODE_NULL;
|
|
lpServiceDetails->szGroupDependencies[0] = UNICODE_NULL;
|
|
|
|
n = 0;
|
|
i = 0;
|
|
|
|
Dependent = SvcConfig->lpDependencies;
|
|
while(( Dependent != NULL ) && ( Dependent[ 0 ] != TEXT( '\0' ))) {
|
|
|
|
|
|
//
|
|
// If the dependent has the prefix SC_GROUP_IDENTIFIER then
|
|
// display it in the group dependency list otherwise display it
|
|
// in the service dependency list.
|
|
//
|
|
|
|
if( Dependent[ 0 ] == SC_GROUP_IDENTIFIER ) {
|
|
|
|
// skip over the SC_GROUP_IDENTIFIER
|
|
Dependent++;
|
|
|
|
// Copy remaining String to the appropriate location
|
|
while( Dependent[0] != TEXT( '\0') ) {
|
|
lpServiceDetails->szGroupDependencies[n++] = Dependent[0];
|
|
Dependent++;
|
|
}
|
|
|
|
// terminate the new string with a NULL
|
|
lpServiceDetails->szGroupDependencies[n++] = UNICODE_NULL;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Copy the String to the appropriate location
|
|
while( Dependent[0] != TEXT( '\0' ) ){
|
|
lpServiceDetails->szServiceDependencies[i++] = Dependent[0];
|
|
Dependent++;
|
|
}
|
|
|
|
// terminate the new string with a NULL
|
|
lpServiceDetails->szServiceDependencies[i++] = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Get the next dependent from the list of NUL terminated
|
|
// strings (the list itself is further NUL terminated).
|
|
//
|
|
|
|
Dependent++;
|
|
|
|
}
|
|
|
|
//
|
|
// Add an extra UNICODE_NULL to each string to double terminate
|
|
//
|
|
|
|
lpServiceDetails->szServiceDependencies[i] = UNICODE_NULL;
|
|
lpServiceDetails->szGroupDependencies[n] = UNICODE_NULL;
|
|
|
|
//
|
|
// Destrot the QUERY_SERVICE_CONFIG structure.
|
|
//
|
|
|
|
Success = DestroySvcConfig( SvcConfig );
|
|
DbgAssert( Success );
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DevicesAndServicesTabProc(
|
|
IN HWND hWnd,
|
|
IN UINT message,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ServiceListDlgProc displays the lists of services or devices that are
|
|
available on the system. Double clicking on one of these displayed services
|
|
or devices causes a second dialog box to be displayed with detailed
|
|
information.
|
|
|
|
Arguments:
|
|
|
|
Standard DLGPROC entry.
|
|
|
|
Return Value:
|
|
|
|
BOOL - Depending on input message and processing options.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL Success;
|
|
|
|
switch( message ) {
|
|
|
|
|
|
case WM_INITDIALOG:
|
|
InitializeDriversServicesTab( hWnd );
|
|
return(FALSE);
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
HSVC hSvc = (HSVC) GetWindowLong(hWnd, GWL_USERDATA);
|
|
|
|
//
|
|
// Free all the memory used to store the ESS structures
|
|
//
|
|
if (hSvc) {
|
|
CloseSvc(hSvc);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_NOTIFY:
|
|
return (NotifyHandler( hWnd, message, wParam, lParam ) );
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch( LOWORD( wParam )) {
|
|
|
|
|
|
case IDC_PUSH_SHOW_SERVICES:
|
|
DisplayList(hWnd, SERVICE_WIN32);
|
|
break;
|
|
|
|
case IDC_PUSH_SHOW_DRIVERS:
|
|
DisplayList(hWnd, SERVICE_DRIVER);
|
|
break;
|
|
|
|
case IDC_PUSH_REFRESH:
|
|
|
|
DisplayList(hWnd, 0);
|
|
break;
|
|
|
|
case IDC_PUSH_PROPERTIES:
|
|
{
|
|
LV_ITEM lvi;
|
|
DISPLAY_SERVICE DisplayService;
|
|
SERVICE_DETAILS ServiceDetails;
|
|
HSVC hSvc = (HSVC) GetWindowLong(hWnd, GWL_USERDATA);
|
|
|
|
|
|
//
|
|
// Get the lParam of the current item, which is the ESS
|
|
//
|
|
lvi.mask = LVIF_PARAM | LVIF_STATE;
|
|
lvi.iItem = (int) GetWindowLong( GetDlgItem( hWnd, IDC_LV_DRIVERS_SERVICES),
|
|
GWL_USERDATA);
|
|
lvi.iSubItem = 0;
|
|
Success = ListView_GetItem( GetDlgItem( hWnd, IDC_LV_DRIVERS_SERVICES ), &lvi);
|
|
|
|
|
|
//
|
|
// Set up a DISPLAY_SERVICE object.
|
|
//
|
|
|
|
DisplayService.hSvc = hSvc;
|
|
DisplayService.Ess = (LPENUM_SERVICE_STATUS) lvi.lParam;
|
|
SetSignature( &DisplayService );
|
|
|
|
|
|
//
|
|
// Get the Service Details
|
|
//
|
|
|
|
Success = GetServiceDetails( &DisplayService, &ServiceDetails );
|
|
|
|
if (Success) {
|
|
|
|
//
|
|
// Display the property sheet
|
|
//
|
|
|
|
DisplayServicePropertySheet( hWnd, &ServiceDetails );
|
|
|
|
}
|
|
else
|
|
{
|
|
TCHAR Buffer[256];
|
|
|
|
//
|
|
// if we failed to get the service details, diplay an
|
|
// error msg
|
|
//
|
|
|
|
wsprintf(Buffer,
|
|
GetString( IDS_SERVICE_NOT_AVAILABLE ),
|
|
((LPENUM_SERVICE_STATUS) lvi.lParam)->lpDisplayName);
|
|
|
|
MessageBox( hWnd, Buffer, GetString( IDS_APPLICATION_FULLNAME ), MB_ICONSTOP | MB_OK );
|
|
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
} // end IDC_PUSH_PROPERTIES
|
|
|
|
default:
|
|
|
|
return ~0;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
DisplayServicePropertySheet(
|
|
HWND hWnd,
|
|
LPSERVICE_DETAILS ServiceDetails
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays the property pages for the current service or driver
|
|
|
|
Arguments:
|
|
|
|
hWnd - Handle of the owner window
|
|
ServiceDetails - pointer to LPSERVICE_DETAILS structure we will display
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if succesful
|
|
|
|
--*/
|
|
|
|
{
|
|
PROPSHEETPAGE psp[2];
|
|
PROPSHEETHEADER psh;
|
|
TCHAR Tab1[256];
|
|
TCHAR Tab2[256];
|
|
|
|
// Get Tab names
|
|
wsprintf (Tab1, (LPTSTR) GetString( IDS_GENERAL_TAB ));
|
|
wsprintf (Tab2, (LPTSTR) GetString( IDS_DEPENDENCIES_TAB ));
|
|
|
|
//Fill out the PROPSHEETPAGE data structure for the General info sheet
|
|
|
|
psp[0].dwSize = sizeof(PROPSHEETPAGE);
|
|
psp[0].dwFlags = PSP_USETITLE;
|
|
psp[0].hInstance = _hModule;
|
|
psp[0].pszTemplate = MAKEINTRESOURCE(IDD_SERVICE_PAGE);
|
|
psp[0].pfnDlgProc = DevicesAndServicesDetailsProc;
|
|
psp[0].pszTitle = Tab1;
|
|
psp[0].lParam = (LONG) ServiceDetails;
|
|
|
|
//Fill out the PROPSHEETPAGE data structure for the dependencies info sheet
|
|
|
|
psp[1].dwSize = sizeof(PROPSHEETPAGE);
|
|
psp[1].dwFlags = PSP_USETITLE;
|
|
psp[1].hInstance = _hModule;
|
|
psp[1].pszTemplate = MAKEINTRESOURCE(IDD_SERVICE_PAGE2);
|
|
psp[1].pfnDlgProc = DevicesAndServicesDetailsProc2;
|
|
psp[1].pszTitle = Tab2;
|
|
psp[1].lParam = (LONG) ServiceDetails;
|
|
|
|
//Fill out the PROPSHEETHEADER
|
|
|
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
|
psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_PROPTITLE;
|
|
psh.hwndParent = hWnd;
|
|
psh.hInstance = _hModule;
|
|
psh.pszIcon = MAKEINTRESOURCE(IDI_WINMSD);
|
|
psh.pszCaption = ServiceDetails->szDisplayName;
|
|
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
|
|
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
|
|
|
|
//And finally display the dialog with the two property sheets.
|
|
|
|
return PropertySheet(&psh);
|
|
|
|
|
|
}
|
|
BOOL
|
|
BuildServicesReport(
|
|
IN HWND hWnd,
|
|
IN UINT iDetailLevel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Formats and adds ServicesData to the report buffer.
|
|
|
|
Arguments:
|
|
|
|
hWnd - Main window handle
|
|
iDetailLevel - summary or complete details?
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if report is build successfully, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
AddLineToReport( 2, RFO_SKIPLINE, NULL, NULL );
|
|
AddLineToReport( 0, RFO_SINGLELINE, (LPTSTR) GetString( IDS_SERVICES_REPORT ), NULL );
|
|
AddLineToReport( 0, RFO_SEPARATOR, NULL, NULL );
|
|
|
|
BuildReports(hWnd, SERVICE_WIN32, iDetailLevel);
|
|
|
|
AddLineToReport( 2, RFO_SKIPLINE, NULL, NULL );
|
|
AddLineToReport( 0, RFO_SINGLELINE, (LPTSTR) GetString( IDS_DRIVERS_REPORT ), NULL );
|
|
AddLineToReport( 0, RFO_SEPARATOR, NULL, NULL );
|
|
|
|
BuildReports(hWnd, SERVICE_DRIVER, iDetailLevel);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
BuildReports(
|
|
IN HWND hWnd,
|
|
DWORD ServiceType,
|
|
IN UINT iDetailLevel
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds lines to report based on SERVICE_TYPE
|
|
|
|
Arguments:
|
|
|
|
hWnd - Main window handle
|
|
ServiceType - Either SERVICE_DRIVER or SERVICE_WIN32
|
|
iDetailLevel - summary or complete details?
|
|
|
|
Return Value:
|
|
|
|
|
|
*/
|
|
{
|
|
HSVC hSvc;
|
|
LPENUM_SERVICE_STATUS Ess;
|
|
TCHAR OutputBuffer[MAX_PATH],
|
|
szBuffer[MAX_PATH],
|
|
szBuffer2[MAX_PATH];
|
|
BOOL Success;
|
|
DISPLAY_SERVICE DisplayService;
|
|
SERVICE_DETAILS ServiceDetails;
|
|
LPTSTR Dependent;
|
|
LONG Index;
|
|
|
|
hSvc = OpenSvc( ServiceType );
|
|
|
|
if( hSvc == NULL ) {
|
|
EndDialog( hWnd, 0 );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// For each service/device of the supplied type, add it to the list.
|
|
//
|
|
|
|
while( Ess = QueryNextSvcEss( hSvc ) )
|
|
{
|
|
|
|
//
|
|
// Only add the service to the list if it is currently running
|
|
//
|
|
|
|
if ((iDetailLevel == IDC_SUMMARY_REPORT) &&
|
|
( Ess->ServiceStatus.dwCurrentState != SERVICE_RUNNING ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get the Service Details
|
|
//
|
|
|
|
DisplayService.hSvc = hSvc;
|
|
DisplayService.Ess = Ess;
|
|
SetSignature( &DisplayService );
|
|
|
|
Success = GetServiceDetails( &DisplayService, &ServiceDetails );
|
|
|
|
if (Success)
|
|
{
|
|
|
|
lstrcpy(szBuffer, Ess->lpDisplayName);
|
|
|
|
if (lstrlen(ServiceDetails.szLoadOrderGroup))
|
|
{
|
|
lstrcat( szBuffer, L" (");
|
|
lstrcat( szBuffer, ServiceDetails.szLoadOrderGroup );
|
|
lstrcat( szBuffer, L")");
|
|
}
|
|
|
|
wsprintf(OutputBuffer,L"%-45s %-9s (%s)",
|
|
szBuffer,
|
|
ServiceDetails.szCurrentState,
|
|
ServiceDetails.szStartType
|
|
);
|
|
|
|
AddLineToReport(0,RFO_SINGLELINE,OutputBuffer,NULL);
|
|
|
|
//
|
|
// If we are reporting all details, include the additional info:
|
|
//
|
|
|
|
if ( iDetailLevel == IDC_COMPLETE_REPORT )
|
|
{
|
|
|
|
//add filename if available
|
|
if(lstrcmp(ServiceDetails.szPathName, GetString(IDS_NOT_AVAILABLE)) != 0)
|
|
{
|
|
AddLineToReport(SINGLE_INDENT,RFO_SINGLELINE,ServiceDetails.szPathName,NULL);
|
|
}
|
|
|
|
//add Service Account Name if it exists
|
|
if(lstrlen(ServiceDetails.szStartName) != 0)
|
|
{
|
|
AddLineToReport( SINGLE_INDENT,
|
|
RFO_RPTLINE,
|
|
(LPTSTR) GetString( IDS_SERVICE_ACCOUNT_NAME ),
|
|
ServiceDetails.szStartName );
|
|
}
|
|
|
|
//add the error severity
|
|
AddLineToReport( SINGLE_INDENT,
|
|
RFO_RPTLINE,
|
|
(LPTSTR) GetString( IDS_ERROR_SEVERITY ),
|
|
ServiceDetails.szExitCode );
|
|
|
|
//add the service flags
|
|
lstrcpy( szBuffer, L"");
|
|
|
|
if( ServiceDetails.dwServiceType & SERVICE_KERNEL_DRIVER )
|
|
{
|
|
lstrcat( szBuffer, GetString( IDS_SERVICE_KERNEL_DRIVER ));
|
|
lstrcat( szBuffer, L", " );
|
|
}
|
|
|
|
if( ServiceDetails.dwServiceType & SERVICE_FILE_SYSTEM_DRIVER )
|
|
{
|
|
lstrcat( szBuffer, GetString( IDS_SERVICE_FILE_SYSTEM_DRIVER ));
|
|
lstrcat( szBuffer, L", " );
|
|
}
|
|
|
|
if( ServiceDetails.dwServiceType & SERVICE_WIN32_OWN_PROCESS )
|
|
{
|
|
lstrcat( szBuffer, GetString( IDS_SERVICE_WIN32_OWN_PROCESS ));
|
|
}
|
|
else
|
|
{
|
|
lstrcat( szBuffer, GetString( IDS_SERVICE_WIN32_SHARE_PROCESS ));
|
|
}
|
|
|
|
if( ServiceDetails.dwServiceType & SERVICE_INTERACTIVE_PROCESS )
|
|
{
|
|
lstrcat( szBuffer, L", " );
|
|
lstrcat( szBuffer, GetString( IDS_SERVICE_INTERACTIVE ));
|
|
}
|
|
|
|
AddLineToReport( SINGLE_INDENT,
|
|
RFO_RPTLINE,
|
|
(LPTSTR) GetString( IDS_SERVICE_FLAGS ),
|
|
szBuffer );
|
|
|
|
//add the service dependencies if any
|
|
if(lstrlen(ServiceDetails.szServiceDependencies) != 0)
|
|
{
|
|
|
|
AddLineToReport( SINGLE_INDENT,
|
|
RFO_SINGLELINE,
|
|
(LPTSTR) GetString( IDS_SERVICE_DEPENDENCIES ),
|
|
NULL );
|
|
|
|
Dependent = ServiceDetails.szServiceDependencies;
|
|
while(( Dependent != NULL ) && ( Dependent[ 0 ] != TEXT( '\0' )))
|
|
{
|
|
|
|
AddLineToReport( DOUBLE_INDENT,
|
|
RFO_SINGLELINE,
|
|
Dependent,
|
|
NULL);
|
|
|
|
Dependent += _tcslen( Dependent ) + 1;
|
|
}
|
|
|
|
}
|
|
|
|
//add the group dependencies if any
|
|
if(lstrlen(ServiceDetails.szGroupDependencies) != 0)
|
|
{
|
|
|
|
AddLineToReport( SINGLE_INDENT,
|
|
RFO_SINGLELINE,
|
|
(LPTSTR) GetString( IDS_GROUP_DEPENDENCIES ),
|
|
NULL );
|
|
|
|
Dependent = ServiceDetails.szGroupDependencies;
|
|
while(( Dependent != NULL ) && ( Dependent[ 0 ] != TEXT( '\0' )))
|
|
{
|
|
|
|
AddLineToReport( DOUBLE_INDENT,
|
|
RFO_SINGLELINE,
|
|
Dependent,
|
|
NULL);
|
|
|
|
Dependent += _tcslen( Dependent ) + 1;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CloseSvc(hSvc);
|
|
}
|
|
|
|
BOOL
|
|
DisplayList(
|
|
IN HWND hWnd,
|
|
IN UINT ServiceType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays the appropriate drivers or services in the ListView box
|
|
|
|
Arguments:
|
|
|
|
hWnd - to the main window
|
|
ServiceType - either SERVICE_DRIVER for drivers or SERVICE_WIN32 for services
|
|
this may be 0 to use the last known value for this param.
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if successful
|
|
|
|
--*/
|
|
{
|
|
LV_COLUMN lvc;
|
|
LV_ITEM lvI;
|
|
UINT index = 0;
|
|
TCHAR szBuffer[MAX_PATH];
|
|
RECT rect;
|
|
BOOL Success;
|
|
LPENUM_SERVICE_STATUS Ess;
|
|
|
|
static
|
|
HSVC hSvc;
|
|
|
|
static
|
|
UINT iType;
|
|
|
|
// as long as this is not 0 set iType to ServiceType
|
|
if (ServiceType)
|
|
iType = ServiceType;
|
|
|
|
// make sure we have a valid type
|
|
if ( (iType != SERVICE_DRIVER) && (iType != SERVICE_WIN32) ) {
|
|
iType = SERVICE_WIN32;
|
|
}
|
|
|
|
DbgAssert( ( iType == SERVICE_WIN32 ) || ( iType == SERVICE_DRIVER ));
|
|
|
|
//
|
|
// initialize the list view
|
|
//
|
|
|
|
// first delete any items and columns we might have
|
|
Success = ListView_DeleteAllItems( GetDlgItem( hWnd, IDC_LV_DRIVERS_SERVICES) );
|
|
Success = ListView_DeleteColumn( GetDlgItem( hWnd, IDC_LV_DRIVERS_SERVICES), 1 );
|
|
Success = ListView_DeleteColumn( GetDlgItem( hWnd, IDC_LV_DRIVERS_SERVICES), 0 );
|
|
|
|
|
|
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
|
|
lvc.cx = 250;
|
|
|
|
if (iType == SERVICE_WIN32)
|
|
LoadString(_hModule, IDS_SERVICE, szBuffer, cchSizeof(szBuffer));
|
|
else
|
|
LoadString(_hModule, IDS_DRIVER, szBuffer, cchSizeof(szBuffer));
|
|
|
|
lvc.pszText = szBuffer;
|
|
lvc.fmt = LVCFMT_LEFT;
|
|
ListView_InsertColumn(GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), 0, &lvc);
|
|
|
|
lvc.cx = 40;
|
|
LoadString(_hModule, IDS_STATE, szBuffer, cchSizeof(szBuffer));
|
|
lvc.pszText = szBuffer;
|
|
lvc.fmt = LVCFMT_LEFT;
|
|
ListView_InsertColumn(GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), 1, &lvc);
|
|
|
|
|
|
// Open the service controller for the supplied type of service.
|
|
hSvc = OpenSvc( iType );
|
|
DbgHandleAssert( hSvc ) ;
|
|
|
|
|
|
// If we failed, display an appropriate error message
|
|
if( hSvc == NULL ) {
|
|
|
|
DWORD dwError = GetLastError();
|
|
|
|
wsprintf( szBuffer,
|
|
GetString( IDS_SC_ERROR ),
|
|
dwError,
|
|
_lpszSelectedComputer );
|
|
|
|
// display error in the LV
|
|
lvI.mask = LVIF_TEXT | TVIF_PARAM;
|
|
lvI.iItem = index;
|
|
lvI.iSubItem = 0;
|
|
lvI.pszText= szBuffer;
|
|
lvI.cchTextMax = MAX_PATH;
|
|
lvI.lParam = 0;
|
|
|
|
Success = ListView_InsertItem(GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), &lvI);
|
|
//adjust the column width to make it look good
|
|
Success = ListView_DeleteColumn( GetDlgItem( hWnd, IDC_LV_DRIVERS_SERVICES), 1 );
|
|
GetClientRect( GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), &rect );
|
|
ListView_SetColumnWidth( GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), 0, rect.right);
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// For each service/device of the supplied type, add it to the list.
|
|
//
|
|
|
|
Ess = QueryNextSvcEss( hSvc );
|
|
|
|
while( Ess )
|
|
{
|
|
|
|
DbgAssert( Ess->ServiceStatus.dwServiceType & iType );
|
|
|
|
// Add the service name and its state to the ListView. Store a
|
|
// pointer to the service details in the lParam.
|
|
lvI.mask = LVIF_TEXT | LVIF_PARAM ;
|
|
lvI.iItem = index;
|
|
lvI.iSubItem = 0;
|
|
lvI.pszText= Ess->lpDisplayName;
|
|
lvI.cchTextMax = 128;
|
|
lvI.lParam = (LPARAM) Ess;
|
|
|
|
Success = ListView_InsertItem(GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), &lvI);
|
|
ListView_SetItemText( GetDlgItem( hWnd, IDC_LV_DRIVERS_SERVICES ), index++, 1, LPSTR_TEXTCALLBACK);
|
|
|
|
//
|
|
// Next SErvice entry
|
|
//
|
|
Ess = QueryNextSvcEss( hSvc );
|
|
|
|
}
|
|
|
|
//adjust the column width to make it look good
|
|
GetClientRect( GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), &rect );
|
|
ListView_SetColumnWidth( GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES), 1, rect.right - 250);
|
|
|
|
|
|
//
|
|
// Set focus to first item in the list
|
|
//
|
|
|
|
ListView_SetItemState(GetDlgItem(hWnd, IDC_LV_DRIVERS_SERVICES),
|
|
0,
|
|
LVIS_SELECTED | LVIS_FOCUSED,
|
|
LVIS_SELECTED | LVIS_FOCUSED
|
|
);
|
|
|
|
|
|
//
|
|
// Store the service "handle" in the window long data since
|
|
// we need to free this memory when the window is destroyed
|
|
// see WM_DESTROY.
|
|
//
|
|
|
|
SetWindowLong(hWnd, GWL_USERDATA, (LONG) hSvc);
|
|
|
|
|
|
}
|
|
|
|
LRESULT
|
|
NotifyHandler( HWND hWnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles WM_NOTIFY messages
|
|
|
|
Arguments:
|
|
|
|
Standard DLGPROC entry.
|
|
|
|
Return Value:
|
|
|
|
LRESULT - Depending on input message and processing options.
|
|
|
|
--*/
|
|
|
|
{
|
|
LV_DISPINFO *pLvdi = (LV_DISPINFO *)lParam;
|
|
NM_LISTVIEW *pNm = (NM_LISTVIEW *)lParam;
|
|
LPENUM_SERVICE_STATUS Ess = (LPENUM_SERVICE_STATUS)(pLvdi->item.lParam);
|
|
|
|
TCHAR szBuffer[25];
|
|
|
|
if (wParam != IDC_LV_DRIVERS_SERVICES)
|
|
return 0L;
|
|
|
|
switch(pLvdi->hdr.code)
|
|
{
|
|
case LVN_GETDISPINFO:
|
|
|
|
//
|
|
// Only look for the data if Ess is valid
|
|
//
|
|
|
|
if( Ess ){
|
|
|
|
switch (pLvdi->item.iSubItem)
|
|
{
|
|
|
|
case 1:
|
|
|
|
wsprintf(
|
|
szBuffer,
|
|
L"%s",
|
|
GetString(
|
|
GetStringId(
|
|
StringTable,
|
|
StringTableCount,
|
|
ServiceCurrentState,
|
|
Ess->ServiceStatus.dwCurrentState
|
|
)
|
|
)
|
|
);
|
|
|
|
pLvdi->item.pszText = szBuffer;
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LVN_COLUMNCLICK:
|
|
|
|
ListView_SortItems( pNm->hdr.hwndFrom,
|
|
ListViewCompareProc,
|
|
(LPARAM)(pNm->iSubItem));
|
|
|
|
ListView_SetItemState(pNm->hdr.hwndFrom,
|
|
0,
|
|
LVIS_SELECTED | LVIS_FOCUSED,
|
|
LVIS_SELECTED | LVIS_FOCUSED
|
|
);
|
|
break;
|
|
|
|
case LVN_ITEMCHANGED:
|
|
|
|
//
|
|
// Store the index to the current item in the GWL_USERDATA of the
|
|
// ListView window.
|
|
//
|
|
|
|
if(pNm->uNewState & LVIS_FOCUSED){
|
|
|
|
SetWindowLong(pNm->hdr.hwndFrom, GWL_USERDATA, (LONG) pNm->iItem);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NM_DBLCLK:
|
|
{
|
|
|
|
// pretend we have clicked the Property button
|
|
|
|
PostMessage(
|
|
GetParent(hWnd),
|
|
WM_COMMAND,
|
|
MAKEWPARAM( IDC_PUSH_PROPERTIES, BN_CLICKED ),
|
|
0
|
|
);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
UINT
|
|
CALLBACK
|
|
ListViewCompareProc(LPARAM lParam1,
|
|
LPARAM lParam2,
|
|
LPARAM lParamSort
|
|
)
|
|
{
|
|
LPENUM_SERVICE_STATUS Ess1 = (LPENUM_SERVICE_STATUS) lParam1;
|
|
LPENUM_SERVICE_STATUS Ess2 = (LPENUM_SERVICE_STATUS) lParam2;
|
|
LPWSTR lpStr1, lpStr2;
|
|
int iResult = 0;
|
|
|
|
if (Ess1 && Ess2)
|
|
{
|
|
switch( lParamSort)
|
|
{
|
|
case 0: // Sort by name.
|
|
lpStr1 = Ess1->lpDisplayName;
|
|
lpStr2 = Ess2->lpDisplayName;
|
|
iResult = lstrcmpi(lpStr1, lpStr2);
|
|
break;
|
|
|
|
case 1: // Sort by status. Yes, this is backwards but sorts the way I want.
|
|
iResult = Ess2->ServiceStatus.dwCurrentState - Ess1->ServiceStatus.dwCurrentState;
|
|
break;
|
|
|
|
default:
|
|
iResult = 0;
|
|
break;
|
|
}
|
|
}
|
|
return(iResult);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
InitializeDriversServicesTab(
|
|
HWND hWnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds the appropriate controls to the version tab control and
|
|
initializes any needed structures.
|
|
|
|
Arguments:
|
|
|
|
hWnd - to the main window
|
|
|
|
Return Value:
|
|
|
|
BOOL - TRUE if successful
|
|
|
|
--*/
|
|
{
|
|
HCURSOR hSaveCursor;
|
|
DLGHDR *pHdr = (DLGHDR *) GetWindowLong(
|
|
GetParent(hWnd), GWL_USERDATA);
|
|
|
|
//
|
|
// Set the pointer to an hourglass
|
|
//
|
|
|
|
hSaveCursor = SetCursor ( LoadCursor ( NULL, IDC_WAIT ) ) ;
|
|
DbgHandleAssert( hSaveCursor ) ;
|
|
|
|
//
|
|
// set state of global buttons
|
|
//
|
|
EnableControl( GetParent(hWnd),
|
|
IDC_PUSH_PROPERTIES,
|
|
TRUE);
|
|
|
|
EnableControl( GetParent(hWnd),
|
|
IDC_PUSH_REFRESH,
|
|
TRUE);
|
|
|
|
//
|
|
// Size and position the child dialog
|
|
//
|
|
SetWindowPos(hWnd, HWND_TOP,
|
|
pHdr->rcDisplay.left,
|
|
pHdr->rcDisplay.top,
|
|
pHdr->rcDisplay.right - pHdr->rcDisplay.left,
|
|
pHdr->rcDisplay.bottom - pHdr->rcDisplay.top,
|
|
SWP_SHOWWINDOW);
|
|
|
|
|
|
//
|
|
// Set the extended style to get full row selection
|
|
//
|
|
SendDlgItemMessage(hWnd, IDC_LV_DRIVERS_SERVICES, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
|
|
|
|
|
|
//
|
|
// Initialize the selection buttons
|
|
//
|
|
SendDlgItemMessage( hWnd,
|
|
IDC_PUSH_SHOW_SERVICES,
|
|
BM_SETCHECK,
|
|
BST_CHECKED,
|
|
0
|
|
);
|
|
|
|
|
|
|
|
UpdateWindow( hWnd );
|
|
|
|
//
|
|
// Fill out the fields initially with services
|
|
//
|
|
{
|
|
DisplayList(hWnd, SERVICE_WIN32);
|
|
}
|
|
|
|
SetCursor ( hSaveCursor ) ;
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|