Windows: Break dependency on OLE32

The OLE32 library provides the IIDFromString() function to parse a
string to a GUID, but we can implement a simple GUID parsing function
and remove this dependence. Doing so also avoids fetching the Unicode
form of the "DeviceInterfaceGUIDs" property.

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c
index d38788e..e9fcc8e 100644
--- a/libusb/os/windows_winusb.c
+++ b/libusb/os/windows_winusb.c
@@ -104,12 +104,12 @@
 	} while (0)
 
 #if defined(ENABLE_LOGGING)
-static const char *guid_to_string(const GUID *guid)
+static const char *guid_to_string(const GUID *guid, char guid_string[MAX_GUID_STRING_LENGTH])
 {
-	static char guid_string[MAX_GUID_STRING_LENGTH];
-
-	if (guid == NULL)
-		return "";
+	if (guid == NULL) {
+		guid_string[0] = '\0';
+		return guid_string;
+	}
 
 	sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
 		(unsigned int)guid->Data1, guid->Data2, guid->Data3,
@@ -120,6 +120,37 @@
 }
 #endif
 
+static bool string_to_guid(const char guid_string[MAX_GUID_STRING_LENGTH], GUID *guid)
+{
+	unsigned short tmp[4];
+	int num_chars = -1;
+	char extra;
+	int r;
+
+	// Unfortunately MinGW complains that '%hhx' is not a valid format specifier,
+	// even though Visual Studio 2013 and later support it. Rather than complicating
+	// the logic in this function with '#ifdef's, use a temporary array on the stack
+	// to store the conversions.
+	r = sscanf(guid_string, "{%8x-%4hx-%4hx-%4hx-%4hx%4hx%4hx}%n%c",
+		(unsigned int *)&guid->Data1, &guid->Data2, &guid->Data3,
+		&tmp[0], &tmp[1], &tmp[2], &tmp[3], &num_chars, &extra);
+
+	if ((r != 7) || (num_chars != 38))
+		return false;
+
+	// Extract the bytes from the 2-byte shorts
+	guid->Data4[0] = (unsigned char)((tmp[0] >> 8) & 0xFF);
+	guid->Data4[1] = (unsigned char)(tmp[0] & 0xFF);
+	guid->Data4[2] = (unsigned char)((tmp[1] >> 8) & 0xFF);
+	guid->Data4[3] = (unsigned char)(tmp[1] & 0xFF);
+	guid->Data4[4] = (unsigned char)((tmp[2] >> 8) & 0xFF);
+	guid->Data4[5] = (unsigned char)(tmp[2] & 0xFF);
+	guid->Data4[6] = (unsigned char)((tmp[3] >> 8) & 0xFF);
+	guid->Data4[7] = (unsigned char)(tmp[3] & 0xFF);
+
+	return true;
+}
+
 /*
  * Normalize Microsoft's paths: return a duplicate of the given path
  * with all characters converted to uppercase
@@ -149,12 +180,9 @@
 
 	// Prefixed to avoid conflict with header files
 	DLL_GET_HANDLE(ctx, AdvAPI32);
-	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, true);
+	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExA, true);
 	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, true);
 
-	DLL_GET_HANDLE(ctx, OLE32);
-	DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, true);
-
 	DLL_GET_HANDLE(ctx, SetupAPI);
 	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, true);
 	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, true);
@@ -172,7 +200,6 @@
 static void exit_dlls(void)
 {
 	DLL_FREE_HANDLE(SetupAPI);
-	DLL_FREE_HANDLE(OLE32);
 	DLL_FREE_HANDLE(AdvAPI32);
 	DLL_FREE_HANDLE(Cfgmgr32);
 }
@@ -233,6 +260,7 @@
 {
 	SP_DEVICE_INTERFACE_DATA dev_interface_data;
 	PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details;
+	char guid_string[MAX_GUID_STRING_LENGTH];
 	DWORD size;
 
 	dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
@@ -241,7 +269,7 @@
 		if (!pSetupDiEnumDeviceInfo(dev_info, *_index, dev_info_data)) {
 			if (GetLastError() != ERROR_NO_MORE_ITEMS) {
 				usbi_err(ctx, "Could not obtain device info data for %s index %lu: %s",
-					guid_to_string(guid), ULONG_CAST(*_index), windows_error_str(0));
+					guid_to_string(guid, guid_string), ULONG_CAST(*_index), windows_error_str(0));
 				return LIBUSB_ERROR_OTHER;
 			}
 
@@ -257,7 +285,7 @@
 
 		if (GetLastError() != ERROR_NO_MORE_ITEMS) {
 			usbi_err(ctx, "Could not obtain interface data for %s devInst %lX: %s",
-				guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
+				guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
 			return LIBUSB_ERROR_OTHER;
 		}
 
@@ -269,7 +297,7 @@
 		// The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
 		if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
 			usbi_err(ctx, "could not access interface data (dummy) for %s devInst %lX: %s",
-				guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
+				guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
 			return LIBUSB_ERROR_OTHER;
 		}
 	} else {
@@ -280,7 +308,7 @@
 	dev_interface_details = malloc(size);
 	if (dev_interface_details == NULL) {
 		usbi_err(ctx, "could not allocate interface data for %s devInst %lX",
-			guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst));
+			guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst));
 		return LIBUSB_ERROR_NO_MEM;
 	}
 
@@ -288,7 +316,7 @@
 	if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data,
 		dev_interface_details, size, NULL, NULL)) {
 		usbi_err(ctx, "could not access interface data (actual) for %s devInst %lX: %s",
-			guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
+			guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
 		free(dev_interface_details);
 		return LIBUSB_ERROR_OTHER;
 	}
@@ -298,7 +326,7 @@
 
 	if (*dev_interface_path == NULL) {
 		usbi_err(ctx, "could not allocate interface path for %s devInst %lX",
-			guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst));
+			guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst));
 		return LIBUSB_ERROR_NO_MEM;
 	}
 
@@ -381,7 +409,7 @@
 		DWORD value_length = sizeof(DWORD);
 		LONG status;
 
-		status = pRegQueryValueExW(hkey_dev_interface, L"LUsb0", NULL, NULL,
+		status = pRegQueryValueExA(hkey_dev_interface, "LUsb0", NULL, NULL,
 			(LPBYTE)&libusb0_symboliclink_index, &value_length);
 		if (status == ERROR_SUCCESS) {
 			if (libusb0_symboliclink_index < 256) {
@@ -1379,7 +1407,7 @@
 	unsigned long session_id;
 	DWORD size, port_nr, reg_type, install_state;
 	HKEY key;
-	WCHAR guid_string_w[MAX_GUID_STRING_LENGTH];
+	char guid_string[MAX_GUID_STRING_LENGTH];
 	GUID *if_guid;
 	LONG s;
 #define HUB_PASS 0
@@ -1449,7 +1477,7 @@
 //#define ENUM_DEBUG
 #if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG)
 		const char * const passname[] = {"HUB", "DEV", "HCD", "GEN", "HID", "EXT"};
-		usbi_dbg("#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass]));
+		usbi_dbg("#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass], guid_string));
 #endif
 		if ((pass == HID_PASS) && (guid_list[HID_PASS] == NULL))
 			continue;
@@ -1550,16 +1578,16 @@
 				if (key == INVALID_HANDLE_VALUE)
 					break;
 				// Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order
-				size = sizeof(guid_string_w);
-				s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, &reg_type,
-					(LPBYTE)guid_string_w, &size);
+				size = sizeof(guid_string);
+				s = pRegQueryValueExA(key, "DeviceInterfaceGUIDs", NULL, &reg_type,
+					(LPBYTE)guid_string, &size);
 				if (s == ERROR_FILE_NOT_FOUND)
-					s = pRegQueryValueExW(key, L"DeviceInterfaceGUID", NULL, &reg_type,
-						(LPBYTE)guid_string_w, &size);
+					s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, &reg_type,
+						(LPBYTE)guid_string, &size);
 				pRegCloseKey(key);
 				if ((s == ERROR_SUCCESS) &&
-				    (((reg_type == REG_SZ) && (size == (sizeof(guid_string_w) - sizeof(WCHAR)))) ||
-				     ((reg_type == REG_MULTI_SZ) && (size == sizeof(guid_string_w))))) {
+				    (((reg_type == REG_SZ) && (size == (sizeof(guid_string) - sizeof(char)))) ||
+				     ((reg_type == REG_MULTI_SZ) && (size == sizeof(guid_string))))) {
 					if (nb_guids == guid_size) {
 						new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *));
 						if (new_guid_list == NULL) {
@@ -1574,8 +1602,8 @@
 						usbi_err(ctx, "failed to alloc if_guid");
 						LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
 					}
-					if (pIIDFromString(guid_string_w, if_guid) != 0) {
-						usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string, skipping", dev_id);
+					if (!string_to_guid(guid_string, if_guid)) {
+						usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid_string);
 						free(if_guid);
 					} else {
 						// Check if we've already seen this GUID
@@ -1584,7 +1612,7 @@
 								break;
 						}
 						if (j == nb_guids) {
-							usbi_dbg("extra GUID: %s", guid_to_string(if_guid));
+							usbi_dbg("extra GUID: %s", guid_string);
 							guid_list[nb_guids++] = if_guid;
 						} else {
 							// Duplicate, ignore
diff --git a/libusb/os/windows_winusb.h b/libusb/os/windows_winusb.h
index 439042f..6646dc7 100644
--- a/libusb/os/windows_winusb.h
+++ b/libusb/os/windows_winusb.h
@@ -236,13 +236,9 @@
 
 /* AdvAPI32 dependencies */
 DLL_DECLARE_HANDLE(AdvAPI32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
+DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExA, (HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
 DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
 
-/* OLE32 dependency */
-DLL_DECLARE_HANDLE(OLE32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, IIDFromString, (LPCOLESTR, LPIID));
-
 /* SetupAPI dependencies */
 DLL_DECLARE_HANDLE(SetupAPI);
 DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD));
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index e0cb374..c30b57d 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11590
+#define LIBUSB_NANO 11591