我正在开发将显示器(监视器模型S / N,ID,等等)上相应的监视器上的对话框从EDID块导出的信息的应用程序。
此代码适用于发现用于显示器的EDID信息。 它通过枚举下HKLM \ SYSTEM的显示键\ CURRENTCONTROLSET \枚举\ DISPLAY \ [显示器] \ [PnPID] \设备参数\ EDID提取EDID信息。
更新:上面的代码是依靠即插即用使用注册表的“副作用”。 我现在使用的SETUPAPI枚举监视器中,正确地处理监视器附接/移除(不同于从上面的链接的代码。)
我想在Windows.Forms.Screen.AllScreens []每个屏幕相关(\\。\ DISPLAY1,\\。\ DISPLAY2等)与所述项从上述注册表检查返回。
注:在下面的代码块,DisplayDetails.GetMonitorDetails()现在已经使用SETUPAPI替换为更强大的注册表枚举代码,但返回的数据是一样的。
如
private void Form1_Load(object sender, EventArgs e)
{
Console.WriteLine("Polling displays on {0}:", System.Environment.MachineName);
int i = 0;
foreach ( DisplayDetails dd in DisplayDetails.GetMonitorDetails())
{
Console.WriteLine( "Info: Model: {0}, MonitorID: {1}, PnPID: {2}, Serial#:{3}", dd.Model, dd.MonitorID, dd.PnPID, dd.SerialNumber );
Console.WriteLine( "Does this correlate to Screen: {0}?", Screen.AllScreens[i++].DeviceName );
}
}
输出:
信息:型号:戴尔P2411H,MonitorID:DELA06E,PnPID:5 2e2fefea&0&UID1078018,序列号:F8NDP0C ... PU
这是否关联到屏幕:\\。\ DISPLAY1?
信息:型号:戴尔P2411H,MonitorID:DELA06E,PnPID:5 2e2fefea&0&UID1078019,序列号:F8NDP0C ... AU
这是否关联到屏幕:\\。\ DISPLAY2?
答:NO
在测试中,我发现这些不可靠的关联(我在第一显示枚举是\\的系统。\ DISPLAY2)。
我的问题:有没有办法得到可靠对于给定Forms.Screen EDID信息? 我能得到的EDID块,但没有发现任何路径关联这个到UI顶级窗体。 提示用户是不希望的,如在我的使用情况下,两个(或更多个)监视器将可能是相同的模型和分辨率,只有通过在S / N几个数字不同。
我看了之后Forms.Screen API路径,Win32的EnumDisplay,其他注册表的GUID(PnP和驱动程序相关的),但没有发现任何有希望的路径。
我也研究了WMI Win32_DesktopMonitor API(Windows 7中),但它不会出现有任何更多的信息,这将有助于我将其与该Windows.Forms.Screen.AllScreens []条目。
我想,如果有一种方法可以做到这一点,它是通过SETUPAPI,但是我还没有找到它。
为解决GDI到SETUPAPI的方法是可用的EnumDisplayDevices API。 如果你在为dwFlags中的EDD_GET_DEVICE_INTERFACE_NAME传球,监视器枚举将返回形式的DeviceID的信息:
Monitor 0 info:
DeviceName: \\.\DISPLAY1
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078018#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
Monitor 1 info:
DeviceName: \\.\DISPLAY2
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078019#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
所述的DeviceID字段现在匹配来自didd.DevicePath结果,如在下面的C#片段检索到:
Guid MonitorGUID = new Guid(Win32.GUID_DEVINTERFACE_MONITOR);
// We start at the "root" of the device tree and look for all
// devices that match the interface GUID of a monitor
IntPtr h = Win32.SetupDiGetClassDevs(ref MonitorGUID, IntPtr.Zero, IntPtr.Zero, (uint)(Win32.DIGCF_PRESENT | Win32.DIGCF_DEVICEINTERFACE));
if (h.ToInt64() != Win32.INVALID_HANDLE_VALUE)
{
bool Success = true;
uint i = 0;
while (Success)
{
// create a Device Interface Data structure
Win32.SP_DEVICE_INTERFACE_DATA dia = new Win32.SP_DEVICE_INTERFACE_DATA();
dia.cbSize = (uint)Marshal.SizeOf(dia);
// start the enumeration
Success = Win32.SetupDiEnumDeviceInterfaces(h, IntPtr.Zero, ref MonitorGUID, i, ref dia);
if (Success)
{
// build a DevInfo Data structure
Win32.SP_DEVINFO_DATA da = new Win32.SP_DEVINFO_DATA();
da.cbSize = (uint)Marshal.SizeOf(da);
// build a Device Interface Detail Data structure
Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
didd.cbSize = (uint)(4 + Marshal.SystemDefaultCharSize); // trust me :)
// now we can get some more detailed information
uint nRequiredSize = 0;
uint nBytes = Win32.BUFFER_SIZE;
if (Win32.SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, out nRequiredSize, ref da))
{
// Now we get the InstanceID
IntPtr ptrInstanceBuf = Marshal.AllocHGlobal((int)nBytes);
Win32.CM_Get_Device_ID(da.DevInst, ptrInstanceBuf, (int)nBytes, 0);
string InstanceID = Marshal.PtrToStringAuto(ptrInstanceBuf);
Console.WriteLine("InstanceID: {0}", InstanceID );
Marshal.FreeHGlobal(ptrInstanceBuf);
Console.WriteLine("DevicePath: {0}", didd.DevicePath );
}
i++;
}
}
}
Win32.SetupDiDestroyDeviceInfoList(h);
}
示例输出:
InstanceID: DISPLAY\DELA06E\5&2E2FEFEA&0&UID1078018
DevicePath: \\?\display#dela06e#5&2e2fefea&0&uid1078018#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
从原来的EnumDisplayDevices的设备名称的Forms.Screen.DeviceName属性相匹配。
有了这两个信息块,现在有可能使用像以下的片段的SetupDIEnumDeviceInterface遍历期间读取EDID块:
private static byte[] GetMonitorEDID(IntPtr pDevInfoSet, SP_DEVINFO_DATA deviceInfoData)
{
IntPtr hDeviceRegistryKey = SetupDiOpenDevRegKey(pDevInfoSet, ref deviceInfoData,
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (hDeviceRegistryKey == IntPtr.Zero)
{
throw new Exception("Failed to open a registry key for device-specific configuration information");
}
IntPtr ptrBuff = Marshal.AllocHGlobal((int)256);
try
{
RegistryValueKind lpRegKeyType = RegistryValueKind.Binary;
int length = 256;
uint result = RegQueryValueEx(hDeviceRegistryKey, "EDID", 0, ref lpRegKeyType, ptrBuff, ref length);
if (result != 0)
{
throw new Exception("Can not read registry value EDID for device " + deviceInfoData.ClassGuid);
}
}
finally
{
RegCloseKey(hDeviceRegistryKey);
}
byte[] edidBlock = new byte[256];
Marshal.Copy(ptrBuff, edidBlock, 0, 256);
Marshal.FreeHGlobal(ptrBuff);
return edidBlock;
}
其中,最后,可被解析为VESA描述符块,如在示出的DisplayDetails.GetMonitorDetails()在此代码方法。
文章来源: Looking for a reliable mapping of Forms.Screen.DeviceName to Monitor EDID info