| Main | Next | Site Index | Download | Disclaimer | Privacy |


 

 

 

 

 

 

WINDOWS SERVICES & PROCESS: A SUPPLEMENTARY NOTE

 

 

 

 

 

 

 

Windows Service: Functions used in program examples of Windows Services part 1 and Windows Services part 2 wherever applicable. To learn about function you can jump to C & C++ functions tutorials.

 

 

The Page Index

  1. ServiceMain()

  2. StartServiceCtrlDispatcher()

  3. RegisterServiceCtrlHandler()

  4. RegisterServiceCtrlHandlerEx()

  5. SetServiceStatus()

  6. Handler()

  7. HandlerEx()

  8. StartService()

  9. CreateProcess()

 

 

ServiceMain()

 

Item

Description

Function

ServiceMain().

Use

As the starting point for a service. The LPSERVICE_MAIN_FUNCTION type defines a pointer to this callback function. ServiceMain() is a placeholder for an application-defined function name.

Prototype

VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv);

Parameters

dwArgc - [in] Number of arguments in the lpszArgv array.

lpszArgv - [in] Pointer to an array of pointers to null-terminated argument strings. The first argument in the array is the name of the service, and subsequent arguments are any strings passed to the service by the process that called the StartService() function to start the service.

Return value

This function does not return a value.

Include file

<windows.h>

Remark

See below.

 

Table 1.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Some Remarks

 

A service program can start one or more services. A service process has a SERVICE_TABLE_ENTRY structure for each service that it can start. The structure specifies the service name and a pointer to the ServiceMain() function for that service. When the service control manager receives a request to start a service, it starts the service process (if it is not already running). The main thread of the service process calls the StartServiceCtrlDispatcher() function with a pointer to an array of SERVICE_TABLE_ENTRY structures. Then the service control manager sends a start request to the service control dispatcher for this service process. The service control dispatcher creates a new thread to execute the ServiceMain() function of the service being started. The ServiceMain() function should immediately call the RegisterServiceCtrlHandlerEx() function to specify a HandlerEx() function to handle control requests. Next, it should call the SetServiceStatus() function to send status information to the service control manager. After these calls, the function should complete the initialization of the service. Do not attempt to start another service in the ServiceMain() function. The Service Control Manager (SCM) waits until the service reports a status of SERVICE_RUNNING. It is recommended that the service reports this status as quickly as possible, as other components in the system that require interaction with SCM will be blocked during this time. Some functions may require interaction with the SCM either directly or indirectly. The SCM locks the service control database during initialization, so if a service attempts to call StartService() during initialization, the call will block. When the service reports to the SCM that it has successfully started, it can call StartService(). If the service requires another service to be running, the service should set the required dependencies. Furthermore, you should not call any system functions during service initialization. The service code should call system functions only after it reports a status of SERVICE_RUNNING. The ServiceMain() function should call the RegisterWaitForSingleObject() function on an event and exit. This will terminate the thread that is running the ServiceMain() function, but will not terminate the service. The service control handler should signal this event when the service stops. A thread from the thread pool will execute the code that performs the cleanup and calls SetServiceStatus() with SERVICE_STOPPED.  Windows NT:  On earlier platforms where RegisterWaitForSingleObject() is not available, it is common practice for the thread executing the ServiceMain() function to wait on an event that is signaled by the service control handler when the service stops. When the event is signaled, ServiceMainitself() performs any cleanup and calls SetServiceStatus() with SERVICE_STOPPED.

 

StartServiceCtrlDispatcher()

 

Item

Description

Function

StartServiceCtrlDispatcher().

Use

Connects the main thread of a service process to the service control manager, which causes the thread to be the service control dispatcher thread for the calling process.

Prototype

BOOL StartServiceCtrlDispatcher( const LPSERVICE_TABLE_ENTRY  lpServiceTable);

Parameters

lpServiceTable - [in] Pointer to an array of SERVICE_TABLE_ENTRY structures containing one entry for each service that can execute in the calling process. The members of the last entry in the table must have NULL values to designate the end of the table.

Return value

See below.

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. More remarks below.

 

Table 2.

 

Return Values

 

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError(). The following error code can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

 

Return code

Description

