Coming from WiX
If you know WiX, you already know MSI. FalkForge targets the same Windows Installer tables — it just uses C# instead of XML. This guide translates the WiX patterns you know into FalkForge equivalents.
Concepts mapping
| WiX | FalkForge | Notes |
|---|---|---|
.wxs source file | Program.cs | C# replaces XML |
<Package> element | PackageBuilder lambda | Fluent API in a lambda |
<Fragment> | C# methods or classes | Just organize your code normally |
<Component> | Auto-generated | FalkForge creates components automatically |
<ComponentGroup> | Not needed | No indirection required |
<Feature> / <ComponentRef> | .WithFeature("name") | Chain onto any file, registry entry, or service |
<Directory> tree | Auto-resolved from paths | Specify target path, directories are inferred |
WixUI_Mondo etc. | DialogTemplate.Mondo | Same 5 templates |
<Property> | MsiProperty class | Type-safe with comparison operators |
<Condition> | Condition class | &, |, ! operators |
.wxl localization files | JSON localization | Culture fallback chain |
| Burn bootstrapper | Bundle engine | NativeAOT compiled, DPAPI secure properties |
wix build CLI | forge build or dotnet run | |
wix msi decompile | forge decompile / forge migrate | decompile = C# snippet; migrate = full buildable project |
| Extension NuGet packages | Built-in extensions | No extra packages to install |
wix.exe | forge CLI | build, validate, inspect, decompile commands |
Common patterns
Each pattern shows WiX v4 XML on the left and FalkForge C# on the right.
Adding files
WiX
<Component Directory="INSTALLFOLDER">
<File Source="app.exe" />
</Component>
FalkForge
package.AddFile("payload/app.exe")
.To("INSTALLFOLDER")
.WithFeature("Main");
Deep dive: Automatic components
FalkForge auto-creates the component. In WiX you must define Component + File + assign to a Feature via ComponentRef. In FalkForge, .WithFeature() handles all of that.
Registry entries
WiX
<Component Directory="INSTALLFOLDER">
<RegistryValue Root="HKLM"
Key="SOFTWARE\MyApp"
Name="InstallDir"
Type="string"
Value="[INSTALLFOLDER]" />
</Component>
FalkForge
package.AddRegistryEntry(
RegistryHive.LocalMachine,
@"SOFTWARE\MyApp",
"InstallDir",
"[INSTALLFOLDER]")
.WithFeature("Main");
Windows services
WiX
<Component Directory="INSTALLFOLDER">
<File Source="myservice.exe" />
<ServiceInstall
Name="MyService"
DisplayName="My Service"
Start="auto"
Type="ownProcess"
Account="LocalSystem" />
<ServiceControl
Id="StartMyService"
Name="MyService"
Start="install"
Stop="both"
Remove="uninstall" />
</Component>
FalkForge
package.AddFile("payload/myservice.exe")
.To("INSTALLFOLDER")
.WithFeature("Server")
.AddService("MyService", svc => svc
.DisplayName("My Service")
.StartType(ServiceStartType.Automatic)
.Account(ServiceAccount.LocalSystem));
Deep dive: Automatic service control
FalkForge generates both ServiceInstall and ServiceControl rows automatically. In WiX you must author both explicitly.
Shortcuts
WiX
<Component Directory="ProgramMenuFolder">
<Shortcut Id="StartMenuShortcut"
Name="My App"
Target="[INSTALLFOLDER]app.exe"
WorkingDirectory="INSTALLFOLDER" />
<RemoveFolder Id="RemovePMF"
On="uninstall" />
<RegistryValue Root="HKCU"
Key="SOFTWARE\MyApp"
Name="installed"
Type="integer"
Value="1"
KeyPath="yes" />
</Component>
FalkForge
package.AddShortcut("My App",
"[INSTALLFOLDER]app.exe")
.ToStartMenu()
.WithFeature("Main");
Deep dive: KeyPath and RemoveFolder
In WiX, a shortcut component needs a registry KeyPath because shortcuts can't be key paths. FalkForge handles this automatically.
Features
WiX
<Feature Id="Main"
Title="Main Application"
Level="1">
<ComponentRef Id="AppComponent" />
<Feature Id="Plugins"
Title="Optional Plugins"
Level="1">
<ComponentRef Id="Plugin1" />
</Feature>
</Feature>
FalkForge
package.AddFile("payload/app.exe")
.WithFeature("Main");
package.AddFile("payload/plugin1.dll")
.WithFeature("Plugins", parent: "Main");
Custom actions
WiX
<CustomAction Id="SetInstallDir"
Property="INSTALLFOLDER"
Value="C:\MyApp" />
<InstallExecuteSequence>
<Custom Action="SetInstallDir"
Before="CostFinalize" />
</InstallExecuteSequence>
FalkForge
package.AddSetPropertyAction(
"INSTALLFOLDER", @"C:\MyApp")
.Before(SequenceAction.CostFinalize);
Properties and conditions
WiX
<Property Id="MYPROP"
Value="default" />
<Condition Message="Requires Windows 10">
<![CDATA[VersionNT >= 1000]]>
</Condition>
FalkForge
package.SetProperty("MYPROP", "default");
package.AddLaunchCondition(
Condition.IsWindows10OrLater,
"Requires Windows 10");
Deep dive: Type-safe conditions
Condition provides pre-built checks like IsWindows10OrLater, Is64BitOS, IsAdmin. You can combine them with &, |, ! operators.
Major upgrade
WiX
<MajorUpgrade
DowngradeErrorMessage="A newer version is installed." />
FalkForge
package.MajorUpgrade(upgrade => upgrade
.BlockDowngrades(
"A newer version is installed."));
Localization
WiX (.wxl file)
<WixLocalization
Culture="en-US"
xmlns="http://wixtoolset.org/schemas/v4/wxl">
<String Id="WelcomeTitle">Welcome</String>
</WixLocalization>
FalkForge
package.Localization(loc => loc
.AddBuiltInCultures()
.DefaultCulture("en-US")
.DetectCulture());
Deep dive: JSON localization
FalkForge uses JSON localization files instead of WiX's XML .wxl format. Built-in cultures ship with en-US and sv-SE. Custom cultures use the same JSON format.
Launch conditions
WiX
<Launch
Condition="Privileged"
Message="Administrator privileges required." />
FalkForge
package.AddLaunchCondition(
Condition.IsPrivileged,
"Administrator privileges required.");
Extension mapping
| WiX Extension | FalkForge | Notes |
|---|---|---|
| WixToolset.Firewall.wixext | Extensions.Firewall | Built-in, no package needed |
| WixToolset.Iis.wixext | Extensions.Iis | AppPool, WebSite, Bindings, Certificates |
| WixToolset.Sql.wixext | Extensions.Sql | DB creation, script execution |
| WixToolset.Netfx.wixext | Extensions.DotNet | Registry + filesystem probing |
| WixToolset.Util.wixext | Extensions.Util | XmlConfig, UserMgmt, FileShare, QuietExec |
| WixToolset.Dependency.wixext | Extensions.Dependency | WiX-compatible provider/consumer model |
| WixToolset.Http.wixext | Extensions.Http | SNI/SSL bindings, URL reservations |
| WixToolset.UI.wixext | DialogTemplate (built-in) | 5 built-in templates |
| WixToolset.Bal.wixext | InstallerApp + InstallerPage<T> | Built-in WPF UI framework |
Bundle migration
WiX Burn and FalkForge bundles serve the same purpose — chaining multiple packages into a single installer. Key differences:
- NativeAOT engine — no .NET runtime needed at install time. The bundle engine is a self-contained native executable.
- DPAPI secure property passing — properties never appear as plaintext command-line arguments. Secure values are passed via named pipe IPC and protected with Windows DPAPI.
- IMsiApi P/Invoke — MSI packages are installed via direct Windows Installer API calls, not by spawning
msiexec.exeas a subprocess. - Built-in WPF UI — no need to write a custom bootstrapper application from scratch. Use
InstallerPage<TView>with ReactiveUI for custom installer pages. - JSON update feeds — simpler than Atom XML. Configure with
UpdatePolicyfor notify-only, download-and-prompt, or auto-update. - Same package types — MSI, MSP, MSU, EXE, and nested Bundle are all supported.
What you gain
- Compile-time validation — typos caught at build, not install time.
- MSIX output — build MSI and MSIX from the same codebase.
- SBOM generation — CycloneDX format for supply chain security.
- Triple decompiler — decompile MSI, FalkForge bundles, and WiX Burn bundles.
- NativeAOT engine — smaller, faster, no runtime dependency.
- Built-in WPF custom UI —
InstallerPage<TView>with ReactiveUI. - ECDSA payload signing — free, built-in tamper-evident integrity verification for bundle payloads, no external tool required. An optional separate tool, Sigil, adds SBOM attestation on top (see Sigil in the reference docs).
- Compile-time security guards — REG007 warns when registry values reference password properties. WiX has no equivalent compile-time check.
- WinGet manifest generation —
.WinGet()on PackageBuilder auto-generates the 3-file YAML manifest set. Advanced Installer charges $2,400+/year for this feature.
Migrating your existing installer
forge migrate is the recommended starting point for any WiX (or other tool) migration. It reads your compiled .msi, .msm, or WiX Burn .exe and writes a complete, buildable FalkForge C# project — not just a code snippet.
Run it
forge migrate your-product.msi -o ./migrated --falkforge-src /path/to/falkforge/src
After it finishes, ./migrated/ contains:
Program.cs— full fluent API installer definition, reconstructed from the MSI databaseYourProduct.csproj— project file with references to FalkForge.Core and Compiler.Msipayload/— files extracted from the original MSI cabinetMIGRATION-REPORT.md— lists anything that did not map automatically (complex custom actions, unusual sequences, etc.)
Build the generated project immediately:
dotnet build migrated/
If the build succeeds, the round-trip is complete. You now have an editable FalkForge project that produces an equivalent installer.
Flags
| Flag | Description |
|---|---|
<file> | Installer to migrate (.msi, .msm, or .exe) |
-o / --output | Output directory (default: <filename>-migrated) |
--falkforge-src | Path to the FalkForge src/ directory; sets the ProjectReference in the generated .csproj |
Deep dive: migrate vs. decompile
forge decompile produces a C# code snippet you can read and copy from. It is useful for inspecting an MSI or getting a quick translation of one section.
forge migrate produces a complete project you can edit and rebuild. Use migrate when your goal is to switch your installer to FalkForge permanently. Use decompile when you just want to inspect or lift a pattern.
See demo/54-forge-migrate for a full round-trip example, including a PowerShell script that automates all three steps (build sample MSI → migrate → build generated project).
Just want to inspect? Use decompile
forge decompile your-product.msi
This generates a C# snippet from your existing MSI. Good for inspecting structure or lifting specific patterns, but it is not a buildable project. Use forge migrate (above) for a full migration.