从Windows服务访问环境变量

34

我正在尝试使用C#编写Windows服务。我需要找到存储在环境变量中的特定文件的路径。在常规的C#控制台应用程序中,我可以通过以下代码实现:

string t = System.Environment.GetEnvironmentVariable("TIP_HOME");

如果我将它写入控制台,我会看到它成功了。
现在,如果我在Windows服务中尝试相同的代码,则字符串“t”为空。
有任何想法为什么?
10个回答

51

我不知道这是否有用,但我发现对于每个服务,都有一个直接向服务添加环境变量的选项。

这是通过注册表完成的。

假设您的服务的键是...

HKLM\SYSTEM\CurrentControlSet\Services\YourService

创建一个名为Environment的REG_MULTI_SZ。

现在,您可以添加像...这样的条目

Var1=Value1
Var2=Value2

这些环境变量将可供服务代码使用。

如果您正在使用Windows资源工具包来将脚本安装为服务(instsrv.exe和srvany.exe),那么您有选项为服务设置环境变量,但很可能选择的是错误的选项,因为这些选项是针对srvany.exe的。

相反,您可以使用键...

HKLM \ SYSTEM \ CurrentControlSet \ Services \ YourService \ Parameters

并创建一个名为AppEnvironment的REG_MULTI_SZ。

以同样的方式设置条目。

现在,您的脚本服务拥有自己的环境变量。

我正在使用PHP + WinCache这些技术,以便我能够为每个服务设置唯一的APP_POOL_ID,从而允许WinCache为所有“线程”(使用WShell启动非阻塞子“线程”,仍然共享与启动器相同的WinCache,允许简单的进程间通信)共享中央缓存(基于APP_POOL_ID)。

无论如何。我希望这有所帮助。

我认为,主要的问题在于你没有向全局环境添加不必要的环境变量。当您拥有多个环境变量时,您可以保持它们具有针对性和独特性。

问候,

Richard。


太好了!笔记非常有用!我会在我的项目中使用它。 - Igor Malin

25

你的问题似乎类似于我们经历过的事情,很难弄清楚发生了什么。

问题在于当添加/删除/更改环境变量时,服务环境不会意识到这一点,直到它“重新启动”。这是因为这些环境变量存储在注册表中,而这个注册表只有在系统启动时被服务环境读取一次。

这意味着为了使服务捕捉到环境变量的更改,需要进行系统重启。

请参阅关于此事的Microsoft KB


3
请注意,这仅适用于在本地系统帐户下运行的服务。对于在指定用户帐户下运行的服务,在重新启动后,它们将从注册表中获取环境更改。 - Martin Ba

6
服务可能是在不同的账户下运行,因此无法获得相同的环境变量。

我想我应该澄清一下,TIP_HOME是一个系统变量。我以为系统变量不是特定于用户的? - Brian
1
好的,作为一个测试,您可以向您的服务添加调试代码,使其在启动时迭代所有环境变量并将其输出到临时文件中。 - EBGreen

3

你是否在本地系统帐户下运行服务?

添加TIP_HOME变量后,您是否重新启动了计算机?

在本地系统下运行的服务从services.exe服务启动,它只在启动时读取其环境变量:http://support.microsoft.com/kb/821761


是的,自從系統變量被設置以來,機器已經重新啟動過了。我正在管理員賬戶下創建和啟動服務。 - Brian
https://web.archive.org/web/20100306183453/http://support.microsoft.com/kb/821761 - gavenkoa

1

服务通常在以下三个服务账户之一下运行:Local ServiceLocal SystemNetwork Service。对于这三种账户,您的典型环境变量将为null


调查


我进行了测试,让服务编写事件日志条目,并打印它存储在HOMEPATH变量中的内容。对于服务账户,它返回为空。在C#中:

protected override void OnStart(string[] args)
{
    EventLog.WriteEntry("The HomePath for this service is '" + Environment.GetEnvironmentVariable("HOMEPATH") + "'", EventLogEntryType.Information);
}

可能的解决方案。
您可以在服务属性窗口或服务安装配置中设置服务使用哪个帐户(例如您的用户帐户)。我测试时,使用我的用户帐户时,事件日志条目显示“此服务的HomePath为'\Users\Admin-PC'”。如果使用您的用户帐户,则可以访问您通常可以访问的所有环境变量。

1
你是否了解系统和用户环境变量?默认情况下,Windows服务在system账户下运行。

是的,我要查找的变量是系统变量。请参见我下面发布的答案。 - Brian

1

尝试这段代码 string getsyspath = System.Environment.GetEnvironmentVariable("TIP_HOME", EnvironmentVariableTarget.Machine);


1
您需要检查变量的存储方式。Set/GetEnvironmentVariable 有超载方法: Environment.GetEnvironmentVariable 方法 (String, EnvironmentVariableTarget) 问题在于,环境变量( EnvironmentVariableTarget )有三种存储类型:
- Machine (对所有用户可用) - User (对当前用户可用) - Process (仅对当前进程可用 【不建议使用】)
如果将信息存储为 Machine 或 User,则可以通过运行 Run (Win+R) 来测试它: %TIP_HOME%
希望能有所帮助 :)

1

好的,我不太理解这个,但是这是我找到的内容。

在同一个服务中,我首先尝试了之前描述的方法,但字符串返回为空。

然后,如果我枚举每个系统级环境变量,它可以很好地找到我要查找的变量。

这里是一段代码片段,稍微修改自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);
}

0
我将那行代码修改成了这样:

string t = System.Environment.GetEnvironmentVariable("TIP_HOME", EnvironmentVariableTarget.Machine);

我可以查看注册表并确认 TIP_HOME 已经设置。

这是来自 MSDN 的信息: Machine:在 Windows 操作系统注册表中,环境变量存储或检索自 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment 键。

用户变量存储在注册表的其他位置。

不过,当我使用这个更改运行服务时,字符串仍然为空。


你试过像我建议的那样枚举环境变量了吗? - EBGreen
我正在努力弄清楚如何……我对C#非常陌生,只需要用它完成这个小项目。 - Brian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接