The trouble with "bitness" (aka architecture) and shiming.


I want to highlight an issue with implementing PSF shimming that I ran into.  It was particularly annoying because the symptoms did not match the real problem.


The issue is the need for alignment of the shim launcher, the shims, and the target application when it comes to what I call "bitness".  "Bitness", is how I describe if the app, or a component, is 32-bit or 64-bit.  This shows up in some tooling as "Architecture", but as an overused term that one can be confusing to people.


Here is what I (think I) know:


Starting out with the easy part, if the target application is a 32-bit exe then you need to use the 32-bit launcher and 32-bit shims.  If the target application is 64-bit, then you need to use the 64-bit launcher and shims.  The impact of this is, unless we build a radically different launcher than in the PSF repository currently, it will become necessary to have independent 32 and 64 bit MSIX packages if the vendor has 32 and 64 bit exes for the application.


But then it gets messy with "AnyCPU" executables.  AnyCPU is a build option that produces a single exe or dll that will run 32-bit on a 32-bit OS and 64-bit on x64 (I believe that on x64 an AnyCPU dll will run in the bitness of the process that loaded it). 


On an x64 OS when a 32-bit launcher creates the application process using an AnyCPU exe the application process becomes 64-bit (configurable in the linking, but by default 64) and will need 64-bit shims.  So even though the vendor supplies only one exe, we still need two different packages with different bitness shims (and probably launcher for simplicity). 


But it is NOT obvious that an executable is AnyCPU.  And as I learned over the past two days not so easy to diagnose as CreateProcess returns with a file not found error. 


If PSF is going to be "easy", we need to make bitness issues handled automatically.  As the current shims are C++ based I don't think we can make them AnyCPU.

5 Replies

Good points. However, all commercial apps that I've seen where the releases yielded x86, x64, and AnyCPU build did just that - made all three platforms available (or bitness - I like that word too.) 


If AnyCPU is problematic with the PSF shim launcher, why not package with the x86 or x64 build?

Yes - "bitness" describes it quite well.


If you are building an installer, you can include all components.  But if you are an IT pro repackaging with "the tool", the installer only puts down the bitness specific bits associated with the OS you capture on.


Given that we are capturing and deploying to Windows 10 - this isn't much of an issue because nobody uses the 32-bit version of the OS (well, except in VMs where memory matters I suppose).


It sounds like the PSF components actually handle more of this automatically than I thought - making sure they insert the right bitness shims if we supply them. But until I can test real-world scenarios on this I'll hold on making a final judgement.

@TIMOTHY MANGAN you can use corflags.exe from the Windows SDK to determine if an app is AnyCPU btw:

CPU Architecture           PE      32BITREQ   32BITPREF
------------------------   -----   --------   ---------
x86 (32-bit)               PE32           1           0
x64 (64-bit)               PE32+          0           0
Any CPU                    PE32           0           0
Any CPU 32-Bit Preferred   PE32           0           1


@Dan Gough Well, I do that in PsfTooling to know which components to install, but it gets more complicated too.


In AnyCPU, the dev can specify what the default should be - this affects how the AnyCPU will run if on an x64 machine.  Visual Studio used to default this default setting x64, but now defaults to x86. But then it isn't just the file because we also have a GPO for the target system that can override that default!


Ultimately I resolved the PsfMonitor issue by changing away from AnyCPU and the PSF now builds bitness specific versions of that component too.  

@TIMOTHY MANGAN The PSF Launcher executable comes in both 32 and 64 bit variants, both of them being able to launch any kind of process as long as the PSF Runtime dll with the same bitness as the launched process is also present in the package with a corresponding name (PsfRuntime.dll or PsfRuntime[arch].dll).


Another PSF component available is PsfRunDll executable which is needed only if the main application process creates additional processes (with different bitness), so I would say that the bitness issues are being handled automatically by the PSF.


If you are using a tool with PSF support, like Advanced Installer, all that bootstrapping is being done behind the scenes, you just have to pick the predefined fixup you need since all are available for both architectures.