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
 
 
74
# Special Win32 API constants
 
 
75
# Handles of std streams
 
 
76
WIN32_STDIN_HANDLE = -10
 
 
77
WIN32_STDOUT_HANDLE = -11
 
 
78
WIN32_STDERR_HANDLE = -12
 
 
80
# CSIDL constants (from MSDN 2003)
 
 
81
CSIDL_APPDATA = 0x001A      # Application Data folder
 
 
82
CSIDL_PERSONAL = 0x0005     # My Documents folder
 
 
84
# from winapi C headers
 
 
87
MAX_COMPUTERNAME_LENGTH = 31
 
 
90
def get_console_size(defaultx=80, defaulty=25):
 
 
91
    """Return size of current console.
 
 
93
    This function try to determine actual size of current working
 
 
94
    console window and return tuple (sizex, sizey) if success,
 
 
95
    or default size (defaultx, defaulty) otherwise.
 
 
99
        return (defaultx, defaulty)
 
 
101
    # To avoid problem with redirecting output via pipe
 
 
102
    # need to use stderr instead of stdout
 
 
103
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
 
 
104
    csbi = ctypes.create_string_buffer(22)
 
 
105
    res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
 
 
108
        (bufx, bufy, curx, cury, wattr,
 
 
109
        left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
 
 
110
        sizex = right - left + 1
 
 
111
        sizey = bottom - top + 1
 
 
112
        return (sizex, sizey)
 
 
114
        return (defaultx, defaulty)
 
 
117
def get_appdata_location():
 
 
118
    """Return Application Data location.
 
 
119
    Return None if we cannot obtain location.
 
 
121
    Returned value can be unicode or plain sring.
 
 
122
    To convert plain string to unicode use
 
 
123
    s.decode(osutils.get_user_encoding())
 
 
127
            SHGetSpecialFolderPath = \
 
 
128
                ctypes.windll.shell32.SHGetSpecialFolderPathW
 
 
129
        except AttributeError:
 
 
132
            buf = ctypes.create_unicode_buffer(MAX_PATH)
 
 
133
            if SHGetSpecialFolderPath(None,buf,CSIDL_APPDATA,0):
 
 
136
    appdata = os.environ.get('APPDATA')
 
 
139
    # if we fall to this point we on win98
 
 
140
    # at least try C:/WINDOWS/Application Data
 
 
141
    windir = os.environ.get('windir')
 
 
143
        appdata = os.path.join(windir, 'Application Data')
 
 
144
        if os.path.isdir(appdata):
 
 
146
    # did not find anything
 
 
150
def get_home_location():
 
 
151
    """Return user's home location.
 
 
152
    Assume on win32 it's the <My Documents> folder.
 
 
153
    If location cannot be obtained return system drive root,
 
 
156
    Returned value can be unicode or plain sring.
 
 
157
    To convert plain string to unicode use
 
 
158
    s.decode(osutils.get_user_encoding())
 
 
162
            SHGetSpecialFolderPath = \
 
 
163
                ctypes.windll.shell32.SHGetSpecialFolderPathW
 
 
164
        except AttributeError:
 
 
167
            buf = ctypes.create_unicode_buffer(MAX_PATH)
 
 
168
            if SHGetSpecialFolderPath(None,buf,CSIDL_PERSONAL,0):
 
 
170
    # try for HOME env variable
 
 
171
    home = os.path.expanduser('~')
 
 
174
    # at least return windows root directory
 
 
175
    windir = os.environ.get('windir')
 
 
177
        return os.path.splitdrive(windir)[0] + '/'
 
 
178
    # otherwise C:\ is good enough for 98% users
 
 
183
    """Return user name as login name.
 
 
184
    If name cannot be obtained return None.
 
 
186
    Returned value can be unicode or plain sring.
 
 
187
    To convert plain string to unicode use
 
 
188
    s.decode(osutils.get_user_encoding())
 
 
192
            advapi32 = ctypes.windll.advapi32
 
 
193
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
 
 
194
        except AttributeError:
 
 
