6

我面临以下问题场景:

  • 以正常方式构建 MSI,例如:MyTest.msi
  • 重命名它,保留 msi 扩展名。例如:MyTest_V1.0.0.msi
  • 测试它,它工作。安装成功。
  • 再次重复过程。这次重命名为 ex:MyTest_V2.0.0.msi
  • 对其进行测试,当文件位于本地磁盘上时,它会因“网络错误”而失败。

"尝试从文件 MyTest_V1.0.0.msi 读取时发生网络错误"

什么给出了,我们不能简单地重命名一个 MSI 文件吗?有什么问题可以阻止这种情况吗?现在我陷入了困境。请指导。

致以最崇高的敬意,穆罕默德·穆巴希尔。

4

3 回答 3

2

当您重命名 MSI 文件并且不希望它在使用原始 MSI 文件进行任何安装时出现问题时,我建议您更改重命名文件中的一些摘要信息和属性。我通常修改:

  • 包代码,一个 GUID,它需要一个新的 GUID
  • ProductName 属性需要不同的名称
  • ProductCode,另一个 GUID,需要一个新的 GUID

如果可以找到,您可以使用 Microsoft 的 Orca 数据库编辑器来修改这些属性。

这是一篇介绍如何使用 Orca 数据库编辑器编辑 Windows Installer 文件的文章:https: //support.microsoft.com/en-us/kb/255905

以下是一些其他详细信息:https ://msdn.microsoft.com/en-us/library/windows/desktop/aa370557(v=vs.85).aspx

  • 某些系统(具有较旧版本的 Windows SDK 将在 \Program Files (x86)\Microsoft SDKs\Windows\v7.0\Bin\Orca.msi 安装 Orca
  • 2010 或更早的 Windows SDK 应该有它。
于 2016-02-08T14:34:31.467 回答
1

重命名 MSI 文件没有限制。

但是还有其他陷阱,例如更新 MSI,其中一些甚至包括重命名。如果您想使用所谓的“小更新”或“小升级”来更新 MSI 文件,重命名 MSI 文件不是一个好主意!

你写

•测试它,它的工作原理。安装成功。•再次重复过程。

如果您在两者之间卸载了旧的 MSI(这将是一个解决方案)或者您的 V2.0 MSI 应该是什么类型的更新,我什么也没读。

如果您不了解 MSI 升级细节,请先告知更新类型,提到的两个以及“主要升级”。后者的陷阱比前两个少一点 :-) (补丁升级在你真正有经验之前我会忽略。)你可以在更新中做很多错误的事情。一定要有真正对MSI有经验的人加入,否则迟早会有麻烦。

通常,如果您正在寻找像您这样的问题,请输出一个日志文件。您会在那里找到描述的错误,但通常会有更多信息。

于 2013-07-09T14:58:30.710 回答
0

我自己找到了解决方案。这就像网站安装程序设置的教程。**

步骤: 对于网站设置,您必须安装 webDeployemnt 设置,然后从 VS 添加 WebDeployemnt 项目和此 webProject ADD 作为 etup 项目中的参考。示例:来自 WebDeploy 项目的预编译 Web Putput。

黑白网站和 Web 应用程序的区别。网站有多个程序集并且没有 .sln 文件。WebApp 具有 .sln 文件,因此所有程序集合并为一个。

1-设置设置属性:

  • RemovePreviousVersion 真。
  • DetectNewerVersionInstalled 错误。

2- 在安装项目的 postbuild 事件中使用 vbScript 或 c# 代码;

  • 更改 MSI 的产品版本。
  • 更改您的 MSI 的产品代码。新的 Guid 32 字符。
  • 将 MaxVersion 设置为您的新版本。这在 MSI 的升级表中可用。
  • 确保 UpgradeCode 在所有情况下都必须相同。意味着当心不要改变它。

下面我发布了 VbScript PBE.vbs 和 C# 代码。

从这里帮助 webLinks 我有一个想法来克服我的问题: https ://www.simple-talk.com/dotnet/visual-studio/updates-to-setup-projects/

从 MSIProject 的 PostbuildEvent 调用 PBE.vbs。cscript //nologo "$(ProjectDir)PBE.vbs" "$(BuiltOuputPath)"

Dim pInstaller
    Set pInstaller = CreateObject("WindowsInstaller.Installer")    
    Dim pDatabase
    Set pDatabase = pInstaller.OpenDatabase(WScript.Arguments(0), 2)

    Dim pView1
    Set pView1 = pDatabase.OpenView("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductVersion'")
    pView1.Execute   
    Dim pRecord1
    Set pRecord1 = pView1.Fetch 
    If (Not pRecord1 Is Nothing) Then
        pRecord1.StringData(1) = "1.0.5"    
    Else
        MsgBox "Error during ProductVersion."
    End If  
    pView1.Modify 4, pRecord1
    pView1.Close
    'MsgBox "Product Version is: " + pRecord1.StringData(1) 

    Dim pView3
    Set pView3 = pDatabase.OpenView("SELECT VersionMax FROM Upgrade")
    pView3.Execute    
    Dim pRecord3
    Set pRecord3 = pView3.Fetch 
    If (Not pRecord3 Is Nothing) Then       
        pRecord3.StringData(1) = pRecord1.StringData(1)
    Else
        MsgBox "Error during VersionMax."
    End If  
    pView3.Modify 4, pRecord3
    pView3.Close
    MsgBox "VersionMax is: " + pRecord3.StringData(1)

    Dim pView2
    Set pView2 = pDatabase.OpenView("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")
    pView2.Execute    
    Dim pRecord2
    Set pRecord2 = pView2.Fetch 
    If (Not pRecord2 Is Nothing) Then       
        pRecord2.StringData(1) = CreateGUID()
    Else
        MsgBox "Error during ProductCode."
    End If  
    pView2.Modify 4, pRecord2
    pView2.Close

    'MsgBox "Product Code is: " + pRecord2.StringData(1)    

    pDatabase.Commit


