blind_html Re: Fwd: [Nvda-dev] commit r2928 - in trunk: . installer source source/NVDAHelpersource/appModules source/config source/gui user_docs/en

  • From: Paul Tandy <paul96cars@xxxxxxxxx>
  • To: blind_html@xxxxxxxxxxxxx
  • Date: Sun, 17 May 2009 20:12:15 -0800

Hello,

How did you get on that list?
I want to join because I would like to test out nvda.



----- Original Message -----
From: Nimer Jaber <nimerjaber1@xxxxxxxxx
To: blind_html@xxxxxxxxxxxxx
Date sent: Fri, 15 May 2009 07:11:31 -0600
Subject: blind_html Fwd: [Nvda-dev] commit r2928 - in trunk: .
installer source source/NVDAHelpersource/appModules source/config source/gui user_docs/en

This is exciting!!!

-------- Original Message --------
Subject:        [Nvda-dev] commit r2928 - in trunk: .  installer source
source/NVDAHelper source/appModules source/config source/gui
user_docs/en
Date:   Fri, 15 May 2009 07:13:21 +0000
From:   NVDA Subversion <svn@xxxxxxxxxxxxxxxx
Reply-To: News and discussion for NVDA (NonVisual Desktop
Access), a
free and open source screen reader for Microsoft Windows
<nvda-dev@xxxxxxxxxxxxxxxxxx
To:     nvda-dev@xxxxxxxxxxxxxxxxxx



Author: nvda
Date: Fri May 15 07:13:17 2009
New Revision: 2928

