有没有办法在VS2008安装项目中包含版本号作为output.msi文件名的一部分?
我想要一个名为“myinstaller-1.0.13.msi”的输出文件,其中版本部分是根据我在部署项目属性中放置的版本号自动设置的。
答案 0 :(得分:17)
我不想使用上面的.exe方法并且有一点时间,所以我开始挖掘。我在Windows 7 64位上使用VS 2008。当我有一个安装项目时,让我们调用它MySetup项目的所有细节都可以在$(ProjectDir)MySetup.vdproj文件中找到。
产品版本将在该文件的单行中找到,格式为
ProductVersion="8:1.0.0"
现在,在安装项目上有一个post-build事件。如果选择一个安装项目并点击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是YYYYMMDD形式的当前日期。
findstr行通过MySetup.vdproj,删除任何包含PostBuildEvent的行,然后返回带有productVersion的单行,并将其输出到文件。 然后我们删除引号,空格,将点转换成下划线。
for行将冒号中的剩余字符串拆分,然后取出第二部分,并再次将其输出到文件中。
然后我们将realvar设置为文件中剩余的值,并重命名MySetup.msi以包含日期和版本。
因此,鉴于上面的ProductVersion,如果是2012年3月27日,该文件将重命名为
MySetup-20120327-1_0_0.msi
显然,使用此方法可以获取vdproj文件中的任何变量并将它们包含在输出文件名中,我们不必构建任何额外的.exe程序来执行此操作。
HTH
答案 1 :(得分: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"
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 ...
答案 2 :(得分:12)
不确定你是否仍然需要这个但是想要回答这个,因为我们在postbuild事件中做了类似的操作。就我所做的研究而言,无法通过设置过程在内部设置文件名。
您可以通过在构建后事件中通过外部应用程序命名输出文件来以其他方式执行此操作。
以下是您可以做的事情:
在帖子构建活动中 - &gt;
[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;
}
}
答案 3 :(得分:2)
如果您使用WIX项目(而不是VS Setup&amp; Deployment项目),那么this article将准确地解释如何实现您的目标。
答案 4 :(得分:1)
我在Powershell中用2行做到了。
g
将现有的.vdproj重命名为MySetup.vdproj.template,并在要插入主要exe文件版本的任何位置插入“ $ {VERSION}”。
然后VS将检测vdproj文件中的更改,并询问您是否要重新加载它。
答案 5 :(得分:0)
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;
}
}
}