将应用程序清单嵌入到VB6 exe中

时间:2010-02-02 08:57:20

标签: vb6 resources uac manifest

我最近浏览了一堆用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指出我正确的方向。可惜我无法将你们两个都标记为答案!

3 个答案:

答案 0 :(得分:9)

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

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

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

答案 1 :(得分:9)

有趣的是,我最近必须做同样的事情。按照克里斯蒂安描述的步骤,我第一次通过工作。为了繁荣,这是我遵循的整个工作流程:

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

  4. 如针对rc生成.res文件的原始问题中所述,运行RC.EXE

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

    ResFile32 = “Resources.res”

    1. 在标准vb6环境中构建EXE。部署在vista或win7计算机上时,屏蔽会显示,并提示用户以管理员身份运行。在工作室中打开EXE文件时,我验证了资源。

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

    3. 如果您仍然遇到麻烦,请告诉我,我会尽可能地与您分享。除此之外,我不确定除了Works on my Machine!

      之外还告诉你什么

答案 2 :(得分:7)

使用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可执行文件的自动构建过程中使用它已超过两年了。它非常成功,我们从回归测试中消除了操作系统兼容性测试 - 特定于清单。