ERROR_FAILED_SERVICE_CONTROLLER_CONNECT

Typically, this error indicates that the program is being run as a console application rather than as a service.

If the program will be run as a console application for debugging purposes, structure it such that service-specific code is not called when this error is returned.

ERROR_INVALID_DATA

The specified dispatch table contains entries that are not in the proper format.

ERROR_SERVICE_ALREADY_RUNNING

The process has already called StartServiceCtrlDispatcher(). Each process can call StartServiceCtrlDispatcher() only one time. For Windows NT:  This value is not supported.

 

Table 3

 

Some Remarks

 

When the service control manager starts a service process, it waits for the process to call the StartServiceCtrlDispatcher() function. The main thread of a service process should make this call as soon as possible after it starts up. If StartServiceCtrlDispatcher() succeeds, it connects the calling thread to the service control manager and does not return until all running services in the process have terminated. The service control manager uses this connection to send control and service start requests to the main thread of the service process. The main thread acts as a dispatcher by invoking the appropriate HandlerEx() function to handle control requests, or by creating a new thread to execute the appropriate ServiceMain() function when a new service is started. The lpServiceTable parameter contains an entry for each service that can run in the calling process. Each entry specifies the ServiceMain() function for that service. For SERVICE_WIN32_SHARE_PROCESS services, each entry must contain the name of a service. This name is the service name that was specified by the CreateService() function when the service was installed. For SERVICE_WIN32_OWN_PROCESS services, the service name in the table entry is ignored. If a service runs in its own process, the main thread of the service process should immediately call StartServiceCtrlDispatcher(). All initialization tasks are done in the service's ServiceMain() function when the service is started. If multiple services share a process and some common process-wide initialization needs to be done before any ServiceMain() function is called, the main thread can do the work before calling StartServiceCtrlDispatcher(), as long as it takes less than 30 seconds. Otherwise, another thread must be created to do the process-wide initialization, while the main thread calls StartServiceCtrlDispatcher() and becomes the service control dispatcher. Any service-specific initialization should still be done in the individual service main functions.

 

RegisterServiceCtrlHandler()

 

Item

Description

Function

RegisterServiceCtrlHandler().

Use

A service calls the RegisterServiceCtrlHandler() function to register a function to handle its service control requests. This function has been superseded by the RegisterServiceCtrlHandlerEx() function. A service can use either function, but the new function supports user-defined context data, and the new handler function supports additional extended control codes.

Prototype

SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler( LPCTSTR lpServiceName, LPHANDLER_FUNCTION   lpHandlerProc);

Parameters

lpServiceName - [in] Pointer to a null-terminated string that specifies the name of the service run by the calling thread. This is the service name that the service control program specified in the CreateService() function when creating the service. If the service type is SERVICE_WIN32_OWN_PROCESS, the function does not verify that the specified name is valid, because there is only one registered service in the process.

lpHandlerProc - [in] Pointer to the handler function to be registered.

Return value

See below.

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. The ServiceMain() function of a new service should immediately call the RegisterServiceCtrlHandler() function to register a control handler function with the control dispatcher. This enables the control dispatcher to invoke the specified function when it receives control requests for this service. The threads of the calling process can use the service status handle returned by this function to identify the service in subsequent calls to the SetServiceStatus() function.

The RegisterServiceCtrlHandler() function must be called before the first SetServiceStatus() call because RegisterServiceCtrlHandler() returns a service status handle for the caller to use so that no other service can inadvertently set this service status. In addition, the control handler must be in place to receive control requests by the time the service specifies the controls it accepts through the SetServiceStatus() function. When the control handler function is invoked with a control request, it must call SetServiceStatus() to notify the service control manager of its current status, regardless of whether the status of the service has changed. The service status handle does not have to be closed.

 

Table 4.

 

Return Values

 

If the function succeeds, the return value is a service status handle. If the function fails, the return value is zero. To get extended error information, call GetLastError(). The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

 

Return code

Description

ERROR_INVALID_NAME

The specified service name is invalid.

ERROR_SERVICE_DOES_NOT_EXIST

The specified service does not exist.

 

Table 5

 

RegisterServiceCtrlHandlerEx()

 

Item

Description

Function

