在 Windows 環境下使用 JNA (Java Native Access) 調用本地 DLL 時,最常見的啟動錯誤是:
java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 應用程序
at com.sun.jna.Native.open(Native Method)
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:...)
...
核心結論:JVM 位數 (32/64-bit) 與目標 DLL 位數不匹配。64 位 JVM 只能加載 64 位 DLL,32 位 JVM 只能加載 32 位 DLL。兩者位數必須嚴格一致。
| 檢查項 | 命令/方法 | 預期結果 |
|---|---|---|
| JVM 位數 | java -version 輸出包含 "64-Bit Server VM" → 64 位;無 "64-Bit" → 32 位 | 與 DLL 位數一致 |
| DLL 位數 | VS Developer Command Prompt: dumpbin /headers xxx.dll | find "machine"x64 → 8664 (AMD64) x86 → 14C (I386) | 與 JVM 位數一致 |
| 依賴 DLL 完整性 | dumpbin /dependents xxx.dll 檢查所有依賴項是否存在於 PATH | 無缺失依賴 |
| 系統 PATH | DLL 所在目錄是否在 PATH 環境變量中,或用 System.load("abs/path/xxx.dll") 絕對路徑加載 | 可被系統加載器找到 |
java.exe。public interface MyDLL extends Library {
// 1. 使用 JNA Platform 類型映射,避免手寫結構體對齊錯誤
// 2. 顯式指定調用約定:StdCallLibrary (Windows API 默認) 或 Library (C 默認 cdecl)
MyDLL INSTANCE = Native.load("MyDLL", MyDLL.class,
Map.of("calling-convention", StdCallLibrary.class)); // 或直接繼承 StdCallLibrary
// 3. 複雜結構體繼承 Structure,使用 @FieldOrder 保證內存佈局
int initDevice(int port);
int readData(Pointer buffer, int maxLen);
void closeDevice();
}
// 啟動時檢查位數匹配,早失敗快診斷
static {
String arch = System.getProperty("sun.arch.data.model"); // "32" or "64"
String dllPath = "libs/" + (arch.equals("64") ? "x64" : "x86") + "/MyDLL.dll";
File f = new File(dllPath);
if (!f.exists()) throw new UnsatisfiedLinkError("Missing " + arch + "-bit DLL: " + dllPath);
System.load(f.getAbsolutePath()); // 顯式絕對路徑加載,避免 PATH 污染
}
Error 126: The specified module could not be found (實際是依賴 DLL 缺失)。stdcall (JNA 用 StdCallLibrary),C 庫多為 cdecl (用 Library)。混用會導致棧平衡錯誤、參數亂碼、崩潰。A 後綴 (ANSI/GBK),W 後綴 (UTF-16)。JNA 默認 W 版本,傳 String 自動轉 UTF-16;若需 ANSI,用 Native.toByteArray(str, "GBK") 手動轉 byte[] 或 Pointer。ThreadLocal 獨享實例。UnsatisfiedLinkError: %1 不是有效的 Win32 應用程序 99% 是 JVM/DLL 位數不匹配。現代項目強烈建議全鏈路 64 位化:64 位 JDK + 64 位 DLL + 64 位依賴。若受限於廠商只提供 32 位 DLL,採用進程隔離代理模式隔離風險,避免主應用被迫降級為 32 位 JVM。