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.
420 lines
9.5 KiB
420 lines
9.5 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srventry.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the main entry for services controlled by services.exe.
|
|
It also contains general startup and terminate routines.
|
|
|
|
Author:
|
|
|
|
Paula Tomlinson (paulat) 6-8-1995
|
|
|
|
Environment:
|
|
|
|
User-mode only.
|
|
|
|
Revision History:
|
|
|
|
8-June-1995 paulat
|
|
|
|
Creation and initial implementation.
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// includes
|
|
//
|
|
|
|
#include <precomp.h>
|
|
#include <svcs.h>
|
|
|
|
|
|
#define PLUGPLAY_PARAMETERS TEXT("System\\CurrentControlSet\\Services\\PlugPlay\\Parameters")
|
|
#define PLUGPLAY_PARAM_INIT TEXT("DoInitDetection")
|
|
|
|
|
|
//
|
|
// private prototypes
|
|
//
|
|
|
|
VOID
|
|
PnPControlHandler(
|
|
IN DWORD dwOpcode
|
|
);
|
|
|
|
VOID PnPServiceStatusUpdate(
|
|
SERVICE_STATUS_HANDLE hSvcHandle,
|
|
DWORD dwState,
|
|
DWORD dwCheckPoint,
|
|
DWORD dwExitCode
|
|
);
|
|
|
|
|
|
//
|
|
// global data
|
|
//
|
|
|
|
PSVCS_GLOBAL_DATA PnPGlobalData = NULL;
|
|
HANDLE PnPGlobalSvcRefHandle = NULL;
|
|
HANDLE hTerminateEvent = NULL;
|
|
WCHAR LocalComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
|
DWORD CurrentServiceState = 0;
|
|
SERVICE_STATUS_HANDLE hSvcHandle = 0;
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SVCS_ENTRY_POINT(
|
|
DWORD argc,
|
|
LPWSTR argv[],
|
|
PSVCS_GLOBAL_DATA SvcsGlobalData,
|
|
HANDLE SvcRefHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the main routine for the User-mode Plug-and-Play Service. It
|
|
registers itself as an RPC server and notifies the Service Controller
|
|
of the PNP service control entry point.
|
|
|
|
Arguments:
|
|
|
|
Command-line arguments.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
LONG Status; // NTSTATUS
|
|
DWORD Length;
|
|
HANDLE hThread = NULL;
|
|
DWORD ThreadID;
|
|
BOOL bInit = TRUE;
|
|
HKEY hKey = NULL;
|
|
|
|
|
|
UNREFERENCED_PARAMETER(argc);
|
|
UNREFERENCED_PARAMETER(argv);
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// Initialization
|
|
//-----------------------------------------------------------
|
|
|
|
//
|
|
// Save the global data and service reference handle in global variables
|
|
//
|
|
PnPGlobalSvcRefHandle = SvcRefHandle;
|
|
PnPGlobalData = SvcsGlobalData;
|
|
|
|
//
|
|
// Save the local computer name
|
|
//
|
|
Length = MAX_COMPUTERNAME_LENGTH;
|
|
GetComputerNameW(LocalComputerName, &Length);
|
|
|
|
|
|
if ((hSvcHandle = RegisterServiceCtrlHandler(
|
|
L"PlugPlay", PnPControlHandler)) == (SERVICE_STATUS_HANDLE)NULL) {
|
|
|
|
OutputDebugString(TEXT("UMPNPMGR: RegisterServiceCtrlHandler failed\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Notify Service Controller that we're alive
|
|
//
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_START_PENDING, 1, 0);
|
|
|
|
//
|
|
// Create an event which is used by the service control handler to notify
|
|
// the Browser service that it is time to terminate.
|
|
//
|
|
if ((hTerminateEvent = CreateEvent(
|
|
NULL, // security attributes
|
|
TRUE, // Event must be manually reset
|
|
FALSE, // Initial state is non-signalled
|
|
NULL // Event is not named
|
|
)) == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Notify Service Controller that we're alive
|
|
//
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_START_PENDING, 2, 0);
|
|
|
|
// init pnp. init the critical section or mutex, whatever
|
|
// RtlInitializeResource
|
|
|
|
//
|
|
// Notify Service Controller that we're alive
|
|
//
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_START_PENDING, 3, 0);
|
|
|
|
// Check for dependent services? (brmain.c,bowqueue.c)
|
|
// Create worker thread, PnPWorkerThread
|
|
|
|
//
|
|
// Notify Service Controller that we're alive
|
|
//
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_START_PENDING, 4, 0);
|
|
|
|
//
|
|
// Initialize the PNP service to recieve RPC requests
|
|
//
|
|
// NOTE: Now all RPC servers in services.exe share the same pipe name.
|
|
// However, in order to support communication with version 1.0 of WinNt,
|
|
// it is necessary for the Client Pipe name to remain the same as
|
|
// it was in version 1.0. Mapping to the new name is performed in
|
|
// the Named Pipe File System code.
|
|
//
|
|
if ((Status = PnPGlobalData->StartRpcServer(
|
|
PnPGlobalData->SvcsRpcPipeName,
|
|
pnp_ServerIfHandle)) != NO_ERROR) {
|
|
|
|
OutputDebugString(TEXT("UMPNPMGR: StartRpcServer Failed\n"));
|
|
return;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------
|
|
// Initialize pnp manager
|
|
//----------------------------------------------------------
|
|
|
|
#if 0
|
|
//
|
|
// check if startup initialization is disabled in registry
|
|
//
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, PLUGPLAY_PARAMETERS, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
ULONG ulSize = sizeof(DWORD);
|
|
|
|
if (RegQueryValueEx(hKey, PLUGPLAY_PARAM_INIT, NULL, NULL,
|
|
(LPBYTE)&bInit, &ulSize) != ERROR_SUCCESS) {
|
|
bInit = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
#endif
|
|
|
|
|
|
if (bInit) {
|
|
|
|
hThread = CreateThread(
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)InitializePnPManager,
|
|
NULL,
|
|
0,
|
|
&ThreadID);
|
|
|
|
if (hThread != NULL) {
|
|
CloseHandle(hThread);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (!InitializePnPManager()) {
|
|
OutputDebugString(TEXT("UMPNPMGR: Failed to initialize\n"));
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Notify Service Controller that we're now running
|
|
//
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_RUNNING, 0, 0);
|
|
|
|
// call the worker thread, which loops, waiting for events (work
|
|
// requests in addition to the termination event)
|
|
|
|
|
|
//----------------------------------------------------------
|
|
// Wait for Termination
|
|
//----------------------------------------------------------
|
|
|
|
WaitForSingleObject(
|
|
hTerminateEvent,
|
|
INFINITE);
|
|
|
|
|
|
//----------------------------------------------------------
|
|
// Cleanup
|
|
//----------------------------------------------------------
|
|
|
|
//
|
|
// Stop the RPC server (if we got this far, it must be started (?)
|
|
//
|
|
PnPGlobalData->StopRpcServer(pnp_ServerIfHandle);
|
|
|
|
// Stop worker thread
|
|
// delete resource, critical section, etc
|
|
|
|
CloseHandle(hTerminateEvent);
|
|
|
|
//
|
|
// Notify Service Controller that we've now stopped
|
|
//
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_STOPPED, 0, 0);
|
|
|
|
//
|
|
// We should actually return here so that the DLL gets unloaded.
|
|
// However, RPC has a problem in that it might still call our
|
|
// context rundown routine even though we unregistered our interface.
|
|
// So we exit thread instead. This keeps our Dll loaded.
|
|
//
|
|
//ExitThread(0);
|
|
|
|
return;
|
|
|
|
} // SVCS_ENTRY_POINT
|
|
|
|
|
|
|
|
|
|
VOID
|
|
PnPControlHandler(
|
|
IN DWORD dwOpcode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the service control handler of the Plug-and-Play service.
|
|
|
|
Arguments:
|
|
|
|
Opcode - Supplies a value which specifies the action for the Browser
|
|
service to perform.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
switch (dwOpcode) {
|
|
|
|
case SERVICE_CONTROL_STOP:
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
|
//
|
|
// if we aren't already in the middle of a stop, then
|
|
// stop the PNP service now
|
|
//
|
|
if (CurrentServiceState != SERVICE_STOP ||
|
|
CurrentServiceState != SERVICE_STOP_PENDING) {
|
|
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_STOP_PENDING, 1, 0);
|
|
|
|
//
|
|
// do cleanup
|
|
//
|
|
|
|
//
|
|
// set the termination event so the service main entry pt
|
|
// (SVC_ENTRY_POINT) can return
|
|
//
|
|
SetEvent(hTerminateEvent);
|
|
}
|
|
|
|
PnPServiceStatusUpdate(hSvcHandle, SERVICE_STOP_PENDING, 2, 0);
|
|
break;
|
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
//
|
|
// Request to immediately notify Service Controller of
|
|
// current status
|
|
//
|
|
PnPServiceStatusUpdate(hSvcHandle, CurrentServiceState, 0, 0);
|
|
break;
|
|
|
|
case SERVICE_CONTROL_PAUSE:
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
PnPServiceStatusUpdate(hSvcHandle, CurrentServiceState, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
|
|
} // PnPControlHandler
|
|
|
|
|
|
|
|
|
|
VOID PnPServiceStatusUpdate(
|
|
SERVICE_STATUS_HANDLE hSvcHandle,
|
|
DWORD dwState,
|
|
DWORD dwCheckPoint,
|
|
DWORD dwExitCode
|
|
)
|
|
|
|
{
|
|
SERVICE_STATUS SvcStatus;
|
|
BOOL Status;
|
|
|
|
|
|
SvcStatus.dwServiceType = SERVICE_WIN32;
|
|
SvcStatus.dwCurrentState = CurrentServiceState = dwState;
|
|
SvcStatus.dwCheckPoint = dwCheckPoint;
|
|
|
|
|
|
if (dwState == SERVICE_RUNNING) {
|
|
SvcStatus.dwControlsAccepted =
|
|
SERVICE_ACCEPT_STOP |
|
|
SERVICE_ACCEPT_PAUSE_CONTINUE |
|
|
SERVICE_ACCEPT_SHUTDOWN;
|
|
}
|
|
else {
|
|
SvcStatus.dwControlsAccepted = 0;
|
|
}
|
|
|
|
|
|
if (dwState == SERVICE_START_PENDING |
|
|
dwState == SERVICE_STOP_PENDING |
|
|
dwState == SERVICE_PAUSE_PENDING |
|
|
dwState == SERVICE_STOP_PENDING) {
|
|
|
|
SvcStatus.dwWaitHint = 45000; // 45 seconds
|
|
}
|
|
else {
|
|
SvcStatus.dwWaitHint = 0;
|
|
}
|
|
|
|
|
|
if (dwExitCode != 0) {
|
|
SvcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
|
|
SvcStatus.dwServiceSpecificExitCode = dwExitCode;
|
|
}
|
|
else {
|
|
SvcStatus.dwWin32ExitCode = NO_ERROR;
|
|
SvcStatus.dwServiceSpecificExitCode = 0;
|
|
}
|
|
|
|
Status = SetServiceStatus(hSvcHandle, &SvcStatus);
|
|
|
|
return;
|
|
|
|
} // PnPServiceStatusUpdate
|
|
|