Click here to Skip to main content
11,642,855 members (75,398 online)
Click here to Skip to main content

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

, 19 Aug 2008 Zlib 150.8K 6.2K 83
Rate this:
Please Sign up or sign in to vote.
This tool will spy on COM registration process and create side by side (SxS) manifest file(s)

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

    Share

    About the Author

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

    You may also be interested in...

    Comments and Discussions

     
    QuestionManifests for OPOS CCO's Pin
    Sinspin19-Mar-14 21:55
    memberSinspin19-Mar-14 21:55 
    QuestionClass not registered Pin
    hackerspk14-Jan-14 15:12
    memberhackerspk14-Jan-14 15:12 
    QuestionClient manifest creation fails if client.exe is smaller than 10kB Pin
    Member 86543605-Nov-12 3:13
    memberMember 86543605-Nov-12 3:13 
    GeneralMy vote of 5 Pin
    Rotted Frog17-Sep-12 6:35
    memberRotted Frog17-Sep-12 6:35 
    GeneralProblem on Win7 x64 Pin
    tzleo28-Jun-12 21:11
    membertzleo28-Jun-12 21:11 
    GeneralRe: Problem on Win7 x64 Pin
    gxdata10-Oct-12 5:44
    membergxdata10-Oct-12 5:44 
    GeneralMy vote of 5 Pin
    bartolo18-Jun-12 0:28
    memberbartolo18-Jun-12 0:28 
    QuestionDoesn't work for .Net COM DLLs Pin
    Member 887136123-May-12 5:15
    memberMember 887136123-May-12 5:15 
    QuestionSHA1 Hash Pin
    Member 83801226-Apr-12 12:20
    memberMember 83801226-Apr-12 12:20 
    AnswerRe: SHA1 Hash Pin
    Cristian Adam17-Jun-12 22:48
    memberCristian Adam17-Jun-12 22:48 
    GeneralRe: SHA1 Hash Pin
    tzleo28-Jun-12 23:15
    membertzleo28-Jun-12 23:15 
    GeneralMy vote of 5 Pin
    herves17-Apr-12 4:15
    memberherves17-Apr-12 4:15 
    QuestionMultiple COMs in one single manifest Pin
    gbessis29-Feb-12 3:21
    membergbessis29-Feb-12 3:21 
    GeneralMy vote of 5 Pin
    manoj kumar choubey28-Feb-12 18:21
    membermanoj kumar choubey28-Feb-12 18:21 
    QuestionTrick to get Windows 7 to recognise external manifests. Pin
    Member 17089578-Sep-11 20:44
    memberMember 17089578-Sep-11 20:44 
    AnswerRe: Trick to get Windows 7 to recognise external manifests. Pin
    herves17-Apr-12 8:20
    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!' error Pin
    sprezzatura31-Aug-11 9:52
    membersprezzatura31-Aug-11 9:52 
    GeneralLove it, got it working, but does MS give us the equivalent of new ActiveXObject('some.programID') for registration free com Pin
    Member 10038611-Jun-11 14:42
    memberMember 10038611-Jun-11 14:42 
    GeneralRe: Love it, got it working, but does MS give us the equivalent of new ActiveXObject('some.programID') for registration free com Pin
    Cristian Adam2-Jun-11 1:20
    memberCristian Adam2-Jun-11 1:20 
    GeneralMANY THANKS ! Pin
    Member 768808621-Feb-11 4:46
    memberMember 768808621-Feb-11 4:46 
    GeneralRe: MANY THANKS ! Pin
    Cristian Adam21-Feb-11 5:01
    memberCristian Adam21-Feb-11 5:01 
    GeneralGenius! Pin
    AveiMil15-Jul-10 23:18
    memberAveiMil15-Jul-10 23:18 
    GeneralcomInterfaceProxyStub Pin
    Neil Sl23-Feb-10 4:37
    memberNeil Sl23-Feb-10 4:37 
    GeneralRe: comInterfaceProxyStub Pin
    Neil Sl25-Feb-10 10:46
    memberNeil Sl25-Feb-10 10:46 
    GeneralRe: comInterfaceProxyStub Pin
    wladek523-Apr-11 6:08
    memberwladek523-Apr-11 6:08 
    QuestionProgID? Pin
    Member 36316253-Feb-10 1:07
    memberMember 36316253-Feb-10 1:07 
    AnswerRe: ProgID? Pin
    Cristian Adam4-Feb-10 23:46
    memberCristian Adam4-Feb-10 23:46 
    SuggestionRe: ProgID? Pin
    Vladimir Rutsky25-Jan-13 1:06
    memberVladimir Rutsky25-Jan-13 1:06 
    GeneralassemblyIdentity element name attribute seems to be wrong. Pin
    Felix Collins1-Oct-09 11:27
    memberFelix Collins1-Oct-09 11:27 
    Generalregsvr42 GUI Pin
    stanX31-Aug-09 0:52
    memberstanX31-Aug-09 0:52 
    GeneralRe: regsvr42 GUI Pin
    Cristian Adam31-Aug-09 3:47
    memberCristian Adam31-Aug-09 3:47 
    GeneralRe: regsvr42 GUI Pin
    stanliritche3-Nov-11 3:01
    memberstanliritche3-Nov-11 3:01 
    QuestionCan not get the <comclass> info</comclass> Pin
    fcfs30-Jul-09 23:28
    memberfcfs30-Jul-09 23:28 
    GeneralCan't get manifest to work Pin
    Randem0614-Jul-09 20:07
    memberRandem0614-Jul-09 20:07 
    GeneralRe: Can't get manifest to work Pin
    Cristian Adam14-Jul-09 22:34
    memberCristian Adam14-Jul-09 22:34 
    GeneralRe: Can't get manifest to work Pin
    Randem0614-Jul-09 23:21
    memberRandem0614-Jul-09 23:21 
    GeneralRe: Can't get manifest to work Pin
    Cristian Adam15-Jul-09 1:40
    memberCristian Adam15-Jul-09 1:40 
    GeneralRe: Can't get manifest to work Pin
    Randem0616-Jul-09 21:29
    memberRandem0616-Jul-09 21:29 
    GeneralRe: Can't get manifest to work [modified] Pin
    Randem0616-Jul-09 21:59
    memberRandem0616-Jul-09 21:59 
    GeneralRe: Can't get manifest to work Pin
    Randem0616-Jul-09 22:21
    memberRandem0616-Jul-09 22:21 
    GeneralRe: Can't get manifest to work Pin
    Cristian Adam16-Jul-09 23:12
    memberCristian Adam16-Jul-09 23:12 
    GeneralRe: Can't get manifest to work Pin
    Randem0616-Jul-09 23:50
    memberRandem0616-Jul-09 23:50 
    GeneralRe: Can't get manifest to work Pin
    Cristian Adam17-Jul-09 1:02
    memberCristian Adam17-Jul-09 1:02 
    GeneralRe: Can't get manifest to work Pin
    Randem0617-Jul-09 19:31
    memberRandem0617-Jul-09 19:31 
    GeneralRe: Can't get manifest to work Pin
    Vlad Vissoultchev24-Sep-09 22:31
    memberVlad Vissoultchev24-Sep-09 22:31 
    General-version has no effect Pin
    Randem0613-Jul-09 22:38
    memberRandem0613-Jul-09 22:38 
    GeneralRe: -version has no effect Pin
    Cristian Adam13-Jul-09 23:27
    memberCristian Adam13-Jul-09 23:27 
    GeneralRe: -version has no effect Pin
    Randem0614-Jul-09 17:03
    memberRandem0614-Jul-09 17:03 
    GeneralThank you very much, Cristian! Pin
    Wolfgang Riedmann30-May-09 2:06
    memberWolfgang Riedmann30-May-09 2:06 
    QuestionQuestion about 'comInterfaceExternalProxyStub' Pin
    pkooman326-May-09 4:51
    memberpkooman326-May-09 4:51 

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

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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