When using the Windows setupapi function SetupDiGetDriverInfoDetailA, it can set the thread local error variable to ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_USER_BUFFER.
The two mean basically the same thing: Your buffer is too small. The SP_DRVINFO_DETAIL_DATA_A struct has a dynamically sized tail that contains the Hardware IDs. ERROR_INVALID_USER_BUFFER means that that dynamically sized area is too small.
You will get ERROR_INSUFFICIENT_BUFFER, if the buffer is smaller than sizeof(SP_DRVINFO_DETAIL_DATA_A).
In order to make correct use of the SetupDiGetDriverInfoDetailA function, the buffer needs to be sizeof(SP_DRVINFO_DETAIL_DATA_A) + *RequiredSize large!
(RequiredSize is a PDWORD (DWORD *) type variable that is set by SetupDiGetDriverInfoDetailA when you ask it for the right size of the buffer.
Complete C code snippet that shows how to use it:
bool windows_get_driver_info_data_a(
HDEVINFO *dev_info_set,
SP_DEVINFO_DATA *dev_info_data,
SP_DRVINFO_DATA_A *drv_info_data,
SP_DRVINFO_DETAIL_DATA_A *drv_info_detail_data,
DWORD *property_buffer_length,
DWORD *required_length
)
{
DWORD error;
char buf[512];
while(TRUE)
{
if (!SetupDiGetDriverInfoDetailA(
*dev_info_set,
dev_info_data,
drv_info_data,
drv_info_detail_data,
*property_buffer_length,
required_length
))
{
DBG0(DBG_LIB, "required_length: %u", *required_length);
DBG0(DBG_LIB, "buffer length: %u", *property_buffer_length);
error = GetLastError();
if(!error)
{
return TRUE;
}
else if (error == ERROR_INSUFFICIENT_BUFFER)
{
// allocate memory
drv_info_detail_data = realloc(
drv_info_detail_data,
*required_length + sizeof(SP_DRVINFO_DETAIL_DATA_A));
drv_info_detail_data->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
*property_buffer_length = *required_length + sizeof(SP_DRVINFO_DETAIL_DATA_A);
DBG0(DBG_LIB, "required_length: %u", *required_length);
if (!SetupDiGetDriverInfoDetailA(
*dev_info_set,
dev_info_data,
drv_info_data,
drv_info_detail_data,
*property_buffer_length,
required_length
))
{
error = GetLastError();
if (error)
{
// previous returned length was bogus, something
// is fishy. Log error message and skip item.
DBG1(DBG_LIB, "Previous required length was bogus. New error is: %s", dlerror_mt(buf, sizeof(buf)));
}
}
} else {
// other error occured. Log error and skip item.
DBG1(DBG_LIB, "A different error occured: %s", dlerror_mt(buf, sizeof(buf)));
}
}
}
return FALSE;
}