Function CreateGUID
  Dim TypeLib
  Set TypeLib = CreateObject("Scriptlet.TypeLib")
  CreateGUID = Left(TypeLib.Guid, 38)
End Function

用于重命名 msi 文件的 C# 控制台应用程序代码。

首先,您必须在新控制台应用程序中添加参考。那是 tlbimp.exe 生成的 .NET 包装器,包装了 ActiveX 组件 c:\windows\system32\msi.dll。您可以让 IDE 为您制作一个,使用 Project + Add Reference,COM 选项卡,选择“Microsoft Windows Installer Object Library”。

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using WindowsInstaller;
using System.Diagnostics;


// 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 RenameMSI
{
    [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();
                 msiFilePath = @"D:\TEST Projects\TestWebsites\MsiSetupForAsp.netApp\TestWebApplicationSetup\Debug\TestWebApplicationSetup.msi";
            }
            else
            {
                Console.WriteLine("Argument Received args[0]: " + args[0]);
                msiFilePath = args[0];                
            }


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

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

                }
            }

            Program p = new Program();
            string VersionMax = p.GetMsiVersionProperty(msiFilePath, "ProductVersion");
            string productName = p.GetMsiVersionProperty(msiFilePath, "ProductName");

            p.SetMsiProperty(msiFilePath, "ProductVersion", "mub.sni");
            p.SetMsiProperty(msiFilePath, "ProductName", "mub.sni");
            //p.setMaxVersion(msiFilePath, );

            //p.RenameMSI(msiFilePath);

            #endregion

            #region old code.
            //String inputFile = @"C:\\Install1.msi";
            //// Get the type of the Windows Installer object 
            //Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");

            //// Create the Windows Installer object 
            //Installer installer = (Installer)Activator.CreateInstance(installerType);

            //WindowsInstaller.Installer ins = (WindowsInstaller.Installer)new Installer();

            //string MSIpath = @"";

            //Database db = ins.OpenDatabase(MSIpath, WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly); //// Open the MSI database in the input file 

            //// Open a view on the Property table for the Label property 
            //View vw = db.OpenView(@"SELECT * FROM Property WHERE Property = 'ProductVersion'");  // I'd like to pull from other tables besides Property as well

            //vw.Execute(null); // Execute the view query 

            //Record record = vw.Fetch(); // Get the record from the view 

            ////// Get the Label from the data 
            //string Label = record.get_StringData(2);
            //String[] a = Label.Split('.');

            //string MajorNumber = a[0];
            //string MinorNumber = a[1];

            //int RevisionNumber = 0;
            //int.TryParse(a[a.Length - 1], out RevisionNumber);
            //RevisionNumber++;

            //Console.WriteLine("Before " + record.get_StringData(1) + ": " + record.get_StringData(2));
            //record.set_StringData(a.Length - 1, String.Concat(MajorNumber, ".", MinorNumber, ".",  RevisionNumber.ToString()));

            //Console.WriteLine("After " + record.get_StringData(1) + ": " + record.get_StringData(2));
            //while (record != null)
            //{
            //    Console.WriteLine(record.get_StringData(1));
            //    record.set_StringData(1, RevisionNumber.ToString());

            //    record = vw.Fetch();
            //}

            //vw.Modify(MsiViewModify.msiViewModifyMerge, record);

            //vw.Close();
            //db.Commit();
            #endregion


            //Console.Read();
        }
        private void setMaxVersion()
        {
        }
        private void RenameMSI(string msiFilePath)
        {
            StringBuilder sb = new StringBuilder();
            string[] words = msiFilePath.Split('\\');
            foreach (string word in words)
            {
                sb.Append(word + '\\');

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

                }
            }

            Program p = new Program();
            string VersionMax = p.GetMsiVersionProperty(msiFilePath, "ProductVersion");
            string productName = p.GetMsiVersionProperty(msiFilePath, "ProductName");

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


            System.IO.File.Move(msiFilePath, newMSIpath);
        }
        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);
            //string sql = "SELECT * FROM Upgrade"; // "SELECT VersionMax FROM Upgrade"

            View view = db.OpenView(sql);
            //View view = 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;
        }
        private string SetMsiProperty(string msiFilePath, string property, string value)
        {
            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.msiOpenDatabaseModeTransact); //// 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)
            {
                record.set_StringData(1, value);


            }

            view.Modify(MsiViewModify.msiViewModifyReplace, record);
            view.Close();
            db.Commit();

            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(record);
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(view);
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(db);

            return retVal;
        }
        static string GetMsiProperty(string msiFile, string property)
        {
            string retVal = string.Empty;
            return retVal;
        }
    }
}
于 2013-07-12T11:21:00.410 回答