How to programatically change a project's prod

2019-01-17 23:13发布

问题:

Here is my problem:

I have several deployment projects. In order to deploy an application, I need to do several tasks, one of them is to change each deployment project's product version and product code.

I can't find a way to programatically change them.

Can anyone help me ?

Thanks in advance.

UPDATE: Since it's a Deployment project (which finally produces an executable installer), I'm not able to work with MSBuild, instead I'm using the Devenv from the command prompt. (Bruno, thanks for your quick response).

回答1:

I was searching for the exact same thing today. I found this using google:

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(); 
    } 
 }


回答2:

I know that the original poster is looking for a .NET 2.0 solution to this problem. However, since this wasn't tagged as .NET, I'll offer up my C++ solution to the problem. This may be applicable in .NET land, but I'll leave that to others.

This not only updates the version information in the about box and log file for my application, but also all of the Windows version info that is seen in Windows Explorer.

UPDATE: Added some changes that I've made to the process since my original answer.

First off, I moved the entire version info block from my Project.rc file to my Project.rc2 file:

/////////////////////////////////////////////////////////////////////////////
//
// 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

This essentially transports all of the version info stuff that you would edit from the resource editor into a separate file. This makes it so that you don't get errors when editing the resource file from outside of the editor. The downside is that you can no longer edit the version info from the resource editor. But, since we want this stuff updated automatically, that isn't a big deal.

Next, I created a VersionInfo.h file and added it to my project:

#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."

I then included VersionInfo.h in the rc2 file and made the following changes:

#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>

With this setup, I could edit my build script (which uses Perl) to modify the version info in the VersionInfo.h file before rebuilding the entire project using the devenv command line.

One additional step that I added that may also be of interest (although it is not completely perfected yet, and may be a future question here) is to generate a unique build number every time the project is built. In the current incarnation, it always works for complete rebuilds, but only sporadically on incremental builds. What I did was create a file called build_number.incl that contains the following:

#define CurrentBuildNumber  "20081020P1525" 

Which is essentially the date and time that the build was started. I created a batch file that is run as a pre-build event to the project that generates this file. The script also defines BuildYear so that the copyright in the VersionInfo.h file always contains the year of the most recent build. The batch script is the following:

    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 ----------------------------------------------------------------------

This file is then included in any file in the project that needs to use the build number (i.e. the about box).

Some of this was gleaned from this CodeProject post.

Hopefully this info proves helpful.



回答3:

I had the same problem, and I found out that modifying the .vdproj file in a prebuildevent does not exactly do what I like.

I used some other code to modify the msi file file after the the setup project has been build, so I use the postbuildevent.

See my blog-post here.



回答4:

We use a program that updates each AssemblyInfo.cs or AssemblyInfo.vb based on a configuration file value. we run this executable before each build. That was the best we could do to automate this process. You can add a call to this batch process in your projects configuration as a pre build step.



回答5:

You could use the msbuild task to update you product version. Check out this post from the MSBuild team on this subject.



回答6:

Embedding SVN Revision number at compile time in a Windows app

In my answer to this question, I describe how I accomplish this task using SVN.



回答7:

This may not be quite what you're after, but way back in the mists of time I wrote something called stampver, which can auto-increment a build number directly in the .exe file as a post-build step.



回答8:

Resource Tuner Console

This console resource editor allows creating a reliable and repeatable process for updating Product Version Information resources during the final stage of the build process from the command prompt.

See specifically the batch manipulation of file version information page for greater details:

  • http://www.reseditor.com/rtc-solution-version-info.htm


回答9:

Do it from within a batch file?



回答10:

I know this a very old thread, but here's a vbs solution to achieve the same end. Simply place this in your deployment folder next to the .vdproj file.

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

Then in your real project, have a post build event similar to:

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

This will update the vdproj with a new ProductCode in preparation for the next build. After the build is complete, VS will prompt for a reload of the deployment project.



回答11:

Look into the use of RCS, CVS and/or subversion. I am only familiar with RCS; my understanding is that CVS is based on RCS but more comprehensive. I have read on various boards that subversion is the better, but I have never used it. RCS has been adequate for keeping track of changes and versions on all my documents and software projects.

RCS is here: http://www.cs.purdue.edu/homes/trinkle/RCS/

CVS is here: http://www.nongnu.org/cvs/

Subversion is here: http://subversion.tigris.org/