一般应用程序可以操作注册表,不会出现上面问题。但是做成Windows服务的形式就会存在很多问题。
问题一:服务无法访问到HKEY_CURRENT_USER中的值。
解决:服务一般做成LocalSystem,本地服务,本地服务权限比较高,但本地服务无法访问HKEY_CURRENT_USER中的值,因为它是保存当前用户的信息内容(需要用户登录),本地服务无法访问到需要用户登录的注册表信息。HKEY_CURRENT_USER中的值是一直在变的,登录用户不同,值不同,HKEY_USERS下保存了很多sid,包含用户的sid,这个sid是唯一的,由很多因素决定,HKEY_CURRENT_USER就是HKEY_USERS下当前登录sid的映射。
应用程序可以通过代码方式访问到当前用户的sid,如某个sid:S-1-5-21-1993962763-1677128483-682003330-1021,用本地服务访问用户sid不可行,访问到的会是S-1-5-18,获取到的是当前用户服务的sid。
//C#应用程序获得当前用户的安全标识符
using System.Security.Principal;
WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
string userSid = windowsIdentity.User.Value;
问题二:服务实现开机自启动。
解决: 服务实现开机启动,需要设置StartType为Automatic,可实现开机自启动,但是如果服务里有获取mac地址,网卡,cpu,硬盘等信息的代码,无法实现开机自启动,查找原因是因为服务依赖获取mac地址的信息等模块是依赖Windows服务WMI Performance Adapter,当这个服务还未启动时,自己做的服务也无法启动。在代码里面添加服务依赖 ,也可以添加多个服务依赖:
this.serviceInstaller1.ServicesDependedOn = new string[]{"WMI Performance Adapter"};
问题三:服务有些电脑的数据读取不到
解决:查找问题原因,写log后发现HKEY_USERS下的值没有找到用户的sid,故访问不到HKEY_CURRENT_USER中的键值。可能用户没有登录。
服务是开机启动,服务启动后,可能用户还没有登录,所有访问不到用户的sid信息。等用户登录后,服务的onstart代码已经执行完毕,所有就造成用户数据读不到。处理方法是待用户登录后再去执行服务的处理代码,之前一直让服务代码while循环执行判断用户已登录,可以判断explorer.exe进程是否开启。
while(!flgUserOn)
{
int n=0;
Process[] pros = Process.GetProcesses();
for ( n=0; n < pros.Length; n++ )
{
string name = pros[n].ProcessName;
if ( name =="explorer" )
{
flgUserOn = true;
break;
}
}
}
问题四:服务的安装问题
有三种方式安装服务,一种是用vs自带的工具,在服务exe文件所在目录敲入命令installutil Service.exe安装服务,installutil /u Service.exe卸载服务,第二种方式是用.NET的安装部署项目来安装程序。第三种方式是用C#的代码来安装、卸载停止、开启服务。