Ejemplo n.º 1
0
    def __enter__(self):
        self.handle = HANDLE()
        name = LPCSTR(self.printer_name)
        if not OpenPrinterA(name, pointer(self.handle), None):
            raise Exception("failed to open printer %s" % self.printer_name)
        log("OpenPrinter: handle=%#x", self.handle.value)
        size = DWORD(0)
        GetPrinterA(self.handle, 1, None, 0, pointer(size))
        if size.value == 0:
            raise Exception("GetPrinterA PRINTER_INFO_1 failed for '%s'" %
                            self.printer_name)
        log("GetPrinter: PRINTER_INFO_1 size=%#x", size.value)
        self.info1 = msvcrt.malloc(size.value)
        if not GetPrinterA(self.handle, 1, self.info1, size.value,
                           pointer(size)):
            raise Exception("GetPrinterA PRINTER_INFO_1 failed for '%s'",
                            self.printer_name)
        info = cast(self.info1, POINTER(PRINTER_INFO_1))
        log(" flags=%#x" % info[0].Flags)
        log(" name=%#s" % info[0].pName)
        log(" description=%s" % info[0].pDescription)
        log(" comment=%s" % info[0].pComment)

        size = DWORD(0)
        GetPrinterA(self.handle, 2, None, 0, pointer(size))
        if size.value == 0:
            raise Exception("GetPrinterA PRINTER_INFO_2 failed for '%s'",
                            self.printer_name)
        log("GetPrinter: PRINTER_INFO_2 size=%#x", size.value)
        self.info2 = msvcrt.malloc(size.value)
        if GetPrinterA(self.handle, 2, self.info2, size.value, pointer(size)):
            info = cast(self.info2, POINTER(PRINTER_INFO_2))
            log(" driver=%#s" % info[0].pDriverName)

        size = DWORD(0)
        GetPrinterA(self.handle, 8, None, 0, pointer(size))
        if size.value == 0:
            raise Exception("GetPrinter: PRINTER_INFO_8 failed for '%s'" %
                            self.printer_name)
        self.info8 = msvcrt.malloc(size.value)
        if GetPrinterA(self.handle, 8, self.info8, size.value, pointer(size)):
            info = cast(self.info8, POINTER(PRINTER_INFO_8))
            if info[0] and info[0].pDevMode:
                devmode = cast(info[0].pDevMode, POINTER(DEVMODE))
                log("PRINTER_INFO_8: devmode=%s" % devmode)
                log("PRINTER_INFO_8: device name='%s'" %
                    devmode[0].dmDeviceName)

        size = DWORD(0)
        GetPrinterA(self.handle, 9, None, 0, pointer(size))
        if size.value == 0:
            raise Exception("GetPrinter: PRINTER_INFO_9 failed for '%s'" %
                            self.printer_name)
        log("GetPrinter: PRINTER_INFO_9 size=%#x" % size.value)
        self.info9 = msvcrt.malloc(size.value)
        if GetPrinterA(self.handle, 9, self.info9, size.value, pointer(size)):
            info = cast(self.info9, POINTER(PRINTER_INFO_9))
            if info[0] and info[0].pDevMode:
                devmode = cast(info[0].pDevMode, POINTER(DEVMODE))
                log("PRINTER_INFO_9: devmode=%s" % devmode)
                log("PRINTER_INFO_9: device name=%s" % devmode[0].dmDeviceName)
        assert devmode, "failed to query a DEVMODE for %s" % self.printer_name
        self.hdc = CreateDCA(None, name, None, devmode)
        log("CreateDCA(..)=%#x", self.hdc)
        return self.hdc
Ejemplo n.º 2
0
def iterate_comports():
    """Return a generator that yields descriptions for serial ports"""
    PortsGUIDs = (GUID *
                  8)()  # so far only seen one used, so hope 8 are enough...
    ports_guids_size = DWORD()
    if not SetupDiClassGuidsFromName("Ports", PortsGUIDs,
                                     ctypes.sizeof(PortsGUIDs),
                                     ctypes.byref(ports_guids_size)):
        raise ctypes.WinError()

    ModemsGUIDs = (GUID *
                   8)()  # so far only seen one used, so hope 8 are enough...
    modems_guids_size = DWORD()
    if not SetupDiClassGuidsFromName("Modem", ModemsGUIDs,
                                     ctypes.sizeof(ModemsGUIDs),
                                     ctypes.byref(modems_guids_size)):
        raise ctypes.WinError()

    GUIDs = PortsGUIDs[:ports_guids_size.
                       value] + ModemsGUIDs[:modems_guids_size.value]

    # repeat for all possible GUIDs
    for index in range(len(GUIDs)):
        bInterfaceNumber = None
        g_hdi = SetupDiGetClassDevs(
            ctypes.byref(GUIDs[index]), None, NULL, DIGCF_PRESENT
        )  # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports

        devinfo = SP_DEVINFO_DATA()
        devinfo.cbSize = ctypes.sizeof(devinfo)
        index = 0
        while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)):
            index += 1

            # get the real com port name
            hkey = SetupDiOpenDevRegKey(
                g_hdi,
                ctypes.byref(devinfo),
                DICS_FLAG_GLOBAL,
                0,
                DIREG_DEV,  # DIREG_DRV for SW info
                KEY_READ)
            port_name_buffer = ctypes.create_unicode_buffer(250)
            port_name_length = ULONG(ctypes.sizeof(port_name_buffer))
            RegQueryValueEx(hkey, "PortName", None, None,
                            ctypes.byref(port_name_buffer),
                            ctypes.byref(port_name_length))
            RegCloseKey(hkey)

            # unfortunately does this method also include parallel ports.
            # we could check for names starting with COM or just exclude LPT
            # and hope that other "unknown" names are serial ports...
            if port_name_buffer.value.startswith('LPT'):
                continue

            # hardware ID
            szHardwareID = ctypes.create_unicode_buffer(250)
            # try to get ID that includes serial number
            if not SetupDiGetDeviceInstanceId(
                    g_hdi,
                    ctypes.byref(devinfo),
                    #~ ctypes.byref(szHardwareID),
                    szHardwareID,
                    ctypes.sizeof(szHardwareID) - 1,
                    None):
                # fall back to more generic hardware ID if that would fail
                if not SetupDiGetDeviceRegistryProperty(
                        g_hdi, ctypes.byref(devinfo), SPDRP_HARDWAREID, None,
                        ctypes.byref(szHardwareID),
                        ctypes.sizeof(szHardwareID) - 1, None):
                    # Ignore ERROR_INSUFFICIENT_BUFFER
                    if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
                        raise ctypes.WinError()
            # stringify
            szHardwareID_str = szHardwareID.value

            info = list_ports_common.ListPortInfo(port_name_buffer.value,
                                                  skip_link_detection=True)

            # in case of USB, make a more readable string, similar to that form
            # that we also generate on other platforms
            if szHardwareID_str.startswith('USB'):
                m = re.search(
                    r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(.*))?',
                    szHardwareID_str, re.I)
                if m:
                    info.vid = int(m.group(1), 16)
                    if m.group(3):
                        info.pid = int(m.group(3), 16)
                    if m.group(5):
                        bInterfaceNumber = int(m.group(5))

                    # Check that the USB serial number only contains alphanumeric characters. It
                    # may be a windows device ID (ephemeral ID) for composite devices.
                    if m.group(7) and re.match(r'^\w+$', m.group(7)):
                        info.serial_number = m.group(7)
                    else:
                        info.serial_number = get_parent_serial_number(
                            devinfo.DevInst, info.vid, info.pid)

                # calculate a location string
                loc_path_str = ctypes.create_unicode_buffer(250)
                if SetupDiGetDeviceRegistryProperty(
                        g_hdi, ctypes.byref(devinfo), SPDRP_LOCATION_PATHS,
                        None, ctypes.byref(loc_path_str),
                        ctypes.sizeof(loc_path_str) - 1, None):
                    m = re.finditer(r'USBROOT\((\w+)\)|#USB\((\w+)\)',
                                    loc_path_str.value)
                    location = []
                    for g in m:
                        if g.group(1):
                            location.append('{:d}'.format(int(g.group(1)) + 1))
                        else:
                            if len(location) > 1:
                                location.append('.')
                            else:
                                location.append('-')
                            location.append(g.group(2))
                    if bInterfaceNumber is not None:
                        location.append(':{}.{}'.format(
                            'x',  # XXX how to determine correct bConfigurationValue?
                            bInterfaceNumber))
                    if location:
                        info.location = ''.join(location)
                info.hwid = info.usb_info()
            elif szHardwareID_str.startswith('FTDIBUS'):
                m = re.search(
                    r'VID_([0-9a-f]{4})\+PID_([0-9a-f]{4})(\+(\w+))?',
                    szHardwareID_str, re.I)
                if m:
                    info.vid = int(m.group(1), 16)
                    info.pid = int(m.group(2), 16)
                    if m.group(4):
                        info.serial_number = m.group(4)
                # USB location is hidden by FDTI driver :(
                info.hwid = info.usb_info()
            else:
                info.hwid = szHardwareID_str

            # friendly name
            szFriendlyName = ctypes.create_unicode_buffer(250)
            if SetupDiGetDeviceRegistryProperty(
                    g_hdi,
                    ctypes.byref(devinfo),
                    SPDRP_FRIENDLYNAME,
                    #~ SPDRP_DEVICEDESC,
                    None,
                    ctypes.byref(szFriendlyName),
                    ctypes.sizeof(szFriendlyName) - 1,
                    None):
                info.description = szFriendlyName.value
            #~ else:
            # Ignore ERROR_INSUFFICIENT_BUFFER
            #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
            #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value))
            # ignore errors and still include the port in the list, friendly name will be same as port name

            # manufacturer
            szManufacturer = ctypes.create_unicode_buffer(250)
            if SetupDiGetDeviceRegistryProperty(
                    g_hdi,
                    ctypes.byref(devinfo),
                    SPDRP_MFG,
                    #~ SPDRP_DEVICEDESC,
                    None,
                    ctypes.byref(szManufacturer),
                    ctypes.sizeof(szManufacturer) - 1,
                    None):
                info.manufacturer = szManufacturer.value
            yield info
        SetupDiDestroyDeviceInfoList(g_hdi)
