OSDN Git Service

Initial attempt to allow COM GetActiveObject to be used for COM objects running in...
authorJames Teh <jamie@jantrid.net>
Wed, 9 Jan 2013 02:53:31 +0000 (12:53 +1000)
committerJames Teh <jamie@jantrid.net>
Wed, 9 Jan 2013 02:53:31 +0000 (12:53 +1000)
To do this, another process is created without uiAccess and the object is fetched there. We then use LresultFromObject to get it back to NVDA.
The public function is comHelper.getActiveObject.

source/comHelper.py [new file with mode: 0644]
source/nvda_slave.pyw

diff --git a/source/comHelper.py b/source/comHelper.py
new file mode 100644 (file)
index 0000000..4be1d75
--- /dev/null
@@ -0,0 +1,43 @@
+#comHelper.py\r
+#A part of NonVisual Desktop Access (NVDA)\r
+#Copyright (C) 2013 NV Access Limited\r
+#This file is covered by the GNU General Public License.\r
+#See the file COPYING for more details.\r
+\r
+"""Utilities to help with issues related to COM.\r
+"""\r
+\r
+import subprocess\r
+import comtypes.client.dynamic\r
+from comtypes import IUnknown\r
+from comtypes.automation import IDispatch\r
+import oleacc\r
+import config\r
+\r
+def _lresultFromGetActiveObject(progid, dynamic):\r
+       o = comtypes.client.GetActiveObject(progid, dynamic=dynamic)\r
+       if not isinstance(o, IUnknown):\r
+               o = o._comobj\r
+       return oleacc.LresultFromObject(0, o)\r
+\r
+def getActiveObject(progid, dynamic=False):\r
+       """Get an active COM object, handling privilege issues.\r
+       This is similar to comtypes.client.GetActiveObject\r
+       except that it can retrieve objects from normal processes when NVDA is running with uiAccess.\r
+       """\r
+       # TODO: Try in our own process first; no point spawning a process when we don't need to.\r
+       p = subprocess.Popen((config.SLAVE_FILENAME, "comGetActiveObject", progid, "%d" % dynamic),\r
+               stdin=subprocess.PIPE, stdout=subprocess.PIPE)\r
+       try:\r
+               # FIXME: Throw better exception for COM error in slave.\r
+               lres = int(p.stdout.readline())\r
+               o = oleacc.ObjectFromLresult(lres, 0,\r
+                       IDispatch if dynamic else IUnknown)\r
+               if dynamic:\r
+                       o = comtypes.client.dynamic.Dispatch(o)\r
+               return o\r
+       finally:\r
+               # This will cause EOF for the waiting process, which will then exit.\r
+               p.stdin.close()\r
+               p.wait()\r
+               p.stdout.close()\r
index 042dc8d..7eb568b 100755 (executable)
@@ -81,6 +81,16 @@ def main():
                                _("Cannot install NVDA add-on from {path}.\n"\r
                                "You must be running NVDA to be able to install add-ons.").format(path=addonPath),\r
                                0, winUser.MB_ICONERROR)\r
+               elif action == "comGetActiveObject":\r
+                       import comHelper\r
+                       # py2exe scraps sys.stdout.\r
+                       sys.__stdout__.write("%s\n" %\r
+                               comHelper._lresultFromGetActiveObject(args[0], bool(int(args[1]))))\r
+                       sys.__stdout__.flush()\r
+                       try:\r
+                               raw_input()\r
+                       except EOFError:\r
+                               pass\r
                else:\r
                        raise ValueError("No such action")\r
 \r