locked
howto get HANDLE of a display device from DISPLAY_DEVICE.DeviceName RRS feed

  • Question

  • Hi,

    I need all HANDLEs of the display device (conected to my computer). Therefore I use EnumDisplayDevices to retrieve the DISPLAY_DEVICE.DeviceName names.
    They are fine. For example I have here "\\.\DISPLAY1\Monitor0" etc.... So EnumDisplayDevices works fine.
    But now I tried to open the this devices with:

       HANDLE hDisplayDevice = CreateFile( DisplayDevice.DeviceName,    
                                                             GENERIC_READ | GENERIC_WRITE,
                                                             FILE_SHARE_READ | FILE_SHARE_WRITE,
                                                             NULL,                                    // default security attributes
                                                             OPEN_EXISTING,                   // disposition
                                                             0,                                        // file attributes
                                                             NULL );
        DWORD LastError = GetLastError();

    Executing this, retrieves:
            hDisplayDevice  = 0xfffffff
            DWORD LastError = 5     =    ERROR_ACCESS_DENIED


    Can you please answer the following questions:

           1.

    ----------

    Is there no other way to open that display device and to get a handle on it?

    For example with "GetPhysicalMonitorsFromHMONITOR" I can get a handle on display device which are associate with a specific monitor ( e.g. primary monitor ). Since I need the handles of a display device I though, that is should be possible to get all those handles with the above described way ( 1. EnumDisplayDevices  & 2. CreateFile ).  Since this currently fails ==> The question is whether their is no other way to the handles of all physical display devices?

           2.
    ----------

    I guess opening the display device with the "CreateFile" function should be the right way to open that device and to retrieve a handle on it. - Are I am wrong with that opinion? Is this not right? ==> Do I have to use another function to open the display device and to retrieve a handle on it?

           3.
    ----------

    What might be the reason for that ERROR_ACCESS_DENIED ?  Since I started the program as admin ( Run as admin) It should have enough privileges. So their should not occure that ERROR_ACCESS_DENIED. ==> Why do that occure anyway  and how do I solve that problem?





    Friday, March 16, 2012 2:50 PM