StartServiceCtrlDispatcherEx().

Use

A service calls the RegisterServiceCtrlHandlerEx() function to register a function to handle its service control requests. This function supersedes the RegisterServiceCtrlHandler() function. A service can use either function, but the new function supports user-defined context data, and the new handler function supports additional extended control codes.

Prototype

SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerEx( LPCTSTR lpServiceName,

  LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID  lpContext);

Parameters

lpServiceName - [in] Pointer to a null-terminated string that specifies the name of the service run by the calling thread. This is the service name that the service control program specified in the CreateService() function when creating the service.

lpHandlerProc - [in] Pointer to the handler function to be registered.

lpContext - [in] User-defined data. This parameter, which is passed to the handler function, can help identify the service when multiple services share a process.

Return value

If the function succeeds, the return value is a service status handle. If the function fails, the return value is zero. To get extended error information, call GetLastError(). The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

  1. ERROR_INVALID_NAME - The specified service name is invalid.

  2. ERROR_SERVICE_DOES_NOT_EXIST - The specified service does not exist.

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. The ServiceMain() function of a new service should immediately call the RegisterServiceCtrlHandlerEx() function to register a control handler function with the control dispatcher. This enables the control dispatcher to invoke the specified function when it receives control requests for this service. The threads of the calling process can use the service status handle returned by this function to identify the service in subsequent calls to the SetServiceStatus() function. The RegisterServiceCtrlHandlerEx() function must be called before the first SetServiceStatus() call because RegisterServiceCtrlHandlerEx() returns a service status handle for the caller to use so that no other service can inadvertently set this service status. In addition, the control handler must be in place to receive control requests by the time the service specifies the controls it accepts through the SetServiceStatus() function. When the control handler function is invoked with a control request, it must call SetServiceStatus() to notify the service control manager of its current status, regardless of whether the status of the service has changed. The service status handle does not have to be closed.

 

Table 6.

 

SetServiceStatus()

 

Item

Description

Function

SetServiceStatus().

Use

Updates the service control manager's status information for the calling service.

Prototype

BOOL SetServiceStatus( SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus);

Parameters

hServiceStatus - [in] Handle to the status information structure for the current service. This handle is returned by the RegisterServiceCtrlHandlerEx() function.

lpServiceStatus - [in] Pointer to the SERVICE_STATUS structure that contains the latest status information for the calling service.

Return value

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError(). The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

  1. ERROR_INVALID_DATA - The specified service status structure is invalid.

  2. ERROR_INVALID_HANDLE - The specified handle is invalid.

Include file

<windows.h>

Remark

See below.

 

Table 7.

 

Some Remarks

 

A ServiceMain() function first calls the RegisterServiceCtrlHandlerEx() function to get the service's SERVICE_STATUS_HANDLE. Then it immediately calls the SetServiceStatus() function to notify the service control manager that its status is SERVICE_START_PENDING. During initialization, the service can provide updated status to indicate that it is making progress but it needs more time. A common bug is for the service to have the main thread perform the initialization while a separate thread continues to call SetServiceStatus() to prevent the service control manager from marking it as hung. However, if the main thread hangs, then the service start ends up in an infinite loop because the worker thread continues to report that the main thread is making progress. When a service receives a control request, the service's Handler() function must call SetServiceStatus(), even if the service's status did not change. A service can also use this function at any time and by any thread of the service to notify the service control manager of status changes. Examples of such unsolicited status updates include:

  1. Checkpoint updates that occur when the service is in transition from one state to another.

  2. Fatal error updates that occur when the service must stop due to a recoverable error.

 

A service can call this function only after it has called RegisterServiceCtrlHandlerEx() to get a service status handle. If a service calls SetServiceStatus() with the dwCurrentState member set to SERVICE_STOPPED and the dwWin32ExitCode member set to a nonzero value, the following entry is written into the System event log:

 

   Event ID    = 7023

   Source      = Service Control Manager

   Type        = Error

   Description = <ServiceName> terminated with the following error:

                 <ExitCode>.

 

Handler()

 

Item

Description

Function

Handler().

Use

