Forum Discussion
Private SxS Components (registration-free COM)
I guess I will have to just update the CI pipeline to use different manifests for MSI versus MSIX, and register the offending components in the VREG for the latter (I've quickly proven this out by hand and it works fine for my case). Not ideal, but it works.
JDHIntercede Sounds like the right approach.
I'm running into this in trying to repackage existing MSIs into MSIX. Can you describe how to tell if the manifest is for registration-free COM? A sample manifest would go a long way to help me understand this.
- Jun 29, 2022
JDHIntercede Regarding csrss...
This is a session process. It will only attempt to read an external manifest file from a folder once during the life of the user session. I am seeing it successfully read the manifest file from the MSIX package during that first run. Subsequent launches don't look for the file again.
This doesn't explain the problem or eliminate the problem. I just want to make sure you didn't jump to incorrect conclusions.
- JDHIntercedeJun 30, 2022Brass Contributor
That explains the behaviour I saw when I put the DLLs into the real file-system where csrss was looking for them (it worked and then continued to work after I deleted them - confused me for a little while that one did!). Possibly also indicates that while csrss is reading the referenced dependency manifests from the real file-system, the application itself is able to find the DLLs inside the VFS (otherwise I'd assume it would have stopped working after deleting the files from the real FS).
- JDHIntercedeJun 27, 2022Brass Contributor
It pretty-much comes down to the elements inside it.
You can extract a manifest using mt.exe (https://docs.microsoft.com/en-us/windows/win32/sbscs/mt-exe) with the following:
mt.exe -inputresource:TheApplication.exe;#1 -out:extracted.manifest
If you open up the file you extracted, you're looking for elements like <comClass>, <typelib>, <comInterfaceExternalProxyStub> (docs https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests schema is https://docs.microsoft.com/en-us/windows/win32/sbscs/manifest-file-schema).
I've found that registrations directly inside the application manifest (i.e. the manifest in the application executable) seem to work fine. The issue comes about when the manifest is referencing external manifests, even if these are private and in the same folder. To identify this kind of thing, look for something like:
<dependency> <dependentAssembly> <assemblyIdentity name="SomeComponent" version="1.2.3.4" publicKeyToken="00000a0000cb0d0c" processorArchitecture="x86"/> </dependentAssembly> </dependency>
These entries are saying I depend on 'SomeComponent' with the identity specified, and the loader will look first in the GAC, then in the current directory for a DLL/manifest with the same name (this is the bit that's not respecting the VFS in MSIX), then, if not found, in a subdirectory with the same name. Side note: regardless of MSIX, if it finds a DLL with the same name, but without an embedded manifest, before it finds a standalone manifest file, it will fail - this can cause problems where the manifest file is standalone rather than embedded, as the loader stops looking after the failure even if the manifest exists.
- Jun 27, 2022
JDHIntercede Yeah, I've been digging into this a little.
I am fairly sure that you should be able to use the components with either internal or external application and component manifests in your MSIX package AS IS.
The trick will be to add the com registration directly into the AppXManifest. This, in essence, it the modern way to advertise the com components, whether or not they originally were registration-free or registered in the registry. It allows for side-by-side deployment in the package, but the installation of the MSIX package writes the registration from the AppXManifest into a new per-package location in the registry to make things easy to clean up.
- JDHIntercedeJun 27, 2022Brass Contributor
TIMOTHY_MANGAN Unfortunately, if the exe has an embedded application manifest that is expecting private SxS registration then it absolutely will not work as-is with the components registered 'normally' inside the container, either leveraging the VREG or the AppXManifest. Believe me, I've tried - I picked up this task I estimated at 4hrs last Tuesday, and I just got it all working nearly a week later.
My main build produces an MSI, which I then use the workspace from to create my MSIX. I had to update my build to:
- Remove the signature from the MSI exe
- Extract the manifest
- Remove the <dependency> nodes
- Re-embed the manifest in the exe
- Re-sign the exe
Then my components are registered as normal in the MSIX VREG, with the files placed in the VFS in their 'global' locations, which removes the need for the <dependency> nodes in the first place. MSI keeps the <dependency> nodes as I want that to have private SxS registration without exposing interfaces to the wider system.
I think the root cause of all this is where Windows reports the process as being run from to external callers. If you run an MSIX-packaged app then use the .NET https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.getprocessbyid?view=net-6.0 method to get a handle to it, then check where it's located, you'll see it returns the real equivalent of any VFS location rather than the actual path inside the WindowsApps folder. I first encountered this with one of our own apps that checks the signature of the caller, and we have to basically check if the process is associated with a package (https://docs.microsoft.com/en-gb/windows/win32/api/appmodel/nf-appmodel-getpackagefullname) then check in the known subfolder of the package install location for the reported exe, and, if it's not in a package, just check the path Windows reported. You can literally get a situation where Windows reports a process is running from a location that doesn't exist.