C語言判斷windows USB裝置驅動是否正常
阿新 • • 發佈:2020-11-04
USB裝置驅動在不同電腦有不同表現:正常;驅動顯示感嘆號,不能使用,我用如下程式碼判斷
type.h
#ifndef TYPE_H #define TYPE_H #include <setupapi.h> struct wdi_device_info { struct wdi_device_info *next; unsigned short vid; unsigned short pid; BOOL is_composite; unsigned char mi; char* desc; char* driver; char* device_id; char* hardware_id; char* compatible_id; char* upper_filter; UINT64 driver_version; }; struct wdi_options_create_list { BOOL list_all; BOOL list_hubs; BOOL trim_whitespaces; }; #define WINVER 0x0600 #define _WIN32_WINNT 0x0600 #define STR_BUFFER_SIZE 256 #define MAX_DESC_LENGTH 256 #define CR_SUCCESS 0x00000000 #if defined(_MSC_VER) #define safe_vsnprintf(buf, size, format, arg) _vsnprintf_s(buf, size, _TRUNCATE, format, arg) #define safe_snprintf(buf, size, ...) _snprintf_s(buf, size, _TRUNCATE, __VA_ARGS__) #else #define safe_vsnprintf vsnprintf #define safe_snprintf snprintf #endif #define MUTEX_START char mutex_name[10+sizeof(__FUNCTION__)]; HANDLE mutex; \ safe_snprintf(mutex_name, 10+sizeof(__FUNCTION__), "Global\\%s", __FUNCTION__); \ mutex = CreateMutexA(NULL, TRUE, mutex_name); \ if (mutex == NULL) return WDI_ERROR_RESOURCE; \ if (GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(mutex); return WDI_ERROR_BUSY; } #define PF_ERR plog #define sfree(p) do {if (p != NULL) {free((void*)(p)); p = NULL;}} while(0) #define wchar_to_utf8_no_alloc(wsrc, dest, dest_size) \ WideCharToMultiByte(CP_UTF8, 0, wsrc, -1, dest, dest_size, NULL, NULL) #define PF_DECL_LIBRARY(name) HANDLE h##name = NULL #define PF_LOAD_LIBRARY(name) h##name = LoadLibraryA(#name) #define PF_DECL_LOAD_LIBRARY(name) HANDLE PF_LOAD_LIBRARY(name) #define PF_TYPE(api, ret, proc, args) typedef ret (api *proc##_t)args #define PF_DECL(proc) proc##_t pf##proc = NULL #define PF_TYPE_DECL(api, ret, proc, args) PF_TYPE(api, ret, proc, args); PF_DECL(proc) #define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0) #define safe_strdup _strdup #define safe_stricmp(str1, str2) _stricmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2)) typedef DWORD DEVNODE, DEVINST; typedef DEVNODE *PDEVNODE, *PDEVINST; typedef DWORD RETURN_TYPE; typedef RETURN_TYPE CONFIGRET; typedef GUID DEVPROPGUID, *PDEVPROPGUID; typedef ULONG DEVPROPID, *PDEVPROPID; enum WindowsVersion { WINDOWS_UNDEFINED = -1, WINDOWS_UNSUPPORTED = 0, WINDOWS_7 = 0x61, WINDOWS_8 = 0x62, WINDOWS_8_1 = 0x63, WINDOWS_10_PREVIEW1 = 0x64, WINDOWS_10 = 0xA0, WINDOWS_MAX }; enum wdi_error { WDI_SUCCESS = 0, WDI_ERROR_IO = -1, WDI_ERROR_INVALID_PARAM = -2, WDI_ERROR_ACCESS = -3, WDI_ERROR_NO_DEVICE = -4, WDI_ERROR_NOT_FOUND = -5, WDI_ERROR_BUSY = -6, WDI_ERROR_TIMEOUT = -7, WDI_ERROR_OVERFLOW = -8, WDI_ERROR_PENDING_INSTALLATION = -9, WDI_ERROR_INTERRUPTED = -10, WDI_ERROR_RESOURCE = -11, WDI_ERROR_NOT_SUPPORTED = -12, WDI_ERROR_EXISTS = -13, WDI_ERROR_USER_CANCEL = -14, WDI_ERROR_NEEDS_ADMIN = -15, WDI_ERROR_WOW64 = -16, WDI_ERROR_INF_SYNTAX = -17, WDI_ERROR_CAT_MISSING = -18, WDI_ERROR_UNSIGNED = -19, WDI_ERROR_OTHER = -99 }; int nWindowsVersion = WINDOWS_UNDEFINED; static void free_di(struct wdi_device_info *di) { if (di == NULL) { return; } safe_free(di->desc); safe_free(di->driver); safe_free(di->device_id); safe_free(di->hardware_id); safe_free(di->compatible_id); safe_free(di->upper_filter); safe_free(di); } int wdi_destroy_list(struct wdi_device_info* list) { struct wdi_device_info *tmp; MUTEX_START; while(list != NULL) { tmp = list; list = list->next; free_di(tmp); } CloseHandle(mutex); return WDI_SUCCESS; } struct wdi_device_info *device, *devlist = NULL; struct wdi_options_create_list cl_options = { 0 }; HMENU hMenuOptions; #define IDM_IGNOREHUBS 40009 BOOL create_device = FALSE; static __inline char* wchar_to_utf8(const wchar_t* wstr) { int size = 0; char* str = NULL; // Find out the size we need to allocate for our converted string size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); if (size <= 1) // An empty string would be size 1 return NULL; if ((str = (char*)calloc(size, 1)) == NULL) return NULL; if (wchar_to_utf8_no_alloc(wstr, str, size) != size) { sfree(str); return NULL; } return str; } static const DEVPROPKEY DEVPKEY_Device_BusReportedDeviceDesc = { { 0x540b947e, 0x8b40, 0x45bc, {0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2} }, 4 }; typedef ULONG DEVPROPTYPE, *PDEVPROPTYPE; #define safe_swprintf _snwprintf #define safe_strlen(str) ((((char*)str)==NULL)?0:strlen(str)) #define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2), count) #endif // TYPE_H
main.cpp
bool bDevConnect(wdi_device_info **list, wdi_options_create_list *options) { bool b = false; // true:usb裝置正常 false:有usb裝置驅動未安裝 DWORD size, reg_type; HDEVINFO dev_info; SP_DEVINFO_DATA dev_info_data; HKEY key; char strbuf[STR_BUFFER_SIZE], drv_version[] = "xxxxx.xxxxx.xxxxx.xxxxx"; struct wdi_device_info *start = NULL, *device_info = NULL; const char* usbhub_name[] = { "usbhub", "usbhub3", "usb3hub", "nusb3hub", "rusb3hub", "flxhcih", "tihub3", "etronhub3", "viahub3", "asmthub3", "iusb3hub", "vusb3hub", "amdhub30", "vhhub" }; const char usbccgp_name[] = "usbccgp"; BOOL is_hub; *list = NULL; // List all connected USB devices dev_info = SetupDiGetClassDevsA(NULL, "USB", NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); // Find the ones that are driverless for (int i = 0; ; i++) { // Free any invalid previously allocated struct free_di(device_info); // dev_info_data.cbSize = sizeof(dev_info_data); // sizeof(dev_info_data) return different value(28, 32) in different computer dev_info_data.cbSize = 32; if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) { b = true; break; } // Allocate a driver_info struct to store our data device_info = (struct wdi_device_info*)calloc(1, sizeof(struct wdi_device_info)); if (device_info == NULL) { wdi_destroy_list(start); SetupDiDestroyDeviceInfoList(dev_info); } // SPDRP_DRIVER seems to do a better job at detecting driverless devices than // SPDRP_INSTALL_STATE drv_version[0] = 0; if (SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER, ®_type, (BYTE*)strbuf, STR_BUFFER_SIZE, &size)) { if ((options == NULL) || (!options->list_all)) { continue; } // While we have the driver key, pick up the driver version key = SetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ); size = sizeof(drv_version); if (key != INVALID_HANDLE_VALUE) { RegQueryValueExA(key, "DriverVersion", NULL, ®_type, (BYTE*)drv_version, &size); } } // Eliminate USB hubs by checking the driver string strbuf[0] = 0; if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_SERVICE, ®_type, (BYTE*)strbuf, STR_BUFFER_SIZE, &size)) { device_info->driver = NULL; } else { device_info->driver = safe_strdup(strbuf); } is_hub = FALSE; for (int j=0; j<ARRAYSIZE(usbhub_name); j++) { if (safe_stricmp(strbuf, usbhub_name[j]) == 0) { is_hub = TRUE; break; } } if (is_hub && ((options == NULL) || (!options->list_hubs))) { continue; } // Also eliminate composite devices parent drivers, as replacing these drivers if (safe_stricmp(strbuf, usbccgp_name) == 0) { if ((options == NULL) || (!options->list_hubs)) { continue; } } // Retrieve the first hardware ID if (SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_HARDWAREID, ®_type, (BYTE*)strbuf, STR_BUFFER_SIZE, &size)) { b = false; break; } else { strbuf[0] = 0; } } return b; } int main() { if (devlist != NULL) { wdi_destroy_list(devlist); } cl_options.trim_whitespaces = TRUE; bool r; r = bDevConnect(&devlist, &cl_options); if(r) { // usb裝置正常 } else { // usb裝置驅動未安裝 } return 0; }