问题
I try to change my gamma of just one screen and not all my screens.
I use this code to help me
But this SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref s_ramp);
Is for all devices.
[EDIT2] I saw one weird thing : SetDeviceGammaRamp is not the same gamma of the Nvidia Panel Controller (I tried to change my value of SetDeviceGammaRamp, and it's like if i changed the value of brightness and contrast in the Nvidia panel). So i think i must to use NVidia API :/
So, how can i change this code to put my gamma on my first screen, or my second, but not both
[EDIT1] This is what i made :
class Monitor
{
[DllImport("user32.dll")]
static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
public delegate int MonitorEnumProc(IntPtr hMonitor, IntPtr hDCMonitor, ref Rect lprcMonitor, IntPtr dwData);
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool GetMonitorInfo(IntPtr hmon, ref MonitorInfo mi);
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
/// <summary>
/// The struct that contains the display information
/// </summary>
public class DisplayInfo
{
public string Availability { get; set; }
public string ScreenHeight { get; set; }
public string ScreenWidth { get; set; }
public Rect MonitorArea { get; set; }
public Rect WorkArea { get; set; }
public IntPtr DC { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
struct MonitorInfo
{
public uint size;
public Rect monitor;
public Rect work;
public uint flags;
}
/// <summary>
/// Collection of display information
/// </summary>
public class DisplayInfoCollection : List<DisplayInfo>
{
}
/// <summary>
/// Returns the number of Displays using the Win32 functions
/// </summary>
/// <returns>collection of Display Info</returns>
public DisplayInfoCollection GetDisplays()
{
DisplayInfoCollection col = new DisplayInfoCollection();
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData)
{
MonitorInfo mi = new MonitorInfo();
mi.size = (uint)Marshal.SizeOf(mi);
bool success = GetMonitorInfo(hMonitor, ref mi);
if (success)
{
DisplayInfo di = new DisplayInfo();
di.ScreenWidth = (mi.monitor.right - mi.monitor.left).ToString();
di.ScreenHeight = (mi.monitor.bottom - mi.monitor.top).ToString();
di.MonitorArea = mi.monitor;
di.WorkArea = mi.work;
di.Availability = mi.flags.ToString();
di.DC = GetDC(hdcMonitor);
col.Add(di);
}
return 1;
}, IntPtr.Zero);
return col;
}
public Monitor()
{
}
}
And for SetDeviceGammaRamp, i made this :
GammaRamp gamma = new GammaRamp();
Monitor.DisplayInfoCollection monitors;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Monitor monitor = new Monitor();
monitors = monitor.GetDisplays();
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
int value = trackBar1.Value;
gamma.SetValue(Convert.ToByte(value), monitors[1].DC);
}
GammaRamp class :
public void SetValue(byte value, IntPtr hdc)
{
Ramp gammaArray = new Ramp { Red = new ushort[256], Green = new ushort[256], Blue = new ushort[256] };
for (int i = 0; i < 256; i++)
{
gammaArray.Red[i] = gammaArray.Green[i] = gammaArray.Blue[i] = (ushort)Math.Min(i * (value + 128), ushort.MaxValue);
}
SetDeviceGammaRamp(hdc, ref gammaArray);
}
回答1:
You can get the DC of another monitor by using EnumDisplayMonitors or GetMonitorInfo functions.
See complete explanations at HMONITOR and the Device Context.
EDIT
As explained in EnumDisplayMonitors,
- pass
IntPtr.Zero
tohdc
parameter (values encompasses all displays) - then in MONITORENUMPROC,
hdcMonitor
should contain the right DC for the current monitor being evaluated - then change your
di.DC = GetDC(IntPtr.Zero);
todi.DC = GetDC(hdcMonitor);
(passing Zero
to GetDC
will obviously specify all monitors, not what you want)
EDIT 2
Little confusion with the docs, in fact the 3rd type of call in the remarks of EnumDisplayMonitors should be performed:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow
{
private readonly List<IntPtr> _dcs = new List<IntPtr>();
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var hdc = NativeMethods.GetDC(IntPtr.Zero);
if (hdc == IntPtr.Zero)
throw new InvalidOperationException();
if (!NativeMethods.EnumDisplayMonitors(hdc, IntPtr.Zero, Monitorenumproc, IntPtr.Zero))
throw new InvalidOperationException();
if (NativeMethods.ReleaseDC(IntPtr.Zero, hdc) == 0)
throw new InvalidOperationException();
foreach (var monitorDc in _dcs)
{
// do something cool !
}
}
private int Monitorenumproc(IntPtr param0, IntPtr param1, ref tagRECT param2, IntPtr param3)
{
// optional actually ...
var info = new MonitorInfo {cbSize = (uint) Marshal.SizeOf<MonitorInfo>()};
if (!NativeMethods.GetMonitorInfoW(param0, ref info))
throw new InvalidOperationException();
_dcs.Add(param1); // grab DC for current monitor !
return 1;
}
}
public class NativeMethods
{
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
public static extern int ReleaseDC([In] IntPtr hWnd, [In] IntPtr hDC);
[DllImport("user32.dll", EntryPoint = "GetDC")]
public static extern IntPtr GetDC([In] IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "GetMonitorInfoW")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorInfoW([In] IntPtr hMonitor, ref MonitorInfo lpmi);
[DllImport("user32.dll", EntryPoint = "EnumDisplayMonitors")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDisplayMonitors([In] IntPtr hdc, [In] IntPtr lprcClip, MONITORENUMPROC lpfnEnum,
IntPtr dwData);
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int MONITORENUMPROC(IntPtr param0, IntPtr param1, ref tagRECT param2, IntPtr param3);
[StructLayout(LayoutKind.Sequential)]
public struct MonitorInfo
{
public uint cbSize;
public tagRECT rcMonitor;
public tagRECT rcWork;
public uint dwFlags;
}
[StructLayout(LayoutKind.Sequential)]
public struct tagRECT
{
public int left;
public int top;
public int right;
public int bottom;
}
}
You should be able to get per-monitor DC, (cannot 100% confirm since I only have one screen).
If all else fails then maybe that NVidia thing interferes somehow under the hood.
来源:https://stackoverflow.com/questions/34486842/how-to-change-the-gamma-ramp-of-a-single-display-monitor-nvidia-config