如何在VS Setup Project输出文件名中包含版本号

cha*_*rdy 26 setup-project visual-studio-2008 visual-studio

有没有办法在VS2008安装项目中包含版本号作为output.msi文件名的一部分?

我想要一个名为"myinstaller-1.0.13.msi"的输出文件,其中版本部分是根据我在部署项目属性中放置的版本号自动设置的.

小智 18

我不想使用上面的.exe方法,并且有一点闲暇,所以我开始使用diggind.我在Windows 7 64位上使用VS 2008.当我有一个安装项目时,让我们调用它MySetup项目的所有细节都可以在文件$(ProjectDir)MySetup.vdproj中找到.

产品版本将在表单中该文件的单行中找到

ProductVersion="8:1.0.0"
Run Code Online (Sandbox Code Playgroud)

现在,在安装项目上有一个构建后事件.如果选择一个安装项目并点击F4,则右键单击并选择属性时,会得到一组完全不同的属性.点击F4后你会看到其中一个是PostBuildEvent.再次假设安装项目名为MySetup,以下将设置.msi的名称以包括日期和版本

set datevar=%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%
findstr /v PostBuildEvent $(ProjectDir)MySetup.vdproj | findstr ProductVersion >$(ProjectDir)version.txt
set /p var=<$(ProjectDir)version.txt
set var=%var:"=%
set var=%var: =%
set var=%var:.=_%
for /f "tokens=1,2 delims=:" %%i in ("%var%") do @echo %%j >$(ProjectDir)version.txt
set /p realvar=<$(ProjectDir)version.txt
rename "$(ProjectDir)$(Configuration)\MySetup.msi" "MySetup-%datevar%-%realvar%.msi"
Run Code Online (Sandbox Code Playgroud)

我会带你了解上面的内容.

datevar是YYYYMMDD格式的当前日期.

findstr行通过MySetup.vdproj,删除PostBuildEvent中的任何行,然后返回带有productVersion的单行,并将其输出到文件.然后我们删除引号,空格,将点转换成下划线.

for行在冒号上拆分剩余的字符串,然后取第二部分,并再次将其输出到文件.

然后,我们将realvar设置为文件中剩余的值,并重命名MySetup.msi以包含日期和版本.

因此,鉴于上面的ProductVersion,如果是2012年3月27日,则文件将重命名为

MySetup-20120327-1_0_0.msi
Run Code Online (Sandbox Code Playgroud)

显然,使用此方法可以获取vdproj文件中的任何变量并将它们包含在输出文件名中,我们不必构建任何额外的.exe程序来执行此操作.

HTH

  • 我和@MuhammadMubashir有类似的问题.%date%的格式取决于本地化设置,并且字段并不总是位于同一位置.在Win7 US上,日期有一个缩写的星期几,它在示例代码中仅提取"dd/mm/yyyy".这会导致重命名目标的文件名字符无效,从而导致其失败. (2认同)

ant*_*tak 13

与Jim Grimmett的答案相同的概念,但依赖性较小:

FOR /F "tokens=2 delims== " %%V IN ('FINDSTR /B /R /C:" *\"ProductVersion\"" "$(ProjectDir)MySetupProjectName.vdproj"') DO FOR %%I IN ("$(BuiltOuputPath)") DO REN "$(BuiltOuputPath)" "%%~nI-%%~nxV%%~xI"
Run Code Online (Sandbox Code Playgroud)

一些注意事项:

MySetupProjectName.vdproj应更改为项目文件的名称.忘记改变这种导致生成错误:'PostBuildEvent' failed with error code '1'Output窗口显示该文件FINDSTR无法打开.

分步说明:

FINDSTR /B /R /C:" *\"ProductVersion\"" $(ProjectDir)MySetupProjectName.vdproj

  • "ProductVersion" = "8:x.y.z.etc"将从项目文件中找到该行.

FOR /F "tokens=2 delims== " %%V IN (...) DO ... %%~nxV ...

  • 这用于x.y.z.etc从上面的结果中解析出部分.

$(BuiltOuputPath)

  • 这是原始输出路径,根据它在构建后事件命令行的"宏"中所说的内容.

FOR %%I IN (...) DO ... %%~nI-%%~nxV%%~xI

  • 这用于将字符串转换foo.msifoo-x.y.z.etc.msi.

REN "$(BuiltOuputPath)" ...

  • 这只是将输出路径重命名为新名称.

FOR ... DO FOR .. DO REN ...

  • 它写在这样的一行上,以便一路上的错误干净地打破了构建.


JPR*_*ddy 12

不确定你是否仍然需要这个,但是想要回答这个,因为我们在postbuild事件中做了类似的操作.就我所做的研究而言,无法通过设置过程在内部设置文件名.

您可以通过在构建后事件中通过外部应用程序命名输出文件以其他方式执行此操作.

这是你可以做的:

在post build事件中 - >

[MsiRenamerAppPath]\MsiRenamer.exe"$(BuildOutputPath)"

创建一个应用程序,它将使用部署项目中的版本号重命名msi文件.以下是用于该应用程序的代码.这应该符合你的要求我猜.

alteridem文章中获取获取msi属性代码

class MsiRenamer
  {
    static void Main(string[] args)
    {
      string inputFile;
      string productName = "[ProductName]";

      if (args.Length == 0)
      {
        Console.WriteLine("Enter MSI file:");
        inputFile = Console.ReadLine();
      }
      else
      {
        inputFile = args[0];
      }

      try
      {
        string version;

        if (inputFile.EndsWith(".msi", StringComparison.OrdinalIgnoreCase))
        {
          // Read the MSI property
          version = GetMsiProperty(inputFile, "ProductVersion");
          productName = GetMsiProperty(inputFile, "ProductName");
        }
        else
        {
          return;
        }
        // Edit: MarkLakata: .msi extension is added back to filename
        File.Copy(inputFile, string.Format("{0} {1}.msi", productName, version));
        File.Delete(inputFile);
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }

    static string GetMsiProperty(string msiFile, string property)
    {
      string retVal = string.Empty;

      // Create an Installer instance  
      Type classType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
      Object installerObj = Activator.CreateInstance(classType);
      Installer installer = installerObj as Installer;

      // Open the msi file for reading  
      // 0 - Read, 1 - Read/Write  
      Database database = installer.OpenDatabase(msiFile, 0);

      // Fetch the requested property  
      string sql = String.Format(
          "SELECT Value FROM Property WHERE Property='{0}'", property);
      View view = database.OpenView(sql);
      view.Execute(null);

      // Read in the fetched record  
      Record record = view.Fetch();
      if (record != null)
      {
        retVal = record.get_StringData(1);
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(record);
      }
      view.Close();
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(view);
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(database);

      return retVal;
    }
  }
Run Code Online (Sandbox Code Playgroud)

  • 要使用它,请确保向Microsoft Windows Installer对象库添加COM引用,并"使用WindowsInstaller;" 在此代码段中. (2认同)