def Enumerate():
    """See base class."""
    hid_guid = GUID()
    hid.HidD_GetHidGuid(ctypes.byref(hid_guid))

    devices = setupapi.SetupDiGetClassDevsA(
        ctypes.byref(hid_guid), None, None, 0x12)
    index = 0
    interface_info = DeviceInterfaceData()
    interface_info.cbSize = ctypes.sizeof(DeviceInterfaceData)  # pylint: disable=invalid-name

    out = []
    while True:
      result = setupapi.SetupDiEnumDeviceInterfaces(
          devices, 0, ctypes.byref(hid_guid), index,
          ctypes.byref(interface_info))
      index += 1
      if not result:
        break

      detail_len = wintypes.DWORD()
      result = setupapi.SetupDiGetDeviceInterfaceDetailA(
          devices, ctypes.byref(interface_info), None, 0,
          ctypes.byref(detail_len), None)

      detail_len = detail_len.value
      if detail_len == 0:
        # skip this device, some kind of error
        continue

      buf = ctypes.create_string_buffer(detail_len)
      interface_detail = DeviceInterfaceDetailData.from_buffer(buf)
      interface_detail.cbSize = ctypes.sizeof(DeviceInterfaceDetailData)

      result = setupapi.SetupDiGetDeviceInterfaceDetailA(
          devices, ctypes.byref(interface_info),
          ctypes.byref(interface_detail), detail_len, None, None)

      if not result:
        raise ctypes.WinError()

      descriptor = base.DeviceDescriptor()
      # This is a bit of a hack to work around a limitation of ctypes and
      # "header" structures that are common in windows.  DevicePath is a
      # ctypes array of length 1, but it is backed with a buffer that is much
      # longer and contains a null terminated string.  So, we read the null
      # terminated string off DevicePath here.  Per the comment above, the
      # alignment of this struct varies depending on architecture, but
      # in all cases the path string starts 1 DWORD into the structure.
      #
      # The path length is:
      #   length of detail buffer - header length (1 DWORD)
      path_len = detail_len - ctypes.sizeof(wintypes.DWORD)
      descriptor.path = ctypes.string_at(
          ctypes.addressof(interface_detail.DevicePath), path_len)

      device = None
      try:
        device = OpenDevice(descriptor.path, True)
      except WindowsError as e:  # pylint: disable=undefined-variable
        if e.winerror == ERROR_ACCESS_DENIED:  # Access Denied, e.g. a keyboard
          continue
        else:
          raise e

      try:
        FillDeviceAttributes(device, descriptor)
        FillDeviceCapabilities(device, descriptor)
        out.append(descriptor.ToPublicDict())
      finally:
        kernel32.CloseHandle(device)

    return out
See base class.