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
1 Answer
Reset to default 0You 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
Add the nuget package
Microsoft.Windows.CsWin32
to your projectAdd a file named
NativeMethods.txt
in the root path of your project with the following contentGetDisplayConfigBufferSizes QueryDisplayConfig
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 ); }