add the driver details dialog (not fully implemented)
[reactos.git] / reactos / lib / devmgr / misc.c
index 8da0f0f..28e358b 100644 (file)
  */
 #include <precomp.h>
 
+#define NDEBUG
+#include <debug.h>
+
 HINSTANCE hDllInstance = NULL;
 
 
-static INT
+INT
 LengthOfStrResource(IN HINSTANCE hInst,
                     IN UINT uID)
 {
@@ -97,32 +100,42 @@ AllocAndLoadString(OUT LPWSTR *lpTarget,
 static INT
 AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
                        IN HINSTANCE hInst,
-                       IN UINT uID1,
-                       IN UINT uID2)
+                       IN UINT *uID,
+                       IN UINT nIDs)
 {
-    INT ln;
+    INT ln = 0;
+    UINT i;
 
-    ln = LengthOfStrResource(hInst,
-                             uID1);
-    ln += LengthOfStrResource(hInst,
-                              uID2);
-    if (ln++ > 0)
+    for (i = 0;
+         i != nIDs;
+         i++)
+    {
+        ln += LengthOfStrResource(hInst,
+                                  uID[i]);
+    }
+
+    if (ln != 0)
     {
         (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
-                                         ln * sizeof(WCHAR));
+                                         (ln + 1) * sizeof(WCHAR));
         if ((*lpTarget) != NULL)
         {
-            INT Ret, Ret2 = 0;
-            if (!(Ret = LoadStringW(hInst, uID1, *lpTarget, ln)))
-            {
-                LocalFree((HLOCAL)(*lpTarget));
-            }
-            else if (!(Ret2 = LoadStringW(hInst, uID2, *lpTarget + Ret, ln - Ret)))
+            LPWSTR s = *lpTarget;
+            INT Ret = 0;
+
+            for (i = 0;
+                 i != nIDs;
+                 i++)
             {
-                LocalFree((HLOCAL)(*lpTarget));
-                Ret = 0;
+                if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
+                {
+                    LocalFree((HLOCAL)(*lpTarget));
+                }
+
+                s += Ret;
             }
-            return Ret + Ret2;
+
+            return s - *lpTarget;
         }
     }
     return 0;
@@ -141,7 +154,7 @@ 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
@@ -164,8 +177,8 @@ LoadAndFormatString(IN HINSTANCE hInstance,
 
 DWORD
 LoadAndFormatStringsCat(IN HINSTANCE hInstance,
-                        IN UINT uID1,
-                        IN UINT uID2,
+                        IN UINT *uID,
+                        IN UINT nIDs,
                         OUT LPWSTR *lpTarget,
                         ...)
 {
@@ -175,8 +188,8 @@ LoadAndFormatStringsCat(IN HINSTANCE hInstance,
 
     if (AllocAndLoadStringsCat(&lpFormat,
                                hInstance,
-                               uID1,
-                               uID2) > 0)
+                               uID,
+                               nIDs) != 0)
     {
         va_start(lArgs, lpTarget);
         /* let's use FormatMessage to format it because it has the ability to allocate
@@ -244,7 +257,10 @@ ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
                              0,
                              nLength * sizeof(WCHAR));
     if (lpUnicodeStr == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return NULL;
+    }
 
     if (!MultiByteToWideChar(uCodePage,
                              0,
@@ -301,26 +317,199 @@ GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
 
 
 BOOL
-GetDeviceLocationString(IN DEVINST dnDevInst,
+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);
-    cRet = CM_Get_DevNode_Registry_Property(dnDevInst,
-                                            CM_DRP_LOCATION_INFORMATION,
-                                            &RegDataType,
-                                            szBuffer,
-                                            &DataSize,
-                                            0);
-    if (cRet != CR_SUCCESS ||
-        RegDataType != REG_SZ)
+    szBuffer[0] = L'\0';
+    if (dnParentDevInst != 0)
     {
-        szBuffer[0] = L'\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,
@@ -329,163 +518,294 @@ GetDeviceLocationString(IN DEVINST dnDevInst,
             Ret = TRUE;
         }
     }
-    else
+
+    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)
     {
-        /* FIXME - check string for NULL termination! */
-        Ret = TRUE;
+        /* 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' && szBuffer[0] <= L'9')
+    if (szBuffer[0] == L'\0')
     {
-        /* convert the string to an integer value and create a
-           formatted string */
-        LPWSTR szFormatted;
-        ULONG ulLocation = (ULONG)wcstoul(szBuffer,
-                                          NULL,
-                                          10);
-        if (LoadAndFormatString(hDllInstance,
-                                IDS_LOCATIONSTR,
-                                &szFormatted,
-                                ulLocation,
-                                szBuffer) != 0)
+        /* unable to query the information */
+        if (LoadString(hDllInstance,
+                       IDS_NOTAVAILABLE,
+                       szBuffer,
+                       BufferSize))
         {
-            wcsncpy(szBuffer,
-                    szFormatted,
-                    BufferSize - 1);
-            szBuffer[BufferSize - 1] = L'\0';
-            LocalFree((HLOCAL)szFormatted);
+            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;
         }
-        else
-            Ret = FALSE;
     }
 
     return Ret;
 }
 
 
