1
2
3
4
5
6
7 from ctypes import *
8 from ctypes.wintypes import *
9 import threading
10 import win32serviceutil
11 import win32service
12 import sys
13 import os
14 import time
15 import subprocess
16 import _winreg
17
18 CREATE_UNICODE_ENVIRONMENT=1024
19 INFINITE = 0xffffffff
20 UOI_NAME = 2
21 SYNCHRONIZE = 0x100000
22 WAIT_OBJECT_0 = 0
23 MAXIMUM_ALLOWED = 0x2000000
24 SecurityIdentification = 2
25 TokenPrimary = 1
26 PROCESS_QUERY_INFORMATION = 0x0400
27 TokenSessionId = 12
28 TokenUIAccess = 26
29 WTS_CONSOLE_CONNECT = 0x1
30 WTS_CONSOLE_DISCONNECT = 0x2
31 WTS_SESSION_LOGON = 0x5
32 WTS_SESSION_LOGOFF = 0x6
33 WTS_SESSION_LOCK = 0x7
34 WTS_SESSION_UNLOCK = 0x8
35 WTS_CURRENT_SERVER_HANDLE = 0
36 WTSUserName = 5
37
38 nvdaExec = os.path.join(sys.prefix,"nvda.exe")
39 slaveExec = os.path.join(sys.prefix,"nvda_slave.exe")
40 nvdaSystemConfigDir=os.path.join(sys.prefix,'systemConfig')
41
43 """A HANDLE which is automatically closed when no longer in use.
44 """
45
47 if self:
48 windll.kernel32.CloseHandle(self)
49
50 isDebug = False
51
53 if not isDebug:
54 return
55 try:
56 file(os.path.join(os.getenv("windir"), "temp", "nvda_service.log"), "a").write(msg + "\n")
57 except (OSError, IOError):
58 pass
59
66
68 _fields_=[
69 ('cb',DWORD),
70 ('lpReserved',LPWSTR),
71 ('lpDesktop',LPWSTR),
72 ('lpTitle',LPWSTR),
73 ('dwX',DWORD),
74 ('dwY',DWORD),
75 ('dwXSize',DWORD),
76 ('dwYSize',DWORD),
77 ('dwXCountChars',DWORD),
78 ('dwYCountChars',DWORD),
79 ('dwFillAttribute',DWORD),
80 ('dwFlags',DWORD),
81 ('wShowWindow',WORD),
82 ('cbReserved2',WORD),
83 ('lpReserved2',POINTER(c_byte)),
84 ('hSTDInput',HANDLE),
85 ('hSTDOutput',HANDLE),
86 ('hSTDError',HANDLE),
87 ]
88
96
98
99 token = AutoHANDLE()
100 windll.wtsapi32.WTSQueryUserToken(session, byref(token))
101 return token
102
107
113
119
121 argsString=subprocess.list2cmdline(list(argStrings))
122 startupInfo=STARTUPINFO(cb=sizeof(STARTUPINFO),lpDesktop=desktop)
123 processInformation=PROCESS_INFORMATION()
124 cmdBuf=create_unicode_buffer(u'"%s" %s'%(executable,argsString))
125 if token:
126 env=c_void_p()
127 windll.userenv.CreateEnvironmentBlock(byref(env),token,False)
128 try:
129 if windll.advapi32.CreateProcessAsUserW(token, None, cmdBuf,None,None,False,CREATE_UNICODE_ENVIRONMENT,env,None,byref(startupInfo),byref(processInformation)) == 0:
130 raise WinError()
131 finally:
132 windll.userenv.DestroyEnvironmentBlock(env)
133 else:
134 if windll.kernel32.CreateProcessW(None, cmdBuf,None,None,False,0,None,None,byref(startupInfo),byref(processInformation)) == 0:
135 raise WinError()
136 windll.kernel32.CloseHandle(processInformation.hThread)
137 return AutoHANDLE(processInformation.hProcess)
138
140 initDebug()
141 desktop = getInputDesktopName()
142 debug("launcher: starting with desktop %s" % desktop)
143 desktopBn = os.path.basename(desktop)
144 if desktopBn != u"Winlogon" and not desktopBn.startswith(u"InfoCard{"):
145 debug("launcher: user or screen-saver desktop, exiting")
146 return
147
148 debug("launcher: starting NVDA")
149 process = startNVDA(desktop)
150 desktopSwitchEvt = AutoHANDLE(windll.kernel32.OpenEventW(SYNCHRONIZE, False, u"WinSta0_DesktopSwitch"))
151 windll.kernel32.WaitForSingleObject(desktopSwitchEvt, INFINITE)
152 debug("launcher: desktop switch, exiting NVDA on desktop %s" % desktop)
153 exitNVDA(desktop)
154
155
156 windll.kernel32.TerminateProcess(process, 1)
157
165
171
180
182 username = c_wchar_p()
183 size = DWORD()
184 windll.wtsapi32.WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session, WTSUserName, byref(username), byref(size))
185 ret = bool(username.value)
186 windll.wtsapi32.WTSFreeMemory(username)
187 return ret
188
190 t = threading.Thread(target=func)
191 t.setDaemon(True)
192 t.start()
193
195 try:
196 k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, ur"SOFTWARE\NVDA")
197 return bool(_winreg.QueryValueEx(k, u"startOnLogonScreen")[0])
198 except WindowsError:
199 return False
200
202 global isDebug
203 try:
204 k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, ur"SOFTWARE\NVDA")
205 isDebug = bool(_winreg.QueryValueEx(k, u"serviceDebug")[0])
206 except WindowsError:
207 isDebug = False
208
210
211 _svc_name_="nvda"
212 _svc_display_name_="NVDA"
213
215 return win32serviceutil.ServiceFramework.GetAcceptedControls(self) | win32service.SERVICE_ACCEPT_SESSIONCHANGE
216
239
241 if self.desktopSwitchSupervisorStarted:
242 return
243 self.desktopSwitchSupervisorStarted = True
244 origSession = self.session
245 debug("starting desktop switch supervisor, session %d" % origSession)
246 desktopSwitchEvt = AutoHANDLE(windll.kernel32.OpenEventW(SYNCHRONIZE, False, u"Session\%d\WinSta0_DesktopSwitch" % self.session))
247 if not desktopSwitchEvt:
248 try:
249 raise WinError()
250 except Exception, e:
251 debug("error opening event: %s" % e)
252 raise
253
254 while True:
255 windll.kernel32.WaitForSingleObject(desktopSwitchEvt, INFINITE)
256 if self.session != origSession:
257 break
258 debug("desktop switch, session %r" % self.session)
259 self.handleDesktopSwitch()
260
261 debug("desktop switch supervisor terminated, session %d" % origSession)
262
271
273 if control == win32service.SERVICE_CONTROL_SESSIONCHANGE:
274 self.handleSessionChange(eventType, data[0])
275
299
301 with self.launcherLock:
302 if self.launcherStarted:
303 return
304
305 debug("attempt launcher start on session %d" % self.session)
306 token = getSessionSystemToken(self.session)
307 try:
308 process = executeProcess(ur"WinSta0\Winlogon", token, slaveExec, u"service_NVDALauncher")
309 self.launcherStarted = True
310 debug("launcher started on session %d" % self.session)
311 except Exception, e:
312 debug("error starting launcher: %s" % e)
313
315 initDebug()
316 debug("service starting")
317 self.isWindowsXP = sys.getwindowsversion()[0:2] == (5, 1)
318 self.exitEvent = threading.Event()
319 self.initSession(windll.kernel32.WTSGetActiveConsoleSessionId())
320 self.exitEvent.wait()
321 debug("service exiting")
322
325
327 servicePath = os.path.join(nvdaDir, __name__ + ".exe")
328 if not os.path.isfile(servicePath):
329 raise RuntimeError("Could not find service executable")
330 win32serviceutil.InstallService(None, NVDAService._svc_name_, NVDAService._svc_display_name_, startType=win32service.SERVICE_AUTO_START, exeName=servicePath)
331
334
337
339 """Stop the running service and wait for its process to die.
340 """
341 scm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS)
342 try:
343 serv = win32service.OpenService(scm, NVDAService._svc_name_, win32service.SERVICE_ALL_ACCESS)
344 try:
345 pid = win32service.QueryServiceStatusEx(serv)["ProcessId"]
346
347
348 win32service.ControlService(serv, win32service.SERVICE_CONTROL_STOP)
349
350
351 proc = AutoHANDLE(windll.kernel32.OpenProcess(SYNCHRONIZE, False, pid))
352 if not proc:
353 return
354 windll.kernel32.WaitForSingleObject(proc, INFINITE)
355
356 finally:
357 win32service.CloseServiceHandle(serv)
358 finally:
359 win32service.CloseServiceHandle(scm)
360
361 if __name__=='__main__':
362 if not getattr(sys, "frozen", None):
363 raise RuntimeError("Can only be run compiled with py2exe")
364 win32serviceutil.HandleCommandLine(NVDAService)
365