Ejemplo n.º 3
0
def prepare_intercept(callback):
    """
    Registers a Windows low level keyboard hook. The provided callback will
    be invoked for each high-level keyboard event, and is expected to return
    True if the key event should be passed to the next program, or False if
    the event is to be blocked.

    No event is processed until the Windows messages are pumped (see
    start_intercept).
    """
    _setup_name_tables()

    def process_key(event_type, vk, scan_code, is_extended):
        global shift_is_pressed, altgr_is_pressed, ignore_next_right_alt
        #print(event_type, vk, scan_code, is_extended)

        # Pressing alt-gr also generates an extra "right alt" event
        if vk == 0xA5 and ignore_next_right_alt:
            ignore_next_right_alt = False
            return True

        modifiers = (('shift', ) * shift_is_pressed +
                     ('alt gr', ) * altgr_is_pressed + ('num lock', ) *
                     (user32.GetKeyState(0x90) & 1) + ('caps lock', ) *
                     (user32.GetKeyState(0x14) & 1) + ('scroll lock', ) *
                     (user32.GetKeyState(0x91) & 1))
        entry = (scan_code, vk, is_extended, modifiers)
        if entry not in to_name:
            to_name[entry] = list(get_event_names(*entry))

        names = to_name[entry]
        name = names[0] if names else None

        # TODO: inaccurate when holding multiple different shifts.
        if vk in shift_vks:
            shift_is_pressed = event_type == KEY_DOWN
        if scan_code == 541 and vk == 162:
            ignore_next_right_alt = True
            altgr_is_pressed = event_type == KEY_DOWN

        is_keypad = (scan_code, vk, is_extended) in keypad_keys
        return callback(
            KeyboardEvent(event_type=event_type,
                          scan_code=scan_code or -vk,
                          name=name,
                          is_keypad=is_keypad))

    def low_level_keyboard_handler(nCode, wParam, lParam):
        try:
            vk = lParam.contents.vk_code
            # Ignore the second `alt` DOWN observed in some cases.
            fake_alt = (LLKHF_INJECTED | 0x20)
            # Ignore events generated by SendInput with Unicode.
            if vk != VK_PACKET and lParam.contents.flags & fake_alt != fake_alt:
                event_type = keyboard_event_types[wParam]
                is_extended = lParam.contents.flags & 1
                scan_code = lParam.contents.scan_code
                should_continue = process_key(event_type, vk, scan_code,
                                              is_extended)
                if not should_continue:
                    return -1
        except Exception as e:
            print('Error in keyboard hook:')
            traceback.print_exc()

        return CallNextHookEx(None, nCode, wParam, lParam)

    WH_KEYBOARD_LL = c_int(13)
    keyboard_callback = LowLevelKeyboardProc(low_level_keyboard_handler)
    handle = GetModuleHandleW(None)
    thread_id = DWORD(0)
    keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_callback, handle,
                                     thread_id)

    # Register to remove the hook when the interpreter exits. Unfortunately a
    # try/finally block doesn't seem to work here.
    atexit.register(UnhookWindowsHookEx, keyboard_callback)
Ejemplo n.º 4
0
GUID_DEVINTERFACE_FLOPPY = GUID(0x53f56311, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00,
                                0xa0, 0xc9, 0x1e, 0xfb, 0x8b)
GUID_DEVINTERFACE_USB_DEVICE = GUID(0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F,
                                    0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED)
GUID_DEVINTERFACE_USB_HUB = GUID(0xf18a0e88, 0xc30c, 0x11d0, 0x88, 0x15, 0x00,
                                 0xa0, 0xc9, 0x06, 0xbe, 0xd8)
DRIVE_UNKNOWN, DRIVE_NO_ROOT_DIR, DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_REMOTE, DRIVE_CDROM, DRIVE_RAMDISK = 0, 1, 2, 3, 4, 5, 6
DIGCF_PRESENT = 0x00000002
DIGCF_ALLCLASSES = 0x00000004
DIGCF_DEVICEINTERFACE = 0x00000010
ERROR_INSUFFICIENT_BUFFER = 0x7a
ERROR_MORE_DATA = 234
ERROR_INVALID_DATA = 0xd
ERROR_GEN_FAILURE = 31
HDEVINFO = HANDLE
SPDRP_DEVICEDESC = DWORD(0x00000000)
SPDRP_HARDWAREID = DWORD(0x00000001)
SPDRP_COMPATIBLEIDS = DWORD(0x00000002)
SPDRP_UNUSED0 = DWORD(0x00000003)
SPDRP_SERVICE = DWORD(0x00000004)
SPDRP_UNUSED1 = DWORD(0x00000005)
SPDRP_UNUSED2 = DWORD(0x00000006)
SPDRP_CLASS = DWORD(0x00000007)
SPDRP_CLASSGUID = DWORD(0x00000008)
SPDRP_DRIVER = DWORD(0x00000009)
SPDRP_CONFIGFLAGS = DWORD(0x0000000A)
SPDRP_MFG = DWORD(0x0000000B)
SPDRP_FRIENDLYNAME = DWORD(0x0000000C)
SPDRP_LOCATION_INFORMATION = DWORD(0x0000000D)
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = DWORD(0x0000000E)
SPDRP_CAPABILITIES = DWORD(0x0000000F)
Ejemplo n.º 5
0
 def not_a_console(handle):
     if handle == INVALID_HANDLE_VALUE or handle is None:
         return True
     return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
             or GetConsoleMode(handle, byref(DWORD())) == 0)
Ejemplo n.º 6
0
def listUsbDevices(onlyAvailable=True):
	"""List USB devices on the system.
	@param onlyAvailable: Only return devices that are currently available.
	@type onlyAvailable: bool
	@return: Generates dicts including keys of usbID (VID and PID), devicePath and hardwareID.
	@rtype: generator of dict
	"""
	flags = DIGCF_DEVICEINTERFACE
	if onlyAvailable:
		flags |= DIGCF_PRESENT

	buf = ctypes.create_unicode_buffer(1024)
	g_hdi = SetupDiGetClassDevs(GUID_DEVINTERFACE_USB_DEVICE, None, NULL, flags)
	try:
		for dwIndex in xrange(256):
			did = SP_DEVICE_INTERFACE_DATA()
			did.cbSize = ctypes.sizeof(did)

			if not SetupDiEnumDeviceInterfaces(
				g_hdi,
				None,
				GUID_DEVINTERFACE_USB_DEVICE,
				dwIndex,
				ctypes.byref(did)
			):
				if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS:
					raise ctypes.WinError()
				break

			dwNeeded = DWORD()
			# get the size
			if not SetupDiGetDeviceInterfaceDetail(
				g_hdi,
				ctypes.byref(did),
				None, 0, ctypes.byref(dwNeeded),
				None
			):
				# Ignore ERROR_INSUFFICIENT_BUFFER
				if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
					raise ctypes.WinError()
			# allocate buffer
			class SP_DEVICE_INTERFACE_DETAIL_DATA_W(ctypes.Structure):
				_fields_ = (
					('cbSize', DWORD),
					('DevicePath', WCHAR*(dwNeeded.value - ctypes.sizeof(DWORD))),
				)
				def __str__(self):
					return "DevicePath:%s" % (self.DevicePath,)
			idd = SP_DEVICE_INTERFACE_DETAIL_DATA_W()
			idd.cbSize = SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_W
			devinfo = SP_DEVINFO_DATA()
			devinfo.cbSize = ctypes.sizeof(devinfo)
			if not SetupDiGetDeviceInterfaceDetail(
				g_hdi,
				ctypes.byref(did),
				ctypes.byref(idd), dwNeeded, None,
				ctypes.byref(devinfo)
			):
				raise ctypes.WinError()

			# hardware ID
			if not SetupDiGetDeviceRegistryProperty(
				g_hdi,
				ctypes.byref(devinfo),
				SPDRP_HARDWAREID,
				None,
				ctypes.byref(buf), ctypes.sizeof(buf) - 1,
				None
			):
				# Ignore ERROR_INSUFFICIENT_BUFFER
				if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
					raise ctypes.WinError()
			else:
				# The string is of the form "usb\VID_xxxx&PID_xxxx&..."
				usbId = buf.value[4:21] # VID_xxxx&PID_xxxx
				info = {
					"hardwareID": buf.value,
					"usbID": usbId,
					"devicePath": idd.DevicePath}
				if _isDebug():
					log.debug("%r" % usbId)
				yield info
	finally:
		SetupDiDestroyDeviceInfoList(g_hdi)
	if _isDebug():
		log.debug("Finished listing USB devices")
Ejemplo n.º 7
0
    def get_brightness(cls, display: Optional[Union[int, str]] = None) -> List[int]:
        '''
        Retrieve the brightness of all connected displays using the `ctypes.windll` API

        Args:
            display (int or str): The specific display you wish to query.
                Can be index, name, model, serial or edid string.
                `int` is faster as it isn't passed to `filter_monitors` to be matched against.
                `str` is slower as it is passed to `filter_monitors` to match to a display.

        Returns:
            list: list of ints (0 to 100)

        Examples:
            ```python
            import screen_brightness_control as sbc

            # Get the brightness for all detected displays
            current_brightness = sbc.windows.VCP.get_brightness()
            print('There are', len(current_brightness), 'detected displays')

            # Get the brightness for the primary display
            primary_brightness = sbc.windows.VCP.get_brightness(display = 0)[0]

            # Get the brightness for a secondary display
            secondary_brightness = sbc.windows.VCP.get_brightness(display = 1)[0]

            # Get the brightness for a display with the model 'GL2450H'
            benq_brightness = sbc.windows.VCP.get_brightness(display = 'GL2450H')[0]
            ```
        '''
        # filter monitors even if display kwarg is not specified due to oddities surrounding issues #7 and #8
        # https://github.com/Crozzers/screen_brightness_control/issues/7
        # https://github.com/Crozzers/screen_brightness_control/issues/8
        # essentially, we get 'ghost' monitors showing up here that cannot actually
        # be adjusted (even if no error gets raised) so we use this to filter out
        # such ghost monitors by only attempting to get the brightness for valid monitors
        # (determined by VCP.get_display_info)
        # yes, it does add an unnecessary function call but that's only if you're using this module low-level.
        # Top-level functions always end up specifying the display kwarg anyway
        if type(display) == int:
            indexes = [display]
        else:
            indexes = [i['index'] for i in filter_monitors(display=display, haystack=cls.get_display_info())]

        count = 0
        values = []
        for m in cls.iter_physical_monitors():
            try:
                v = __cache__.get(f'vcp_brightness_{count}')
            except Exception:
                cur_out = DWORD()
                for _ in range(10):
                    if windll.dxva2.GetVCPFeatureAndVCPFeatureReply(HANDLE(m), BYTE(0x10), None, byref(cur_out), None):
                        v = cur_out.value
                        break
                    else:
                        time.sleep(0.02)
                        v = None
                del(cur_out)
            if v is not None:
                if count in indexes:
                    try:
                        __cache__.store(f'vcp_brightness_{count}', v, expires=0.1)
                    except IndexError:
                        pass
                    values.append(v)
                    if count >= max(indexes):
                        break
            count += 1

        return values
