如何以编程的方式更改项目的产品版本?

12

我有几个部署项目。为了部署一个应用程序,我需要执行多个任务之一是更改每个部署项目的产品版本和产品代码。

我找不到以编程方式更改它们的方法。

由于这是一个部署项目(最终生成可执行安装程序),我无法使用MSBuild工作,而是在命令提示符中使用Devenv。


这是什么类型的项目?C++还是C# / VB? - Aaron Fischer
该项目是一个C#部署项目,我正在使用.Net 2.0。 - El Padrino
有没有完整的源代码的最终解决方案?这些是vdproj项目吗? - Kiquenet
这是一个csproj文件,没有最终的工作解决方案。 - El Padrino
10个回答

11

今天我在搜索完全相同的事情。我使用谷歌找到了这个:

static void Main(string[] args) 
{
    string setupFileName = @"<Replace the path to vdproj file>"; 
    StreamReader reader = File.OpenText(setupFileName); 
    string file = string.Empty; 

    try 
    { 
        Regex expression = new Regex(@"(?:\""ProductCode\"" = 
        \""8.){([\d\w-]+)}"); 
        Regex expression1 = new Regex(@"(?:\""UpgradeCode\"" = 
        \""8.){([\d\w-]+)}"); 
        file = reader.ReadToEnd(); 

        file = expression.Replace(file, "\"ProductCode\" = \"8:{" + 
        Guid.NewGuid().ToString().ToUpper() + "}"); 
        file = expression1.Replace(file, "\"UpgradeCode\" = \"8:{" 
        + Guid.NewGuid().ToString().ToUpper() + "}"); 
    } 
    finally 
    { 
        // Close the file otherwise the compile may not work 
        reader.Close(); 
    } 

    TextWriter tw = new StreamWriter(setupFileName); 
    try 
    { 
        tw.Write(file); 
    } 
    finally 
    { 
        // close the stream 
        tw.Close(); 
    } 
 }

