3
Set of functions to work with console on Windows.
4
Author: Alexander Belchenko (e-mail: bialix AT ukr.net)
1
# Copyright (C) 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Win32-specific helper functions
19
Only one dependency: ctypes should be installed.
28
if sys.platform == 'win32':
29
_major,_minor,_build,_platform,_text = sys.getwindowsversion()
32
# The operating system platform.
33
# This member can be one of the following values.
34
# ========================== ======================================
36
# -------------------------- --------------------------------------
37
# VER_PLATFORM_WIN32_NT The operating system is Windows Vista,
38
# 2 Windows Server "Longhorn",
39
# Windows Server 2003, Windows XP,
40
# Windows 2000, or Windows NT.
42
# VER_PLATFORM_WIN32_WINDOWS The operating system is Windows Me,
43
# 1 Windows 98, or Windows 95.
44
# ========================== ======================================
48
# don't care about real Windows name, just to force safe operations
54
# We can cope without it; use a separate variable to help pyflakes
61
if winver == 'Windows 98':
62
create_buffer = ctypes.create_string_buffer
65
create_buffer = ctypes.create_unicode_buffer
79
# Special Win32 API constants
80
# Handles of std streams
16
81
WIN32_STDIN_HANDLE = -10
17
82
WIN32_STDOUT_HANDLE = -11
18
83
WIN32_STDERR_HANDLE = -12
85
# CSIDL constants (from MSDN 2003)
86
CSIDL_APPDATA = 0x001A # Application Data folder
87
CSIDL_PERSONAL = 0x0005 # My Documents folder
89
# from winapi C headers
92
MAX_COMPUTERNAME_LENGTH = 31
21
95
def get_console_size(defaultx=80, defaulty=25):
22
""" Return size of current console.
24
This function try to determine actual size of current working
25
console window and return tuple (sizex, sizey) if success,
26
or default size (defaultx, defaulty) otherwise.
28
Dependencies: ctypes should be installed.
32
return (defaultx, defaulty)
34
# To avoid problem with redirecting output via pipe
35
# need to use stderr instead of stdout
36
h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
37
csbi = ctypes.create_string_buffer(22)
38
res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
41
(bufx, bufy, curx, cury, wattr,
96
"""Return size of current console.
98
This function try to determine actual size of current working
99
console window and return tuple (sizex, sizey) if success,
100
or default size (defaultx, defaulty) otherwise.
104
return (defaultx, defaulty)
106
# To avoid problem with redirecting output via pipe
107
# need to use stderr instead of stdout
108
h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
109
csbi = ctypes.create_string_buffer(22)
110
res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
113
(bufx, bufy, curx, cury, wattr,
42
114
left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
43
sizex = right - left + 1
44
sizey = bottom - top + 1
47
return (defaultx, defaulty)
115
sizex = right - left + 1
116
sizey = bottom - top + 1
117
return (sizex, sizey)
119
return (defaultx, defaulty)
122
def get_appdata_location():
123
"""Return Application Data location.
124
Return None if we cannot obtain location.
126
Returned value can be unicode or plain sring.
127
To convert plain string to unicode use
128
s.decode(bzrlib.user_encoding)
132
SHGetSpecialFolderPath = \
133
ctypes.windll.shell32.SHGetSpecialFolderPathW
134
except AttributeError:
137
buf = ctypes.create_unicode_buffer(MAX_PATH)
138
if SHGetSpecialFolderPath(None,buf,CSIDL_APPDATA,0):
141
appdata = os.environ.get('APPDATA')
144
# if we fall to this point we on win98
145
# at least try C:/WINDOWS/Application Data
146
windir = os.environ.get('windir')
148
appdata = os.path.join(windir, 'Application Data')
149
if os.path.isdir(appdata):
151
# did not find anything
155
def get_home_location():
156
"""Return user's home location.
157
Assume on win32 it's the <My Documents> folder.
158
If location cannot be obtained return system drive root,
161
Returned value can be unicode or plain sring.
162
To convert plain string to unicode use
163
s.decode(bzrlib.user_encoding)
167
SHGetSpecialFolderPath = \
168
ctypes.windll.shell32.SHGetSpecialFolderPathW
169
except AttributeError:
172
buf = ctypes.create_unicode_buffer(MAX_PATH)
173
if SHGetSpecialFolderPath(None,buf,CSIDL_PERSONAL,0):
175
# try for HOME env variable
176
home = os.path.expanduser('~')
179
# at least return windows root directory
180
windir = os.environ.get('windir')
182
return os.path.splitdrive(windir)[0] + '/'
183
# otherwise C:\ is good enough for 98% users
188
"""Return user name as login name.
189
If name cannot be obtained return None.
191
Returned value can be unicode or plain sring.
192
To convert plain string to unicode use
193
s.decode(bzrlib.user_encoding)
197
advapi32 = ctypes.windll.advapi32
198
GetUserName = getattr(advapi32, 'GetUserName'+suffix)
199
except AttributeError:
202
buf = create_buffer(UNLEN+1)
203
n = ctypes.c_int(UNLEN+1)
204
if GetUserName(buf, ctypes.byref(n)):
206
# otherwise try env variables
207
return os.environ.get('USERNAME', None)
210
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
211
# computer or the cluster associated with the local computer."
212
_WIN32_ComputerNameDnsHostname = 1
215
"""Return host machine name.
216
If name cannot be obtained return None.
218
:return: A unicode string representing the host name. On win98, this may be
219
a plain string as win32 api doesn't support unicode.
223
return win32api.GetComputerNameEx(_WIN32_ComputerNameDnsHostname)
224
except (NotImplementedError, win32api.error):
225
# NotImplemented will happen on win9x...
229
kernel32 = ctypes.windll.kernel32
230
except AttributeError:
231
pass # Missing the module we need
233
buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
234
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
236
# Try GetComputerNameEx which gives a proper Unicode hostname
237
GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
239
if (GetComputerNameEx is not None
240
and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
241
buf, ctypes.byref(n))):
244
# Try GetComputerName in case GetComputerNameEx wasn't found
245
# It returns the NETBIOS name, which isn't as good, but still ok.
246
# The first GetComputerNameEx might have changed 'n', so reset it
247
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
248
GetComputerName = getattr(kernel32, 'GetComputerName'+suffix,
250
if (GetComputerName is not None
251
and GetComputerName(buf, ctypes.byref(n))):
253
# otherwise try env variables, which will be 'mbcs' encoded
254
# on Windows (Python doesn't expose the native win32 unicode environment)
256
# http://msdn.microsoft.com/en-us/library/aa246807.aspx
257
# environment variables should always be encoded in 'mbcs'.
259
return os.environ['COMPUTERNAME'].decode("mbcs")
264
def _ensure_unicode(s):
265
if s and type(s) != unicode:
267
s = s.decode(bzrlib.user_encoding)
271
def get_appdata_location_unicode():
272
return _ensure_unicode(get_appdata_location())
274
def get_home_location_unicode():
275
return _ensure_unicode(get_home_location())
277
def get_user_name_unicode():
278
return _ensure_unicode(get_user_name())
280
def get_host_name_unicode():
281
return _ensure_unicode(get_host_name())
284
def _ensure_with_dir(path):
285
if not os.path.split(path)[0] or path.startswith(u'*') or path.startswith(u'?'):
286
return u'./' + path, True
290
def _undo_ensure_with_dir(path, corrected):
298
def glob_expand(file_list):
299
"""Replacement for glob expansion by the shell.
301
Win32's cmd.exe does not do glob expansion (eg ``*.py``), so we do our own
304
:param file_list: A list of filenames which may include shell globs.
305
:return: An expanded list of filenames.
307
Introduced in bzrlib 0.18.
312
expanded_file_list = []
313
for possible_glob in file_list:
315
# work around bugs in glob.glob()
316
# - Python bug #1001604 ("glob doesn't return unicode with ...")
317
# - failing expansion for */* with non-iso-8859-* chars
318
possible_glob, corrected = _ensure_with_dir(possible_glob)
319
glob_files = glob.glob(possible_glob)
322
# special case to let the normal code path handle
323
# files that do not exists
324
expanded_file_list.append(
325
_undo_ensure_with_dir(possible_glob, corrected))
327
glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files]
328
expanded_file_list += glob_files
330
return [elem.replace(u'\\', u'/') for elem in expanded_file_list]
333
def get_app_path(appname):
334
"""Look up in Windows registry for full path to application executable.
335
Typicaly, applications create subkey with their basename
336
in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
338
:param appname: name of application (if no filename extension
339
is specified, .exe used)
340
:return: full path to aplication executable from registry,
341
or appname itself if nothing found.
345
hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
346
r'SOFTWARE\Microsoft\Windows'
347
r'\CurrentVersion\App Paths')
348
except EnvironmentError:
352
if not os.path.splitext(basename)[1]:
353
basename = appname + '.exe'
356
fullpath = _winreg.QueryValue(hkey, basename)
360
_winreg.CloseKey(hkey)
365
def set_file_attr_hidden(path):
366
"""Set file attributes to hidden if possible"""
368
win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)