Share via


How to: Embed a Manifest Inside a C/C++ Application 

It is recommended that a C/C++ application have its manifest embedded inside the final binary because this ensures proper runtime behavior in most scenarios. Visual Studio by default tries to embed the manifest when building a project from source files; see Manifest Generation in Visual Studio for more details. However if an application is built using nmake, some changes to the existing makefile are necessary. This section demonstrates how to change existing makefiles to automatically embed the manifest inside the final binary.

First let’s take a look at MyApplication.exe, which is a simple application built from one file using an nmake script as follows:

!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
!else
CPPFLAGS=$(CPPFLAGS) /MD
!endif

MyApplication.exe : MyApplication.obj
link $** /out:$@ $(LFLAGS)

MyApplication.obj : MyApplication.cpp

clean : 
del MyApplication.obj MyApplication.exe

If this script is run unchanged with Visual C++ 2005, it successfully creates MyApplication.exe. It also creates the external manifest file MyApplication.exe.manifest, for use by the operating system to load dependent assemblies at runtime.

However, it may be required to embed the manifest inside MyApplication.exe. There are several ways to achieve this. A simple way to do this is to embed the external manifest generated by the linker as a resource inside the final binary. This can be achieved by making the following changes to the nmake script file:

# Step 1. Adding _VC_MANIFEST_INC to specify which build is incremental (1 - incremental)
# Step 2. Adding _VC_MANIFEST_BASENAME used to specify name of a temporary resource file
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
_VC_MANIFEST_INC=1
_VC_MANIFEST_BASENAME=__VC80.Debug

!else
CPPFLAGS=$(CPPFLAGS) /MD
_VC_MANIFEST_INC=0
_VC_MANIFEST_BASENAME=__VC80

!endif

# Step 3. 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

#Step 4. Adding _VC_MANIFEST_EMBED_EXE - command to embedd manifest to 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

# Step 5. Changing command used to build EXE
MyApplication.exe : MyApplication.obj $(_VC_MANIFEST_AUTO_RES)
link $** /out:$@ $(LFLAGS)
$(_VC_MANIFEST_EMBED_EXE)


MyApplication.obj : MyApplication.cpp

# Step 6. Adding commands to generate initial empty manifest file, 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

# Step 7. Adding _VC_MANIFEST_CLEAN - command to clean generate files 
#         for temporary resources
!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

clean : 
del MyApplication.obj MyApplication.exe MyApplication.exe.manifest
$(_VC_MANIFEST_CLEAN)

Similar changes are required in the case of a library. In this case, the library MyLibrary.dll is built using the following script:

!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

In this case, the build script must change in a way similar to the case of the application. The manifest has to be embedded as a resource with ID equal to 2, instead of 1 as it was for MyApplication.exe.

# Step 1. Adding _VC_MANIFEST_INC to specify which build is incremental (1 - incremental)
# Step 2. Adding _VC_MANIFEST_BASENAME used to specify name of a temporary resource file
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /DLL /INCREMENTAL
_VC_MANIFEST_INC=1
_VC_MANIFEST_BASENAME=__VC80.Debug

!else
CPPFLAGS=$(CPPFLAGS) /MD
LFLAGS=$(LFLAGS) /DLL
_VC_MANIFEST_INC=0
_VC_MANIFEST_BASENAME=__VC80

!endif

#Step 3. 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

#Step 4. Adding _VC_MANIFEST_EMBED_DLL - command to embedd manifest into DLL

!if "$(_VC_MANIFEST_INC)" == "1"

MT_SPECIAL_RETURN=1090650113
MT_SPECIAL_SWITCH=-notify_update


_VC_MANIFEST_EMBED_DLL= \
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_DLL= \
if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2

!endif

# Step 5. Changing command used to build DLL
MyLibrary.dll : MyLibrary.obj $(_VC_MANIFEST_AUTO_RES)
link $** /out:$@ $(LFLAGS)
$(_VC_MANIFEST_EMBED_DLL)


MyLibrary.obj : MyLibrary.cpp

# Step 6. Adding commands to generate initial empty manifest file, RC file that references it
#         and for generating the .res file
# Note:  RT_MANIFEST has ID 2, because this is DLL.

$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc

$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
type <<$@
#include <winuser.h>
2RT_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

#Step 7. Adding _VC_MANIFEST_CLEAN - command to clean generate files for temporary resources
!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

clean : 
del MyLibrary.obj MyLibrary.dll MyLibrary.dll.manifest
$(_VC_MANIFEST_CLEAN)

See Also

Concepts

Understanding Manifest Generation for C/C++ Programs