Converting Xibo Windows Client from 32-bit to 64-bit: A Complete Technical Walkthrough
Converting Xibo Windows Player
from 32-bit to 64-bit
How I took the official x86 Xibo installer, analysed every binary layer, rebuilt the file set with genuine x64 NuGet packages, authored a fresh WiX MSI, and shipped a production-ready 64-bit installer — so the player can finally use the full RAM of the machine it runs on.
Download the x64 Installer
Unofficial community build — replaces the x86 installation automatically. Includes VC++ 2015–2022 x64 redistributable.
⬇ Download Setup.exeNot affiliated with Xibo Signage Ltd • Open-source build under AGPLv3 • View original source
Why This Needed Doing
Xibo is a well-regarded open-source digital signage platform. The Windows client at version 4 R406.3 ships exclusively as a 32-bit (x86) application. For light deployments — a single image slideshow or a basic ticker — that is fine. But for anything serious, it becomes a problem.
The machines I run Xibo on are displaying heavy layouts: multiple simultaneous video zones, HTML widgets powered by live JavaScript, large image playlists cycling through dozens of high-resolution assets, and web content from the Xibo CMS refreshing in real time. That is a lot of work for any player, and the 32-bit version was not handling it.
The crashes were consistent and repeatable. The player would run fine, the working set would climb steadily, and then somewhere around 3–3.5 GB the process would either freeze or terminate. Every single time. The cause is fundamental to how 32-bit processes work on Windows: they cannot address more than 4 GB of virtual memory regardless of how much physical RAM is installed. On a machine with 16 GB or 32 GB sitting idle, the player is still limited to a ceiling of roughly 3–4 GB.
Xibo's rendering engine is CefSharp, which embeds Chromium. Each browser renderer subprocess uses 300–600 MB on its own. Stack four or five zones of live web content alongside video decoding and image caching and you blow through that ceiling very quickly.
The fix is to make the player run as a genuine 64-bit process. There is no official x64 build. So I built one.
Understanding the Binary Architecture First
Before touching any files, I needed to understand exactly what the installation contains and what each binary type requires to become 64-bit. This is not a simple find-and-replace job. There are three fundamentally different categories of binary, and they each need different treatment.
The PE Header and Machine Type
Every Windows executable starts with a PE (Portable Executable) header. At offset 0x3C in the file is a pointer to the PE signature, and immediately after that signature at PE+4 is a 2-byte Machine field identifying the target architecture:
XiboClient.exe has Machine = 0x014C. That is where the investigation starts.
The CLR Header and the AnyCPU Trick
.NET assemblies have an additional layer on top of the PE header: the CLR header. This contains a Flags DWORD at offset +16. Two bits matter:
XiboClient.exe has CLR Flags = 0x0003: ILONLY is set, and 32BIT_REQUIRED is also set. That second bit is the problem. It instructs the .NET runtime to load the process as 32-bit regardless of the operating system architecture.
The fix is a two-byte patch: clear bit 1 and write 0x0001. With ILONLY=true and 32BIT_REQUIRED=false, the .NET host — mscoree.dll's _CorExeMain entry point — detects a 64-bit OS and relaunches the process natively as 64-bit. This is the standard AnyCPU mechanism. Critically, the PE Machine type at PE+4 stays 0x014C and does not need to change. The CLR host handles the architectural redirection transparently.
CefSharp — The Part That Cannot Be Patched
Not everything in the Xibo installation is pure MSIL. Two CefSharp DLLs are C++/CLI mixed-mode assemblies — they contain compiled native x86 machine code alongside managed code, with ILONLY=false:
Pure MSIL — patchable
- XiboClient.exe — CLR flags patch only
- Xibo.scr — CLR flags patch only
- CefSharp.dll
- CefSharp.Core.dll
- CefSharp.Wpf.dll
- All other managed .NET DLLs
Native / Mixed-mode — must replace
- CefSharp.Core.Runtime.dll (C++/CLI)
- CefSharp.BrowserSubprocess.Core.dll (C++/CLI)
- libcef.dll (native CEF runtime)
- chrome_elf.dll, libEGL.dll, libGLESv2.dll
- vk_swiftshader.dll, vulkan-1.dll
- e_sqlite3.dll, WebView2Loader.dll
Mixed-mode assemblies contain real x86 machine instructions. The AnyCPU trick does not apply. They must be replaced entirely with genuine x64 builds sourced from NuGet.
Pulling Apart the Original MSI
The original installer is xibo-client-v4-R406.3-win32-x86.msi (164 MB). I extracted everything from it using an admin-install, which unpacks all files without executing any installation logic:
That gave me 151 files. I also decompiled the MSI database itself using WiX's dark.exe, which produced a 328 KB WXS file revealing everything the installer does: registry keys, shortcuts, custom actions, prerequisites, install paths, and upgrade codes.
The important findings from that decompilation:
{95D9C9E5-F261-4E15-9106-2B1A3B508B07}
{443E7578-7FEF-47E8-9078-04DDA8B96F3A} — used in the new MSI so it auto-replaces the x86 installation
[ProgramFilesFolder]\[ProductName] — the x86 path. Needs changing to ProgramFiles64Folder.
Advanced Installer 19.8.1 — uses proprietary DLLs (aicustact.dll, Prereq.dll) that cannot be redistributed. A fresh WiX MSI was required.
VC++ 2015-2022 x86 redistributable. Needs to become x64.
IE compat keys written to both SOFTWARE\Microsoft\... and SOFTWARE\WOW6432Node\... The WOW6432Node entries are for 32-bit processes only and were omitted from the x64 build.
Sourcing the x64 Replacement Binaries
NuGet is the canonical source for CefSharp and CEF runtime packages. One version-matching trap to be aware of: the CefSharp DLLs report a FileVersion of 141.0.110.0 (four-part), but the NuGet package ID uses 141.0.110 (three-part, no trailing zero). I verified the correct version by querying the NuGet flat container API directly rather than guessing.
The packages I downloaded and extracted:
chromiumembeddedframework.runtime.win-x64 141.0.11 — 151.7 MB NuGet package containing libcef.dll, chrome_elf.dll, libEGL.dll, libGLESv2.dll, vk_swiftshader.dll, vulkan-1.dll, plus two DLLs new to CEF 141 x64 not present in the original x86 build: dxcompiler.dll and dxil.dll. Also contains all locale .pak files (220 files including gendered language variants) and the chrome_100_percent.pak, chrome_200_percent.pak and resources.pak files that were missing from the admin-install extraction.
CefSharp.Common 141.0.110 — 23 MB. The CefSharp/x64/ subdirectory contains the two C++/CLI mixed-mode assemblies that must be replaced: CefSharp.Core.Runtime.dll and CefSharp.BrowserSubprocess.Core.dll, along with their .pdb symbols and a new CefSharp.Core.Runtime.xml documentation file.
SQLitePCLRaw.lib.e_sqlite3 2.1.4 — provides runtimes/win-x64/native/e_sqlite3.dll.
Microsoft.Web.WebView2 1.0.3537.50 — provides runtimes/win-x64/native/WebView2Loader.dll.
Microsoft.SqlServer.Types 160.1000.6 and 14.0.1016.290 — the older 14.x package is the source of msvcr120.dll x64, found in nativeBinaries/x64/. This runtime is not in Windows System32 by default but was present in the original build.
Building the x64 File Set
With all source material ready, I assembled the final x64 build in a working directory. The process had several distinct steps:
1. Base Copy & Cleanup
Copied all extracted files to the build folder. Immediately removed watchdog\x86\ entirely — no 32-bit watchdog is needed alongside a 64-bit player.
2. Patch XiboClient.exe
Located the CLR header via the PE structure, read the Flags DWORD at CLR+16. Was 0x0003. Cleared bit 1. Wrote 0x0001. PE machine type left unchanged at 0x014C.
3. Patch Xibo.scr
The screensaver is also a .NET assembly with the same CLR flags problem. Applied the identical 0x0003 → 0x0001 patch.
4. Replace CefSharp DLLs
Extracted CefSharp/x64/ from the NuGet package and replaced CefSharp.Core.Runtime.dll and CefSharp.BrowserSubprocess.Core.dll with genuine x64 C++/CLI builds.
5. Replace CEF Runtime
Replaced all native CEF DLLs from runtimes/win-x64/native/. Added dxcompiler.dll and dxil.dll which are new in CEF 141 x64. Updated the full locales/ directory.
6. SQLite, WebView2, msvcr120
Dropped in the x64 builds of e_sqlite3.dll, WebView2Loader.dll, and msvcr120.dll from their respective NuGet packages.
7. Update Watchdog Config
Edited watchdog\x64\XiboClientWatchdog.exe.config: changed ProcessPath from C:\Program Files (x86)\Xibo Player\... to C:\Program Files\Xibo Player\...
The patch for XiboClient.exe in PowerShell looks like this:
Creating the MSI Installer with WiX
The original MSI cannot simply be repacked with the swapped binaries. It was built with Advanced Installer 19.8.1, which embeds proprietary custom DLLs (aicustact.dll, Prereq.dll, SoftwareDetector.dll) as Binary table entries. These implement prerequisite downloading, path resolution and DPI scaling. They are Advanced Installer's own IP — not redistributable, not usable outside their toolchain. Compiling the decompiled WXS back fails immediately because those DLLs are unavailable.
A fresh WiX-based MSI was the right solution. WiX 3.14 (wix3141rtm) is available as a portable binary zip from GitHub — no installation required. I used four tools from it: candle.exe (compiler), light.exe (linker), heat.exe (file harvester), and dark.exe (decompiler, used earlier for analysis).
Harvesting 314 Files Automatically
Rather than manually defining component entries for every file, heat.exe can scan the build directory and generate them:
This produced a 90 KB WXS file with 1,307 lines, correctly handling all subdirectories. One post-processing fix was needed: heat.exe named the watchdog\x64\ directory with Id="x64", which collides with the reserved MSI public property X64. The linker rejects this with ICE99. I renamed every occurrence to Id="watchdog_x64_dir" and updated the corresponding shortcut WorkingDirectory reference.
Key Product.wxs Decisions
Platform="x64" on the Package element marks the MSI as a 64-bit installer. The summary information Template property becomes "x64;1033".
ProgramFiles64Folder as the install root ensures the player lands in C:\Program Files\Xibo Player\ rather than the x86 path.
UpgradeCode matches the original x86 MSI so the x64 installer auto-detects and replaces the existing installation. AllowDowngrades="yes" handles version comparison edge cases — the original MSI stores "4.406.3" as its version string, which packs to an effective internal value higher than standard MSI notation expects.
All FEATURE_BROWSER_EMULATION and FEATURE_GPU_RENDERING keys written with Win64="yes" to reach the 64-bit hive. All WOW6432Node entries from the original MSI deliberately omitted — those only matter for 32-bit processes.
"Xibo Player" (maximised), "Xibo Player Options" (argument "o"), "Xibo Player Watchdog" (minimised, targets watchdog\x64\XiboClientWatchdog.exe), and a Startup folder shortcut for auto-launch.
The Compilation Commands
With both WXS files ready, candle compiles and light links:
Output
xibo-client-v4-R406.3-win64-x64.msi — 172.7 MB. Zero errors, zero warnings. Verified via the Windows Installer COM API: Platform/Template = "x64;1033", APPDIR parent = ProgramFiles64Folder, all four shortcuts present.
Wrapping It in a Bootstrapper for VC++ Auto-Install
After testing on the first target machine, the installer blocked with a prerequisite error: VC++ 2015-2022 x64 redistributable was not present. Digital signage players are managed devices — expecting an end user to manually install runtimes before running your installer is not acceptable.
The solution is a WiX Burn bootstrapper: a setup.exe wrapper that silently installs prerequisites before launching the MSI. I downloaded the VC++ x64 redist (24.4 MB) from Microsoft's official permalink and embedded it directly in the bundle so it works completely offline:
The Bundle.wxs detects whether VC++ is already installed via a registry search, and only runs the installer if it is missing:
One gotcha: the Burn linker cannot extract an icon from a .NET managed EXE — it expects a standard Win32 resource section. The icon had to be extracted first using System.Drawing.Icon.ExtractAssociatedIcon() and saved as a standalone .ico file before passing it to the bundle.
Final output: xibo-client-v4-R406.3-win64-x64-setup.exe at 196.6 MB. This single file checks for VC++, installs it silently if missing, then runs the Xibo Player MSI which removes the old x86 installation and installs the x64 build to C:\Program Files\Xibo Player\.
Monitoring RAM to Confirm It Works
Since Xibo runs fullscreen and takes over the display, you cannot simply alt-tab to Task Manager to watch memory climbing. I wrote a background PowerShell script that runs before Xibo launches, samples process memory every 30 seconds, and logs to a CSV on the Desktop. No screen interaction needed — check the file when you want results.
On the x86 build, the working set would climb to around 3.5 GB and the process would terminate. On the x64 build, memory climbs freely past 4 GB on heavy layouts and stabilises. No crash, no paging, no frozen player.
What Hardware to Run Xibo On
If you are setting up a new Xibo deployment and need reliable hardware for a signage player, small form factor refurbished business PCs are a cost-effective choice. They are quiet, power efficient, and designed for 24/7 operation. With the x64 build removing the RAM ceiling, a machine with 16 GB or more is worth having for anything beyond basic layouts.
These Dell OptiPlex micro PCs are commonly used for digital signage and are available renewed at reasonable prices:
Dell OptiPlex 7050 USFF
Intel Core i7-6700T • 16 GB RAM • 512 GB SSD • Wi-Fi • Bluetooth • Windows 11 Pro
View on AmazonDell OptiPlex 7060 MFF
Intel Core i5-8500T • 16 GB RAM • 256 GB NVMe SSD • Windows 11 Pro
View on AmazonDell OptiPlex 3070 USFF
Intel Core i5-9500T • 8 GB RAM • 256 GB SSD • Wi-Fi • Windows 11 Pro
View on AmazonDell OptiPlex 3060 Mini
Intel Core i3-8100T • 8 GB DDR4 • 128 GB SSD • Windows 11 Pro
View on AmazonFor light deployments — a single zone, basic images and text — the i3 or i5 machines with 8 GB are perfectly adequate. For anything heavier (multiple video zones, CefSharp-heavy HTML widgets, live web content), stepping up to a 16 GB machine and an 8th gen or newer processor will give the x64 build proper room to breathe. The 7060 with an i5-8500T and 16 GB is a solid middle ground.
Good for light layouts
- Single zone image or video loops
- Basic ticker and text widgets
- RSS feeds and simple HTML
- 8 GB RAM is sufficient
- OptiPlex 3060 or 3070 tier
Worth upgrading RAM for
- Multi-zone layouts with video
- Live web content in CefSharp zones
- Multiple HTML widgets simultaneously
- Large image playlists with fast transitions
- 16 GB strongly recommended
What the Whole Process Taught Me
This project turned out to be a useful tour through several layers of Windows internals that do not often come up in day-to-day work. The PE header format and CLR flags are things most developers never need to think about because the toolchain handles them automatically. When you need to patch a binary you do not have source code for, they become very relevant very quickly.
The NuGet package sourcing was straightforward once I understood that .nupkg files are just ZIP archives and that CefSharp distributes both architectures in the same package under separate subdirectories. The version matching trap — FileVersion 141.0.110.0 versus NuGet package ID 141.0.110 — is the kind of thing that wastes an hour if you do not know to look for it.
WiX took the most time, partly because the original installer used Advanced Installer's proprietary extensions (which cannot be reused) and partly because of the MSI version comparison edge case with "4.406.3". Windows Installer packs version strings into a DWORD with 8-bit fields — a minor version above 255 gets truncated, which means the effective stored version is higher than naive three-part comparison would suggest. That is why a bump to 5.0.0 was needed to ensure the new installer would always supersede the old one regardless of how it was stored.
The Burn bootstrapper was the cleanest part of the whole thing. WiX's bundle format is exactly designed for this scenario — wrap an MSI with prerequisite detection and silent installation, embed the runtime, ship one EXE. It just works.
Summary of Changes Made
Nothing changed about how Xibo behaves
No functionality was altered. No UI was changed. No configuration format was modified. The player connects to the CMS, downloads layouts, and plays content exactly as before — it just no longer crashes when it needs more than 4 GB of RAM to do it.
Final Thoughts
The end result is a 196.6 MB setup.exe that is a drop-in replacement for the official x86 installer. It detects and replaces the existing x86 Xibo Player installation automatically, installs VC++ silently if it is not already present, writes all registry keys to the correct 64-bit hive, and places everything under C:\Program Files\Xibo Player\ — where a 64-bit application belongs.
If you are running Xibo in a demanding signage environment and hitting consistent crashes on heavy layouts, the 32-bit ceiling is almost certainly the cause. The conversion is not trivial — it involves several layers of binary work that the official toolchain normally handles invisibly — but the result is a stable player that can actually use the hardware it is running on.
Comments
Post a Comment