Do Business Apps Run on Windows on Arm? — The Reality of x64 Emulation (Prism) and Native DLLs/COM
· Go Komura · Windows on Arm, Arm64, x64 Emulation, Native Interop, P/Invoke, COM, Driver, C#, .NET, Windows Development, Technical Consulting
“Starting next month we’re moving to a new PC, one of these Copilot+ PCs — will our business system run on it?” As corporate adoption of Snapdragon-powered PCs advances, more and more development shops and IT departments are fielding this question. The marketing copy says “existing apps also run via emulation.” But your own business app P/Invokes a vendor-supplied native DLL behind its C# UI, generates reports through a COM component, and, on top of all that, has a driver installed for dedicated hardware. Honestly, “will it run?” isn’t a question you can answer on the spot.
The short answer up front: “the app itself will usually run fine. What’s dangerous is everything hanging off the app.” Windows 11’s emulation handles x86/x64 user-mode code with fairly impressive accuracy, but there’s a clearly defined “outside emulation’s jurisdiction” zone made up of drivers, shell extensions, and architecture mixing within a process — and that zone happens to be exactly where business apps have historically loved to live.
This article works through how Windows on Arm’s emulation works and where its limits are, the fundamental rule that x64 and Arm64 can’t be mixed within a process, the combination problem specific to .NET apps, and the practical steps for checking “will our app run on an Arm machine” — all backed by what’s verifiable on Microsoft Learn.
1. The Bottom Line First
- A purely managed (.NET) app, or an ordinary x86/x64 desktop app, will run almost entirely fine under Arm Windows 11’s emulation. Emulation is built into the OS — no app modification or extra component is needed.1
- Emulation only takes care of user-mode code. Kernel-mode drivers are not emulated and absolutely require Arm64-native builds. UMDF drivers and printer drivers likewise need to match the OS’s architecture.23
- Shell extensions, IMEs, assistive technologies — anything that’s a “DLL loaded into another process” (Explorer and the like) — also need to be recompiled for Arm64, matching the system. Emulation can’t rescue these.4
- x64 and Arm64 cannot coexist inside a single process. An x64/Arm64EC process can only load x64 and Arm64EC binaries; an Arm64 process can only load Arm64 binaries. An x64 exe can’t call an Arm64 DLL, and neither can the reverse.5
- The mechanisms for getting past this restriction within a single file are Arm64EC (native Arm64 code that can coexist with x64 in the same process) and Arm64X (a binary that lets Arm64 and Arm64EC coexist in one PE, loadable into either kind of process). Arm64X is exactly where a COM in-process server or plugin that’s called from both architectures comes in.56
- .NET officially supports Arm64, and you can publish natively with the RID
win-arm64. On the other hand, run an AnyCPU app on an Arm64 .NET runtime and the process runs as Arm64, so if it’s P/Invoking a native DLL that’s only available in x64, loading it fails — a combination problem worth knowing about.785 - Besides physical hardware (a Copilot+ PC, etc.), you can set up a test environment with a Windows 11 Arm64 VM on Azure, or the Windows 11 Arm64 ISO, usable on Hyper-V on an Arm machine or on an Apple Silicon Mac. Note that you can’t create an Arm64 VM on Hyper-V running on an x64 machine.910
2. What Is Windows on Arm — Snapdragon PCs and Prism
Windows on Arm is Windows running on an Arm64 processor. Since 2024, most “Copilot+ PCs” — a new category of Windows 11 machine equipped with an NPU capable of over 40 trillion operations per second (40+ TOPS) — have adopted Arm-based Snapdragon X-series chips, making this something developers can no longer ignore.1112
What underpins compatibility with existing apps is emulation built into the OS. Here’s how it works, in brief.1
- The emulator JIT-compiles blocks of x86/x64 instructions into Arm64 instructions, caching the translated result per module so subsequent launches are faster.
- Windows 11 can emulate both x86 and x64. Windows 10 on Arm can only emulate x86, so any discussion of x64 business apps effectively assumes Windows 11.
- Windows 11 24H2 introduced a new emulator, Prism, which improves performance over the previous one and lowers CPU usage. Prism is optimized for Qualcomm Snapdragon chips.
- 32-bit (x86) apps run on top of the same WOW64 layer as on x64 Windows, and get file-system/registry redirection. x64 apps, on the other hand, have no WOW64 layer — because system binaries are compiled in the Arm64X format described below, x64 apps can access the entire OS (both the file system and the registry) without redirection.1
The CPU information visible from an app running under emulation is that of the “emulated virtual processor.” For compatibility’s sake, even GetNativeSystemInfo returns the emulated value, so if you want to detect whether the host is actually Arm64, use IsWow64Process2 or GetMachineTypeAttributes.13
For apps that run into trouble under emulation, Windows also provides a way to change emulation settings (default/safe/strict/very strict presets, plus individual fine-grained options) by right-clicking the exe, going to Properties, and opening the Compatibility tab. This trades some performance for compatibility, but it’s worth remembering as an escape hatch for the “this used to work on an older version of Windows on Arm” case.14
3. What Runs Under Emulation, and What Doesn’t
The answer to “will it run?” is determined not by the app itself, but by the kind of dependency involved. Here’s a decision table.
| Category | Behavior on Arm Windows 11 | Basis / notes |
|---|---|---|
| x86/x64 user-mode app (an exe plus a full set of same-architecture DLLs) | Runs under emulation | Unmodified, no extra install needed1 |
| .NET (managed) app | Runs (native Arm64 execution is also possible) | See Chapter 58 |
| Kernel-mode driver | Doesn’t run. Requires Arm64-native | There’s no emulation in the kernel23 |
| UMDF driver / printer driver | Requires the same Arm64 as the OS | Even if the app itself runs under emulation, driver-dependent features won’t work3 |
| Shell extension / IME / assistive technology (a DLL loaded into another process) | Requires an Arm64 recompile | Explorer right-click menus, cloud-storage icon overlays, and the like4 |
| x86 apps that forbid dynamic code generation | Won’t run under emulation | The emulator generates Arm64 instructions at runtime, so ProcessDynamicCodePolicy needs to be relaxed4 |
| Games depending on older OpenGL or anti-cheat drivers | May not run | OpenGL beyond 3.3, or anti-cheat without Arm support, are obstacles15 |
| Peripherals (printers, scanners, dedicated devices) | Determined by whether an Arm64 driver exists | Requires an Arm64 driver, either bundled with the OS or supplied by the vendor15 |
| Antivirus and “software that changes how Windows behaves” | Requires per-product confirmation | Arm support has come a long way, but confirming per product is still recommended15 |
Translated into business-app terms, the red flags look like this:
- VPN clients, asset-management agents, security products — these are essentially bundles of kernel drivers. You need to check with the vendor whether an Arm64-supported version exists.
- USB-dongle license enforcement, dedicated hardware (measurement instruments, payment terminals, etc.) — whether an Arm64 device driver is provided is the make-or-break factor.
- “Adds a feature to Explorer” tools — shell extensions get loaded into Arm64 Explorer, so they simply won’t function while they remain x64.
- Even if the app itself doesn’t fall into these categories, a case where the installer bundles a driver (such as PDF output implemented via a virtual printer driver) runs into the same problem.
4. Mixing Architectures Inside a Process Is Impossible — the Reality of P/Invoke and COM
Since the 32-bit era, there’s been an iron rule: “a 64-bit process cannot load a 32-bit DLL.”16 Windows on Arm has an equivalent structural rule. The official documentation lays out load compatibility as follows.5
| Process architecture | x64 DLL | Arm64EC DLL | Arm64 DLL | Arm64X DLL |
|---|---|---|---|---|
| x64 / Arm64EC process | Loadable | Loadable | Not loadable | Loadable |
| Arm64 process | Not loadable | Not loadable | Loadable | Loadable |
Two mechanisms show up here, and they’re the key to thinking through Arm-readiness design.
- Arm64EC (Emulation Compatible) is a native Arm64 code ABI that follows x64’s calling convention, stack usage, and data layout, so that it can coexist within the same process with x64 code running under emulation. When an x64 app runs on Windows 11 on Arm, most of the OS code loaded into that process is already compiled as Arm64EC, running at native speed without the app ever knowing. This lets you take a gradual migration path — Arm64EC-ify your own code first, one piece at a time, to gain performance, while dependent DLLs stay x64.5
- Arm64X is a binary format that lets traditional Arm64 code and Arm64EC code coexist in a single PE file. Depending on whether the loading process is x64 or Arm64, it behaves as an x64 DLL or an Arm64 DLL respectively, which makes it well suited to a DLL that might be called from processes of either architecture. The official documentation lists “a 64-bit COM server called from both x64 and Arm64 apps,” “a plugin loaded into either x64 or Arm64 apps,” and “a single binary injected into x64/Arm64 processes” as situations where Arm64X is needed.6
Let’s make the real-world impact on business apps concrete.
Case 1: an x64 exe plus an x64 native DLL (P/Invoke). If the entire process is uniformly x64, it runs entirely inside emulation. You can’t mix in an Arm64 DLL just because you want “only this one part” to be faster (as shown in the table above, that’s simply not loadable).
Case 2: a COM in-process server. A COM in-proc server is just a DLL, so the table above applies directly. An x64 client can only use an x64 (or Arm64EC/Arm64X) COM DLL, and the moment you make the app Arm64-native, the x64 COM DLL becomes unloadable. If you need to support both, either make the DLL Arm64X, or apply the tried-and-true pattern from the 32-bit/64-bit era: out-of-process COM/IPC separation (splitting into separate processes connected via inter-process communication). Crossing an architecture boundary at a process boundary has always been the standard approach.166
Case 3: you host a plugin, or you are a plugin. Excel add-ins, plugins for business-package software, print middleware, and any other form where “your DLL gets loaded into someone else’s process” must match the other party’s architecture. Conversely, if your own app hosts plugins, you need to think through the blast radius: making your own app Arm64-native will wipe out every x64 third-party plugin.
Incidentally, you can check what architecture a given binary actually is from a Developer Command Prompt.5
link /dump /headers MyLibrary.dll | findstr machine
# 8664 machine (x64) -> x64
# 8664 machine (x64) (ARM64X) -> includes Arm64EC
# AA64 machine (ARM64) -> Arm64
# AA64 machine (ARM64) (ARM64X) -> Arm64X
5. The Case of .NET Apps — the AnyCPU Trap and Detecting Architecture
.NET (the Core-family runtime) officially supports Windows Arm64, and Windows 11/10 Arm64 is explicitly listed as a supported OS for .NET 8/9/10. Publishing just means specifying win-arm64 as the RID.177
<!-- csproj: publish for Arm64-native -->
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
</PropertyGroup>
dotnet publish -r win-arm64 -c Release
For an app made entirely of managed code, this is essentially the whole job of making it Arm64-native. The JIT simply emits Arm64 code, and no source changes are generally needed. For .NET Framework apps, .NET Framework 4.8.1 added native Arm64 support (for Arm64 machines running Windows 11 — the 4.8.1 runtime does not support native Arm64 apps on Windows 10 Arm machines). A Framework app that stays built as x64 is treated as running under emulation.1819
The problem is the combination that arises when you’re P/Invoking a native DLL. On an Arm machine, the long-standing assumption “it’s a .NET app, so AnyCPU just runs anywhere” gets betrayed.
- Run under an Arm64 .NET SDK/runtime, and the app runs as an Arm64 process by default.8
- An Arm64 process cannot load an x64 DLL (see the table in Chapter 4). In other words, your own AnyCPU code stays untouched, but loading the x64 native DLL you
DllImportfails.5 - Conversely, an app published as
win-x64runs entirely as an x64 process and works inside emulation (native DLL and all). This configuration doesn’t get Arm64-native performance, but it has the highest compatibility.12
What looks like “it works sometimes and not other times” is, more often than not, really a mismatch between the process’s architecture and the architecture of its native dependencies. As a first step toward triage, it’s a huge help to have code on hand that can report what architecture the running process is actually using.
using System.Runtime.InteropServices;
// The process's own architecture (X64 if running under x64 emulation)
Console.WriteLine($"Process: {RuntimeInformation.ProcessArchitecture}");
// The OS's actual underlying architecture (Arm64 on an Arm machine)
Console.WriteLine($"OS: {RuntimeInformation.OSArchitecture}");
One thing to watch out for: OSArchitecture only started returning the “true underlying OS architecture with emulation stripped away” as of .NET 7. Before that, it returned X64 even under emulation, so code on .NET 6 or earlier that uses this API to detect “is this an Arm machine?” won’t behave as expected.2021
Here’s a rundown of the .NET-specific checkpoints.
- Native assets in NuGet packages: a package that only carries
runtimes/win-x64/nativehas nothing to fall back on when you publish forwin-arm64. Check the package contents (or its repository) for the presence ofwin-arm64assets. The RID mechanism exists precisely for this “routing to platform-specific assets.”7 - The dev machine’s SDK layout: on an Arm machine, the Arm64 build of .NET normally installs to
C:\Program Files\dotnet\, while the x64 SDK installs toC:\Program Files\dotnet\x64\, and the two can coexist. Which onedotnet runactually executes as depends on where PATH or DOTNET_ROOT points, so keep that in mind while testing.17 - How to read the exception: an architecture mismatch in a managed assembly shows up as
BadImageFormatException(the official reference itself explicitly lists “loading a component that targets a different platform” as a trigger condition).22
6. An Arm-Readiness Checklist for Your Own App
In practice, it’s efficient to check things in the following three stages.
| Stage | What to do | Judgment |
|---|---|---|
| 1. Inventory dependencies | List every native DLL you P/Invoke, COM component, bundled driver, shell extension, and NuGet package with native assets | Zero drivers or shell extensions is promising. If there are any, check each vendor’s Arm64 support34 |
| 2. Test on real hardware under emulation | Install the app as-is (still an x64 build) on an Arm machine (or an Arm64 VM), and run through the main business scenarios | If it works, “keep running as x64” becomes a viable option. Where it fails, suspect an architecture mismatch in a dependency1 |
| 3. Consider an Arm64-native build | For .NET, publish for win-arm64; for C++, add an Arm64 configuration and check whether the build succeeds |
A build failure typically means a dependency has no Arm64 version. Consider updating it, replacing it, or leaning on Arm64EC23 |
For stages 2 and 3, you have the following options for a test environment.
- Physical hardware: a Snapdragon-based machine such as a Copilot+ PC. Having even one on hand is the most reliable option, including for troubleshooting.12
- Azure VM: in the Azure portal, filter images by Arm64 and create a Windows 11 Arm64 VM (a recommended size such as D2ps_v5, based on Ampere Altra). The advantage is that you can start testing without owning a single Arm machine.9
- Local VM: a Windows 11 Arm64 ISO is officially distributed, and you can build a VM on Hyper-V on an Arm machine or on an Arm-based Apple Silicon Mac. Note that Hyper-V on an x64 machine cannot create an Arm64 VM.10
You can check third-party product compatibility on the status site Microsoft publishes (Works on Windows on Arm), and for line-of-business (LOB) app compatibility issues, the App Assure program provides support at no extra cost for qualifying enterprise plans. Having an official channel available before hitting “it doesn’t work and we’re stuck” is also useful material when explaining the situation to IT staff.1215
7. A Pragmatic Answer for Now — Choosing Among Three Options
Being Arm-ready doesn’t mean “go fully native, no other choice.” In fact, for many business apps, a staged, situational approach is the pragmatic answer.
| Option | Good fit for | Caveats |
|---|---|---|
| (a) Keep running as x64 under emulation | No driver/shell-extension dependency, and performance is already good enough in practice | Prism (24H2+) has already improved performance. Keep the whole process uniformly x64 — don’t mix in Arm64 binaries15 |
| (b) Check with vendors on Arm64 support, or wait | The native DLL/driver in question is third-party | Confirm whether an “Arm64 (or Arm64X) version is planned.” For drivers, there’s no workaround besides waiting323 |
| (c) Build Arm64-native | A pure .NET app, or a case where Arm64 versions of every dependency are already available. When performance or battery life is a requirement | Requires publishing for win-arm64 plus Arm64-ifying every native dependency. If you host plugins, watch the blast radius75 |
If you have a large C++ codebase, there’s a middle ground between (a) and (c): Arm64EC. It’s the official route for the case where “we can’t migrate a huge x64 app all at once” — leaving x64 dependent DLLs as-is while natively porting only your own code, one piece at a time.523
On the tooling side, there’s an Arm64-native version of Visual Studio, and a compiler toolset available on Arm hardware that can target Arm64, x64, and x86 all at once. CI builds can also be produced via cross-compilation on an existing x64 build machine, making it easy to set up a configuration where “only the test run” happens on real Arm hardware or a VM.2423
8. Summary
- Arm Windows 11 can run x86/x64 apps through OS-built-in emulation, and performance has improved further with Prism starting in 24H2. x64 emulation is a Windows 11 feature — Windows 10 on Arm only handles x86.
- Emulation’s jurisdiction is user mode only. Kernel-mode/UMDF/printer drivers, and “DLLs loaded into another process” such as shell extensions, IMEs, and assistive technologies, absolutely require Arm64-native builds. Whether a business app works is determined less by the app itself than by these surrounding dependencies.
- x64 and Arm64 cannot coexist within a process. An x64/Arm64EC process can load x64 plus Arm64EC; an Arm64 process can only load Arm64. Both COM in-process servers and plugins follow this same rule — Arm64X is the standard answer for dual support, and out-of-process COM/IPC is the standard answer for crossing a process boundary.
- .NET can publish natively with
win-arm64, but an AnyCPU app running on the Arm64 runtime runs as an Arm64 process, so it will fail if it’s P/Invoking an x64-only native DLL. Triage withRuntimeInformation.ProcessArchitecture/OSArchitecture(the latter from .NET 7 onward). - The verification procedure is a three-stage flow: “inventory dependencies -> test as-is under emulation on real hardware -> go Arm64-native if needed.” A test environment can be set up via an Azure Arm64 VM or the Arm64 ISO, and enterprises can also draw on App Assure’s support.
- For now, the pragmatic answer is a situational mix: “if it runs under emulation, leave it as is,” “check with driver/DLL vendors on their support status,” and “go Arm64-native if requirements call for it (C++ can also take the staged Arm64EC migration path).”
Related Articles
- Calling a Native DLL from C#: C++/CLI Wrapper vs. P/Invoke
- Calling the Win32 API Safely from C# — a Practical P/Invoke Guide (DllImport / LibraryImport / CsWin32)
- How to Call a C# Native AOT DLL from C/C++
- Single-File Distribution for Windows Apps — Single Binaries and the Limits of OS Dependencies
- A Worked COM Bridge Example: Calling a 64-bit DLL from a 32-bit App
Related Consulting Areas
Komura Software LLC handles investigating whether an existing business app is ready for Windows on Arm, designing architecture migrations for apps that involve native DLLs or COM interop, and root-causing bugs that only occur on Arm machines.
- Windows App Development
- Technical Consulting & Design Review
- Bug Investigation & Root Cause Analysis
- Contact
References
-
Microsoft Learn, How emulation works on Arm. On emulation being built into the OS and able to run unmodified apps, Windows 11 supporting both x86 and x64 while Windows 10 on Arm supports only x86, the JIT translation and per-module caching of x86 instruction blocks, Prism and its Snapdragon optimization in Windows 11 24H2, and x86 apps getting redirection through WOW64 while x64 apps have no WOW64 layer and use Arm64X-compiled system binaries instead. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, How emulation works on Arm. On emulation supporting only user-mode code, not drivers, and on kernel-mode components needing to be compiled as Arm64. ↩ ↩2
-
Microsoft Learn, Troubleshooting x86 desktop apps. On every kernel-mode driver, UMDF driver, and printer driver needing to match the OS’s architecture, and on driver-dependent features remaining unusable even when the app itself runs under emulation. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Troubleshooting x86 desktop apps. On apps that load their own DLL into a Windows process (shell extensions, IMEs, assistive technologies) needing to be recompiled to match the system’s architecture (Arm64), and on x86 apps that disallow dynamic code generation being unable to run under emulation. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Arm64EC - Build and port apps for native performance on Arm. On the interop table showing that x64/Arm64EC processes can load x64 and Arm64EC binaries while Arm64 processes can only load Arm64 binaries, Arm64EC following x64’s software conventions so it can coexist with x64 code in the same process, most of the OS code loaded into an x64 app’s process already being Arm64EC, and how to check a binary’s type with link /dump /headers. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Microsoft Learn, Arm64X PE files. On Arm64X letting Arm64 and Arm64EC code coexist in a single PE and be loaded into either an x64 or an Arm64 process, and on 64-bit COM servers/plugins/injected DLLs called from apps of both architectures being cited as situations that require Arm64X. ↩ ↩2 ↩3
-
Microsoft Learn, .NET RID Catalog. On win-arm64 being defined as a Windows RID, and on RIDs being used to route platform-specific assets in NuGet packages. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Windows on Arm. On running under an Arm64 .NET SDK executing as Arm64 by default, .NET 8 and later supporting native Arm64 execution, and existing x64 .NET apps running under the OS’s x64 emulation. ↩ ↩2 ↩3
-
Microsoft Learn, Quickstart: Create a Windows on Arm virtual machine in the Azure portal. On being able to filter for an Arm64 image in the Azure portal and create a Windows 11 Arm64 VM (a recommended size such as D2ps_v5, based on Ampere Altra). ↩ ↩2
-
Microsoft Learn, Windows 11 Arm ISO files overview. On the Windows 11 Arm64 ISO being distributed, on being able to create a VM on Hyper-V on an Arm machine or on an Apple Silicon Mac, and on Hyper-V on x64 hardware not supporting an Arm64 VM. ↩ ↩2
-
Microsoft Learn, Develop AI applications for Copilot+ PCs. On Copilot+ PCs being a new category of Windows 11 hardware equipped with an NPU capable of over 40 trillion operations per second (40+ TOPS). ↩
-
Microsoft Learn, Windows on Arm. On Windows 10 supporting x86 and Windows 11 adding unmodified x64 execution, most Copilot+ PCs adopting the Snapdragon X series, and the existence of the compatibility-status site (Works on Windows on Arm) and the App Assure Arm Advisory Service. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, How emulation works on Arm - Detecting emulation. On an app under emulation seeing information about the emulated virtual processor, GetNativeSystemInfo also returning the emulated value for compatibility, and on using IsWow64Process2 or GetMachineTypeAttributes to detect an Arm64 host. ↩
-
Microsoft Learn, Adjust emulation settings on Arm. On being able to change Prism’s emulation settings (default/safe/strict/very strict presets and individual settings) from an exe’s Compatibility properties tab. ↩
-
Microsoft Learn, Arm-based Surface devices FAQ. On Arm device limitations (drivers need to be designed for Arm, peripherals depend on Arm64 drivers, games requiring OpenGL beyond 3.3 or unsupported anti-cheat, customization-style apps like IMEs, and per-product confirmation for antivirus software), and on compatibility support via App Assure, including for LOB apps. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Process Interoperability. On a 64-bit process being unable to load a 32-bit DLL (and vice versa), and on the standard pattern of using an out-of-process COM server and RPC to communicate across an architecture boundary. ↩ ↩2
-
Microsoft Learn, Install .NET on Windows. On Windows 11/10 Arm64 being supported by .NET 8/9/10, on an Arm machine installing the Arm64 build of .NET to C:\Program Files\dotnet\ and the x64 SDK to C:\Program Files\dotnet\x64\, and on possibly needing to adjust PATH or DOTNET_ROOT. ↩ ↩2
-
Microsoft Learn, What’s new in .NET Framework. On .NET Framework 4.8.1 adding native Arm64 support, with a performance advantage over x64 code running under emulation on Arm64. ↩
-
Microsoft Learn, Develop Apps for Windows IoT Enterprise. On .NET Framework 4.8.1’s native Arm64 support being for Windows 11, and on the 4.8.1 runtime not supporting native Arm64 apps on Windows 10 devices. ↩
-
Microsoft Learn, RuntimeInformation.OSArchitecture under emulation. On OSArchitecture starting to return Arm64, from .NET 7 on, even for an emulated process on Windows Arm64 (it previously returned X64), and on ProcessArchitecture being the right choice for the process’s own architecture. ↩
-
Microsoft Learn, RuntimeInformation.ProcessArchitecture Property / RuntimeInformation.OSArchitecture Property. On the APIs for retrieving the running process’s architecture and the OS’s actual underlying architecture. ↩
-
Microsoft Learn, BadImageFormatException Class. On BadImageFormatException occurring when an app’s component targets a different platform (loading an assembly of a mismatched architecture). ↩
-
Microsoft Learn, Add Arm support to your Windows app. On the typical obstacles to an Arm64 build (unsupported dependent libraries, architecture-specific code, kernel drivers) and how to address them, on rebuilding with Arm64EC while leaving x64 dependencies in place, on how to obtain Arm hardware or a VM for testing, and on combining cross-compiled builds with testing in an Arm environment. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Visual Studio on Arm-powered devices. On Arm64-native Visual Studio supporting .NET/C++ development, and on the MSVC toolset available on an Arm64 host being able to target Arm64, x64, and x86. ↩
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Safely Calling Win32 APIs from C# — A Practical P/Invoke Guide (DllImport / LibraryImport / CsWin32)
A practical rundown of what to watch for when calling Win32 APIs and native DLLs from C# via P/Invoke. Covers the differences between Dll...
When Your In-House Windows App Gets Flagged as a Virus — Handling Microsoft Defender False Positives and Living With the Performance Impact
We lay out the proper way to respond when Microsoft Defender flags your in-house Windows app as malware: how modern antivirus detection a...
Sleep, Hibernation, Modern Standby, and Long-Running Apps — Designing Around 'It Stopped Overnight'
Why a long-running Windows app can end up 'stopped by the time you check it in the morning,' worked through from the differences between ...
MAX_PATH and Windows Path/Filename Pitfalls — the 260-Character Limit, Reserved Names, Trailing Dots, and Case Sensitivity
A rundown of the path and filename limits behind the classic 'file not found' bug. Covers the breakdown of MAX_PATH=260, enabling long pa...
Pitfalls of Network Drives and UNC Paths — Working With File Servers (Shared Folders) From a Business Application
This article organizes the classic problems that show up when a business application writes to or watches a shared folder: why a drive le...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
ActiveX Migration
Topic page for staged decisions around keeping, wrapping, or replacing COM / ActiveX / OCX assets.
32-bit / 64-bit Interoperability
Topic page for 32-bit / 64-bit interoperability, native boundaries, and related Windows design decisions.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Legacy Asset Reuse & Migration Support
We help plan staged migration while continuing to reuse COM / ActiveX / OCX assets, native code, and 32-bit dependencies.
Frequently Asked Questions
Common questions about the topic of this article.
- Will an ordinary x64 business app run on Windows on Arm?
- In most cases, yes. Windows 11 on Arm has built-in emulation that runs x86/x64 apps unmodified, and starting with Windows 11 24H2, a new emulator called Prism has also improved performance. However, emulation only takes care of user-mode code — kernel-mode drivers, and shell extensions/IMEs and the like that get loaded into other processes such as Explorer, absolutely require Arm64-native builds. Think of it less as a question about the app itself and more as a question about what's hanging off it.
- Can an x64 exe call an Arm64 DLL?
- No. You can't mix x64 and Arm64 binaries inside a single process: an x64 (or Arm64EC) process can only load x64 and Arm64EC binaries, and an Arm64 process can only load Arm64 binaries. The reverse direction — an Arm64 exe calling an x64 DLL — is equally impossible. If you absolutely need a single DLL that supports both, your options are Arm64X, a format that lets Arm64 and Arm64EC code coexist in one file, or splitting into separate processes and communicating via IPC.
- What does it take to make a .NET app Arm64-ready?
- .NET 6 and later officially support Windows Arm64, and you can produce an Arm64-native executable simply by publishing with the RID (runtime identifier) win-arm64. For a purely managed-code app, that's essentially the whole job — but if you're P/Invoking a native DLL, or using a NuGet package that bundles native assets, you need to check whether an Arm64 build exists for each of them. For .NET Framework apps, 4.8.1 supports native Arm64 execution on Windows 11.
- What kind of software doesn't work on Windows on Arm?
- Software that includes kernel-mode drivers tops the list. Drivers aren't emulated, so VPN clients, security products, virtual devices, and USB-dongle license enforcement won't work without an Arm64 driver. Next come things like shell extensions, IMEs, and assistive technologies that load DLLs into OS-side processes, apps that disallow dynamic code generation, and games that depend on older OpenGL or anti-cheat drivers. Whether peripherals work also comes down to whether an Arm64 driver exists for them.
Author Profile
Profile page for the article author.
Go Komura
Representative of KomuraSoft LLC
Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.
Public links