add the driver details dialog (not fully implemented)
[reactos.git] / reactos / lib / devmgr / misc.c
index e7bd266..28e358b 100644 (file)
  */
 #include <precomp.h>
 
-static INT
+#define NDEBUG
+#include <debug.h>
+
+HINSTANCE hDllInstance = NULL;
+
+
+INT
 LengthOfStrResource(IN HINSTANCE hInst,
                     IN UINT uID)
 {
@@ -63,6 +69,7 @@ LengthOfStrResource(IN HINSTANCE hInst,
     return -1;
 }
 
+
 static INT
 AllocAndLoadString(OUT LPWSTR *lpTarget,
                    IN HINSTANCE hInst,
@@ -89,6 +96,52 @@ AllocAndLoadString(OUT LPWSTR *lpTarget,
     return 0;
 }
 
+
+static INT
+AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
+                       IN HINSTANCE hInst,
+                       IN UINT *uID,
+                       IN UINT nIDs)
+{
+    INT ln = 0;
+    UINT i;
+
+    for (i = 0;
+         i != nIDs;
+         i++)
+    {
+        ln += LengthOfStrResource(hInst,
+                                  uID[i]);
+    }
+
+    if (ln != 0)
+    {
+        (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
+                                         (ln + 1) * sizeof(WCHAR));
+        if ((*lpTarget) != NULL)
+        {
+            LPWSTR s = *lpTarget;
+            INT Ret = 0;
+
+            for (i = 0;
+                 i != nIDs;
+                 i++)
+            {
+                if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
+                {
+                    LocalFree((HLOCAL)(*lpTarget));
+                }
+
+                s += Ret;
+            }
+
+            return s - *lpTarget;
+        }
+    }
+    return 0;
+}
+
+
 DWORD
 LoadAndFormatString(IN HINSTANCE hInstance,
                     IN UINT uID,
@@ -101,7 +154,42 @@ LoadAndFormatString(IN HINSTANCE hInstance,
 
     if (AllocAndLoadString(&lpFormat,
                            hInstance,
-                           uID) > 0)
+                           uID) != 0)
+    {
+        va_start(lArgs, lpTarget);
+        /* let's use FormatMessage to format it because it has the ability to allocate
+           memory automatically */
+        Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
+                             lpFormat,
+                             0,
+                             0,
+                             (LPWSTR)lpTarget,
+                             0,
+                             &lArgs);
+        va_end(lArgs);
+
+        LocalFree((HLOCAL)lpFormat);
+    }
+
+    return Ret;
+}
+
+
+DWORD
+LoadAndFormatStringsCat(IN HINSTANCE hInstance,
+                        IN UINT *uID,
+                        IN UINT nIDs,
+                        OUT LPWSTR *lpTarget,
+                        ...)
+{
+    DWORD Ret = 0;
+    LPWSTR lpFormat;
+    va_list lArgs;
+
+    if (AllocAndLoadStringsCat(&lpFormat,
+                               hInstance,
+                               uID,
+                               nIDs) != 0)
     {
         va_start(lArgs, lpTarget);
         /* let's use FormatMessage to format it because it has the ability to allocate
@@ -121,6 +209,7 @@ LoadAndFormatString(IN HINSTANCE hInstance,
     return Ret;
 }
 
+
 LPARAM
 ListViewGetSelectedItemData(IN HWND hwnd)
 {
@@ -146,3 +235,878 @@ ListViewGetSelectedItemData(IN HWND hwnd)
 
     return 0;
 }
+
+
+LPWSTR
+ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
+                          IN UINT uCodePage)
+{
+    LPWSTR lpUnicodeStr;
+    INT nLength;
+
+    nLength = MultiByteToWideChar(uCodePage,
+                                  0,
+                                  lpMultiByteStr,
+                                  -1,
+                                  NULL,
+                                  0);
+    if (nLength == 0)
+        return NULL;
+
+    lpUnicodeStr = HeapAlloc(GetProcessHeap(),
+                             0,
+                             nLength * sizeof(WCHAR));
+    if (lpUnicodeStr == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+
+    if (!MultiByteToWideChar(uCodePage,
+                             0,
+                             lpMultiByteStr,
+                             nLength,
+                             lpUnicodeStr,
+                             nLength))
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpUnicodeStr);
+        return NULL;
+    }
+
+    return lpUnicodeStr;
+}
+
+
+BOOL
+GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
+                            IN PSP_DEVINFO_DATA DeviceInfoData,
+                            OUT LPWSTR szBuffer,
+                            IN DWORD BufferSize)
+{
+    DWORD RegDataType;
+    BOOL Ret = FALSE;
+
+    if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
+                                          DeviceInfoData,
+                                          SPDRP_MFG,
+                                          &RegDataType,
+                                          (PBYTE)szBuffer,
+                                          BufferSize * sizeof(WCHAR),
+                                          NULL) ||
+        RegDataType != REG_SZ)
+    {
+        szBuffer[0] = L'\0';
+        if (LoadString(hDllInstance,
+                       IDS_UNKNOWN,
+                       szBuffer,
+                       BufferSize))
+        {
+            Ret = TRUE;
+        }
+    }
+    else
+    {
+        /* FIXME - check string for NULL termination! */
+        Ret = TRUE;
+    }
+
+    return Ret;
+}
+
+
+BOOL
+GetDeviceLocationString(IN DEVINST dnDevInst  OPTIONAL,
+                        IN DEVINST dnParentDevInst  OPTIONAL,
+                        OUT LPWSTR szBuffer,
+                        IN DWORD BufferSize)
+{
+    DWORD RegDataType;
+    ULONG DataSize;
+    CONFIGRET cRet;
+    LPWSTR szFormatted;
+    BOOL Ret = FALSE;
+
+    DataSize = BufferSize * sizeof(WCHAR);
+    szBuffer[0] = L'\0';
+    if (dnParentDevInst != 0)
+    {
+        /* query the parent node name */
+        if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
+                                             CM_DRP_DEVICEDESC,
+                                             &RegDataType,
+                                             szBuffer,
+                                             &DataSize,
+                                             0) == CR_SUCCESS &&
+             RegDataType == REG_SZ &&
+             LoadAndFormatString(hDllInstance,
+                                 IDS_DEVONPARENT,
+                                 &szFormatted,
+                                 szBuffer) != 0)
+        {
+            wcsncpy(szBuffer,
+                    szFormatted,
+                    BufferSize - 1);
+            szBuffer[BufferSize - 1] = L'\0';
+            LocalFree((HLOCAL)szFormatted);
+            Ret = TRUE;
+        }
+    }
+    else if (dnDevInst != 0)
+    {
+        cRet = CM_Get_DevNode_Registry_Property(dnDevInst,
+                                                CM_DRP_LOCATION_INFORMATION,
+                                                &RegDataType,
+                                                szBuffer,
+                                                &DataSize,
+                                                0);
+        if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
+        {
+            /* FIXME - check string for NULL termination! */
+            Ret = TRUE;
+        }
+
+        if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
+        {
+            /* convert the string to an integer value and create a
+               formatted string */
+            ULONG ulLocation = (ULONG)wcstoul(szBuffer,
+                                              NULL,
+                                              10);
+            if (LoadAndFormatString(hDllInstance,
+                                    IDS_LOCATIONSTR,
+                                    &szFormatted,
+                                    ulLocation,
+                                    szBuffer) != 0)
+            {
+                wcsncpy(szBuffer,
+                        szFormatted,
+                        BufferSize - 1);
+                szBuffer[BufferSize - 1] = L'\0';
+                LocalFree((HLOCAL)szFormatted);
+            }
+            else
+                Ret = FALSE;
+        }
+    }
+
+    if (!Ret &&
+        LoadString(hDllInstance,
+                   IDS_UNKNOWN,
+                   szBuffer,
+                   BufferSize))
+    {
+        Ret = TRUE;
+    }
+
+    return Ret;
+}
+
+
+BOOL
+GetDeviceStatusString(IN DEVINST DevInst,
+                      IN HMACHINE hMachine,
+                      OUT LPWSTR szBuffer,
+                      IN DWORD BufferSize)
+{
+    CONFIGRET cr;
+    ULONG Status, ProblemNumber;
+    UINT MessageId = IDS_UNKNOWN;
+    BOOL Ret = FALSE;
+
+    szBuffer[0] = L'\0';
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DevInst,
+                                  0,
+                                  hMachine);
+    if (cr == CR_SUCCESS)
+    {
+        if (Status & DN_HAS_PROBLEM)
+        {
+            UINT uRet;
+
+            uRet = DeviceProblemText(hMachine,
+                                     DevInst,
+                                     ProblemNumber,
+                                     szBuffer,
+                                     (BufferSize != 0 ? BufferSize : BufferSize - 1));
+
+            Ret = (uRet != 0 && uRet < BufferSize);
+        }
+        else
+        {
+            if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
+            {
+                MessageId = IDS_NODRIVERLOADED;
+            }
+            else
+            {
+                MessageId = IDS_DEV_NO_PROBLEM;
+            }
+
+            goto GeneralMessage;
+        }
+    }
+    else
+    {
+GeneralMessage:
+        if (LoadString(hDllInstance,
+                        MessageId,
+                        szBuffer,
+                        (int)BufferSize))
+        {
+            Ret = TRUE;
+        }
+    }
+
+    return Ret;
+}
+
+
+BOOL
+GetDriverProviderString(IN HDEVINFO DeviceInfoSet,
+                        IN PSP_DEVINFO_DATA DeviceInfoData,
+                        OUT LPWSTR szBuffer,
+                        IN DWORD BufferSize)
+{
+    HKEY hKey;
+    DWORD dwSize, dwType;
+    BOOL Ret = FALSE;
+
+    szBuffer[0] = L'\0';
+
+    /* get driver provider, date and version */
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
+                                DeviceInfoData,
+                                DICS_FLAG_GLOBAL,
+                                0,
+                                DIREG_DRV,
+                                KEY_QUERY_VALUE);
+    if (hKey != INVALID_HANDLE_VALUE)
+    {
+        /* query the driver provider */
+        dwSize = BufferSize;
+        if (RegQueryValueEx(hKey,
+                            REGSTR_VAL_PROVIDER_NAME,
+                            NULL,
+                            &dwType,
+                            (LPBYTE)szBuffer,
+                            &dwSize) == ERROR_SUCCESS &&
+            dwType == REG_SZ &&
+            szBuffer[0] != L'\0')
+        {
+            Ret = TRUE;
+        }
+        else
+        {
+            szBuffer[0] = L'\0';
+        }
+
+        RegCloseKey(hKey);
+    }
+
+    if (szBuffer[0] == L'\0')
+    {
+        /* unable to query the information */
+        if (LoadString(hDllInstance,
+                       IDS_UNKNOWN,
+                       szBuffer,
+                       BufferSize))
+        {
+            Ret = TRUE;
+        }
+    }
+
+    return Ret;
+}
+
+
+BOOL
+GetDriverVersionString(IN HDEVINFO DeviceInfoSet,
+                       IN PSP_DEVINFO_DATA DeviceInfoData,
+                       OUT LPWSTR szBuffer,
+                       IN DWORD BufferSize)
+{
+    HKEY hKey;
+    DWORD dwSize, dwType;
+    BOOL Ret = FALSE;
+
+    szBuffer[0] = L'\0';
+
+    /* get driver provider, date and version */
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
+                                DeviceInfoData,
+                                DICS_FLAG_GLOBAL,
+                                0,
+                                DIREG_DRV,
+                                KEY_QUERY_VALUE);
+    if (hKey != INVALID_HANDLE_VALUE)
+    {
+        /* query the driver provider */
+        dwSize = BufferSize;
+        if (RegQueryValueEx(hKey,
+                            L"DriverVersion",
+                            NULL,
+                            &dwType,
+                            (LPBYTE)szBuffer,
+                            &dwSize) == ERROR_SUCCESS &&
+            dwType == REG_SZ &&
+            szBuffer[0] != L'\0')
+        {
+            Ret = TRUE;
+        }
+        else
+        {
+            szBuffer[0] = L'\0';
+        }
+
+        RegCloseKey(hKey);
+    }
+
+    if (szBuffer[0] == L'\0')
+    {
+        /* unable to query the information */
+        if (LoadString(hDllInstance,
+                       IDS_NOTAVAILABLE,
+                       szBuffer,
+                       BufferSize))
+        {
+            Ret = TRUE;
+        }
+    }
+
+    return Ret;
+}
+
+BOOL
+GetDriverDateString(IN HDEVINFO DeviceInfoSet,
+                    IN PSP_DEVINFO_DATA DeviceInfoData,
+                    OUT LPWSTR szBuffer,
+                    IN DWORD BufferSize)
+{
+    HKEY hKey;
+    FILETIME DriverDate;
+    SYSTEMTIME SystemTime, LocalTime;
+    DWORD dwSize, dwType;
+    BOOL Ret = FALSE;
+
+    szBuffer[0] = L'\0';
+
+    /* get driver provider, date and version */
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
+                                DeviceInfoData,
+                                DICS_FLAG_GLOBAL,
+                                0,
+                                DIREG_DRV,
+                                KEY_QUERY_VALUE);
+    if (hKey != INVALID_HANDLE_VALUE)
+    {
+        /* query the driver provider */
+        dwSize = sizeof(FILETIME);
+        if (RegQueryValueEx(hKey,
+                            L"DriverDateData",
+                            NULL,
+                            &dwType,
+                            (LPBYTE)&DriverDate,
+                            &dwSize) == ERROR_SUCCESS &&
+            dwType == REG_BINARY &&
+            dwSize == sizeof(FILETIME) &&
+            FileTimeToSystemTime(&DriverDate,
+                                 &SystemTime) &&
+            SystemTimeToTzSpecificLocalTime(NULL,
+                                            &SystemTime,
+                                            &LocalTime) &&
+            GetDateFormat(LOCALE_USER_DEFAULT,
+                          DATE_SHORTDATE,
+                          &LocalTime,
+                          NULL,
+                          szBuffer,
+                          BufferSize) != 0)
+        {
+            Ret = TRUE;
+        }
+
+        RegCloseKey(hKey);
+    }
+
+    if (!Ret)
+    {
+        /* unable to query the information */
+        if (LoadString(hDllInstance,
+                       IDS_NOTAVAILABLE,
+                       szBuffer,
+                       BufferSize))
+        {
+            Ret = TRUE;
+        }
+    }
+
+    return Ret;
+}
+
+
+
+BOOL
+IsDeviceHidden(IN DEVINST DevInst,
+               IN HMACHINE hMachine,
+               OUT BOOL *IsHidden)
+{
+    CONFIGRET cr;
+    ULONG Status, ProblemNumber;
+    BOOL Ret = FALSE;
+
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DevInst,
+                                  0,
+                                  hMachine);
+    if (cr == CR_SUCCESS)
+    {
+        *IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
+        Ret = TRUE;
+    }
+
+    return Ret;
+}
+
+
+BOOL
+CanDisableDevice(IN DEVINST DevInst,
+                 IN HMACHINE hMachine,
+                 OUT BOOL *CanDisable)
+{
+    CONFIGRET cr;
+    ULONG Status, ProblemNumber;
+    BOOL Ret = FALSE;
+
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DevInst,
+                                  0,
+                                  hMachine);
+    if (cr == CR_SUCCESS)
+    {
+        *CanDisable = ((Status & DN_DISABLEABLE) != 0);
+        Ret = TRUE;
+    }
+
+    return Ret;
+}
+
+
+BOOL
+IsDeviceStarted(IN DEVINST DevInst,
+                IN HMACHINE hMachine,
+                OUT BOOL *IsStarted)
+{
+    CONFIGRET cr;
+    ULONG Status, ProblemNumber;
+    BOOL Ret = FALSE;
+
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DevInst,
+                                  0,
+                                  hMachine);
+    if (cr == CR_SUCCESS)
+    {
+        *IsStarted = ((Status & DN_STARTED) != 0);
+        Ret = TRUE;
+    }
+
+    return Ret;
+}
+
+
+BOOL
+IsDriverInstalled(IN DEVINST DevInst,
+                  IN HMACHINE hMachine,
+                  OUT BOOL *Installed)
+{
+    CONFIGRET cr;
+    ULONG Status, ProblemNumber;
+    BOOL Ret = FALSE;
+
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DevInst,
+                                  0,
+                                  hMachine);
+    if (cr == CR_SUCCESS)
+    {
+        *Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
+                      (Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
+        Ret = TRUE;
+    }
+
+    return Ret;
+}
+
+
+BOOL
+EnableDevice(IN HDEVINFO DeviceInfoSet,
+             IN PSP_DEVINFO_DATA DevInfoData  OPTIONAL,
+             IN BOOL bEnable,
+             IN DWORD HardwareProfile  OPTIONAL,
+             OUT BOOL *bNeedReboot  OPTIONAL)
+{
+    SP_PROPCHANGE_PARAMS pcp;
+    SP_DEVINSTALL_PARAMS dp;
+    DWORD LastErr;
+    BOOL Ret = FALSE;
+
+    pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+    pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
+    pcp.HwProfile = HardwareProfile;
+
+    if (bEnable)
+    {
+        /* try to enable the device on the global profile */
+        pcp.StateChange = DICS_ENABLE;
+        pcp.Scope = DICS_FLAG_GLOBAL;
+
+        /* ignore errors */
+        LastErr = GetLastError();
+        if (SetupDiSetClassInstallParams(DeviceInfoSet,
+                                         DevInfoData,
+                                         &pcp.ClassInstallHeader,
+                                         sizeof(SP_PROPCHANGE_PARAMS)))
+        {
+            SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
+                                      DeviceInfoSet,
+                                      DevInfoData);
+        }
+        SetLastError(LastErr);
+    }
+
+    /* try config-specific */
+    pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
+    pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
+
+    if (SetupDiSetClassInstallParams(DeviceInfoSet,
+                                     DevInfoData,
+                                     &pcp.ClassInstallHeader,
+                                     sizeof(SP_PROPCHANGE_PARAMS)) &&
+        SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
+                                  DeviceInfoSet,
+                                  DevInfoData))
+    {
+        dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
+                                          DevInfoData,
+                                          &dp))
+        {
+            if (bNeedReboot != NULL)
+            {
+                *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
+            }
+
+            Ret = TRUE;
+        }
+    }
+    return Ret;
+}
+
+
+BOOL
+GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
+                    OUT LPWSTR szBuffer,
+                    IN DWORD BufferSize)
+{
+    BOOL Ret = FALSE;
+
+    if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
+                                    szBuffer,
+                                    BufferSize,
+                                    NULL))
+    {
+        szBuffer[0] = L'\0';
+        if (LoadString(hDllInstance,
+                       IDS_UNKNOWN,
+                       szBuffer,
+                       BufferSize))
+        {
+            Ret = TRUE;
+        }
+    }
+    else
+    {
+        /* FIXME - check string for NULL termination! */
+        Ret = TRUE;
+    }
+
+    return Ret;
+}
+
+
+BOOL
+GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
+                           IN PSP_DEVINFO_DATA DeviceInfoData,
+                           OUT LPWSTR szBuffer,
+                           IN DWORD BufferSize)
+{
+    DWORD RegDataType;
+    BOOL Ret = FALSE;
+
+    if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
+                                          DeviceInfoData,
+                                          SPDRP_FRIENDLYNAME,
+                                          &RegDataType,
+                                          (PBYTE)szBuffer,
+                                          BufferSize * sizeof(WCHAR),
+                                          NULL) ||
+         SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
+                                          DeviceInfoData,
+                                          SPDRP_DEVICEDESC,
+                                          &RegDataType,
+                                          (PBYTE)szBuffer,
+                                          BufferSize * sizeof(WCHAR),
+                                          NULL)) &&
+        RegDataType == REG_SZ)
+    {
+        /* FIXME - check string for NULL termination! */
+        Ret = TRUE;
+    }
+    else
+    {
+        szBuffer[0] = L'\0';
+        if (LoadString(hDllInstance,
+                       IDS_UNKNOWNDEVICE,
+                       szBuffer,
+                       BufferSize))
+        {
+            Ret = TRUE;
+        }
+    }
+
+    return Ret;
+}
+
+
+BOOL
+FindCurrentDriver(IN HDEVINFO DeviceInfoSet,
+                  IN PSP_DEVINFO_DATA DeviceInfoData,
+                  OUT PSP_DRVINFO_DATA DriverInfoData)
+{
+    HKEY hKey = INVALID_HANDLE_VALUE;
+    SP_DEVINSTALL_PARAMS InstallParams = {0};
+    SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = {0};
+    WCHAR InfPath[MAX_PATH];
+    WCHAR InfSection[LINE_LEN];
+    DWORD dwType, dwLength;
+    DWORD i = 0;
+    LONG rc;
+    BOOL Ret = FALSE;
+
+    /* Steps to find the right driver:
+     * 1) Get the device install parameters
+     * 2) Open the driver registry key
+     * 3) Read the .inf file name
+     * 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name
+     * 5) Build class driver list
+     * 6) Read inf section and inf section extension from registry
+     * 7) Enumerate drivers
+     * 8) Find the one who is in the same section as current driver?
+     */
+
+    /* 1) Get the install params */
+    InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+    if (!SetupDiGetDeviceInstallParams(DeviceInfoSet,
+                                       DeviceInfoData,
+                                       &InstallParams))
+    {
+        DPRINT1("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+#ifdef DI_FLAGSEX_INSTALLEDDRIVER
+    InstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
+    if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
+                                      DeviceInfoData,
+                                      &InstallParams))
+    {
+        if (SetupDiBuildDriverInfoList(DeviceInfoSet,
+                                       DeviceInfoData,
+                                       SPDIT_CLASSDRIVER) &&
+            SetupDiEnumDriverInfo(DeviceInfoSet,
+                                  DeviceInfoData,
+                                  SPDIT_CLASSDRIVER,
+                                  0,
+                                  DriverInfoData))
+        {
+            Ret = TRUE;
+        }
+
+        goto Cleanup;
+    }
+    InstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
+#endif
+
+    /* 2) Open the driver registry key */
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
+                                DeviceInfoData,
+                                DICS_FLAG_GLOBAL,
+                                0,
+                                DIREG_DRV,
+                                KEY_QUERY_VALUE);
+    if (hKey == INVALID_HANDLE_VALUE)
+    {
+        DPRINT1("SetupDiOpenDevRegKey() failed with error 0x%lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    /* 3) Read the .inf file name */
+    dwLength = (sizeof(InfPath) / sizeof(InfPath[0])) - 1;
+    rc = RegQueryValueEx(hKey,
+                         REGSTR_VAL_INFPATH,
+                         0,
+                         &dwType,
+                         (LPBYTE)InfPath,
+                         &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        DPRINT1("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
+        goto Cleanup;
+    }
+    else if (dwType != REG_SZ)
+    {
+        SetLastError(ERROR_GEN_FAILURE);
+        DPRINT1("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
+        goto Cleanup;
+    }
+    InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
+
+    /* 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name */
+    InstallParams.Flags |= DI_ENUMSINGLEINF;
+    InstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
+    wcscpy(InstallParams.DriverPath, InfPath);
+    if (!SetupDiSetDeviceInstallParams(DeviceInfoSet,
+                                       DeviceInfoData,
+                                       &InstallParams))
+    {
+        DPRINT1("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    /* 5) Build class driver list */
+    if (!SetupDiBuildDriverInfoList(DeviceInfoSet,
+                                    DeviceInfoData,
+                                    SPDIT_CLASSDRIVER))
+    {
+        DPRINT1("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    /* 6) Read inf section and from registry */
+    dwLength = (sizeof(InfSection) / sizeof(InfSection[0])) - 1;
+    rc = RegQueryValueEx(hKey,
+                         REGSTR_VAL_INFSECTION,
+                         0,
+                         &dwType,
+                         (LPBYTE)InfSection,
+                         &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        DPRINT1("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
+        goto Cleanup;
+    }
+    else if (dwType != REG_SZ)
+    {
+        SetLastError(ERROR_GEN_FAILURE);
+        DPRINT1("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
+        goto Cleanup;
+    }
+    InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
+
+    /* 7) Enumerate drivers */
+    DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
+    DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+    while (SetupDiEnumDriverInfo(DeviceInfoSet,
+                                 DeviceInfoData,
+                                 SPDIT_CLASSDRIVER,
+                                 i,
+                                 DriverInfoData))
+    {
+        /* 8) Find the one who is in the same section as current driver */
+        if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
+                                        DeviceInfoData,
+                                        DriverInfoData,
+                                        &DriverInfoDetailData,
+                                        DriverInfoDetailData.cbSize,
+                                        NULL) &&
+            GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            DPRINT1("SetupDiGetDriverInfoDetail() failed with error 0x%lx\n", GetLastError());
+            goto Cleanup;
+        }
+        if (!wcsicmp(DriverInfoDetailData.SectionName,
+                     InfSection) != 0)
+        {
+            /* We have found the right driver */
+            Ret = TRUE;
+            goto Cleanup;
+        }
+
+        i++;
+    }
+    if (GetLastError() != ERROR_NO_MORE_ITEMS)
+    {
+        DPRINT1("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    SetLastError(ERROR_NO_DRIVER_SELECTED);
+
+Cleanup:
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
+    return Ret;
+}
+
+
+HINSTANCE
+LoadAndInitComctl32(VOID)
+{
+    typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
+    PINITCOMMONCONTROLS pInitCommonControls;
+    HINSTANCE hComCtl32;
+
+    hComCtl32 = LoadLibrary(L"comctl32.dll");
+    if (hComCtl32 != NULL)
+    {
+        /* initialize the common controls */
+        pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
+                                                                  "InitCommonControls");
+        if (pInitCommonControls == NULL)
+        {
+            FreeLibrary(hComCtl32);
+            return NULL;
+        }
+
+        pInitCommonControls();
+    }
+
+    return hComCtl32;
+}
+
+
+BOOL
+STDCALL
+DllMain(IN HINSTANCE hinstDLL,
+        IN DWORD dwReason,
+           IN LPVOID lpvReserved)
+{
+    switch (dwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hinstDLL);
+            hDllInstance = hinstDLL;
+            break;
+    }
+
+    return TRUE;
+}