Ejemplo n.º 8
0
def _yeiComPorts():
    """ This generator scans the device registry for com ports and yields port,
        desc, hw_id
    """

    GUID_list = [
        GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, GUID_DEVINTERFACE_COMPORT
    ]
    ports_yielded = []
    bt_device_list = None

    for device_GUID in GUID_list:
        g_hdi = SetupDiGetClassDevs(ctypes.byref(device_GUID), None, NULL,
                                    DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)
        for dw_index in range(256):
            friendly_name_string = ""
            did = SP_DEVICE_INTERFACE_DATA()
            did.cbSize = ctypes.sizeof(did)

            if not SetupDiEnumDeviceInterfaces(
                    g_hdi, None, ctypes.byref(device_GUID), dw_index,
                    ctypes.byref(did)):
                if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS:
                    if '-d' in sys.argv:
                        raise ctypes.WinError()
                break

            dw_needed = DWORD()
            # Get the size
            if not SetupDiGetDeviceInterfaceDetail(
                    g_hdi, ctypes.byref(did), None, 0, ctypes.byref(dw_needed),
                    None):
                # Ignore ERROR_INSUFFICIENT_BUFFER
                if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
                    if '-d' in sys.argv:
                        raise ctypes.WinError()

            # Allocate buffer
            class SP_DEVICE_INTERFACE_DETAIL_DATA_A(ctypes.Structure):
                _fields_ = [
                    ('cbSize', DWORD),
                    ('DevicePath',
                     CHAR * (dw_needed.value - ctypes.sizeof(DWORD))),
                ]

                def __str__(self):
                    return "DevicePath: %s" % self.DevicePath

            idd = SP_DEVICE_INTERFACE_DETAIL_DATA_A()
            if is_64bit():
                idd.cbSize = 8
            else:
                idd.cbSize = 5

            dev_info = SP_DEVINFO_DATA()
            dev_info.cbSize = ctypes.sizeof(dev_info)
            if not SetupDiGetDeviceInterfaceDetail(
                    g_hdi, ctypes.byref(did), ctypes.byref(idd), dw_needed,
                    None, ctypes.byref(dev_info)):
                if '-d' in sys.argv:
                    raise ctypes.WinError()

            # hardware ID
            sz_hardware_id = _byteBuffer(1024)
            if not SetupDiGetDeviceRegistryProperty(
                    g_hdi, ctypes.byref(dev_info), SPDRP_HARDWAREID, None,
                    ctypes.byref(sz_hardware_id),
                    ctypes.sizeof(sz_hardware_id) - 1, None):
                # Ignore ERROR_INSUFFICIENT_BUFFER
                if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
                    if '-d' in sys.argv:
                        raise ctypes.WinError()

            #Build VID/PID string
            vid_pid_string = ""
            hw_string = _string(sz_hardware_id)
            hw_string = hw_string.upper()
            vid_idx = hw_string.find("VID_")
            pid_idx = hw_string.find("PID_")
            if vid_idx != -1 and pid_idx != -1:
                vid_end = hw_string.find("&", vid_idx + 1)
                vid = hw_string[vid_idx:vid_end]
                pid_end = hw_string.find("&", pid_idx + 1)
                pid = hw_string[pid_idx:pid_end]
                vid_pid_string = vid + "&" + pid

            enum_name_buff = _byteBuffer(1024)
            if SetupDiGetDeviceRegistryProperty(
                    g_hdi, ctypes.byref(dev_info), SPDRP_ENUMERATOR_NAME, None,
                    ctypes.byref(enum_name_buff),
                    ctypes.sizeof(enum_name_buff) - 1, None):
                if _string(enum_name_buff).upper() == "BTHENUM":
                    # This is a bluetooth enumerator, we should do further
                    # investigation
                    if bt_device_list is None:
                        bt_device_list = _getBluetoothDevices()

                    device_path_str = idd.DevicePath
                    if type(device_path_str) is bytes:
                        device_path_str = bytes.decode(device_path_str)
                    start_idx = device_path_str.rfind("&") + 1
                    end_idx = start_idx + 12
                    bt_addr_string = device_path_str[start_idx:end_idx]
                    bt_address = _stringToBluetoothAddress(bt_addr_string)
                    if bt_address == _stringToBluetoothAddress("0"):
                        continue
                    connected_dev = None
                    for bt_dev in bt_device_list:
                        if bt_dev.Address == bt_address:
                            connected_dev = bt_dev
                            break
                    if connected_dev is not None:
                        if (str(connected_dev.szName).find("YEI_3SpaceBT") !=
                                -1):
                            # The device is a 3-Space Sensor!
                            vid_pid_string = "VID_2476&PID_1060"
                            friendly_name_string = "3 Space Bluetooth over Bluetooth link "

            sz_friendly_name = _byteBuffer(1024)
            if not SetupDiGetDeviceRegistryProperty(
                    g_hdi, ctypes.byref(dev_info), SPDRP_FRIENDLYNAME, None,
                    ctypes.byref(sz_friendly_name),
                    ctypes.sizeof(sz_friendly_name) - 1, None):
                # Ignore ERROR_INSUFFICIENT_BUFFER
                if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
                    if '-d' in sys.argv:
                        raise IOError("Failed to get details for %s (%s)" %
                                      (dev_info, sz_hardware_id.value))
                    port_name = None
            else:
                # The real com port name has to read differently...
                h_key = SetupDiOpenDevRegKey(g_hdi, ctypes.byref(dev_info),
                                             DICS_FLAG_GLOBAL, 0, DIREG_DEV,
                                             KEY_READ)
                port_name_buffer = _byteBuffer(1024)
                port_name_length = ULONG(ctypes.sizeof(port_name_buffer))
                RegQueryValueEx(h_key, PortName, None, None,
                                ctypes.byref(port_name_buffer),
                                ctypes.byref(port_name_length))
                RegCloseKey(h_key)

                # We either use the generated friendly name or our overridden
                # one, with preference to the overridden one.
                if friendly_name_string == "":
                    friendly_name_string = _string(sz_friendly_name)
                else:
                    friendly_name_string += "(" + _string(
                        port_name_buffer) + ")"
                if _string(port_name_buffer) not in ports_yielded:
                    ports_yielded.append(_string(port_name_buffer))
                    yield (_string(port_name_buffer), friendly_name_string,
                           _string(sz_hardware_id), vid_pid_string)
        SetupDiDestroyDeviceInfoList(g_hdi)
