1

我有一个使用 Visual Studio 2005 用 VB.Net 编写的应用程序。该应用程序允许用户创建和保存项目文件。当我分发应用程序时,我会包含一些演示项目文件,这些文件会安装在公共应用程序数据文件夹中。

XP - C:\Documents and Settings\所有用户\应用程序数据

Vista & 7 - C:\程序数据

我发现了一个意外行为——如果公共应用程序数据文件夹中的任何文件被删除,并且应用程序从开始菜单运行,那么安装过程将启动并尝试恢复丢失的文件。如果 MSI 文件不再存在于其原始位置或已更改,则应用程序将无法运行。我认为这是一个“功能”,但这是我不想要的。谁能告诉我发生了什么以及如何避免它?

更多细节:

  • 我使用 Visual Studio 部署项目创建了安装程序包。

  • 如果我直接启动 EXE,则不会发生此行为。因此,我希望该行为与开始菜单快捷方式有关。我注意到快捷方式不是普通的快捷方式——它没有“目标位置”。

感谢所有建议。

-TC

4

1 回答 1

1

我了解到这种行为涉及称为“按需安装”(又名“自我修复”)的东西。安装包创建的不寻常快捷方式称为“广告快捷方式”。现在我有了问题的名称,很容易找到有关如何解决它的信息。尤其:

这些页面包含大量信息。为了方便其他可能偶然发现这篇文章的人,我将总结他们所说的话:

广告快捷方式是做一些花哨的事情的特殊快捷方式。最值得注意的是,他们在启动目标之前重新安装损坏的应用程序。关于它们是善的、恶的还是无害的存在一些争论。在我看来,他们做了大多数用户没想到的事情,这让他们变得邪恶。因此,我想为我的应用程序禁用它们。

Visual Studio 安装项目会自动创建 MSI 包,默认情况下会生成广告的快捷方式。在安装 MSI 程序包时,通过使用 DISABLEADVTSHORTCUTS=1 作为 Setup.exe 的命令行参数很容易覆盖该默认值。此外,使用像 Orca 这样的实用程序,您可以通过插入 DISABLEADVTSHORTCUTS=1 作为 MSI 的属性来手动更改默认值。但是,如果您希望 Visual Studio 自动创建不创建广告快捷方式的 MSI 包,那就更难了。我是这样做的:

  1. 首先,我在上面的一个链接中使用 Gary Chang 提供的 DisableAdvt 代码创建了一个 VBS 文件(我在下面重复了该代码)。只需创建一个文本文件,粘贴代码。并将其保存为 DisableAdvt.vbs。

  2. 然后,为您的设置项目创建一个构建后事件。确切的语法将取决于您的文件位置。因为我的 DisableAdvt.vbs 位于解决方案文件夹的“工具”子文件夹中,所以我的构建后事件如下所示:

    • "$(ProjectDir)..\Tools\DisableAdvt\DisableAdvt.vbs" "$(BuiltOuputPath)"

这就是我必须做的。它就像一个魅力。

-TC

一些注意事项:

在 Visual Studio 2005 中,安装项目的生成事件的访问方式与其他类型的项目不同。单击解决方案资源管理器中的项目名称,然后在“属性”窗格中查找 PostBuildEvent。

Orca 是一个实用程序,可用于手动将 DISABLEADVTSHORTCUTS 属性插入 MSI 文件。使用我的方法,不需要 Orca。但是,它对于验证构建事件是否正在进行预期的更改很有用。

在构建事件中,拼写错误的“BuiltOuputPath”是故意的。

这是 Gary Chang 的 DisableAdvt.vbs 代码(请注意,我在第 21 行修正了一个错字——非常重要!):

Option Explicit

Const msiOpenDatabaseModeTransact = 1
Dim argNum, argCount:argCount = Wscript.Arguments.Count

Dim openMode : openMode =  msiOpenDatabaseModeTransact

' Connect to Windows installer object
On Error Resume Next
Dim installer : Set installer = Nothing
Set installer = Wscript.CreateObject("WindowsInstaller.Installer") :
CheckError

' Open database
Dim databasePath:databasePath = Wscript.Arguments(0)
Dim database : Set database = installer.OpenDatabase(databasePath, openMode) : CheckError

' Process SQL statements
Dim query, view, record, message, rowData, columnCount, delim, column

query = "INSERT INTO Property(Property, Value) VALUES ('DISABLEADVTSHORTCUTS', '1')"  
Set view = database.OpenView(query) : CheckError
view.Execute : CheckError

database.Commit

If Not IsEmpty(message) Then Wscript.Echo message
Wscript.Quit 0

Sub CheckError
  Dim message, errRec
  If Err = 0 Then Exit Sub
  message = Err.Source & " " & Hex(Err) & ": " & Err.Description
  If Not installer Is Nothing Then
    Set errRec = installer.LastErrorRecord
    If Not errRec Is Nothing Then message = message & vbLf & errRec.FormatText
  End If
Fail message
End Sub

Sub Fail(message)
  Wscript.Echo message
  Wscript.Quit 2
End Sub
于 2011-09-01T14:51:24.383 回答