-static const UINT ProblemStringId[] =
+
+BOOL
+IsDeviceHidden(IN DEVINST DevInst,
+               IN HMACHINE hMachine,
+               OUT BOOL *IsHidden)
 {
-    IDS_DEV_NO_PROBLEM,
-    IDS_DEV_NOT_CONFIGURED,
-    IDS_DEV_OUT_OF_MEMORY,
-    IDS_DEV_ENTRY_IS_WRONG_TYPE,
-    IDS_DEV_LACKED_ARBITRATOR,
-    IDS_DEV_BOOT_CONFIG_CONFLICT,
-    IDS_DEV_FAILED_FILTER,
-    IDS_DEV_DEVLOADER_NOT_FOUND,
-    IDS_DEV_INVALID_DATA,
-    IDS_DEV_FAILED_START,
-    IDS_DEV_LIAR,
-    IDS_DEV_NORMAL_CONFLICT,
-    IDS_DEV_NOT_VERIFIED,
-    IDS_DEV_NEED_RESTART,
-    IDS_DEV_REENUMERATION,
-    IDS_DEV_PARTIAL_LOG_CONF,
-    IDS_DEV_UNKNOWN_RESOURCE,
-    IDS_DEV_REINSTALL,
-    IDS_DEV_REGISTRY,
-    IDS_UNKNOWN, /* CM_PROB_VXDLDR, not used on NT */
-    IDS_DEV_WILL_BE_REMOVED,
-    IDS_DEV_DISABLED,
-    IDS_DEV_DEVLOADER_NOT_READY,
-    IDS_DEV_DEVICE_NOT_THERE,
-    IDS_DEV_MOVED,
-    IDS_DEV_TOO_EARLY,
-    IDS_DEV_NO_VALID_LOG_CONF,
-    IDS_DEV_FAILED_INSTALL,
-    IDS_DEV_HARDWARE_DISABLED,
-    IDS_DEV_CANT_SHARE_IRQ,
-    IDS_DEV_FAILED_ADD,
-    IDS_DEV_DISABLED_SERVICE,
-    IDS_DEV_TRANSLATION_FAILED,
-    IDS_DEV_NO_SOFTCONFIG,
-    IDS_DEV_BIOS_TABLE,
-    IDS_DEV_IRQ_TRANSLATION_FAILED,
-    IDS_DEV_FAILED_DRIVER_ENTRY,
-    IDS_DEV_DRIVER_FAILED_PRIOR_UNLOAD,
-    IDS_DEV_DRIVER_FAILED_LOAD,
-    IDS_DEV_DRIVER_SERVICE_KEY_INVALID,
-    IDS_DEV_LEGACY_SERVICE_NO_DEVICES,
-    IDS_DEV_DUPLICATE_DEVICE,
-    IDS_DEV_FAILED_POST_START,
-    IDS_DEV_HALTED,
-    IDS_DEV_PHANTOM,
-    IDS_DEV_SYSTEM_SHUTDOWN,
-    IDS_DEV_HELD_FOR_EJECT,
-    IDS_DEV_DRIVER_BLOCKED,
-    IDS_DEV_REGISTRY_TOO_LARGE,
-    IDS_DEV_SETPROPERTIES_FAILED,
-};
+    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
-GetDeviceStatusString(IN DEVINST DevInst,
-                      IN HANDLE hMachine,
-                      OUT LPWSTR szBuffer,
-                      IN DWORD BufferSize)
+CanDisableDevice(IN DEVINST DevInst,
+                 IN HMACHINE hMachine,
+                 OUT BOOL *CanDisable)
 {
     CONFIGRET cr;
     ULONG Status, ProblemNumber;
     BOOL Ret = FALSE;
 
-    if (hMachine != NULL)
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DevInst,
+                                  0,
+                                  hMachine);
+    if (cr == CR_SUCCESS)
     {
-        cr = CM_Get_DevNode_Status_Ex(&Status,
-                                      &ProblemNumber,
-                                      DevInst,
-                                      0,
-                                      hMachine);
+        *CanDisable = ((Status & DN_DISABLEABLE) != 0);
+        Ret = TRUE;
     }
-    else
+
+    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)
     {
-        cr = CM_Get_DevNode_Status(&Status,
-                                   &ProblemNumber,
-                                   DevInst,
-                                   0);
+        *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)
     {
-        UINT MessageId;
+        *Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
+                      (Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
+        Ret = TRUE;
+    }
 
-        if (ProblemNumber < sizeof(ProblemStringId) / sizeof(ProblemStringId[0]))
-            MessageId = ProblemStringId[ProblemNumber];
-        else
-            MessageId = IDS_UNKNOWN;
+    return Ret;
+}
 
-        szBuffer[0] = L'\0';
-        if (ProblemNumber == 0)
+
+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)))
         {
-            if (LoadString(hDllInstance,
-                           MessageId,
-                           szBuffer,
-                           BufferSize))
-            {
-                Ret = TRUE;
-            }
+            SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
+                                      DeviceInfoSet,
+                                      DevInfoData);
         }
-        else
-        {
-            LPWSTR szProblem;
+        SetLastError(LastErr);
+    }
 
-            if (LoadAndFormatStringsCat(hDllInstance,
-                                        MessageId,
-                                        IDS_DEVCODE,
-                                        &szProblem,
-                                        ProblemNumber))
+    /* 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)
             {
-                wcsncpy(szBuffer,
-                        szProblem,
-                        BufferSize - 1);
-                szBuffer[BufferSize - 1] = L'\0';
-
-                LocalFree((HLOCAL)szProblem);
-
-                Ret = TRUE;
+                *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
             }
+
+            Ret = TRUE;
         }
     }
-
     return Ret;
 }
 
@@ -553,7 +873,7 @@ GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
     {
         szBuffer[0] = L'\0';
         if (LoadString(hDllInstance,
-                       IDS_UNKNOWN,
+                       IDS_UNKNOWNDEVICE,
                        szBuffer,
                        BufferSize))
         {
@@ -565,6 +885,189 @@ GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
 }
 
 
+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)
 {