Ejemplo n.º 9
0
def enable_ansi_colors_win10():
    import ctypes

    # Function factory for errcheck callbacks that raise WinError on failure.
    def raise_if(error_result):
        def check(result, func, args):
            if result == error_result:
                raise ctypes.WinError(ctypes.get_last_error())
            return args

        return check

    # Windows API types.
    from ctypes.wintypes import BOOL, DWORD, HANDLE, LPCWSTR, LPVOID
    LPDWORD = ctypes.POINTER(DWORD)

    # Generic constants.
    NULL = ctypes.c_void_p(0).value
    INVALID_HANDLE_VALUE = ctypes.c_void_p(-1).value
    ERROR_INVALID_PARAMETER = 87

    # CreateFile flags.
    # yapf: disable
    GENERIC_READ  = 0x80000000
    GENERIC_WRITE = 0x40000000
    FILE_SHARE_READ  = 0x01
    FILE_SHARE_WRITE = 0x02
    OPEN_EXISTING = 3
    # yapf: enable

    # Get/SetConsoleMode flags.
    ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x04

    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

    # HANDLE CreateFileW(...)
    CreateFileW = kernel32.CreateFileW
    CreateFileW.restype = HANDLE
    CreateFileW.errcheck = raise_if(INVALID_HANDLE_VALUE)
    # yapf: disable
    CreateFileW.argtypes = (LPCWSTR,  # lpFileName
                            DWORD,    # dwDesiredAccess
                            DWORD,    # dwShareMode
                            LPVOID,   # lpSecurityAttributes
                            DWORD,    # dwCreationDisposition
                            DWORD,    # dwFlagsAndAttributes
                            HANDLE)   # hTemplateFile
    # yapf: enable

    # BOOL CloseHandle(HANDLE hObject)
    CloseHandle = kernel32.CloseHandle
    CloseHandle.restype = BOOL
    CloseHandle.errcheck = raise_if(False)
    CloseHandle.argtypes = (HANDLE, )

    # BOOL GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
    GetConsoleMode = kernel32.GetConsoleMode
    GetConsoleMode.restype = BOOL
    GetConsoleMode.errcheck = raise_if(False)
    GetConsoleMode.argtypes = (HANDLE, LPDWORD)

    # BOOL SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode)
    SetConsoleMode = kernel32.SetConsoleMode
    SetConsoleMode.restype = BOOL
    SetConsoleMode.errcheck = raise_if(False)
    SetConsoleMode.argtypes = (HANDLE, DWORD)

    # Open the console output device.
    conout = CreateFileW("CONOUT$", GENERIC_READ | GENERIC_WRITE,
                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                         OPEN_EXISTING, 0, 0)

    # Get the current mode.
    mode = DWORD()
    GetConsoleMode(conout, ctypes.byref(mode))

    # Try to set the flag that controls ANSI escape code support.
    try:
        SetConsoleMode(conout, mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
    except WindowsError as e:
        if e.winerror == ERROR_INVALID_PARAMETER:
            return False  # Not supported, likely an older version of Windows.
        raise
    finally:
        CloseHandle(conout)

    return True
Ejemplo n.º 10
0
# workaround to allow ImageGrab to capture the whole screen
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()

# get monitor resolution
screen_w = ctypes.windll.user32.GetSystemMetrics(0)
screen_h = ctypes.windll.user32.GetSystemMetrics(1)
print('screen_w=', screen_w, 'screen_h=', screen_h)

# loop
while True:
    # retrieve size and position of the window
    rect = RECT()
    DWMWA_EXTENDED_FRAME_BOUNDS = 9
    dwmapi.DwmGetWindowAttribute(HWND(win_hwnd), DWORD(DWMWA_EXTENDED_FRAME_BOUNDS), ctypes.byref(rect), ctypes.sizeof(rect))

    x = rect.left
    y = rect.top
    w = rect.right- x
    h = rect.bottom - y
    print('x=', x, 'y=', y, 'w=', w, 'h=', h)

    if (w == 0 or h == 0):
        continue

    # take a full screenshot of the desktop
    full_screen = np.array(ImageGrab.grab( bbox= (0, 0, screen_w, screen_h) ))
    if (full_screen is None):
        continue
Ejemplo n.º 11
0
# Import modules
from ctypes import byref, c_bool, windll
from ctypes.wintypes import DWORD

__t1 = c_bool()
__t2 = DWORD()
""" Make blue screen of death """


def bsod():
    windll.ntdll.RtlAdjustPrivilege(19, 1, 0, byref(__t1))
    windll.ntdll.NtRaiseHardError(0xc0000022, 0, 0, 0, 6, byref(__t2))
Ejemplo n.º 12
0
    def __init__(self):
        self.parser = EdidParser()
        # name aliases to respect winapi-style syntax
        self.NULL = 0
        self.HDEVINFO = ctypes.c_void_p
        self.PCTSTR = ctypes.c_char_p
        self.PDWORD = ctypes.POINTER(DWORD)
        self.REGSAM = DWORD
        # some details of the windows API differ between 32 and 64 bit systems..
        # ULONG_PTR is a an ordinary number, not a pointer and contrary to the
        # name it is either 32 or 64 bits, depending on the type of windows...
        # so test if this a 32 bit windows...
        if sizeof(c_ulong) != sizeof(c_void_p):
            # assume 64 bits
            self.ULONG_PTR = c_int64
        else:
            # 32 bits
            self.ULONG_PTR = c_ulong
        # some structures need to be passed to winapi calls
        self.GUID = type(
            'GUID', (ctypes.Structure, ),
            dict(_fields_=[('Data1', DWORD), ('Data2',
                                              WORD), ('Data3',
                                                      WORD), ('Data4',
                                                              BYTE * 8)]))
        self.SP_DEVINFO_DATA = type(
            'SP_DEVINFO_DATA', (ctypes.Structure, ),
            dict(_fields_=[('cbSize', DWORD), (
                'ClassGuid',
                self.GUID), ('DevInst', DWORD), ('Reserved', self.ULONG_PTR)]))
        self.PSP_DEVINFO_DATA = ctypes.POINTER(self.SP_DEVINFO_DATA)
        # setupapi DLL and registration of its functions needed
        self.setupapi = ctypes.windll.LoadLibrary("setupapi")
        # step 1 - get class GUID for 'Monitor' devices
        self.SetupDiClassGuidsFromName = self.setupapi.SetupDiClassGuidsFromNameA
        self.SetupDiClassGuidsFromName.argtypes = [
            self.PCTSTR,
            ctypes.POINTER(self.GUID), DWORD, self.PDWORD
        ]
        self.SetupDiClassGuidsFromName.restype = BOOL
        # step 2 - obtain handle to a device information set
        self.SetupDiGetClassDevs = self.setupapi.SetupDiGetClassDevsA
        self.SetupDiGetClassDevs.argtypes = [
            ctypes.POINTER(self.GUID), self.PCTSTR, HWND, DWORD
        ]
        self.SetupDiGetClassDevs.restype = self.HDEVINFO
        self.SetupDiGetClassDevs.errcheck = self.ValidHandle
        # step 3 - get structure that specifies a device information element
        # in a device information set
        self.SetupDiEnumDeviceInfo = self.setupapi.SetupDiEnumDeviceInfo
        self.SetupDiEnumDeviceInfo.argtypes = [
            self.HDEVINFO, DWORD, self.PSP_DEVINFO_DATA
        ]
        self.SetupDiEnumDeviceInfo.restype = BOOL
        # step 4 - obtain ID for the registry key where EDID actually is
        self.SetupDiOpenDevRegKey = self.setupapi.SetupDiOpenDevRegKey
        self.SetupDiOpenDevRegKey.argtypes = [
            self.HDEVINFO, self.PSP_DEVINFO_DATA, DWORD, DWORD, DWORD,
            self.REGSAM
        ]
        self.SetupDiOpenDevRegKey.restype = HKEY
        # garbage collection for device information
        self.SetupDiDestroyDeviceInfoList = \
            self.setupapi.SetupDiDestroyDeviceInfoList
        self.SetupDiDestroyDeviceInfoList.argtypes = [self.HDEVINFO]
        self.SetupDiDestroyDeviceInfoList.restype = BOOL
        # garbage collection for registry key
        self.advapi32 = ctypes.windll.LoadLibrary("Advapi32")
        self.RegCloseKey = self.advapi32.RegCloseKey
        self.RegCloseKey.argtypes = [HKEY]
        self.RegCloseKey.restype = LONG
        # misc constants for API functions
        self.DIGCF_PRESENT = 2  # for Step 2 function - to return only devices
        # that are currently present in a system
        self.DIGCF_DEVICEINTERFACE = 16
        # next constants are for step 4
        self.DICS_FLAG_GLOBAL = 1  # specifies that we need global
        # configuration information (not specific to a particular hardware
        # profile
        self.DIREG_DEV = 0x00000001  # Open a hardware key for the device
        self.KEY_READ = 0x20019  # need key for read-only mode

        self.GUIDs = (self.GUID * 8)()  # so far only seen one used, so hope
        # 8 are enough...
        self.guids_size = DWORD()
Ejemplo n.º 13
0
def set_vcp_feature(monitor, code, value):
    """Sends a DDC command to the specified monitor.
    """
    if not windll.dxva2.SetVCPFeature(HANDLE(monitor), BYTE(code),
                                      DWORD(value)):
        raise WinError()
Ejemplo n.º 14
0
 def WriteFile(handle, data, ol=None):
     c_written = DWORD()
     success = ctypes.windll.kernel32.WriteFile(
         handle, ctypes.create_string_buffer(encode(data)), len(data),
         ctypes.byref(c_written), ol)
     return ctypes.windll.kernel32.GetLastError(), c_written.value
Ejemplo n.º 15
0
def GetProductInfo(dwOSMajorVersion=5, dwOSMinorVersion=0, dwSpMajorVersion=0, dwSpMinorVersion=0):
    product_type = DWORD(0)
    from xpra.platform.win32.common import GetProductInfo as k32GetProductInfo
    v = k32GetProductInfo(dwOSMajorVersion, dwOSMinorVersion, dwSpMajorVersion, dwSpMinorVersion, byref(product_type))
    log("GetProductInfo(%i, %i, %i, %i)=%i product_type=%s", dwOSMajorVersion, dwOSMinorVersion, dwSpMajorVersion, dwSpMinorVersion, v, hex(product_type.value))
    return bool(v)
Ejemplo n.º 16
0
def set_monitor_brightness(monitor, brightness):
    if not SetMonitorBrightness(monitor, DWORD(brightness)):
        raise WinError()
Ejemplo n.º 17
0
def listComPorts(onlyAvailable=True):
	"""List com ports on the system.
	@param onlyAvailable: Only return ports that are currently available.
	@type onlyAvailable: bool
	@return: Dicts including keys of port, friendlyName and hardwareID.
	@rtype: generator of dict
	"""
	flags = DIGCF_DEVICEINTERFACE
	if onlyAvailable:
		flags |= DIGCF_PRESENT

	buf = ctypes.create_unicode_buffer(1024)
	g_hdi = SetupDiGetClassDevs(ctypes.byref(GUID_CLASS_COMPORT), None, NULL, flags)
	try:
		for dwIndex in xrange(256):
			entry = {}
			did = SP_DEVICE_INTERFACE_DATA()
			did.cbSize = ctypes.sizeof(did)

			if not SetupDiEnumDeviceInterfaces(
				g_hdi,
				None,
				ctypes.byref(GUID_CLASS_COMPORT),
				dwIndex,
				ctypes.byref(did)
			):
				if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS:
					raise ctypes.WinError()
				break

			dwNeeded = DWORD()
			# get the size
			if not SetupDiGetDeviceInterfaceDetail(
				g_hdi,
				ctypes.byref(did),
				None, 0, ctypes.byref(dwNeeded),
				None
			):
				# Ignore ERROR_INSUFFICIENT_BUFFER
				if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
					raise ctypes.WinError()
			# allocate buffer
			class SP_DEVICE_INTERFACE_DETAIL_DATA_W(ctypes.Structure):
				_fields_ = (
					('cbSize', DWORD),
					('DevicePath', WCHAR*(dwNeeded.value - ctypes.sizeof(DWORD))),
				)
				def __str__(self):
					return "DevicePath:%s" % (self.DevicePath,)
			idd = SP_DEVICE_INTERFACE_DETAIL_DATA_W()
			idd.cbSize = SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_W
			devinfo = SP_DEVINFO_DATA()
			devinfo.cbSize = ctypes.sizeof(devinfo)
			if not SetupDiGetDeviceInterfaceDetail(
				g_hdi,
				ctypes.byref(did),
				ctypes.byref(idd), dwNeeded, None,
				ctypes.byref(devinfo)
			):
				raise ctypes.WinError()

			# hardware ID
			if not SetupDiGetDeviceRegistryProperty(
				g_hdi,
				ctypes.byref(devinfo),
				SPDRP_HARDWAREID,
				None,
				ctypes.byref(buf), ctypes.sizeof(buf) - 1,
				None
			):
				# Ignore ERROR_INSUFFICIENT_BUFFER
				if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
					raise ctypes.WinError()
			else:
				hwID = entry["hardwareID"] = buf.value

			regKey = ctypes.windll.setupapi.SetupDiOpenDevRegKey(g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, winreg.KEY_READ)
			try:
				try:
					port = entry["port"] = winreg.QueryValueEx(regKey, "PortName")[0]
				except WindowsError:
					# #6015: In some rare cases, this value doesn't exist.
					log.debugWarning("No PortName value for hardware ID %s" % hwID)
					continue
				if not port:
					log.debugWarning("Empty PortName value for hardware ID %s" % hwID)
					continue
				if hwID.startswith("BTHENUM\\"):
					# This is a Microsoft bluetooth port.
					try:
						addr = winreg.QueryValueEx(regKey, "Bluetooth_UniqueID")[0].split("#", 1)[1].split("_", 1)[0]
						addr = int(addr, 16)
						entry["bluetoothAddress"] = addr
						if addr:
							entry["bluetoothName"] = getBluetoothDeviceInfo(addr).szName
					except:
						pass
				elif hwID == r"Bluetooth\0004&0002":
					# This is a Toshiba bluetooth port.
					try:
						entry["bluetoothAddress"], entry["bluetoothName"] = getToshibaBluetoothPortInfo(port)
					except:
						pass
				elif hwID == r"{95C7A0A0-3094-11D7-A202-00508B9D7D5A}\BLUETOOTHPORT":
					try:
						entry["bluetoothAddress"], entry["bluetoothName"] = getWidcommBluetoothPortInfo(port)
					except:
						pass
				elif "USB" in hwID or "FTDIBUS" in hwID:
					usbIDStart = hwID.find("VID_")
					if usbIDStart==-1:
						continue
					usbID = entry['usbID'] = hwID[usbIDStart:usbIDStart+17] # VID_xxxx&PID_xxxx
			finally:
				ctypes.windll.advapi32.RegCloseKey(regKey)

			# friendly name
			if not SetupDiGetDeviceRegistryProperty(
				g_hdi,
				ctypes.byref(devinfo),
				SPDRP_FRIENDLYNAME,
				None,
				ctypes.byref(buf), ctypes.sizeof(buf) - 1,
				None
			):
				# #6007: SPDRP_FRIENDLYNAME sometimes doesn't exist/isn't valid.
				log.debugWarning("Couldn't get SPDRP_FRIENDLYNAME for %r: %s" % (port, ctypes.WinError()))
				entry["friendlyName"] = port
			else:
				entry["friendlyName"] = buf.value

			if _isDebug():
				log.debug("%r" % entry)
			yield entry

	finally:
		SetupDiDestroyDeviceInfoList(g_hdi)
	if _isDebug():
		log.debug("Finished listing com ports")
Ejemplo n.º 18
0
def set_monitor_contrast(monitor, brightness):
    if not SetMonitorContrast(monitor, DWORD(brightness)):
        raise WinError()
Ejemplo n.º 19
0
def listHidDevices(onlyAvailable=True):
	"""List HID devices on the system.
	@param onlyAvailable: Only return devices that are currently available.
	@type onlyAvailable: bool
	@return: Generates dicts including keys such as hardwareID,
		usbID (in the form "VID_xxxx&PID_xxxx")
		and devicePath.
	@rtype: generator of dict
	"""
	global _hidGuid
	if not _hidGuid:
		_hidGuid = GUID()
		ctypes.windll.hid.HidD_GetHidGuid(ctypes.byref(_hidGuid))

	flags = DIGCF_DEVICEINTERFACE
	if onlyAvailable:
		flags |= DIGCF_PRESENT

	buf = ctypes.create_unicode_buffer(1024)
	g_hdi = SetupDiGetClassDevs(_hidGuid, None, NULL, flags)
	try:
		for dwIndex in xrange(256):
			did = SP_DEVICE_INTERFACE_DATA()
			did.cbSize = ctypes.sizeof(did)

			if not SetupDiEnumDeviceInterfaces(
				g_hdi,
				None,
				_hidGuid,
				dwIndex,
				ctypes.byref(did)
			):
				if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS:
					raise ctypes.WinError()
				break

			dwNeeded = DWORD()
			# get the size
			if not SetupDiGetDeviceInterfaceDetail(
				g_hdi,
				ctypes.byref(did),
				None, 0, ctypes.byref(dwNeeded),
				None
			):
				# Ignore ERROR_INSUFFICIENT_BUFFER
				if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
					raise ctypes.WinError()
			# allocate buffer
			class SP_DEVICE_INTERFACE_DETAIL_DATA_W(ctypes.Structure):
				_fields_ = (
					('cbSize', DWORD),
					('DevicePath', WCHAR*(dwNeeded.value - ctypes.sizeof(DWORD))),
				)
				def __str__(self):
					return "DevicePath:%s" % (self.DevicePath,)
			idd = SP_DEVICE_INTERFACE_DETAIL_DATA_W()
			idd.cbSize = SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_W
			devinfo = SP_DEVINFO_DATA()
			devinfo.cbSize = ctypes.sizeof(devinfo)
			if not SetupDiGetDeviceInterfaceDetail(
				g_hdi,
				ctypes.byref(did),
				ctypes.byref(idd), dwNeeded, None,
				ctypes.byref(devinfo)
			):
				raise ctypes.WinError()

			# hardware ID
			if not SetupDiGetDeviceRegistryProperty(
				g_hdi,
				ctypes.byref(devinfo),
				SPDRP_HARDWAREID,
				None,
				ctypes.byref(buf), ctypes.sizeof(buf) - 1,
				None
			):
				# Ignore ERROR_INSUFFICIENT_BUFFER
				if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
					raise ctypes.WinError()
			else:
				hwId = buf.value
				info = _getHidInfo(hwId, idd.DevicePath)
				if _isDebug():
					log.debug("%r" % info)
				yield info
	finally:
		SetupDiDestroyDeviceInfoList(g_hdi)
	if _isDebug():
		log.debug("Finished listing HID devices")
Ejemplo n.º 20
0
def _elevate_win(args=None):
    if windll.shell32.IsUserAnAdmin() and args is None:
        return
    # Constant definitions

    args = args.split(" ") if args is not None else sys.argv

    SEE_MASK_NOCLOSEPROCESS = 0x00000040
    SEE_MASK_NO_CONSOLE = 0x00008000

    class ShellExecuteInfo(ctypes.Structure):
        _fields_ = [('cbSize', DWORD), ('fMask', c_ulong), ('hwnd', HWND),
                    ('lpVerb', c_char_p), ('lpFile', c_char_p),
                    ('lpParameters', c_char_p), ('lpDirectory', c_char_p),
                    ('nShow', c_int), ('hInstApp', HINSTANCE),
                    ('lpIDList', c_void_p), ('lpClass', c_char_p),
                    ('hKeyClass', HKEY), ('dwHotKey', DWORD),
                    ('hIcon', HANDLE), ('hProcess', HANDLE)]

        def __init__(self, **kw):
            super(ShellExecuteInfo, self).__init__()
            self.cbSize = ctypes.sizeof(self)
            for field_name, field_value in kw.items():
                setattr(self, field_name, field_value)

    PShellExecuteInfo = POINTER(ShellExecuteInfo)

    # Function definitions

    ShellExecuteEx = windll.shell32.ShellExecuteExA
    ShellExecuteEx.argtypes = (PShellExecuteInfo, )
    ShellExecuteEx.restype = BOOL

    WaitForSingleObject = windll.kernel32.WaitForSingleObject
    WaitForSingleObject.argtypes = (HANDLE, DWORD)
    WaitForSingleObject.restype = DWORD

    CloseHandle = windll.kernel32.CloseHandle
    CloseHandle.argtypes = (HANDLE, )
    CloseHandle.restype = BOOL

    params = ShellExecuteInfo(
        fMask=SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE,
        hwnd=None,
        lpVerb=b'runas',
        lpFile=args[0].encode('cp1252'),
        lpParameters=subprocess.list2cmdline(args[1:]).encode('cp1252'),
        nShow=0)

    if not ShellExecuteEx(ctypes.byref(params)):
        sys.exit(1)

    handle = params.hProcess
    ret = DWORD()
    WaitForSingleObject(handle, -1)

    if windll.kernel32.GetExitCodeProcess(handle, ctypes.byref(ret)) == 0:
        sys.exit(1)

    CloseHandle(handle)
    sys.exit(ret.value)
Ejemplo n.º 21
0
    def __init__(self,
                 mode="both",
                 redirect_ports=(80, 443),
                 custom_filter=None,
                 proxy_addr=False,
                 proxy_port=8080,
                 api_host="localhost",
                 api_port=PROXY_API_PORT,
                 cache_size=65536):
        """
        :param mode: Redirection operation mode: "forward" to only redirect forwarded packets, "local" to only redirect
        packets originating from the local machine, "both" to redirect both.
        :param redirect_ports: if the destination port is in this tuple, the requests are redirected to the proxy.
        :param custom_filter: specify a custom WinDivert filter to select packets that should be intercepted. Overrides
        redirect_ports setting.
        :param proxy_addr: IP address of the proxy (IP within a network, 127.0.0.1 does not work). By default,
        this is detected automatically.
        :param proxy_port: Port the proxy is listenting on.
        :param api_host: Host the forward module API is listening on.
        :param api_port: Port the forward module API is listening on.
        :param cache_size: Maximum number of connection tuples that are stored. Only relevant in very high
        load scenarios.
        """
        if proxy_port in redirect_ports:
            raise ValueError("The proxy port must not be a redirect port.")

        if not proxy_addr:
            # Auto-Detect local IP.
            # https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(("8.8.8.8", 80))
            proxy_addr = s.getsockname()[0]
            s.close()

        self.mode = mode
        self.proxy_addr, self.proxy_port = proxy_addr, proxy_port
        self.connection_cache_size = cache_size

        self.client_server_map = OrderedDict()

        self.api = APIServer(self, (api_host, api_port), APIRequestHandler)
        self.api_thread = threading.Thread(target=self.api.serve_forever)
        self.api_thread.daemon = True

        self.driver = WinDivert()
        self.driver.register()

        self.request_filter = custom_filter or " or ".join(
            ("tcp.DstPort == %d" % p) for p in redirect_ports)
        self.request_forward_handle = None
        self.request_forward_thread = threading.Thread(
            target=self.request_forward)
        self.request_forward_thread.daemon = True

        self.addr_pid_map = dict()
        self.trusted_pids = set()
        self.tcptable2 = MIB_TCPTABLE2(0)
        self.tcptable2_size = DWORD(0)
        self.request_local_handle = None
        self.request_local_thread = threading.Thread(target=self.request_local)
        self.request_local_thread.daemon = True

        # The proxy server responds to the client. To the client,
        # this response should look like it has been sent by the real target
        self.response_filter = "outbound and tcp.SrcPort == %d" % proxy_port
        self.response_handle = None
        self.response_thread = threading.Thread(target=self.response)
        self.response_thread.daemon = True

        self.icmp_handle = None
Ejemplo n.º 22
0
 def finish_connection(self, timeout):
     if not GetOverlappedResultEx(self._handle, self._overlapped,
             ctypes.byref(DWORD(0)), timeout*1000, True):
         raise ctypes.WinError(ctypes.get_last_error())
Ejemplo n.º 23
0
    # and TZOmegaTZIOY
    # <http://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462>.
    try:
        # <http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
        # HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
        # returns INVALID_HANDLE_VALUE, NULL, or a valid handle
        #
        # <http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx>
        # DWORD WINAPI GetFileType(DWORD hFile);
        #
        # <http://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx>
        # BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);

        GetStdHandle = WINFUNCTYPE(HANDLE,
                                   DWORD)(("GetStdHandle", windll.kernel32))
        STD_OUTPUT_HANDLE = DWORD(-11)
        STD_ERROR_HANDLE = DWORD(-12)
        GetFileType = WINFUNCTYPE(DWORD,
                                  DWORD)(("GetFileType", windll.kernel32))
        FILE_TYPE_CHAR = 0x0002
        FILE_TYPE_REMOTE = 0x8000
        GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
            ("GetConsoleMode", windll.kernel32))
        INVALID_HANDLE_VALUE = DWORD(-1).value

        def not_a_console(handle):
            if handle == INVALID_HANDLE_VALUE or handle is None:
                return True
            return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
                    or GetConsoleMode(handle, byref(DWORD())) == 0)
