Monday, July 27, 2026

Installing through IAssemblyCache

 

Windows Side-by-Side

 When you want to share your DLL's across applications there are a couple of options:

  • put in a directory and add a path variable
  • dump in the Windows system directory
  • put in the Windows Side-by-Side (WinSxS)

 Under Windows XP the first two options were not recommended. The third option was then the way to go but is not very well documented so one may question if it is still recommended.

To put something in the WinSxS one need:

  • a manifest
  • a signed cat file which lists all the installed components
  • one or more DLL's to install 

 Using Gemini I came up with the following steps:

  1.  Create a certificate in PowerShell with e.g. 'New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=SxSTestCert" -CertStoreLocation "Cert:\CurrentUser\My"'. This creates a SxSTestCert in the personnel section of the certification store. One can check this with 'cermgr.msc'.
  2. extract the public key and store in a *.cer file.
  3. create a publicKeyToken with SDK tool pktextract.exe from the just created *.cer file. Use calculated value for in the manifest file. this is a crucial step; with a wrong publicKeyToken one get all kinds of errors.
  4. create a manifest (see below). The entries in the manifest file described the side by side assembly
  5. create a cdf file listing all files in the manifest file
  6. create a cat file from the cdf; e.g. 'makecat.exe Test.cdf'
  7. sign the cat file with the certificate with signtool. For example use 'signtool.exe sign /s My /n "SxSTestCert" /fd SHA256 /t http://timestamp.digicert.com Test.MyCompany.MyAssembly.cat' 

 A manifest file may look like:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity 
        type="win32"
        name="Test.MyCompany.MyAssembly"
        version="1.0.0.0"
        processorArchitecture="amd64"
    publicKeyToken="91cb7a3ae2229a15"/>

<!-- Add your DLL file here -->
  <file name="MyPayload.dll">
  </file>
</assembly>

The associated cdf file may look like this:

 [CatalogHeader]
Name=Test.MyCompany.MyAssembly.cat
ResultDir=.
PublicVersion=1
CatalogVersion=2
HashAlgorithms=SHA256

[CatalogFiles]
<HASH>Test.MyCompany.MyAssembly.manifest=Test.MyCompany.MyAssembly.manifest
<HASH>MyPayload.dll=MyPayload.dll

Now that you have all files in code you have to invoke 'InstallAssembly'. Note that there is no sxs.lib to link against so the function 'CreateAssemblyCache' must be extracted from 'sxs.dll' through LoadLibrary / GetProcAddress.

#include <winsxs.h>
#include <atlbase.h>

void AssemblyCreate()
{
   CComPtr<IAssemblyCache> ptrCache; 
   HMDULE hModule = ::LoadLibrary(sxs.dll);

   using PfCreateAssemblyCache = HRESULT (*) (IAssemblyCache**, DWORD); 

   PfCreateAssemblyCache pfCreateAssemblyCache = reinterpret_cast<PfCreateAssemblyCache>(::GetProcAddress(hModule, "CreateAssemblyCache"));

   HRESULT hr = pfCreateAssemblyCache(&ptrCache, 0);
      
   FUSION_INSTALL_REFERENCE ref = { 0 };
   ref.cbSize              = sizeof(FUSION_INSTALL_REFERENCE);
   ref.dwFlags             = 0;
   ref.guidScheme          = FUSION_REFCOUNT_OPAQUE_STRING_GUID; // Required!
   ref.szIdentifier        = L"MyTestInstallerApp";
   ref.szNonCannonicalData = L"Test Installation";

   constexpr wchar_t szManifestFilePath[]  = L"Test.MyCompany.MyAssembly.manifest";
   
   hr = ptrCache->InstallAssembly(0, szManifestFilePath, &ref);

   if (SUCCEEDED(hr))
   {
   }
   ::FreeLibrary(hModule);

 This creates a side by side package:

  • on Windows 10 on C:\Windows\WinSxS and Manifests folders
  • on Windows 11 on C:\Windows\WinSxS\Fusion folder

Note that since Windows 7 an alternative exist using application config files and probing. This works the same as the first option but with a fragile global PATH variable.

 

Sunday, April 26, 2026

Watch out for open plan offices

 

Open plan office

 I had to work for more than a decade in an open plan office which was far from ideal. Open plan offices in the Netherlands are actual open; not with cubicles like in the USA which would give some kind of privacy. There is a lot of visual and auditory noise in the open plan office which makes concentrating and doing your work difficult. Also when you need a meeting to discuss topics you have to reserve a room instead of just talking in your own room.

 The bad part was that I anticipated all this and reported this to my manager when he came up with the initiative to create an open plan office in the new building. He shove the arguments aside and said that I should first try it out before having an opinion. I countered that the old situation was already like an open plan office so I don't need new experience. He also used the dumb argument that he himself worked happily on an open plan office so I should be happy too. He then stated that if it wouldn't work out he would reverse the situation which of course never happened.

 He then put all developers in a big open plan office but he reserved for himself a nice private room. 

 I complained about the open plan office every assessment but nothing changed. When the open plan office was finally under scrutiny the manager even lied that the whole open plan office idea was on our request and now we suddenly wanted something differently. 

 He eventually got fired; not for his open plan office but actually for the wrong reasons. Still the performance drop due the open plan office would have been a strong argument to let him go. A new manager came and put me in a private room. Other developers weren't so lucky: they still had to endure the open plan office.

Thursday, January 1, 2026

Careful with refactoring

Refactoring issue

 Last year we applied a small refactoring in a piece of code. The construct was a parent - child relationship with the child hold by unique_ptr. Simplified the code was somewhat as follows:

struct Parent
{
   explicit Parent(bool bShow)
   : m_bShow(bShow)
   {
      m_ptr = std::make_unique<Child>(this);
   }

   std::unique_ptr<Child> m_ptr;
   bool                   m_bShow; 
};

struct Child
{
   explicit Child(Parent* pParent)
   : m_bShow(pParent->m_bShow)
   {
   }

   bool  m_bShow; 
};

 Although the code has a bidirectional dependency between parent and child iIt will compile if one splits out in header and source files for parent and child. 

 The heap use of child seemed redundant so it was removed and the child will be hold by value:

struct Parent
{
   explicit Parent(bool bShow)
   : m_child(this)
   , m_bShow(bShow)
   {
   }

   Child   m_child;
   bool    m_bShow; 
};

 This refactoring lead though to a bug where sometimes things were shown and sometimes not. The bug only appeared in release mode under certain conditions. It turned out that the value of 'm_bShow' was using uninitialized memory. We accidentally created a memory safety issue in years. 

 The problem is that the child is created before the parent is fully created and thereby using uninitialized memory of the parent. The solution is easy by reversing creation order:

struct Parent
{
   explicit Parent(bool bShow)
   : m_bShow(bShow)
   , m_child(this)
   {
   }

   bool    m_bShow; 
   Child   m_child;
};

 Using the 'this' pointer in constructor is a code alarm but not a code smell. As a general rule here declare first all members of built in types before declaring members with classes. If that is not viable one can defer creation by using std::optional instead of std::unique_ptr. std::optional is often more optimal from a performance perspective.

 Not sure how Rust would have prevented this; probably by disallowing the construct in the first place. That would be pity since circumventing the extra heap allocation and pointer access is certainly worthwhile the final solution where children are hold by value.

Installing through IAssemblyCache

  Windows Side-by-Side  When you want to share your DLL's across applications there are a couple of options: put in a directory and add ...