Starting to pull the understanding of Manifests together.

Published June 26, 2010
Advertisement
If you are writing an application in c++ application in visual studio you will
typically be linking against the "microsoft c runtime."

If you look in your windows\system32 folder you will see a few of these.
...Directory of C:\Windows\System3207/13/2009  09:15 PM           149,019 crtdll.dll07/13/2009  09:15 PM           690,688 msvcrt.dll07/13/2009  09:15 PM           253,952 msvcrt20.dll07/13/2009  09:07 PM            60,928 msvcrt40.dll...


This looks innocent enough. All of these files are old though.
Where are the new ones? Why did the move?

The where is easy: \windows\winsxs
... Directory of C:\Windows\winsxs\x86_microsoft-windows-msvcrt_31bf3856ad364e35_6.1.7600.16385_none_d12b8c440039b31e07/13/2009  09:15 PM           690,688 msvcrt.dll...


Conceptually the why is necessary: one of the major vulnerabilities
of earlier versions of windows was "dll hell." If a given application
installs a library to \windows\system32 and another overwrites it
there is now a knot where two different apps collide in their library
dependencies.

The old trick was to try to update to the newest version of the dll
and hope that it worked for both. Unfortunately, that was the best
idea in an impossible situation. If an interface changed between
two library versions then you are simply boned.

MS Project Fusion to the rescue! Windows XPSP2 introduced manifests
the ActCtx API and the \windows\winsxs directory. Now, applications should never
install anything dlls to \windows\system32. Everything should be versioned and
go in \windows\winsxs.

Winsxs is a like a database with multiple keys. For an assembly
to be installed to winsxs it must meet the following requirements:

1) The assembly must have an a "SxS Manifest"

a) The manifest must have an "Assembly Identity"
*) The identity must have a name.
*) The identity must have a version.
*) The identity must have a type.
*) The identity must have a publicKeyToken.
*) The identity must have a processorArchitecture
*) The identity may have a language [defaults to en]
*) The identity may have a culture [defualts to neutral]

b) The manifest must have entries for each file in the assembly
*) The must have a hash
*) The must have a for every COM class
*) The must have a for every COM interface.

2) The assembly must have a security cabinet.
3) The assembly must be installed into WinSxS with a MSI installer.
4) All exe's, dll's, and the security cabinet must be signed with
a trusted 2048bit certificate.
5) The assembly may have an optional policy to route versions.


Things to note here: Authenticode certificates are 1024bit only and will not
work. You will need to extract your public key token from your code signing
certificate. To make a SxSManifest from C++ you need to feed mt.exe your tlb
and rgs files. To make a SxSManifest from an ocx or a dll you don't have the
source too: you will need to use "regsvr42" to probe the interfaces. I've gone
over how to do all these in my last two weeks entries,
review them for more information.


As difficult as it is to make a WinSxS install: the "Assembly Identity" shows
the true power of it. I've already been spouting about Reg Free COM and
installing multiple simultaneous versions. But look, we also can target 32bit or
64bit by just changing the manifest entry. We can have 32bit and 64bit installed
on the same machine at the same time with the same GUIDS! The client application
just needs a different dependency manifest to select one versus another.
I've not had to use them, but these same manifest tricks allow you to install
multiple language and cultures.


Implications on dependencies:
Manifests go hand in hand with static imports. If you are a windows developer
you have probably used depends.exe. If you have used it recently, you may
have noticed that there are yellow bangs beside some of your import dlls.



Look at that! It claims that it can't find the C runtime! The reason for this
should be obvious: our application uses a manifest to find the C runtime.
Manifests are scripts to program the ActCtx API -- which only exists at
runtime.
Depends literally has no way of knowing how to find that dll
since you can edit your manifest to target any version you want.

Like I said a long time ago, If you are using visual stdudio 2005 or higher
you have been using the ActCtx API all along without knowing it. In you look
in your build directory you will notice that the linker automatically produced
a file called MyApp.intermediate.manifest. Depending on what standard libraries
you linked to, it will look something like this:

                                                                                          


[With the default compiler settings with file will get embedded as an RT_MAINFEST
at CREATEPROCESS_MANIFEST_RESOURCE_ID for an exe or ISOLATIONAWARE_MANIFEST_RESOURCE_ID for a dll.]

That last entry has our C runtime link!
Linking to that lib causes a static import to exist in our application but
it relays on the ActCtx at runtime to do the mapping!