A Handler function is an application-defined callback function used with the RegisterServiceCtrlHandler() function. A service program uses it as the control handler function of a particular service. The LPHANDLER_FUNCTION type defines a pointer to this function. Handler is a placeholder for the application-defined name. This function has been superseded by the HandlerEx() control handler function used with the RegisterServiceCtrlHandlerEx() function. A service can use either control handler, but the new control handler supports user-defined context data and additional extended control codes.

Prototype

VOID WINAPI Handler(DWORD fdwControl);

Parameters

Se below.

Return value

This function does not return a value.

Include file

<windows.h>

Remark

See below.

 

Table 8.

 

Parameters

 

fdwControl - [in] Control code. This parameter can be one of the following values.

 

Control code

Meaning

SERVICE_CONTROL_CONTINUE

Notifies a paused service that it should resume.

SERVICE_CONTROL_INTERROGATE

Notifies a service that it should report its current status information to the service control manager.

SERVICE_CONTROL_NETBINDADD

Notifies a network service that there is a new component for binding. The service should bind to the new component. However, this control code has been deprecated; use PnP functionality instead. For Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDDISABLE

Notifies a network service that one of its bindings has been disabled. The service should reread its binding information and remove the binding. However, this control code has been deprecated; use PnP functionality instead. For Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDENABLE

Notifies a network service that a disabled binding has been enabled. The service should reread its binding information and add the new binding. However, this control code has been deprecated; use PnP functionality instead. For Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDREMOVE

Notifies a network service that a component for binding has been removed. The service should reread its binding information and unbind from the removed component. However, this control code has been deprecated; use PnP functionality instead. For Windows NT:  This value is not supported.

SERVICE_CONTROL_PARAMCHANGE

Notifies a service that its startup parameters have changed. The service should reread its startup parameters. For Windows NT:  This value is not supported.

SERVICE_CONTROL_PAUSE

Notifies a service that it should pause.

SERVICE_CONTROL_SHUTDOWN

Notifies a service that the system is shutting down so the service can perform cleanup tasks.

For more information, see Remarks section.

SERVICE_CONTROL_STOP

Notifies a service that it should stop.

 

Table 9

 

This parameter can also be a user-defined control code, as described in the following table.

 

Control code

Meaning

Range 128 to 255.

The service defines the action associated with the control code.

 

Table 10

 

Some Remarks

 

When a service is started, its ServiceMain() function should immediately call the RegisterServiceCtrlHandler() function to specify a Handler() function to process control requests. The control dispatcher in the main thread of a service process invokes the control handler function for the specified service whenever it receives a control request from the service control manager. After processing the control request, the control handler must call the SetServiceStatus() function to report its current status to the service control manager. When the service control manager sends a control code to a service, it waits for the handler function to return before sending additional control codes to other services. If the handler function does not return promptly, it may block other services from receiving control codes.

The SERVICE_CONTROL_SHUTDOWN control code should only be processed by services that must absolutely clean up during shutdown, because there is a limited time (about 20 seconds) available for service shutdown. After this time expires, system shutdown proceeds regardless of whether service shutdown is complete. Note that if the system is left in the shutdown state (not restarted or powered down), the service continues to run.

If the service needs more time to clean up, it should send STOP_PENDING status messages, along with a wait hint, so the service controller knows how long to wait before reporting to the system that service shutdown is complete. However, to prevent a service from stopping shutdown, there is a limit to how long the service controller will wait. To change this time limit, modify the WaitToKillServiceTimeout() value in the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

HandlerEx()

 

Item

Description

Function

HandlerEx().

Use

Is an application-defined callback function used with the RegisterServiceCtrlHandlerEx() function. A service program can use it as the control handler function of a particular service. The LPHANDLER_FUNCTION_EX type defines a pointer to this function. HandlerEx() is a placeholder for the application-defined name. This function supersedes the Handler() control handler function used with the RegisterServiceCtrlHandler() function. A service can use either control handler, but the new control handler supports user-defined context data and additional extended control codes.

Prototype

DWORD WINAPI HandlerEx( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext);

Parameters

See below.

Return value

