Bug 600280. Use Setup API instead of the registry directly to get device information. r=jrmuizel,a=joe
authorTetsuro Kato <tete009+bugzilla@gmail.com>
Mon, 24 Jan 2011 10:05:59 -0500
changeset 61175 e09b598992e8f4495e1bd7d51f8b95d39ee966de
parent 61174 32f8623164fbe5a0a5438333bab96d61072e6ca3
child 61176 812710794ca1a65b9f5c5014babc948d32376bbb
push idunknown
push userunknown
push dateunknown
reviewersjrmuizel, joe
bugs600280
milestone2.0b10pre
Bug 600280. Use Setup API instead of the registry directly to get device information. r=jrmuizel,a=joe This fixes driver version and date being empty or null for some graphic cards under Windows 2000/XP
widget/src/windows/GfxInfo.cpp
--- a/widget/src/windows/GfxInfo.cpp
+++ b/widget/src/windows/GfxInfo.cpp
@@ -32,16 +32,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <windows.h>
+#include <setupapi.h>
 #include "gfxWindowsPlatform.h"
 #include "GfxInfo.h"
 #include "GfxInfoWebGL.h"
 #include "nsUnicharUtils.h"
 #include "nsPrintfCString.h"
 #include "mozilla/FunctionTimer.h"
 #include "prenv.h"
 #include "prprf.h"
