如何:将清单嵌入到 C/C++ 应用程序更新:2007 年 11 月 建议 C/C++ 应用程序(或库)将其清单嵌入最终的二进制文件中,因为这可以确保运行时行为在多数情况下正确无误。默认情况下,当 Visual Studio 从源文件生成项目时,会尝试嵌入清单;有关更多信息,请参见 Visual Studio 中的清单生成。但是,如果应用程序是通过使用 nmake 生成的,则需要更改现有的生成文件。本节演示了如何更改现有的生成文件,以便将清单自动嵌入最终二进制文件中。 有两种方法可将清单嵌入应用程序或库中。
下面的示例说明如何更改生成文件以将两种方法相结合。 请看 MyApp.exe 的 nmake 脚本,它是一个很简单的仅由一个文件生成的应用程序: # build MyApp.exe !if "$(DEBUG)" == "1" CPPFLAGS=$(CPPFLAGS) /MDd LFLAGS=$(LFLAGS) /INCREMENTAL !else CPPFLAGS=$(CPPFLAGS) /MD !endif MyApp.exe : MyApp.obj link $** /out:$@ $(LFLAGS) MyApp.obj : MyApp.cpp clean : del MyApp.obj MyApp.exe 如果此脚本不经更改便在 Visual C++ 2005 上运行,它将成功创建 MyApp.exe。它还将创建外部清单文件 MyApp.exe.manifest,操作系统会使用此外部清单文件在运行时加载依赖程序集。 MyLibrary.dll 的 nmake 脚本与之很相似: # build MyLibrary.dll !if "$(DEBUG)" == "1" CPPFLAGS=$(CPPFLAGS) /MDd LFLAGS=$(LFLAGS) /DLL /INCREMENTAL !else CPPFLAGS=$(CPPFLAGS) /MD LFLAGS=$(LFLAGS) /DLL !endif MyLibrary.dll : MyLibrary.obj link $** /out:$@ $(LFLAGS) MyLibrary.obj : MyLibrary.cpp clean : del MyLibrary.obj MyLibrary.dll 若要使用嵌入的清单来执行生成,则必须对原始生成文件进行四处小改动。对于 MyApp.exe 生成文件: # build MyApp.exe !include makefile.inc #^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.) !if "$(DEBUG)" == "1" CPPFLAGS=$(CPPFLAGS) /MDd LFLAGS=$(LFLAGS) /INCREMENTAL !else CPPFLAGS=$(CPPFLAGS) /MD !endif MyApp.exe : MyApp.obj link $** /out:$@ $(LFLAGS) $(_VC_MANIFEST_EMBED_EXE) #^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2 MyApp.obj : MyApp.cpp clean : del MyApp.obj MyApp.exe $(_VC_MANIFEST_CLEAN) #^^^^^^^^^^^^^^^^^^^^^^^^ Change #3 !include makefile.targ.inc #^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.) 对于 MyLibrary.dll 生成文件: # build MyLibrary.dll !include makefile.inc #^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.) !if "$(DEBUG)" == "1" CPPFLAGS=$(CPPFLAGS) /MDd LFLAGS=$(LFLAGS) /DLL /INCREMENTAL !else CPPFLAGS=$(CPPFLAGS) /MD LFLAGS=$(LFLAGS) /DLL !endif MyLibrary.dll : MyLibrary.obj link $** /out:$@ $(LFLAGS) $(_VC_MANIFEST_EMBED_DLL) #^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2. MyLibrary.obj : MyLibrary.cpp clean : del MyLibrary.obj MyLibrary.dll $(_VC_MANIFEST_CLEAN) #^^^^^^^^^^^^^^^^^^^^^^^^ Change #3. !include makefile.targ.inc #^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.) 生成文件现在包含两个执行实际工作的文件,它们是 makefile.inc 和 makefile.targ.inc。 创建 makefile.inc,然后将以下内容复制到该文件中: # makefile.inc -- Include this file into existing makefile at the very top. # _VC_MANIFEST_INC specifies whether build is incremental (1 - incremental). # _VC_MANIFEST_BASENAME specifies name of a temporary resource file. !if "$(DEBUG)" == "1" CPPFLAGS=$(CPPFLAGS) /MDd LFLAGS=$(LFLAGS) /INCREMENTAL _VC_MANIFEST_INC=1 _VC_MANIFEST_BASENAME=__VC90.Debug !else CPPFLAGS=$(CPPFLAGS) /MD _VC_MANIFEST_INC=0 _VC_MANIFEST_BASENAME=__VC90 !endif #################################################### # Specifying name of temporary resource file used only in incremental builds: !if "$(_VC_MANIFEST_INC)" == "1" _VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res !else _VC_MANIFEST_AUTO_RES= !endif #################################################### # _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE: !if "$(_VC_MANIFEST_INC)" == "1" #MT_SPECIAL_RETURN=1090650113 #MT_SPECIAL_SWITCH=-notify_resource_update MT_SPECIAL_RETURN=0 MT_SPECIAL_SWITCH= _VC_MANIFEST_EMBED_EXE= if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" rc /r $(_VC_MANIFEST_BASENAME).auto.rc & link $** /out:$@ $(LFLAGS) !else _VC_MANIFEST_EMBED_EXE= if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1 !endif #################################################### # _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily: !if "$(_VC_MANIFEST_INC)" == "1" _VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res $(_VC_MANIFEST_BASENAME).auto.rc $(_VC_MANIFEST_BASENAME).auto.manifest !else _VC_MANIFEST_CLEAN= !endif # End of makefile.inc #################################################### 现在,创建 makefile.targ.inc,然后将以下内容复制到该文件中: # makefile.targ.inc - include this at the very bottom of the existing makefile #################################################### # Commands to generate initial empty manifest file and the RC file # that references it, and for generating the .res file: $(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc $(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest type <<$@ #include <winuser.h> 1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest" << KEEP $(_VC_MANIFEST_BASENAME).auto.manifest : type <<$@ <?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> </assembly> << KEEP # end of makefile.targ.inc |
|