~bzr-pqm/bzr/bzr.dev

2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
#
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
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.
7
#
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.
12
#
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
16
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
17
"""Win32-specific helper functions
18
19
Only one dependency: ctypes should be installed.
20
"""
21
22
import os
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
23
import struct
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
24
import sys
25
26
27
# Windows version
28
if sys.platform == 'win32':
29
    _major,_minor,_build,_platform,_text = sys.getwindowsversion()
2245.4.11 by Alexander Belchenko
Small fixes after John's review; added NEWS entry
30
    # from MSDN:
31
    # dwPlatformId
32
    #   The operating system platform.
33
    #   This member can be one of the following values.
34
    #   ==========================  ======================================
35
    #   Value                       Meaning
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.
41
    #
42
    #   VER_PLATFORM_WIN32_WINDOWS  The operating system is Windows Me,
43
    #   1                           Windows 98, or Windows 95.
44
    #   ==========================  ======================================
45
    if _platform == 2:
46
        winver = 'Windows NT'
47
    else:
48
        # don't care about real Windows name, just to force safe operations
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
49
        winver = 'Windows 98'
50
else:
51
    winver = None
52
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
53
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
54
# We can cope without it; use a separate variable to help pyflakes
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
55
try:
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
56
    import ctypes
57
    has_ctypes = True
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
58
except ImportError:
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
59
    has_ctypes = False
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
60
else:
61
    if winver == 'Windows 98':
62
        create_buffer = ctypes.create_string_buffer
63
        suffix = 'A'
64
    else:
65
        create_buffer = ctypes.create_unicode_buffer
66
        suffix = 'W'
67
68
69
# Special Win32 API constants
70
# Handles of std streams
1704.2.3 by Martin Pool
(win32) Detect terminal width using GetConsoleScreenBufferInfo (Alexander)
71
WIN32_STDIN_HANDLE = -10
72
WIN32_STDOUT_HANDLE = -11
73
WIN32_STDERR_HANDLE = -12
74
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
75
# CSIDL constants (from MSDN 2003)
76
CSIDL_APPDATA = 0x001A      # Application Data folder
77
CSIDL_PERSONAL = 0x0005     # My Documents folder
78
79
# from winapi C headers
80
MAX_PATH = 260
81
UNLEN = 256
82
MAX_COMPUTERNAME_LENGTH = 31
83
1704.2.3 by Martin Pool
(win32) Detect terminal width using GetConsoleScreenBufferInfo (Alexander)
84
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
85
def get_console_size(defaultx=80, defaulty=25):
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
86
    """Return size of current console.
87
88
    This function try to determine actual size of current working
89
    console window and return tuple (sizex, sizey) if success,
90
    or default size (defaultx, defaulty) otherwise.
91
    """
92
    if not has_ctypes:
93
        # no ctypes is found
94
        return (defaultx, defaulty)
95
96
    # To avoid problem with redirecting output via pipe
97
    # need to use stderr instead of stdout
98
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
99
    csbi = ctypes.create_string_buffer(22)
100
    res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
101
102
    if res:
103
        (bufx, bufy, curx, cury, wattr,
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
104
        left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
105
        sizex = right - left + 1
106
        sizey = bottom - top + 1
107
        return (sizex, sizey)
108
    else:
109
        return (defaultx, defaulty)
110
111
112
def get_appdata_location():
113
    """Return Application Data location.
114
    Return None if we cannot obtain location.
115
116
    Returned value can be unicode or plain sring.
117
    To convert plain string to unicode use
118
    s.decode(bzrlib.user_encoding)
119
    """
120
    if has_ctypes:
121
        try:
122
            SHGetSpecialFolderPath = \
123
                ctypes.windll.shell32.SHGetSpecialFolderPathW
124
        except AttributeError:
125
            pass
126
        else:
127
            buf = ctypes.create_unicode_buffer(MAX_PATH)
128
            if SHGetSpecialFolderPath(None,buf,CSIDL_APPDATA,0):
129
                return buf.value
130
    # from env variable
131
    appdata = os.environ.get('APPDATA')
132
    if appdata:
133
        return appdata
134
    # if we fall to this point we on win98
135
    # at least try C:/WINDOWS/Application Data
136
    windir = os.environ.get('windir')
137
    if windir:
138
        appdata = os.path.join(windir, 'Application Data')
139
        if os.path.isdir(appdata):
140
            return appdata
141
    # did not find anything
142
    return None
143
144
145
def get_home_location():
146
    """Return user's home location.
147
    Assume on win32 it's the <My Documents> folder.
148
    If location cannot be obtained return system drive root,
149
    i.e. C:\
150
151
    Returned value can be unicode or plain sring.
152
    To convert plain string to unicode use
153
    s.decode(bzrlib.user_encoding)
154
    """
155
    if has_ctypes:
156
        try:
157
            SHGetSpecialFolderPath = \
158
                ctypes.windll.shell32.SHGetSpecialFolderPathW
159
        except AttributeError:
160
            pass
161
        else:
162
            buf = ctypes.create_unicode_buffer(MAX_PATH)
163
            if SHGetSpecialFolderPath(None,buf,CSIDL_PERSONAL,0):
164
                return buf.value
165
    # try for HOME env variable
166
    home = os.path.expanduser('~')
167
    if home != '~':
168
        return home
169
    # at least return windows root directory
170
    windir = os.environ.get('windir')
171
    if windir:
172
        return os.path.splitdrive(windir) + '/'
173
    # otherwise C:\ is good enough for 98% users
174
    return 'C:/'
175
176
177
def get_user_name():
178
    """Return user name as login name.
179
    If name cannot be obtained return None.
180
181
    Returned value can be unicode or plain sring.
182
    To convert plain string to unicode use
183
    s.decode(bzrlib.user_encoding)
184
    """
185
    if has_ctypes:
186
        try:
187
            advapi32 = ctypes.windll.advapi32
188
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
189
        except AttributeError:
190
            pass
191
        else:
192
            buf = create_buffer(UNLEN+1)
193
            n = ctypes.c_int(UNLEN+1)
194
            if GetUserName(buf, ctypes.byref(n)):
195
                return buf.value
196
    # otherwise try env variables
197
    return os.environ.get('USERNAME', None)
198
199
200
def get_host_name():
201
    """Return host machine name.
202
    If name cannot be obtained return None.
203
204
    Returned value can be unicode or plain sring.
205
    To convert plain string to unicode use
206
    s.decode(bzrlib.user_encoding)
207
    """
208
    if has_ctypes:
209
        try:
210
            kernel32 = ctypes.windll.kernel32
211
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix)
212
        except AttributeError:
213
            pass
214
        else:
215
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
216
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
217
            if GetComputerName(buf, ctypes.byref(n)):
218
                return buf.value
219
    # otherwise try env variables
220
    return os.environ.get('COMPUTERNAME', None)
221
222
223
def _ensure_unicode(s):
224
    if s and type(s) != unicode:
225
        import bzrlib
226
        s = s.decode(bzrlib.user_encoding)
227
    return s
228
    
229
230
def get_appdata_location_unicode():
231
    return _ensure_unicode(get_appdata_location())
232
233
def get_home_location_unicode():
234
    return _ensure_unicode(get_home_location())
235
236
def get_user_name_unicode():
237
    return _ensure_unicode(get_user_name())
238
239
def get_host_name_unicode():
240
    return _ensure_unicode(get_host_name())