将应用程序清单嵌入VB6 exe

将应用程序清单嵌入VB6 exe,vb6,resources,uac,manifest,Vb6,Resources,Uac,Manifest,我最近浏览了大量用VB6编写的独立实用程序应用程序,以确保Windows Vista及以上版本的注册表虚拟化已关闭。我为每个exe创建了一个独立的清单文件,适当地设置了requestedExecutionLevel(其中一些需要修改HKEY\U LOCAL\U MACHINE注册表项,其他则不需要),并对它们进行了测试。它们似乎都工作正常 我只剩下一个小问题。由于它们是独立的实用程序,人们习惯于在网络上复制它们并手动运行它们。如果有人忘记复制清单文件和exe,则exe将以静默方式写入虚拟化注册表

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

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

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

#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"
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
RegistryTestVB6.exe
    Icon
        1 [Neutral]
    RT_MANIFEST
        1 [English (United States)]
    Version
        1 [English (United States)]
这应该可以正常工作,除了VB编译器总是创建资源ID为1的应用程序图标。当我尝试上面的代码时,Windows拒绝运行exe,抱怨资源错误(稍后我将用详细信息更新本文)。我尝试将资源ID更改为另一个数字,之后Windows成功运行了该程序,但无法识别清单内容

有人知道如何让嵌入式清单在VB6 exe中工作,还是我应该只使用外部文件

更新1

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

#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"
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
RegistryTestVB6.exe
    Icon
        1 [Neutral]
    RT_MANIFEST
        1 [English (United States)]
    Version
        1 [English (United States)]
%ProgramFiles%\Microsoft Visual Studio\VB98\Wizards\rc.exe”/r/fo“Resources.res”“Resources.rc”

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

#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"
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
RegistryTestVB6.exe
    Icon
        1 [Neutral]
    RT_MANIFEST
        1 [English (United States)]
    Version
        1 [English (United States)]
当我将编译后的exe读入VS2008资源编辑器时,它如下所示:

#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"
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
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

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

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

以及7上的以下错误:

应用程序无法启动,因为其并行配置不正确。有关详细信息,请参阅应用程序事件日志或使用命令行sxstrace.exe工具

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

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

不用说XML不是无效的,它与我在.NET exe中使用的编码完全相同,并且有效

分辨率

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


感谢迈克尔和吉姆为我指明了正确的方向。很遗憾,我不能把你们两个都当作答案

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

这一怪癖在一本书中有记载


此外,还可以使用VB6 IDE添加资源,而不是编辑VBP。效果可能是一样的,但资源编辑器是实现这一点的标准方法。

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

  • 创建了一个RC文件,如原始问题中所述
  • 创建了一个app.manifest,保留了空格字符,这对于该操作非常重要。如前面的回答所述,文件大小必须是4的倍数

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

  • 编辑了my Project.VBP文件,以便在顶部附近包含以下行:
  • ResFile32=“Resources.res”

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

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

  • 如果你仍然有困难,让我知道,我会尽我所能与你分享。除此之外,我不知道该告诉你什么,除了使用。在可执行文件中嵌入应用程序清单有更简单的选择,无论是C++还是VB6,或者只是关于任何其他语言。是专门为在二进制文件中嵌入清单而编写的,并随Windows SDK免费提供。使用mt.exe的附加好处是它可以自动处理任何必要的填充

    编译完二进制文件后,只需运行以下命令行。我使用了VisualC++ 2005编译器内部使用的命名约定,其中清单文件名包含“.I.P.清单”的完整程序名。
    mt.exe-nologo-manifest“program.exe.intermediate.manifest”-输出资源:“program.exe;#1

    更新:我个人已经在VB6可执行文件的自动生成过程中使用了两年多。它非常成功,我们已经消除了