C# 从Windows服务访问环境变量

C# 从Windows服务访问环境变量,c#,windows-services,permissions,C#,Windows Services,Permissions,我正在尝试用C#编写Windows服务。我需要找到某个文件的路径,该文件存储在环境变量中。在常规的C#控制台应用程序中,我可以通过以下几行实现这一点: string t = System.Environment.GetEnvironmentVariable("TIP_HOME"); 如果我把它写到控制台,我会看到它是成功的 现在,如果我在Windows服务中尝试相同的代码,字符串t为空 知道原因吗?该服务可能在不同的帐户下运行,并且没有获得相同的环境变量。您是否知道系统和用户环境变量?默认情况

我正在尝试用C#编写Windows服务。我需要找到某个文件的路径,该文件存储在环境变量中。在常规的C#控制台应用程序中,我可以通过以下几行实现这一点:

string t = System.Environment.GetEnvironmentVariable("TIP_HOME");
如果我把它写到控制台,我会看到它是成功的

现在,如果我在Windows服务中尝试相同的代码,字符串
t
为空


知道原因吗?

该服务可能在不同的帐户下运行,并且没有获得相同的环境变量。

您是否知道系统用户环境变量?默认情况下,Windows服务在系统帐户下运行。

我将该行代码修改为:

字符串t=System.Environment.GetEnvironmentVariable(“TIP_HOME”,EnvironmentVariableTarget.Machine)

我可以查看我的注册表,看到TIP_HOME已设置

这来自MSDN: 计算机:环境变量是从Windows操作系统注册表中的HKEY\U LOCAL\U Machine\System\CurrentControlSet\Control\Session Manager\environment项存储或检索的

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


但是,当我使用此更改运行服务时,字符串仍然显示为空。

您的问题似乎与我们所经历的类似,可能很难弄清楚到底发生了什么

当添加/删除/更改环境变量时,服务环境在“重新启动”之前不会识别这一点。这是因为这些环境变量存储在注册表中,并且此注册表由服务环境仅读取一次。。。在系统启动时

这意味着,为了让服务获取环境变量中的更改,需要重新启动系统


看看这张照片。

好吧,我不太明白,但这是我发现的

在同一个服务中,我首先尝试前面描述的内容,字符串返回空

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

下面是一个代码片段,它是根据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);
}

您是否在本地系统帐户下运行该服务

添加TIP_HOME变量后是否重新启动了机器

在本地系统下运行的服务从Services.exe服务启动,该服务仅在启动时读取其环境:

请尝试此代码
字符串getsyspath=System.Environment.GetEnvironmentVariable(“TIP_HOME”,EnvironmentVariableTarget.Machine)

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

这是通过注册表完成的

说你服务的关键是

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,该ID允许WinCache为所有“线程”共享一个中央缓存(基于APP_POOL_ID)(使用WShell启动非阻塞子“线程”,并且仍然与启动器共享同一个WinCache,允许简单的进程间通信)

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

我认为,总的来说,您并没有在全球环境中添加不必要的环境变量。当您拥有超过1个时,您可以使它们具有针对性和唯一性

问候,


Richard。

您需要检查变量是如何存储的。 Set/GetEnvironmentVariable有一个重载方法:

问题是,存储环境变量()有三种类型:

  • 机器(适用于所有用户)
  • 用户(可用于当前用户)
  • 流程(仅适用于当前流程[不推荐btw])
如果您将信息存储为计算机或用户,则可以将其测试为运行(Win+R):%TIP\U HOME%


希望能有所帮助:)

服务通常在三个服务帐户中的一个帐户下运行,
本地服务
本地系统
网络服务
。对于所有这些,您的典型环境变量将为null


调查


我通过让服务编写一个事件日志条目,并打印它存储在HOMEPATH变量中的内容来进行测试。它返回空的服务帐户。在C#中:


可能的解决方案


您可以在“服务属性”窗口或“服务安装配置”中设置服务使用的帐户(例如您的用户帐户)。当我使用我的用户帐户进行测试时,显示的事件日志条目
此服务的主路径是“\Users\Admin PC”
。如果它正在使用您的用户帐户,它将可以访问您通常可以访问的所有环境变量。
.

我想我应该澄清这一点,但提示HOME是一个系统变量。我认为系统变量不是特定于用户的?好吧,作为一种测试,您可以将调试代码添加到您的服务中,让它在整个环境中迭代
protected override void OnStart(string[] args)
{
    EventLog.WriteEntry("The HomePath for this service is '" + Environment.GetEnvironmentVariable("HOMEPATH") + "'", EventLogEntryType.Information);
}