The return value for this function depends on the control code received. The rules for this return value are as follows.

  1. If your service does not handle the control, return ERROR_CALL_NOT_IMPLEMENTED.

  2. If your service handles SERVICE_CONTROL_DEVICEEVENT, return NO_ERROR to grant the request and an error code to deny the request.

  3. If your service handles SERVICE_CONTROL_HARDWAREPROFILECHANGE, return NO_ERROR to grant the request and an error code to deny the request.

  4. If your service handles SERVICE_CONTROL_POWEREVENT, return NO_ERROR to grant the request and an error code to deny the request.

  5. For all other control codes your service handles, return NO_ERROR.

Include file

<windows.h>

Remark

See below.

 

Table 11.

 

Parameters

 

dwControl - [in] Control code. This parameter can be one of the following values.

 

Control code

Meaning

SERVICE_CONTROL_CONTINUE

Notifies a paused service that it should resume.

SERVICE_CONTROL_INTERROGATE

Notifies a service to report its current status information to the service control manager.

SERVICE_CONTROL_NETBINDADD

Notifies a network service that there is a new component for binding. The service should bind to the new component. However, this control code has been deprecated; use PnP functionality instead. Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDDISABLE

Notifies a network service that one of its bindings has been disabled. The service should reread its binding information and remove the binding. However, this control code has been deprecated; use PnP functionality instead. Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDENABLE

Notifies a network service that a disabled binding has been enabled. The service should reread its binding information and add the new binding. However, this control code has been deprecated; use PnP functionality instead. Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDREMOVE

Notifies a network service that a component for binding has been removed. The service should reread its binding information and unbind from the removed component. However, this control code has been deprecated; use PnP functionality instead. Windows NT:  This value is not supported.

SERVICE_CONTROL_PARAMCHANGE

Notifies a service that service-specific startup parameters have changed. The service should reread its startup parameters. Windows NT:  This value is not supported.

SERVICE_CONTROL_PAUSE

Notifies a service that it should pause.

SERVICE_CONTROL_SHUTDOWN

Notifies a service that the system is shutting down so the service can perform cleanup tasks. For more information, see Remarks.

SERVICE_CONTROL_STOP

Notifies a service that it should stop.

 

Table 12

 

This parameter can also be one of the following extended control codes. Note that these control codes are not supported by the Handler() function.

 

Control code

Meaning

SERVICE_CONTROL_DEVICEEVENT

Notifies a service of device events. The service must have registered to receive these notifications using the RegisterDeviceNotification() function. For Windows NT:  This value is not supported.

SERVICE_CONTROL_HARDWAREPROFILECHANGE

Notifies a service that the computer's hardware profile has changed. For Windows NT:  This value is not supported.

SERVICE_CONTROL_POWEREVENT

Notifies a service of system power events. For Windows NT:  This value is not supported.

SERVICE_CONTROL_SESSIONCHANGE

Notifies a service of session change events. For Windows 2000/NT:  This value is not supported.

 

Table 13

 

This parameter can also be a user-defined control code, as described in the following table.

 

Control code

Meaning

Range 128 to 255.

The service defines the action associated with the control code.

 

Table 14

 

dwEventType - [in] Type of event that has occurred. This parameter is used if dwControl is SERVICE_CONTROL_DEVICEEVENT, SERVICE_CONTROL_HARDWAREPROFILECHANGE, SERVICE_CONTROL_POWEREVENT, or SERVICE_CONTROL_SESSIONCHANGE. Otherwise, it is zero. If dwControl is SERVICE_CONTROL_DEVICEEVENT, this parameter can be one of the following values:

  1. DBT_DEVICEARRIVAL

  2. DBT_DEVICEREMOVECOMPLETE

  3. DBT_DEVICEQUERYREMOVE

  4. DBT_DEVICEQUERYREMOVEFAILED

  5. DBT_DEVICEREMOVEPENDING

  6. DBT_CUSTOMEVENT

 

If dwControl is SERVICE_CONTROL_HARDWAREPROFILECHANGE, this parameter can be one of the following values:

  1. DBT_CONFIGCHANGED

  2. DBT_QUERYCHANGECONFIG

  3. DBT_CONFIGCHANGECANCELED

 

If dwControl is SERVICE_CONTROL_POWEREVENT, this parameter can be one of the values specified in the wParam parameter of the WM_POWERBROADCAST message. If dwControl is SERVICE_CONTROL_SESSIONCHANGE, this parameter can be one of the values specified in the wParam parameter of the WM_WTSSESSION_CHANGE message.

