最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - QueryDisplayConfigSetDisplayConfig APIs set resolution failed - Stack Overflow

programmeradmin7浏览0评论

When using the QueryDisplayConfig/SetDisplayedConfig APIs to modify screen resolution, regardless of the operation, the code 87 is returned. I cannot know what caused it. I used the method of VNet DisplayedConfig Buffer Sizes, but I still failed [Image]: .png Here is my complete code:

using System;
using System.IO;
using System.Runtime.InteropServices;

class Program
{
    // Structure definition
    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_PATH_INFO
    {
        public uint pathId;
        public uint sourceMode;
        public uint targetMode;
        public uint statusFlags;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_MODE_INFO
    {
        public uint width;
        public uint height;
        public uint refreshRate;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_PATH_INFO_V2
    {
        public uint pathId;
        public DISPLAYCONFIG_MODE_INFO sourceMode;
        public DISPLAYCONFIG_MODE_INFO targetMode;
        public uint statusFlags;
    }

    // API
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int GetDisplayConfigBufferSizes(uint pathInfoCount, uint modeInfoCount, ref uint pathInfoSize, ref uint modeInfoSize);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int QueryDisplayConfig(uint flags, ref uint pathInfoSize, IntPtr pathInfo, ref uint modeInfoSize, IntPtr modeInfo, IntPtr currentSettings);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SetDisplayConfig(uint flags, uint pathInfoCount, IntPtr pathInfo, uint modeInfoCount, IntPtr modeInfo, uint currentSettings);

    const uint SDC_TOPOLOGY_CLONE = 0x00000001;
    const uint SDC_TOPOLOGY_EXTEND = 0x00000002;
    const uint SDC_TOPOLOGY_INTERNAL = 0x00000004;

    // log
   private static void Log(string message)
    {
        string logMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}";
        Console.WriteLine(logMessage);

        // Optionally log to a file
        try
        {
            string logFile = "screen_resolution_change.log";
            File.AppendAllText(logFile, logMessage + Environment.NewLine);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error writing to log file: {ex.Message}");
        }
    }

   public static void Main()
    {
        uint pathInfoSize = 0;
        uint modeInfoSize = 0;

        // Get buffer size
        Log("Getting buffer sizes for display configuration...");
        int result = GetDisplayConfigBufferSizes(0, 0, ref pathInfoSize, ref modeInfoSize);
        if (result != 0)
        {
            Log($"Error in GetDisplayConfigBufferSizes: {result}");
            return;
        }

        Log($"Buffer sizes - PathInfoSize: {pathInfoSize}, ModeInfoSize: {modeInfoSize}");

        // Allocate memory for path information and mode information
        IntPtr pathInfoBuffer = Marshal.AllocHGlobal((int)pathInfoSize);
        IntPtr modeInfoBuffer = Marshal.AllocHGlobal((int)modeInfoSize);

        try
        {
            // Query display configuration
            Log("Querying current display configuration...");
            result = QueryDisplayConfig(0, ref pathInfoSize, pathInfoBuffer, ref modeInfoSize, modeInfoBuffer, IntPtr.Zero);
            if (result != 0)
            {
                Log($"Error in QueryDisplayConfig: {result}");
                return;
            }

            Log("Current display configuration retrieved successfully.");

            // Obtain and modify resolution
            DISPLAYCONFIG_PATH_INFO_V2 pathInfo = Marshal.PtrToStructure<DISPLAYCONFIG_PATH_INFO_V2>(pathInfoBuffer);
            DISPLAYCONFIG_MODE_INFO newMode = pathInfo.sourceMode;
            newMode.width = 1920; // New resolution width
            newMode.height = 1080; // New resolution height

            // Output the modified resolution
            Log($"Changing resolution to {newMode.width}x{newMode.height}");

            // Modify display settings
            Marshal.StructureToPtr(newMode, modeInfoBuffer, false);

            // Apply new display configuration
            Log("Applying new display configuration...");
            result = SetDisplayConfig(0, 1, pathInfoBuffer, 1, modeInfoBuffer, 0);
            if (result != 0)
            {
                Log($"Error in SetDisplayConfig: {result}");
            }
            else
            {
                Log("Resolution changed successfully!");
            }
        }
        finally
        {
            // free memory
            Marshal.FreeHGlobal(pathInfoBuffer);
            Marshal.FreeHGlobal(modeInfoBuffer);
        }
    }
}

When using the QueryDisplayConfig/SetDisplayedConfig APIs to modify screen resolution, regardless of the operation, the code 87 is returned. I cannot know what caused it. I used the method of VNet DisplayedConfig Buffer Sizes, but I still failed [Image]: https://i.sstatic/gY0OfDlI.png Here is my complete code:

using System;
using System.IO;
using System.Runtime.InteropServices;

class Program
{
    // Structure definition
    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_PATH_INFO
    {
        public uint pathId;
        public uint sourceMode;
        public uint targetMode;
        public uint statusFlags;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_MODE_INFO
    {
        public uint width;
        public uint height;
        public uint refreshRate;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_PATH_INFO_V2
    {
        public uint pathId;
        public DISPLAYCONFIG_MODE_INFO sourceMode;
        public DISPLAYCONFIG_MODE_INFO targetMode;
        public uint statusFlags;
    }

    // API
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int GetDisplayConfigBufferSizes(uint pathInfoCount, uint modeInfoCount, ref uint pathInfoSize, ref uint modeInfoSize);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int QueryDisplayConfig(uint flags, ref uint pathInfoSize, IntPtr pathInfo, ref uint modeInfoSize, IntPtr modeInfo, IntPtr currentSettings);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SetDisplayConfig(uint flags, uint pathInfoCount, IntPtr pathInfo, uint modeInfoCount, IntPtr modeInfo, uint currentSettings);

    const uint SDC_TOPOLOGY_CLONE = 0x00000001;
    const uint SDC_TOPOLOGY_EXTEND = 0x00000002;
    const uint SDC_TOPOLOGY_INTERNAL = 0x00000004;

    // log
   private static void Log(string message)
    {
        string logMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}";
        Console.WriteLine(logMessage);

        // Optionally log to a file
        try
        {
            string logFile = "screen_resolution_change.log";
            File.AppendAllText(logFile, logMessage + Environment.NewLine);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error writing to log file: {ex.Message}");
        }
    }

   public static void Main()
    {
        uint pathInfoSize = 0;
        uint modeInfoSize = 0;

        // Get buffer size
        Log("Getting buffer sizes for display configuration...");
        int result = GetDisplayConfigBufferSizes(0, 0, ref pathInfoSize, ref modeInfoSize);
        if (result != 0)
        {
            Log($"Error in GetDisplayConfigBufferSizes: {result}");
            return;
        }

        Log($"Buffer sizes - PathInfoSize: {pathInfoSize}, ModeInfoSize: {modeInfoSize}");

        // Allocate memory for path information and mode information
        IntPtr pathInfoBuffer = Marshal.AllocHGlobal((int)pathInfoSize);
        IntPtr modeInfoBuffer = Marshal.AllocHGlobal((int)modeInfoSize);

        try
        {
            // Query display configuration
            Log("Querying current display configuration...");
            result = QueryDisplayConfig(0, ref pathInfoSize, pathInfoBuffer, ref modeInfoSize, modeInfoBuffer, IntPtr.Zero);
            if (result != 0)
            {
                Log($"Error in QueryDisplayConfig: {result}");
                return;
            }

            Log("Current display configuration retrieved successfully.");

            // Obtain and modify resolution
            DISPLAYCONFIG_PATH_INFO_V2 pathInfo = Marshal.PtrToStructure<DISPLAYCONFIG_PATH_INFO_V2>(pathInfoBuffer);
            DISPLAYCONFIG_MODE_INFO newMode = pathInfo.sourceMode;
            newMode.width = 1920; // New resolution width
            newMode.height = 1080; // New resolution height

            // Output the modified resolution
            Log($"Changing resolution to {newMode.width}x{newMode.height}");

            // Modify display settings
            Marshal.StructureToPtr(newMode, modeInfoBuffer, false);

            // Apply new display configuration
            Log("Applying new display configuration...");
            result = SetDisplayConfig(0, 1, pathInfoBuffer, 1, modeInfoBuffer, 0);
            if (result != 0)
            {
                Log($"Error in SetDisplayConfig: {result}");
            }
            else
            {
                Log("Resolution changed successfully!");
            }
        }
        finally
        {
            // free memory
            Marshal.FreeHGlobal(pathInfoBuffer);
            Marshal.FreeHGlobal(modeInfoBuffer);
        }
    }
}
Share Improve this question edited Nov 20, 2024 at 2:23 BestYuan asked Nov 19, 2024 at 2:20 BestYuanBestYuan 11 bronze badge 2
  • 87 is ERROR_INVALID_PARAMETER - so check your parameters – Sir Rufo Commented Nov 19, 2024 at 4:13
  • Sir, What parameters should I pass in during the first call? – BestYuan Commented Nov 19, 2024 at 7:32
Add a comment  | 

1 Answer 1

Reset to default 0

You have to call the method GetDisplayConfigBufferSizes first to determine the length of both arrays. After that you can call the method QueryDisplayConfig.

Here a complete example how to call that Win32 methods

  1. Add the nuget package Microsoft.Windows.CsWin32 to your project

  2. Add a file named NativeMethods.txt in the root path of your project with the following content

    GetDisplayConfigBufferSizes
    QueryDisplayConfig
    
  3. Finally the code to call both methods

    using System.ComponentModel;
    
    using Windows.Win32;
    using Windows.Win32.Devices.Display;
    using Windows.Win32.Foundation;
    
    QUERY_DISPLAY_CONFIG_FLAGS flags = QUERY_DISPLAY_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS;
    
    CheckWin32Error( PInvoke.GetDisplayConfigBufferSizes( flags,
        out uint numInfoPathArrayElements,
        out uint numInfoModesArrayElements ) );
    
    DISPLAYCONFIG_PATH_INFO[] infoPaths = new DISPLAYCONFIG_PATH_INFO[numInfoPathArrayElements];
    DISPLAYCONFIG_MODE_INFO[] infoModes = new DISPLAYCONFIG_MODE_INFO[numInfoModesArrayElements];
    
    unsafe
    {
        DISPLAYCONFIG_TOPOLOGY_ID* currentTopologyId = null;
    
        fixed ( DISPLAYCONFIG_PATH_INFO* pInfoPaths = infoPaths )
        fixed ( DISPLAYCONFIG_MODE_INFO* pInfoModes = infoModes )
        {
            CheckWin32Error( PInvoke.QueryDisplayConfig( flags,
                ref numInfoPathArrayElements,
                pInfoPaths, ref numInfoModesArrayElements, pInfoModes, currentTopologyId ) );
        }
    }
    
    // now handle the data in infoPaths and infoModes
    
    return;
    
    static void CheckWin32Error( WIN32_ERROR result )
    {
        if ( result == WIN32_ERROR.NO_ERROR )
        {
            return;
        }
    
        throw new Win32Exception( (int)result );
    }
    
发布评论

评论列表(0)

  1. 暂无评论