Converting Xibo Windows Client from 32-bit to 64-bit: A Complete Technical Walkthrough

Digital Signage & Windows Engineering

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.

Xibo Player v4 R406.3 x86 → x64 .NET CLR Patching CefSharp / Chromium WiX Toolset 3.14 Digital Signage
Disclaimer: I have no affiliation with, am not employed by, and receive no compensation from Xibo Signage Ltd. This is an unofficial community build — it is not produced, endorsed, or supported by Xibo Signage Ltd in any way. Xibo is a trademark of Xibo Signage Ltd. The Xibo Windows Player is open-source software released under the GNU Affero General Public License v3 (AGPLv3), which permits free redistribution and modification. This build is provided free of charge to help other Xibo users. The original source code is available at github.com/xibosignage/xibo-dotnetclient; all modifications made to produce this x64 build are documented in full in this article.

Download the x64 Installer

Unofficial community build — replaces the x86 installation automatically. Includes VC++ 2015–2022 x64 redistributable.

Xibo Player v4 R406.3 x64 (64-bit) 196.6 MB Windows 10 / 11 VC++ Bundled
⬇ Download Setup.exe

Not 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:

0x014C = IMAGE_FILE_MACHINE_I386 (x86 / 32-bit) 0x8664 = IMAGE_FILE_MACHINE_AMD64 (x64 / 64-bit)

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:

Bit 0 (0x0001) COMIMAGE_FLAGS_ILONLY — assembly is pure MSIL, no native code Bit 1 (0x0002) COMIMAGE_FLAGS_32BITREQUIRED — force 32-bit even on 64-bit OS

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.

The key insight: for a pure MSIL .NET assembly, you do not need to recompile anything. A two-byte patch to the CLR flags is all that is required to unlock 64-bit execution.

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:

msiexec /a xibo-client-v4-R406.3-win32-x86.msi TARGETDIR=D:\Xibo\_extracted\ /qn

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:

ProductCode

{95D9C9E5-F261-4E15-9106-2B1A3B508B07}

UpgradeCode

{443E7578-7FEF-47E8-9078-04DDA8B96F3A} — used in the new MSI so it auto-replaces the x86 installation

Install Path

[ProgramFilesFolder]\[ProductName] — the x86 path. Needs changing to ProgramFiles64Folder.

Build Tool

Advanced Installer 19.8.1 — uses proprietary DLLs (aicustact.dll, Prereq.dll) that cannot be redistributed. A fresh WiX MSI was required.

Prerequisites

VC++ 2015-2022 x86 redistributable. Needs to become x64.

Registry

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:

CEF Runtime x64

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

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.

SQLite x64

SQLitePCLRaw.lib.e_sqlite3 2.1.4 — provides runtimes/win-x64/native/e_sqlite3.dll.

WebView2 x64

Microsoft.Web.WebView2 1.0.3537.50 — provides runtimes/win-x64/native/WebView2Loader.dll.

SqlServer Types

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:

# Read raw bytes $bytes = [System.IO.File]::ReadAllBytes("XiboClient.exe") # Follow PE pointer at 0x3C to find PE header offset $peOff = [BitConverter]::ToInt32($bytes, 0x3C) # CLR header RVA is at PE+0xE8 (COM descriptor data directory) $clrRva = [BitConverter]::ToInt32($bytes, $peOff + 0xE8) # Convert RVA to file offset using section table, then read # Flags DWORD at CLR+16. Was: 0x0003. Clear bit 1: write 0x0001. $bytes[$clrFlagsOffset] = 0x01 $bytes[$clrFlagsOffset + 1] = 0x00 [System.IO.File]::WriteAllBytes("XiboClient.exe", $bytes)

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:

heat.exe dir D:\Xibo\_build_x64 -cg XiboFiles -dr APPDIR -gg -gl -srd -sreg -sfrag -suid -var var.BuildDir -out D:\Xibo\_wix_src\Files.wxs

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

Platform="x64" on the Package element marks the MSI as a 64-bit installer. The summary information Template property becomes "x64;1033".

Install Path