Ejemplo n.º 24
0
def get_unicode_console():
    """
    Get Unicode console objects.

    @return: stdin, stdout, stderr, argv
    @rtype: tuple
    """
    # Make Unicode console output work independently of the current code page.
    # This also fixes <http://bugs.python.org/issue1602>.
    # Credit to Michael Kaplan
    # <http://blogs.msdn.com/b/michkap/archive/2010/04/07/9989346.aspx>
    # and TZOmegaTZIOY
    # <https://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462>.

    global stdin, stdout, stderr, argv

    if not OSWIN32:
        return stdin, stdout, stderr, argv

    try:
        # <https://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
        # HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
        # returns INVALID_HANDLE_VALUE, NULL, or a valid handle
        #
        # <https://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx>
        # DWORD WINAPI GetFileType(DWORD hFile);
        #
        # <https://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx>
        # BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);

        GetStdHandle = WINFUNCTYPE(HANDLE,
                                   DWORD)(('GetStdHandle', windll.kernel32))
        STD_INPUT_HANDLE = DWORD(-10)
        STD_OUTPUT_HANDLE = DWORD(-11)
        STD_ERROR_HANDLE = DWORD(-12)
        GetFileType = WINFUNCTYPE(DWORD,
                                  DWORD)(('GetFileType', windll.kernel32))
        FILE_TYPE_CHAR = 0x0002
        FILE_TYPE_REMOTE = 0x8000
        GetConsoleMode = (WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
            ("GetConsoleMode", windll.kernel32)))
        INVALID_HANDLE_VALUE = DWORD(-1).value

        def not_a_console(handle):
            """Return whether the handle is not to a console."""
            if handle == INVALID_HANDLE_VALUE or handle is None:
                return True
            return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
                    or GetConsoleMode(handle, byref(DWORD())) == 0)

        old_stdin_fileno = old_fileno('in')
        old_stdout_fileno = old_fileno('out')
        old_stderr_fileno = old_fileno('err')

        STDIN_FILENO = 0
        STDOUT_FILENO = 1
        STDERR_FILENO = 2
        real_stdin = (old_stdin_fileno == STDIN_FILENO)
        real_stdout = (old_stdout_fileno == STDOUT_FILENO)
        real_stderr = (old_stderr_fileno == STDERR_FILENO)

        if real_stdin:
            hStdin = GetStdHandle(STD_INPUT_HANDLE)
            if not_a_console(hStdin):
                real_stdin = False

        if real_stdout:
            hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
            force_truetype_console(hStdout)
            if not_a_console(hStdout):
                real_stdout = False

        if real_stderr:
            hStderr = GetStdHandle(STD_ERROR_HANDLE)
            force_truetype_console(hStderr)
            if not_a_console(hStderr):
                real_stderr = False

        if real_stdout or real_stderr:
            if real_stdin:
                stdin = UnicodeInput(hStdin, name='<Unicode console stdin>')

            if real_stdout:
                stdout = UnicodeOutput(hStdout, sys.stdout, STDOUT_FILENO,
                                       '<Unicode console stdout>')
            else:
                stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno,
                                       '<Unicode redirected stdout>')

            if real_stderr:
                stderr = UnicodeOutput(hStderr, sys.stderr, STDERR_FILENO,
                                       '<Unicode console stderr>')
            else:
                stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno,
                                       '<Unicode redirected stderr>')
    except Exception as e:
        _complain(
            'exception {!r} while fixing up sys.stdout and sys.stderr'.format(
                e))

    if PY3:
        # no need to work around issue2128 since it's a Python 2 only issue
        return stdin, stdout, stderr, argv

    # While we're at it, let's unmangle the command-line arguments:

    # This works around <http://bugs.python.org/issue2128>.
    GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32))
    CommandLineToArgvW = (WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR,
                                      POINTER(c_int))(("CommandLineToArgvW",
                                                       windll.shell32)))

    argc = c_int(0)
    argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))

    argv = [argv_unicode[i].encode('utf-8') for i in range(0, argc.value)]

    if not hasattr(sys, 'frozen'):
        # If this is an executable produced by py2exe or bbfreeze, then it will
        # have been invoked directly. Otherwise, unicode_argv[0] is the Python
        # interpreter, so skip that.
        argv = argv[1:]

        # Also skip option arguments to the Python interpreter.
        while len(argv) > 0:
            arg = argv[0]
            if not arg.startswith(b"-") or arg == u"-":
                break
            argv = argv[1:]
            if arg == u'-m':
                # sys.argv[0] should really be the absolute path of the module
                # source, but never mind
                break
            if arg == u'-c':
                argv[0] = u'-c'
                break

    if argv == []:
        argv = [u'']

    return stdin, stdout, stderr, argv