Log:
* new: NVDA can be configured to start automatically after
you log on to Windows. The option is in the General Settings dialog.
* new: NVDA can read secure Windows screens such as the
Windows logon, control+alt+delete and UAC screens in Windows XP and above. Reading of the Windows logon screen can be configured from the General Settings dialog. (#97)
* fix: On Windows Vista, the NVDA installer now starts NVDA
with normal user privileges when requested to run NVDA on the finish screen.

New misc-deps package, version 2009-05-15-01. Includes new
NVDAHelper with bug fixes, new nvVBufLib with bug fixes and optimisations, and NSIS components for secure desktop and UAC support.


Added:
   trunk/source/NVDAHelper/IA2Support.cpp
- copied, changed from r2927,
/trunk/source/NVDAHelper/IA2Support.c
   trunk/source/NVDAHelper/hookManager.cpp
- copied, changed from r2927,
/trunk/source/NVDAHelper/hookManager.c
   trunk/source/NVDAHelper/inputLangChange.cpp
- copied, changed from r2927,
/trunk/source/NVDAHelper/inputLangChange.c
   trunk/source/NVDAHelper/typedCharacter.cpp
- copied, changed from r2927,
/trunk/source/NVDAHelper/typedCharacter.c
   trunk/source/appModules/logonui.py
   trunk/source/nvda_service.py
   trunk/source/nvda_slave.pyw
   trunk/source/shellapi.py
Removed:
   trunk/source/NVDAHelper/IA2Support.c
   trunk/source/NVDAHelper/hookManager.c
   trunk/source/NVDAHelper/inputLangChange.c
   trunk/source/NVDAHelper/typedCharacter.c
Modified:
   trunk/dependencies.txt
   trunk/installer/nvda.nsi
   trunk/source/IAccessibleHandler.py
   trunk/source/NVDAHelper/hookManager.h
   trunk/source/config/__init__.py
   trunk/source/gui/settingsDialogs.py
   trunk/source/nvda.pyw
   trunk/source/setup.py
   trunk/source/winKernel.py
   trunk/source/winUser.py
   trunk/user_docs/en/whats new.txt

Modified: trunk/dependencies.txt
=================================================================
=============
--- trunk/dependencies.txt      (original)
+++ trunk/dependencies.txt      Fri May 15 07:13:17 2009
@@ -7,7 +7,7 @@
 http://www.wxpython.org/
 Python Windows Extensions (for Python 2.6), build 212 or later:
 http://www.sourceforge.net/projects/pywin32/
-Several other packages, made available for convenience in the
NVDA miscellaneous dependencies package, version 2009-04-16-01 or later:
+Several other packages, made available for convenience in the
NVDA miscellaneous dependencies package, version 2009-05-15-01 or later:
 http://www.nvda-project.org/wiki/MiscellaneousDependencies

 To build a binary version of NVDA, you will also need:

Modified: trunk/installer/nvda.nsi
=================================================================
=============
--- trunk/installer/nvda.nsi    (original)
+++ trunk/installer/nvda.nsi    Fri May 15 07:13:17 2009
@@ -11,6 +11,7 @@
 !include "Library.nsh"
 !include "FileFunc.nsh"

+
 ;--------
 ;Settings

@@ -36,6 +37,7 @@
 SetDateSave on
 XPStyle on
 InstProgressFlags Smooth
+RequestExecutionLevel user /* RequestExecutionLevel REQUIRED! */
 !define MUI_ABORTWARNING ;Should ask to exit
 !define MUI_UNINSTALLER ;We want an uninstaller to be generated

@@ -54,6 +56,8 @@
 !define MUI_CUSTOMFUNCTION_GUIINIT NVDA_GUIInit
 !define MUI_CUSTOMFUNCTION_ABORT userAbort

+!include "serviceLib.nsh"
+
 ;--------------------------------
 ;Pages

@@ -71,6 +75,9 @@
 ;Directory selection page
 !insertmacro MUI_PAGE_DIRECTORY

+;Components selection page
+!insertmacro MUI_PAGE_COMPONENTS
+
 ;Start menu page
 Var StartMenuFolder
 !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
@@ -153,6 +160,8 @@
 ReserveFile "${NSISDIR}\Plugins\system.dll"
 ReserveFile "${NSISDIR}\Plugins\banner.dll"
 ReserveFile "waves\${SNDLogo}"
+ReserveFile "UAC.dll"
+!addplugindir "."

 ;-----
 ;Include install logger code (depends on some above settings)
@@ -170,8 +179,7 @@
 ;-----
 ;Sections

-;The only installable section
-Section "install"
+Section "-NVDA"
 SetShellVarContext all
 SetOutPath "$INSTDIR"
; open and close uninstallation log after ennumerating all the
files being copied
@@ -214,10 +222,19 @@
WriteRegStr ${INSTDIR_REG_ROOT} "Software\${PRODUCT}" ""
$INSTDIR
  SectionEnd

+section "nvda service (Windows logon / Security dialog support)"
+!insertmacro SERVICE create "nvda"
"path=$INSTDIR\nvda_service.exe;autostart=1;display=NonVisual Desktop Access;description=Runs NVDA at Windows logon and in Windows security dialogs;"
+!insertmacro SERVICE "start" "nvda" ""
+SectionEnd
+
 ;The uninstall section
 Section "Uninstall"
 SetShellVarContext all
-
+;Stop and uninstall the service
+!undef UN
+!define UN "un."
+!insertmacro SERVICE stop "nvda" ""
+!insertmacro SERVICE delete "nvda" ""
 ; Uninstall libraries
!insertmacro UninstallLib DLL NOTSHARED REBOOT_NOTPROTECTED
"$INSTDIR\lib\NVDAHelper.dll"
!insertmacro UninstallLib DLL NOTSHARED REBOOT_NOTPROTECTED
"$INSTDIR\lib\VBufBase.dll"
@@ -246,6 +263,18 @@
 ;Functions

 Function .onInit
+UAC::RunElevated
+;If couldn't change user then fail
+strcmp 0 $0 +1 elevationFail
+;If we are the outer user process, then silently quit
+strcmp 1 $1 +1 +2
+quit
+;If we are now an admin, success
+strcmp 1 $3 elevationSuccess
+elevationFail:
+MessageBox mb_iconstop "Unable to elevate, error $0"
+quit
+elevationSuccess:
 strcpy $runAppOnInstSuccess "0"
; Fix an error from previous installers where the "nvda" file
would be left behind after uninstall
 IfFileExists "$PROGRAMFILES\NVDA" 0
@@ -356,7 +385,7 @@
 !insertmacro UNINSTALL.LOG_UPDATE_INSTALL
 Execwait "$PLUGINSDIR\${NVDATempDir}\${NVDAApp} -q"
 strcmp $runAppOnInstSuccess "1" +1 end
-Exec "$INSTDIR\${NVDAApp}"
+uac::exec "" "$INSTDIR\${NVDAApp}" "" ""
 end:
 FunctionEnd

@@ -367,6 +396,7 @@
 Function .onGUIEnd
 ; Clean up the temporary folder
 rmdir /R /REBOOTOK "$PLUGINSDIR\${NVDATempDir}"
+UAC::Unload ;Must call unload!
 FunctionEnd

 function makeRunAppOnInstSuccess

Modified: trunk/source/IAccessibleHandler.py
=================================================================
=============
--- trunk/source/IAccessibleHandler.py  (original)
+++ trunk/source/IAccessibleHandler.py  Fri May 15 07:13:17 2009
@@ -898,9 +898,6 @@
        def _get_role(self):
                return controlTypes.ROLE_PANE

-       def _get_description(self):
-               return _("Inaccessible to NVDA")
-
 def processDesktopSwitchWinEvent(window,objectID,childID):
        hDesk=ctypes.windll.user32.OpenInputDesktop(0, False, 0)
        #name = ctypes.create_string_buffer(256)

Modified: trunk/source/NVDAHelper/hookManager.h
=================================================================
=============
--- trunk/source/NVDAHelper/hookManager.h       (original)
+++ trunk/source/NVDAHelper/hookManager.h Fri May 15 07:13:17
2009
@@ -7,7 +7,7 @@
 #include<windows.h
 #include<wchar.h

-#define DLLEXPORT __declspec(dllexport)
+#define DLLEXPORT extern "C" __declspec(dllexport)

 //Private variables
 extern HINSTANCE moduleHandle;

Added: trunk/source/appModules/logonui.py
=================================================================
=============
--- (empty file)
+++ trunk/source/appModules/logonui.py  Fri May 15 07:13:17 2009
@@ -0,0 +1,44 @@
+import keyUtils
+from NVDAObjects.IAccessible import IAccessible
+import _default
+
+class PasswordField(IAccessible):
+
+       def bindKeys(self):
+               for key, script in (
+                       ("extendedUp", "changeUser"),
+                       ("extendedDown", "changeUser"),
+               ):
+                       self.bindKey_runtime(key, script)
+
+       def _get_name(self):
+ # Focus automatically jumps to the password field when
a user is selected.  This field has no name.
+ # This means that the new selected user is not
reported.
+ # Therefore, override the name of the password field to
be the selected user name.
+               try:
+ # The accessibility hierarchy is totally screwed
here, so NVDA gets confused.
+                       # Therefore, we'll have to do it the ugly way...
+                       return self.IAccessibleObject.accParent.accName(0)
+               except:
+                       return super(PasswordField, self).name
+
+       def script_changeUser(self, key):
+ # The up and down arrow keys change the selected user,
but there's no reliable NVDA event for detecting this.
+               oldName = self.name
+               keyUtils.sendKey(key)
+               if oldName == self.name:
+                       return
+               self.event_gainFocus()
+
+class AppModule(_default.AppModule):
+
+       def event_NVDAObject_init(self, obj):
+ if obj.windowClassName == "NativeHWNDHost" and
obj.parent and not obj.parent.parent:
+ # Make sure the top level pane is always
presented.
+                       obj.isPresentableFocusAncestor = True
+                       return
+
+ if obj.windowClassName == "Edit" and not obj.name and
not obj.parent:
+ self.overlayCustomNVDAObjectClass(obj,
PasswordField, outerMost=True)
+                       obj.bindKeys()
+                       return

Modified: trunk/source/config/__init__.py
=================================================================
=============
--- trunk/source/config/__init__.py     (original)
+++ trunk/source/config/__init__.py     Fri May 15 07:13:17 2009
@@ -4,6 +4,7 @@
 import globalVars
 import _winreg
 import os
+import sys
 from cStringIO import StringIO
 from configobj import ConfigObj
 from validate import Validator
@@ -205,3 +206,73 @@
if
ctypes.windll.shell32.SHGetSpecialFolderPathW(0,buf,CSI
DL_APPDATA,0):
                        return u'%s\\nvda'%buf.value
        return u'.\\'
+
+RUN_REGKEY = ur"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
+
+def getStartAfterLogon():
+       try:
+ k = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
RUN_REGKEY)
+               val = _winreg.QueryValueEx(k, u"nvda")[0]
+               return os.stat(val) == os.stat(sys.argv[0])
+       except (WindowsError, OSError):
+               return False
+
+def setStartAfterLogon(enable):
+ k = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, RUN_REGKEY,
0, _winreg.KEY_WRITE)
+       if enable:
+ _winreg.SetValueEx(k, u"nvda", None, _winreg.REG_SZ,
sys.argv[0])
+       else:
+               _winreg.DeleteValue(k, u"nvda")
+
+SERVICE_FILENAME = u"nvda_service.exe"
+
+def isServiceInstalled():
+       if not os.path.isfile(SERVICE_FILENAME):
+               return False
+       try:
+ k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
ur"SYSTEM\CurrentControlSet\Services\nvda")
+ val = _winreg.QueryValueEx(k,
u"ImagePath")[0].replace(u'"', u'')
+               return os.stat(val) == os.stat(SERVICE_FILENAME)
+       except (WindowsError, OSError):
+               return False
+
+def execElevated(path, params=None, wait=False):
+       import shellapi
+       import winKernel
+       import winUser
+ sei = shellapi.SHELLEXECUTEINFO(lpVerb=u"runas",
lpFile=os.path.abspath(path), lpParameters=params, nShow=winUser.SW_HIDE)
+       if wait:
+               sei.fMask = shellapi.SEE_MASK_NOCLOSEPROCESS
+       shellapi.ShellExecuteEx(sei)
+       if wait:
+               try:
+ winKernel.waitForSingleObject(sei.hProcess,
winKernel.INFINITE)
+                       return winKernel.GetExitCodeProcess(sei.hProcess)
+               finally:
+                       winKernel.closeHandle(sei.hProcess)
+
+SLAVE_FILENAME = u"nvda_slave.exe"
+
+NVDA_REGKEY = ur"SOFTWARE\NVDA"
+
+def getStartOnLogonScreen():
+       try:
+ k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
NVDA_REGKEY)
+ return bool(_winreg.QueryValueEx(k,
u"startOnLogonScreen")[0])
+       except WindowsError:
+               return False
+
+def _setStartOnLogonScreen(enable):
+ k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, NVDA_REGKEY,
0, _winreg.KEY_WRITE)
+ _winreg.SetValueEx(k, u"startOnLogonScreen", None,
_winreg.REG_DWORD, int(enable))
+
+def setStartOnLogonScreen(enable):
+       if getStartOnLogonScreen() == enable:
+               return
+       try:
+               # Try setting it directly.
+               _setStartOnLogonScreen(enable)
+       except WindowsError:
+ # We probably don't have admin privs, so we need to
elevate to do this using the slave.
+ if execElevated(SLAVE_FILENAME,
"config_setStartOnLogonScreen %d" % enable, wait=True) != 0:
+ raise RuntimeError("Slave failed to set
startOnLogonScreen")

Modified: trunk/source/gui/settingsDialogs.py
=================================================================
=============
--- trunk/source/gui/settingsDialogs.py (original)
+++ trunk/source/gui/settingsDialogs.py Fri May 15 07:13:17 2009
@@ -128,6 +128,16 @@
log.debugWarning("Could not set log level list to
current log level")
                logLevelSizer.Add(self.logLevelList)
                
settingsSizer.Add(logLevelSizer,border=10,flag=wx.BOTTO
M)
+ self.startAfterLogonCheckBox = wx.CheckBox(self,
wx.ID_ANY, label=_("&Automatically start NVDA after I log on to Windows"))
+               
self.startAfterLogonCheckBox.SetValue(config.getStartAf
terLogon())
+               if not config.isInstalledCopy():
+                       self.startAfterLogonCheckBox.Disable()
+               settingsSizer.Add(self.startAfterLogonCheckBox)
+ self.startOnLogonScreenCheckBox = wx.CheckBox(self,
wx.ID_ANY, label=_("Use NVDA on the Windows logon screen (requires administrator privileges)"))
+               
self.startOnLogonScreenCheckBox.SetValue(config.getStar
tOnLogonScreen())
+               if not config.isServiceInstalled():
+                       self.startOnLogonScreenCheckBox.Disable()
+               settingsSizer.Add(self.startOnLogonScreenCheckBox)

        def postInit(self):
                self.languageList.SetFocus()
@@ -147,6 +157,13 @@
                
logLevel=self.LOG_LEVELS[self.logLevelList.GetSelection
()][0]
                
config.conf["general"]["loggingLevel"]=logHandler.level
Names[logLevel]
                logHandler.setLogLevelFromConfig()
+               if self.startAfterLogonCheckBox.IsEnabled():
+                       
config.setStartAfterLogon(self.startAfterLogonChec
kBox.GetValue())
+               if self.startOnLogonScreenCheckBox.IsEnabled():
+                       try:
+                               
config.setStartOnLogonScreen(self.startOnLogo
nScreenCheckBox.GetValue())
+                       except (WindowsError, RuntimeError):
+ wx.MessageBox(_("This change requires
administrator privileges."), _("Insufficient Privileges"), style=wx.OK | wx.ICON_ERROR)
                if self.oldLanguage!=newLanguage:
if wx.MessageDialog(self,_("For the new language
to take effect, the configuration must be saved and NVDA must be restarted. Press enter to save and restart NVDA, or cancel to manually save and exit at a later time."),_("Language Configuration Change"),wx.OK|wx.CANCEL|wx.ICON_WARNING).ShowModa
l()==wx.ID_OK:
                                config.save()

Modified: trunk/source/nvda.pyw
=================================================================
=============
--- trunk/source/nvda.pyw       (original)
+++ trunk/source/nvda.pyw       Fri May 15 07:13:17 2009
@@ -62,6 +62,7 @@
 parser=NoConsoleOptionParser()
parser.add_option('-q','--quit',action="store_true",dest='quit',d
efault=False,help="Quit already running copy of NVDA")
parser.add_option('-r','--replace',action="store_true",dest='repl
ace',default=False,help="Quit already running copy of NVDA and start this one")
+parser.add_option('-k','--check-running',action="store_true",des
t='check_running',default=False,help="Report whether NVDA is running via the exit code; 0 if running, 1 if not running")
parser.add_option('-f','--log-file',dest='logFileName',default=lo
gFileName,help="The file where log messages should be written to")
parser.add_option('-l','--log-level',type="int",dest='logLevel',d
efault=0,help="The lowest level of message logged (debug 10, info 20, warning 30, error 40, critical 50), default is warning")
parser.add_option('-c','--config-path',dest='configPath',default=
config.getUserDefaultConfigPath(),help="The path where all settings for NVDA are stored")
@@ -87,6 +88,9 @@
                                sys.exit(1)
if globalVars.appArgs.quit or (oldAppWindowHandle and not
globalVars.appArgs.replace):
        sys.exit(0)
+elif globalVars.appArgs.check_running:
+       # NVDA is not running.
+       sys.exit(1)

 #os.environ['PYCHECKER']="--limit 10000 -q --changetypes"
 #import pychecker.checker

Added: trunk/source/nvda_service.py
=================================================================
=============
--- (empty file)
+++ trunk/source/nvda_service.py        Fri May 15 07:13:17 2009
@@ -0,0 +1,288 @@
+from ctypes import *
+from ctypes.wintypes import *
+import threading
+import win32serviceutil
+import win32service
+import sys
+import os
+import time
+import _winreg
+
+CREATE_UNICODE_ENVIRONMENT=1024
+INFINITE = 0xffffffff
+UOI_NAME = 2
+SYNCHRONIZE = 0x100000
+WAIT_OBJECT_0 = 0
+MAXIMUM_ALLOWED = 0x2000000
+SecurityIdentification = 2
+TokenPrimary = 1
+PROCESS_QUERY_INFORMATION = 0x0400
+TokenSessionId = 12
+TokenUIAccess = 26
+WTS_CONSOLE_CONNECT = 0x1
+WTS_CONSOLE_DISCONNECT = 0x2
+WTS_SESSION_LOGON = 0x5
+WTS_SESSION_LOGOFF = 0x6
+WTS_SESSION_LOCK = 0x7
+WTS_SESSION_UNLOCK = 0x8
+WTS_CURRENT_SERVER_HANDLE = 0
+WTSUserName = 5
+
+nvdaExec = os.path.join(sys.prefix,"nvda.exe")
+slaveExec = os.path.join(sys.prefix,"nvda_slave.exe")
+
+def debug(msg):
+       try:
+ file(os.path.join(os.getenv("windir"), "temp",
"nvda_service.log"), "a").write(msg + "\n")
+       except (OSError, IOError):
+               pass
+
+def getInputDesktopName():
+       desktop = windll.user32.OpenInputDesktop(0, False, 0)
+       name = create_unicode_buffer(256)
+ windll.user32.GetUserObjectInformationW(desktop, UOI_NAME,
byref(name), sizeof(name), None)
+       windll.user32.CloseDesktop(desktop)
+       return ur"WinSta0\%s" % name.value
+
+class STARTUPINFO(Structure):
+       _fields_=[
+               ('cb',DWORD),
+               ('lpReserved',LPWSTR),
+               ('lpDesktop',LPWSTR),
+               ('lpTitle',LPWSTR),
+               ('dwX',DWORD),
+               ('dwY',DWORD),
+               ('dwXSize',DWORD),
+               ('dwYSize',DWORD),
+               ('dwXCountChars',DWORD),
+               ('dwYCountChars',DWORD),
+               ('dwFillAttribute',DWORD),
+               ('dwFlags',DWORD),
+               ('wShowWindow',WORD),
+               ('cbReserved2',WORD),
+               ('lpReserved2',POINTER(c_byte)),
+               ('hSTDInput',HANDLE),
+               ('hSTDOutput',HANDLE),
+               ('hSTDError',HANDLE),
+       ]
+
+class PROCESS_INFORMATION(Structure):
+       _fields_=[
+               ('hProcess',HANDLE),
+               ('hThread',HANDLE),
+               ('dwProcessID',DWORD),
+               ('dwThreadID',DWORD),
+       ]
+
+def getLoggedOnUserToken(session):
+       # Only works in Windows XP and above.
+       token = HANDLE()
+       windll.wtsapi32.WTSQueryUserToken(session, byref(token))
+       return token.value
+
+def duplicateTokenPrimary(token):
+       newToken = HANDLE()
+ windll.advapi32.DuplicateTokenEx(token, MAXIMUM_ALLOWED,
None, SecurityIdentification, TokenPrimary, byref(newToken))
+       windll.kernel32.CloseHandle(token)
+       return newToken.value
+
+def getOwnToken():
+ process =
windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, False, os.getpid())
+       token = HANDLE()
+ windll.advapi32.OpenProcessToken(process, MAXIMUM_ALLOWED,
byref(token))
+       windll.kernel32.CloseHandle(process)
+       return token
+
+def getSessionSystemToken(session):
+       token = duplicateTokenPrimary(getOwnToken())
+       session = DWORD(session)
+ windll.advapi32.SetTokenInformation(token, TokenSessionId,
byref(session), sizeof(DWORD))
+       return token
+
+def executeProcess(desktop, token, executable, *argStrings):
+       argsString=" ".join(list(argStrings))
+       
startupInfo=STARTUPINFO(cb=sizeof(STARTUPINFO),lpDesktop=des
ktop)
+       processInformation=PROCESS_INFORMATION()
+ cmdBuf=create_unicode_buffer(u'"%s"
%s'%(executable,argsString))
+       if token:
+               env=c_void_p()
+               
windll.userenv.CreateEnvironmentBlock(byref(env),token,
False)
+               try:
+ if windll.advapi32.CreateProcessAsUserW(token,
None, cmdBuf,None,None,False,CREATE_UNICODE_ENVIRONMENT,
env,None,byref(startupInfo),byref(processInformati
on)) == 0:
+                               raise WinError()
+               finally:
+                       windll.kernel32.CloseHandle(token)
+                       windll.userenv.DestroyEnvironmentBlock(env)
+       else:
+ if windll.kernel32.CreateProcessW(None,
cmdBuf,None,None,False,0,None,None,byref(startupInfo),b
yref(processInformation)) == 0:
+                       raise WinError()
+       return processInformation.hProcess
+
+def nvdaLauncher():
+       desktop = getInputDesktopName()
+       if desktop == ur"WinSta0\Default":
+               return
+
+       startNVDA(desktop)
+ desktopSwitchEvt = windll.kernel32.OpenEventW(SYNCHRONIZE,
False, u"WinSta0_DesktopSwitch")
+ windll.kernel32.WaitForSingleObject(desktopSwitchEvt,
INFINITE)
+       windll.kernel32.CloseHandle(desktopSwitchEvt)
+       exitNVDA(desktop)
+
+def startNVDA(desktop):
+       process = executeProcess(desktop, None, nvdaExec, "-m")
+       windll.kernel32.CloseHandle(process)
+
+def startNVDAUIAccess(session, desktop):
+       token = duplicateTokenPrimary(getLoggedOnUserToken(session))
+       uiAccess = ULONG(1)
+ windll.advapi32.SetTokenInformation(token, TokenUIAccess,
byref(uiAccess), sizeof(ULONG))
+       process = executeProcess(desktop, token, nvdaExec, "-m")
+       windll.kernel32.CloseHandle(process)
+
+def exitNVDA(desktop):
+       process = executeProcess(desktop, None, nvdaExec, "-q")
+       windll.kernel32.WaitForSingleObject(process, 10000)
+       windll.kernel32.CloseHandle(process)
+
+def isUserRunningNVDA(session):
+       token = getSessionSystemToken(session)
+ process = executeProcess(ur"WinSta0\Default", token,
nvdaExec, u"--check-running")
+       windll.kernel32.WaitForSingleObject(process, INFINITE)
+       exitCode = DWORD()
+       windll.kernel32.GetExitCodeProcess(process, byref(exitCode))
+       windll.kernel32.CloseHandle(process)
+       return exitCode.value == 0
+
+def isSessionLoggedOn(session):
+       username = c_wchar_p()
+       size = DWORD()
+       
windll.wtsapi32.WTSQuerySessionInformationW(WTS_CURRENT_SERV
ER_HANDLE, session, WTSUserName, byref(username), byref(size))
+       ret = bool(username.value)
+       windll.wtsapi32.WTSFreeMemory(username)
+       return ret
+
+def execBg(func):
+       t = threading.Thread(target=func)
+       t.setDaemon(True)
+       t.start()
+
+def shouldStartOnLogonScreen():
+       try:
+ k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
ur"SOFTWARE\NVDA")
+ return bool(_winreg.QueryValueEx(k,
u"startOnLogonScreen")[0])
+       except WindowsError:
+               return False
+
+class NVDAService(win32serviceutil.ServiceFramework):
+
+       _svc_name_="nvda"
+       _svc_display_name_="nonVisual Desktop Access"
+
+       def GetAcceptedControls(self):
+ return
win32serviceutil.ServiceFramework.GetAcceptedControls(s
elf) | win32service.SERVICE_ACCEPT_SESSIONCHANGE
+
+       def initSession(self, session):
+               debug("init session %d" % session)
+               self.session = session
+               self.launcherLock = threading.RLock()
+               self.launcherStarted = False
+               self.desktopSwitchSupervisorStarted = False
+               self.isSessionLoggedOn = isSessionLoggedOn(session)
+               debug("session logged on: %r" % self.isSessionLoggedOn)
+
+               if self.isSessionLoggedOn:
+ # The session is logged on, so treat this as a
normal desktop switch.
+                       self.handleDesktopSwitch()
+                       execBg(self.desktopSwitchSupervisor)
+               else:
+                       # We're at the logon screen.
+                       if shouldStartOnLogonScreen():
+                               execBg(self.startLauncher)
+ # The desktop switch supervisor will be started by
the logon event.
+
+       def desktopSwitchSupervisor(self):
+               if self.desktopSwitchSupervisorStarted:
+                       return
+               self.desktopSwitchSupervisorStarted = True
+               origSession = self.session
+ debug("starting desktop switch supervisor, session %d"
% origSession)
+ desktopSwitchEvt =
windll.kernel32.OpenEventW(SYNCHRONIZE, False, u"Session\%d\WinSta0_DesktopSwitch" % self.session)
+               if not desktopSwitchEvt:
+                       try:
+                               raise WinError()
+                       except Exception, e:
+                               debug("error opening event: %s" % e)
+                               raise
+
+               while self.session == origSession:
+                       
windll.kernel32.WaitForSingleObject(desktopSwitchE
vt, INFINITE)
+                       debug("desktop switch, session %r" % self.session)
+                       self.handleDesktopSwitch()
+
+               windll.kernel32.CloseHandle(desktopSwitchEvt)
+ debug("desktop switch supervisor terminated, session
%d" % origSession)
+
+       def handleDesktopSwitch(self):
+               with self.launcherLock:
+                       self.launcherStarted = False
+
+ if (not self.isSessionLoggedOn and
shouldStartOnLogonScreen()) or isUserRunningNVDA(self.session):
+                       self.startLauncher()
+               else:
+                       debug("not starting launcher")
+
+       def SvcOtherEx(self, control, eventType, data):
+ if control ==
win32service.SERVICE_CONTROL_SESSIONCHANGE:
+                       self.handleSessionChange(eventType, data[0])
+
+       def handleSessionChange(self, event, session):
+               if event == WTS_CONSOLE_CONNECT:
+                       debug("connect %d" % session)
+                       if session != self.session:
+                               self.initSession(session)
+               elif event == WTS_SESSION_LOGON:
+                       debug("logon %d" % session)
+                       self.isSessionLoggedOn = True
+                       execBg(self.desktopSwitchSupervisor)
+               elif event == WTS_SESSION_LOGOFF:
+                       debug("logoff %d" % session)
+                       self.isSessionLoggedOn = False
+                       # We may be heading back to the logon screen.
+                       if shouldStartOnLogonScreen():
+                               execBg(self.startLauncher)
+               elif event == WTS_SESSION_LOCK:
+                       debug("lock %d" % session)
+                       if session == self.session:
+ # We always start NVDA for the lock/switch
user screen.
+                               self.startLauncher()
+
+       def startLauncher(self):
+               with self.launcherLock:
+                       if self.launcherStarted:
+                               return
+
+                       debug("attempt launcher start")
+                       token = getSessionSystemToken(self.session)
+                       try:
+ process =
executeProcess(ur"WinSta0\Winlogon", token, slaveExec, u"service_NVDALauncher")
+                               self.launcherStarted = True
+                               debug("launcher started")
+                               windll.kernel32.CloseHandle(process)
+                       except Exception, e:
+                               debug("error starting launcher: %s" % e)
+
+       def SvcDoRun(self):
+               debug("service starting")
+               self.exitEvent = threading.Event()
+               
self.initSession(windll.kernel32.WTSGetActiveConsoleSes
sionId())
+               self.exitEvent.wait()
+               debug("service exiting")
+
+       def SvcStop(self):
+               self.exitEvent.set()
+
+if __name__=='__main__':
+       if not getattr(sys, "frozen", None):
+ raise RuntimeError("Can only be run compiled with
py2exe")
+       win32serviceutil.HandleCommandLine(NVDAService)

Added: trunk/source/nvda_slave.pyw
=================================================================
=============
--- (empty file)
+++ trunk/source/nvda_slave.pyw Fri May 15 07:13:17 2009
@@ -0,0 +1,32 @@
+"""NVDA slave process
+Performs miscellaneous tasks which need to be performed in a
separate process.
+"""
+
+import sys
+if hasattr(sys, "frozen"):
+ # Error messages (which are only for debugging) should not
cause the py2exe log message box to appear.
+       sys.stderr = sys.stdout
+
+def main():
+       try:
+               action = sys.argv[1]
+       except IndexError:
+               sys.exit("No action")
+       args = sys.argv[2:]
+
+       try:
+               if action == "service_NVDALauncher":
+                       import nvda_service
+                       nvda_service.nvdaLauncher()
+               elif action == "config_setStartOnLogonScreen":
+                       enable = bool(int(args[0]))
+                       import config
+                       config._setStartOnLogonScreen(enable)
+               else:
+                       raise ValueError("No such action")
+
+       except Exception, e:
+               sys.exit(e)
+
+if __name__ == "__main__":
+       main()

Modified: trunk/source/setup.py
=================================================================
=============
--- trunk/source/setup.py       (original)
+++ trunk/source/setup.py       Fri May 15 07:13:17 2009
@@ -98,13 +98,31 @@
 'Operating System :: Microsoft :: Windows',
 ],
        cmdclass={"py2exe": py2exe},
-       windows = [{
-               "script":"nvda.pyw",
-               "uac_info": ("asInvoker", False),
-               "icon_resources":[(1,"images/nvda.ico")],
-               "version":"0.0.0.0",
-               "product_version":version,
-               "copyright":copyright,
+       windows=[
+               {
+                       "script":"nvda.pyw",
+                       "uac_info": ("asInvoker", False),
+                       "icon_resources":[(1,"images/nvda.ico")],
+                       "version":"0.0.0.0",
+                       "product_version":version,
+                       "copyright":copyright,
+               },
+               {
+                       "script": "nvda_slave.pyw",
+                       "icon_resources": [(1,"images/nvda.ico")],
+                       "version": "0.0.0.0",
+                       "product_version": version,
+                       "copyright": copyright,
+               },
+       ],
+       service=[{
+               "modules": ["nvda_service"],
+               "icon_resources": [(1, "images/nvda.ico")],
+               "version": "0.0.0.0",
+               "product_version": version,
+               "copyright": copyright,
+               "uac_info": ("requireAdministrator", False),
+               "cmdline_style": "pywin32",
        }],
        options = {"py2exe": {
                "bundle_files": 3,
@@ -112,7 +130,6 @@
                "packages": ["NVDAObjects","virtualBuffers"],
                "includes": getOptionalIncludes(),
        }},
-       zipfile = None,
        data_files=[
                (".",glob("*.dll")+glob("*.manifest")+["builtin.dic"]),
("documentation", ['../copying.txt',
'../contributors.txt']),

Added: trunk/source/shellapi.py
=================================================================
=============
--- (empty file)
+++ trunk/source/shellapi.py    Fri May 15 07:13:17 2009
@@ -0,0 +1,38 @@
+#shellapi.py
+#A part of NonVisual Desktop Access (NVDA)
+#Copyright (C) 2006-2009 NVDA
Contributors<http://www.nvda-project.org/
+#This file is covered by the GNU General Public License.
+#See the file COPYING for more details.
+
+from ctypes import *
+from ctypes.wintypes import *
+
+shell32 = windll.shell32
+
+class SHELLEXECUTEINFOW(Structure):
+       _fields_ = (
+               ("cbSize", DWORD),
+               ("fMask", ULONG),
+               ("hwnd", HWND),
+               ("lpVerb", LPCWSTR),
+               ("lpFile", LPCWSTR),
+               ("lpParameters", LPCWSTR),
+               ("lpDirectory", LPCWSTR),
+               ("nShow", c_int),
+               ("hInstApp", HINSTANCE),
+               ("lpIDList", LPVOID),
+               ("lpClass", LPCWSTR),
+               ("hkeyClass", HKEY),
+               ("dwHotKey", DWORD),
+               ("hIconOrMonitor", HANDLE),
+               ("hProcess", HANDLE),
+       )
+       def __init__(self, **kwargs):
+ super(SHELLEXECUTEINFOW,
self).__init__(cbSize=sizeof(self), **kwargs)
+SHELLEXECUTEINFO = SHELLEXECUTEINFOW
+
+SEE_MASK_NOCLOSEPROCESS = 0x00000040
+
+def ShellExecuteEx(execInfo):
+       if not shell32.ShellExecuteExW(byref(execInfo)):
+               raise WinError()

Modified: trunk/source/winKernel.py
=================================================================
=============
--- trunk/source/winKernel.py   (original)
+++ trunk/source/winKernel.py   Fri May 15 07:13:17 2009
@@ -101,3 +101,9 @@
        res = kernel32.SetProcessShutdownParameters(level, flags)
        if res == 0:
                raise ctypes.WinError()
+
+def GetExitCodeProcess(process):
+       exitCode = ctypes.wintypes.DWORD()
+ if not kernel32.GetExitCodeProcess(process,
ctypes.byref(exitCode)):
+               raise ctypes.WinError()
+       return exitCode.value

Modified: trunk/source/winUser.py
=================================================================
=============
--- trunk/source/winUser.py     (original)
+++ trunk/source/winUser.py     Fri May 15 07:13:17 2009
@@ -237,6 +237,10 @@
 EVENT_CONSOLE_START_APPLICATION=0x4006
 EVENT_CONSOLE_END_APPLICATION=0x4007

+# ShowWindow() commands
+SW_HIDE = 0
+SW_SHOWNORMAL = 1
+
 def setSystemScreenReaderFlag(val):
        
user32.SystemParametersInfoW(SPI_SETSCREENREADER,val,0,SPIF_
SENDCHANGE)


Modified: trunk/user_docs/en/whats new.txt
=================================================================
=============
--- trunk/user_docs/en/whats new.txt    (original)
+++ trunk/user_docs/en/whats new.txt    Fri May 15 07:13:17 2009
@@ -24,8 +24,11 @@
*New: In Windows Vista, if the user moves to the secure desktop
(either because a UAC control dialog appeared, or because control+alt+delete was pressed), NVDA will announce the fact that the user is now on the secure desktop. This desktop is still not accessible to NVDA, though the user at least is notified as to what happened.
*Fix: better support for Dos consoles. specifically: NVDA can
now read the content of particular consoles it always used to think were blank. Pressing control+break no longer terminates NVDA.
*New: NVDA can announce text under the mouse within dos
console windows.
+* new: NVDA can be configured to start automatically after you
log on to Windows.  The option is in the General Settings dialog.
+* new: NVDA can read secure Windows screens such as the Windows
logon, control+alt+delete and UAC screens in Windows XP and above. Reading of the Windows logon screen can be configured from the General Settings dialog. (#97)
+* fix: On Windows Vista, the NVDA installer now starts NVDA with
normal user privileges when requested to run NVDA on the finish screen.

- Changes since 0.6 P2:
+Changes since 0.6 P2:
* new: As Microsoft Excel's formula bar is inaccessible to
NVDA, provide an NVDA specific dialog box for editing when the user presses f2 on a cell.
* change: If the audio output device is set to use the Windows
default device (Microsoft Sound Mapper), NVDA will now switch to the new default device for eSpeak and tones when the default device changes. For example, NVDA will switch to a USB audio device if it automatically becomes the default device when it is connected.
* fix: The last chunk of audio is no longer cut off when using
NVDA with eSpeak on a remote desktop server.

_______________________________________________
Nvda-dev mailing list
Nvda-dev@xxxxxxxxxxxxxxxxxx
http://lists.nvaccess.org/listinfo/nvda-dev

blind_html
To unsubscribe, please send a blank email to
blind_html-request@xxxxxxxxxxxxx
with unsubscribe in the subject line.
To access the archives, please visit:
http://www.freelists.org/archive/blind_html

Thanks
blind_html
To unsubscribe, please send a blank email to
blind_html-request@xxxxxxxxxxxxx
with unsubscribe in the subject line.
To access the archives, please visit:
http://www.freelists.org/archive/blind_html

Thanks

Other related posts: