1
2
3
4
5
6
7 """Manages appModules.
8 @var runningTable: a dictionary of the currently running appModules, using their application's main window handle as a key.
9 @type runningTable: dict
10 """
11
12 import itertools
13 import ctypes
14 import os
15 import sys
16 import pkgutil
17 import baseObject
18 import globalVars
19 from logHandler import log
20 import NVDAHelper
21 import ui
22 import winUser
23 import winKernel
24 import config
25 import NVDAObjects
26 import api
27 import appModules
28
29
30 runningTable={}
31
32 NVDAProcessID=None
33 _importers=None
34
35 -class processEntry32W(ctypes.Structure):
36 _fields_ = [
37 ("dwSize",ctypes.wintypes.DWORD),
38 ("cntUsage", ctypes.wintypes.DWORD),
39 ("th32ProcessID", ctypes.wintypes.DWORD),
40 ("th32DefaultHeapID", ctypes.wintypes.DWORD),
41 ("th32ModuleID",ctypes.wintypes.DWORD),
42 ("cntThreads",ctypes.wintypes.DWORD),
43 ("th32ParentProcessID",ctypes.wintypes.DWORD),
44 ("pcPriClassBase",ctypes.c_long),
45 ("dwFlags",ctypes.wintypes.DWORD),
46 ("szExeFile", ctypes.c_wchar * 260)
47 ]
48
50 """Finds out the application name of the given process.
51 @param processID: the ID of the process handle of the application you wish to get the name of.
52 @type processID: int
53 @param includeExt: C{True} to include the extension of the application's executable filename, C{False} to exclude it.
54 @type window: bool
55 @returns: application name
56 @rtype: unicode or str
57 """
58 if processID==NVDAProcessID:
59 return "nvda.exe" if includeExt else "nvda"
60 FSnapshotHandle = winKernel.kernel32.CreateToolhelp32Snapshot (2,0)
61 FProcessEntry32 = processEntry32W()
62 FProcessEntry32.dwSize = ctypes.sizeof(processEntry32W)
63 ContinueLoop = winKernel.kernel32.Process32FirstW(FSnapshotHandle, ctypes.byref(FProcessEntry32))
64 appName = unicode()
65 while ContinueLoop:
66 if FProcessEntry32.th32ProcessID == processID:
67 appName = FProcessEntry32.szExeFile
68 break
69 ContinueLoop = winKernel.kernel32.Process32NextW(FSnapshotHandle, ctypes.byref(FProcessEntry32))
70 winKernel.kernel32.CloseHandle(FSnapshotHandle)
71 if not includeExt:
72 appName=os.path.splitext(appName)[0].lower()
73 return appName
74
79
81 """Finds the appModule that is for the given process ID. The module is also cached for later retreavals.
82 @param processID: The ID of the process for which you wish to find the appModule.
83 @type processID: int
84 @returns: the appModule, or None if there isn't one
85 @rtype: appModule
86 """
87 mod=runningTable.get(processID)
88 if not mod:
89 appName=getAppNameFromProcessID(processID)
90 mod=fetchAppModule(processID,appName)
91 if not mod:
92 raise RuntimeError("error fetching default appModule")
93 runningTable[processID]=mod
94 return mod
95
97 """Removes any appModules from the cache whose process has died, and also tries to load a new appModule for the given process ID if need be.
98 @param processID: the ID of the process.
99 @type processID: int
100 """
101 for deadMod in [mod for mod in runningTable.itervalues() if not mod.isAlive]:
102 log.debug("application %s closed"%deadMod.appName)
103 del runningTable[deadMod.processID]
104 if deadMod in set(o.appModule for o in api.getFocusAncestors()+[api.getFocusObject()] if o and o.appModule):
105 if hasattr(deadMod,'event_appLoseFocus'):
106 deadMod.event_appLoseFocus()
107 try:
108 deadMod.terminate()
109 except:
110 log.exception("Error terminating app module %r" % deadMod)
111
112 getAppModuleFromProcessID(processID)
113
115 return any(importer.find_module("appModules.%s" % name) for importer in _importers)
116
118 """Returns an appModule found in the appModules directory, for the given application name.
119 @param processID: process ID for it to be associated with
120 @type processID: integer
121 @param appName: the application name for which an appModule should be found.
122 @type appName: unicode or str
123 @returns: the appModule, or None if not found
124 @rtype: AppModule
125 """
126
127
128
129 modName = appName.encode("mbcs")
130
131 if doesAppModuleExist(modName):
132 try:
133 return __import__("appModules.%s" % modName, globals(), locals(), ("appModules",)).AppModule(processID, appName)
134 except:
135 log.error("error in appModule %r"%modName, exc_info=True)
136
137 ui.message(_("Error in appModule %s")%appName)
138
139
140 return AppModule(processID, appName)
141
143 """Reloads running appModules.
144 especially, it clears the cache of running appModules and deletes them from sys.modules.
145 Each appModule will be reloaded immediately as a reaction on a first event coming from the process.
146 """
147 global appModules
148 terminate()
149 del appModules
150 mods=[k for k,v in sys.modules.iteritems() if k.startswith("appModules") and v is not None]
151 for mod in mods:
152 del sys.modules[mod]
153 import appModules
154 initialize()
155
163
171
172
173 -class AppModule(baseObject.ScriptableObject):
174 """Base app module.
175 App modules provide specific support for a single application.
176 Each app module should be a Python module in the appModules package named according to the executable it supports;
177 e.g. explorer.py for the explorer.exe application.
178 It should containa C{AppModule} class which inherits from this base class.
179 App modules can implement and bind gestures to scripts.
180 These bindings will only take effect while an object in the associated application has focus.
181 See L{ScriptableObject} for details.
182 App modules can also receive NVDAObject events for objects within the associated application.
183 This is done by implementing methods called C{event_eventName},
184 where C{eventName} is the name of the event; e.g. C{event_gainFocus}.
185 These event methods take two arguments: the NVDAObject on which the event was fired
186 and a callable taking no arguments which calls the next event handler.
187 """
188
189
190
191
192 sleepMode=False
193
194 - def __init__(self,processID,appName=None):
206
208 return "<%r (appName %r, process ID %s) at address %x>"%(self.appModuleName,self.appName,self.processID,id(self))
209
211 return self.__class__.__module__.split('.')[-1]
212
215
217 """Terminate this app module.
218 This is called to perform any clean up when this app module is being destroyed.
219 Subclasses should call the superclass method first.
220 """
221 winKernel.closeHandle(self.processHandle)
222 NVDAHelper.localLib.destroyConnection(self.helperLocalBindingHandle)
223
225 """Choose NVDAObject overlay classes for a given NVDAObject.
226 This is called when an NVDAObject is being instantiated after L{NVDAObjects.NVDAObject.findOverlayClasses} has been called on the API-level class.
227 This allows an AppModule to add or remove overlay classes.
228 See L{NVDAObjects.NVDAObject.findOverlayClasses} for details about overlay classes.
229 @param obj: The object being created.
230 @type obj: L{NVDAObjects.NVDAObject}
231 @param clsList: The list of classes, which will be modified by this method if appropriate.
232 @type clsList: list of L{NVDAObjects.NVDAObject}
233 """
234