static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
{
    HDEVINFO dev_info;
    SP_DEVINFO_DATA dev_info_data;
    DWORD size = 0;
    int i;
    char dev_name[MAX_PATH];
    char *buffer = NULL;
    GuestPCIAddress *pci = NULL;
    char *name = g_strdup(&guid[4]);

    if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) {
        error_setg_win32(errp, GetLastError(), "failed to get dos device name");
        goto out;
    }

    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0,
                                   DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (dev_info == INVALID_HANDLE_VALUE) {
        error_setg_win32(errp, GetLastError(), "failed to get devices tree");
        goto out;
    }

    dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
    for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
        DWORD addr, bus, slot, func, dev, data, size2;
        while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                                            SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
                                            &data, (PBYTE)buffer, size,
                                            &size2)) {
            size = MAX(size, size2);
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
                g_free(buffer);
                /* Double the size to avoid problems on
                 * W2k MBCS systems per KB 888609.
                 * https://support.microsoft.com/en-us/kb/259695 */
                buffer = g_malloc(size * 2);
            } else {
                error_setg_win32(errp, GetLastError(),
                        "failed to get device name");
                goto free_dev_info;
            }
        }

        if (g_strcmp0(buffer, dev_name)) {
            continue;
        }

        /* There is no need to allocate buffer in the next functions. The size
         * is known and ULONG according to
         * https://support.microsoft.com/en-us/kb/253232
         * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
         */
        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                   SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) {
            break;
        }

        /* The function retrieves the device's address. This value will be
         * transformed into device function and number */
        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                   SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) {
            break;
        }

        /* This call returns UINumber of DEVICE_CAPABILITIES structure.
         * This number is typically a user-perceived slot number. */
        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                   SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) {
            break;
        }

        /* SetupApi gives us the same information as driver with
         * IoGetDeviceProperty. According to Microsoft
         * https://support.microsoft.com/en-us/kb/253232
         * FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
         * DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
         * SPDRP_ADDRESS is propertyAddress, so we do the same.*/

        func = addr & 0x0000FFFF;
        dev = (addr >> 16) & 0x0000FFFF;
        pci = g_malloc0(sizeof(*pci));
        pci->domain = dev;
        pci->slot = slot;
        pci->function = func;
        pci->bus = bus;
        break;
    }

free_dev_info:
    SetupDiDestroyDeviceInfoList(dev_info);
out:
    g_free(buffer);
    g_free(name);
    return pci;
}
static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
{
    HDEVINFO dev_info;
    SP_DEVINFO_DATA dev_info_data;
    DWORD size = 0;
    int i;
    char dev_name[MAX_PATH];
    char *buffer = NULL;
    GuestPCIAddress *pci = NULL;
    char *name = g_strdup(&guid[4]);

    if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) {
        error_setg_win32(errp, GetLastError(), "failed to get dos device name");
        goto out;
    }

    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0,
                                   DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (dev_info == INVALID_HANDLE_VALUE) {
        error_setg_win32(errp, GetLastError(), "failed to get devices tree");
        goto out;
    }

    dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
    for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
        DWORD addr, bus, slot, func, dev, data, size2;
        while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                                            SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
                                            &data, (PBYTE)buffer, size,
                                            &size2)) {
            size = MAX(size, size2);
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
                g_free(buffer);
                 
                buffer = g_malloc(size * 2);
            } else {
                error_setg_win32(errp, GetLastError(),
                        "failed to get device name");
                goto free_dev_info;
            }
        }

        if (g_strcmp0(buffer, dev_name)) {
            continue;
        }

         
        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                   SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) {
            break;
        }

         
        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                   SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) {
            break;
        }

         
        if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
                   SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) {
            break;
        }

         

        func = addr & 0x0000FFFF;
        dev = (addr >> 16) & 0x0000FFFF;
        pci = g_malloc0(sizeof(*pci));
        pci->domain = dev;
        pci->slot = slot;
        pci->function = func;
        pci->bus = bus;
        break;
    }

free_dev_info:
    SetupDiDestroyDeviceInfoList(dev_info);
out:
    g_free(buffer);
    g_free(name);
    return pci;
}