How to enumerate monitors?
;==========================================================================================================================================
;
; How to enumerate currently active monitors?
;
; Read and parse monitor EDID asset information from the registry.
;
;------------------------------------------------------------------------------------------------------------------------------------------
; Heavily based on WinBatch script by Deana Falk, Technical SupportWilson WindowWare Inc.
; Based on code found at http://www.robvanderwoude.com/files/dispedid_vbs.txt
; Based on a script by Michael Baird.
; See also: http://en.wikipedia.org/wiki/Extended_display_identification_data
;------------------------------------------------------------------------------------------------------------------------------------------
; (c)Detlev Dalitz.20120427.20120428.
;==========================================================================================================================================


DirChange (DirScript ())
GoSub DEFINE_FUNCTIONS

strMsgTitle = "EDID Monitor asset information"
strMsgText = ""

cstHKLM = ObjectType ("I4", -2147483646) ; 2147483650; &H80000002; HKEY_LOCAL_MACHINE.
strComputer = "."
objReg = ObjectGet ("winmgmts:{impersonationLevel=impersonate}!//" : strComputer : "/root/default:StdRegProv")
strKeyPath = "SYSTEM\CurrentControlSet\Enum\DISPLAY"

; Predefine variables. Their type and value will be adapted when they are used.
arrKeys = 0
arrKeysSub1 = 0
arrKeysSub2 = 0
arrEDID = 0

; Enumerate Keys.
objReg.EnumKey(cstHKLM, strKeyPath, arrKeys)
intKLast = ArrInfo (arrKeys, 1) - 1

For intK = 0 To intKLast
   strKeyName = arrKeys[intK]

   ; Enumerate KeysSub1.
   strPathKeySub1 = strKeyPath : "\" : arrKeys[intK]
   objReg.EnumKey(cstHKLM, strPathKeySub1, arrKeysSub1)
   intSub1Last = ArrInfo (arrKeysSub1, 1) - 1

   For intSub1 = 0 To intSub1Last
      strKeySub1Name = arrKeysSub1[intSub1]

      ; Enumerate KeysSub2.
      strPathKeySub2 = strPathKeySub1 : "\" : arrKeysSub1[intSub1]
      objReg.EnumKey(cstHKLM, strPathKeySub2, arrKeysSub2)
      intSub2Last = ArrInfo (arrKeysSub2, 1) - 1

      ; If device is not active, then continue loop.
      blnControl = @FALSE
      For intSub2 = 0 To intSub2Last
         blnControl = arrKeysSub2[intSub2] == "Control"
         If blnControl Then Break
      Next
      If !blnControl Then Continue

      ; Try to get valid binary value, otherwise continue loop.
      ; First check for BAD_EDID value.
      strPathKeySub3 = strPathKeySub2 : "\Device Parameters"
      objReg.GetBinaryValue(cstHKLM, strPathKeySub3, "BAD_EDID", arrEDID)
      If ObjectTypeGet (arrEDID) == "ARRAY|VARIANT" Then Continue

      ; Then check for EDID value.
      objReg.GetBinaryValue(cstHKLM, strPathKeySub3, "EDID", arrEDID)
      If ObjectTypeGet (arrEDID) != "ARRAY|VARIANT" Then Continue

      ; Parse EDID structure. Get monitor name and serial number.
      arrResult = udfParseEDID (arrEDID)

      ; Get other values.
      strMfg = ""
      objReg.GetStringValue(cstHKLM, strPathKeySub2, "Mfg", strMfg)
      If StrIndex (strMfg, ";", 1, @FWDSCAN) Then strMfg = StrSub (strMfg, StrIndex (strMfg, ";", 1, @FWDSCAN) + 1, -1)
      If strMfg == "" Then strMfg = "unknown"

      strDeviceDesc = ""
      objReg.GetStringValue(cstHKLM, strPathKeySub2, "DeviceDesc", strDeviceDesc)
      If StrIndex (strDeviceDesc, ";", 1, @FWDSCAN) Then strDeviceDesc = StrSub (strDeviceDesc, StrIndex (strDeviceDesc, ";", 1, @FWDSCAN) + 1, -1)
      If strDeviceDesc == "" Then strDeviceDesc = "unknown"

      strMsgText = strMsgText : @CRLF : "Manufacturer = " : strMfg : @CRLF : "Description = " : strDeviceDesc : @CRLF : "Model = " : arrResult[0] : @CRLF : "Serial# = " : arrResult[1] : @CRLF
   Next
