0, write in front
The class library package under the DOTNET platform is quite perfect, and ordinary applications can complete all work using the class library. For Windows Service support, you only need to inherit the servicebase provided under the DOTNET to create Windows Service, and call the ServiceControl class to control the service start and close, it is very easy.
However, after generating a service type application, you must be registered in the SCM (Service Control Manager) to be called as a service as a service. However, for Service's registration and logout, the DOTNET does provide the corresponding class ServiceInstaller and ServiceProcessInstaller, but only can be used with Installer installation process, which cannot be called separately in the ordinary application, that is to say to install one. Service is used as a test, I have to create a installation package.
How to use the API to register with SCM and log out of a service, let's take a brief introduction.
1, implementation overview
Open the service management tool in Control Panel, you can see all registered services of this unit, select a service's property, find a service there are many setup items: name, description, type, run account, etc. All of this can be set by calling the API function.
In the service's API, the instance of each service is represented by the handle, and the handle of the required service must first go to the SCM handle, so all calls start with OpenScManager, successful call OpenScManager A SCM handle will be obtained. If you are a registration service, use the SCM handle to call CreateService to create a new service; if you are logging for service, call the OpenService function, get a handle of the already existing service, and then use this service handle to call the deleteService logout service. Finally, close the service handle and SCM handle via CloseServiceHandle.
The process is simple, and the place where Csharp is more troublesome is the declaration of the API, and will be mentioned below.
2, register service
The registration service has been mentioned in front of the SARS, OpenScManager, CreateService and ClosServiceHandle. Let's introduce these API statements before use.
[DllImport ( "advapi32.dll")] public static extern System.IntPtr OpenSCManager (System.String lpMachineName, System.String lpDatabaseName, System.UInt32 dwDesiredAccess); [DllImport ( "advapi32.dll", EntryPoint = "CreateServiceA")] public static extern System.IntPtr CreateService (System.IntPtr hSCManager, System.String lpServiceName, System.String lpDisplayName, System.UInt32 dwDesiredAccess, System.UInt32 dwServiceType, System.UInt32 dwStartType, System.UInt32 dwErrorControl, System.String lpBinaryPathName, System. String lpLoadOrderGroup, System.IntPtr lpdwTagId, System.String lpDependencies, System.String lpServiceStartName, System.String lpPassword); [DllImport ( "advapi32.dll")] public static extern System.Boolean CloseServiceHandle (System.IntPtr hSCObject); that the About Service's API is implemented in Advapi32.dll, the prototype of the function can look up the header file in WinsVC and WinBase.
If you are familiar with Windows programming, you will know that the handle type is a 32-bit integer. Use INTPTR to declare, DWORD corresponds to the string type, the only thing you need to emphasize, is a DWord * Here, the declaration is also intPtr, because the NULL value is passed in most cases in the call, if you use Out Uint32, the NULL value cannot be passed.
Carefully see the declaration of CreateService can find that this function can really do a lot of things, including the service name (LPServiceName, the logo, calling Openserive, etc.), display name (LPDisplayName, is our service management tool in Service Name seen in
), Service type (DWServiceType, the operating mode of the specified service: independent process, sharing process, driver or interactive login mode, etc.), start-up type (DWStartType, automatic, manual or prohibition, etc.), service failure ( DwerrorControl), implement the path to the binary file of the service code (lpbinaryPathname), the name of the order group (lplandordergroup), accept the Tag flag (LPDWTAGID)
), Relying on the service's name group (LPDependenCIES), the startup service account (LPServiceStartName, if null, indicating using localsystem), start the password of the service account (LPPassword). If the call is successful, then a non-0 handle will be returned, and the service registration is successful. Looking at the above series of attributes, everyone may find less than that, is the longest and most awakened column in Service management tool, the settings of Description, the settings of Description need to call another API, as follows:
Public Static Extern System.Boolean ChangeServiceConfig2 (System.Uint32 dwinfolevel, ref system.string lpinfo); where lpinfo's declaration prototype is a LPVOID, if you set the description property, point to a structure:
typedef struct _SERVICE_DESCRIPTION {LPTSTR lpDescription;} SERVICE_DESCRIPTION, * LPSERVICE_DESCRIPTION; this structure which includes a character pointer, that is required to pass a pointer to a pointer pointing character in the function call, lazy sake, ref System.String sufficient, without Then define the structure, huh, huh!
Complete examples are as follows, constant definitions see this article last:
private static System.Boolean RegistService () {System.Boolean fRet = false; System.IntPtr hServiceManager = IntPtr.Zero, hService = IntPtr.Zero; System.String sServicePath = null, sDesc = null;
sServicePath = Application.StartupPath @ "/ sampleservice.exe"; hServiceManager = OpenSCManager (Environment.MachineName, null, SC_MANAGER_ALL_ACCESS); if (! hServiceManager = IntPtr.Zero) {hService = CreateService (hServiceManager, "sampleservice", "Sample Service ", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, sServicePath, null, IntPtr.Zero, null, null, null); if (hService = IntPtr.Zero) {sDesc =!" This is a sample service "; fRet =. ChangeServiceConfig2 (hService, SERVICE_CONFIG_DESCRIPTION, ref sDesc); CloseServiceHandle (hService); hService = IntPtr.Zero;} CloseServiceHandle (hServiceManager); hServiceManager = IntPtr.Zero;} return fRet;} 3, cancellation of Service
Compared with registration, the logout is simple, and the four APIs of OpenScManager, OpenService, DeleteService and ClosServiceHandle, the other two API declarations are as follows:
[DllImport ( "advapi32.dll")] public static extern System.IntPtr OpenService (System.IntPtr hSCManager, System.String lpServiceName, System.UInt32 dwDesiredAccess); [DllImport ( "advapi32.dll")] public static extern System.Boolean DeleteService (System.intptr HService); more simple, nothing to say, look at a complete example:
Private static system.Boolean unregistService () {system.boolean Fret = false; system.intptr.zero, hservice = INTPTR.ZERO;
hServiceManager = OpenSCManager (Environment.MachineName, null, SC_MANAGER_ALL_ACCESS); if (hServiceManager = IntPtr.Zero!) {hService = OpenService (hServiceManager, "sampleservice", SERVICE_ALL_ACCESS); if (! hService = IntPtr.Zero) {fRet = DeleteService ( HService); ClosESERVICEHANDE (HSERVICE); HSERVICE = INTPTR.ZERO;} ClosESERVICEHANDE (HSERVICEMANAGER); hserviceManager = INTPTR.ZERO;} returnif;} 4, final
You can add additional processing in implementation of the service, the main function is determined, if it is "-i", then the registration service is indicated, if "-u" means that the service is logged out, and vice versa is running normally.
5, declaration of API and constant
All APIs and constants used herein are as follows:
// declare APIs for service [DllImport ( "advapi32.dll")] public static extern System.IntPtr OpenSCManager (System.String lpMachineName, System.String lpDatabaseName, System.UInt32 dwDesiredAccess); [DllImport ( "advapi32.dll", EntryPoint = "CreateServiceA")] public static extern System.IntPtr CreateService (System.IntPtr hSCManager, System.String lpServiceName, System.String lpDisplayName, System.UInt32 dwDesiredAccess, System.UInt32 dwServiceType, System.UInt32 dwStartType, System.UInt32 dwErrorControl, System .String lpBinaryPathName, System.String lpLoadOrderGroup, System.IntPtr lpdwTagId, System.String lpDependencies, System.String lpServiceStartName, System.String lpPassword); [DllImport ( "advapi32.dll")] public static extern System.IntPtr OpenService (System. INTPTR HSCMANAGER, System.String LPServiceName, System.uint32 DwdesiredAccess; [DLLIMPORT ("Advapi32.dll")] Public Static Extern System.Boolean deleteService (System.IntPtr hService); [DllImport ( "advapi32.dll")] public static extern System.Boolean CloseServiceHandle (System.IntPtr hSCObject); [DllImport ( "advapi32.dll")] public static extern System.Boolean ChangeServiceConfig2 (System .Intptr hservice, system.uint32 dwinfolevel, ref system.string lpinfo;
public const System.UInt32 STANDARD_RIGHTS_REQUIRED = 0xF0000; // Service Control Manager object specific access types public const System.UInt32 SC_MANAGER_CONNECT = 0x0001; public const System.UInt32 SC_MANAGER_CREATE_SERVICE = 0x0002; public const System.UInt32 SC_MANAGER_ENUMERATE_SERVICE = 0x0004; public const System.UInt32 SC_MANAGER_LOCK = 0x0008; public const System.UInt32 SC_MANAGER_QUERY_LOCK_STATUS = 0x0010; public const System.UInt32 SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020; public const System.UInt32 SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG; // Service object specific access type Public const system.uint32 service_query_config = 0x0001; public const system.uint32 service_change_config = 0x0002; public const system.uint32 service_query_status = 0x0004; public const System.UInt32 SERVICE_ENUMERATE_DEPENDENTS = 0x0008; public const System.UInt32 SERVICE_START = 0x0010; public const System.UInt32 SERVICE_STOP = 0x0020; public const System.UInt32 SERVICE_PAUSE_CONTINUE = 0x0040; public const System.UInt32 SERVICE_INTERROGATE = 0x0080; public const System .Uint32 service_user_defined_control = 0x0100; public const system.uint32 service_all_access =
STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL; // service type public const System.UInt32 SERVICE_KERNEL_DRIVER = 0x00000001; public const System.UInt32 SERVICE_FILE_SYSTEM_DRIVER = 0x00000002; public const System.UInt32 SERVICE_ADAPTER = 0x00000004 ; public const System.UInt32 SERVICE_RECOGNIZER_DRIVER = 0x00000008; public const System.UInt32 SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER; public const System.UInt32 SERVICE_WIN32_OWN_PROCESS = 0x00000010; public const System.UInt32 SERVICE_WIN32_SHARE_PROCESS = 0x00000020; public const System.UInt32 SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | Service_win32_share_process; pu blic const System.UInt32 SERVICE_INTERACTIVE_PROCESS = 0x00000100; public const System.UInt32 SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS; // Start Type public const System.UInt32 SERVICE_BOOT_START = 0x00000000; public const System.UInt32 SERVICE_SYSTEM_START = 0x00000001; public const System. UInt32 SERVICE_AUTO_START = 0x00000002; public const System.UInt32 SERVICE_DEMAND_START = 0x00000003; public const System.UInt32 SERVICE_DISABLED = 0x00000004; // Error control type public const System.UInt32 SERVICE_ERROR_IGNORE = 0x00000000; public const System.UInt32 SERVICE_ERROR_NORMAL = 0x00000001;