Repository: nvaccess/nvda

Issue:
WinVersion: add machine architecture property
Hi,

Stemming from #14397:

### Background:
Over the years, Windows supported various processor architectures from various vendors, including Intel x86 (32-bit), AMD64, Itanium (now discontinued), and ARM family (32-bit and 64-bit). While the base machine architecture for NVDA is x86, it provides support for x64 (Intel and AMD) and ARM64 through remote helper libraries.

While #14397 highlighted the need to improve support for ARM64 machines, it brought up an unspoken questino: can NVDA effectively detect different machine architectures? Moreover, thinking about this issue led me to believe that it would be helpful to let NVDA report machine architecture as part of Windows version information, similar to what Resource Monitor add-on provides.

### Is your feature request related to a problem? Please describe.
At the moment NVDA does recognize workstation versus server Windows releases, but not machine architecture, which could have helped debug #14397 and similar issues.

### Describe the solution you'd like
Add machine architecture (WinVersion.architecture) property to WinVersion class and report it at startup. This allows developers to figure out if the issue is specific to an architecture such as AMD64 or AM64, as well as detect test machines easily once ARM machines are used more on the cloud (currently virtual machines on the cloud are powered by x64 processors).

In addition, the following changes can be made:

1. App modules: 64-bit process dtection becoes easier thanks to checking for Windows machine architecture check.
2. Update check: made simpler by fetching WinVersion property.

### Describe alternatives you've considered
Leave code as is and rely on environment variables to detect machine architecture.

### Additional context
For an example, see josephsl/resourcemonitor, specifically Windows version script (NVDA+Shift+number row 6).

### Proposed solution:
Bring machine architecture detection code from Resource Monitor add-on to NVDA Core, likely to target 2023.1 or 2023.2. I'd be happy to mentor someone to bring this feature request to life.

Thanks.


Discussion:
Hi,

An enhanced solution in four lines:

import platform

Then define architecture attribute (constructor parameter and the constructor body itself, two lines), then in getWinVer function:

architecture = platform.machine()

The platform module became part of NVDA in 2019.3 with migration to Python 3, likely coming in as part of updated Py2exe dependency or via another one.

Thanks.

Resolving patch:
diff --git a/source/winVersion.py b/source/winVersion.py
--- a/source/winVersion.py
+++ b/source/winVersion.py
@@ -15,6 +15,7 @@
 import os
 import functools
 import winreg
+import platform
 
 
 # Records a mapping between Windows builds and release names.
@@ -68,7 +69,7 @@ def _getRunningVersionNameFromWinReg() -> str:
 class WinVersion(object):
 	"""
 	Represents a Windows release.
-	Includes version major, minor, build, service pack information,
+	Includes version major, minor, build, service pack information, machine architecture,
 	as well as tools such as checking for specific Windows 10 releases.
 	"""
 
@@ -79,7 +80,8 @@ def __init__(
 			build: int = 0,
 			releaseName: Optional[str] = None,
 			servicePack: str = "",
-			productType: str = ""
+			productType: str = "",
+			processorArchitecture: str = ""
 	):
 		self.major = major
 		self.minor = minor
@@ -90,6 +92,7 @@ def __init__(
 			self.releaseName = self._getWindowsReleaseName()
 		self.servicePack = servicePack
 		self.productType = productType
+		self.processorArchitecture = processorArchitecture
 
 	def _getWindowsReleaseName(self) -> str:
 		"""Returns the public release name for a given Windows release based on major, minor, and build.
@@ -123,6 +126,8 @@ def __repr__(self):
 			winVersionText.append(f"service pack {self.servicePack}")
 		if self.productType != "":
 			winVersionText.append(self.productType)
+		if self.processorArchitecture != "":
+			winVersionText.append(self.processorArchitecture)
 		return " ".join(winVersionText)
 
 	def __eq__(self, other):
@@ -187,7 +192,8 @@ def getWinVer():
 		build=winVer.build,
 		releaseName=releaseName,
 		servicePack=winVer.service_pack,
-		productType=("workstation", "domain controller", "server")[winVer.product_type - 1]
+		productType=("workstation", "domain controller", "server")[winVer.product_type - 1],
+		processorArchitecture=platform.machine()
 	)
 
 


Test patch:
diff --git a/tests/unit/test_winVersion.py b/tests/unit/test_winVersion.py
--- a/tests/unit/test_winVersion.py
+++ b/tests/unit/test_winVersion.py
@@ -1,12 +1,13 @@
 # A part of NonVisual Desktop Access (NVDA)
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
-# Copyright (C) 2021 NV Access Limited, Joseph Lee
+# Copyright (C) 2021-2022 NV Access Limited, Joseph Lee
 
 """Unit tests for the Windows version module."""
 
 import unittest
 import sys
+import os
 import winVersion
 
 
@@ -78,3 +79,9 @@ def test_winVerUnknownBuildToReleaseName(self):
 			major=unknownMajor, minor=unknownMinor, build=unknownBuild
 		)
 		self.assertEqual(badWin81Info.releaseName, "Windows release unknown")
+
+	def test_winVerProcessorArchitecture(self):
+		# See if processor architecture matches what Windows says.
+		# Use os.environ to guard against platform.machine() giving odd results.
+		actualArchitecture = os.environ.get("PROCESSOR_ARCHITEW6432", os.environ["PROCESSOR_ARCHITECTURE"])
+		self.assertEqual(winVersion.getWinVer().processorArchitecture, actualArchitecture)