8

On the Media Foundation SDK there is the GetPhysicalMonitorsFromHMONITOR function that I am trying to implement using C# but with no luck ...

In the returned PHYSICAL_MONITOR[], the function returns the string description of the monitor but for some mysterious reasons, the hPhysicalMonitor handle remains at 0.

I have generated the signatures with P/Invoke Interop Assistant with minor modifications.

Does the PHYSICAL_MONITOR structure or anything else needs further tuning ?

Thank you.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WindowsFormsApplication1;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public enum MC_DISPLAY_TECHNOLOGY_TYPE
        {
            MC_SHADOW_MASK_CATHODE_RAY_TUBE,

            MC_APERTURE_GRILL_CATHODE_RAY_TUBE,

            MC_THIN_FILM_TRANSISTOR,

            MC_LIQUID_CRYSTAL_ON_SILICON,

            MC_PLASMA,

            MC_ORGANIC_LIGHT_EMITTING_DIODE,

            MC_ELECTROLUMINESCENT,

            MC_MICROELECTROMECHANICAL,

            MC_FIELD_EMISSION_DEVICE,
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct PHYSICAL_MONITOR
        {
            public IntPtr hPhysicalMonitor;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szPhysicalMonitorDescription;
        }

        #region Imports

        [DllImport("user32.dll", EntryPoint = "MonitorFromWindow")]
        public static extern IntPtr MonitorFromWindow(
            [In] IntPtr hwnd, uint dwFlags);

        [DllImport("dxva2.dll", EntryPoint = "GetMonitorTechnologyType")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetMonitorTechnologyType(
            IntPtr hMonitor, ref MC_DISPLAY_TECHNOLOGY_TYPE pdtyDisplayTechnologyType);

        [DllImport("dxva2.dll", EntryPoint = "GetMonitorCapabilities")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetMonitorCapabilities(
            IntPtr hMonitor, ref uint pdwMonitorCapabilities, ref uint pdwSupportedColorTemperatures);

        [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DestroyPhysicalMonitors(
            uint dwPhysicalMonitorArraySize, ref PHYSICAL_MONITOR[] pPhysicalMonitorArray);

        [DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(
            IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);

        [DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetPhysicalMonitorsFromHMONITOR(
            IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray);

        #endregion

        public Form1() { InitializeComponent(); }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Get monitor handle.
            uint dwFlags = 0u;
            IntPtr ptr = MonitorFromWindow(Handle, dwFlags);

            // Get number of physical monitors.
            uint pdwNumberOfPhysicalMonitors = 0u;
            bool b1 = GetNumberOfPhysicalMonitorsFromHMONITOR(ptr, ref pdwNumberOfPhysicalMonitors);

            if (b1)
            {
                // Get physical monitors.
                uint dwPhysicalMonitorArraySize = 0u;
                dwPhysicalMonitorArraySize = pdwNumberOfPhysicalMonitors;
                PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];

                //NOTE : Handles remain null !
                bool b2 = GetPhysicalMonitorsFromHMONITOR(ptr, dwPhysicalMonitorArraySize, pPhysicalMonitorArray);

                if (pPhysicalMonitorArray[0].hPhysicalMonitor
                    == IntPtr.Zero)
                {
                    throw new Exception("ERROR !");
                }

                // Monitor has capabilities to do that ?
                if (b2)
                {
                    uint pdwMonitorCapabilities = 0u;
                    uint pdwSupportedColorTemperatures = 0u;
                    bool b3 = GetMonitorCapabilities(
                        ptr, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);

                    // If yes, get technology type.
                    if (b3)
                    {
                        MC_DISPLAY_TECHNOLOGY_TYPE type = MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;

                        bool b4 = GetMonitorTechnologyType(ptr, ref type);
                        if (b4)
                        {
                            // Do work.
                        }
                        else
                        {
                            throw new Exception("Couldn't get monitor technology type.");
                        }
                    }
                    else
                    {
                        throw new Exception("Couldn't get monitor capabilities.");
                    }
                }
                else
                {
                    throw new Exception("The monitor doesn't have the required capabilities.");
                }

                bool b5 = DestroyPhysicalMonitors(dwPhysicalMonitorArraySize, ref pPhysicalMonitorArray);
                if (!b5)
                {
                    throw new Exception("Couldn't destroy physical monitors.");
                }
            }
            else
            {
                throw new Exception("Couldn't get number of physical monitors.");
            }
        }
    }
}
  • Linked from the old new thing http://blogs.msdn.com/b/oldnewthing/archive/2015/11/05/10652516.aspx – Joshua Nov 05 '15 at 19:20

3 Answers3

2

It is alright that the hPhysicalMonitor value is 0. However, in the question's code sample all calls after the GetPhysicalMonitorsFromHMONITOR should use the hPhysicalMonitor reference instead of the ptr reference. The updated Form_Load method should be the following:

private void Form1_Load(object sender, EventArgs e)
{
    // Get monitor handle.
    uint dwFlags = 0u;
    IntPtr ptr = MonitorFromWindow(Handle, dwFlags);

    // Get number of physical monitors.
    uint pdwNumberOfPhysicalMonitors = 0u;
    bool b1 = GetNumberOfPhysicalMonitorsFromHMONITOR(ptr, ref pdwNumberOfPhysicalMonitors);

    if (b1)
    {
        // Get physical monitors.
        uint dwPhysicalMonitorArraySize = 0u;
        dwPhysicalMonitorArraySize = pdwNumberOfPhysicalMonitors;
        PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];

        //NOTE : Handles remain null !
        bool b2 = GetPhysicalMonitorsFromHMONITOR(ptr, dwPhysicalMonitorArraySize, pPhysicalMonitorArray);

        // Monitor has capabilities to do that ?
        if (b2)
        {
            uint pdwMonitorCapabilities = 0u;
            uint pdwSupportedColorTemperatures = 0u;
            bool b3 = GetMonitorCapabilities(pPhysicalMonitorArray[0].hPhysicalMonitor, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);

            // If yes, get technology type.
            if (b3)
            {
                MC_DISPLAY_TECHNOLOGY_TYPE type = MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;

                bool b4 = GetMonitorTechnologyType(pPhysicalMonitorArray[0].hPhysicalMonitor, ref type);
                if (b4)
                {
                    // Do work.
                }
                else
                {
                    throw new Exception("Couldn't get monitor technology type.");
                }
            }
            else
            {
                throw new Exception("Couldn't get monitor capabilities.");
            }
        }
        else
        {
            throw new Exception("The monitor doesn't have the required capabilities.");
        }

        bool b5 = DestroyPhysicalMonitors(dwPhysicalMonitorArraySize, ref pPhysicalMonitorArray);
        if (!b5)
        {
            throw new Exception("Couldn't destroy physical monitors.");
        }
    }
    else
    {
        throw new Exception("Couldn't get number of physical monitors.");
    }
}
RodKnee
  • 131
  • 1
  • 5
2

Your statement:

The function returns the string description of the monitor but for some mysterious reasons, the hMonitor handle remains at 0.

is correct. If you look at the docs here, you'll see that hMonitor is clearly an [in] parameter and will not be changed.

Update following comment:

Sorry, didn't realize you meant the physical handle being returned in the structure. All the information I can find on that particular problem seems to indicate that your monitor probably isn't fully DDC/CI compatible (e.g., here).

All your structure definitions look fine to me, based on the docs on MSDN for that particular call. And indeed, it is populating the description for you.

What is the value for the number of physical monitors being returned from GetNumberOfPhysicalMonitorsFromHMONITOR (pdwNumberOfPhysicalMonitors)?

Also, what is the size of your PHYSICAL_MONITOR structure and are you running in 32 or 64 bits?

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Sorry but I made a mistake, I corrected my post. (I was looking for hPhysicalMonitor in fact) –  May 11 '09 at 02:36
  • Useful link. Getting a zero Physical Monitor handle as well but this monitor is DDC/CI (mostly). Checked this through [SoftMCSS](http://www.entechtaiwan.com/lib/softmccs.shtm) and from the scan log their monitor handle corresponds to `hmonitor` above. No mention of a physical handle as such! The zero value might correspond to the device number also listed in the log. Who knows? – Laurie Stearn Apr 25 '17 at 14:43
-1

The monitor supports this function because with software like softMCCS and WinI2C/DDC, the properties are returned correctly.

The return pdwNumberOfPhysicalMonitors value is 1 which is correct.

As you can see, its size is pdwNumberOfPhysicalMonitors :

PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];

And I am running Vista 32.

It is somewhat strange because half of it works, that's now about 4 days I am over it but still no progress ...

Thank you.

  • Also, I had to change the string description in PHYSICAL_MONITOR, because with P/Invoke Interop Assistant, SizeConst was set to -1, which is illegal. –  May 11 '09 at 11:48