lpEventData - [in] Additional device information, if required. The format of this data depends on the value of the dwControl and dwEventType parameters. If dwEventType is SERVICE_CONTROL_DEVICEEVENT, this data corresponds to the lParam parameter that applications receive as part of a WM_DEVICECHANGE message. If dwEventType is SERVICE_CONTROL_POWEREVENT, this data corresponds to the lParam parameter that applications receive as part of a WM_POWERBROADCAST message. If dwEventType is SERVICE_CONTROL_SESSIONCHANGE, this parameter is a WTSSESSION_NOTIFICATION structure.

lpContext - [in] User-defined data passed from RegisterServiceCtrlHandlerEx(). When multiple services share a process, the lpContext parameter can help identify the service.

 

Some Remarks

 

When a service is started, its ServiceMain() function should immediately call the RegisterServiceCtrlHandlerEx() function to specify a HandlerEx() function to process control requests. To specify the control codes to be accepted, use the SetServiceStatus() and RegisterDeviceNotification() functions. The control dispatcher in the main thread of a service invokes the control handler function for the specified service whenever it receives a control request from the service control manager. After processing the control request, the control handler must call SetServiceStatus() to report its current status to the service control manager. When the service control manager sends a control code to a service, it waits for the handler function to return before sending additional control codes to other services. If the handler function does not return promptly, it may block other services from receiving control codes. The SERVICE_CONTROL_SHUTDOWN control code should only be processed by services that must absolutely clean up during shutdown, because there is a limited time (about 20 seconds) available for service shutdown. After this time expires, system shutdown proceeds regardless of whether service shutdown is complete. Note that if the system is left in the shutdown state (not restarted or powered down), the service continues to run. If the service needs more time to clean up, it should send STOP_PENDING status messages, along with a wait hint, so the service controller knows how long to wait before reporting to the system that service shutdown is complete. However, to prevent a service from stopping shutdown, there is a limit to how long the service controller will wait. To change this time limit, modify the WaitToKillServiceTimeout value in the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

Be sure to handle Plug and Play device events as quickly as possible; otherwise, the system may become unresponsive. If your event handler is to perform an operation that may block execution (such as I/O), it is best to start another thread to perform the operation asynchronously.

 

StartService()

 

Item

Description

Function

StartService().

Use

Starts a service.

Prototype

BOOL StartService( SC_HANDLE hService, DWORD dwNumServiceArgs, LPCTSTR* lpServiceArgVectors);

Parameters

hService - [in] Handle to the service. This handle is returned by the OpenService() or CreateService() function, and it must have the SERVICE_START access right.

dwNumServiceArgs - [in] Number of strings in the lpServiceArgVectors array. If lpServiceArgVectors is NULL, this parameter can be zero.

lpServiceArgVectors - [in] Pointer to an array of pointers to null-terminated strings to be passed to a service as arguments. Driver services do not receive these arguments. If no arguments are passed to the service, this parameter can be NULL. The service accesses these arguments through its ServiceMain() function. The first argument (argv[0]) is the name of the service by default, followed by the arguments, if any, in the lpServiceArgVectors array.

Return value

See below.

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. More remarks below.

 

Table 15.

 

Return Values

 

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError(). The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

 

Return code

Description

ERROR_ACCESS_DENIED

The handle does not have the SERVICE_START access right.

ERROR_INVALID_HANDLE

The handle is invalid.

ERROR_PATH_NOT_FOUND

The service binary file could not be found.

ERROR_SERVICE_ALREADY_RUNNING

An instance of the service is already running.

ERROR_SERVICE_DATABASE_LOCKED

The database is locked.

ERROR_SERVICE_DEPENDENCY_DELETED

The service depends on a service that does not exist or has been marked for deletion.

ERROR_SERVICE_DEPENDENCY_FAIL

The service depends on another service that has failed to start.

ERROR_SERVICE_DISABLED

The service has been disabled.

ERROR_SERVICE_LOGON_FAILED

The service could not be logged on. This error occurs if the service was started from an account that does not have the "Log on as a service" right.

ERROR_SERVICE_MARKED_FOR_DELETE

