Forum Discussion
Trying to MSIX package LOB application that needs TWAIN access
Just wanted to post an update.
I tried Peer's proposed solution but I didn't find any success with it. I still couldn't access the TWAIN data sources through the Datasource manager.
What did work for me after a lot of trial and error was to perform the following two actions when the application starts (or at least before you open the TWAIN Data source manager). The MSIX package is also built with runFullTrust.
- A PInvoke call to SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
Enumerate every subdirectory of C:\Windows\twain_32\ (if app is x86, twain_64 if app is x64) and AddDllDirectory() each one.
[DllImport("kernel32.dll", SetLastError = true)]
static extern int SetDefaultDllDirectories(uint flags);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr AddDllDirectory(string dir);
const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000;
public static void Register(string twainRoot = @"C:\WINDOWS\twain_32")
{
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
if (!Directory.Exists(twainRoot)) return;
AddDllDirectory(twainRoot);
foreach (var d in Directory.EnumerateDirectories(twainRoot, "*", SearchOption.AllDirectories))
{
AddDllDirectory(d); // every DS subfolder, so each DS's siblings resolve
}
}
I believe the issue is down to how the TWAIN Data source manager loads each Vendor driver. It uses the LoadLibrary winAPI call instead of LoadLibraryEx and as a result it manages to load the DS driver file ok, but then when the dependencies for each DS driver attempt to load it cannot find their location and its search path is restricted because of the MSIX container and how it restricts the DLL search path of LoadLibrary.
FYI for someone reading this. Some informational MSIX implementation details that might help others:
- If programmatically adding a directory to the default directories solves an issue, then that issue should also be solvable by adding LoaderSearchOrder extension in the AppXManifest file (there is an undocumented limit of 5 directories added this way).
- LoadLibrary API is not really different than LoadLibraryEx, in fact LoadLibrary calls LoadLibraryEx.
- Rather than say MSIX restricts the paths checked, I would suggest that it can be that when an app is placed in a container it may have a different search list.
- First, the current working directory of the application may be different than before (fixable using a new extension on the application entry of the AppXManifest).
- Second, the root directory of the package is added to the list.
- Third, any "App Paths" registration of the traditional application installer that adds to the search path list will be ignored (normally fixed by LoaderSearchOrder).
- Fourth, the traditional installer may have used a change to the Path variable and since that installer is not used, additional paths may be missing (any native installer that has updated the path variable on the system is respected by MSIX container; this only is about when this application installer used to update the path. Again, LoaderSearchOrder can help).
- Fifth, there is that LoaderSearchOrder which adds to the list.