nsresult
sbWinDeviceHasInterface(DEVINST     aDevInst,
                        const GUID* aGUID,
                        bool*     aHasInterface)
{
  // Validate arguments.
  NS_ENSURE_ARG_POINTER(aGUID);
  NS_ENSURE_ARG_POINTER(aHasInterface);

  // Function variables.
  nsresult rv;

  // Set default result.
  *aHasInterface = PR_FALSE;

  // Get the device info set and set it up for auto-disposal.
  nsAutoString deviceInstanceID;
  rv = sbWinGetDeviceInstanceID(aDevInst, deviceInstanceID);
  NS_ENSURE_SUCCESS(rv, rv);
  HDEVINFO devInfo = SetupDiGetClassDevsW(aGUID,
                                          deviceInstanceID.get(),
                                          NULL,
                                          DIGCF_DEVICEINTERFACE);
  NS_ENSURE_TRUE(devInfo != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
  sbAutoHDEVINFO autoDevInfo(devInfo);

  // Get the device info for the device instance.  Device does not have the
  // interface if it does not have a device info data record.
  SP_DEVINFO_DATA devInfoData;
  rv = sbWinGetDevInfoData(aDevInst, devInfo, &devInfoData);
  if (NS_FAILED(rv))
    return NS_OK;

  // Get the device interface detail.  Device does not have the interface if it
  // does not have the interface detail.
  PSP_DEVICE_INTERFACE_DETAIL_DATA devIfDetailData;
  rv = sbWinGetDevInterfaceDetail(&devIfDetailData,
                                  devInfo,
                                  &devInfoData,
                                  aGUID);
  if (NS_FAILED(rv))
    return NS_OK;
  sbAutoNSMemPtr autoDevIfDetailData(devIfDetailData);

  // Device has the interface.
  *aHasInterface = PR_TRUE;

  return NS_OK;
}
nsresult
sbWinGetDevicePath(DEVINST     aDevInst,
                   const GUID* aGUID,
                   nsAString&  aDevicePath)
{
  // Validate arguments.
  NS_ENSURE_ARG_POINTER(aGUID);

  // Function variables.
  nsresult rv;

  // Get the device info set and set it up for auto-disposal.
  nsAutoString deviceInstanceID;
  rv = sbWinGetDeviceInstanceID(aDevInst, deviceInstanceID);
  NS_ENSURE_SUCCESS(rv, rv);
  HDEVINFO devInfo = SetupDiGetClassDevsW(aGUID,
                                          deviceInstanceID.get(),
                                          NULL,
                                          DIGCF_DEVICEINTERFACE);
  NS_ENSURE_TRUE(devInfo != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
  sbAutoHDEVINFO autoDevInfo(devInfo);

  // Get the device info for the device instance.
  SP_DEVINFO_DATA devInfoData;
  rv = sbWinGetDevInfoData(aDevInst, devInfo, &devInfoData);
  NS_ENSURE_SUCCESS(rv, rv);

  // Get the device interface detail data for the device instance.
  PSP_DEVICE_INTERFACE_DETAIL_DATA devIfDetailData;
  rv = sbWinGetDevInterfaceDetail(&devIfDetailData,
                                  devInfo,
                                  &devInfoData,
                                  aGUID);
  NS_ENSURE_SUCCESS(rv, rv);
  sbAutoNSMemPtr autoDevIfDetailData(devIfDetailData);

  // Return results.
  aDevicePath.Assign(devIfDetailData->DevicePath);

  return NS_OK;
}
nsresult
sbWinFindDevicesByStorageDevNum(STORAGE_DEVICE_NUMBER* aStorageDevNum,
                                PRBool                 aMatchPartitionNumber,
                                const GUID*            aGUID,
                                nsTArray<DEVINST>&     aDevInstList)
{
  // Validate arguments.
  NS_ENSURE_ARG_POINTER(aStorageDevNum);
  NS_ENSURE_ARG_POINTER(aGUID);

  // Function variables.
  nsresult rv;

  // Get the interface device class info and set up for auto-disposal.
  HDEVINFO devInfo =
             SetupDiGetClassDevsW(aGUID,
                                  NULL,
                                  NULL,
                                  DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
  NS_ENSURE_TRUE(devInfo != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
  sbAutoHDEVINFO autoDevInfo(devInfo);

  // Search for device instances with a matching storage device number.
  aDevInstList.Clear();
  DWORD devIndex = 0;
  while (1) {
    // Get the next device detail data and set it up for auto-disposal.
    PSP_DEVICE_INTERFACE_DETAIL_DATA devIfDetailData;
    SP_DEVINFO_DATA                  devInfoData;
    rv = sbWinGetDevDetail(&devIfDetailData,
                           &devInfoData,
                           devInfo,
                           aGUID,
                           devIndex++);
    if (rv == NS_ERROR_NOT_AVAILABLE)
      break;
    NS_ENSURE_SUCCESS(rv, rv);
    sbAutoMemPtr<SP_DEVICE_INTERFACE_DETAIL_DATA>
      autoDevIfDetailData(devIfDetailData);

    // Get the next storage device number.
    STORAGE_DEVICE_NUMBER storageDevNum;
    rv = sbWinGetStorageDevNum(devIfDetailData->DevicePath, &storageDevNum);
    if (NS_FAILED(rv))
      continue;

    // Skip device instance if it doesn't match the target storage device
    // number.
    if (storageDevNum.DeviceType != aStorageDevNum->DeviceType)
      continue;
    if (storageDevNum.DeviceNumber != aStorageDevNum->DeviceNumber)
      continue;
    if (aMatchPartitionNumber &&
        (storageDevNum.PartitionNumber != aStorageDevNum->PartitionNumber)) {
      continue;
    }

    // Add device instance to list.
    NS_ENSURE_TRUE(aDevInstList.AppendElement(devInfoData.DevInst),
                   NS_ERROR_OUT_OF_MEMORY);
  }

  return NS_OK;
}