View Javadoc
1   /*
2    * Copyright 2016-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.Advapi32;
14  import com.sun.jna.platform.win32.Guid;
15  import com.sun.jna.platform.win32.SetupApi;
16  import com.sun.jna.platform.win32.WinBase;
17  import com.sun.jna.platform.win32.WinError;
18  import com.sun.jna.platform.win32.WinNT;
19  import com.sun.jna.platform.win32.WinNT.HANDLE;
20  import com.sun.jna.platform.win32.WinReg.HKEY;
21  
22  import oshi.annotation.concurrent.Immutable;
23  import oshi.hardware.Display;
24  import oshi.hardware.common.AbstractDisplay;
25  import oshi.jna.ByRef.CloseableIntByReference;
26  import oshi.jna.Struct.CloseableSpDeviceInterfaceData;
27  import oshi.jna.Struct.CloseableSpDevinfoData;
28  
29  /**
30   * A Display
31   */
32  @Immutable
33  final class WindowsDisplay extends AbstractDisplay {
34  
35      private static final Logger LOG = LoggerFactory.getLogger(WindowsDisplay.class);
36  
37      private static final SetupApi SU = SetupApi.INSTANCE;
38      private static final Advapi32 ADV = Advapi32.INSTANCE;
39  
40      private static final Guid.GUID GUID_DEVINTERFACE_MONITOR = new Guid.GUID("E6F07B5F-EE97-4a90-B076-33F57BF4EAA7");
41  
42      /**
43       * Constructor for WindowsDisplay.
44       *
45       * @param edid a byte array representing a display EDID
46       */
47      WindowsDisplay(byte[] edid) {
48          super(edid);
49          LOG.debug("Initialized WindowsDisplay");
50      }
51  
52      /**
53       * Gets Display Information
54       *
55       * @return An array of Display objects representing monitors, etc.
56       */
57      public static List<Display> getDisplays() {
58          List<Display> displays = new ArrayList<>();
59  
60          HANDLE hDevInfo = SU.SetupDiGetClassDevs(GUID_DEVINTERFACE_MONITOR, null, null,
61                  SetupApi.DIGCF_PRESENT | SetupApi.DIGCF_DEVICEINTERFACE);
62          if (!hDevInfo.equals(WinBase.INVALID_HANDLE_VALUE)) {
63              try (CloseableSpDeviceInterfaceData deviceInterfaceData = new CloseableSpDeviceInterfaceData();
64                      CloseableSpDevinfoData info = new CloseableSpDevinfoData()) {
65                  deviceInterfaceData.cbSize = deviceInterfaceData.size();
66  
67                  for (int memberIndex = 0; SU.SetupDiEnumDeviceInfo(hDevInfo, memberIndex, info); memberIndex++) {
68                      HKEY key = SU.SetupDiOpenDevRegKey(hDevInfo, info, SetupApi.DICS_FLAG_GLOBAL, 0, SetupApi.DIREG_DEV,
69                              WinNT.KEY_QUERY_VALUE);
70  
71                      byte[] edid = new byte[1];
72  
73                      try (CloseableIntByReference pType = new CloseableIntByReference();
74                              CloseableIntByReference lpcbData = new CloseableIntByReference()) {
75                          if (ADV.RegQueryValueEx(key, "EDID", 0, pType, edid, lpcbData) == WinError.ERROR_MORE_DATA) {
76                              edid = new byte[lpcbData.getValue()];
77                              if (ADV.RegQueryValueEx(key, "EDID", 0, pType, edid, lpcbData) == WinError.ERROR_SUCCESS) {
78                                  Display display = new WindowsDisplay(edid);
79                                  displays.add(display);
80                              }
81                          }
82                      }
83                      Advapi32.INSTANCE.RegCloseKey(key);
84                  }
85              }
86              SU.SetupDiDestroyDeviceInfoList(hDevInfo);
87          }
88          return displays;
89      }
90  }