Ejemplo n.º 25
0
def get_parent_serial_number(child_devinst,
                             child_vid,
                             child_pid,
                             depth=0,
                             last_serial_number=None):
    """ Get the serial number of the parent of a device.

    Args:
        child_devinst: The device instance handle to get the parent serial number of.
        child_vid: The vendor ID of the child device.
        child_pid: The product ID of the child device.
        depth: The current iteration depth of the USB device tree.
    """

    # If the traversal depth is beyond the max, abandon attempting to find the serial number.
    if depth > MAX_USB_DEVICE_TREE_TRAVERSAL_DEPTH:
        return '' if not last_serial_number else last_serial_number

    # Get the parent device instance.
    devinst = DWORD()
    ret = CM_Get_Parent(ctypes.byref(devinst), child_devinst, 0)

    if ret:
        win_error = CM_MapCrToWin32Err(DWORD(ret), DWORD(0))

        # If there is no parent available, the child was the root device. We cannot traverse
        # further.
        if win_error == ERROR_NOT_FOUND:
            return '' if not last_serial_number else last_serial_number

        raise ctypes.WinError(win_error)

    # Get the ID of the parent device and parse it for vendor ID, product ID, and serial number.
    parentHardwareID = ctypes.create_unicode_buffer(250)

    ret = CM_Get_Device_IDW(devinst, parentHardwareID,
                            ctypes.sizeof(parentHardwareID) - 1, 0)

    if ret:
        raise ctypes.WinError(CM_MapCrToWin32Err(DWORD(ret), DWORD(0)))

    parentHardwareID_str = parentHardwareID.value
    m = re.search(
        r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(.*))?',
        parentHardwareID_str, re.I)

    # return early if we have no matches (likely malformed serial, traversed too far)
    if not m:
        return '' if not last_serial_number else last_serial_number

    vid = None
    pid = None
    serial_number = None
    if m.group(1):
        vid = int(m.group(1), 16)
    if m.group(3):
        pid = int(m.group(3), 16)
    if m.group(7):
        serial_number = m.group(7)

    # store what we found as a fallback for malformed serial values up the chain
    found_serial_number = serial_number

    # Check that the USB serial number only contains alphanumeric characters. It may be a windows
    # device ID (ephemeral ID).
    if serial_number and not re.match(r'^\w+$', serial_number):
        serial_number = None

    if not vid or not pid:
        # If pid and vid are not available at this device level, continue to the parent.
        return get_parent_serial_number(devinst, child_vid, child_pid,
                                        depth + 1, found_serial_number)

    if pid != child_pid or vid != child_vid:
        # If the VID or PID has changed, we are no longer looking at the same physical device. The
        # serial number is unknown.
        return '' if not last_serial_number else last_serial_number

    # In this case, the vid and pid of the parent device are identical to the child. However, if
    # there still isn't a serial number available, continue to the next parent.
    if not serial_number:
        return get_parent_serial_number(devinst, child_vid, child_pid,
                                        depth + 1, found_serial_number)

    # Finally, the VID and PID are identical to the child and a serial number is present, so return
    # it.
    return serial_number