我使用了这种方法来更改我的vsproj上的产品代码,这样当我的msi构建并运行时,它可以很好地升级,而不需要要求用户删除先前的版本。非常感谢,我一直在寻找如何做到这一点! - Mike D
+1 我有同样的问题,似乎正则表达式可能是最简单的解决方案。 - Beta033
我将脚本作为控制台应用程序(C#)运行,但文件没有发生任何变化,可能是什么问题? - MoonLight

5

我知道原帖作者正在寻找一个.NET 2.0的解决方案来解决这个问题。然而,由于这没有标记为.NET,我将提供我的C++解决方案来解决这个问题。这可能适用于.NET领域,但我会留给其他人来处理。

这不仅更新了我的应用程序关于框和日志文件中的版本信息,还更新了在Windows资源管理器中看到的所有Windows版本信息。

更新:添加了我自原答案以来所做的一些更改。

首先,我将整个版本信息块从我的Project.rc文件移动到了我的Project.rc2文件中:

/////////////////////////////////////////////////////////////////////////////
//
// Version
//

VS_VERSION_INFO VERSIONINFO
 FILEVERSION FILE_VER
 PRODUCTVERSION PROD_VER
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
  FILEFLAGS 0x1L
#else
  FILEFLAGS 0x0L
#endif
  FILEOS 0x4L
  FILETYPE 0x1L
  FILESUBTYPE 0x0L
BEGIN
   BLOCK "StringFileInfo"
   BEGIN
       BLOCK "040904e4"
       BEGIN
           VALUE "CompanyName", "MyCompany"
           VALUE "FileDescription", "Software Description"
           VALUE "FileVersion", 1,0,0,1
           VALUE "InternalName", "FileName.exe"
           VALUE "LegalCopyright", "(c) 2008 My Company.  All rights reserved."
           VALUE "OriginalFilename", "FileName.exe"
           VALUE "ProductName", "Product Name"
           VALUE "ProductVersion", 1,0,0,1
       END
   END
   BLOCK "VarFileInfo"
   BEGIN
       VALUE "Translation", 0x409, 1252
   END
END

这实质上是将您从资源编辑器中编辑的所有版本信息传输到单独的文件中。这样,当从编辑器外部编辑资源文件时,就不会出现错误。缺点是您无法再从资源编辑器中编辑版本信息。但是,由于我们希望该内容自动更新,所以这并不是什么大问题。

接下来,我创建了一个VersionInfo.h文件,并将其添加到我的项目中:

#pragma once

//major release version of the program, increment only when major changes are made
#define VER_MAJOR 2

//minor release version of the program, increment if any new features are added
#define VER_MINOR 0

//any bugfix updates, no new features
#define VER_REV 0

//if this is some special release (e.g. Alpha 1) put the special release string here
#define STR_SPECIAL_REL "Alpha 1"


#define FILE_VER VER_MAJOR,VER_MINOR,VER_REV
#define PROD_VER FILE_VER

//these are special macros that convert numerical version tokens into string tokens
//we can't use actual int and string types because they won't work in the RC files
#define STRINGIZE2(x) #x
#define STRINGIZE(x) STRINGIZE2(x)

#define STR_FILE_VER STRINGIZE(VER_MAJOR) "." STRINGIZE(VER_MINOR) "." STRINGIZE(VER_REV)
#define STR_PROD_VER STR_FILE_VER " " STR_SPECIAL_REL

#define STR_COPYRIGHT_INFO "©" BuildYear " Your Company. All rights reserved."

我随后在rc2文件中包含了VersionInfo.h,并进行了以下更改:
#include "VersionInfo.h"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//

<no changes>
           VALUE "FileVersion", STR_FILE_VER
           <no changes>
           VALUE "LegalCopyright", STR_COPYRIGHT_INFO
           <no changes>
           VALUE "ProductVersion", STR_PROD_VER
<no changes>

使用这个设置,我可以编辑我的构建脚本(使用Perl),在使用devenv命令行重新构建整个项目之前修改VersionInfo.h文件中的版本信息。

我添加了一个可能也很有用的额外步骤(尽管它还没有完全完善,可能会成为未来的问题),就是每次构建项目时生成唯一的构建号。在当前的版本中,它总是适用于完全重建,但只在增量构建中偶尔适用。我所做的是创建一个名为build_number.incl的文件,其中包含以下内容:

#define CurrentBuildNumber  "20081020P1525" 

这实际上是构建开始的日期和时间。我创建了一个批处理文件,作为项目的预构建事件运行,生成此文件。该脚本还定义了BuildYear,以便VersionInfo.h文件中的版权始终包含最近构建的年份。批处理脚本如下:

    echo Generating Build Number
    @For /F "tokens=2,3,4 delims=/ " %%A in ('Date /t') do @(
    Set Month=%%A
    Set Day=%%B
    Set Year=%%C
    )

    @For /F "tokens=1,2,3 delims=/M: " %%A in ('Time /t') do @(
    Set Hour=%%A
    Set Minute=%%B
    Set AmPm=%%C
    )

    @echo #define CurrentBuildNumber  "%Year%%Month%%Day%%AmPm%%Hour%%Minute%" > "$(ProjectDir)\build_number.incl"
    @echo #define BuildYear "%Year%" >> "$(ProjectDir)\build_number.incl"
    echo ----------------------------------------------------------------------

然后将此文件包含在项目中需要使用构建号(即关于框)的任何文件中。

其中一些内容来自这篇CodeProject文章

希望这些信息能够有所帮助。


2
我遇到了同样的问题,我发现在prebuildevent中修改.vdproj文件并不能完全实现我的需求。因此我使用了其他代码,在安装程序项目构建后修改msi文件,所以我使用了postbuildevent。请参考我的博客文章这里

1
遇到了完全相同的问题。VS在运行预构建步骤后不会重新加载vdproj,因此必须要么构建两次,要么使用后构建方法。 - OSH

1
我们使用一个程序,根据配置文件的值更新每个AssemblyInfo.cs或AssemblyInfo.vb。我们在每次构建之前运行此可执行文件。这是我们自动化此过程所能做到的最好的方式。您可以将此批处理过程的调用添加到项目配置中作为预构建步骤。

这可以通过使用前置条件包含在构建过程中。 - Joshua Lowry

0

我知道这是一个非常老的帖子,但这里有一个vbs解决方案来实现相同的目的。只需将其放置在您的部署文件夹旁边的.vdproj文件中。

Function CreateGuid()
    CreateGuid = Left(CreateObject("Scriptlet.TypeLib").Guid,38)
End Function

Const ForReading = 1, ForWriting = 2, ForAppending = 8

Set fso = CreateObject("Scripting.FileSystemObject")
Set RegEx = CreateObject("VBScript.RegExp")

For Each file in fso.GetFolder(".").Files
    if (fso.GetExtensionName(file.Name) = "vdproj") then
        WScript.Echo "Updating: " + file.Name
        Set oFile = fso.OpenTextFile(file.Name, ForReading, True)
        fileContents = oFile.ReadAll
        oFile.Close
        RegEx.Pattern = """ProductCode"" = ""8:{.*-.*-.*-.*-.*}"
        fileContents=Regex.Replace(fileContents, """ProductCode"" = ""8:" & CreateGuid)
        Set oFile = fso.OpenTextFile(file.Name, ForWriting, True)
        oFile.Write fileContents
        oFile.Close
    end if
Next

然后在您的实际项目中,有一个类似于以下的后构建事件:

cd $(SolutionDir)\CustomWebSetup
cscript -nologo UpdateProductCode.vbs

这将更新vdproj,为下一次构建做准备。构建完成后,VS会提示重新加载部署项目。


0

0
你可以使用msbuild任务来更新产品版本。请查看MSBuild团队关于此主题的这篇文章

现在(2012年)的AssemblyInfoTask在哪里? - Kiquenet

0

0

这可能不完全是您想要的,但在很久以前,我写了一个叫做stampver的东西,它可以作为后构建步骤直接在.exe文件中自动递增版本号。


-3

我使用git post-commit钩子更新源代码的版本信息。 - ashwoods

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接