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
 
 
81
WIN32_STDIN_HANDLE = -10
 
 
82
WIN32_STDOUT_HANDLE = -11
 
 
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
 
 
95
def get_console_size(defaultx=80, defaulty=25):
 
 
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,
 
 
114
        left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
 
 
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)