123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- # -*- test-case-name: twisted.python.test.test_win32 -*-
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- """
- Win32 utilities.
- See also twisted.python.shortcut.
- @var O_BINARY: the 'binary' mode flag on Windows, or 0 on other platforms, so it
- may safely be OR'ed into a mask for os.open.
- """
- from __future__ import division, absolute_import
- import re
- import os
- try:
- import win32api
- import win32con
- except ImportError:
- pass
- from twisted.python.deprecate import deprecated
- from twisted.python.runtime import platform
- from incremental import Version
- # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp
- ERROR_FILE_NOT_FOUND = 2
- ERROR_PATH_NOT_FOUND = 3
- ERROR_INVALID_NAME = 123
- ERROR_DIRECTORY = 267
- O_BINARY = getattr(os, "O_BINARY", 0)
- class FakeWindowsError(OSError):
- """
- Stand-in for sometimes-builtin exception on platforms for which it
- is missing.
- """
- try:
- WindowsError = WindowsError
- except NameError:
- WindowsError = FakeWindowsError
- @deprecated(Version("Twisted", 15, 3, 0))
- def getProgramsMenuPath():
- """
- Get the path to the Programs menu.
- Probably will break on non-US Windows.
- @return: the filesystem location of the common Start Menu->Programs.
- @rtype: L{str}
- """
- if not platform.isWindows():
- return "C:\\Windows\\Start Menu\\Programs"
- keyname = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders'
- hShellFolders = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE,
- keyname, 0, win32con.KEY_READ)
- return win32api.RegQueryValueEx(hShellFolders, 'Common Programs')[0]
- @deprecated(Version("Twisted", 15, 3, 0))
- def getProgramFilesPath():
- """Get the path to the Program Files folder."""
- keyname = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
- currentV = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE,
- keyname, 0, win32con.KEY_READ)
- return win32api.RegQueryValueEx(currentV, 'ProgramFilesDir')[0]
- _cmdLineQuoteRe = re.compile(r'(\\*)"')
- _cmdLineQuoteRe2 = re.compile(r'(\\+)\Z')
- def cmdLineQuote(s):
- """
- Internal method for quoting a single command-line argument.
- @param s: an unquoted string that you want to quote so that something that
- does cmd.exe-style unquoting will interpret it as a single argument,
- even if it contains spaces.
- @type s: C{str}
- @return: a quoted string.
- @rtype: C{str}
- """
- quote = ((" " in s) or ("\t" in s) or ('"' in s) or s == '') and '"' or ''
- return quote + _cmdLineQuoteRe2.sub(r"\1\1", _cmdLineQuoteRe.sub(r'\1\1\\"', s)) + quote
- def quoteArguments(arguments):
- """
- Quote an iterable of command-line arguments for passing to CreateProcess or
- a similar API. This allows the list passed to C{reactor.spawnProcess} to
- match the child process's C{sys.argv} properly.
- @param arglist: an iterable of C{str}, each unquoted.
- @return: a single string, with the given sequence quoted as necessary.
- """
- return ' '.join([cmdLineQuote(a) for a in arguments])
- class _ErrorFormatter(object):
- """
- Formatter for Windows error messages.
- @ivar winError: A callable which takes one integer error number argument
- and returns an L{exceptions.WindowsError} instance for that error (like
- L{ctypes.WinError}).
- @ivar formatMessage: A callable which takes one integer error number
- argument and returns a C{str} giving the message for that error (like
- L{win32api.FormatMessage}).
- @ivar errorTab: A mapping from integer error numbers to C{str} messages
- which correspond to those erorrs (like I{socket.errorTab}).
- """
- def __init__(self, WinError, FormatMessage, errorTab):
- self.winError = WinError
- self.formatMessage = FormatMessage
- self.errorTab = errorTab
- def fromEnvironment(cls):
- """
- Get as many of the platform-specific error translation objects as
- possible and return an instance of C{cls} created with them.
- """
- try:
- from ctypes import WinError
- except ImportError:
- WinError = None
- try:
- from win32api import FormatMessage
- except ImportError:
- FormatMessage = None
- try:
- from socket import errorTab
- except ImportError:
- errorTab = None
- return cls(WinError, FormatMessage, errorTab)
- fromEnvironment = classmethod(fromEnvironment)
- def formatError(self, errorcode):
- """
- Returns the string associated with a Windows error message, such as the
- ones found in socket.error.
- Attempts direct lookup against the win32 API via ctypes and then
- pywin32 if available), then in the error table in the socket module,
- then finally defaulting to C{os.strerror}.
- @param errorcode: the Windows error code
- @type errorcode: C{int}
- @return: The error message string
- @rtype: C{str}
- """
- if self.winError is not None:
- return self.winError(errorcode).strerror
- if self.formatMessage is not None:
- return self.formatMessage(errorcode)
- if self.errorTab is not None:
- result = self.errorTab.get(errorcode)
- if result is not None:
- return result
- return os.strerror(errorcode)
- formatError = _ErrorFormatter.fromEnvironment().formatError
|