For our custom dll's we need to be able to advertise entries like that so
that client applications can find us in winsxs. Unfortunately, there is no
tool in visual studio 2005 to do so.

In an earlier post, I had you start moving your winsxs build process
to the pre and post build steps. You need a batch file that is something like
this:
MakeDLLIntoAssembly [RTMBroker Directory] [Component Directory] [Component name] [Component Filename] [Component TLB] [Component Version] [Component PublicKey] [CertName]"


Lets look at my script:
@echo offrem begin MakeDLLIntoAssembly.batif "%1" == "" goto errorcd %2attrib -r %4echo Preparing Files for %3 RTM Distribution.rem Build the required Assembly Identity, and extract Reg Free COM info From the TLB and RGS%1\bin\mt /nologo -rgs:RTM.rgs -tlb:%5 -dll:%4 -identity:"MyCompanyName.%3, processorArchitecture=x86, version=%6, type=win32, publicKeyToken=%7" -out:%4.sxs.manifestrem The vs2005 linker will have produced the intermediate manfiest, merge it with the one we created to make a complete one [gives us c runtime, etc]%1\bin\mt /nologo -manifest %4.sxs.manifest %4.intermediate.manifest -out:%4.manifest%1\bin\mt /nologo -manifest %4.manifest -outputresource:%4;2rem Sign our output with the 2048 bit cert%1\bin\signcode -spc %1\Signing\ssl-cert.crt -v %1\Signing\ssl-cert.pvk -t http://timestamp.verisign.com/scripts/timstamp.dll -n "Company Name" -i "http://" %4rem Now that we signed it, the file hash will have changed. Re-hash for security to validate.%1\bin\mt /nologo -manifest %4.manifest -hashupdate -out:%4.manifestrem Make the security cabinet%1\bin\mt /nologo -manifest %4.manifest -makecdfs%1\bin\makecat %4.manifest.cdfrem Sign the cabinet with the 2048bit cert%1\bin\signcode -spc %1\Signing\ssl-cert.crt -v %1\Signing\ssl-cert.pvk -t http://timestamp.verisign.com/scripts/timstamp.dll -n "Company Name" -i "http://" %4 %4.catrem intermediate file.del %4.sxs.manifestrem applications have to be able to reference us as a dependencyrem mt sadly lacks this option directly, so we have to fake itecho Making Dependeny Manifestecho ^ > %4.dependentassembly.manifestecho ^ >> %4.dependentassembly.manifestecho ^ >> %4.dependentassembly.manifestecho ^ >> %4.dependentassembly.manifestecho ^ >> %4.dependentassembly.manifestecho ^ >> %4.dependentassembly.manifestecho ^ >> %4.dependentassembly.manifestecho ^

>> %4.dependentassembly.manifest

:error
echo Usage MakeDLLIntoAssembly [RTMBroker Directory] [Component Directory] [Component name] [Component Filename] [Component TLB] [Component Version] [Component PublicKey] [CertName]"

:end


If you read the comments in the code: it will give you all the required pieces for a sxs install. I omitted the code for embedding the interop dll's. I'll
come back to that in a future entry.


One of the important tricks here is the "dependency manifest." Lets look
at the output of what it makes:
  	 		 			 		 	  


Its a just a finger print...
Now to use it when you build your application or game, the linker will give you
the standard intermediate like the one above.

If you add:
mt -manifest mygame.intermediate.manifest MyRenderingEngine.dependency.manifest (-out:MyGame.exe.manifest or -outputresource:mygame.exe;2)"


To your post build step, the manifest tool with merge the two manifest snippets
into one and give you a finalized manifest that looks like:
                                                                                          		 			 		 	




Now the ActCtx API knows how to find us if we are in winsxs!

If you have a series of libraries: MyRenderer.dll, MyAIEngine.dll,
MyNetworkEngine.dll, etc. You will just need to loop over the mt call
and keep concatenating them together. [The manifest tool only accepts two
manifests at a time, you will have to use an intermediate file.]

After these steps you may still have to tweak your manifest a little more.
If you are running on vista/7 and you need the application to run as
administrator you have to add:


We still have to go over a few topics to finalize this discussion: "local"
assembly manifests, using an MSI to install into WinSXS, and finalizing our
making our interop dll's use reg free com.
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement