~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
#
3
# Author: Alexander Belchenko
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
19
"""Win32-specific helper functions
20
21
Only one dependency: ctypes should be installed.
22
"""
23
24
import os
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
25
import struct
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
26
import sys
27
28
29
# Windows version
30
if sys.platform == 'win32':
31
    _major,_minor,_build,_platform,_text = sys.getwindowsversion()
32
    if _platform == 0:
33
        raise Exception('This platform does not supported!')
34
    elif _platform == 1:
35
        winver = 'Windows 98'
36
    else:
37
        winver = 'Windows NT'
38
else:
39
    winver = None
40
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
41
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
42
# 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
43
try:
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
44
    import ctypes
45
    has_ctypes = True
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
46
except ImportError:
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
47
    has_ctypes = False
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
48
else:
49
    if winver == 'Windows 98':
50
        create_buffer = ctypes.create_string_buffer
51
        suffix = 'A'
52
    else:
53
        create_buffer = ctypes.create_unicode_buffer
54
        suffix = 'W'
55
56
57
# Special Win32 API constants
58
# Handles of std streams
1704.2.3 by Martin Pool
(win32) Detect terminal width using GetConsoleScreenBufferInfo (Alexander)
59
WIN32_STDIN_HANDLE = -10
60
WIN32_STDOUT_HANDLE = -11
61
WIN32_STDERR_HANDLE = -12
62
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
63
# CSIDL constants (from MSDN 2003)
64
CSIDL_APPDATA = 0x001A      # Application Data folder
65
CSIDL_PERSONAL = 0x0005     # My Documents folder
66
67
# from winapi C headers
68
MAX_PATH = 260
69
UNLEN = 256
70
MAX_COMPUTERNAME_LENGTH = 31
71
1704.2.3 by Martin Pool
(win32) Detect terminal width using GetConsoleScreenBufferInfo (Alexander)
72
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
73
def get_console_size(defaultx=80, defaulty=25):
2245.4.1 by Alexander Belchenko
win32utils: Windows-specific functions that use Win32 API via ctypes
74
    """Return size of current console.
75
76
    This function try to determine actual size of current working
77
    console window and return tuple (sizex, sizey) if success,
78
    or default size (defaultx, defaulty) otherwise.
79
    """
80
    if not has_ctypes:
81
        # no ctypes is found
82
        return (defaultx, defaulty)
83
84
    # To avoid problem with redirecting output via pipe
85
    # need to use stderr instead of stdout
86
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
87
    csbi = ctypes.create_string_buffer(22)
88
    res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
89
90
    if res:
91
        (bufx, bufy, curx, cury, wattr,
1185.16.86 by mbp at sourcefrog
- win32 get_console_size from Alexander
92
        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
93
        sizex = right - left + 1
94
        sizey = bottom - top + 1
95
        return (sizex, sizey)
96
    else:
97
        return (defaultx, defaulty)
98
99
100
def get_appdata_location():
101
    """Return Application Data location.
102
    Return None if we cannot obtain location.
103
104
    Returned value can be unicode or plain sring.
105
    To convert plain string to unicode use
106
    s.decode(bzrlib.user_encoding)
107
    """
108
    if has_ctypes:
109
        try:
110
            SHGetSpecialFolderPath = \
111
                ctypes.windll.shell32.SHGetSpecialFolderPathW
112
        except AttributeError:
113
            pass
114
        else:
115
            buf = ctypes.create_unicode_buffer(MAX_PATH)
116
            if SHGetSpecialFolderPath(None,buf,CSIDL_APPDATA,0):
117
                return buf.value
118
    # from env variable
119
    appdata = os.environ.get('APPDATA')
120
    if appdata:
121
        return appdata
122
    # if we fall to this point we on win98
123
    # at least try C:/WINDOWS/Application Data
124
    windir = os.environ.get('windir')
125
    if windir:
126
        appdata = os.path.join(windir, 'Application Data')
127
        if os.path.isdir(appdata):
128
            return appdata
129
    # did not find anything
130
    return None
131
132
133
def get_home_location():
134
    """Return user's home location.
135
    Assume on win32 it's the <My Documents> folder.
136
    If location cannot be obtained return system drive root,
137
    i.e. C:\
138
139
    Returned value can be unicode or plain sring.
140
    To convert plain string to unicode use
141
    s.decode(bzrlib.user_encoding)
142
    """
143
    if has_ctypes:
144
        try:
145
            SHGetSpecialFolderPath = \
146
                ctypes.windll.shell32.SHGetSpecialFolderPathW
147
        except AttributeError:
148
            pass
149
        else:
150
            buf = ctypes.create_unicode_buffer(MAX_PATH)
151
            if SHGetSpecialFolderPath(None,buf,CSIDL_PERSONAL,0):
152
                return buf.value
153
    # try for HOME env variable
154
    home = os.path.expanduser('~')
155
    if home != '~':
156
        return home
157
    # at least return windows root directory
158
    windir = os.environ.get('windir')
159
    if windir:
160
        return os.path.splitdrive(windir) + '/'
161
    # otherwise C:\ is good enough for 98% users
162
    return 'C:/'
163
164
165
def get_user_name():
166
    """Return user name as login name.
167
    If name cannot be obtained return None.
168
169
    Returned value can be unicode or plain sring.
170
    To convert plain string to unicode use
171
    s.decode(bzrlib.user_encoding)
172
    """
173
    if has_ctypes:
174
        try:
175
            advapi32 = ctypes.windll.advapi32
176
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
177
        except AttributeError:
178
            pass
179
        else:
180
            buf = create_buffer(UNLEN+1)
181
            n = ctypes.c_int(UNLEN+1)
182
            if GetUserName(buf, ctypes.byref(n)):
183
                return buf.value
184
    # otherwise try env variables
185
    return os.environ.get('USERNAME', None)
186
187
188
def get_host_name():
189
    """Return host machine name.
190
    If name cannot be obtained return None.
191
192
    Returned value can be unicode or plain sring.
193
    To convert plain string to unicode use
194
    s.decode(bzrlib.user_encoding)
195
    """
196
    if has_ctypes:
197
        try:
198
            kernel32 = ctypes.windll.kernel32
199
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix)
200
        except AttributeError:
201
            pass
202
        else:
203
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
204
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
205
            if GetComputerName(buf, ctypes.byref(n)):
206
                return buf.value
207
    # otherwise try env variables
208
    return os.environ.get('COMPUTERNAME', None)
209
210
211
def _ensure_unicode(s):
212
    if s and type(s) != unicode:
213
        import bzrlib
214
        s = s.decode(bzrlib.user_encoding)
215
    return s
216
    
217
218
def get_appdata_location_unicode():
219
    return _ensure_unicode(get_appdata_location())
220
221
def get_home_location_unicode():
222
    return _ensure_unicode(get_home_location())
223
224
def get_user_name_unicode():
225
    return _ensure_unicode(get_user_name())
226
227
def get_host_name_unicode():
228
    return _ensure_unicode(get_host_name())