Skip to content

App modules: add additional app properties such as app path, immersive process, and app architecture#8644

Merged
michaelDCurran merged 14 commits into
nvaccess:masterfrom
josephsl:i7894appModProperties
Jul 6, 2020
Merged

App modules: add additional app properties such as app path, immersive process, and app architecture#8644
michaelDCurran merged 14 commits into
nvaccess:masterfrom
josephsl:i7894appModProperties

Conversation

@josephsl

@josephsl josephsl commented Aug 18, 2018

Copy link
Copy Markdown
Contributor

Link to issue number:

Fixes #7894

Summary of the issue:

Adds additional app properties such as path, immersive process, and architecture (WoW64).

Description of how this pull request fixes the issue:

Adds the following properties:

  • appPath: returns full executable path for the current application.
  • isWindowsStoreApp: looks for a package info structure to determine if an app is a Store application (see a later comment as to why this route is used).
  • appArchitecture: uses kernel32.dll's IsWoW64Process2 (Windows 10 Version 1511 and later) to return a string denoting which machien the app was written for, suitable for working with x86/x64 processes on ARM64.

Testing performed:

Tested with various apps, both Win32 desktop apps and universal apps.

Known issues with pull request:

None

Change log entry:

Changes for developers:
Additional properties were added to app modules, including path for the executable (appPath), is a Windows Store app (isWindowsStoreApp), and machine architecture for the app (appArchitecture). (#7894)

@josephsl

Copy link
Copy Markdown
Contributor Author

Hi,

I'll ask for a review once appArchitecture property is implemented and tested.

Thanks.

@josephsl josephsl changed the title App modules: add additional app properties such ah path, immersive process, and app architecture App modules: add additional app properties such as app path, immersive process, and app architecture Aug 18, 2018
Comment thread source/appModuleHandler.py Outdated
These include Windows store apps on Windows 8 and 8.1, and Universal Windows Platform (UWP) apps on Windows 10.
@rtype: bool
"""
if winVersion.winVersion.major and winVersion.winVersion.minor == (6, 1):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is wrong. It should be:

if (winVersion.winVersion.major, winVersion.winVersion.minor) == (6, 1):

I prefer

if (winVersion.winVersion.major, winVersion.winVersion.minor) < (6, 2):

@josephsl

josephsl commented Aug 20, 2018 via email

Copy link
Copy Markdown
Contributor Author

@francipvb

Copy link
Copy Markdown
Contributor

What about Version fields such major, minor and revision?

@josephsl

josephsl commented Jun 14, 2019 via email

Copy link
Copy Markdown
Contributor Author

@francipvb

Copy link
Copy Markdown
Contributor

Hello @josephsl,

Hi, not quite possible due to so many versioning schemes in use (for example, major.minor, year.major, major.minor.build, major.minor.revision, etc). Thanks.

Anyway, it can be nice to have such features, regardless the version scheme used by the application. Repeating code to parse the actual version of the running application for every app module that requires it is not a good way to do.

Another thing to consider is that the scheme major.minor is a standard under windows and it is relatively safe to add major and minor.

Cheers,

@josephsl

josephsl commented Jun 14, 2019 via email

Copy link
Copy Markdown
Contributor Author

@francipvb

francipvb commented Jun 14, 2019 via email

Copy link
Copy Markdown
Contributor

chooseNVDAObjectOverlayClasses._isBase = True

def _get_appPath(self):
"""Returns the full path for the executable e.g. 'C:\\Windows\\explorer.exe' for Explorer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry but I don't see the utility of this under an appModule.

@josephsl

Copy link
Copy Markdown
Contributor Author

Hi,

Version class: this can be fetched easily for immersive apps as all that's required will be parsing the user mode app model structure.

Regarding first, mid, last: there are three issues with this:

  1. Not exactly user friendly: although great for developers who knows what they stand for, for users, they may wish to write it as appModule.version_major instead of appModule.version_first as major/minor/build/revision terms are more prominent.
  2. Does not describe schemes fully: what if the only version info expressions are first, first.last, first.mid, mid.last, etc.? At least version_first is guaranteed, but even then, there are system components that won't return a meaningful version info at all (see below).
  3. No version info for processes with NULL handle: in order to fetch product info (or for that matter, anything with processes), a process handle (hProcess) must be obtained. There are situations where this fails, the most prominent example being desktop window object held by CSRSS (Client/Server Runtime Subsystem/Windows subsystem process). At least the PID can be obtained, but when trying to obtain version info, NVDA (or rather, Python) records a traceback, saying that process handle is 0 (note that process handles are relative to the calling application, not system-wide), meaning any proposal regarding parsing version info will fail for CSRSS. There are other system components that won't even show up via Windows API (although they are running), nor if they do show up somehow, hProcess will still be NULL (system process (part of ntoskrnl.exe, PID 0) will refuse to yield version info (for these, you must use sys.getwindowsversion and build versioning info). Note that we cannot catalog all sorts of system processes where hProcess will be NULL - things are changing fast.

Thanks.

@josephsl

Copy link
Copy Markdown
Contributor Author

Hi,

Actually, yes there is a utility for appPath: virtual machine hosts, executable path for immersive apps, and eventually, for running unit tests.

Thanks.

@josephsl josephsl force-pushed the i7894appModProperties branch from a7e0c01 to 90e5d60 Compare June 21, 2019 05:11
@josephsl josephsl force-pushed the i7894appModProperties branch from 029715c to aef37aa Compare July 12, 2019 15:31
@josephsl josephsl force-pushed the i7894appModProperties branch 2 times, most recently from 8547b4a to 6ea4767 Compare August 2, 2019 19:54
@josephsl

Copy link
Copy Markdown
Contributor Author

Hi,

There is a related issue that was discovered while working on Windows 10 Calculator app module: no product info for certain universal apps, and I'm testing a potential solution. Because that issue is different from this PR, an issue/PR pair will be created that will reference this pull request.

Thanks.

@josephsl

Copy link
Copy Markdown
Contributor Author

Hi,

Update on Windows Store app property: originally it asked user32::IsImmersiveProcess and answered "yes" or "no" depending on return value (1 or 0, respectively). However, this method isn't complete because:

  1. What Windows reports as immersive app is actually not the case for File Explorer and other apps. In case of File Explorer, this is because it is a .Net (managed) application.
  2. What Windows reports as a native (non-immersive) app turns out to be a Store app, the most notable being Office 365 package obtained from Microsoft Store.

A more accurate way is probing for app package info structure that ships with a Store package. Based on an app model XML, this structure records the following information:

  • Package name (publisher.name)
  • Product version (a four-part string separated by a dot).
  • Architecture: the intended architecture for this app (which can be "neutral" (can run anywhere) or a processor architecture).
  • Package language: the language the package is designed for (for many apps, it is either not defined (an empty string) or "neutral").
  • App ID: a unique app model identifier for this package.

This structure is returned by kernel32::GetPackageFullName function as a string representation (see #10108 for more details). Every Store package (native or managed, including Store version of NVDA) will return this structure despite immersive process function returning values that do not fully reflect what the underlying package is. There might be a use case for IsImmersiveProcess - perhaps looking to see if we're dealing with a managed application.

Note that the above remark is irrelevant on Windows 7 as it does not come with package info functions nor immersive process checker routine.

Thanks.

@josephsl josephsl force-pushed the i7894appModProperties branch from 6ea4767 to 9a5b082 Compare September 18, 2019 18:42
@feerrenrut feerrenrut added audience/nvda-dev PR or issue is relevant to NVDA / Add-on developers enhancement Addon/API Changes to NVDA's API for addons to support addon development. labels Apr 8, 2020
@josephsl

Copy link
Copy Markdown
Contributor Author

Hi,

Suspended until further notice in light of #11006.

Thanks.

@Adriani90

Copy link
Copy Markdown
Collaborator

@josephsl I understand #11006 addresses new pull requests, not already existing pull requests. If we don't continue work on existing pull requests, then we run into the same issue later on.
I suggest if possible, continue work on existing pull requests, so that the backlog can be reviewed and finalized as soon as possible.

@josephsl

josephsl commented Apr 14, 2020 via email

Copy link
Copy Markdown
Contributor Author

josephsl added 12 commits April 14, 2020 14:18
…re also supported. Re nvaccess#7894.

Add appModuleHandler.AppModule.appPath property used to obtain the full path for the executable (e.g. C:\Windows\explorer.exe).
Also, in app module docstring, clarify that app module packages (appmodname/__init__.py) are also supported.
AppModule.isWindowsStoreApp will call user32.dll::IsImmersiveProcess to determine if the app is hosted inside a Windows RT container. This is useful for dealing with universla apps on Windows 10.
appModule.appArchitecture will return the architecture for which the app is written. It can be x86 (32-bit app on 32-bit Windows), AMD64 (x64 app), or ARM64 (64-bit ARM app). This is accomplished by use of kernel32.dll's IsWow64Process2 (available on Windows 10 build 10586 and later).
appModule.isWindowsStoreApp: check if it is below Windows 8, also fixed tuple syntax.
appModule.appArchitecture: variable renames to make it clear.
…. re nvaccess#7894.

Thanks to work on ARM64 detection in appModule.is64BitProcess: use kernel32::isWow64Process2 directly and obtain either AMD64 or ARM64, falling back to AMD64 if that Windows API function isn't present (the function is present in Windows 10 Version 1511 (build 10586) and later).
…on of 32-bit ARM apps. Re nvaccess#7894.

Windows 10 Version 1903 includes foundatoins to support 32-bit ARM apps. Because this means two 32-bit architectures must be handled, rewrite app architecture method to:
1. Record architecture to arch names inside a map.
2. Call kernel32::IsWow64Process2 first and obtain arch name fromthe arch values map.
3. If IsWow64process2 fails for some reason (Windows 7 through 10 Version 1507), return appropriate architecture name based on 64-bit process status.
Fixes include inline comments and spaces around dictionary operator.
… info for Microsoft Store apps. Re nvaccess#7894.

User32.dll::IsImmersiveProcess won't quite cut it for Store apps:
* File Explorer is seen as an immersive app but it is not really a Store application.
* Converted desktop apps are seen as not immersive but they are Store apps.
The more accurate way to determine this information is looking for app package info, which can be done by calling kernel32.dll::GetPackageFullName. This returns a string representation of app name, version, architecture, language, and app ID (the first two are used in nvaccess#4259). Every Store app comes with app model XML file that provides data for this structure (Store version of NVDA is no exception). Thus use this method, which is now part of a private function in the base app module so not only product name and version setter can use it, but also Store app property can call this method.
…fo function. Re nvaccess#7894.

Use the dedicated package info function for obtaining product name and version:
* If the package info is a string, info will be parsed.
* If it is None, executable file info will be fetched.
…nderlying process is a Windows Store app. Re nvaccess#7894.

User32.dll::IsImmersiveProcess won't work all the way, but package info fetching will (on Windows 8 and later). Therefore use the package info method to determine if a given process is a Windows Store app.
@josephsl josephsl force-pushed the i7894appModProperties branch from 386e220 to e827cfc Compare April 14, 2020 21:34
@josephsl

Copy link
Copy Markdown
Contributor Author

Hi,

The PR is trivial enough for a fast forward review, but I imagine there might be scenarios where testing might be required. Even then, I think there are PR's that are more urgent than this one (depends on PR tags).

Thanks.

@feerrenrut

Copy link
Copy Markdown
Contributor

Suspended until further notice in light of #11006.

Please continue to work on this PR. #11006 requests no new PR's. This PR already exists and is thus in the backlog of PR's that we want to address before accepting new ones. We are trying to stop PR's from going stale, and then becoming hard to merge.

Forgive me for replying to you multiple times, I want to avoid the community being mislead.

@josephsl

josephsl commented Apr 15, 2020 via email

Copy link
Copy Markdown
Contributor Author

Comment thread source/appModuleHandler.py Outdated
# Others such as Store version of Office are not truly hosted apps but are distributed via Store.
length = ctypes.c_uint()
buf = ctypes.windll.kernel32.GetPackageFullName(self.processHandle, ctypes.byref(length), None)
packageFullName = ctypes.create_unicode_buffer(buf)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The argument to create_unicode_buffer should be length, not buf I believe?
According to https://docs.microsoft.com/en-us/windows/win32/api/appmodel/nf-appmodel-getpackagefullname
GetPackageFullname returns ERROR_SUCCESS or an error code. The needed length is written to the length parameter.

@josephsl

josephsl commented Jul 6, 2020 via email

Copy link
Copy Markdown
Contributor Author

…er to obtain actual package info length (addressing review action). Re nvaccess#7894.
@michaelDCurran michaelDCurran merged commit 4799068 into nvaccess:master Jul 6, 2020
@nvaccessAuto nvaccessAuto added this to the 2020.3 milestone Jul 6, 2020
michaelDCurran added a commit that referenced this pull request Jul 6, 2020
@josephsl josephsl deleted the i7894appModProperties branch July 19, 2020 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Addon/API Changes to NVDA's API for addons to support addon development. audience/nvda-dev PR or issue is relevant to NVDA / Add-on developers enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App modules: add additional properties for benefit of testing, add-ons and alike

7 participants