3

这与 TFS 2010 构建系统有关。在我们的构建工作流程中,我们使用 System.Environment 类的 SetEnvironmentVariable 方法设置了几个环境变量。我已确认此环境变量已在构建服务器上正确设置,并且已设置为系统范围的环境变量。

问题是,当在此 WF 中调用 MSBuild 并编译解决方案时,我们尝试读取此环境变量的构建后事件会失败,因为它们无法看到此环境变量。

有没有办法强制 MSBuild 重新加载环境变量或强制正在运行的 WF 重新加载环境变量?我的怀疑是,即使 WF 创建了这个变量,它也不会刷新它的环境状态,因此看不到这个变量。此外,由于 WF 调用 MSBuild,它会将相同的环境状态传递给不包含此变量的 MSBuild。

更新

在 Visual Studio 中粘贴以下代码并运行它。SendMessageTimeOut 的延迟为 10 秒,因此请耐心等待。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace EnvironmentVarTest
{
    class Program
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool
        SendMessageTimeout(
            IntPtr hWnd,
            int Msg,
            int wParam,
            string lParam,
            int fuFlags,
            int uTimeout,
            out int lpdwResult
        );

        public const int HWND_BROADCAST = 0xffff;
        public const int WM_SETTINGCHANGE = 0x001A;
        public const int SMTO_NORMAL = 0x0000;
        public const int SMTO_BLOCK = 0x0001;
        public const int SMTO_ABORTIFHUNG = 0x0002;
        public const int SMTO_NOTIMEOUTIFNOTHUNG = 0x0008;


        static void Main(string[] args)
        {
            Program p = new Program();
            string environmentVariableValue = DateTime.Now.ToLongTimeString().Replace(":", String.Empty);
            Console.WriteLine("On the CMD window that opens up after about 10 seconds, if you type %samplevar% and hit Enter, you should see: " + environmentVariableValue);
            p.SetEnvironmentVariable(environmentVariableValue);
            RefreshProcessVars();
            p.ReadEnvironmentVariable();

            p.StartCMD();
            Console.ReadLine();
        }

        void SetEnvironmentVariable(string value)
        {
            System.Environment.SetEnvironmentVariable("samplevar", value, EnvironmentVariableTarget.Machine);

        }

        static void RefreshProcessVars()
        {
            int result;
            bool callresult = SendMessageTimeout(
                 (System.IntPtr)HWND_BROADCAST,
                 WM_SETTINGCHANGE,
                 0,
                 "Environment",
                 SMTO_BLOCK | SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG,
                 10000,
                 out result);

            if (!callresult || result == 0)
            {
                int lasterror = Marshal.GetLastWin32Error();
                Win32Exception winex = new Win32Exception(lasterror);
                Console.WriteLine("Exception happened while calling SendMessageTimeOut. The exception message is " + winex.Message);
            }
        }
        void ReadEnvironmentVariable()
        {
            var x = System.Environment.GetEnvironmentVariable("smaplevar", EnvironmentVariableTarget.Machine);

        }

        void StartCMD()
        {
            Process.Start("cmd.exe");
        }
    }
}
4

1 回答 1

2

不幸的是,由于MSBuild进程在启动时传递了环境变量的缓存版本,因此该进程的命令行功能将无法看到更新的值。在我看来,您最好的选择是在构建后事件中更改该变量,或者将值存储在您可以从构建后事件中读取的介质中。

更新

好的,所以下面的声明(可以在此处找到)我认为解释环境变量的来源以及为什么您没有在MSBuild.

默认情况下,子进程继承其父进程的环境变量。

所以,两个人可以参加那场比赛,让我们广播已经发生了变化,看看是否会为我们解决这个问题。下面是应该为您执行此操作的代码。

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool
SendMessageTimeout(
    IntPtr hWnd,
    int Msg,
    int wParam,
    string lParam,
    int fuFlags,
    int uTimeout,
    out int lpdwResult
);

public const int HWND_BROADCAST = 0xffff;
public const int WM_SETTINGCHANGE = 0x001A;
public const int SMTO_NORMAL = 0x0000;
public const int SMTO_BLOCK = 0x0001;
public const int SMTO_ABORTIFHUNG = 0x0002;
public const int SMTO_NOTIMEOUTIFNOTHUNG = 0x0008;

int result;
SendMessageTimeout(
    (System.IntPtr)HWND_BROADCAST,
    WM_SETTINGCHANGE,
    0,
    "Environment",
    SMTO_BLOCK | SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG,
    SomeTimeoutValue,
    out result);
于 2012-09-11T17:07:25.307 回答