ProgramFiles64Folder as the install root ensures the player lands in C:\Program Files\Xibo Player\ rather than the x86 path.

Upgrade Logic

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.

Registry

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.

Shortcuts

"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:

# Compile both source files to .wixobj candle.exe -arch x64 "-dBuildDir=D:\Xibo\_build_x64" -ext WixNetFxExtension.dll -ext WixUIExtension.dll -out D:\Xibo\_wix_obj\ Product.wxs Files.wxs # Link to final MSI — suppress two known false-positive ICE warnings light.exe -ext WixNetFxExtension.dll -ext WixUIExtension.dll -sice:ICE69 -sice:ICE90 -out xibo-client-v4-R406.3-win64-x64.msi -b D:\Xibo\_build_x64 Product.wixobj Files.wixobj

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:

# Official Microsoft permalink — always points to latest 2015-2022 x64 https://aka.ms/vs/17/release/vc_redist.x64.exe

The Bundle.wxs detects whether VC++ is already installed via a registry search, and only runs the installer if it is missing:

<util:RegistrySearch Id="VCRedistX64Search" Variable="VCRedistX64Installed" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X64" Value="Installed" Win64="yes" /> <ExePackage Id="VCRedistX64" SourceFile="vc_redist.x64.exe" InstallCommand="/install /quiet /norestart" DetectCondition="VCRedistX64Installed = 1" Vital="yes" Permanent="yes" /> <MsiPackage Id="XiboPlayer" SourceFile="xibo-client-v4-R406.3-win64-x64.msi" Vital="yes" />

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.

$log = "$env:USERPROFILE\Desktop\xibo-ram-log.csv"; $peak = 0 "Timestamp,WorkingSet_MB,Private_MB,Peak_WorkingSet_MB" | Out-File $log while ($true) { $p = Get-Process XiboClient -ErrorAction SilentlyContinue if ($p) { $ws = [math]::Round($p.WorkingSet64 / 1MB, 1) $pr = [math]::Round($p.PrivateMemorySize64 / 1MB, 1) if ($ws -gt $peak) { $peak = $ws } "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss'),$ws,$pr,$peak" | Out-File $log -Append } Start-Sleep 30 }

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.

The result: the player now runs through layouts that previously crashed it every time, on the same hardware, with no changes to how anything is configured or displayed.

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:

Renewed

Dell OptiPlex 7050 USFF

Intel Core i7-6700T • 16 GB RAM • 512 GB SSD • Wi-Fi • Bluetooth • Windows 11 Pro

View on Amazon
Renewed

Dell OptiPlex 7060 MFF

Intel Core i5-8500T • 16 GB RAM • 256 GB NVMe SSD • Windows 11 Pro

View on Amazon
Renewed

Dell OptiPlex 3070 USFF

Intel Core i5-9500T • 8 GB RAM • 256 GB SSD • Wi-Fi • Windows 11 Pro

View on Amazon
Renewed

Dell OptiPlex 3060 Mini

Intel Core i3-8100T • 8 GB DDR4 • 128 GB SSD • Windows 11 Pro

View on Amazon

For 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

CLR flags patched on XiboClient.exe
CLR flags patched on Xibo.scr
CefSharp x64 DLLs replaced
CEF x64 runtime replaced
dxcompiler.dll + dxil.dll added
220 locale PAK files updated
e_sqlite3.dll x64 replaced
WebView2Loader.dll x64 replaced
msvcr120.dll x64 added
watchdog\x86\ removed
Watchdog config path updated
WiX x64 MSI authored
ProgramFiles64Folder install path
64-bit registry hive only
WOW6432Node entries removed
Burn bootstrapper with VC++ redist

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.

The short version: two bytes changed in the CLR header unlock the whole thing. Everything else — replacing native DLLs, authoring the MSI, building the bootstrapper — is the work that makes those two bytes actually mean something in a production deployment.

Comments

Popular posts from this blog

Why I Built My PC Around the AMD Ryzen 9 9950X3D

Building the Trofeo Vision App Thermalright Should Have Shipped