Next
objReg = 0
strMsgText = StrSub (strMsgText, 3, -1) ; Remove leading @CRLF.

Pause (strMsgTitle, strMsgText)

:CANCEL
Exit

;==========================================================================================================================================
:DEFINE_FUNCTIONS
;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfParseEDID (arrEDID)
arrTestModel = Arrayize ("0,0,0,252", ",")      ; Descriptor type: Monitor name (text).
arrTestSerial = Arrayize ("0,0,0,255", ",")     ; Descriptor type: Monitor serial number (text).
arrDescriptors = Arrayize ("54,72,90,108", ",") ; Relevant entry points into the EDID structure (descriptor blocks).
arrResult = Arrayize (",", ",")                 ; Preset result array with two empty elements.
For intD = 0 To 3
   For intB = 0 To 3
      intIndex = arrDescriptors[intD] + intB
      blnModel = arrTestModel[intB] == arrEDID[intIndex]   ; VT UI1, 1-byte unsigned integer.
      blnSerial = arrTestSerial[intB] == arrEDID[intIndex] ; VT UI1, 1-byte unsigned integer.
   Next
   If blnModel || blnSerial
      strTemp = ""
      For intB = 5 To 17
         intIndex = arrDescriptors[intD] + intB
         Switch arrEDID[intIndex]
         Case 0
         Case 7
         Case 10
         Case 13
            strTemp = strTemp : " "
            Break
         Case arrEDID[intIndex]
            strTemp = strTemp : Num2Char (arrEDID[intIndex])
         EndSwitch
      Next
      strTemp = StrTrim (strTemp)
      If blnModel Then arrResult[0] = strTemp
      If blnSerial Then arrResult[1] = strTemp
   EndIf
Next
Return arrResult
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------
Return ; from GoSub DEFINE_FUNCTIONS
;==========================================================================================================================================
; EDID Extended display identification data structure, version 1.3
;
;   Descriptor blocks.
;   Detailed timing descriptors, in decreasing preference order.
;   After all detailed timing descriptors, additional descriptors are permitted:
;   • Monitor range limits (required)
;   • ASCII text (monitor name (required), monitor serial number, or unstructured text)
;   • 6 Additional standard timing information blocks
;   • Colour point data
;
;   Bytes  : Description
;   054–071: Descriptor 1
;   072–089: Descriptor 2
;   090–107: Descriptor 3
;   108–125: Descriptor 4
;------------------------------------------------------------------------------------------------------------------------------------------
; EDID Descriptor block
;
;   Bytes  : Description
;   000–001: Zero, indicates not a detailed timing descriptor
;   002    : Zero
;   003    : Descriptor type. FA–FF currently defined. 00–0F reserved for vendors.
;   004    : Zero
;   005–017: Defined by descriptor type. If text, code page 437 text, terminated (if less than 13 bytes) with LF and padded with SP.
;
;   Currently defined descriptor types are:
;   0xFF : Monitor serial number (text)
;   0xFE : Unspecified text (text)
;   0xFD : Monitor range limits. 6- or 13-byte binary descriptor.
;   0xFC : Monitor name (text)
;   0xFB : Additional white point data. 2× 5-byte descriptors, padded with 0A 20 20.
;   0xFA : Additional standard timing identifiers. 6× 2-byte descriptors, padded with 0A.
;==========================================================================================================================================