MSBuild无法查看从构建工作流设置的环境变量

时间:2012-09-11 14:08:13

标签: environment-variables workflow-foundation-4 tfsbuild msbuild-4.0

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

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

有没有办法强制MSBuild重新加载环境变量或强制正在运行的WF重新加载环境变量?我怀疑是即使WF创建了这个变量,它也不会刷新它的Environment状态,因此无法看到变量。此外,由于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");
        }
    }
}

1 个答案:

答案 0 :(得分:2)

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

更新

好的,所以下面的陈述(可以找到here)我认为解释哪里来自环境变量为什么你不是在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);