OSDN Git Service

Provide framework to support loading specific app modules for executables which host...
authorJames Teh <jamie@nvaccess.org>
Thu, 11 Sep 2014 10:23:18 +0000 (20:23 +1000)
committerJames Teh <jamie@nvaccess.org>
Thu, 6 Nov 2014 03:48:35 +0000 (13:48 +1000)
For example, this will allow specific app modules to be loaded for apps hosted by javaw.exe, rather than always loading just the javaw app module.
This is done by implementing the getAppNameFromHost function in the module for the hosting executable (not the AppModule class). See the code documentation for the AppModule class for details.
Note that this commit doesn't include any modules which actually implement this.

source/appModuleHandler.py

index 7879c61..94e907d 100644 (file)
@@ -1,6 +1,7 @@
+# -*- coding: UTF-8 -*-\r
 #appModuleHandler.py\r
 #A part of NonVisual Desktop Access (NVDA)\r
-#Copyright (C) 2006-2007 NVDA Contributors <http://www.nvda-project.org/>\r
+#Copyright (C) 2006-2014 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Patrick Zajda\r
 #This file is covered by the GNU General Public License.\r
 #See the file COPYING for more details.\r
 \r
@@ -18,6 +19,7 @@ import sys
 import pkgutil\r
 import threading\r
 import tempfile\r
+import comtypes.client\r
 import baseObject\r
 import globalVars\r
 from logHandler import log\r
@@ -76,6 +78,18 @@ def getAppNameFromProcessID(processID,includeExt=False):
        winKernel.kernel32.CloseHandle(FSnapshotHandle)\r
        if not includeExt:\r
                appName=os.path.splitext(appName)[0].lower()\r
+       if not appName:\r
+               return appName\r
+\r
+       # This might be an executable which hosts multiple apps.\r
+       # Try querying the app module for the name of the app being hosted.\r
+       try:\r
+               # Python 2.x can't properly handle unicode module names, so convert them.\r
+               mod = __import__("appModules.%s" % appName.encode("mbcs"),\r
+                       globals(), locals(), ("appModules",))\r
+               return mod.getAppNameFromHost(processID)\r
+       except (ImportError, AttributeError, LookupError):\r
+               pass\r
        return appName\r
 \r
 def getAppModuleForNVDAObject(obj):\r
@@ -260,6 +274,15 @@ class AppModule(baseObject.ScriptableObject):
        where C{eventName} is the name of the event; e.g. C{event_gainFocus}.\r
        These event methods take two arguments: the NVDAObject on which the event was fired\r
        and a callable taking no arguments which calls the next event handler.\r
+\r
+       Some executables host many different applications; e.g. javaw.exe.\r
+       In this case, it is desirable that a specific app module be loaded for each\r
+       actual application, rather than the one for the hosting executable.\r
+       To support this, the module for the hosting executable\r
+       (not the C{AppModule} class within it) can implement the function\r
+       C{getAppNameFromHost(processId)}, where C{processId} is the id of the host process.\r
+       It should return a unicode string specifying the name that should be used.\r
+       Alternatively, it can raise C{LookupError} if a name couldn't be determined.\r
        """\r
 \r
        #: Whether NVDA should sleep while in this application (e.g. the application is self-voicing).\r
@@ -408,3 +431,22 @@ class AppProfileTrigger(config.ProfileTrigger):
 \r
        def __init__(self, appName):\r
                self.spec = "app:%s" % appName\r
+\r
+def getWmiProcessInfo(processId):\r
+       """Retrieve the WMI Win32_Process class instance for a given process.\r
+       For details about the available properties, see\r
+       http://msdn.microsoft.com/en-us/library/aa394372%28v=vs.85%29.aspx\r
+       @param processId: The id of the process in question.\r
+       @type processId: int\r
+       @return: The WMI Win32_Process class instance.\r
+       @raise LookupError: If there was an error retrieving the instance.\r
+       """\r
+       try:\r
+               wmi = comtypes.client.CoGetObject(r"winmgmts:root\cimv2", dynamic=True)\r
+               results = wmi.ExecQuery("select * from Win32_Process "\r
+                       "where ProcessId = %d" % processId)\r
+               for result in results:\r
+                       return result\r
+       except:\r
+               raise LookupError("Couldn't get process information using WMI")\r
+       raise LookupError("No such process")\r