##// END OF EJS Templates
port win32.py to using the Python ctypes library...
Adrian Buehlmann -
r13375:f1fa8f48 default
parent child Browse files
Show More
@@ -16,23 +16,14 b''
16 16 <File Name="mercurial.parsers.pyd" />
17 17 <File Name="pyexpat.pyd" />
18 18 <File Name="python26.dll" />
19 <File Name="pythoncom26.dll" />
20 <File Name="pywintypes26.dll" />
21 19 <File Name="bz2.pyd" />
22 20 <File Name="select.pyd" />
23 21 <File Name="unicodedata.pyd" />
24 <File Name="win32api.pyd" />
25 <File Name="win32com.shell.shell.pyd" />
26 <File Name="win32console.pyd" />
27 <File Name="win32file.pyd" />
28 <File Name="win32gui.pyd" />
29 <File Name="win32pipe.pyd" />
30 <File Name="win32process.pyd" />
22 <File Name="_ctypes.pyd" />
31 23 <File Name="_elementtree.pyd" />
32 24 <File Name="_hashlib.pyd" />
33 25 <File Name="_socket.pyd" />
34 26 <File Name="_ssl.pyd" />
35 <File Name="_win32sysloader.pyd" />
36 27 </Component>
37 28 </DirectoryRef>
38 29 </Fragment>
@@ -9,7 +9,7 b''
9 9 <?define contrib.vim.guid = {BB04903A-652D-4C4F-9590-2BD07A2304F2} ?>
10 10
11 11 <!-- dist.wxs -->
12 <?define dist.guid = {0F63D160-0740-4BAF-BF25-0C6930310F51} ?>
12 <?define dist.guid = {C3B634A4-1B05-4A40-94A9-38EE853CF693} ?>
13 13
14 14 <!-- doc.wxs -->
15 15 <?define doc.hg.1.html.guid = {AAAA3FDA-EDC5-4220-B59D-D342722358A2} ?>
@@ -13,6 +13,7 b' posixfile = open'
13 13 nulldev = '/dev/null'
14 14 normpath = os.path.normpath
15 15 samestat = os.path.samestat
16 os_link = os.link
16 17 unlink = os.unlink
17 18 rename = os.rename
18 19 expandglobs = False
@@ -24,6 +25,10 b' def openhardlinks():'
24 25 '''return true if it is safe to hold open file handles to hardlinks'''
25 26 return True
26 27
28 def nlinks(name):
29 '''return number of hardlinks for the given file'''
30 return os.lstat(name).st_nlink
31
27 32 def rcfiles(path):
28 33 rcs = [os.path.join(path, 'hgrc')]
29 34 rcdir = os.path.join(path, 'hgrc.d')
@@ -554,16 +554,6 b' class path_auditor(object):'
554 554 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
555 555 self.auditeddir.update(prefixes)
556 556
557 def nlinks(pathname):
558 """Return number of hardlinks for the given file."""
559 return os.lstat(pathname).st_nlink
560
561 if hasattr(os, 'link'):
562 os_link = os.link
563 else:
564 def os_link(src, dst):
565 raise OSError(0, _("Hardlinks not supported"))
566
567 557 def lookup_reg(key, name=None, scope=None):
568 558 return None
569 559
@@ -5,74 +5,173 b''
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 """Utility functions that use win32 API.
8 import osutil, encoding
9 import ctypes, errno, os, struct, subprocess
10
11 _kernel32 = ctypes.windll.kernel32
12
13 _BOOL = ctypes.c_long
14 _WORD = ctypes.c_ushort
15 _DWORD = ctypes.c_ulong
16 _LPCSTR = _LPSTR = ctypes.c_char_p
17 _HANDLE = ctypes.c_void_p
18 _HWND = _HANDLE
19
20 _INVALID_HANDLE_VALUE = -1
21
22 # GetLastError
23 _ERROR_SUCCESS = 0
24 _ERROR_INVALID_PARAMETER = 87
25 _ERROR_INSUFFICIENT_BUFFER = 122
26
27 # WPARAM is defined as UINT_PTR (unsigned type)
28 # LPARAM is defined as LONG_PTR (signed type)
29 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
30 _WPARAM = ctypes.c_ulong
31 _LPARAM = ctypes.c_long
32 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
33 _WPARAM = ctypes.c_ulonglong
34 _LPARAM = ctypes.c_longlong
35
36 class _FILETIME(ctypes.Structure):
37 _fields_ = [('dwLowDateTime', _DWORD),
38 ('dwHighDateTime', _DWORD)]
39
40 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
41 _fields_ = [('dwFileAttributes', _DWORD),
42 ('ftCreationTime', _FILETIME),
43 ('ftLastAccessTime', _FILETIME),
44 ('ftLastWriteTime', _FILETIME),
45 ('dwVolumeSerialNumber', _DWORD),
46 ('nFileSizeHigh', _DWORD),
47 ('nFileSizeLow', _DWORD),
48 ('nNumberOfLinks', _DWORD),
49 ('nFileIndexHigh', _DWORD),
50 ('nFileIndexLow', _DWORD)]
51
52 # CreateFile
53 _FILE_SHARE_READ = 0x00000001
54 _FILE_SHARE_WRITE = 0x00000002
55 _FILE_SHARE_DELETE = 0x00000004
56
57 _OPEN_EXISTING = 3
58
59 # Process Security and Access Rights
60 _PROCESS_QUERY_INFORMATION = 0x0400
61
62 # GetExitCodeProcess
63 _STILL_ACTIVE = 259
64
65 # registry
66 _HKEY_CURRENT_USER = 0x80000001L
67 _HKEY_LOCAL_MACHINE = 0x80000002L
68 _KEY_READ = 0x20019
69 _REG_SZ = 1
70 _REG_DWORD = 4
9 71
10 Mark Hammond's win32all package allows better functionality on
11 Windows. This module overrides definitions in util.py. If not
12 available, import of this module will fail, and generic code will be
13 used.
14 """
72 class _STARTUPINFO(ctypes.Structure):
73 _fields_ = [('cb', _DWORD),
74 ('lpReserved', _LPSTR),
75 ('lpDesktop', _LPSTR),
76 ('lpTitle', _LPSTR),
77 ('dwX', _DWORD),
78 ('dwY', _DWORD),
79 ('dwXSize', _DWORD),
80 ('dwYSize', _DWORD),
81 ('dwXCountChars', _DWORD),
82 ('dwYCountChars', _DWORD),
83 ('dwFillAttribute', _DWORD),
84 ('dwFlags', _DWORD),
85 ('wShowWindow', _WORD),
86 ('cbReserved2', _WORD),
87 ('lpReserved2', ctypes.c_char_p),
88 ('hStdInput', _HANDLE),
89 ('hStdOutput', _HANDLE),
90 ('hStdError', _HANDLE)]
91
92 class _PROCESS_INFORMATION(ctypes.Structure):
93 _fields_ = [('hProcess', _HANDLE),
94 ('hThread', _HANDLE),
95 ('dwProcessId', _DWORD),
96 ('dwThreadId', _DWORD)]
97
98 _DETACHED_PROCESS = 0x00000008
99 _STARTF_USESHOWWINDOW = 0x00000001
100 _SW_HIDE = 0
15 101
16 import win32api
102 class _COORD(ctypes.Structure):
103 _fields_ = [('X', ctypes.c_short),
104 ('Y', ctypes.c_short)]
105
106 class _SMALL_RECT(ctypes.Structure):
107 _fields_ = [('Left', ctypes.c_short),
108 ('Top', ctypes.c_short),
109 ('Right', ctypes.c_short),
110 ('Bottom', ctypes.c_short)]
111
112 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
113 _fields_ = [('dwSize', _COORD),
114 ('dwCursorPosition', _COORD),
115 ('wAttributes', _WORD),
116 ('srWindow', _SMALL_RECT),
117 ('dwMaximumWindowSize', _COORD)]
17 118
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
19 import winerror, win32gui, win32console
20 import osutil, encoding
21 from win32com.shell import shell, shellcon
119 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
120
121 def _raiseoserror(name):
122 err = ctypes.WinError()
123 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
124
125 def _getfileinfo(name):
126 fh = _kernel32.CreateFileA(name, 0,
127 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
128 None, _OPEN_EXISTING, 0, None)
129 if fh == _INVALID_HANDLE_VALUE:
130 _raiseoserror(name)
131 try:
132 fi = _BY_HANDLE_FILE_INFORMATION()
133 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
134 _raiseoserror(name)
135 return fi
136 finally:
137 _kernel32.CloseHandle(fh)
22 138
23 139 def os_link(src, dst):
24 try:
25 win32file.CreateHardLink(dst, src)
26 except pywintypes.error:
27 raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
28 except NotImplementedError: # Another fake error win Win98
29 raise OSError(errno.EINVAL, 'Hardlinking not supported')
140 if not _kernel32.CreateHardLinkA(dst, src, None):
141 _raiseoserror(src)
30 142
31 def _getfileinfo(pathname):
32 """Return number of hardlinks for the given file."""
33 try:
34 fh = win32file.CreateFile(pathname, 0,
35 win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE |
36 win32file.FILE_SHARE_DELETE,
37 None, win32file.OPEN_EXISTING, 0, None)
38 except pywintypes.error:
39 raise OSError(errno.ENOENT, 'The system cannot find the file specified')
40 try:
41 return win32file.GetFileInformationByHandle(fh)
42 finally:
43 fh.Close()
44
45 def nlinks(pathname):
46 """Return number of hardlinks for the given file."""
47 return _getfileinfo(pathname)[7]
143 def nlinks(name):
144 '''return number of hardlinks for the given file'''
145 return _getfileinfo(name).nNumberOfLinks
48 146
49 147 def samefile(fpath1, fpath2):
50 """Returns whether fpath1 and fpath2 refer to the same file. This is only
51 guaranteed to work for files, not directories."""
148 '''Returns whether fpath1 and fpath2 refer to the same file. This is only
149 guaranteed to work for files, not directories.'''
52 150 res1 = _getfileinfo(fpath1)
53 151 res2 = _getfileinfo(fpath2)
54 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
55 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
152 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
153 and res1.nFileIndexHigh == res2.nFileIndexHigh
154 and res1.nFileIndexLow == res2.nFileIndexLow)
56 155
57 156 def samedevice(fpath1, fpath2):
58 """Returns whether fpath1 and fpath2 are on the same device. This is only
59 guaranteed to work for files, not directories."""
157 '''Returns whether fpath1 and fpath2 are on the same device. This is only
158 guaranteed to work for files, not directories.'''
60 159 res1 = _getfileinfo(fpath1)
61 160 res2 = _getfileinfo(fpath2)
62 return res1[4] == res2[4]
161 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
63 162
64 163 def testpid(pid):
65 164 '''return True if pid is still running or unable to
66 165 determine, False otherwise'''
67 try:
68 handle = win32api.OpenProcess(
69 win32con.PROCESS_QUERY_INFORMATION, False, pid)
70 if handle:
71 status = win32process.GetExitCodeProcess(handle)
72 return status == win32con.STILL_ACTIVE
73 except pywintypes.error, details:
74 return details[0] != winerror.ERROR_INVALID_PARAMETER
75 return True
166 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
167 if h:
168 try:
169 status = _DWORD()
170 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
171 return status.value == _STILL_ACTIVE
172 finally:
173 _kernel32.CloseHandle(h)
174 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
76 175
77 176 def lookup_reg(key, valname=None, scope=None):
78 177 ''' Look up a key/value name in the Windows registry.
@@ -83,101 +182,169 b' def lookup_reg(key, valname=None, scope='
83 182 a sequence of scopes to look up in order. Default (CURRENT_USER,
84 183 LOCAL_MACHINE).
85 184 '''
86 try:
87 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
88 QueryValueEx, OpenKey
89 except ImportError:
90 return None
91
185 adv = ctypes.windll.advapi32
186 byref = ctypes.byref
92 187 if scope is None:
93 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
188 scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
94 189 elif not isinstance(scope, (list, tuple)):
95 190 scope = (scope,)
96 191 for s in scope:
192 kh = _HANDLE()
193 res = adv.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
194 if res != _ERROR_SUCCESS:
195 continue
97 196 try:
98 val = QueryValueEx(OpenKey(s, key), valname)[0]
99 # never let a Unicode string escape into the wild
100 return encoding.tolocal(val.encode('UTF-8'))
101 except EnvironmentError:
102 pass
197 size = _DWORD(600)
198 type = _DWORD()
199 buf = ctypes.create_string_buffer(size.value + 1)
200 res = adv.RegQueryValueExA(kh.value, valname, None,
201 byref(type), buf, byref(size))
202 if res != _ERROR_SUCCESS:
203 continue
204 if type.value == _REG_SZ:
205 # never let a Unicode string escape into the wild
206 return encoding.tolocal(buf.value.encode('UTF-8'))
207 elif type.value == _REG_DWORD:
208 fmt = '<L'
209 s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
210 return struct.unpack(fmt, s)[0]
211 finally:
212 adv.RegCloseKey(kh.value)
103 213
104 214 def system_rcpath_win32():
105 215 '''return default os-specific hgrc search path'''
106 filename = win32api.GetModuleFileName(0)
216 rcpath = []
217 size = 600
218 buf = ctypes.create_string_buffer(size + 1)
219 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
220 if len == 0:
221 raise ctypes.WinError()
222 elif len == size:
223 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
224 filename = buf.value
107 225 # Use mercurial.ini found in directory with hg.exe
108 226 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
109 227 if os.path.isfile(progrc):
110 return [progrc]
228 rcpath.append(progrc)
229 return rcpath
111 230 # Use hgrc.d found in directory with hg.exe
112 231 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
113 232 if os.path.isdir(progrcd):
114 rcpath = []
115 233 for f, kind in osutil.listdir(progrcd):
116 234 if f.endswith('.rc'):
117 235 rcpath.append(os.path.join(progrcd, f))
118 236 return rcpath
119 237 # else look for a system rcpath in the registry
120 try:
121 value = win32api.RegQueryValue(
122 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
123 rcpath = []
124 for p in value.split(os.pathsep):
125 if p.lower().endswith('mercurial.ini'):
126 rcpath.append(p)
127 elif os.path.isdir(p):
128 for f, kind in osutil.listdir(p):
129 if f.endswith('.rc'):
130 rcpath.append(os.path.join(p, f))
238 value = lookup_reg('SOFTWARE\\Mercurial', None, _HKEY_LOCAL_MACHINE)
239 if not isinstance(value, str) or not value:
131 240 return rcpath
132 except pywintypes.error:
133 return []
241 value = value.replace('/', os.sep)
242 for p in value.split(os.pathsep):
243 if p.lower().endswith('mercurial.ini'):
244 rcpath.append(p)
245 elif os.path.isdir(p):
246 for f, kind in osutil.listdir(p):
247 if f.endswith('.rc'):
248 rcpath.append(os.path.join(p, f))
249 return rcpath
134 250
135 251 def user_rcpath_win32():
136 252 '''return os-specific hgrc search path to the user dir'''
137 253 userdir = os.path.expanduser('~')
138 if sys.getwindowsversion()[3] != 2 and userdir == '~':
139 # We are on win < nt: fetch the APPDATA directory location and use
140 # the parent directory as the user home dir.
141 appdir = shell.SHGetPathFromIDList(
142 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
143 userdir = os.path.dirname(appdir)
144 254 return [os.path.join(userdir, 'mercurial.ini'),
145 255 os.path.join(userdir, '.hgrc')]
146 256
147 257 def getuser():
148 258 '''return name of current user'''
149 return win32api.GetUserName()
259 adv = ctypes.windll.advapi32
260 size = _DWORD(300)
261 buf = ctypes.create_string_buffer(size.value + 1)
262 if not adv.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
263 raise ctypes.WinError()
264 return buf.value
150 265
151 def set_signal_handler_win32():
152 """Register a termination handler for console events including
266 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
267 _signal_handler = []
268
269 def set_signal_handler():
270 '''Register a termination handler for console events including
153 271 CTRL+C. python signal handlers do not work well with socket
154 272 operations.
155 """
273 '''
156 274 def handler(event):
157 win32process.ExitProcess(1)
158 win32api.SetConsoleCtrlHandler(handler)
275 _kernel32.ExitProcess(1)
276
277 if _signal_handler:
278 return # already registered
279 h = _SIGNAL_HANDLER(handler)
280 _signal_handler.append(h) # needed to prevent garbage collection
281 if not _kernel32.SetConsoleCtrlHandler(h, True):
282 raise ctypes.WinError()
283
284 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
159 285
160 286 def hidewindow():
161 def callback(*args, **kwargs):
162 hwnd, pid = args
163 wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
164 if pid == wpid:
165 win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
287 user32 = ctypes.windll.user32
166 288
167 pid = win32process.GetCurrentProcessId()
168 win32gui.EnumWindows(callback, pid)
289 def callback(hwnd, pid):
290 wpid = _DWORD()
291 user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
292 if pid == wpid.value:
293 user32.ShowWindow(hwnd, _SW_HIDE)
294 return False # stop enumerating windows
295 return True
296
297 pid = _kernel32.GetCurrentProcessId()
298 user32.EnumWindows(_WNDENUMPROC(callback), pid)
169 299
170 300 def termwidth():
171 try:
172 # Query stderr to avoid problems with redirections
173 screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
174 if screenbuf is None:
175 return 79
176 try:
177 window = screenbuf.GetConsoleScreenBufferInfo()['Window']
178 width = window.Right - window.Left
179 return width
180 finally:
181 screenbuf.Detach()
182 except pywintypes.error:
183 return 79
301 # cmd.exe does not handle CR like a unix console, the CR is
302 # counted in the line length. On 80 columns consoles, if 80
303 # characters are written, the following CR won't apply on the
304 # current line but on the new one. Keep room for it.
305 width = 79
306 # Query stderr to avoid problems with redirections
307 screenbuf = _kernel32.GetStdHandle(
308 _STD_ERROR_HANDLE) # don't close the handle returned
309 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
310 return width
311 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
312 if not _kernel32.GetConsoleScreenBufferInfo(
313 screenbuf, ctypes.byref(csbi)):
314 return width
315 width = csbi.srWindow.Right - csbi.srWindow.Left
316 return width
317
318 def spawndetached(args):
319 # No standard library function really spawns a fully detached
320 # process under win32 because they allocate pipes or other objects
321 # to handle standard streams communications. Passing these objects
322 # to the child process requires handle inheritance to be enabled
323 # which makes really detached processes impossible.
324 si = _STARTUPINFO()
325 si.cb = ctypes.sizeof(_STARTUPINFO)
326 si.dwFlags = _STARTF_USESHOWWINDOW
327 si.wShowWindow = _SW_HIDE
328
329 pi = _PROCESS_INFORMATION()
330
331 env = ''
332 for k in os.environ:
333 env += "%s=%s\0" % (k, os.environ[k])
334 if not env:
335 env = '\0'
336 env += '\0'
337
338 args = subprocess.list2cmdline(args)
339 # Not running the command in shell mode makes python26 hang when
340 # writing to hgweb output socket.
341 comspec = os.environ.get("COMSPEC", "cmd.exe")
342 args = comspec + " /c " + args
343
344 res = _kernel32.CreateProcessA(
345 None, args, None, None, False, _DETACHED_PROCESS,
346 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
347 if not res:
348 raise ctypes.WinError()
349
350 return pi.dwProcessId
@@ -71,7 +71,7 b' def _is_win_9x():'
71 71 return 'command' in os.environ.get('comspec', '')
72 72
73 73 def openhardlinks():
74 return not _is_win_9x() and "win32api" in globals()
74 return not _is_win_9x()
75 75
76 76 def system_rcpath():
77 77 try:
@@ -106,10 +106,6 b' def sshargs(sshcmd, host, user, port):'
106 106 args = user and ("%s@%s" % (user, host)) or host
107 107 return port and ("%s %s %s" % (args, pflag, port)) or args
108 108
109 def testpid(pid):
110 '''return False if pid dead, True if running or not known'''
111 return True
112
113 109 def set_flags(f, l, x):
114 110 pass
115 111
@@ -208,12 +204,6 b' def find_exe(command):'
208 204 return executable
209 205 return findexisting(os.path.expanduser(os.path.expandvars(command)))
210 206
211 def set_signal_handler():
212 try:
213 set_signal_handler_win32()
214 except NameError:
215 pass
216
217 207 def statfiles(files):
218 208 '''Stat each file in files and yield stat or None if file does not exist.
219 209 Cluster and cache stat per directory to minimize number of OS stat calls.'''
@@ -241,11 +231,6 b' def statfiles(files):'
241 231 cache = dircache.setdefault(dir, dmap)
242 232 yield cache.get(base, None)
243 233
244 def getuser():
245 '''return name of current user'''
246 raise error.Abort(_('user name not available - set USERNAME '
247 'environment variable'))
248
249 234 def username(uid=None):
250 235 """Return the name of the user with the given uid.
251 236
@@ -335,37 +320,6 b' def rename(src, dst):'
335 320 unlink(dst)
336 321 os.rename(src, dst)
337 322
338 def spawndetached(args):
339 # No standard library function really spawns a fully detached
340 # process under win32 because they allocate pipes or other objects
341 # to handle standard streams communications. Passing these objects
342 # to the child process requires handle inheritance to be enabled
343 # which makes really detached processes impossible.
344 class STARTUPINFO:
345 dwFlags = subprocess.STARTF_USESHOWWINDOW
346 hStdInput = None
347 hStdOutput = None
348 hStdError = None
349 wShowWindow = subprocess.SW_HIDE
350
351 args = subprocess.list2cmdline(args)
352 # Not running the command in shell mode makes python26 hang when
353 # writing to hgweb output socket.
354 comspec = os.environ.get("COMSPEC", "cmd.exe")
355 args = comspec + " /c " + args
356 hp, ht, pid, tid = subprocess.CreateProcess(
357 None, args,
358 # no special security
359 None, None,
360 # Do not inherit handles
361 0,
362 # DETACHED_PROCESS
363 0x00000008,
364 os.environ,
365 os.getcwd(),
366 STARTUPINFO())
367 return pid
368
369 323 def gethgcmd():
370 324 return [sys.executable] + sys.argv[:1]
371 325
@@ -380,10 +334,6 b' def groupmembers(name):'
380 334 # Don't support groups on Windows for now
381 335 raise KeyError()
382 336
383 try:
384 # override functions with win32 versions if possible
385 from win32 import *
386 except ImportError:
387 pass
337 from win32 import *
388 338
389 339 expandglobs = True
General Comments 0
You need to be logged in to leave comments. Login now