Click here to Skip to main content
Click here to Skip to main content

regsvr42: Generate SxS Manifest Files from Native DLLs for Registration-Free COM

By , 19 Aug 2008
 

Introduction

Windows XP introduced a new COM activation model called Registration-Free COM activation. The Registration-Free COM activation is a registry replacement for COM components. The registry information will reside in a DotManifest file that can be stored in the same folder as the application itself.

This means that you don't have to have information into registry, information which is normally stored into HKEY_LOCAL_MACHINE, thus enabling regular user accounts to use COM DLLs without registering them into the system.

The problem with these DotManifest files is that they are pretty hard to write by hand. For managed assemblies there is Genman32 - A tool to generate Sxs manifest for managed assembly for Registration Free COM/.NET Interop, but there is no tool for native DLLs, this is why I've decided to write such a tool.

Background

The following MSDN article will give the proper background information: Registration-Free Activation of COM Components: A Walkthrough by Steve White and Leslie Muller. Also of great help is the MSDN Side-by-side Assemblies Reference.

A DotManifest file is a XML file — you probably have heard about these in conjunction with Common Controls version 6, or with Windows Vista elevation privileges and not to mention the (in)famous Microsoft.VC[8|9]0.CRT.manifest and Microsoft.VC[8|9]0.MFC.manifest files. These days every application has embedded a DotManifest file inside by the Manifest Tool as a resource type 24 (RT_MANIFEST). A typical DotManifest file looks like:

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level='asInvoker' uiAccess='false' />
      </requestedPrivileges>
    </security>

  </trustInfo>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8'
          processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC90.MFC' version='9.0.21022.8'
          processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />

    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls'
          version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df'
          language="'*'" />
    </dependentAssembly>
  </dependency>
</assembly>

The Spying

In order to get the the information about the COM registration process I had to "intercept" the following registry access functions:

  • RegCreateKeyA
  • RegCreateKeyW
  • RegCreateKeyExA
  • RegCreateKeyExW
  • RegSetValueA
  • RegSetValueW
  • RegSetValueExA
  • RegSetValueExW
  • RegOpenKeyA
  • RegOpenKeyW
  • RegOpenKeyExA
  • RegOpenKeyExW
  • RegCloseKey

The interception was done by using the class CAPIHook presented in Chapter 22: DLL Injection and API Hooking of the book Windows via C/C++, Fifth Edition written by Jeffrey Richter and Christophe Nasarre, Microsoft Press (c) 2008. One can use the Detours library from Microsoft Research instead of CAPIHook. I've decided for the latter because of simpler deployment (just the executable, no signature DLL).

Setting up a CAPIHook is being done like this

std::auto_ptr<CAPIHook> Interceptor::m_RegCreateKeyA;

...

    if (!m_RegCreateKeyA.get())
    {
        m_RegCreateKeyA.reset(new CAPIHook("Advapi32.dll", "RegCreateKeyA",
            (PROC)RegCreateKeyA));
    }

The upper code will redirect RegCreateKeyA through Interceptor::RegCreateKeyA, the original function can be reached through m_RegCreateKeyA. Interceptor::RegCreateKeyA, like this:

LONG WINAPI Interceptor::RegCreateKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
{
    if (m_doTrace)
    {
        PrintKeyStats(hKey, lpSubKey, __FUNCTIONW__);
    }

    // just to have it initialized
    LONG result = ERROR_ARENA_TRASHED;
    try
    {
        result = ((PFNREGCREATEKEYA)(PROC)*m_RegCreateKeyA)(hKey, lpSubKey, phkResult);
    }
    catch (...)
    {
    }

    if (result == ERROR_SUCCESS)
    {
        InsertSubkeyIntoUserKeyMap(hKey, *phkResult, lpSubKey, __FUNCTIONW__);
    }

    return result;
}

After all the information was acquired then the information is processed and written into DotManifest files. The manifest files are encoded as UTF-8. I would like to point fprintf's ccs=<encoding> parameter which was used to save the manifest files as UTF-8.

void ManifestWriter::WriteToFile(const std::wstring& outputManifestFile)
{
    FILE* file = _wfopen(outputManifestFile.c_str(), L"w, ccs=utf-8");
    if (file)
    {
        fwrite(&*m_data.str().begin(), 1, m_data.str().size() * 2, file);
        fclose(file);
    }
}

In order to get all the information possible, first DllUnregisterServer function is called, then DllRegisterServer and at the end again DllUnregisterServer. If you use regsvr42 on a system where you already have the COM DLL registered and still want to use it normally don't forget to run regsvr32 for that COM DLL.

Tool Usage

The basic usage is:

regsvr42 com.dll

which will generate a file named com.sxs.manifest. You can find out what interfaces and coclasses the COM DLL exports.