The service has been marked for deletion.

ERROR_SERVICE_NO_THREAD

A thread could not be created for the service.

ERROR_SERVICE_REQUEST_TIMEOUT

The process for the service was started, but it did not call StartServiceCtrlDispatcher(), or the thread that called StartServiceCtrlDispatcher() may be blocked in a control handler function.

 

Table 16

 

 

Some Remarks

 

When a driver service is started, the StartService() function does not return until the device driver has finished initializing. When a service is started, the Service Control Manager (SCM) spawns the service process, if necessary. If the specified service shares a process with other services, the required process may already exist. The StartService() function does not wait for the first status update from the new service, because it can take a while.

Instead, it returns when the SCM receives notification from the service control dispatcher that the ServiceMain() thread for this service was created successfully. The SCM sets the following default status values before returning from StartService():

  1. Current state of the service is set to SERVICE_START_PENDING.

  2. Controls accepted is set to none (zero).

  3. The CheckPoint value is set to zero.

  4. The WaitHint time is set to 2 seconds.

 

The calling process can determine if the new service has finished its initialization by calling the QueryServiceStatus() function periodically to query the service's status. A service cannot call StartService() during initialization. The reason is that the SCM locks the service control database during initialization, so a call to StartService() will block. Once the service reports to the SCM that it has successfully started, it can call StartService(). As with ControlService(), StartService() will block for 30 seconds if any service is busy handling a control code. If the busy service still has not returned from its handler function when the timeout expires, StartService() fails with ERROR_SERVICE_REQUEST_TIMEOUT. This is because the SCM processes only one service control notification at a time.

 

CreateProcess()

 

Item

Description

Function

CreateProcess().

Use

Creates a new process and its primary thread. The new process runs the specified executable file in the security context of the calling process. If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation token. To run the new process in the security context of the user represented by the impersonation token, use the CreateProcessAsUser() or CreateProcessWithLogonW() function.

Prototype

BOOL CreateProcess( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);

Parameters

See below.

Return value

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError().

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. Note that Unicode support on Windows Me/98/95 requires Microsoft Layer for Unicode. More remarks below.

 

Table 17.

 

Parameters

 

lpApplicationName - [in] Pointer to a null-terminated string that specifies the module to execute. The specified module can be a Windows-based application. It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.

The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a partial name, the function uses the current drive and current directory to complete the specification. The function will not use the search path. If the file name does not contain an extension, .exe is assumed. Therefore, if the file name extension is .com, this parameter must include the .com extension. The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space-delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

  1. c:\program.exe files\sub dir\program name

  2. c:\program files\sub.exe dir\program name

  3. c:\program files\sub dir\program.exe name

  4. c:\program files\sub dir\program name.exe

 

If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module as well as its arguments.

lpCommandLine - [in, out] Pointer to a null-terminated string that specifies the command line to execute. The maximum length of this string is 32K characters. Windows 2000:  The maximum length of this string is MAX_PATH characters. The Unicode version of this function, CreateProcessW(), will fail if this parameter is a const string. The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line. If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine() to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line. If lpApplicationName is NULL, the first white-space – delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:

 

  1. The directory from which the application loaded.

  2. The current directory for the parent process.

  3. The 32-bit Windows system directory. Use the GetSystemDirectory() function to get the path of this directory. For Windows Me/98/95:  The Windows system directory. Use the GetSystemDirectory() function to get the path of this directory.

  1. The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.

  2. The Windows directory. Use the GetWindowsDirectory() function to get the path of this directory.

  3. The directories that are listed in the PATH environment variable.

 

The system adds a null character to the command line string to separate the file name from the arguments. This divides the original string into two strings for internal processing.

lpProcessAttributes - [in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpProcessAttributes is NULL, the handle cannot be inherited. The lpSecurityDescriptor member of the structure specifies a security descriptor for the new process. If lpProcessAttributes is NULL or lpSecurityDescriptor is NULL, the process gets a default security descriptor. The ACLs in the default security descriptor for a process come from the primary or impersonation token of the creator.

lpThreadAttributes - [in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited. The lpSecurityDescriptor member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is NULL or lpSecurityDescriptor is NULL, the thread gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the creator.

bInheritHandles - [in] If this parameter TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE, the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.

dwCreationFlags - [in] Flags that control the priority class and the creation of the process. This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's threads. If none of the priority class flags is specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASS or BELOW_NORMAL_PRIORITY_CLASS. In this case, the child process receives the default priority class of the calling process.

lpEnvironment - [in] Pointer to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process. An environment block consists of a null-terminated block of null-terminated strings. Each string is in the form: name=value. Because the equal sign is used as a separator, it must not be used in the name of an environment variable. An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT. Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.

lpCurrentDirectory - [in] Pointer to a null-terminated string that specifies the full path to the current directory for the process. The string can also specify a UNC path. If this parameter is NULL, the new process will have the same current drive and directory as the calling process. This feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.

lpStartupInfo - [in] Pointer to a STARTUPINFO structure that specifies the window station, desktop, standard handles, and appearance of the main window for the new process.

lpProcessInformation - [out] Pointer to a PROCESS_INFORMATION structure that receives identification information about the new process. Handles in PROCESS_INFORMATION must be closed with CloseHandle() when they are no longer needed.

 

Some Remarks

 

The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess() function to open a handle to the process. The initial thread in the process is also assigned a thread identifier. It can be specified in the OpenThread() function to open a handle to the thread. The identifier is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in the PROCESS_INFORMATION structure. The calling thread can use the WaitForInputIdle() function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcess() returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle() before trying to find a window associated with the new process. The preferred way to shut down a process is by using the ExitProcess() function, because this function sends notification of approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess(), other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs).

A parent process can directly alter the environment variables of a child process during process creation. This is the only situation when a process can directly change the environment settings of another process. If an application provides an environment block, the current directory information of the system drives is not automatically propagated to the new process. For example, there is an environment variable named =C: whose value is the current directory on drive C. An application must manually pass the current directory information to the new process. To do so, the application must explicitly create these environment variable strings, sort them alphabetically (because the system uses a sorted environment), and put them into the environment block. Typically, they will go at the front of the environment block, due to the environment block sort order.

One way to obtain the current directory information for a drive X is to call GetFullPathName("X:",. .). That avoids an application having to scan the environment block. If the full path returned is X:\, there is no need to pass that value on as environment data, since the root directory is the default current directory for drive X of a new process. Note:  The name of the executable in the command line that the operating system provides to a process is not necessarily identical to that in the command line that the calling process gives to the CreateProcess() function. The operating system may prepend a fully qualified path to an executable name that is provided without a fully qualified path. When a process is created with CREATE_NEW_PROCESS_GROUP specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE) is made on behalf of the new process; this means that the new process has CTRL+C disabled. This lets shells handle CTRL+C themselves, and selectively pass that signal on to sub-processes. CTRL+BREAK is not disabled, and may be used to interrupt the process/process group. For Windows Me/98/95:  CreateProcessW() is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows Me/98/95 Systems.

 

Security Remarks

 

The first parameter, lpApplicationName, can be NULL, in which case the executable name must be in the white space-delimited string pointed to by lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe", if it exists, instead of "MyApp.exe".

CreateProcess(NULL, "C:\\Program Files\\MyApp", ...)

If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls CreateProcess() using the Program Files directory will run this application instead of the intended application. To avoid this problem, do not pass NULL for lpApplicationName. If you do pass NULL for lpApplicationName, use quotation marks around the executable path in lpCommandLine, as shown in the example below.

CreateProcess(NULL, "\"C:\\Program Files\\MyApp.exe\" -L -S", ...)

---------------------------------------------------------Part 1/4----------------------------------------------------

 

 

 

 

 

 

 

Further reading and digging:

 

  1. Microsoft Visual C++, online MSDN.

  2. Structure, enum, union and typedef story can be found at C enum, typedef, define etc..

  3. For Multibytes, Unicode characters and Localization please refer to Unicode & Multibyte 1 (Story) and Unicode & Multibyte 2 (Implementation).

  4. Windows data type information is in Windows data type.

  5. Check the best selling C / C++ and Windows books at Amazon.com.

 

 

 

 

| Main | Next | Site Index | Download | Disclaimer | Privacy |