All replies

  • On 3/16/2012 10:50 AM, ThePerfectWave wrote:

    I need all HANDLEs of the display device (conected to my computer). Therefore I use EnumDisplayDevices to retrieve the DISPLAY_DEVICE.DeviceName names.

    You are probably looking for CreateDC. Certainly not CreateFile. What do you plan to do with the handle once you have it? What's the ultimate goal of the exercise?


    Igor Tandetnik

    Friday, March 16, 2012 2:57 PM
  • If I recall correctly, EnumDisplayDevices() uses a callback function to enumerate the devices, and the callback receives the RECT that the monitor is assigned to.  Take a point from this RECT structure and pass it along to MonitorFromPoint() to obtain an HMONITOR handle.

    So, to try to answer your questions:

    1. If the CreateFile() documentation doesn't say it works for monitors, then it is not the way to obtain handles.  Check it out.
    2. See #1.  The answer might be the same.  Also see MonitorFromPoint().
    3. Don't know if this is even the right path.  See #1 to see if it should be possible in the first place.

    Jose R. MCP

    Friday, March 16, 2012 3:01 PM
  • Hi,

    thanks for that fast answers.

    @ IGOR:   No I do not need a DC. ==> I need the HANDLEs on the display devices To pass them to monitor configuration functions ( e.g. SetMonitorBrightness, etc. ... ).

    @ WebJOSE:   No the EnumDisplayDevices does not work with a callback ( you are thinking about EnumDisplayMonitors, that's the function that works with a callback ).  Further the data retrieved with EnumDisplayDevices does not contain a RECT.

    I am almost sure / guess that CreateFile can open such a DisplayDevice.  Hmmm.... last error code = 5 ( access denied ) ==> may be I have to pass a pointer to the right security attributes ....  Does somebody know that?

    Does somebody know how I can open my display  devices ( "\\.\DISPLAY1\Monitor0", etc... ) ... Can somebody pass the correct CreateFile sample code / parameters....

    This would be greate !

    Thanks in advance for your help. 


    Saturday, March 17, 2012 11:32 PM
  • ThePerfectWave wrote:

    @ IGOR: No I do not need a DC. ==> I need the HANDLEs on the  display devices To pass them to monitor configuration functions (
    e.g. SetMonitorBrightness, etc. ... ).

    The documentation for SetMonitorBrightness seems pretty clear: "To get  the monitor handle, call GetPhysicalMonitorsFromHMONITOR or  GetPhysicalMonitorsFromIDirect3DDevice9".


    Igor Tandetnik

    Saturday, March 17, 2012 11:46 PM
  • I already use this function:   GetPhysicalMonitorsFromHMONITOR   ==> I know that this function works fine.

    But this function just retrieves the physical monitor(s) that are used by HMONITOR. (This are not all the physical monitor devices connected to the computer)

    In contrast to the function GetPhysicalMonitorsFromHMONITOR the function EnumDisplayDevices can give you the "DISPLAY_DEVICE.DeviceNames" of A L L physical monitors.

    Since those "DISPLAY_DEVICE.DeviceNames" contain names like "\\.\DISPLAY1\Monitor0" etc.... I am pretty sure that with those "DISPLAY_DEVICE.DeviceNames" the CreateFile function should be able to open this devices and retrieve handles on that opened devices. Since "DISPLAY_DEVICE.DeviceNames" have the same "SYNTAX" as required for the lpFileName parameter of CreateFile-function, I am pretty sure that CreateFile can open this physical monitor devices.

    ==> The question is, what is wrong with this approach:

      HANDLE hDisplayDevice = CreateFile( DisplayDevice.DeviceName,    
                                                             GENERIC_READ | GENERIC_WRITE,
                                                             FILE_SHARE_READ | FILE_SHARE_WRITE,
                                                             NULL,                                    // default security attributes
                                                             OPEN_EXISTING,                   // disposition
                                                             0,                                        // file attributes
                                                             NULL );

    Why does this call not open the physical monitor devices.  ==> Does somebody know what must be changed in this code piece?

    Thanks a lot in advance for your help.




    Monday, March 19, 2012 3:17 PM
  • On 3/19/2012 11:17 AM, ThePerfectWave wrote:

    I already use this function:   GetPhysicalMonitorsFromHMONITOR   ==>  I know that this function works fine.

    But this function just retrieves the physical monitor(s) that are used by HMONITOR.

    In contrast to the function GetPhysicalMonitorsFromHMONITOR the
    function EnumDisplayDevices can give you the
    "DISPLAY_DEVICE.DeviceNames" if*A L L* physical monitors.

    I can only assume, based on the documentation, that SetMonitorBrightness is only capable of setting the brightness of a physical monitor used either by an HMONITOR or an IDirect3DDevice9.

    It's not clear to me how a system can have a physical monitor that is not associated with any HMONITOR. Or at least, how a system can display anything on such a monitor (and if it can't display anything on it, why would one care about its brightness?)

    Since those "DISPLAY_DEVICE.DeviceNames" contain names like
    "\\.\DISPLAY1\Monitor0" etc.... I am pretty sure that with those
    "DISPLAY_DEVICE.DeviceNames" the CreateFile function should be able
    to open this devices and retrieve handles on that opened devices.

    If you are willing to engage in wishful thinking, to believe your gut instinct in the face of the explicit documentation to the contrary as well as the outcome of empirical experiments, then by all means, carry on.


    Igor Tandetnik

    Monday, March 19, 2012 3:38 PM
  • Is there somebody else, who can answer my question?


    The original question is:
    ---------------------------
    I retrieve with EnumDisplayDevices all physical display devices. Those contain in
    DisplayDevice.DeviceName names like "\\.\DISPLAY1\Monitor0". Passing such a name
    into the function CreateFile should help me to open those physical display devices
    and to retrieve a proper HANDLE.

    I call CreateFile with the following parameters:

      HANDLE hDisplayDevice = CreateFile( DisplayDevice.DeviceName,    
                                                             GENERIC_READ | GENERIC_WRITE,
                                                             FILE_SHARE_READ | FILE_SHARE_WRITE,
                                                             NULL,                 
                                                             OPEN_EXISTING,        
                                                             0,                    
                                                             NULL );

    Does somebody else know why this call does not open my physical display devieces?
    Can somebody else tell me please, what I have to fix, so that the above call will open
    my physical display devices?


    Thanks in advance for your help.

     
    Tuesday, March 20, 2012 2:36 PM
  • Wow. It is amazing that asking a simple question provokes nothing but irrelevant and frequently rather rude responses.

    The documented interface in EnumDisplayDevices is broken, as far as I can tell, in all versions of windows from XP to Win7. The value returned for the DeviceName field "\\.\DISPLAY\Monitor0" ought to be a symlink to the actual monitor device interface symlink, instead it is nothing at all. There is no \\.\DISPLAY\Monitor0 symlink in the global object namespace (or anywhere for that matter.) It is a bug.  I don't have a good answer for you. I am just amazed at the people responding with "you are engaged in wishful thinking" when in fact it is a broken api.

    The docs do claim that one can "Set this flag to EDD_GET_DEVICE_INTERFACE_NAME (0x00000001) to retrieve the device interface name for GUID_DEVINTERFACE_MONITOR" (for dwFlags) however, that too is busted.  Even better GUID_DEVINTERFACE_MONITOR is defined as {E6F07B5F-EE97-4a90-B076-33F57BF4EAA7} when in fact the interface for monitor devices that works is {866519b5-3f07-4c97-b7df-24c5d8a8ccb8}. (Tested on Win7, not tested on earlier releases.) You can find the monitor devices using setupdiapis with that guid. Correlating them back to the monitors enumerated by EnumDisplayDevices is the mystery I'm working on at the moment, which is how I stumbled on this thread. If I find the answer I'll update here.

    And to those unhelpful responders here: there are many legitimate reasons for people out here working on third party products to need to manage the physical displays attached to an instance of Windows. The APIs for doing that are broken and poorly documented, and have been so for at least 12 years.


    Mark Roddy Windows Driver and OS consultant www.hollistech.com

    Thursday, June 14, 2012 1:34 PM
  • On 6/14/2012 9:34 AM, markRoddy wrote:

    I am just amazed at the people responding with "you are engaged in wishful thinking" when in fact it is a broken api.

    One doesn't preclude the other. Perhaps the API is broken, but if one discovers this fact, and nevertheless keeps repeating "there must be a way to get it to work, and I'm going to ignore any evidence to the contrary", is this not wishful thinking?


    Igor Tandetnik

    Thursday, June 14, 2012 4:33 PM
  • Sorry about being a bit abrupt. I'm working on a related problem and the lack of information is massively frustrating. 

    Go reread this thread. Nobody provided any help at all to the OP in solving his legitimate problem. As somebody searching the net for clues on how to work-around this mess in win32, I ended up here and it looked promising.... and then nothing. Everyone is trying to argue the OP out of doing what he is trying to do.

    If you google this issue, it is all over the place and nobody has any good answers. And yet I suspect that people inside MSFT know very well how to access all  the monitor devices on the system - the busted EnumDisplayDevices api is doing just that, it just doesn't manage to return useful information about all of them.

    In all fairness I think you tried - but then you ended up telling the OP to not bother with this because it wasn't going to work. The other responder just couldn't But what are his alternatives? He has to construct the code to do a task- set the brightness on all monitors attached to the system regardless of their logical "attached to desktop" state - and there is no documented way to do that because the documented monitor enumerator api is busted.

    I have the bits figured out on how to find the monitor devices. Once I've tested it out I'll document it here and perhaps the next 100 or so people trying to enumerate monitor devices attached to the system will have a better experience.


    Mark Roddy Windows Driver and OS consultant www.hollistech.com

    Thursday, June 14, 2012 7:08 PM
  • On 6/14/2012 3:08 PM, markRoddy wrote:

    Go reread this thread. Nobody provided any help at all to the OP in solving his legitimate problem.

    The OP wanted to use SetMonitorBrightness, and was told that he could do that using a handle returned by GetPhysicalMonitorsFromHMONITOR. The OP instead insisted that he absolutely must use CreateFile to obtain the monitor handle, and wouldn't accept any other suggestion. He never explained why the documented solution is, in his opinion, inadequate, nor what made him believe that CreateFile was the way to go.

    Do you also believe this solution is inadequate, or that CreateFile is the way to go? Could you explain why?

    As somebody searching the net for clues on how to work-around this mess in win32, I ended up here and it looked promising.... and then nothing. Everyone is trying to argue the OP out of doing what he is trying to do.

    The OP stated a problem P and his proposed solution A, then complained that A didn't work. He was pointed to solution B. He rejected B, for no obvious reason, and kept asking how to make A work. Well, A doesn't work. Is it bad that everyone was trying to get the OP to abandon A and try B? How should this situation have been handled differently, in your opinion?

    If you google this issue, it is all over the place and nobody has any good answers. And yet I suspect that people inside MSFT know very well how to access all  the monitor devices on the system - the busted EnumDisplayDevices api is doing just that, it just doesn't manage to return useful information about all of them.

    Anything wrong with EnumDisplayMonitors, possibly followed by GetPhysicalMonitorsFromHMONITOR?

    In all fairness I think you tried - but then you ended up telling the OP to not bother with this because it wasn't going to work.

    I ended up telling the OP not to bother with his proposed solution, because it didn't work, nor was there any reason to believe that it was even supposed to work. I didn't tell him to stop trying to solve the problem. But he refused to entertain any other solution, so what more could I do?


    Igor Tandetnik

    Thursday, June 14, 2012 7:47 PM
  • So here is what I actually found out about this issue, with the following caveats: only tested on a Win7 system with an XPDM (xp style) graphics adapter. WDDM is TBD, XP is TBD.

    The approach I took was to use the setupdi api to find the device paths for all monitors.

    Examination of the registry indicates that those paths exist and the device interface guid being used is {866519b5-3f07-4c97-b7df-24c5d8a8ccb8} - note that this is not the device interface documented by microsoft, GUID_DEVINTERFACE_MONITOR is defined as {E6F07B5F-EE97-4a90-B076-33F57BF4EAA7}.

    That works just fine. It only enumerates "real" rather than virtual monitors and they are clearly the same monitors that EnumDisplayDevices enumerates if one filters out all the uninteresting virtual devices.

    The devicepath is available through SetupDiGetDeviceInterfaceDetail, the tricky part is to correlate those device paths to the monitor DISPLAY_DEVICE data produced by EnumDisplayDevices.

    What I looked for was a data field in common, and I found it. The DISPLAY_DEVICE.DeviceKey field for a monitor is a registry path specific to that device. That registry path is available as a registry key from the setupdi function SetupDiOpenDevRegKey, using the SP_DEVICE_INFO_DATA obtained  from SetupDiGetDeviceInterfaceDetail.

    One can use NtQueryKey to obtain the pathname for a registry key, and then you just match up the setup data sets with the EnumDisplayDevices data sets using the registry path to correlate them. You now have the missing device path for the monitor data produced by EnumDisplayDevices.

    Update: well of course while what I outlined does find the symlinks for monitor pdos and correlate them to the DISPLAY_DEVICE objects, you still have to go through the Enum* and Change*apis to do things like get/set resolution, and they all expect the useless pathname in the DISPLAY_DEVICE object. Oh well... works for fetching the edid out of the registry, probably not for much else. One could send IOCTLs down these paths to the video driver, that would be a bit dangerous for anything other than reading the configuration.

    Are the win32 graphics config apis only broken for multi-monitor on vista and later for XPDM devices? Does it work for WDDM devices? Does it work on xp? Anyone have a clue?


    Mark Roddy Windows Driver and OS consultant www.hollistech.com



    • Edited by markRoddy Friday, June 15, 2012 6:13 PM
    Thursday, June 14, 2012 10:04 PM
  • Is there no other way to open that display device and to get a handle on it?

    There are at least two ways to do this. However, handle obtained with the "CreateFile" function is not compatible with handle obtained with the "GetPhysicalMonitorsFromHMONITOR" function.

    Way 1:

    DISPLAY_DEVICE ddAdapter;
    ddAdapter.cb = sizeof(DISPLAY_DEVICE);
    for (DWORD dwAdapterNum = 0; EnumDisplayDevices(NULL, dwAdapterNum, &ddAdapter, 0); dwAdapterNum++)
    {
        if ((ddAdapter.StateFlags & (DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_MIRRORING_DRIVER)) == DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
        {
            DISPLAY_DEVICE ddMonitor;
            ddMonitor.cb = sizeof(DISPLAY_DEVICE);
            for (DWORD dwMonitorNum = 0; EnumDisplayDevices(ddAdapter.DeviceName, dwMonitorNum, &ddMonitor, EDD_GET_DEVICE_INTERFACE_NAME); dwMonitorNum++)
            {
                if (ddMonitor.StateFlags & DISPLAY_DEVICE_ACTIVE)
                {
                    HANDLE hMonitor = CreateFile(ddMonitor.DeviceID, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    
                    // ...
    
                    CloseHandle(hMonitor);
                }
            }
        }
    }

    Way 2:

    HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
    SP_DEVINFO_DATA DeviceInfoData;
    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    for (DWORD dwDeviceIndex = 0; SetupDiEnumDeviceInfo(DeviceInfoSet, dwDeviceIndex, &DeviceInfoData); dwDeviceIndex++)
    {
        SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
        DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        for (DWORD dwMemberIndex = 0; SetupDiEnumDeviceInterfaces(DeviceInfoSet, &DeviceInfoData, &GUID_DEVINTERFACE_MONITOR, dwMemberIndex, &DeviceInterfaceData); dwMemberIndex++)
        {
            DWORD dwDeviceInterfaceDetailDataSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + MAX_PATH * sizeof(TCHAR);
            PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)new BYTE[dwDeviceInterfaceDetailDataSize];
            pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
            if (SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &DeviceInterfaceData, pDeviceInterfaceDetailData, dwDeviceInterfaceDetailDataSize, NULL, NULL))
            {
                HANDLE hMonitor = CreateFile(pDeviceInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
                delete[] pDeviceInterfaceDetailData;

                // ...

                CloseHandle(hMonitor);
            }
        }
    }

    Monday, August 5, 2013 4:18 PM
  • What I looked for was a data field in common, and I found it. The DISPLAY_DEVICE.DeviceKey field for a monitor is a registry path specific to that device. That registry path is available as a registry key from the setupdi function SetupDiOpenDevRegKey, using the SP_DEVICE_INFO_DATA obtained  from SetupDiGetDeviceInterfaceDetail.

    One can use NtQueryKey to obtain the pathname for a registry key, and then you just match up the setup data sets with the EnumDisplayDevices data sets using the registry path to correlate them. You now have the missing device path for the monitor data produced by EnumDisplayDevices.

    Hi,

    i tried that solution but i got different registry paths. The DISPLAY_DEVICE.DeviceKey gets me a path in ...System\CurrentControlSet\Control\Video\[some GUID]... , but with NtQueryKey i have path in ...System\ControlSet001\Enum\Display\[Monitorname]\[InstanceName]...That makes it nearly impossible to compare.

    What i now do is the following:

    I query the registry key below "SYSTEM\CurrentControlSet\Control\DeviceClasses\{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" to get all the monitor devices and check whether there is a subkey "Control". If the subkey exists it means that this device is connected and i put the DeviceInstance in a list. 

    Then i take that list and do some queries on wmi. In the namespace root\wmi i execute "Select * From WmiMonitorConnectionParams" and read the column "VideoOutputTechnology". Btw. to get the wmi-key "InstanceName" you have to add "_0" to the "DeviceInstance" in the list. The VideoOutputTechnology gets me the connection type so i know which kind of handle i have to use: For Internal or LVDS (laptop display etc.) i can use a "CreateFile", for types like HDMI, DVI etc.. i have to call "EnumDisplayMonitors".

    The part that follows is a bit dirty: When i call "EnumDisplayMonitors", the order of the displays that appear in the callback function is the same as i get them from the registry query. But this is the point where i can connect all my information an handles -> "CreateFile" for internal and "GetPhysicalMonitorsFromHMONITOR" for the others.

    I agree with most people here: its a dirty and nasty work to do for such a simple task like setting the brightness for all monitors. So i hope i can help someone else out there ;)

    Monday, September 2, 2013 7:46 AM
  • On my computer, running windows 8.1, the DISPLAY_DEVICE.DeviceID I get from EnumDisplayDevices is the same as PSP_DEVICE_INTERFACE_DETAIL_DATA->DevicePath I get from SetupDiGetDeviceInterfaceDetail.
    Friday, June 27, 2014 10:57 PM