single.php

C# WinUI3で有効なモニターの一覧を取得する方法

C# WinUI 3アプリを作っていく途中で、調べたことを忘録的に投稿します。今回はWinUI3プロジェクトで有効なモニター(ディスプレイ)の一覧を取得する方法です。

複数の有効なモニターを取得

こんな感じでパソコンに接続されたモニターの一覧を取得します。

[QueryDisplayConfig]で取得

有効なモニターの一覧を[QueryDisplayConfig]で取得します。

[DllImport("User32.dll")]
public static extern int GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS flags, ref uint numPathArrayElements, ref uint numModeInfoArrayElements);

[DllImport("User32.dll")]
public static extern int QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS flags, ref uint numPathArrayElements, [Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref uint numModeInfoArrayElements, [Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId);

private int GetMonitorArray(ref DISPLAYCONFIG_PATH_INFO[]? pathArray, ref DISPLAYCONFIG_MODE_INFO[]? modeArray)
{
  uint PathArrayLength = 0;
  uint ModeArrayLength = 0;

  QUERY_DEVICE_CONFIG_FLAGS filter = Win32.QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS;
  int Result = Win32.GetDisplayConfigBufferSizes(filter, ref PathArrayLength, ref ModeArrayLength);
  if (Result == ERROR_SUCCESS)
  {
    pathArray = new DISPLAYCONFIG_PATH_INFO[PathArrayLength];
    modeArray = new DISPLAYCONFIG_MODE_INFO[ModeArrayLength];
    Result = QueryDisplayConfig(filter, ref PathArrayLength, pathArray, ref ModeArrayLength, modeArray, IntPtr.Zero);
  }
  return Result;
}

[DisplayConfigGetDeviceInfo]で名前を取得

取得した有効なディスプレイの一覧から[DisplayConfigGetDeviceInfo]で名前を取得します。

private string GetMonitorName(int Index, DISPLAYCONFIG_PATH_INFO[]? pathArray)
{
  string MonitorName = "";
  if (pathArray != null)
  {
    DISPLAYCONFIG_TARGET_DEVICE_NAME displayconfigTargetDeviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
    displayconfigTargetDeviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
    displayconfigTargetDeviceName.header.adapterId = pathArray[Index].targetInfo.adapterId;
    displayconfigTargetDeviceName.header.id = pathArray[Index].targetInfo.id;
    displayconfigTargetDeviceName.header.size = (uint)Marshal.SizeOf(typeof(DISPLAYCONFIG_TARGET_DEVICE_NAME));
    if (DisplayConfigGetDeviceInfo(ref displayconfigTargetDeviceName) == ERROR_SUCCESS)
    {
      MonitorName = displayconfigTargetDeviceName.monitorFriendlyDeviceName.ToString();
    }
  }
  return MonitorName;
}

モニターの一覧を表示

Xamlに表示するコンボボックスを追加します。

<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
  <StackPanel Orientation="Vertical">
    <ComboBox Name="MonitorList" Width="120"></ComboBox>
  </StackPanel>
</Grid>

最後に、取得した一覧をコンボボックスに追加するコードを追加します。

public MonitorList()
{
  InitializeComponent();
  SetupMonitorList();
}

private void SetupMonitorList()
{
  DISPLAYCONFIG_PATH_INFO[]? pathArray = null;
  DISPLAYCONFIG_MODE_INFO[]? modeArray = null;

  if (GetMonitorArray(ref pathArray, ref modeArray) == ERROR_SUCCESS)
  {
    if(pathArray == null)
    {
      return;
    }
    for (int Index = 0; Index < pathArray.Length; Index++)
    {
      MonitorList.Items.Add(GetMonitorName(Index, pathArray));
    }
  }
}

実行すると有効なモニターの名前がコンボボックスに追加されます。(私の場合、同じ機種のモニターが2つあるので一覧では同じ名前になっています)

最後に長くなりますが、[DisplayConfigGetDeviceInfo]と[QueryDisplayConfig]で利用した構造体と列挙値を記載します。

public const int ERROR_SUCCESS = 0;

public static uint SDC_APPLY = 0x00000080;
public static uint SDC_USE_SUPPLIED_DISPLAY_CONFIG = 0x00000020;
public static uint SDC_ALLOW_CHANGES = 0x00000400;
public static uint SDC_TOPOLOGY_INTERNAL = 0x00000001;

public enum QUERY_DEVICE_CONFIG_FLAGS : uint
{
  QDC_ALL_PATHS = 0x00000001,
  QDC_ONLY_ACTIVE_PATHS = 0x00000002,
  QDC_DATABASE_CURRENT = 0x00000004
}

public struct DISPLAYCONFIG_PATH_INFO
{
  public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
  public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
  public uint flags;
}

public struct LUID
{
  public uint LowPart;
  public int HighPart;
}

public struct DISPLAYCONFIG_PATH_SOURCE_INFO
{
  public LUID adapterId;
  public uint id;
  public uint modeInfoIdx;
  public uint statusFlags;
}

public struct DISPLAYCONFIG_PATH_TARGET_INFO
{
  public LUID adapterId;
  public uint id;
  public uint modeInfoIdx;
  DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
  DISPLAYCONFIG_ROTATION rotation;
  DISPLAYCONFIG_SCALING scaling;
  DISPLAYCONFIG_RATIONAL refreshRate;
  DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
  public bool targetAvailable;
  public uint statusFlags;
}


public struct DISPLAYCONFIG_RATIONAL
{
  public uint Numerator;
  public uint Denominator;
}

public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint
{
  DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
  DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
  DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
  DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
  DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
  DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF
}

public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint
{
  DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
  DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
  DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF
}

public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint
{
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 0xFFFFFFFF,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000,
  DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF
}

public enum DISPLAYCONFIG_ROTATION : uint
{
  DISPLAYCONFIG_ROTATION_IDENTITY = 1,
  DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
  DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
  DISPLAYCONFIG_ROTATION_ROTATE270 = 4,
  DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF
}
public enum DISPLAYCONFIG_SCALING : uint
{
  DISPLAYCONFIG_SCALING_IDENTITY = 1,
  DISPLAYCONFIG_SCALING_CENTERED = 2,
  DISPLAYCONFIG_SCALING_STRETCHED = 3,
  DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
  DISPLAYCONFIG_SCALING_CUSTOM = 5,
  DISPLAYCONFIG_SCALING_PREFERRED = 128,
  DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF
}
public enum DISPLAYCONFIG_PIXELFORMAT : uint
{
  DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
  DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
  DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
  DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
  DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
  DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xFFFFFFFF
}

public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint
{
  DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
  DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
  DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
  DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
  DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
  DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
  DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
  DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
  DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
  DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
  DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
  DISPLAYCONFIG_DEVICE_INFO_GET_MONITOR_SPECIALIZATION,
  DISPLAYCONFIG_DEVICE_INFO_SET_MONITOR_SPECIALIZATION,
  DISPLAYCONFIG_DEVICE_INFO_SET_RESERVED1,
  DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2,
  DISPLAYCONFIG_DEVICE_INFO_SET_HDR_STATE,
  DISPLAYCONFIG_DEVICE_INFO_SET_WCG_STATE,
  DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF,
}

public struct DISPLAYCONFIG_MODE_INFO
{
  public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
  public uint id;
  public LUID adapterId;
  public DISPLAYCONFIG_MODE_INFO_UNION modeInfo;
}

[StructLayout(LayoutKind.Explicit)]
public struct DISPLAYCONFIG_MODE_INFO_UNION
{
  [FieldOffset(0)]
  public DISPLAYCONFIG_TARGET_MODE targetMode;
  [FieldOffset(0)]
  public DISPLAYCONFIG_SOURCE_MODE sourceMode;
}

public struct DISPLAYCONFIG_TARGET_MODE
{
  public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
}

public struct DISPLAYCONFIG_SOURCE_MODE
{
  public uint width;
  public uint height;
  public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
  public POINTL position;
}

public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
{
  public ulong pixelRate;
  public DISPLAYCONFIG_RATIONAL hSyncFreq;
  public DISPLAYCONFIG_RATIONAL vSyncFreq;
  public DISPLAYCONFIG_2DREGION activeSize;
  public DISPLAYCONFIG_2DREGION totalSize;
  public uint videoStandard;
  public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
}

public struct POINTL
{
  int x;
  int y;
}

public struct DISPLAYCONFIG_2DREGION
{
  public uint cx;
  public uint cy;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAYCONFIG_TARGET_DEVICE_NAME
{
  public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
  public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
  public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
  public ushort edidManufactureId;
  public ushort edidProductCodeId;
  public uint connectorInstance;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
  public string monitorFriendlyDeviceName;

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

public struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
  public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
  public uint size;
  public LUID adapterId;
  public uint id;
}

public struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
{
  public uint flag;
}

まとめ

今回は、WinUI3プロジェクトで有効なモニター(ディスプレイ)の一覧を取得する方法について書きました。

名前を取得するだけでも、非常に多くの構造体と列挙値が必要になりますが、Win32APIの[DisplayConfigGetDeviceInfo]と[QueryDisplayConfig]を利用して有効なモニターの一覧が取得できました。

また、文字列変数を利用している[DISPLAYCONFIG_TARGET_DEVICE_NAME]は[Charset]設定に注意が必要です。

WinUI 3で、有効なモニター(ディスプレイ)の一覧を取得したい人の参考になれば幸いです。

スポンサーリンク

最後までご覧いただき、ありがとうございます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です