【问题标题】:Embedding an application manifest into a VB6 exe将应用程序清单嵌入到 VB6 exe 中
【发布时间】:2010-02-02 08:57:20
【问题描述】:

我最近浏览了一堆用 VB6 编写的独立实用程序,以确保为 Windows Vista 及更高版本关闭注册表虚拟化。我为每个exe创建了一个独立的清单文件,适当地设置了requestedExecutionLevel(其中一些需要修改HKEY_LOCAL_MACHINE注册表项,其他不需要),并对其进行了测试。它们似乎都可以正常工作。

我只剩下一个小问题了。由于它们是独立的实用程序,人们习惯于在网络上复制它们并手动运行它们。如果有人忘记复制清单文件和 exe,那么 exe 将默默地写入虚拟化注册表项而不是真实注册表项,并导致难以调试的问题。

显而易见的解决方案是将清单作为资源嵌入到 exe 中。我在网上看到的所有文章都告诉你嵌入资源是这样的:

#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"

这应该可以正常工作,除了 VB 编译器总是创建资源 ID = 1 的应用程序图标。当我尝试上面的代码时,Windows 拒绝运行 exe,抱怨资源错误(我会更新这个稍后发布详细信息)。我尝试将资源 ID 更改为另一个数字,之后 Windows 成功运行程序但无法识别清单内容。

有谁知道让嵌入式清单在 VB6 exe 中工作的方法,还是我应该坚持使用外部文件?

更新 1

上面给出的文本是.rc 文件的全部内容。我将它编译成.res 文件,如下所示:

"%ProgramFiles%\Microsoft Visual Studio\VB98\Wizards\rc.exe" /r /fo "Resources.res" "Resources.rc"

并将其嵌入到 VB6 项目文件中,如下所示:

Type=Exe
Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\..\..\..\..\WINDOWS\system32\stdole2.tlb#OLE Automation
Form=Main.frm
ResFile32="Resources.res"
IconForm="FMain"
Startup="FMain"
HelpFile=""
Title="Windows Vista Registry Test - VB6"
ExeName32="RegistryTestVB6.exe"
Path32=""
Command32=""
Name="RegistryTestVB6"
HelpContextID="0"
CompatibleMode="0"
MajorVer=1
MinorVer=0
RevisionVer=0
AutoIncrementVer=0
ServerSupportFiles=0
VersionComments="Windows Vista Registry Test - VB6"
VersionCompanyName=""
VersionFileDescription="Windows Vista Registry Test - VB6"
VersionLegalCopyright=""
VersionProductName="Windows Vista Registry Test - VB6"
CondComp=""
CompilationType=0
OptimizationType=0
FavorPentiumPro(tm)=0
CodeViewDebugInfo=0
NoAliasing=0
BoundsCheck=0
OverflowCheck=0
FlPointCheck=0
FDIVCheck=0
UnroundedFP=0
StartMode=0
Unattended=0
Retained=0
ThreadPerObject=0
MaxNumberOfThreads=1

当我将编译好的exe读入VS2008资源编辑器时,是这样的:

RegistryTestVB6.exe
    Icon
        1 [Neutral]
    RT_MANIFEST
        1 [English (United States)]
    Version
        1 [English (United States)]

当我在 VS2008 中构建一个完全等效的 VB.NET 测试应用程序,然后将其加载到资源编辑器中时,它看起来像这样:

RegistryTestNET.exe
    Icon
        32512 [Neutral]
    RT_MANIFEST
        1 [Neutral]
    Version
        1 [Neutral]

更新 2

测试 - .NET exe 在 Windows XP 和 Windows 7 上都可以正常运行。但是,VB6 exe 在 XP 上会产生以下错误:

此应用程序无法启动,因为应用程序配置不正确。重新安装应用程序可能会解决此问题。

7 出现以下错误:

应用程序无法启动,因为它的并排配置不正确。请查看应用程序事件日志或使用命令行 sxstrace.exe 工具了解更多详细信息。

查看事件日志,我看到以下条目:

