Jun 24 2022 09:14 AM
Jun 24 2022 09:14 AM
My application has private SxS components that it includes with an Application Manifest. This manifest includes dependentAssembly nodes that refer to COM DLLs in the same folder that have embedded assembly manifests. This all works fine outside of MSIX, but fails with a standard SxS error when packaged (The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail).
Looking at the goings-on in Procmon, I can see that it's the 'csrss.exe' Windows component that is performing the lookup for the dependencies, and since this lives outside the container and is not invoked by my app directly (it's always running in the background), it is looking in the real ProgramFilesX86 folder rather than the one in the VFS that actually contains the DLLs.
Does anyone have any suggestions on what the best way to handle this would be? I've tried the PSF FileRedirectionFixup and DynamicLibraryFixup in PSF, which don't work - I suspect this is because csrss isn't something that is being created from my application, but rather is something running in Windows and handling SxS, and so it isn't being intercepted. The bitness doesn't always match either, so I don't think PSF could intercept it even if it wanted to (my app is x86 due to 3rd part native components, but csrss is x64 on an x64 system).
My only fallback is to munge the VREG such that the components are registered 'globally' rather than privately (which is fine for MSIX as it's scoped to the container), but that means I need to have different Application Manifest files depending on if I'm packaging MSI versus MSIX (I ship both) since the exe will be expecting SxS as-is.
Jun 24 2022 02:03 PM
Jun 27 2022 02:14 AM
Jun 27 2022 05:28 AM
@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 27 2022 10:58 AM - edited Jun 27 2022 11:02 AM
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
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="220.127.116.11" 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 11:11 AM
@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.
Jun 27 2022 11:24 AM
@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:
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 Process.GetProcessById 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 (GetPackageFullName function (appmodel.h) - Win32 apps | Microsoft Docs) 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.
Jun 29 2022 11:40 AM
@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.
Jun 30 2022 03:49 AM - edited Jun 30 2022 03:51 AM
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).