When used with a client application the usage is:

regsvr42 -client:client.exe com.dll

which will generate besides com.sxs.manifest another manifest file named client.exe.manifest. If client.exe already has a manifest file embedded, the contents of that manifest file are preserved into client.exe.manifest alongside with the reference to com.sxs assembly.

If you have more than one COM DLLs you want to use can use the tool in batch mode like:

regsvr42 -client:client.exe -batch:file_containing_com_dll_file_names

You can put all the COM DLLs inside one directory and there will be just one manifest file inside the directory named directory_name.manifest

regsvr42 -client:client.exe -dir:directory_with_com_dlls

If you have more than one directories with COM DLLs you can use the -batch function with all the names of the directories written in the batch file.

regsvr42 -client:client.exe -batch:file_containing_directory_names

DirectShow Filters

DirectShow filters are COM DLLs. They come in three flavours: source filters, transform filters and render filters.

The source filters add extra information into registry to support DirectShow's intelligent connect, this extra information cannot be stored into a DotManifest file. If your application relays on Intelligent Connect for a source filter, it will not work correctly.

There is one solution for this problem. For example instead of using IGraphBuilder::RenderFile one should:

  • Add the source filter in to the DirectShow graph
  • Acquire the IFileSourceFilter interface and call the Load method
  • Acquire the output pin of the source filter and call IPin::Render

    Test Application

    I have made a test application which uses a source filter as described above. The test application will try to play an accPlus radio station by the use of Orban/Coding Technologies AAC/aacPlus Player Plugin

    To test the application you need to have the Orban Plugin installed and the just run playradio.exe.

    To test the Registration-Free COM mechanism first you have to unregister the Orban Plugin like:

    regsvr32 /u "%ProgramFiles%\Orban\AAC-aacPlus Plugin\aacpParser.dll"

    After that check to see that playradio.exe displays Class not registered. ErrorCode: 0x80040154.

    Then run make_manifest.cmd, a convenience batch file, which does the DotManifest creation like regsvr42 -client:playradio.exe "%ProgramFiles%\Orban\AAC-aacPlus Plugin\aacpParser.dll". Two DotManifest files will be created:

    aacpParser.sxs.manifest

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    
    <assemblyIdentity
        type="win32"
        name="aacpParser.sxs"
        version="1.0.0.0" />
    
    <file name="C:\\Program Files\\Orban\\AAC-aacPlus Plugin\\aacpParser.dll">
    
        <comClass
            description="ORBAN-CT AAC/aacPlus Stream Parser"
            clsid="{301F7BDA-B1F8-4453-82B2-0B9187DF3F3F}"
            threadingModel="Both" />
    
        <comClass
            description="ORBAN-CT AAC/aacPlus Stream Parser About Page"
            clsid="{CA920EED-F427-41B8-838F-33FCF47D5306}"
            threadingModel="Both" />
    
    </file>
    
    </assembly>

    playradio.exe.manifest

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
          <requestedPrivileges>
            <requestedExecutionLevel level="asInvoker" uiAccess="false">
            </requestedExecutionLevel>
    
          </requestedPrivileges>
        </security>
      </trustInfo>
      <dependency>
              <dependentAssembly>
                  <assemblyIdentity
                      type="win32"
                      name="aacpParser.sxs"
                      version="1.0.0.0" />
              </dependentAssembly>
      </dependency>
    </assembly>

    File Hash

    By using the command -hash the file sections will contain a SHA1 hash. To compute the hash I have used CodeProject's CSHA1 by Dominik Reichl. I have verified the validity of the hash by using OpenSSL like this openssl dgst -sha1<com.dll>.

    The problem is that the Manifest Tool mt.exe doesn't think that the hash is valid! The command used was mt -manifest aacpParser.sxs.manifest -validate_file_hashes

    The solution to this problem is to use the Manifest Tool to update the file hash, which renders the -hash function useless, like this: mt -manifest aacpParser.sxs.manifest -hashupdate If anybody knows how to adapt the CSHA1 to produce valid Manifest Tool SHA1 hashes please let me know.

    Debugging

    In case you encounter the following MessageBox:

    This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.

    The Event Viewer - System category contains information about the loading errors of side by side assemblies.

    History

    2008-08-17 Initial release.

  • License

    This article, along with any associated source code and files, is licensed under The zlib/libpng License

    About the Author

    Cristian Adam
    Software Developer
    Germany Germany
    Software engineer by day, Xiph.Org contributor by night.

    Sign Up to vote   Poor Excellent
    Add a reason or comment to your vote: x
    Votes of 3 or less require a comment

    Comments and Discussions

     
    You must Sign In to use this message board.
    Search this forum  
        Spacing  Noise  Layout  Per page   
    QuestionClient manifest creation fails if client.exe is smaller than 10kBmemberMember 86543605-Nov-12 3:13 
    There is small problem in ManifestWriter.cpp line 382. Since the file size data type is unsigned there will be an overflow if the file is smaller than 10kB.
     
    The original line
     
    std::advance(rightToTheEnd, max(0, clientFileBytes.size() - 10 * 1024));
     
    could e. g. be changed into
     
    std::advance(rightToTheEnd, max(0, ((__int64)clientFileBytes.size()) - 10 * 1024));
     
    to avoid this problem.
    GeneralMy vote of 5memberRotted Frog17-Sep-12 6:35 
    This was just what I was looking for, excellent job! Saves me having to write it myself (although I have written a WiX add-in that captures COM registration in a very similar way - I might incorporate similar functionality into that).
    GeneralProblem on Win7 x64membertzleo28-Jun-12 21:11 
    The program doesn't work on win7 x64 because the hook failed.
    And I found one solution is to wrap the COM register part into a dll, then it work again.
    I didn't try on Win7 x86, I don't know if the problem happens depending on the OS. May be some one can tell.
    GeneralRe: Problem on Win7 x64membergxdata10-Oct-12 5:44 
    I found that on both 32-bit and 64-bit Windows 7 it is necessary to run regsvr42.exe in a CMD box with Admin privileges.
    But working with client.exe and SideBySide.dll (already compiled) from the 2005 article by White & Muller (Registration-Free Activation of COM Components: A Walkthrough), the regsvr42 manifests are missing a lot (and will not allow the test client.exe to run).
     
    I haven't yet tried re-compiling both exe and dll from their source, removing the internal manifests, and repeating the exercise.
    GeneralMy vote of 5memberbartolo18-Jun-12 0:28 
    I haven't tried it yet but it looks awesome and I bookmarked it to use it later on. Thanks!
    QuestionDoesn't work for .Net COM DLLsmemberMember 887136123-May-12 5:15 
    Hi, I need to develope a .Net COM DLL so my VB6 application can consume .Net functionality.
     
    When I try to run the utility against my .Net DLL which is exposed to COM it gives me a 'Could not find DLLRegisterServer function'.
     
    Any chance of you utility being configured in the future to deal with these types of scenarios?
     
    Thanks
    QuestionSHA1 HashmemberMember 83801226-Apr-12 12:20 
    Did you every figure out why mt.exe with -validate_file_hashes didn't like your own computed SHA1 hashes? I too am trying to automatically create manifest files in my project along with computing each file's SHA1 hash. But "mt.exe -validate_file_hashes" complains the hashes are invalid even though I verified the hashes myself using multiple hashing utilities.
    AnswerRe: SHA1 HashmemberCristian Adam17-Jun-12 22:48 
    I haven't figured out how to created sha1 sums to the liking of mt.exe.
     
    I think I should remove this functionality, since is obviously not working.
    GeneralRe: SHA1 Hashmembertzleo28-Jun-12 23:15 
    You can use CryptHashData api to create sha1 hash. See http://msdn.microsoft.com/en-us/library/EC1482A2-C2CB-4C5F-AF9C-D493134413D6(v=vs.85,d=lightweight).aspx[^]
    GeneralMy vote of 5memberherves17-Apr-12 4:15 
    Very good tool and very easy to use !
    Many thanks
    QuestionMultiple COMs in one single manifestmembergbessis29-Feb-12 3:21 
    Hi,
    I love your tool : it worked at my first test, placing all the COM files in the same folder and with a simplified command, such as :
    regsvr42 -client:MyApp.exe -Batch:MyComList.txt
     
    But what I did not like was that I obtained a bunch of mini manifests, which make a mess in my folder and should be grouped.
     
    Now, I want a clean setup, with all my COM files (about 15 to 20 files) in a subfolder and as few manifest files as possible.
     
    I tryed to group my COM files in a subfolder names MyComs, and made use of -dir:MyComs
    But the generated manifest does not contain all my dependencies (in fact only one).
     
    Can somebody show me an example of the command and file setup to obtain the desired result ?
     
    Thanks in advance.
    Georges
    GeneralMy vote of 5membermanoj kumar choubey28-Feb-12 18:21 
    Nice
    QuestionTrick to get Windows 7 to recognise external manifests.memberMember 17089578-Sep-11 20:44 
    Plus, if it saves anyone else some time. If you find your manifests work on Xp, but not on Windows 7, it's because Windows 7 ignores external manifests if an internal one is embedded into the exe. You may not THINK you are embedding one, but the default project settings in C# has "Embed manifest with default settings".
     
    You need to change it to "Create application without a manifest" for Windows 7 to consider your external one.
     
    Fantastic app. 4 stars for the functionality and an extra star for the name.
    AnswerRe: Trick to get Windows 7 to recognise external manifests. [modified]memberherves17-Apr-12 8:20 
    With VB.NET, it's not possible to deactivate the embed manifest, but it's possible to copy the content of the com manifest in the embed manifest.
     
    In VS, open the project properties, in the "Application" tab, click on "View Windows Settings" to open the embed manifest.
     
    Open the manifest created with regsvr42 in notepad.
     
    Replace the tag "assemblyIdentity" in the embed manifest with this from com manifest.
     
    And ctrl-S in VS to save the embed manifest and voilà Big Grin | :-D

    modified 17-Apr-12 16:13pm.

    Question'Could not find DllRegisterServer function!' errormembersprezzatura31-Aug-11 9:52 
    I am getting the error "Could not find DllRegisterServer function!".
     
    I have a plain old C# DLL for which I am trying to generate a manifest. I used to use GENMAN32 but it doesn't seem to work with .NET 4.
     
    What do I have to include in my DLL to get REGSVR42 to work?
     
    BTW I got an undefined error on "std::back_inserter()" (in ManifestWriter.cpp). I had to add the following:
     
    #include <iostream>
    #include <iterator>
    #include <vector>

    GeneralLove it, got it working, but does MS give us the equivalent of new ActiveXObject('some.programID') for registration free commemberMember 10038611-Jun-11 14:42 
    I have regsvr42 working produsing the side-by-side manifest files, so many thanks for that.
     
    Now I am wondering if MS give us the equivalent of new ActiveXObject('some.programID') for registration free com
    I am looking through the docs under "Activation Context Reference"
    http://msdn.microsoft.com/en-us/library/aa374166
     
    and "Microsoft.Windows.ActCtx Object"
    http://msdn.microsoft.com/en-us/library/aa375644(v=VS.85).aspx
     
    which "provides a way for scripting engines to access side-by-side assemblies" which is what I want
    I would appreciate if anyone could provide working code for that, I will post back when I get it working
    example, also it says the minimum supported clients are Windows Vista and Server 2003, and I am wondering
    if there's anything for XP?
     
    thanks
    GeneralRe: Love it, got it working, but does MS give us the equivalent of new ActiveXObject('some.programID') for registration free commemberCristian Adam2-Jun-11 1:20 
    I remember doing a test like this:
     
    1. copied c:\Windows\System32\cscript.exe to the directory where I had my COM dll
    2. ran regsvr42 for the COM dll with cscript.exe as client
    3. ran the script like cscript myscript.js
     
    Hope this works for you.
     
    Cheers,
    Cristian.
    GeneralMANY THANKS !memberMember 768808621-Feb-11 4:46 
    Hey man, many many thanks for this. It help me too much!
    I use it for COM objects created in Visual FoxPro.
    GeneralRe: MANY THANKS !memberCristian Adam21-Feb-11 5:01 
    You're welcome!
    GeneralGenius!memberAveiMil15-Jul-10 23:18 
    This tool is genius and has a lot of potential use in the repackaging industry.
    GeneralcomInterfaceProxyStubmemberNeil Sl23-Feb-10 4:37 
    First off, thank you this application makes it much easier to generate manifest files.
     
    Are there any plans to get the code to generate the comInterfaceProxyStub entry in the manifest file. I believe this is required if the COM component implements events.
     
    Neil
    GeneralRe: comInterfaceProxyStubmemberNeil Sl25-Feb-10 10:46 
    I have discoved that it does support comInterfaceProxyStub and comInterfaceExternalProxyStub but it doesn't find this information if you run it on Windows 7 64bit (I suspect it is the 64 bit that is the problem). I think this is possible on 64 bit OSs as the WiX toolset tool "heat" can find the information.
     
    Neil
    GeneralRe: comInterfaceProxyStubmemberwladek523-Apr-11 6:08 
    I can confirm that the comInterfaceProxyStub entries only appear to be generated while using a non x64 OS (I ran it on a win2k3 machine). Brilliant tool, worked like a charm!
    QuestionProgID?memberMember 36316253-Feb-10 1:07 
    Good day,
     
    Your tool is invaluable and really appreciated! However, I've found that it doesn't include all the tags in the manifest files that could have been included - in particular, the "progid" that describes some coclasses. Only when I insert this by hand into the manifest file did I manage to get it working completely.
     
    Is there a way to include this in the utility?
     
    Thanks,
    E
    AnswerRe: ProgID?memberCristian Adam4-Feb-10 23:46 
    Thank for your feedback. I plan to add the progid in an update to the article.
    I don't have an estimate for this though.
     
    Cheers,
    Cristian.

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Permalink | Advertise | Privacy | Mobile
    Web01 | 2.6.130617.1 | Last Updated 19 Aug 2008
    Article Copyright 2008 by Cristian Adam
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid