diff --git a/include/wx/platinfo.h b/include/wx/platinfo.h index 887e15cca1..a256aa08bd 100644 --- a/include/wx/platinfo.h +++ b/include/wx/platinfo.h @@ -296,6 +296,8 @@ public: { return GetEndiannessName(m_endian); } wxString GetCpuArchitectureName() const { return m_cpuArch; } + wxString GetNativeCpuArchitectureName() const + { return m_nativeCpuArch; } wxString GetOperatingSystemDescription() const { return m_osDesc; } wxString GetDesktopEnvironment() const @@ -339,6 +341,8 @@ public: { m_endian = n; } void SetCpuArchitectureName(const wxString& cpuArch) { m_cpuArch = cpuArch; } + void SetNativeCpuArchitectureName(const wxString& cpuArch) + { m_nativeCpuArch = cpuArch; } void SetDesktopEnvironment(const wxString& de) { m_desktopEnv = de; } @@ -427,6 +431,9 @@ protected: // CPU architecture family name, possibly empty if unknown wxString m_cpuArch; + + // native CPU architecture family name, possibly empty if unknown + wxString m_nativeCpuArch; }; // Returns true only for MSW programs running under Wine. diff --git a/include/wx/utils.h b/include/wx/utils.h index 274f2a1aaa..f87b92cf50 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -156,6 +156,9 @@ WXDLLIMPEXP_BASE bool wxIsPlatform64Bit(); // Get machine CPU architecture WXDLLIMPEXP_BASE wxString wxGetCpuArchitectureName(); +// Get native machine CPU architecture +WXDLLIMPEXP_BASE wxString wxGetNativeCpuArchitectureName(); + #ifdef __LINUX__ // Get linux-distro information WXDLLIMPEXP_BASE wxLinuxDistributionInfo wxGetLinuxDistributionInfo(); diff --git a/interface/wx/platinfo.h b/interface/wx/platinfo.h index fac08d23ad..84dce32573 100644 --- a/interface/wx/platinfo.h +++ b/interface/wx/platinfo.h @@ -410,12 +410,21 @@ public: /** Returns the CPU architecture name, if available. - @see wxGetCpuArchitectureName() + @see wxGetCpuArchitectureName(), GetNativeCpuArchitectureName() @since 3.1.5 */ wxString GetCpuArchitectureName() const; + /** + Returns the native CPU architecture name, if available. + + @since 3.1.6 + + @see ::wxGetNativeCpuArchitectureName(), GetCpuArchitectureName() + */ + wxString GetNativeCpuArchitectureName() const; + /** Returns the run-time major version of the OS associated with this wxPlatformInfo instance. diff --git a/interface/wx/utils.h b/interface/wx/utils.h index 2731b414fe..e1fd9c37cf 100644 --- a/interface/wx/utils.h +++ b/interface/wx/utils.h @@ -1099,10 +1099,31 @@ bool wxIsPlatformLittleEndian(); The returned string may be empty if the CPU architecture couldn't be recognized. + @see wxGetNativeCpuArchitectureName() + @since 3.1.5 */ wxString wxGetCpuArchitectureName(); +/** + In some situations the current process and native CPU architecture may be + different. This returns the native CPU architecture regardless of the + current process CPU architecture. + + Common examples for CPU architecture differences are the following: + - Win32 process in x64 Windows (WoW) + - Win32 or x64 process on ARM64 Windows (WoW64) + - x86_64 process on ARM64 macOS (Rosetta 2) + + The returned string may be empty if the CPU architecture couldn't be + recognized. + + @see wxGetCpuArchitectureName() + + @since 3.1.6 +*/ +wxString wxGetNativeCpuArchitectureName(); + /** Returns a structure containing information about the currently running Linux distribution. diff --git a/src/common/platinfo.cpp b/src/common/platinfo.cpp index 38a9355ef2..3776576561 100644 --- a/src/common/platinfo.cpp +++ b/src/common/platinfo.cpp @@ -202,6 +202,7 @@ void wxPlatformInfo::InitForCurrentPlatform() m_endian = wxIsPlatformLittleEndian() ? wxENDIAN_LITTLE : wxENDIAN_BIG; m_bitness = wxIsPlatform64Bit() ? wxBITNESS_64 : wxBITNESS_32; m_cpuArch = wxGetCpuArchitectureName(); + m_nativeCpuArch = wxGetNativeCpuArchitectureName(); #ifdef __LINUX__ m_ldi = wxGetLinuxDistributionInfo(); diff --git a/src/msw/utils.cpp b/src/msw/utils.cpp index 3505230de3..6ca6c9c1fd 100644 --- a/src/msw/utils.cpp +++ b/src/msw/utils.cpp @@ -90,6 +90,14 @@ #define PROCESSOR_ARCHITECTURE_ARM64 12 #endif +#ifndef IMAGE_FILE_MACHINE_ARM64 +#define IMAGE_FILE_MACHINE_ARM64 0xAA64 +#endif + +#ifndef IMAGE_FILE_MACHINE_ARMNT +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 +#endif + #include // For wxKillAllChildren @@ -1312,8 +1320,52 @@ wxWinVersion wxGetWinVersion() return wxWinVersion_Unknown; } +wxString wxGetCpuArchitecureNameFromImageType(USHORT imageType) +{ + switch (imageType) + { + case IMAGE_FILE_MACHINE_I386: + return "x86"; + case IMAGE_FILE_MACHINE_AMD64: + return "x64"; + case IMAGE_FILE_MACHINE_IA64: + return "Itanium"; + case IMAGE_FILE_MACHINE_ARMNT: + return "arm"; + case IMAGE_FILE_MACHINE_ARM64: + return "arm64"; + default: + return wxString(); + } +} + +// Wrap IsWow64Process2 API (Available since Win10 1511) +BOOL wxIsWow64Process2(HANDLE hProcess, USHORT* pProcessMachine, USHORT* pNativeMachine) +{ +#if wxUSE_DYNLIB_CLASS // Win32 + + typedef BOOL(WINAPI *IsWow64Process2_t)(HANDLE, USHORT *, USHORT *); + + wxDynamicLibrary dllKernel32("kernel32.dll"); + IsWow64Process2_t pfnIsWow64Process2 = + (IsWow64Process2_t)dllKernel32.RawGetSymbol("IsWow64Process2"); + + if (pfnIsWow64Process2) + return pfnIsWow64Process2(hProcess, pProcessMachine, pNativeMachine); + else +#endif + return FALSE; +} + wxString wxGetCpuArchitectureName() { + // Try to get the current active CPU architecture via IsWow64Process2() + // first, fallback to GetNativeSystemInfo() otherwise + USHORT machine; + if (wxIsWow64Process2(::GetCurrentProcess(), &machine, NULL) && + machine != IMAGE_FILE_MACHINE_UNKNOWN) + return wxGetCpuArchitecureNameFromImageType(machine); + SYSTEM_INFO si; GetNativeSystemInfo(&si); @@ -1340,6 +1392,18 @@ wxString wxGetCpuArchitectureName() } } +wxString wxGetNativeCpuArchitectureName() +{ + USHORT machine; + USHORT nativeMachine; + if (wxIsWow64Process2(::GetCurrentProcess(), &machine, &nativeMachine)) + return wxGetCpuArchitecureNameFromImageType(nativeMachine); + else + return wxGetCpuArchitectureName(); +} + + + // ---------------------------------------------------------------------------- // sleep functions // ---------------------------------------------------------------------------- diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index 5a865fd8ad..863b08abb4 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -145,6 +145,10 @@ #include // for setpriority() #endif +#if defined(__DARWIN__) + #include +#endif + // ---------------------------------------------------------------------------- // conditional compilation // ---------------------------------------------------------------------------- @@ -1124,6 +1128,19 @@ wxString wxGetCpuArchitectureName() return wxGetCommandOutput(wxT("uname -m")); } +wxString wxGetNativeCpuArchitectureName() +{ +#if defined(__DARWIN__) + // macOS on ARM will report an x86_64 process as translated, assume the native CPU is arm64 + int translated; + size_t translated_size = sizeof(translated); + if (sysctlbyname("sysctl.proc_translated", &translated, &translated_size, NULL, 0) == 0) + return "arm64"; + else +#endif + return wxGetCpuArchitectureName(); +} + #ifdef __LINUX__ static bool