Ejemplo n.º 26
0
    def readlink(path: Union[str, pathlib.Path]) -> Union[str, pathlib.WindowsPath]:
        # FILE_FLAG_OPEN_REPARSE_POINT alone is not enough if 'path'
        # is a symbolic link to a directory or a NTFS junction.
        # We need to set FILE_FLAG_BACKUP_SEMANTICS as well.
        # See https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea

        # description from _winapi.c:601
        # /* REPARSE_DATA_BUFFER usage is heavily under-documented, especially for
        #  junction points. Here's what I've learned along the way:
        #  - A junction point has two components: a print name and a substitute
        #  name. They both describe the link target, but the substitute name is
        #  the physical target and the print name is shown in directory listings.
        #  - The print name must be a native name, prefixed with "\??\".
        #  - Both names are stored after each other in the same buffer (the
        #  PathBuffer) and both must be NUL-terminated.
        #  - There are four members defining their respective offset and length
        #  inside PathBuffer: SubstituteNameOffset, SubstituteNameLength,
        #  PrintNameOffset and PrintNameLength.
        #  - The total size we need to allocate for the REPARSE_DATA_BUFFER, thus,
        #  is the sum of:
        #  - the fixed header size (REPARSE_DATA_BUFFER_HEADER_SIZE)
        #  - the size of the MountPointReparseBuffer member without the PathBuffer
        #  - the size of the prefix ("\??\") in bytes
        #  - the size of the print name in bytes
        #  - the size of the substitute name in bytes
        #  - the size of two NUL terminators in bytes */

        target_is_path = isinstance(path, pathlib.Path)
        target = str(path)
        CreateFileW.argtypes = [LPWSTR, DWORD, DWORD, LPVOID, DWORD, DWORD, HANDLE]
        CreateFileW.restype = HANDLE
        DeviceIoControl.argtypes = [
            HANDLE,
            DWORD,
            LPVOID,
            DWORD,
            LPVOID,
            DWORD,
            LPDWORD,
            LPVOID,
        ]
        DeviceIoControl.restype = BOOL
        handle = HANDLE(
            CreateFileW(
                target,
                GENERIC_READ,
                0,
                None,
                OPEN_EXISTING,
                FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
                0,
            )
        )
        buf = ReparseBuffer()
        ret = DWORD(0)
        status = DeviceIoControl(
            handle,
            FSCTL_GET_REPARSE_POINT,
            None,
            0,
            ctypes.byref(buf),
            MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
            ctypes.byref(ret),
            None,
        )
        CloseHandle(handle)
        if not status:
            logger = getLogger(__file__)
            logger.error("Failed IOCTL access to REPARSE_POINT {})".format(target))
            raise ValueError("not a symbolic link or access permission violation")

        if buf.reparse_tag == IO_REPARSE_TAG_SYMLINK:
            offset = buf.substitute_name_offset
            ending = offset + buf.substitute_name_length
            rpath = bytearray(buf.symlink.path_buffer)[offset:ending].decode("UTF-16-LE")
        elif buf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT:
            offset = buf.substitute_name_offset
            ending = offset + buf.substitute_name_length
            rpath = bytearray(buf.mount.path_buffer)[offset:ending].decode("UTF-16-LE")
        else:
            raise ValueError("not a symbolic link")
        # on posixmodule.c:7859 in py38, we do that
        # ```
        # else if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
        # {
        #    name = (wchar_t *)((char*)rdb->MountPointReparseBuffer.PathBuffer +
        #                       rdb->MountPointReparseBuffer.SubstituteNameOffset);
        #    nameLen = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
        # }
        # else
        # {
        #    PyErr_SetString(PyExc_ValueError, "not a symbolic link");
        # }
        # if (nameLen > 4 && wcsncmp(name, L"\\??\\", 4) == 0) {
        #             /* Our buffer is mutable, so this is okay */
        #             name[1] = L'\\';
        #         }
        # ```
        # so substitute prefix here.
        if rpath.startswith("\\??\\"):
            rpath = "\\\\" + rpath[2:]
        if target_is_path:
            return pathlib.WindowsPath(rpath)
        else:
            return rpath
Ejemplo n.º 27
0
pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]

prototype = WINFUNCTYPE(c_int, c_int, POINTER(MARGINS))
params = (1, "hWnd", 0), (1, "pMarInset", MARGINS(-1, -1, -1, -1))
_DwmExtendFrameIntoClientArea = prototype(
    ("DwmExtendFrameIntoClientArea", windll.dwmapi), params)

prototype = WINFUNCTYPE(c_int, c_int, POINTER(DWM_BLURBEHIND))
params = (1, "hWnd", 0), (1, "pBlurBehind", 0)
_DwmEnableBlurBehindWindow = prototype(
    ("DwmEnableBlurBehindWindow", windll.dwmapi), params)

prototype = WINFUNCTYPE(c_int, POINTER(DWORD), POINTER(c_bool))
params = (2, "pcrColorization", DWORD(0)), (1, "pfOpaqueBlend", c_bool(False))
_DwmGetColorizationColor = prototype(
    ("DwmGetColorizationColor", windll.dwmapi), params)

prototype = WINFUNCTYPE(c_int, POINTER(c_bool))
params = (2, "pfEnabled", c_bool(False)),
_DwmIsCompositionEnabled = prototype(
    ("DwmIsCompositionEnabled", windll.dwmapi), params)

# Before we get started, see if we have the DWM functions.
has_dwm = hasattr(windll, 'dwmapi') and \
          hasattr(windll.dwmapi, 'DwmIsCompositionEnabled')


