I am attempting to write a Windows Service in C#. I need to find the path to a certain file, which is stored in an environment variable. In a regular C# console application, I can achieve that with the following line:
我试图用C#编写Windows服务。我需要找到某个文件的路径,该文件存储在环境变量中。在常规的C#控制台应用程序中,我可以通过以下行实现:
string t = System.Environment.GetEnvironmentVariable("TIP_HOME");
If I write that to the console I see that it was successful.
如果我把它写到控制台,我发现它是成功的。
Now, if I try that same code in a Windows Service, the string t
is empty.
现在,如果我在Windows服务中尝试相同的代码,则字符串t为空。
Any idea why?
知道为什么吗?
10 个解决方案
#1
28
I've no idea if this is useful, but I've found that for every service, there is an option to add environment variables directly to a service.
我不知道这是否有用,但我发现对于每个服务,都可以选择将环境变量直接添加到服务中。
It is done via the registry.
它是通过注册表完成的。
Say the key to your service is ...
说服务的关键是......
HKLM\SYSTEM\CurrentControlSet\Services\YourService
Create a REG_MULTI_SZ called Environment.
创建一个名为Environment的REG_MULTI_SZ。
Now you can add entries like ...
现在你可以添加像......这样的条目
Var1=Value1
Var2=Value2
and these will be available to the service code.
这些将可用于服务代码。
If you are using the Windows Resource ToolKit to install scripts as a service (instsrv.exe and srvany.exe), then, again, you have the option of setting Environment variables for the service, but most likely it is the wrong one as these would be for srvany.exe.
如果您使用Windows资源工具包将脚本作为服务安装(instsrv.exe和srvany.exe),那么,您可以选择为服务设置环境变量,但很可能是错误的,因为这些将用于srvany.exe。
Instead, you use the key ...
相反,你使用密钥......
HKLM\SYSTEM\CurrentControlSet\Services\YourService\Parameters
and create a REG_MULTI_SZ called AppEnvironment
并创建一个名为AppEnvironment的REG_MULTI_SZ
Set the entries in the same way.
以相同的方式设置条目。
And now your script service has it's own environment variables.
现在你的脚本服务有它自己的环境变量。
I'm using these techniques with PHP+WinCache to allow me to set an APP_POOL_ID unique to each service which allows WinCache to share a central cache (based upon APP_POOL_ID) for all "threads" (using WShell to launch non-blocking child "threads" and still share the same WinCache as the launcher, allowing simplistic, inter-process communication).
我在PHP + WinCache中使用这些技术,允许我为每个服务设置唯一的APP_POOL_ID,允许WinCache为所有“线程”共享*缓存(基于APP_POOL_ID)(使用WShell启动非阻塞子线程) “并且仍然与启动器共享相同的WinCache,允许简单的进程间通信。
Anyway. I hope this helps somewhat.
无论如何。我希望这有点帮助。
I think, in the main, you aren't adding unnecessary env_vars to the global environment. You can keep them targetted and unique when you have more than 1.
我认为,总的来说,你没有在全球环境中添加不必要的env_vars。当你有超过1时,你可以保持目标和唯一。
Regards,
Richard.
#2
18
Your problem seems to be something like we've experienced and can be very tricky to figure out what's going on.
你的问题似乎就像我们经历的那样,并且可以非常难以弄清楚发生了什么。
What happens is when environment variables are added/removed/changed, the services environment does not recognize this until it "restarts". This is because these environment variables are stored in the registry and this registry is read only once by the service environment... at system startup.
发生的情况是,添加/删除/更改环境变量时,服务环境在“重新启动”之前无法识别。这是因为这些环境变量存储在注册表中,并且此注册表仅在系统启动时由服务环境读取一次。
This means that in order for a service to pickup a change in environment variables, a system restart needs to occur.
这意味着为了使服务能够获取环境变量的变化,需要进行系统重启。
Check out the Microsoft KB on this.
在此查看Microsoft KB。
#3
6
The service is probably running under a different account and is not getting the same environment variables.
该服务可能在不同的帐户下运行,并且没有获得相同的环境变量。
#4
1
Okay, I don't quite understand this, but here is what I've found..
好吧,我不太明白这一点,但这是我发现的......
In the same service, I first try what I described earlier and the string returns empty.
在同一个服务中,我首先尝试我之前描述的,字符串返回空。
Then, if I enumerate through each of the system-level environment variables, it finds the variable I am looking for just fine.
然后,如果我枚举每个系统级环境变量,它会找到我正在寻找的变量。
Here is a code snippet, slightly modified from some sample code found on MSDN:
这是一段代码片段,稍微修改了MSDN上的一些示例代码:
foreach(DictionaryEntry de in Environment.GetEnvironmentVariables(tgt))
{
key = (string)de.Key;
value = (string)de.Value;
if(key.Equals("TIP_HOME") && value != null)
log.WriteEntry("TIP_HOME="+value, EventLogEntryType.Information);
}
#5
1
Are you running the service under the Local System account?
您是否在本地系统帐户下运行该服务?
Have you restarted the machine after adding the TIP_HOME variable?
添加TIP_HOME变量后重启机器了吗?
Services running under Local System get started from the services.exe service, which only reads its environment when it starts up: http://support.microsoft.com/kb/821761
在本地系统下运行的服务从services.exe服务启动,该服务仅在启动时读取其环境:http://support.microsoft.com/kb/821761
#6
1
try this code string getsyspath = System.Environment.GetEnvironmentVariable("TIP_HOME",EnvironmentVariableTarget.Machine);
试试这段代码字符串getsyspath = System.Environment.GetEnvironmentVariable(“TIP_HOME”,EnvironmentVariableTarget.Machine);
#7
1
You need to check how the variable was stored. There's the overload method for the Set/GetEnvironmentVariable:
您需要检查变量的存储方式。 Set / GetEnvironmentVariable有重载方法:
Environment.GetEnvironmentVariable Method (String, EnvironmentVariableTarget)
Environment.GetEnvironmentVariable方法(String,EnvironmentVariableTarget)
The thing is, there are three types of storing the environment variable (EnvironmentVariableTarget):
问题是,存储环境变量有三种类型(EnvironmentVariableTarget):
- Machine (available for all users)
- User (available for the current user)
- Process (available only for the current Process [not recommended btw])
机器(适用于所有用户)
用户(适用于当前用户)
流程(仅适用于当前流程[不推荐顺便说一句])
If you store the information as Machine or User, then you can test it as running Run (Win + R): %TIP_HOME%
如果您将信息存储为计算机或用户,则可以将其测试为运行Run(Win + R):%TIP_HOME%
Hope it helps :)
希望能帮助到你 :)
#8
0
Are you aware of system and user environment variables? A Windows Service, by default, runs under the system account.
您是否了解系统和用户环境变量?默认情况下,Windows服务在系统帐户下运行。
#9
0
I modified that line of code to this:
我修改了这行代码:
string t = System.Environment.GetEnvironmentVariable("TIP_HOME", EnvironmentVariableTarget.Machine);
string t = System.Environment.GetEnvironmentVariable(“TIP_HOME”,EnvironmentVariableTarget.Machine);
I can look through my registry and see that TIP_HOME is set.
我可以通过我的注册表查看TIP_HOME已设置。
This is from MSDN: Machine: The environment variable is stored or retrieved from the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment key in the Windows operating system registry.
这来自MSDN:Machine:环境变量是从Windows操作系统注册表中的HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment键存储或检索的。
User variables are stored elsewhere in the registry..
用户变量存储在注册表的其他位置。
The string is still showing up empty when I run the service with this change, though.
但是,当我使用此更改运行服务时,字符串仍然显示为空。
#10
0
Services typically are run under one of three service accounts, Local Service
Local System
and Network Service
. For all of which your typical environmental variable will be null.
服务通常在三个服务帐户之一,本地服务本地系统和网络服务下运行。对于所有这些,您的典型环境变量将为null。
To Investigate
I tested by having the service write an event log entry, and print what it stores in the HOMEPATH variable. It returned empty for service accounts. In C#:
我通过让服务编写一个事件日志条目进行测试,并打印它存储在HOMEPATH变量中的内容。它为服务帐户返回空。在C#中:
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("The HomePath for this service is '" + Environment.GetEnvironmentVariable("HOMEPATH") + "'", EventLogEntryType.Information);
}
Possible Solutions
You can set what account a service uses (your user account for instance), in the services properties window or in the service install config. When I tested with my user account the event log entry displayed The HomePath for this service is '\Users\Admin-PC'
. If it were using your user account it would have access to all of the environmental variables that you typically have access to.
.
您可以在服务属性窗口或服务安装配置中设置服务使用的帐户(例如,您的用户帐户)。当我使用我的用户帐户测试时,显示的事件日志条目此服务的HomePath是'\ Users \ Admin-PC'。如果它使用您的用户帐户,则可以访问您通常可以访问的所有环境变量。 。
#1
28
I've no idea if this is useful, but I've found that for every service, there is an option to add environment variables directly to a service.
我不知道这是否有用,但我发现对于每个服务,都可以选择将环境变量直接添加到服务中。
It is done via the registry.
它是通过注册表完成的。
Say the key to your service is ...
说服务的关键是......
HKLM\SYSTEM\CurrentControlSet\Services\YourService
Create a REG_MULTI_SZ called Environment.
创建一个名为Environment的REG_MULTI_SZ。
Now you can add entries like ...
现在你可以添加像......这样的条目
Var1=Value1
Var2=Value2
and these will be available to the service code.
这些将可用于服务代码。
If you are using the Windows Resource ToolKit to install scripts as a service (instsrv.exe and srvany.exe), then, again, you have the option of setting Environment variables for the service, but most likely it is the wrong one as these would be for srvany.exe.
如果您使用Windows资源工具包将脚本作为服务安装(instsrv.exe和srvany.exe),那么,您可以选择为服务设置环境变量,但很可能是错误的,因为这些将用于srvany.exe。
Instead, you use the key ...
相反,你使用密钥......
HKLM\SYSTEM\CurrentControlSet\Services\YourService\Parameters
and create a REG_MULTI_SZ called AppEnvironment
并创建一个名为AppEnvironment的REG_MULTI_SZ
Set the entries in the same way.
以相同的方式设置条目。
And now your script service has it's own environment variables.
现在你的脚本服务有它自己的环境变量。
I'm using these techniques with PHP+WinCache to allow me to set an APP_POOL_ID unique to each service which allows WinCache to share a central cache (based upon APP_POOL_ID) for all "threads" (using WShell to launch non-blocking child "threads" and still share the same WinCache as the launcher, allowing simplistic, inter-process communication).
我在PHP + WinCache中使用这些技术,允许我为每个服务设置唯一的APP_POOL_ID,允许WinCache为所有“线程”共享*缓存(基于APP_POOL_ID)(使用WShell启动非阻塞子线程) “并且仍然与启动器共享相同的WinCache,允许简单的进程间通信。
Anyway. I hope this helps somewhat.
无论如何。我希望这有点帮助。
I think, in the main, you aren't adding unnecessary env_vars to the global environment. You can keep them targetted and unique when you have more than 1.
我认为,总的来说,你没有在全球环境中添加不必要的env_vars。当你有超过1时,你可以保持目标和唯一。
Regards,
Richard.
#2
18
Your problem seems to be something like we've experienced and can be very tricky to figure out what's going on.
你的问题似乎就像我们经历的那样,并且可以非常难以弄清楚发生了什么。
What happens is when environment variables are added/removed/changed, the services environment does not recognize this until it "restarts". This is because these environment variables are stored in the registry and this registry is read only once by the service environment... at system startup.
发生的情况是,添加/删除/更改环境变量时,服务环境在“重新启动”之前无法识别。这是因为这些环境变量存储在注册表中,并且此注册表仅在系统启动时由服务环境读取一次。
This means that in order for a service to pickup a change in environment variables, a system restart needs to occur.
这意味着为了使服务能够获取环境变量的变化,需要进行系统重启。
Check out the Microsoft KB on this.
在此查看Microsoft KB。
#3
6
The service is probably running under a different account and is not getting the same environment variables.
该服务可能在不同的帐户下运行,并且没有获得相同的环境变量。
#4
1
Okay, I don't quite understand this, but here is what I've found..
好吧,我不太明白这一点,但这是我发现的......
In the same service, I first try what I described earlier and the string returns empty.
在同一个服务中,我首先尝试我之前描述的,字符串返回空。
Then, if I enumerate through each of the system-level environment variables, it finds the variable I am looking for just fine.
然后,如果我枚举每个系统级环境变量,它会找到我正在寻找的变量。
Here is a code snippet, slightly modified from some sample code found on MSDN:
这是一段代码片段,稍微修改了MSDN上的一些示例代码:
foreach(DictionaryEntry de in Environment.GetEnvironmentVariables(tgt))
{
key = (string)de.Key;
value = (string)de.Value;
if(key.Equals("TIP_HOME") && value != null)
log.WriteEntry("TIP_HOME="+value, EventLogEntryType.Information);
}
#5
1
Are you running the service under the Local System account?
您是否在本地系统帐户下运行该服务?
Have you restarted the machine after adding the TIP_HOME variable?
添加TIP_HOME变量后重启机器了吗?
Services running under Local System get started from the services.exe service, which only reads its environment when it starts up: http://support.microsoft.com/kb/821761
在本地系统下运行的服务从services.exe服务启动,该服务仅在启动时读取其环境:http://support.microsoft.com/kb/821761
#6
1
try this code string getsyspath = System.Environment.GetEnvironmentVariable("TIP_HOME",EnvironmentVariableTarget.Machine);
试试这段代码字符串getsyspath = System.Environment.GetEnvironmentVariable(“TIP_HOME”,EnvironmentVariableTarget.Machine);
#7
1
You need to check how the variable was stored. There's the overload method for the Set/GetEnvironmentVariable:
您需要检查变量的存储方式。 Set / GetEnvironmentVariable有重载方法:
Environment.GetEnvironmentVariable Method (String, EnvironmentVariableTarget)
Environment.GetEnvironmentVariable方法(String,EnvironmentVariableTarget)
The thing is, there are three types of storing the environment variable (EnvironmentVariableTarget):
问题是,存储环境变量有三种类型(EnvironmentVariableTarget):
- Machine (available for all users)
- User (available for the current user)
- Process (available only for the current Process [not recommended btw])
机器(适用于所有用户)
用户(适用于当前用户)
流程(仅适用于当前流程[不推荐顺便说一句])
If you store the information as Machine or User, then you can test it as running Run (Win + R): %TIP_HOME%
如果您将信息存储为计算机或用户,则可以将其测试为运行Run(Win + R):%TIP_HOME%
Hope it helps :)
希望能帮助到你 :)
#8
0
Are you aware of system and user environment variables? A Windows Service, by default, runs under the system account.
您是否了解系统和用户环境变量?默认情况下,Windows服务在系统帐户下运行。
#9
0
I modified that line of code to this:
我修改了这行代码:
string t = System.Environment.GetEnvironmentVariable("TIP_HOME", EnvironmentVariableTarget.Machine);
string t = System.Environment.GetEnvironmentVariable(“TIP_HOME”,EnvironmentVariableTarget.Machine);
I can look through my registry and see that TIP_HOME is set.
我可以通过我的注册表查看TIP_HOME已设置。
This is from MSDN: Machine: The environment variable is stored or retrieved from the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment key in the Windows operating system registry.
这来自MSDN:Machine:环境变量是从Windows操作系统注册表中的HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment键存储或检索的。
User variables are stored elsewhere in the registry..
用户变量存储在注册表的其他位置。
The string is still showing up empty when I run the service with this change, though.
但是,当我使用此更改运行服务时,字符串仍然显示为空。
#10
0
Services typically are run under one of three service accounts, Local Service
Local System
and Network Service
. For all of which your typical environmental variable will be null.
服务通常在三个服务帐户之一,本地服务本地系统和网络服务下运行。对于所有这些,您的典型环境变量将为null。
To Investigate
I tested by having the service write an event log entry, and print what it stores in the HOMEPATH variable. It returned empty for service accounts. In C#:
我通过让服务编写一个事件日志条目进行测试,并打印它存储在HOMEPATH变量中的内容。它为服务帐户返回空。在C#中:
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("The HomePath for this service is '" + Environment.GetEnvironmentVariable("HOMEPATH") + "'", EventLogEntryType.Information);
}
Possible Solutions
You can set what account a service uses (your user account for instance), in the services properties window or in the service install config. When I tested with my user account the event log entry displayed The HomePath for this service is '\Users\Admin-PC'
. If it were using your user account it would have access to all of the environmental variables that you typically have access to.
.
您可以在服务属性窗口或服务安装配置中设置服务使用的帐户(例如,您的用户帐户)。当我使用我的用户帐户测试时,显示的事件日志条目此服务的HomePath是'\ Users \ Admin-PC'。如果它使用您的用户帐户,则可以访问您通常可以访问的所有环境变量。 。