View Javadoc
1   /*
2    * Copyright 2020-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.windows;
6   
7   import java.util.ArrayList;
8   import java.util.List;
9   
10  import org.slf4j.Logger;
11  import org.slf4j.LoggerFactory;
12  
13  import com.sun.jna.platform.win32.Advapi32Util;
14  import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult;
15  import com.sun.jna.platform.win32.VersionHelpers;
16  import com.sun.jna.platform.win32.Win32Exception;
17  import com.sun.jna.platform.win32.WinError;
18  import com.sun.jna.platform.win32.WinReg;
19  
20  import oshi.annotation.concurrent.Immutable;
21  import oshi.driver.windows.wmi.Win32VideoController;
22  import oshi.driver.windows.wmi.Win32VideoController.VideoControllerProperty;
23  import oshi.hardware.GraphicsCard;
24  import oshi.hardware.common.AbstractGraphicsCard;
25  import oshi.util.Constants;
26  import oshi.util.ParseUtil;
27  import oshi.util.Util;
28  import oshi.util.platform.windows.WmiUtil;
29  import oshi.util.tuples.Triplet;
30  
31  /**
32   * Graphics Card obtained from WMI
33   */
34  @Immutable
35  final class WindowsGraphicsCard extends AbstractGraphicsCard {
36  
37      private static final Logger LOG = LoggerFactory.getLogger(WindowsGraphicsCard.class);
38  
39      private static final boolean IS_VISTA_OR_GREATER = VersionHelpers.IsWindowsVistaOrGreater();
40      public static final String ADAPTER_STRING = "HardwareInformation.AdapterString";
41      public static final String DRIVER_DESC = "DriverDesc";
42      public static final String DRIVER_VERSION = "DriverVersion";
43      public static final String VENDOR = "ProviderName";
44      public static final String QW_MEMORY_SIZE = "HardwareInformation.qwMemorySize";
45      public static final String MEMORY_SIZE = "HardwareInformation.MemorySize";
46      public static final String DISPLAY_DEVICES_REGISTRY_PATH =
47          "SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\";
48  
49      /**
50       * Constructor for WindowsGraphicsCard
51       *
52       * @param name        The name
53       * @param deviceId    The device ID
54       * @param vendor      The vendor
55       * @param versionInfo The version info
56       * @param vram        The VRAM
57       */
58      WindowsGraphicsCard(String name, String deviceId, String vendor, String versionInfo, long vram) {
59          super(name, deviceId, vendor, versionInfo, vram);
60      }
61  
62      /**
63       * public method used by {@link oshi.hardware.common.AbstractHardwareAbstractionLayer} to access the graphics cards.
64       *
65       * @return List of {@link oshi.hardware.platform.windows.WindowsGraphicsCard} objects.
66       */
67      public static List<GraphicsCard> getGraphicsCards() {
68          List<GraphicsCard> cardList = new ArrayList<>();
69  
70          int index = 1;
71          String[] keys = Advapi32Util.registryGetKeys(WinReg.HKEY_LOCAL_MACHINE, DISPLAY_DEVICES_REGISTRY_PATH);
72          for (String key : keys) {
73              if (!key.startsWith("0")) {
74                  continue;
75              }
76  
77              try {
78                  String fullKey = DISPLAY_DEVICES_REGISTRY_PATH + key;
79                  if (!Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, fullKey, ADAPTER_STRING)) {
80                      continue;
81                  }
82  
83                  String name = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, fullKey, DRIVER_DESC);
84                  String deviceId = "VideoController" + index++;
85                  String vendor = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, fullKey, VENDOR);
86                  String versionInfo = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, fullKey, DRIVER_VERSION);
87                  long vram = 0L;
88  
89                  if (Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, fullKey, QW_MEMORY_SIZE)) {
90                      vram = Advapi32Util.registryGetLongValue(WinReg.HKEY_LOCAL_MACHINE, fullKey, QW_MEMORY_SIZE);
91                  } else if (Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, fullKey, MEMORY_SIZE)) {
92                      Object genericValue = Advapi32Util.registryGetValue(WinReg.HKEY_LOCAL_MACHINE, fullKey, MEMORY_SIZE);
93                      if (genericValue instanceof Long) {
94                          vram = (long) genericValue;
95                      } else if (genericValue instanceof Integer) {
96                          vram = Integer.toUnsignedLong((int) genericValue);
97                      } else if (genericValue instanceof byte[]) {
98                          byte[] bytes = (byte[]) genericValue;
99                          vram = ParseUtil.byteArrayToLong(bytes, bytes.length, false);
100                     }
101                 }
102 
103                 cardList.add(new WindowsGraphicsCard(
104                     Util.isBlank(name) ? Constants.UNKNOWN : name,
105                     Util.isBlank(deviceId) ? Constants.UNKNOWN : deviceId,
106                     Util.isBlank(vendor) ? Constants.UNKNOWN : vendor,
107                     Util.isBlank(versionInfo) ? Constants.UNKNOWN : versionInfo,
108                     vram));
109             } catch (Win32Exception e) {
110                 if (e.getErrorCode() != WinError.ERROR_ACCESS_DENIED) {
111                     // Ignore access denied errors, re-throw others
112                     throw e;
113                 }
114             }
115         }
116 
117         if (cardList.isEmpty()) {
118             return getGraphicsCardsFromWmi();
119         }
120         return cardList;
121     }
122 
123     // fall back if something went wrong
124     private static List<GraphicsCard> getGraphicsCardsFromWmi() {
125         List<GraphicsCard> cardList = new ArrayList<>();
126         if (IS_VISTA_OR_GREATER) {
127             WmiResult<VideoControllerProperty> cards = Win32VideoController.queryVideoController();
128             for (int index = 0; index < cards.getResultCount(); index++) {
129                 String name = WmiUtil.getString(cards, VideoControllerProperty.NAME, index);
130                 Triplet<String, String, String> idPair = ParseUtil.parseDeviceIdToVendorProductSerial(
131                         WmiUtil.getString(cards, VideoControllerProperty.PNPDEVICEID, index));
132                 String deviceId = idPair == null ? Constants.UNKNOWN : idPair.getB();
133                 String vendor = WmiUtil.getString(cards, VideoControllerProperty.ADAPTERCOMPATIBILITY, index);
134                 if (idPair != null) {
135                     if (Util.isBlank(vendor)) {
136                         deviceId = idPair.getA();
137                     } else {
138                         vendor = vendor + " (" + idPair.getA() + ")";
139                     }
140                 }
141                 String versionInfo = WmiUtil.getString(cards, VideoControllerProperty.DRIVERVERSION, index);
142                 if (!Util.isBlank(versionInfo)) {
143                     versionInfo = "DriverVersion=" + versionInfo;
144                 } else {
145                     versionInfo = Constants.UNKNOWN;
146                 }
147                 long vram = WmiUtil.getUint32asLong(cards, VideoControllerProperty.ADAPTERRAM, index);
148                 cardList.add(new WindowsGraphicsCard(Util.isBlank(name) ? Constants.UNKNOWN : name, deviceId,
149                         Util.isBlank(vendor) ? Constants.UNKNOWN : vendor, versionInfo, vram));
150             }
151         }
152         return cardList;
153     }
154 }