single.php

C# WinUI3で[Marshal.SizeOf]で構造体サイズが取得できない場合の対処法

C# WinUI 3アプリを作っていく途中で、調べたことを忘録的に投稿します。今回はWinUI3プロジェクトで文字列[string]変数を含む構造体のサイズが[Marshal.SizeOf]メソッドで正しく取得できない場合の対処法です。

[CharSet]が必要

例えば、こんな感じで文字列型を含んだ構造体のサイズを

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;
}

[Marshal.SizeOf]で取得します。

uint StructSize = (uint)Marshal.SizeOf(typeof(DISPLAYCONFIG_TARGET_DEVICE_NAME));

で、[DisplayConfigGetDeviceInfo]などの関数に引き渡すと、[ERROR_INVALID_PARAMETER(87)]のエラーで取得できません。

文字列型を含む構造体に[CharSet]設定を追加すると改善する可能性があります。

具体的には、こんな感じに構造体を変更します。

[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;
}

おそらくWin32 APIで利用している文字列変数が、WCHAR型なのが影響してそうですが[CharSet = CharSet.Unicode]にすると取得できました。

まとめ

今回は短い記事ですが、WinUI3プロジェクトで文字列[string]変数を含む構造体のサイズが[Marshal.SizeOf]メソッドで正しく取得できない場合の対処法について紹介しました。

構造体に文字列変数を利用している場合には[Charset]設定に注意が必要です。

WinUI 3で、[Marshal.SizeOf]メソッドで構造体のサイズが正しく取得できない人の参考になれば幸いです。

スポンサーリンク

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

コメントを残す

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