Как включить номер версии в выходное имя файла проекта установки VS - PullRequest
26 голосов
/ 29 июля 2010

Есть ли способ включить номер версии как часть имени файла output.msi в проект установки VS2008?

Я бы хотел, например, выходной файл с именем: "myinstaller-1.0.13.msi", где часть версии автоматически устанавливается на основе номера версии, который я указал в свойствах проекта развертывания.

Ответы [ 6 ]

18 голосов
/ 27 марта 2012

Я не хотел использовать метод .exe выше, и у меня было немного свободного времени, поэтому я начал копаться. Я использую VS 2008 на Windows 7 64 бит. Когда у меня есть проект установки, давайте назовем его MySetup. Все детали проекта можно найти в файле $ (ProjectDir) MySetup.vdproj.

Версия продукта находится в отдельной строке в этом файле в форме

ProductVersion="8:1.0.0"

Теперь в проекте установки есть событие после сборки. Если вы выберете проект установки и нажмете 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"

Я проведу вас через все вышеописанное.

datevar - текущая дата в форме ГГГГММДД.

Строка findstr проходит через MySetup.vdproj, удаляет любую строку с PostBuildEvent, затем возвращает единственную оставшуюся строку с productVersion и выводит ее в файл. Затем мы удаляем кавычки, пробелы, превращаем точки в подчеркивания.

Строка for разбивает оставшуюся строку на двоеточие, занимает вторую часть и снова выводит ее в файл.

Затем мы устанавливаем для realvar значение, оставленное в файле, и переименовываем MySetup.msi, чтобы включить дату и версию.

Итак, учитывая ProductVersion выше, если бы это было 27 марта 2012 года, файл был бы переименован в

MySetup-20120327-1_0_0.msi

Очевидно, что с помощью этого метода вы можете получить ЛЮБЫЕ переменные в файле vdproj и включить их в имя выходного файла, и нам не нужно создавать никаких дополнительных программ .exe для этого.

НТН

13 голосов
/ 26 декабря 2014

Та же концепция, что и в ответе Джима Гримметта, но с меньшими зависимостями:

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"

Некоторые примечания:

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.msi в foo-x.y.z.etc.msi.

REN "$(BuiltOuputPath)" ...

  • Это просто переименовывает выходной путь к новому имени.

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

  • Он написан в одну строку, как эта, так чтоОшибка по пути чисто ломает сборку.
12 голосов
/ 11 февраля 2011

Не уверен, требуется ли вам это по-прежнему или нет, но вы хотите ответить на этот вопрос, поскольку мы выполняли аналогичную операцию в событии postbuild. Поскольку исследование, которое я проводил, невозможно установить внутреннее имя файла в процессе установки.

Вы можете сделать это другим способом, назвав выходной файл через внешнее приложение в событии после сборки.

Вот что вы можете сделать:

В событии после сборки ->

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

Создайте приложение, которое будет переименовывать MSI-файл с номером версии из проекта развертывания. Ниже приведен код, используемый для приложения. Я думаю, это должно соответствовать вашему требованию.

Получение кода свойств 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;
    }
  }
2 голосов
/ 02 ноября 2010

Если вы используете проект WIX (в отличие от проекта установки и развертывания VS), то в этой статье объясняется, как именно добиться того, чего вы хотите.

1 голос
/ 01 октября 2018

Я сделал это с помощью 2 строк в powershell.

$versionText=(Get-Item MyProgram.exe).VersionInfo.FileVersion
(Get-Content MySetup.vdproj.template).replace('${VERSION}', $($versionText)) | Set-Content MySetup.vdproj

Переименуйте ваш существующий .vdproj в MySetup.vdproj.template и вставьте «$ {VERSION}» туда, куда вы хотите вставить версию вашего основного исполняемого файла.

VS обнаружит изменение в файле vdproj и спросит вас, хотите ли вы его перезагрузить.

0 голосов
/ 22 марта 2013
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using WindowsInstaller;


// cscript //nologo "$(ProjectDir)WiRunSql.vbs" "$(BuiltOuputPath)" "UPDATE `Property` SET `Property`.`Value`='4.0.0.1' WHERE `Property`='ProductVersion'"
// "SELECT `Property`.`ProductVersion` FROM `Property` WHERE `Property`.`Property` = 'ProductVersion'"

/* 
 * That's a .NET wrapper generated by tlbimp.exe, wrapping the ActiveX component c:\windows\system32\msi.dll.  
 * You can let the IDE make one for you with Project + Add Reference, COM tab, 
 * select "Microsoft Windows Installer Object Library". 
 */
namespace PostBuildEventModifyMSI
{
    /* Post build event fro Rename MSI file.
     * $(SolutionDir)PostBuildEventModifyMSI\bin\Debug\PostBuildEventModifyMSI.exe "$(SolutionDir)TestWebApplicationSetup\Debug\TestWebApplicationSetup.msi"
     */

    [System.Runtime.InteropServices.ComImport(), System.Runtime.InteropServices.Guid("000C1090-0000-0000-C000-000000000046")]
    class Installer { }
    class Program
    {
        static void Main(string[] args)
        {
            #region New code.

            string msiFilePath = string.Empty;
            if (args.Length == 0)
            {
                Console.WriteLine("Enter MSI file complete path:");
                msiFilePath = Console.ReadLine();
            }
            else
            {
                Console.WriteLine("Argument Received args[0]: " + args[0]);
                msiFilePath = args[0];
            }

            StringBuilder sb = new StringBuilder();
            string[] words = msiFilePath.Split('\\');
            foreach (string word in words)
            {
                sb.Append(word + '\\');

                if (word.Contains("Debug"))
                {
                    break;
                }
                else
                {

                }
            }

            // Open a view on the Property table for the Label property 
            //UPDATE Property set Value = '2.06.36' where Property = 'ProductVersion'
            Program p = new Program();
            string version = p.GetMsiVersionProperty(msiFilePath, "ProductVersion");
            string productName = p.GetMsiVersionProperty(msiFilePath, "ProductName");

            string newMSIpath = sb.ToString() + string.Format("{0}_{1}.msi", productName, version);
            Console.WriteLine("Original MSI File Path: " + msiFilePath);
            Console.WriteLine("New MSI File Path: " + newMSIpath);


            System.IO.File.Move(msiFilePath, newMSIpath);

            #endregion




            //Console.Read();
        }

        private string GetMsiVersionProperty(string msiFilePath, string property)
        {
            string retVal = string.Empty;

            // Create an Installer instance  
            WindowsInstaller.Installer installer = (WindowsInstaller.Installer) new Installer();

            // Open the msi file for reading  
            // 0 - Read, 1 - Read/Write  
            Database db = installer.OpenDatabase(msiFilePath, WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly); //// Open the MSI database in the input file 

            // Fetch the requested property  
            string sql = String.Format(
                "SELECT Value FROM Property WHERE Property='{0}'", property);
            View view = db.OpenView(sql);
            //View vw = db.OpenView(@"SELECT `Value` FROM `Property` WHERE `Property` = 'ProductVersion'");
            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(db);

            return retVal;
        }

    }
}
...