def windows_getenv(name): # Based on <http://stackoverflow.com/questions/2608200/problems-with-umlauts-in-python-appdata-environvent-variable/2608368#2608368>, # with improved error handling. Returns None if there is no enivronment variable of the given name. if not isinstance(name, unicode): raise AssertionError("name must be Unicode") n = GetEnvironmentVariableW(name, None, 0) # GetEnvironmentVariableW returns DWORD, so n cannot be negative. if n == 0: err = get_last_error() if err == ERROR_ENVVAR_NOT_FOUND: return None raise OSError("WinError: %s\n attempting to read size of environment variable %r" % (WinError(err), name)) if n == 1: # Avoid an ambiguity between a zero-length string and an error in the return value of the # call to GetEnvironmentVariableW below. return u"" buf = create_unicode_buffer(u'\0'*n) retval = GetEnvironmentVariableW(name, buf, n) if retval == 0: err = get_last_error() if err == ERROR_ENVVAR_NOT_FOUND: return None raise OSError("WinError: %s\n attempting to read environment variable %r" % (WinError(err), name)) if retval >= n: raise OSError("Unexpected result %d (expected less than %d) from GetEnvironmentVariableW attempting to read environment variable %r" % (retval, n, name)) return buf.value
def memory_read(pid, address, size): """ read process memory :param int pid: process id for investigating :param int address: start memory address :param int size: block size to read :rtype: None :return: None """ read_buffer = create_string_buffer(size) # c_char_p("data to read") buffer_size = c_ulong(size) bytes_read = c_ulong(0) process_handle = OpenProcess(PROCESS_ALL_ACCESS, False, pid) if not process_handle: print("Process can not be opened: %d" % get_last_error()) return state = ReadProcessMemory(process_handle, address, read_buffer, buffer_size, byref(bytes_read)) if state: # print("state: %d" % state) # print("something found: %s" % read_buffer.raw) print("bytes read: %d" % buffer_size.value) if bytes_read.value == size and len(read_buffer.raw) == size: data = struct.unpack('I' * (size / 4), read_buffer.raw) print(" ".join(['0x%08x' % x for x in data])) else: pass else: print("fail, get last error: %d, state: %d" % ( get_last_error(), (state or 0))) CloseHandle(process_handle)
def _get_heap_size(self): class PROCESS_HEAP_ENTRY_BLOCK(ctypes.Structure): _fields_ = [("hMem", wintypes.HANDLE), ("dwReserved", wintypes.DWORD * 3)] class PROCESS_HEAP_ENTRY_REGION(ctypes.Structure): _fields_ = [("dwCommittedSize", wintypes.DWORD), ("dwUnCommittedSize", wintypes.DWORD), ("lpFirstBlock", wintypes.LPVOID), ("lpLastBlock", wintypes.LPVOID)] class PROCESS_HEAP_ENTRY_UNION(ctypes.Union): _fields_ = [("Block", PROCESS_HEAP_ENTRY_BLOCK), ("Region", PROCESS_HEAP_ENTRY_REGION)] class PROCESS_HEAP_ENTRY (ctypes.Structure): _anonymous_ = ("u",) _fields_ = [("lpData", wintypes.LPVOID), ("cbData", wintypes.DWORD), ("cbOverhead", wintypes.BYTE), ("iRegionIndex", wintypes.BYTE), ("wFlags", wintypes.WORD), ("u", PROCESS_HEAP_ENTRY_UNION)] kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) GetProcessHeaps = kernel32.GetProcessHeaps GetProcessHeaps.restype = wintypes.DWORD GetProcessHeaps.argtypes = [wintypes.DWORD, ctypes.POINTER(wintypes.HANDLE)] HeapWalk = kernel32.HeapWalk HeapWalk.restype = wintypes.BOOL HeapWalk.argtypes = [ wintypes.HANDLE, ctypes.POINTER(PROCESS_HEAP_ENTRY)] heapCount = GetProcessHeaps(0, None) if not heapCount: log.error( "Failed to get heap count: %r", ctypes.get_last_error()) return None # Failed; don't care heaps = (wintypes.HANDLE * heapCount)() heapCount = GetProcessHeaps(len(heaps), heaps) if heapCount == 0: log.error("Failed to get heaps: %r", ctypes.get_last_error()) total_data = 0 total_overhead = 0 for heap in heaps[:heapCount]: entry = PROCESS_HEAP_ENTRY() entry.lpData = None while HeapWalk(heap, entry): total_data += entry.cbData total_overhead += entry.cbOverhead return total_data + total_overhead
def write_unicode_text(self, text, ignore_errors=False): ' Windows only method that writes unicode strings correctly to the windows console using the Win32 API ' if self.is_console: from ctypes import wintypes, byref, c_wchar_p written = wintypes.DWORD(0) chunk = len(text) while text: t, text = text[:chunk], text[chunk:] wt = c_wchar_p(t) if not self.write_console(self.file_handle, wt, self.wcslen(wt), byref(written), None): # Older versions of windows can fail to write large strings # to console with WriteConsoleW (seen it happen on Win XP) import ctypes, winerror err = ctypes.get_last_error() if err == winerror.ERROR_NOT_ENOUGH_MEMORY and chunk >= 128: # Retry with a smaller chunk size (give up if chunk < 128) chunk = chunk // 2 text = t + text continue if err == winerror.ERROR_GEN_FAILURE: # On newer windows, this happens when trying to write # non-ascii chars to the console and the console is set # to use raster fonts (the default). In this case # rather than failing, write an informative error # message and the asciized version of the text. print ('Non-ASCII text detected. You must set your Console\'s font to' ' Lucida Console or Consolas or some other TrueType font to see this text', file=self.stream, end=' -- ') from calibre.utils.filenames import ascii_text print (ascii_text(t + text), file=self.stream, end='') continue if not ignore_errors: raise ctypes.WinError(err)
def __init__(self, storename): self._storename = storename self._hStore = CertOpenSystemStore(None, self.storename) if not self._hStore: # NULL ptr self._hStore = None errmsg = FormatError(get_last_error()) raise OSError(errmsg)
def set_process_limits(): if sys.platform.startswith("win"): """Pre-allocate (but don't commit) a 1GB chunk of memory to prevent it from actually being used by codeintel; this acts as a limit on the amount of memory we can actually use. It has no effects on performance (since we're only eating address space, not RAM/swap) but helps to prevent codeintel from blowing up the system. """ from ctypes import wintypes kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) VirtualAlloc = kernel32.VirtualAlloc VirtualAlloc.argtypes = [ wintypes.LPVOID, wintypes.ULONG, wintypes.DWORD, wintypes.DWORD] VirtualAlloc.restype = wintypes.LPVOID MEM_RESERVE = 0x00002000 MEM_TOP_DOWN = 0x00100000 PAGE_NOACCESS = 0x01 # we can only eat about 1GB; trying for 2GB causes the allocation to # (harmlessly) fail, which doesn't accomplish our goals waste = VirtualAlloc( None, 1 << 30, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) if waste: log.debug("Successfullly allocated: %r", waste) else: log.debug("Failed to reduce address space: %s", ctypes.WinError(ctypes.get_last_error()).strerror)
def errcheck(result, func, args): is_unknown_restype = (success_predicate is DEFAULT_WIN32_SUCCESS and result_type != ctypes.wintypes.BOOL) if (not is_unknown_restype and not success_predicate(result, func, args)): raise WinError(get_last_error()) return args
def get_all_dev_instanceID(ClassGuid, Enumerator, Flags): devinfo = GetClassDevs(ClassGuid, Enumerator, 0, Flags) if devinfo == INVALID_HANDLE_VALUE: raise RuntimeError, format_err() m=0 dinfo = SP_DEVINFO_DATA() dinfo.cbSize = sizeof(SP_DEVINFO_DATA) bufsize = DWORD() res = [] while True: if not EnumDeviceInfo(devinfo, m, dinfo): err = get_last_error() if err != ERROR_NO_MORE_ITEMS: DestroyDeviceInfoList(devinfo) raise RuntimeError, 'EnumDeviceInfo '+format_err(err) break # Find required bufsize GetDeviceInstanceId(devinfo, dinfo, None, 0, bufsize) buf = create_string_buffer(bufsize.value) if not GetDeviceInstanceId(devinfo, dinfo, buf, bufsize, None): DestroyDeviceInfoList(devinfo) raise RuntimeError, 'GetDeviceInstanceId '+format_err() res.append(buf.value) #print "m:%i instanceID:%r"%(m, buf.value) m += 1 DestroyDeviceInfoList(devinfo) return res
def _broadcast(self): HWND_BROADCAST = 0xFFFF WM_SETTINGCHANGE = 0x001A SMTO_ABORTIFHUNG = 0x0002 # result = ctypes.c_long() SendMessageTimeout = ctypes.windll.user32.SendMessageTimeoutW SendMessageTimeout.argtypes = ( HWND, UINT, WPARAM, ctypes.c_wchar_p, UINT, UINT, UINT ) SendMessageTimeout.restype = LPARAM # SendMessageTimeoutProto = WINFUNCTYPE( # POINTER(LONG), # HWND, # UINT, # WPARAM, # LPARAM, # UINT, # UINT, # POINTER(POINTER(DWORD)) # ) # SendMessageTimeout = SendMessageTimeoutProto( # ("SendMessageTimeoutW", windll.user32) # ) if not SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 'Environment', SMTO_ABORTIFHUNG, 5000, 0): err = ctypes.get_last_error() raise ctypes.WinError(err)
def _create(self, name=None): """Create a new pipe as a server, with the given name""" self._has_stream = False flags = (PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED) mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE # Windows XP, version (5, 1) doesn't support PIPE_REJECT_REMOTE_CLIENTS # see bug 104569. if sys.getwindowsversion() >= (5, 2): mode |= PIPE_REJECT_REMOTE_CLIENTS pipe_prefix = "\\\\.\\pipe\\" if name is not None: if not name.lower().startswith(pipe_prefix): name = pipe_prefix + name log.debug("Creating new named pipe %s", name) self._pipe = CreateNamedPipe(name, flags, mode, 1, 0x1000, 0x1000, 0, None) if self._pipe == INVALID_HANDLE_VALUE: self._pipe = None raise ctypes.WinError(ctypes.get_last_error()) else: bits = min((256, (255 - len(pipe_prefix)) * 4)) start = random.getrandbits(bits) log.debug("Trying to create pipe with randomness %s", hex(start)) # Try a few variations on the name in case it's somehow taken for i in xrange(1024): name = (pipe_prefix + (self.pipe_prefix or "") + hex(start + i)[2:-1]) assert len(name) <= 256 # Unfortuantely, it is more reliable to create a nowait pipe # and poll for it than it is to create a blocking pipe. self._pipe = CreateNamedPipe(name, flags, mode, 1, 0x1000, 0x1000, 0, None) if self._pipe != INVALID_HANDLE_VALUE: break self._pipe = None errno = ctypes.get_last_error() if errno != ERROR_ACCESS_DENIED: # we get access denied on a name collision raise ctypes.WinError(errno) else: raise ctypes.WinError(ctypes.get_last_error()) self.name = name
def _ensure_stream(self, action="open"): if self._pipe is None: raise IOError("Cannot %s closed pipe" % (action,)) if self._has_stream: return overlapped = OVERLAPPED() try: if not ConnectNamedPipe(self._pipe, overlapped): errno = ctypes.get_last_error() if errno != ERROR_IO_PENDING: raise ctypes.WinError(errno) if not GetOverlappedResult(self._pipe, overlapped, ctypes.byref(DWORD(0)), True): raise ctypes.WinError(ctypes.get_last_error()) self._has_stream = True finally: CloseHandle(overlapped.hEvent)
def errcheck_bool(result, func, args): if not result: last_error = ctypes.get_last_error() if last_error != 0: raise ctypes.WinError(last_error) else: raise OSError return args
def cp_get_errno(): if os.name == 'nt': return get_last_error() elif os.name == 'posix': return get_errno() #elif os.name == 'mac': TODO else: raise NotImplementedError('OS not supported!')
def write(self, data): self._ensure_stream("write to") overlapped = OVERLAPPED() try: if not WriteFile(self._pipe, data, len(data), None, ctypes.byref(overlapped)): errno = ctypes.get_last_error() if errno != ERROR_IO_PENDING: raise ctypes.WinError(errno) written = DWORD(0) if not GetOverlappedResult(self._pipe, ctypes.byref(overlapped), ctypes.byref(written), True): raise ctypes.WinError(ctypes.get_last_error()) assert written.value == len(data), "Incomplete write" finally: CloseHandle(overlapped.hEvent)
def _check_success(result, func, args): if result == ERROR_DEVICE_NOT_CONNECTED: raise NoControllerError("Controller " + str(args[0]) + " is not connected") if result != ERROR_SUCCESS: raise ctypes.WinError(ctypes.get_last_error()) return args
def read(self, count): self._ensure_stream("read from") overlapped = OVERLAPPED() try: buf = ctypes.create_string_buffer(count) if not ReadFile(self._pipe, ctypes.byref(buf), count, None, ctypes.byref(overlapped)): errno = ctypes.get_last_error() if errno != ERROR_IO_PENDING: raise ctypes.WinError(errno) read = DWORD(0) if not GetOverlappedResult(self._pipe, ctypes.byref(overlapped), ctypes.byref(read), True): raise ctypes.WinError(ctypes.get_last_error()) assert read.value == count return str(buf.value) finally: CloseHandle(overlapped.hEvent)
def is_a_console(self): if self.handle is None: return False if GetConsoleMode(self.handle, byref(c_ulong())): return True else: last_error = get_last_error() if last_error == ERROR_INVALID_HANDLE: return False else: raise WinError(last_error)
def gsmooth(data, smooth_interval): num_vals = np.size(data) import ctypes # use the Gaussian_Kernel_Generator function from the eponymous DLL: dllfn = r'P:\P\DLLs\Gaussian_Kernel_Generator\x64\Release\Gaussian_Kernel_Generator.dll' gkg = ctypes.WinDLL(dllfn, use_last_error=True) e = ctypes.get_last_error() if e != 0: raise ctypes.WinError(e) gkg.Gaussian_Kernel_Generator.argtypes = [ctypes.c_size_t, ctypes.c_size_t, ctypes.POINTER(ctypes.c_double)] gkg.Gaussian_Kernel_Generator.restype = ctypes.c_int # set up args gen_data = (ctypes.c_double*num_vals)() # ??? arggh what does this even mean ???...--> allocate space data_size = ctypes.c_size_t(num_vals) width = ctypes.c_size_t(smooth_interval) # generate the data gkg.Gaussian_Kernel_Generator(data_size, width, gen_data) e = ctypes.get_last_error() # unload the dll loaded above: from ctypes.wintypes import HMODULE ctypes.windll.kernel32.FreeLibrary.argtypes = [HMODULE] ctypes.windll.kernel32.FreeLibrary(gkg._handle) del gkg if e != 0: raise ctypes.WinError(e) # copy the data (again...): kernel = np.empty(num_vals, dtype=np.float) for i in range(num_vals): kernel[i] = gen_data[i] return sysi.fftconvolve(kernel, data, mode='same') # Mode 'same' returns output of length max(M, N). Boundary effects are still visible.
def flush_volume(path): abspath = os.path.realpath(path) if abspath.startswith("\\\\?\\"): abspath = abspath[4 :] drive = os.path.splitdrive(abspath)[0] print("flushing %r" % (drive,)) hVolume = CreateFileW(u"\\\\.\\" + drive, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None ) if hVolume == INVALID_HANDLE_VALUE: raise WinError(get_last_error()) if FlushFileBuffers(hVolume) == 0: raise WinError(get_last_error()) CloseHandle(hVolume)
def _open_directory(path_u): hDirectory = CreateFileW(path_u, FILE_LIST_DIRECTORY, # access rights FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, # don't prevent other processes from accessing None, # no security descriptor OPEN_EXISTING, # directory must already exist FILE_FLAG_BACKUP_SEMANTICS, # necessary to open a directory None # no template file ) if hDirectory == INVALID_HANDLE_VALUE: e = WinError(get_last_error()) raise OSError("Opening directory %s gave WinError: %s" % (quote_output(path_u), e)) return hDirectory
def _create_symlink(source, link_name, dwFlags): # Note: Win32 documentation for CreateSymbolicLink is incorrect. # On success, the function returns "1". # On error, the function returns some random value (e.g. 1280). # The best bet seems to use "GetLastError" and check for error/success. CreateSymbolicLinkW(link_name, source, dwFlags) code = get_last_error() if code != ERROR_SUCCESS: error_desc = FormatError(code).strip() if code == ERROR_PRIVILEGE_NOT_HELD: raise OSError(errno.EPERM, error_desc, link_name) _raise_winerror( code, 'Error creating symbolic link \"%s\"'.format(link_name))
def readlink(path): reparse_point_handle = CreateFileW(path, 0, 0, None, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, None) if reparse_point_handle == INVALID_HANDLE_VALUE: _raise_winerror( get_last_error(), 'Error opening symblic link \"%s\"'.format(path)) target_buffer = c_buffer(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) n_bytes_returned = DWORD() io_result = DeviceIoControl(reparse_point_handle, FSCTL_GET_REPARSE_POINT, None, 0, target_buffer, len(target_buffer), byref(n_bytes_returned), None) CloseHandle(reparse_point_handle) if not io_result: _raise_winerror( get_last_error(), 'Error reading symblic link \"%s\"'.format(path)) rdb = REPARSE_DATA_BUFFER.from_buffer(target_buffer) if rdb.ReparseTag == IO_REPARSE_TAG_SYMLINK: return _preserve_encoding(path, rdb.SymbolicLinkReparseBuffer.PrintName) elif rdb.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT: return _preserve_encoding(path, rdb.MountPointReparseBuffer.PrintName) # Unsupported reparse point type _raise_winerror( ERROR_NOT_SUPPORTED, 'Error reading symblic link \"%s\"'.format(path))
def read_changes(self, hDirectory, recursive, filter): bytes_returned = DWORD(0) r = ReadDirectoryChangesW(hDirectory, self.buffer, self.size, recursive, filter, byref(bytes_returned), None, # NULL -> no overlapped I/O None # NULL -> no completion routine ) if r == 0: self.data = None raise WinError(get_last_error()) self.data = self.buffer.raw[:bytes_returned.value]
def ReadMem(address, length, outputBufferAddr, processID): processHandle = process.GetProcessHandle(processID) # Buffer to store the read bytes. if outputBufferAddr == None: outputBufferAddr = ctypes.create_string_buffer(length) numBytesRead = ctypes.c_size_t() # result = ctypes.windll.kernel32.ReadProcessMemory(processHandle.handle, address, outputBufferAddr, length, ctypes.byref(numBytesRead)) result = ctypes.windll.kernel32.ReadProcessMemory(processHandle.handle, address, outputBufferAddr, length, ctypes.byref(numBytesRead)) if result == 0: lastError = ctypes.get_last_error() raise Exception('ReadProcessMemory() returned error (%r): %r' % (result, lastError)) return outputBufferAddr
def __init__(self): self.manager_pid = os.getppid() self.kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) self.kernel32.OpenProcess.argtypes = (DWORD, BOOL, DWORD) self.kernel32.OpenProcess.restype = HANDLE self.kernel32.WaitForSingleObject.argtypes = (HANDLE, DWORD) self.kernel32.WaitForSingleObject.restype = DWORD # Value obtained from https://msdn.microsoft.com/en-us/library/ms684880.aspx SYNCHRONIZE = 0x00100000 self.manager_handle = self.kernel32.OpenProcess(SYNCHRONIZE, 0, self.manager_pid) if not self.manager_handle: raise ctypes.WinError(ctypes.get_last_error())
def write(self, b): bytes_to_be_written = len(b) buffer = get_buffer(b) code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 code_units_written = c_ulong() if code_units_to_be_written == 0 != bytes_to_be_written: raise ValueError("two-byte code units expected, just one byte given") if not WriteConsoleW(self.handle, buffer, code_units_to_be_written, byref(code_units_written), None): exc = WinError(get_last_error()) if exc.winerror == ERROR_NOT_ENOUGH_MEMORY: exc.strerror += " Try to lower `win_unicode_console.streams.MAX_BYTES_WRITTEN`." raise exc return 2 * code_units_written.value # bytes written
def replace_file(replaced_path, replacement_path, backup_path): precondition_abspath(replaced_path) precondition_abspath(replacement_path) precondition_abspath(backup_path) r = ReplaceFileW(replaced_path, replacement_path, backup_path, REPLACEFILE_IGNORE_MERGE_ERRORS, None, None) if r == 0: # The UnableToUnlinkReplacementError case does not happen on Windows; # all errors should be treated as signalling a conflict. err = get_last_error() if err != ERROR_FILE_NOT_FOUND: raise ConflictError("WinError: %s" % (WinError(err),)) try: rename_no_overwrite(replacement_path, replaced_path) except EnvironmentError: reraise(ConflictError)
def get_device_registry_property(dev_list, p_devinfo, property_type=SPDRP_HARDWAREID, buf=None): if buf is None: buf = create_string_buffer(1024) data_type = DWORD(0) required_size = DWORD(0) ans = None while True: if not SetupDiGetDeviceRegistryProperty(dev_list, p_devinfo, property_type, byref(data_type), cast(buf, POINTER(BYTE)), len(buf), byref(required_size)): err = get_last_error() if err == ERROR_INSUFFICIENT_BUFFER: buf = create_string_buffer(required_size) continue if err == ERROR_INVALID_DATA: break raise WinError(err) ans = convert_registry_data(buf, required_size.value, data_type.value) break return buf, ans
def replace_file(replaced_path, replacement_path): precondition_abspath(replaced_path) precondition_abspath(replacement_path) # no "backup" path (the first None) because we don't want to # create a backup file r = ReplaceFileW(replaced_path, replacement_path, None, REPLACEFILE_IGNORE_MERGE_ERRORS, None, None) if r == 0: # The UnableToUnlinkReplacementError case does not happen on Windows; # all errors should be treated as signalling a conflict. err = get_last_error() if err != ERROR_FILE_NOT_FOUND: raise ConflictError("WinError: %s" % (WinError(err),)) try: move_into_place(replacement_path, replaced_path) except EnvironmentError: reraise(ConflictError)
def _connect_to_existing(self, name): self._has_stream = False pipe_prefix = "\\\\.\\pipe\\" if not name.lower().startswith(pipe_prefix): name = pipe_prefix + name log.debug("Connecting to existing named pipe %s", name) self._pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, None) if self._pipe == INVALID_HANDLE_VALUE: self._pipe = None error = ctypes.WinError(ctypes.get_last_error()) log.debug("Failed to open pipe %s: %s", name, error) raise error self._has_stream = True
def get_image(self, x=0, y=0, width=0, height=0): start = time.time() metrics = get_virtualscreenmetrics() if self.metrics is None or self.metrics != metrics: #new metrics, start from scratch: self.metrics = metrics self.clean() dx, dy, dw, dh = metrics if width == 0: width = dw if height == 0: height = dh #clamp rectangle requested to the virtual desktop size: if x < dx: width -= x - dx x = dx if y < dy: height -= y - dy y = dy if width > dw: width = dw if height > dh: height = dh if not self.dc: self.wnd = GetDesktopWindow() self.dc = GetWindowDC(self.wnd) assert self.dc, "failed to get a drawing context from the desktop window %s" % self.wnd self.bit_depth = GetDeviceCaps(self.dc, win32con.BITSPIXEL) self.memdc = CreateCompatibleDC(self.dc) assert self.memdc, "failed to get a compatible drawing context from %s" % self.dc self.bitmap = CreateCompatibleBitmap(self.dc, width, height) assert self.bitmap, "failed to get a compatible bitmap from %s" % self.dc r = SelectObject(self.memdc, self.bitmap) if r == 0: log.error("Error: cannot select bitmap object") return None select_time = time.time() log("get_image up to SelectObject (%s) took %ims", REGION_CONSTS.get(r, r), (select_time - start) * 1000) try: if BitBlt(self.memdc, 0, 0, width, height, self.dc, x, y, win32con.SRCCOPY) == 0: e = ctypes.get_last_error() #rate limit the error message: now = time.time() if now - self.bitblt_err_time > 10: log.error("Error: failed to blit the screen, error %i", e) self.bitblt_err_time = now return None except Exception as e: log("BitBlt error", exc_info=True) log.error("Error: cannot capture screen") log.error(" %s", e) return None bitblt_time = time.time() log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000) rowstride = roundup(width * self.bit_depth // 8, 2) buf_size = rowstride * height pixels = ctypes.create_string_buffer(b"", buf_size) log("GetBitmapBits(%#x, %#x, %#x)", self.bitmap, buf_size, ctypes.addressof(pixels)) r = GetBitmapBits(self.bitmap, buf_size, ctypes.byref(pixels)) if r == 0: log.error("Error: failed to copy screen bitmap data") return None if r != buf_size: log.warn( "Warning: truncating pixel buffer, got %i bytes but expected %i", r, buf_size) pixels = pixels[:r] log("get_image GetBitmapBits took %ims", (time.time() - bitblt_time) * 1000) assert pixels, "no pixels returned from GetBitmapBits" if self.bit_depth == 32: rgb_format = "BGRX" elif self.bit_depth == 30: rgb_format = "r210" elif self.bit_depth == 24: rgb_format = "BGR" elif self.bit_depth == 16: rgb_format = "BGR565" elif self.bit_depth == 8: rgb_format = "RLE8" else: raise Exception("unsupported bit depth: %s" % self.bit_depth) bpp = self.bit_depth // 8 v = ImageWrapper(x, y, width, height, pixels, rgb_format, self.bit_depth, rowstride, bpp, planes=ImageWrapper.PACKED, thread_safe=True) if self.bit_depth == 8: count = GetSystemPaletteEntries(self.dc, 0, 0, None) log("palette size: %s", count) palette = [] if count > 0: buf = (PALETTEENTRY * count)() r = GetSystemPaletteEntries(self.dc, 0, count, ctypes.byref(buf)) #we expect 16-bit values, so bit-shift them: for p in buf: palette.append( (p.peRed << 8, p.peGreen << 8, p.peBlue << 8)) v.set_palette(palette) log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time() - start) * 1000) return v
def _check_retval_(self, retval): if retval == 0: raise ctypes.WinError(ctypes.get_last_error()) return retval
def handle_err_check(result, func, args): if result == INVALID_HANDLE_VALUE: raise WinError(get_last_error()) return result
def bool_err_check(result, func, args): if not result: raise WinError(get_last_error()) return result
def get_disk_stats(whichdir, reserved_space=0): """Return disk statistics for the storage disk, in the form of a dict with the following fields. total: total bytes on disk free_for_root: bytes actually free on disk free_for_nonroot: bytes free for "a non-privileged user" [Unix] or the current user [Windows]; might take into account quotas depending on platform used: bytes used on disk avail: bytes available excluding reserved space An AttributeError can occur if the OS has no API to get disk information. An EnvironmentError can occur if the OS call fails. whichdir is a directory on the filesystem in question -- the answer is about the filesystem, not about the directory, so the directory is used only to specify which filesystem. reserved_space is how many bytes to subtract from the answer, so you can pass how many bytes you would like to leave unused on this filesystem as reserved_space. """ if have_GetDiskFreeSpaceExW: # If this is a Windows system and GetDiskFreeSpaceExW is available, use it. # (This might put up an error dialog unless # SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX) has been called, # which we do in allmydata.windows.fixups.initialize().) n_free_for_nonroot = c_ulonglong(0) n_total = c_ulonglong(0) n_free_for_root = c_ulonglong(0) retval = GetDiskFreeSpaceExW(whichdir, byref(n_free_for_nonroot), byref(n_total), byref(n_free_for_root)) if retval == 0: raise OSError("WinError: %s\n attempting to get disk statistics for %r" % (WinError(get_last_error()), whichdir)) free_for_nonroot = n_free_for_nonroot.value total = n_total.value free_for_root = n_free_for_root.value else: # For Unix-like systems. # <http://docs.python.org/library/os.html#os.statvfs> # <http://opengroup.org/onlinepubs/7990989799/xsh/fstatvfs.html> # <http://opengroup.org/onlinepubs/7990989799/xsh/sysstatvfs.h.html> s = os.statvfs(whichdir) # on my mac laptop: # statvfs(2) is a wrapper around statfs(2). # statvfs.f_frsize = statfs.f_bsize : # "minimum unit of allocation" (statvfs) # "fundamental file system block size" (statfs) # statvfs.f_bsize = statfs.f_iosize = stat.st_blocks : preferred IO size # on an encrypted home directory ("FileVault"), it gets f_blocks # wrong, and s.f_blocks*s.f_frsize is twice the size of my disk, # but s.f_bavail*s.f_frsize is correct total = s.f_frsize * s.f_blocks free_for_root = s.f_frsize * s.f_bfree free_for_nonroot = s.f_frsize * s.f_bavail # valid for all platforms: used = total - free_for_root avail = max(free_for_nonroot - reserved_space, 0) return { 'total': total, 'free_for_root': free_for_root, 'free_for_nonroot': free_for_nonroot, 'used': used, 'avail': avail, }
#log("potential matching win32 constants for message: %s", [x for x in dir(win32con) if getattr(win32con, x)==msg]) if instance and fn: return fn(instance, hwnd, msg, wParam, lParam) or 0 return DefWindowProcA(hwnd, msg, wParam, lParam) NIwc = WNDCLASSEX() NIwc.cbSize = sizeof(WNDCLASSEX) NIwc.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW NIwc.lpfnWndProc = WNDPROC(NotifyIconWndProc) NIwc.hInstance = GetModuleHandleA(0) NIwc.hBrush = GetStockObject(win32con.WHITE_BRUSH) NIwc.lpszClassName = u"win32NotifyIcon" NIclassAtom = RegisterClassExA(byref(NIwc)) if NIclassAtom==0: raise ctypes.WinError(ctypes.get_last_error()) log("RegisterClassExA(%s)=%i", NIwc.lpszClassName, NIclassAtom) def main(): from xpra.platform.win32.common import user32 def click_callback(button, pressed): menu = CreatePopupMenu() AppendMenu(menu, win32con.MF_STRING, 1024, u"Generate balloon") AppendMenu(menu, win32con.MF_STRING, 1025, u"Exit") pos = POINT() GetCursorPos(byref(pos)) hwnd = tray.hwnd user32.SetForegroundWindow(hwnd) user32.TrackPopupMenu(menu, win32con.TPM_LEFTALIGN, pos.x, pos.y, 0, hwnd, None)
def _check_zero(result, _, args): # second arg is `func` (unused here) if not result: raise c.WinError(c.get_last_error()) return args
def check(result, _func, args): if result == error_result: raise ctypes.WinError(ctypes.get_last_error()) return args
kernel32 = ctypes.WinDLL('kernel32.dll', use_last_error=True) with_load_library_flags = hasattr(kernel32, 'AddDllDirectory') prev_error_mode = kernel32.SetErrorMode(0x0001) kernel32.LoadLibraryW.restype = ctypes.c_void_p if with_load_library_flags: kernel32.AddDllDirectory.restype = ctypes.c_void_p kernel32.LoadLibraryExW.restype = ctypes.c_void_p for dll_path in dll_paths: if sys.version_info >= (3, 8): os.add_dll_directory(dll_path) elif with_load_library_flags: res = kernel32.AddDllDirectory(dll_path) if res is None: err = ctypes.WinError(ctypes.get_last_error()) err.strerror += f' Error adding "{dll_path}" to the DLL directories.' raise err try: ctypes.CDLL('vcruntime140.dll') ctypes.CDLL('msvcp140.dll') if cuda_version not in ('9.2', '10.0'): ctypes.CDLL('vcruntime140_1.dll') except OSError: print('''Microsoft Visual C++ Redistributable is not installed, this may lead to the DLL load failure. It can be downloaded at https://aka.ms/vs/16/release/vc_redist.x64.exe''') dlls = glob.glob(os.path.join(th_dll_path, '*.dll')) path_patched = False for dll in dlls:
def _check_count(result, func, args): if result == 0: raise ctypes.WinError(ctypes.get_last_error()) return args
def init_keyboard_listener(self): class WindowsKeyEvent(AdHocStruct): pass class KBDLLHOOKSTRUCT(Structure): _fields_ = [ ("vk_code", DWORD), ("scan_code", DWORD), ("flags", DWORD), ("time", c_int), ] DOWN = [win32con.WM_KEYDOWN, win32con.WM_SYSKEYDOWN] #UP = [win32con.WM_KEYUP, win32con.WM_SYSKEYUP] ALL_KEY_EVENTS = { win32con.WM_KEYDOWN: "KEYDOWN", win32con.WM_SYSKEYDOWN: "SYSKEYDOWN", win32con.WM_KEYUP: "KEYUP", win32con.WM_SYSKEYUP: "SYSKEYUP", } def low_level_keyboard_handler(nCode, wParam, lParam): try: scan_code = lParam.contents.scan_code vk_code = lParam.contents.vk_code focused = self.client._focused #the keys we intercept before the OS: keyname = { win32con.VK_LWIN: "Super_L", win32con.VK_RWIN: "Super_R", win32con.VK_TAB: "Tab", }.get(vk_code) modifiers = [] kh = self.client.keyboard_helper key_event_type = ALL_KEY_EVENTS.get(wParam) #log("low_level_keyboard_handler(%s, %s, %s) vk_code=%i, scan_code=%i, keyname=%s, key_event_type=%s, focused=%s, keyboard_grabbed=%s", nCode, wParam, lParam, vk_code, scan_code, keyname, key_event_type, focused, self.client.keyboard_grabbed) if self.client.keyboard_grabbed and focused and keyname and kh and kh.keyboard and key_event_type: modifier_keycodes = kh.keyboard.modifier_keycodes modifier_keys = kh.keyboard.modifier_keys if keyname.startswith("Super"): keycode = 0 #find the modifier keycode: (try the exact key we hit first) for x in [keyname, "Super_L", "Super_R"]: keycodes = modifier_keycodes.get(x, []) for k in keycodes: #only interested in numeric keycodes: try: keycode = int(k) break except: pass if keycode > 0: break else: keycode = vk_code #true for non-modifier keys only! for vk, modkeynames in { win32con.VK_NUMLOCK: ["Num_Lock"], win32con.VK_CAPITAL: ["Caps_Lock"], win32con.VK_CONTROL: ["Control_L", "Control_R"], win32con.VK_SHIFT: ["Shift_L", "Shift_R"], }.items(): if GetKeyState(vk): for modkeyname in modkeynames: mod = modifier_keys.get(modkeyname) if mod: modifiers.append(mod) break #keylog.info("keyboard helper=%s, modifier keycodes=%s", kh, modifier_keycodes) grablog( "vk_code=%s, scan_code=%s, event=%s, keyname=%s, keycode=%s, modifiers=%s, focused=%s", vk_code, scan_code, ALL_KEY_EVENTS.get(wParam), keyname, keycode, modifiers, focused) if keycode > 0: key_event = WindowsKeyEvent() key_event.keyname = keyname key_event.pressed = wParam in DOWN key_event.modifiers = modifiers key_event.keyval = scan_code key_event.keycode = keycode key_event.string = "" key_event.group = 0 grablog("detected '%s' key, sending %s", keyname, key_event) self.client.keyboard_helper.send_key_action( focused, key_event) #swallow this event: return 1 except Exception as e: keylog.error("Error: low level keyboard hook failed") keylog.error(" %s", e) return CallNextHookEx(keyboard_hook_id, nCode, wParam, lParam) # Our low level handler signature. CMPFUNC = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(KBDLLHOOKSTRUCT)) # Convert the Python handler into C pointer. pointer = CMPFUNC(low_level_keyboard_handler) # Hook both key up and key down events for common keys (non-system). keyboard_hook_id = SetWindowsHookExA(win32con.WH_KEYBOARD_LL, pointer, GetModuleHandleA(None), 0) # Register to remove the hook when the interpreter exits: keylog("init_keyboard_listener() hook_id=%#x", keyboard_hook_id) msg = MSG() lpmsg = byref(msg) while True: ret = GetMessageA(lpmsg, None, 0, 0) keylog("init_keyboard_listener: GetMessage()=%s", ret) if ret == -1: raise ctypes.WinError(ctypes.get_last_error()) elif ret == 0: keylog("GetMessage()=0, exiting loop") return else: TranslateMessage(lpmsg) DispatchMessageA(lpmsg)
def check_zero(result, func, args): if not result: err = ctypes.get_last_error() if err: raise ctypes.WinError(err) return args
def _checkNull(result, func, arguments): if result: return result else: err = get_last_error() if 'Windows' in _system() else get_errno() raise OSError(err, _strerror(err))
def _check_bool(result, func, args): if not result: raise ctypes.WinError(ctypes.get_last_error()) return args
def _nonzero_success(result, func, args): if not result: raise ctypes.WinError(ctypes.get_last_error()) return args
def MessageBoxW(hwnd, text, caption, utype): result = _MessageBoxW(hwnd, text, caption, utype) if not result: raise ctypes.WinError(ctypes.get_last_error()) return result
def _check_idv(result, func, args): if result.value == INVALID_DWORD_VALUE: raise ctypes.WinError(ctypes.get_last_error()) return result.value
def _general_windows_errcheck(result, func, args): if not result: raise ctypes.WinError(ctypes.get_last_error())
def msgBox(text, caption, utype): result = ctypes.windll.user32.MessageBoxW(0, text, caption, utype) if not result: raise ctypes.WinError(ctypes.get_last_error()) return result
def CheckError(result, msg): if not result: raise ctypes.WinError(ctypes.get_last_error(), msg)
def errcheck(result, func, args): if not result: raise WinError(get_last_error())
def __init__(self, program, cmdline=None, cwd=None, env=None, htoken=None, spawn_flags=WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN | WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN, pty_flags=0, pty_size=(80, 25), pty_mouse=WINPTY_MOUSE_MODE_NONE): self._closed = False config = None try: with winpty_error() as error: config = winpty.config_new(pty_flags, error) cols, rows = pty_size if cols and rows: winpty.config_set_initial_size(config, cols, rows) winpty.config_set_mouse_mode(config, pty_mouse) if htoken: caller_thread_htoken, requested_htoken = htoken htokendup = impersonate_token(caller_thread_htoken) CloseHandle(caller_thread_htoken) if htokendup: winpty.config_set_htoken(config, requested_htoken) with winpty_error() as error: self._pty = winpty.open(config, error) finally: winpty.config_free(config) self._conin = winpty.conin_name(self._pty) self._conout = winpty.conout_name(self._pty) self._conerr = winpty.conerr_name(self._pty) self._process_handle = None try: self._conin_pipe = CreateFile(self._conin, GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, None) if self._conin_pipe == INVALID_HANDLE_VALUE: raise WinError(get_last_error()) self._conout_pipe = CreateFile(self._conout, GENERIC_READ, 0, None, OPEN_EXISTING, 0, None) if self._conout_pipe == INVALID_HANDLE_VALUE: raise WinError(get_last_error()) if self._conerr: self._conerr_pipe = CreateFile(self._conerr, GENERIC_READ, 0, None, OPEN_EXISTING, 0, None) if self._conerr_pipe == INVALID_HANDLE_VALUE: raise WinError(get_last_error()) else: self._conerr_pipe = None try: spawn_ctx = None process_handle = HANDLE() thread_handle = HANDLE() create_process_error = DWORD() with winpty_error() as error: spawn_ctx = winpty.spawn_config_new( spawn_flags, program, cmdline, cwd, env, error) with winpty_error() as error: spawned = winpty.spawn(self._pty, spawn_ctx, pointer(process_handle), pointer(thread_handle), pointer(create_process_error), error) if spawned: self._process_handle = process_handle finally: winpty.spawn_config_free(spawn_ctx) except Exception as e: logger.exception(e) self.close() raise
def get_image(self, x=0, y=0, width=0, height=0): start = time.time() x, y, width, height = self.get_capture_coords(x, y, width, height) if not self.dc: self.wnd = GetDesktopWindow() if not self.wnd: log.error("Error: cannot access the desktop window") log.error(" capturing the screen is not possible") return None self.dc = GetWindowDC(self.wnd) if not self.dc: log.error("Error: cannot get a drawing context") log.error(" capturing the screen is not possible") log.error(" desktop window=%#x", self.wnd) return None self.bit_depth = GetDeviceCaps(self.dc, win32con.BITSPIXEL) self.memdc = CreateCompatibleDC(self.dc) assert self.memdc, "failed to get a compatible drawing context from %s" % self.dc bitmap = CreateCompatibleBitmap(self.dc, width, height) if not bitmap: log.error("Error: failed to get a compatible bitmap") log.error(" from drawing context %#x with size %ix%i", self.dc, width, height) self.clean_dc() return None r = SelectObject(self.memdc, bitmap) if not r: log.error("Error: cannot select bitmap object") return None select_time = time.time() log("get_image up to SelectObject (%s) took %ims", REGION_CONSTS.get(r, r), (select_time - start) * 1000) try: if BitBlt(self.memdc, 0, 0, width, height, self.dc, x, y, win32con.SRCCOPY) == 0: e = ctypes.get_last_error() #rate limit the error message: now = time.time() if now - self.bitblt_err_time > 10: log.error("Error: failed to blit the screen, error %i", e) self.bitblt_err_time = now return None except Exception as e: log("BitBlt error", exc_info=True) log.error("Error: cannot capture screen with BitBlt") log.error(" %s", e) self.clean_dc() return None bitblt_time = time.time() log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000) rowstride = roundup(width * self.bit_depth // 8, 2) buf_size = rowstride * height pixels = ctypes.create_string_buffer(b"", buf_size) log("GetBitmapBits(%#x, %#x, %#x)", bitmap, buf_size, ctypes.addressof(pixels)) r = GetBitmapBits(bitmap, buf_size, ctypes.byref(pixels)) if not r: log.error("Error: failed to copy screen bitmap data") self.clean_dc() return None if r != buf_size: log.warn( "Warning: truncating pixel buffer, got %i bytes but expected %i", r, buf_size) pixels = pixels[:r] log("get_image GetBitmapBits took %ims", (time.time() - bitblt_time) * 1000) DeleteObject(bitmap) assert pixels, "no pixels returned from GetBitmapBits" rgb_format = RGB_FORMATS.get(self.bit_depth) if not rgb_format: raise Exception("unsupported bit depth: %s" % self.bit_depth) bpp = self.bit_depth // 8 v = ImageWrapper(0, 0, width, height, pixels, rgb_format, self.bit_depth, rowstride, bpp, planes=ImageWrapper.PACKED, thread_safe=True) if self.bit_depth == 8: palette = get_palette(self.dc) v.set_palette(palette) log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time() - start) * 1000) return v