@@ -175,16 +176,41 @@ static nsresult GetKeyValue(const WCHAR*
 static void normalizeDriverId(nsString& driverid) {
   ToUpperCase(driverid);
   PRInt32 rev = driverid.Find(NS_LITERAL_CSTRING("&REV_"));
   if (rev != -1) {
     driverid.Cut(rev, driverid.Length());
   }
 }
 
+// Setup API functions
+typedef HDEVINFO (WINAPI*SetupDiGetClassDevsWFunc)(
+  CONST GUID *ClassGuid,
+  PCWSTR Enumerator,
+  HWND hwndParent,
+  DWORD Flags
+);
+typedef BOOL (WINAPI*SetupDiEnumDeviceInfoFunc)(
+  HDEVINFO DeviceInfoSet,
+  DWORD MemberIndex,
+  PSP_DEVINFO_DATA DeviceInfoData
+);
+typedef BOOL (WINAPI*SetupDiGetDeviceRegistryPropertyWFunc)(
+  HDEVINFO DeviceInfoSet,
+  PSP_DEVINFO_DATA DeviceInfoData,
+  DWORD Property,
+  PDWORD PropertyRegDataType,
+  PBYTE PropertyBuffer,
+  DWORD PropertyBufferSize,
+  PDWORD RequiredSize
+);
+typedef BOOL (WINAPI*SetupDiDestroyDeviceInfoListFunc)(
+  HDEVINFO DeviceInfoSet
+);
+
 
 
 /* Other interesting places for info:
  *   IDXGIAdapter::GetDesc()
  *   IDirectDraw7::GetAvailableVidMem()
  *   e->GetAvailableTextureMem()
  * */
 
@@ -227,61 +253,84 @@ GfxInfo::Init()
 
   // chop off DEVICE_KEY_PREFIX
   mDeviceKey = displayDevice.DeviceKey + NS_ARRAY_LENGTH(DEVICE_KEY_PREFIX)-1;
 
   mDeviceID = displayDevice.DeviceID;
   mDeviceString = displayDevice.DeviceString;
 
 
-  HKEY key, subkey;
-  LONG result, enumresult;
-  DWORD index = 0;
-  WCHAR subkeyname[64];
-  WCHAR value[128];
-  DWORD dwcbData = sizeof(subkeyname);
+  HMODULE setupapi = LoadLibraryW(L"setupapi.dll");
+
+  if (setupapi) {
+    SetupDiGetClassDevsWFunc setupGetClassDevs = (SetupDiGetClassDevsWFunc)
+      GetProcAddress(setupapi, "SetupDiGetClassDevsW");
+    SetupDiEnumDeviceInfoFunc setupEnumDeviceInfo = (SetupDiEnumDeviceInfoFunc)
+      GetProcAddress(setupapi, "SetupDiEnumDeviceInfo");
+    SetupDiGetDeviceRegistryPropertyWFunc setupGetDeviceRegistryProperty = (SetupDiGetDeviceRegistryPropertyWFunc)
+      GetProcAddress(setupapi, "SetupDiGetDeviceRegistryPropertyW");
+    SetupDiDestroyDeviceInfoListFunc setupDestroyDeviceInfoList = (SetupDiDestroyDeviceInfoListFunc)
+      GetProcAddress(setupapi, "SetupDiDestroyDeviceInfoList");
 
-  // "{4D36E968-E325-11CE-BFC1-08002BE10318}" is the display class
-  result = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                        L"System\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}", 
-                        0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &key);
-  if (result != ERROR_SUCCESS) {
-    return rv;
-  }
+    if (setupGetClassDevs &&
+        setupEnumDeviceInfo &&
+        setupGetDeviceRegistryProperty &&
+        setupDestroyDeviceInfoList) {
+      /* create a device information set composed of the current display device */
+      HDEVINFO devinfo = setupGetClassDevs(NULL,
+                                           PromiseFlatString(mDeviceID).get(),
+                                           NULL,
+                                           DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
 
-  nsAutoString wantedDriverId(mDeviceID);
-  normalizeDriverId(wantedDriverId);
+      if (devinfo != INVALID_HANDLE_VALUE) {
+        HKEY key;
+        LONG result;
+        WCHAR value[255];
+        DWORD dwcbData;
+        SP_DEVINFO_DATA devinfoData;
+        DWORD memberIndex = 0;
 
-  while ((enumresult = RegEnumKeyExW(key, index, subkeyname, &dwcbData, NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS) {
-    result = RegOpenKeyExW(key, subkeyname, 0, KEY_QUERY_VALUE, &subkey);
-    if (result == ERROR_SUCCESS) {
-      dwcbData = sizeof(value);
-      result = RegQueryValueExW(subkey, L"MatchingDeviceId", NULL, NULL, (LPBYTE)value, &dwcbData);
-      if (result == ERROR_SUCCESS) {
-        nsAutoString matchingDeviceId(value);
-        normalizeDriverId(matchingDeviceId);
-        if (wantedDriverId.Find(matchingDeviceId) > -1) {
-          /* we've found the driver we're looking for */
-          result = RegQueryValueExW(subkey, L"DriverVersion", NULL, NULL, (LPBYTE)value, &dwcbData);
-          if (result == ERROR_SUCCESS)
-            mDriverVersion = value;
-          result = RegQueryValueExW(subkey, L"DriverDate", NULL, NULL, (LPBYTE)value, &dwcbData);
-          if (result == ERROR_SUCCESS)
-            mDriverDate = value;
-          break;
+        devinfoData.cbSize = sizeof(devinfoData);
+        NS_NAMED_LITERAL_STRING(driverKeyPre, "System\\CurrentControlSet\\Control\\Class\\");
+        /* enumerate device information elements in the device information set */
+        while (setupEnumDeviceInfo(devinfo, memberIndex++, &devinfoData)) {
+          /* get a string that identifies the device's driver key */
+          if (setupGetDeviceRegistryProperty(devinfo,
+                                             &devinfoData,
+                                             SPDRP_DRIVER,
+                                             NULL,
+                                             (PBYTE)value,
+                                             sizeof(value),
+                                             NULL)) {
+            nsAutoString driverKey(driverKeyPre);
+            driverKey += value;
+            result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey.BeginReading(), 0, KEY_QUERY_VALUE, &key);
+            if (result == ERROR_SUCCESS) {
+              /* we've found the driver we're looking for */
+              dwcbData = sizeof(value);
+              result = RegQueryValueExW(key, L"DriverVersion", NULL, NULL, (LPBYTE)value, &dwcbData);
+              if (result == ERROR_SUCCESS)
+                mDriverVersion = value;
+              dwcbData = sizeof(value);
+              result = RegQueryValueExW(key, L"DriverDate", NULL, NULL, (LPBYTE)value, &dwcbData);
+              if (result == ERROR_SUCCESS)
+                mDriverDate = value;
+              RegCloseKey(key);
+              break;
+            }
+          }
         }
+
+        setupDestroyDeviceInfoList(devinfo);
       }
-      RegCloseKey(subkey);
     }
-    index++;
-    dwcbData = sizeof(subkeyname);
+
+    FreeLibrary(setupapi);
   }
 
-  RegCloseKey(key);
-
   const char *spoofedDriverVersionString = PR_GetEnv("MOZ_GFX_SPOOF_DRIVER_VERSION");
   if (spoofedDriverVersionString) {
     mDriverVersion.AssignASCII(spoofedDriverVersionString);
   }
 
   const char *spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_VENDOR_ID");
   if (spoofedVendor) {
      PR_sscanf(spoofedVendor, "%x", &mAdapterVendorID);