Skip to content

Commit 52b9b07

Browse files
cdervclaude
andcommitted
fix(R): detect Windows ARM using IsWow64Process2 API
Deno.build.arch reports x86_64 even when x64 Deno runs on ARM64 hardware under emulation. Use Windows IsWow64Process2 API via FFI to detect the actual native hardware architecture. This fixes the x64-on-ARM detection so the custom error message displays instead of the generic "Please check your installation of R" message. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 1ddf39a commit 52b9b07

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

src/core/knitr.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { readYamlFromString } from "./yaml.ts";
1212
import { coerce, satisfies } from "semver/mod.ts";
1313
import { debug } from "../deno_ral/log.ts";
1414
import { isWindows } from "../deno_ral/platform.ts";
15+
import { isWindowsArm } from "./windows.ts";
1516

1617
export interface KnitrCapabilities {
1718
versionMajor: number;
@@ -79,10 +80,9 @@ export class WindowsArmX64RError extends Error {
7980
function checkWindowsArmR(platform: string | undefined): void {
8081
if (!platform) return;
8182

82-
const isWindowsArm = isWindows && Deno.build.arch === "aarch64";
8383
const isX64R = platform.includes("x86_64") || platform.includes("i386");
8484

85-
if (isWindowsArm && isX64R) {
85+
if (isWindowsArm() && isX64R) {
8686
throw new WindowsArmX64RError(
8787
"x64 R detected on Windows ARM.\n\n" +
8888
"x64 R runs under emulation and is not reliable for Quarto.\n" +

src/core/windows.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,53 @@ export async function safeWindowsExec(
163163
removeIfExists(tempFile);
164164
}
165165
}
166+
167+
// Detect Windows ARM hardware using IsWow64Process2 API
168+
// Returns true if running on ARM64 hardware (even from x64 Deno under emulation)
169+
export function isWindowsArm(): boolean {
170+
if (!isWindows) {
171+
return false;
172+
}
173+
174+
try {
175+
// Load kernel32.dll
176+
const kernel32 = Deno.dlopen("kernel32.dll", {
177+
IsWow64Process2: {
178+
parameters: ["pointer", "pointer", "pointer"],
179+
result: "i32",
180+
},
181+
GetCurrentProcess: {
182+
parameters: [],
183+
result: "pointer",
184+
},
185+
});
186+
187+
// Get current process handle
188+
const hProcess = kernel32.symbols.GetCurrentProcess();
189+
190+
// Prepare output parameters - allocate buffer for USHORT (2 bytes each)
191+
const processMachineBuffer = new Uint16Array(1);
192+
const nativeMachineBuffer = new Uint16Array(1);
193+
194+
// Call IsWow64Process2 with pointers to buffers
195+
const result = kernel32.symbols.IsWow64Process2(
196+
hProcess,
197+
Deno.UnsafePointer.of(processMachineBuffer),
198+
Deno.UnsafePointer.of(nativeMachineBuffer),
199+
);
200+
201+
kernel32.close();
202+
203+
if (result === 0) {
204+
// Function failed
205+
return false;
206+
}
207+
208+
// IMAGE_FILE_MACHINE_ARM64 = 0xAA64 = 43620
209+
const IMAGE_FILE_MACHINE_ARM64 = 0xAA64;
210+
return nativeMachineBuffer[0] === IMAGE_FILE_MACHINE_ARM64;
211+
} catch {
212+
// IsWow64Process2 not available (Windows < 10) or other error
213+
return false;
214+
}
215+
}

0 commit comments

Comments
 (0)