197
            buf = create_buffer(UNLEN+1)
 
 
198
            n = ctypes.c_int(UNLEN+1)
 
 
199
            if GetUserName(buf, ctypes.byref(n)):
 
 
201
    # otherwise try env variables
 
 
202
    return os.environ.get('USERNAME', None)
 
 
206
    """Return host machine name.
 
 
207
    If name cannot be obtained return None.
 
 
209
    Returned value can be unicode or plain sring.
 
 
210
    To convert plain string to unicode use
 
 
211
    s.decode(osutils.get_user_encoding())
 
 
215
            kernel32 = ctypes.windll.kernel32
 
 
216
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix)
 
 
217
        except AttributeError:
 
 
220
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
 
 
221
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
 
 
222
            if GetComputerName(buf, ctypes.byref(n)):
 
 
224
    # otherwise try env variables
 
 
225
    return os.environ.get('COMPUTERNAME', None)
 
 
228
def _ensure_unicode(s):
 
 
229
    if s and type(s) != unicode:
 
 
230
        s = s.decode(osutils.get_user_encoding())
 
 
234
def get_appdata_location_unicode():
 
 
235
    return _ensure_unicode(get_appdata_location())
 
 
237
def get_home_location_unicode():
 
 
238
    return _ensure_unicode(get_home_location())
 
 
240
def get_user_name_unicode():
 
 
241
    return _ensure_unicode(get_user_name())
 
 
243
def get_host_name_unicode():
 
 
244
    return _ensure_unicode(get_host_name())
 
 
247
def _ensure_with_dir(path):
 
 
248
    if not os.path.split(path)[0] or path.startswith(u'*') or path.startswith(u'?'):
 
 
249
        return u'./' + path, True
 
 
253
def _undo_ensure_with_dir(path, corrected):
 
 
261
def glob_expand(file_list):
 
 
262
    """Replacement for glob expansion by the shell.
 
 
264
    Win32's cmd.exe does not do glob expansion (eg ``*.py``), so we do our own
 
 
267
    :param file_list: A list of filenames which may include shell globs.
 
 
268
    :return: An expanded list of filenames.
 
 
270
    Introduced in bzrlib 0.18.
 
 
275
    expanded_file_list = []
 
 
276
    for possible_glob in file_list:
 
 
278
        # work around bugs in glob.glob()
 
 
279
        # - Python bug #1001604 ("glob doesn't return unicode with ...")
 
 
280
        # - failing expansion for */* with non-iso-8859-* chars
 
 
281
        possible_glob, corrected = _ensure_with_dir(possible_glob)
 
 
282
        glob_files = glob.glob(possible_glob)
 
 
285
            # special case to let the normal code path handle
 
 
286
            # files that do not exists
 
 
287
            expanded_file_list.append(
 
 
288
                _undo_ensure_with_dir(possible_glob, corrected))
 
 
290
            glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files]
 
 
291
            expanded_file_list += glob_files
 
 
293
    return [elem.replace(u'\\', u'/') for elem in expanded_file_list] 
 
 
296
def get_app_path(appname):
 
 
297
    """Look up in Windows registry for full path to application executable.
 
 
298
    Typicaly, applications create subkey with their basename
 
 
299
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
 
 
301
    :param  appname:    name of application (if no filename extension
 
 
302
                        is specified, .exe used)
 
 
303
    :return:    full path to aplication executable from registry,
 
 
304
                or appname itself if nothing found.
 
 
308
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
 
 
309
                               r'SOFTWARE\Microsoft\Windows'
 
 
310
                               r'\CurrentVersion\App Paths')
 
 
311
    except EnvironmentError:
 
 
315
    if not os.path.splitext(basename)[1]:
 
 
316
        basename = appname + '.exe'
 
 
319
            fullpath = _winreg.QueryValue(hkey, basename)
 
 
323
        _winreg.CloseKey(hkey)
 
 
328
def set_file_attr_hidden(path):
 
 
329
    """Set file attributes to hidden if possible"""
 
 
331
        win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)