分享
 
 
 

CSharp Tips:调用API注册和注销Windows Service

王朝system·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

0、写在前面

DotNET平台下的类库封装的相当完善,普通的应用完全可以利用类库完成所有的工作。对于Windows Service的支持也是一样,只需要继承DotNET下提供的ServiceBase就可以创建Windows的Service,调用ServiceControl类的方法就可以控制Service的启动和关闭,非常容易。

然而生成了一个Service类型的应用程序之后,必须在SCM(Service Control Manager)中注册,才能够被当作一个Service被系统调用。但是对于Service的注册和注销却比较麻烦,DotNET的确也提供了对应的类ServiceInstaller和ServiceProcessInstaller,但是只能够和Installer的安装过程集成使用,不能够单独在普通应用程序中调用,也就是说为了安装一个Service用作测试,我不得不创建一个安装包。

怎样利用API向SCM注册以及注销一个Service呢,下面就简单的介绍一下。

1、实现概述

打开Control Panel中Service的管理工具,可以看到本机所有已注册的Service,选择一个Service的属性会发现一个Service有很多设置项:名称、描述、类型、运行帐号等。所有这些都可以通过调用API函数来设定。

在Service的API中,每一个服务的实例通过句柄来表示,而需要服务的句柄之前必须要先要的到SCM的句柄(Handle),所以所有的调用都是通过OpenSCManager开始,成功的调用OpenSCManager后将获得一个SCM的句柄。如果是注册Service,那么利用SCM句柄调用CreateService来创建一个新的服务;如果是注销Service,则调用OpenService函数,获得一个已经存在的Service的句柄,然后利用这个服务句柄调用DeleteService注销服务。最后通过CloseServiceHandle关闭Service的句柄和SCM的句柄。

过程很简单,在CSharp下比较麻烦的地方就是API的声明,下面会一一提到。

2、注册Service

前面已经提到注册Service一共用到了三个API,OpenSCManager、CreateService和CloseServiceHandle。使用之前先介绍一下这些API的声明。

[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

);

这个了关于Service的API都是在Advapi32.dll中实现的,函数的原型可以自行查找头文件,在Winsvc和Winbase中。

熟悉Windows编程的话一定会了解,句柄类型就是一个32位的整型,在DotNET下用IntPtr来声明,DWORD对应UINT32,LPCSTR对应String类型,唯一需要强调的是CreateService这个函数的lpdwTagId,是一个DWORD*,这里声明也IntPtr,因为在调用中绝大多数情况下传递NULL值,如果用out UINT32,无法传递NULL值。

仔细看CreateService中声明可以发现,这个函数真的可以做很多事情,其中包括Service的名称(lpServiceName,服务的标识,调用OpenSerive等函数时用到)、显示名(lpDisplayName,就是我们在Service的管理工具中看到的名称)、服务类型(dwServiceType,指定服务的运行方式:独立进程、共享进程、驱动程序还是交互式登录模式等等)、启动类型(dwStartType,自动、手动还是禁止等等)、服务失败的严重性(dwErrorControl)、实现服务代码的二进制文件的路径(lpBinaryPathName)、加载顺序组的名称(lpLoadOrderGroup)、接受Tag标志码(lpdwTagId)、依赖服务的名称组(lpDependencies)、启动服务的帐号(lpServiceStartName,如果为NULL,表示使用LocalSystem)、启动服务帐号的口令(lpPassword)。如果调用成功,那么将返回一个非0的句柄,表示服务注册成功。

看了上面的一系列属性说明,大家也许发现还少了一样,就是在Service的管理工具中最长最醒目的一栏Description,Description的设置需要调用另一个API,如下:

public static extern System.Boolean ChangeServiceConfig2(

System.IntPtr hService,

System.UInt32 dwInfoLevel,

ref System.String lpInfo

);

其中lpInfo的声明原型是一个LPVOID,如果设置Description属性的话指向的是一个结构:

typedef struct _SERVICE_DESCRIPTION {

LPTSTR lpDescription;

} SERVICE_DESCRIPTION, *LPSERVICE_DESCRIPTION;

这个结构里面包含了一个字符指针,也就是说需要在函数调用时传递一个指向字符指针的指针,偷懒起见,ref System.String就足够了,无需再定义结构了,呵呵!

完整的例子如下,常量定义见本文最后:

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、注销Service

相对于注册,注销就简单很多了,用到了OpenSCManager、OpenService、DeleteService和CloseServiceHandle四个API,另两个API的声明如下:

[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

);

比较简单没什么可多说的看一个完整的例子:

private static System.Boolean UnRegistService()

{

System.Boolean fRet = false;

System.IntPtr hServiceManager = 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);

CloseServiceHandle(hService);

hService = IntPtr.Zero;

}

CloseServiceHandle(hServiceManager);

hServiceManager = IntPtr.Zero;

}

return fRet;

}

4、最后

可以在实现Service的工程中增加一下额外的处理,Main函数中判断一下调用参数,如果是“-I”,则表示注册Service,如果是“-U”表示注销Service,反之则作为Service正常运行。

5、API和常量的声明

本文所用到的所有API和常量如下:

// 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;

public 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;

public const System.UInt32 SERVICE_ERROR_SEVERE = 0x00000002;

public const System.UInt32 SERVICE_ERROR_CRITICAL = 0x00000003;

// Info levels for ChangeServiceConfig2 and QueryServiceConfig2

public const System.UInt32 SERVICE_CONFIG_DESCRIPTION = 1;

public const System.UInt32 SERVICE_CONFIG_FAILURE_ACTIONS = 2;

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有