The new DynamicLibraryFixup component of the Package Support Framework simplifies the task of ensuring that processes in your package find dlls that are also in your package.
Background
Applications use a variety of techniques to ensure that the exe used to start a process can load the dll files they require. In general, the dll is loaded through a Windows API call, such as LoadLibrary, using just the name of the dll without any file path information. For the most part, activity performed during the installation of the exe and dll components help make this work.
When LoadLibrary is called with the dll name, it will search for a dll file with the provided name in a variety of locations. These locations will include the following:
- The current working directory of the process.
- Additional folders defined at runtime by the application (rarely used).
- Any folders listed in an App Paths registration in the windows registry for the name of the process.
- Any folders listed in the PATH environment variable.
Why we have problems finding Dlls in MSIX
When bringing applications originally designed for native installation (via MSI or EXE installer) into MSIX, we sometimes experience issues because of interference in finding dlls.
The symptoms might vary depending on how the application developer did error checking. So the app might crash, or it might provide a helpful (or not!) dialog box describing the problem, or it might attempt an MSI self repair option. Here is an image of a simple test program that attempts to load two dlls. One is found and one is not.
Even if the developer didn’t provide such clear information on why the application is sick, we can always trace the cause of an issue like this by using a ProcessMonitor trace. In process monitor you could filter on the Path field ending in “.dll” and highlight on the Result field containing either “PATH NOT FOUND” or “FILE NOT FOUND“, as shown in these setups.
In the following images, you can see several attempts to locate the two dlls when running the application without fixup in the MSIX container. Because of where ProcMon tracing occurs in the file system mini-filter drivers, the traces show the effects of what Loadlibrary does plus what the MSIX Runtime does as well for VFS pathing.
In the first case above, we can see that eventually the dll is loaded into memory.
In the second case, we see that the dll is never found.
Causes
The causes of these issues are usually one of the following:
- Change in Current Working Directory. Traditional lnk file shortcuts set a working directory, and by default set it to the directory that the target exe file is in. Modern MSIX shortcuts set the working directory of the target process to the System32 folder.
- Path Variable. The MSIX package installation does not have the ability to manipulate system environment variables, and the container does not support virtualization of a change to one.
- App Path Registration. This registration is effectively ignored.
You might notice that I didn’t include any file system virtualization issues in that list. The MSIX runtime usually does a good job of handling those. But even if you manage to find a case where it doesn’t, the solution below will solve it!
PSF to the rescue
The Package Support Framework (PSF) has a couple of ways to help you solve this issue, depending upon the cause. But you can always safely use both methods if you don’t want to figure out the exact cause.
In any case, to use the PSF you have to add PsfLauncher to the package. This exe should become the replacement target of the shortcut. You must use the 32/64-bit version of PsfLauncher (and other PSF components) that matches the target process. PsfLauncher will then take instructions from the config.json file you add to the package.
The image below shows using PsfTooling (a convenient tool used along side the Microsoft MSIX Packaging Tool to add and configure these components during an installation/capture process) to add in the launcher, configure it, and modify the shortcut. The default settings in PsfTooling will configure the json file to cause the target launch to get the originally intended working directory.
If Working Directory were the cause, this is all that is needed. But if it is any other cause, we can also add the new DynamicLibraryFixup that I contributed to the PSF to solve the issue.
DynmaicLibraryFixup allows to you add configuration in the json file about dll files and the relative path to their location in the package. The fixup implements an intercept to the LoadLibrary calls, and enhances the search by matching against this list. In essence, it does this before letting LoadLibrary look at other places.
Again, PsfTooling makes this a breeze. You simply have to ask PsfTooling to add the Dynamic Library fixup and it does all the rest of the work of finding the dlls in your package and configuring the json appropriately.
Here you can see the app now works.
And we can confirm the activity in the ProcMon trace. Surprisingly now only is the second dll found, even the first one is now found with fewer hits to the file system.
Conclusion
Adding PsfLauncher and DynamcLibraryFixup in your MSIX package can solve issues with “dll not found” issues.