January 21, 2011

You Too Can Make A CoApp Package

We want to get everyone involved in improving and using the CoApp toolkit so I’m writing this blog post to give everyone a taste of the process for building a CoApp package. It’s not pretty and it’s not perfect right now but it’s a start and we’d appreciate any help you can provide!


Before you get stared, you need to have these programs installed:

  • Visual Studio 2010
  • Windows SDK 7.0 or higher -- http://bit.ly/bOoxJT
  • Windows WDK 7.1 -- http://bit.ly/cU1lvH
  • Bazaar for Windows 2.2.0 -- http://bit.ly/d0CSvw (get the standalone installer)

Once you’ve done that, go to command line and perform the following commands:

cd c:\projects (or wherever you want to checkout the code)
md coapp
cd coapp
bzr branch lp:coapp-solution
bzr branch lp:coapp-toolkit
bzr branch lp:coapp-bootstrap
bzr branch lp:coapp-mkpackage

Open the CoApp solution in coapp-solution and build everything. Move the coapp-bootstrap.exe file from the output\x86\debug\bin folder to the output\any\debug\bin folder. We’re ready to get started!

Making a package

Let’s say you want to create a CoApp library called FunLib so developers can use all the neat functionality you’ve developed in it. All FunLib consists of is a DLL file named “funlib.dll.” You’ve built it for the x86 architecture (also called Win32). To turn this library into a CoApp package you’re going to need to create an XML file that the mkPackage tool can read.

We’ll create and a file named “funlib.xml” with the following content to get started on our package:

1 <Package xmlns="http://coapp.org/ns/mkPackage.xsd"
2 Name="FunLib"
3 Version=""
4 Arch="x86">
5 </Package>

This is the shell of what will become our package file. I’ll go through each of the lines in step.

Line one simply contains the beginning of the package description with a namespace declaration. You NEED to have this xmlns tag in with that exact value. If you do not, mkPackage will reject your package!

Line two has the Name attribute which is the name of your package that CoApp uses internally. Your package name may not have spaces in it. Use an underscore instead if you want that. There is a way of having a prettier display name that a user might see in the package manager; we’ll describe that later.

Line three contains the Version attribute which holds the version of your package. The version of your package has to be of the format x.x.x.x where x is any whole number between 0 and 65534, inclusive. Let’s say though your library uses a different versioning system that includes letters, say like “Vista.” There’s also a way to display that version “number” to the package manager user, however you NEED to use a version number here like the type described.

The Arch attribute on line four is where you set the type of architecture your package is designed for. If your package is a native program, probably build in C or C++, you need to say the type of architecture it was built for. In our case you build FunLib for the x86 architecture so that’s what we put in Arch. If you built it for x64, you enter “x64” instead. If the package works on any architecture, like it if it were .NET based, you would use “any” however that hasn’t been tested even once yet so suffice it to say, it don’t work. :)

Now that we’ve got the shell of our package description set up, let’s add a role; in this case, SharedLib.

1 <Package xmlns="http://coapp.org/ns/mkPackage.xsd"
2 Name="FunLib"
3 Version=""
4 Arch="x86">
5 <SharedLib>
6 </SharedLib>
7 </Package>

Each package must have one or more roles but there may only be one role per type. SharedLib is one of the types and, as one would expect, it’s for libraries that you want to be used by other libraries or programs. There’s also an AppRole which is for runnable applications and a few more which I’ll discuss in the future.

Next we’ll add the Publisher element:

1 <Package xmlns="http://coapp.org/ns/mkPackage.xsd"
2 Name="FunLib"
3 Version=""
4 Arch="x86">
5 <Publisher Name="Publisher Name" PublicKeyToken="Publisher PKT" />
6 <SharedLib>
7 </SharedLib>
8 </Package>

The Publisher element describes who is creating the package. The Name and PublicKeyToken attributes correspond to the common name and public key token of the code signing certificate signing the package which you will pass in when you run mkPackage. (Remember CoApp packages must be signed!)

Let’s actually add our DLL to the package:

1 <Package xmlns="http://coapp.org/ns/mkPackage.xsd"
2 Name="FunLib"
3 Version=""
4 Arch="x86">
5 <Publisher Name="Publisher Name" PublicKeyToken="Publisher PKT" />
6 <SharedLib>
7 <Assembly Arch="x86" Src="funlib.dll" Platform="win32">
8 </Assembly>
9 </SharedLib>
10 </Package>

In CoApp, SharedLib roles internally use Windows Side-by-Side or .NET assemblies to handle shared libraries. Set your Arch to “x86” in this case and for Platform enter “win32.” The Src attribute contains the path to your DLL file.

To be an assembly, your library needs to have a manifest, it’s DLL must be signed and have a security catalog. Let’s create a file named funlib.dll.manifest (in the same directory as funlib.dll) to get started:

1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3 <assemblyIdentity type="win32" name="funlib" version=""
4 processorArchitecture="x86"
5 publicKeyToken="Publisher PKT"></assemblyIdentity>
6 <file name="funlib.dll" hashalg="SHA1"/>
7 </assembly>

In the assembly tag the type is “win32” which means it’s a native (non-.NET) assembly. Also, the name attribute must be the name of your dll file without the dll at the end, the processorArchitecture is again “x86,” version must match the version of the package you’re creating and the publicKeyToken must be the same public key token you entered in the Publisher element of your package description. Also inside the File tag there must be a name attribute with the filename of your dll (funlib.dll) and the hash attribute which we’re going to set to SHA1.

Now, we need to perform a couple command line actions in order get our assembly ready. First we’ll call mt from the Windows SDK:

mt.exe -manifest funlib.dll.manifest -outputresource:funlib.dll

This embeds the manifest inside the DLL. Next we sign the package using signtool, also from the Windows SDK:

signtool.exe /v /t http://timestamp.verisign.com/scripts/timestamp.dll /f sample.pfx /p password funlib.dll

Here we sign the DLL with the code signing certificate held in sample.pfx which has a password on it of “password.” Next we have to update the manifest with hashes of the signed file:

mt.exe -manifest funlib.dll.manifest -hashupdate -makecdfs

Next we’ll use the makecat tool from the Windows SDK to create a security catalog:

makecat.exe funlib.dll.manifest.cdf

Finally we sign our newly created security catalog:

signtool.exe /v /t http://timestamp.verisign.com/scripts/timestamp.dll /f sample.pfx /p password funlib.dll.cat

*phew* We’re done setting up everything we need to create an assembly. Now we just go back to our package description and add in a CatFile and Manifest elements.

1 <Package xmlns="http://coapp.org/ns/mkPackage.xsd"
2 Name="FunLib"
3 Version=""
4 Arch="x86">
5 <Publisher Name="Publisher Name" PublicKeyToken="Publisher PKT" />
6 <SharedLib>
7 <Assembly Arch="x86" Src="funlib.dll" Platform="win32">
8 <Manifest Src="funlib.dll.manifest"/>
9 <CatFile Src="funlib.dll.cat" />
10 </Assembly>
11 </SharedLib>
12 </Package>
Your first package description is done! It’s time to run mkPackage and create your package:
mkPackage.exe --pfx-file=sample.pfx --pfx-password=password funlib.xml

You should have an MSI outputted which is your CoApp package. If you double click on the file, it will attempt to download and install the coapp-engine and install itself. Since the coapp-engine doesn’t currently exist, this won’t work. If you want to just see the msi install for testing right now, run this from the command line:

msiexec /i <name of msi file> COAPP_INSTALLED=1

ONLY DO THIS FOR TESTING BEFORE COAPP-ENGINE IS AVAILABLE! If you do this after that, you could cause a bunch of problems with your system!

But that was way too hard!

Yeah, we know. The SmartManifest program in development will handle a bunch of those steps, including the creating of the manifest and security catalog and signing the assembly, as well as adding in the CatFile, Manifest and Publisher elements for you. Once that’s around all you’ll have to do is create your package’s xml description, call SmartManifest and mkPackage and you’ll have a nice new CoApp Package available.

No comments: