public class EDPController
{
[Flags]
private enum SdcFlags : uint
{
Zero = 0,
Apply = 0x00000080,
UseSuppliedDisplayConfig = 0x00000020,
PathPersistIfRequired = 0x00001000,
AllowChanges = 0x00000400,
SaveToDatabase = 0x00000200,
}
private enum QueryDisplayFlags : uint
{
AllPaths = 0x00000001
}
private enum DisplayConfigVideoOutputTechnology : uint
{
Hdmi = 5,
DisplayportExternal = 6,
EmbeddedDisplayport = 11, // eDP identifier
Internal = 10,
}
[StructLayout(LayoutKind.Sequential)]
private struct DisplayConfigPathInfo
{
public DisplayConfigPathSourceInfo sourceInfo;
public DisplayConfigPathTargetInfo targetInfo;
public uint flags;
}
[StructLayout(LayoutKind.Sequential)]
private struct DisplayConfigPathSourceInfo
{
public uint adapterIdLowPart;
public uint adapterIdHighPart;
public uint id;
public uint modeInfoIdx;
public uint statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
private struct DisplayConfigPathTargetInfo
{
public uint adapterIdLowPart;
public uint adapterIdHighPart;
public uint id;
public uint modeInfoIdx;
public DisplayConfigVideoOutputTechnology outputTechnology;
public uint rotation;
public uint scaling;
public uint refreshRateNumerator;
public uint refreshRateDenominator;
public uint scanLineOrdering;
public bool targetAvailable;
public uint statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
private struct DisplayConfigModeInfo
{
public uint infoType;
public uint id;
public uint adapterIdLowPart;
public uint adapterIdHighPart;
public uint modeInfoIdx;
}
[DllImport("user32.dll")]
private static extern int GetDisplayConfigBufferSizes(
QueryDisplayFlags flags,
out uint numPathArrayElements,
out uint numModeInfoArrayElements);
[DllImport("user32.dll")]
private static extern int QueryDisplayConfig(
QueryDisplayFlags flags,
ref uint numPathArrayElements,
[Out] DisplayConfigPathInfo[] pathArray,
ref uint numModeInfoArrayElements,
[Out] DisplayConfigModeInfo[] modeInfoArray,
IntPtr currentTopologyId);
[DllImport("user32.dll")]
private static extern int SetDisplayConfig(
uint numPathArrayElements,
[In] DisplayConfigPathInfo[] pathArray,
uint numModeInfoArrayElements,
[In] DisplayConfigModeInfo[] modeInfoArray,
SdcFlags flags);
private const int DISP_CHANGE_SUCCESSFUL = 0;
public void DisableEDP()
{
ModifyEDPState(false);
}
public void EnableEDP()
{
ModifyEDPState(true);
}
private void ModifyEDPState(bool enable)
{
uint pathCount, modeCount;
// Get buffer sizes for display paths and modes
int result = GetDisplayConfigBufferSizes(QueryDisplayFlags.AllPaths, out pathCount, out modeCount);
if (result != DISP_CHANGE_SUCCESSFUL)
throw new Exception("Failed to get display configuration buffer sizes.");
var paths = new DisplayConfigPathInfo[pathCount];
var modes = new DisplayConfigModeInfo[modeCount];
// Query the current display configuration
result = QueryDisplayConfig(QueryDisplayFlags.AllPaths, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (result != DISP_CHANGE_SUCCESSFUL)
throw new Exception("Failed to query display configuration.");
// Modify the path to enable/disable the eDP display
for (int i = 0; i < paths.Length; i++)
{
if (paths[i].targetInfo.outputTechnology == DisplayConfigVideoOutputTechnology.EmbeddedDisplayport
|| paths[i].targetInfo.outputTechnology == DisplayConfigVideoOutputTechnology.Internal)
{
if (enable)
{
paths[i].flags &= ~(uint)0x2; // Clear the "disabled" flag
}
else
{
paths[i].flags |= 0x2; // Set the "disabled" flag
}
}
}
// Apply the updated display configuration
result = SetDisplayConfig(pathCount, paths, modeCount, modes, SdcFlags.Apply | SdcFlags.UseSuppliedDisplayConfig);
if (result != DISP_CHANGE_SUCCESSFUL)
throw new Exception($"Failed to {(enable ? "enable" : "disable")} eDP monitor.");
}
}
10 и 5 — это дисплеи, найденные в путях, поэтому я сосредоточился только на них и попытался отключить оба. Но в реальном приложении я отключу дисплей, подключенный к EDp по умолчанию.
К сожалению, единственный эффект, который я получаю, — это короткое моргание, но не отключение. Есть ли способ отключить монитор от системной службы (т.е. нет доступа к пользовательскому интерфейсу)?
[StructLayout(LayoutKind.Sequential)] private struct DisplayConfigPathInfo { public DisplayConfigPathSourceInfo sourceInfo; public DisplayConfigPathTargetInfo targetInfo; public uint flags; }
[StructLayout(LayoutKind.Sequential)] private struct DisplayConfigPathSourceInfo { public uint adapterIdLowPart; public uint adapterIdHighPart; public uint id; public uint modeInfoIdx; public uint statusFlags; }
[StructLayout(LayoutKind.Sequential)] private struct DisplayConfigPathTargetInfo { public uint adapterIdLowPart; public uint adapterIdHighPart; public uint id; public uint modeInfoIdx; public DisplayConfigVideoOutputTechnology outputTechnology; public uint rotation; public uint scaling; public uint refreshRateNumerator; public uint refreshRateDenominator; public uint scanLineOrdering; public bool targetAvailable; public uint statusFlags; }
[StructLayout(LayoutKind.Sequential)] private struct DisplayConfigModeInfo { public uint infoType; public uint id; public uint adapterIdLowPart; public uint adapterIdHighPart; public uint modeInfoIdx; }
[DllImport("user32.dll")] private static extern int GetDisplayConfigBufferSizes( QueryDisplayFlags flags, out uint numPathArrayElements, out uint numModeInfoArrayElements);
// Get buffer sizes for display paths and modes int result = GetDisplayConfigBufferSizes(QueryDisplayFlags.AllPaths, out pathCount, out modeCount); if (result != DISP_CHANGE_SUCCESSFUL) throw new Exception("Failed to get display configuration buffer sizes.");
var paths = new DisplayConfigPathInfo[pathCount]; var modes = new DisplayConfigModeInfo[modeCount];
// Query the current display configuration result = QueryDisplayConfig(QueryDisplayFlags.AllPaths, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero); if (result != DISP_CHANGE_SUCCESSFUL) throw new Exception("Failed to query display configuration.");
// Modify the path to enable/disable the eDP display for (int i = 0; i < paths.Length; i++) { if (paths[i].targetInfo.outputTechnology == DisplayConfigVideoOutputTechnology.EmbeddedDisplayport || paths[i].targetInfo.outputTechnology == DisplayConfigVideoOutputTechnology.Internal) { if (enable) { paths[i].flags &= ~(uint)0x2; // Clear the "disabled" flag } else { paths[i].flags |= 0x2; // Set the "disabled" flag } } }
// Apply the updated display configuration result = SetDisplayConfig(pathCount, paths, modeCount, modes, SdcFlags.Apply | SdcFlags.UseSuppliedDisplayConfig); if (result != DISP_CHANGE_SUCCESSFUL) throw new Exception($"Failed to {(enable ? "enable" : "disable")} eDP monitor."); } } [/code] 10 и 5 — это дисплеи, найденные в путях, поэтому я сосредоточился только на них и попытался отключить оба. Но в реальном приложении я отключу дисплей, подключенный к EDp по умолчанию. К сожалению, единственный эффект, который я получаю, — это короткое моргание, но не отключение. Есть ли способ отключить монитор от системной службы (т.е. нет доступа к пользовательскому интерфейсу)?