“RegistryTestVB6.exe”的激活上下文生成失败。第 10 行的清单或策略文件“RegistryTestVB6.exe”出错。无效的 Xml 语法。

不用说 XML 不是无效的,它与我用于 .NET exe 的具有相同编码的文件完全相同,并且该文件有效。

分辨率

VB6 编译器确实要求资源中包含的任意文本文件必须是 4 字节的精确倍数。我只是在 XML 中添加了空格,直到 Notepad++ 告诉我包括 BOM 在内的总文件大小是 4 的倍数。

感谢 Michael 和 Jim 为我指明了正确的方向。可惜我不能把你们俩都标记为答案!

【问题讨论】:

  • 不确定您的问题是什么,但不是图标。每类资源(RT_MANIFEST、RT_ICON)都有自己的 id 命名空间。你能给我们更多的 .rc 文件的文本吗?
  • 我隐约记得 XP 和 Vista 希望清单具有不同的资源 ID。尝试使用 RESOURCE_ID 2,或者可能将相同的清单放在 ID 1 和 ID 2 中。
  • @JohnKnoeller 资源ID实际上是有含义的,可以产生不同的结果,详见here。

标签: vb6 resources uac manifest


【解决方案1】:

有趣的是,我最近不得不做同样的事情。按照 Christian 描述的步骤,我第一次完成了它。为了繁荣,这是我遵循的整个工作流程:

  1. 按照原始问题中的描述创建了一个 RC 文件
  2. 创建了一个 app.manifest,保留了空白字符,这对于它的工作非常重要。如之前的答案所述,文件大小必须是 4 的倍数。

  3. 按照原始问题中所述针对 rc 运行 RC.EXE 以生成 .res 文件

  4. 编辑了我的 Project.VBP 文件以在顶部附近包含以下行:

ResFile32="Resources.res"

  1. 在标准 vb6 环境中构建 EXE。当部署在 vista 或 win7 机器上时,会显示盾牌并提示用户以管理员身份运行。在 Studio 中打开 EXE 文件时,我验证了资源。

  2. Notepad++ 告诉我 app.manifest 文件的编码是 ANSI。它在文件开头没有包含字节顺序标记。

如果您仍有问题,请告诉我,我会尽我所能与您分享。除此之外,除了Works on my Machine!,我不知道该告诉你什么

【讨论】:

    【解决方案2】:

    VB6 有一个怪癖,即任何资源元素的长度都必须是 4 的整数倍。尝试用空格填充清单文件以确保这一点,并查看是否会改变行为。

    这个怪癖记录在Microsoft article Q297112 (archive)。

    此外,您可以使用 VB6 IDE 添加资源,而不是编辑 VBP。效果可能一样,但资源编辑器是执行此操作的标准手段。

    【讨论】:

    • @JimMack 我知道根据我自己的经验这是正确的,但是您是否在任何地方(例如 Microsoft)看到过它的权威文档?
    • +1 谢谢,我一直在摆弄完全相同的问题,结果成功了!
    • @HolisticDeveloper 已在KB297112 中介绍过,但已在 SP5 及更高版本中修复。
    【解决方案3】:

    使用Resource Compiler (rc.exe) 会走很长一段路。有一个更简单的选项可以将应用程序清单嵌入到可执行文件中,无论是 C++ 还是 VB6 或几乎任何其他语言。 The Manifest Tool (mt.exe) 是专门为在二进制文件中嵌入清单而编写的,并随 Windows SDK 免费提供。使用 mt.exe 的另一个好处是它会自动处理任何必要的填充。

    在编译二进制文件后,只需运行以下命令行。我使用了 Visual C++ 2005 编译器内部使用的命名约定,其中清单文件名包含附加“.intermediate.manifest”的完整程序名称。

    mt.exe -nologo -manifest "program.exe.intermediate.manifest" -outputresource:"program.exe;#1

    更新:两年多来,我个人一直在使用 VB6 可执行文件的自动构建过程中使用它。它非常成功,以至于我们从回归测试中消除了操作系统兼容性测试(特定于清单)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 2012-08-07
      • 1970-01-01
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 2019-11-11
      相关资源
      最近更新 更多