def DWM_is_composition_enabled():
    """
Ejemplo n.º 28
0
def fix_unicode_out():
    #code found here:
    #http://stackoverflow.com/a/3259271/428751
    import codecs
    from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int
    from ctypes.wintypes import BOOL, HANDLE, DWORD, LPWSTR, LPCWSTR, LPVOID

    original_stderr = sys.stderr

    # If any exception occurs in this code, we'll probably try to print it on stderr,
    # which makes for frustrating debugging if stderr is directed to our wrapper.
    # So be paranoid about catching errors and reporting them to original_stderr,
    # so that we can at least see them.
    def _complain(message):
        print >> original_stderr, message if isinstance(message,
                                                        str) else repr(message)

    # Work around <http://bugs.python.org/issue6058>.
    codecs.register(lambda name: codecs.lookup('utf-8')
                    if name == 'cp65001' else None)

    # Make Unicode console output work independently of the current code page.
    # This also fixes <http://bugs.python.org/issue1602>.
    # Credit to Michael Kaplan <http://blogs.msdn.com/b/michkap/archive/2010/04/07/9989346.aspx>
    # and TZOmegaTZIOY
    # <http://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462>.
    try:
        # <http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
        # HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
        # returns INVALID_HANDLE_VALUE, NULL, or a valid handle
        #
        # <http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx>
        # DWORD WINAPI GetFileType(DWORD hFile);
        #
        # <http://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx>
        # BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);

        GetStdHandle = WINFUNCTYPE(HANDLE,
                                   DWORD)(("GetStdHandle", windll.kernel32))
        STD_OUTPUT_HANDLE = DWORD(-11)
        STD_ERROR_HANDLE = DWORD(-12)
        GetFileType = WINFUNCTYPE(DWORD,
                                  DWORD)(("GetFileType", windll.kernel32))
        FILE_TYPE_CHAR = 0x0002
        FILE_TYPE_REMOTE = 0x8000
        GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
            ("GetConsoleMode", windll.kernel32))
        INVALID_HANDLE_VALUE = DWORD(-1).value

        def not_a_console(handle):
            if handle == INVALID_HANDLE_VALUE or handle is None:
                return True
            return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
                    or GetConsoleMode(handle, byref(DWORD())) == 0)

        old_stdout_fileno = None
        old_stderr_fileno = None
        if hasattr(sys.stdout, 'fileno'):
            old_stdout_fileno = sys.stdout.fileno()
        if hasattr(sys.stderr, 'fileno'):
            old_stderr_fileno = sys.stderr.fileno()

        STDOUT_FILENO = 1
        STDERR_FILENO = 2
        real_stdout = (old_stdout_fileno == STDOUT_FILENO)
        real_stderr = (old_stderr_fileno == STDERR_FILENO)

        if real_stdout:
            hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
            if not_a_console(hStdout):
                real_stdout = False

        if real_stderr:
            hStderr = GetStdHandle(STD_ERROR_HANDLE)
            if not_a_console(hStderr):
                real_stderr = False

        if real_stdout or real_stderr:
            # BOOL WINAPI WriteConsoleW(HANDLE hOutput, LPWSTR lpBuffer, DWORD nChars,
            #                           LPDWORD lpCharsWritten, LPVOID lpReserved);

            WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD,
                                        POINTER(DWORD), LPVOID)(
                                            ("WriteConsoleW", windll.kernel32))

            class UnicodeOutput:
                def __init__(self, hConsole, stream, fileno, name):
                    self._hConsole = hConsole
                    self._stream = stream
                    self._fileno = fileno
                    self.closed = False
                    self.softspace = False
                    self.mode = 'w'
                    self.encoding = 'utf-8'
                    self.name = name
                    self.flush()

                def isatty(self):
                    return False

                def close(self):
                    # don't really close the handle, that would only cause problems
                    self.closed = True

                def fileno(self):
                    return self._fileno

                def flush(self):
                    if self._hConsole is None:
                        try:
                            self._stream.flush()
                        except Exception as e:
                            _complain("%s.flush: %r from %r" %
                                      (self.name, e, self._stream))
                            raise

                def write(self, text):
                    try:
                        if self._hConsole is None:
                            if isinstance(text, unicode):
                                text = text.encode('utf-8')
                            self._stream.write(text)
                        else:
                            if not isinstance(text, unicode):
                                text = str(text).decode('utf-8')
                            remaining = len(text)
                            while remaining:
                                n = DWORD(0)
                                # There is a shorter-than-documented limitation on the
                                # length of the string passed to WriteConsoleW (see
                                # <http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232>.
                                retval = WriteConsoleW(self._hConsole, text,
                                                       min(remaining, 10000),
                                                       byref(n), None)
                                if retval == 0 or n.value == 0:
                                    raise IOError(
                                        "WriteConsoleW returned %r, n.value = %r"
                                        % (retval, n.value))
                                remaining -= n.value
                                if not remaining:
                                    break
                                text = text[n.value:]
                    except Exception as e:
                        _complain("%s.write: %r" % (self.name, e))
                        raise

                def writelines(self, lines):
                    try:
                        for line in lines:
                            self.write(line)
                    except Exception as e:
                        _complain("%s.writelines: %r" % (self.name, e))
                        raise

            if real_stdout:
                sys.stdout = UnicodeOutput(hStdout, None, STDOUT_FILENO,
                                           '<Unicode console stdout>')
            else:
                sys.stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno,
                                           '<Unicode redirected stdout>')

            if real_stderr:
                sys.stderr = UnicodeOutput(hStderr, None, STDERR_FILENO,
                                           '<Unicode console stderr>')
            else:
                sys.stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno,
                                           '<Unicode redirected stderr>')
    except Exception as e:
        _complain("exception %r while fixing up sys.stdout and sys.stderr" %
                  (e, ))
Ejemplo n.º 29
0
    def _shutdown_with_windows_restart_manager(self, pid):
        """Shut down a process using the Windows Restart Manager.

        When Windows shuts down, it uses a protocol including the
        WM_QUERYENDSESSION and WM_ENDSESSION messages to give
        applications a chance to shut down safely. The best way to
        simulate this is via the Restart Manager, which allows a process
        (such as an installer) to use the same mechanism to shut down
        any other processes which are using registered resources.

        This function starts a Restart Manager session, registers the
        process as a resource, and shuts down the process.

        :param pid: The process id (int) of the process to shutdown

        :raises: WindowsError: if a Windows API call fails
        """
        import ctypes
        from ctypes import Structure, POINTER, WINFUNCTYPE, windll, pointer, WinError
        from ctypes.wintypes import HANDLE, DWORD, BOOL, WCHAR, UINT, ULONG, LPCWSTR

        # set up Windows SDK types
        OpenProcess = windll.kernel32.OpenProcess
        OpenProcess.restype = HANDLE
        OpenProcess.argtypes = [
            DWORD,  # dwDesiredAccess
            BOOL,  # bInheritHandle
            DWORD,
        ]  # dwProcessId
        PROCESS_QUERY_INFORMATION = 0x0400

        class FILETIME(Structure):
            _fields_ = [("dwLowDateTime", DWORD), ("dwHighDateTime", DWORD)]

        LPFILETIME = POINTER(FILETIME)

        GetProcessTimes = windll.kernel32.GetProcessTimes
        GetProcessTimes.restype = BOOL
        GetProcessTimes.argtypes = [
            HANDLE,  # hProcess
            LPFILETIME,  # lpCreationTime
            LPFILETIME,  # lpExitTime
            LPFILETIME,  # lpKernelTime
            LPFILETIME,
        ]  # lpUserTime

        ERROR_SUCCESS = 0

        class RM_UNIQUE_PROCESS(Structure):
            _fields_ = [("dwProcessId", DWORD), ("ProcessStartTime", FILETIME)]

        RmStartSession = windll.rstrtmgr.RmStartSession
        RmStartSession.restype = DWORD
        RmStartSession.argtypes = [
            POINTER(DWORD),  # pSessionHandle
            DWORD,  # dwSessionFlags
            POINTER(WCHAR),
        ]  # strSessionKey

        class GUID(ctypes.Structure):
            _fields_ = [
                ("Data1", ctypes.c_ulong),
                ("Data2", ctypes.c_ushort),
                ("Data3", ctypes.c_ushort),
                ("Data4", ctypes.c_ubyte * 8),
            ]

        CCH_RM_SESSION_KEY = ctypes.sizeof(GUID) * 2

        RmRegisterResources = windll.rstrtmgr.RmRegisterResources
        RmRegisterResources.restype = DWORD
        RmRegisterResources.argtypes = [
            DWORD,  # dwSessionHandle
            UINT,  # nFiles
            POINTER(LPCWSTR),  # rgsFilenames
            UINT,  # nApplications
            POINTER(RM_UNIQUE_PROCESS),  # rgApplications
            UINT,  # nServices
            POINTER(LPCWSTR),
        ]  # rgsServiceNames

        RM_WRITE_STATUS_CALLBACK = WINFUNCTYPE(None, UINT)
        RmShutdown = windll.rstrtmgr.RmShutdown
        RmShutdown.restype = DWORD
        RmShutdown.argtypes = [
            DWORD,  # dwSessionHandle
            ULONG,  # lActionFlags
            RM_WRITE_STATUS_CALLBACK,
        ]  # fnStatus

        RmEndSession = windll.rstrtmgr.RmEndSession
        RmEndSession.restype = DWORD
        RmEndSession.argtypes = [DWORD]  # dwSessionHandle

        # Get the info needed to uniquely identify the process
        hProc = OpenProcess(PROCESS_QUERY_INFORMATION, False, pid)
        if not hProc:
            raise WinError()

        creationTime = FILETIME()
        exitTime = FILETIME()
        kernelTime = FILETIME()
        userTime = FILETIME()
        if not GetProcessTimes(
                hProc,
                pointer(creationTime),
                pointer(exitTime),
                pointer(kernelTime),
                pointer(userTime),
        ):
            raise WinError()

        # Start the Restart Manager Session
        dwSessionHandle = DWORD()
        sessionKeyType = WCHAR * (CCH_RM_SESSION_KEY + 1)
        sessionKey = sessionKeyType()
        if RmStartSession(pointer(dwSessionHandle), 0,
                          sessionKey) != ERROR_SUCCESS:
            raise WinError()

        try:
            UProcs_count = 1
            UProcsArrayType = RM_UNIQUE_PROCESS * UProcs_count
            UProcs = UProcsArrayType(RM_UNIQUE_PROCESS(pid, creationTime))

            # Register the process as a resource
            if (RmRegisterResources(dwSessionHandle, 0, None, UProcs_count,
                                    UProcs, 0, None) != ERROR_SUCCESS):
                raise WinError()

            # Shut down all processes using registered resources
            if (RmShutdown(dwSessionHandle, 0,
                           ctypes.cast(None, RM_WRITE_STATUS_CALLBACK)) !=
                    ERROR_SUCCESS):
                raise WinError()

        finally:
            RmEndSession(dwSessionHandle)
Ejemplo n.º 30
0
def win32_unicode_console():
    import codecs
    from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int
    from ctypes.wintypes import BOOL, HANDLE, DWORD, LPWSTR, LPCWSTR, LPVOID

    original_stderr = sys.stderr

    # Output exceptions in this code to original_stderr, so that we can at least see them
    def _complain(message):
        original_stderr.write(message if isinstance(message, str) else repr(message))
        original_stderr.write('\n')

    codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)

    try:
        GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32))
        STD_OUTPUT_HANDLE = DWORD(-11)
        STD_ERROR_HANDLE = DWORD(-12)
        GetFileType = WINFUNCTYPE(DWORD, DWORD)(("GetFileType", windll.kernel32))
        FILE_TYPE_CHAR = 0x0002
        FILE_TYPE_REMOTE = 0x8000
        GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(("GetConsoleMode", windll.kernel32))
        INVALID_HANDLE_VALUE = DWORD(-1).value

        def not_a_console(handle):
            if handle == INVALID_HANDLE_VALUE or handle is None:
                return True
            return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
                    or GetConsoleMode(handle, byref(DWORD())) == 0)

        old_stdout_fileno = None
        old_stderr_fileno = None
        if hasattr(sys.stdout, 'fileno'):
            old_stdout_fileno = sys.stdout.fileno()
        if hasattr(sys.stderr, 'fileno'):
            old_stderr_fileno = sys.stderr.fileno()

        STDOUT_FILENO = 1
        STDERR_FILENO = 2
        real_stdout = (old_stdout_fileno == STDOUT_FILENO)
        real_stderr = (old_stderr_fileno == STDERR_FILENO)

        if real_stdout:
            hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
            if not_a_console(hStdout):
                real_stdout = False

        if real_stderr:
            hStderr = GetStdHandle(STD_ERROR_HANDLE)
            if not_a_console(hStderr):
                real_stderr = False

        if real_stdout or real_stderr:
            WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD), LPVOID)(("WriteConsoleW", windll.kernel32))

            class UnicodeOutput:
                def __init__(self, hConsole, stream, fileno, name):
                    self._hConsole = hConsole
                    self._stream = stream
                    self._fileno = fileno
                    self.closed = False
                    self.softspace = False
                    self.mode = 'w'
                    self.encoding = 'utf-8'
                    self.name = name
                    self.flush()

                def isatty(self):
                    return False

                def close(self):
                    # don't really close the handle, that would only cause problems
                    self.closed = True

                def fileno(self):
                    return self._fileno

                def flush(self):
                    if self._hConsole is None:
                        try:
                            self._stream.flush()
                        except Exception as e:
                            _complain("%s.flush: %r from %r" % (self.name, e, self._stream))
                            raise

                def write(self, text):
                    try:
                        if self._hConsole is None:
                            if not PY3K and isinstance(text, unicode):
                                text = text.encode('utf-8')
                            elif PY3K and isinstance(text, str):
                                text = text.encode('utf-8')
                            self._stream.write(text)
                        else:
                            if not PY3K and not isinstance(text, unicode):
                                text = str(text).decode('utf-8')
                            elif PY3K and not isinstance(text, str):
                                text = text.decode('utf-8')
                            remaining = len(text)
                            while remaining:
                                n = DWORD(0)
                                # There is a shorter-than-documented limitation on the
                                # length of the string passed to WriteConsoleW (see
                                # <http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232>.
                                retval = WriteConsoleW(self._hConsole, text, min(remaining, 10000), byref(n), None)
                                if retval == 0 or n.value == 0:
                                    raise IOError("WriteConsoleW returned %r, n.value = %r" % (retval, n.value))
                                remaining -= n.value
                                if not remaining:
                                    break
                                text = text[n.value:]
                    except Exception as e:
                        _complain("%s.write: %r" % (self.name, e))
                        raise

                def writelines(self, lines):
                    try:
                        for line in lines:
                            self.write(line)
                    except Exception as e:
                        _complain("%s.writelines: %r" % (self.name, e))
                        raise

            if real_stdout:
                sys.stdout = UnicodeOutput(hStdout, None, STDOUT_FILENO, '<Unicode console stdout>')
            else:
                sys.stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno, '<Unicode redirected stdout>')

            if real_stderr:
                sys.stderr = UnicodeOutput(hStderr, None, STDERR_FILENO, '<Unicode console stderr>')
            else:
                sys.stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno, '<Unicode redirected stderr>')
    except Exception as e:
        _complain("exception %r while fixing up sys.stdout and sys.stderr" % (e,))