1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C# Win32API ShellExecuteExでWindows 10の「コンピューターの基本的な情報の表示」を表示する

Last updated at Posted at 2020-06-25

本文

Windows 10ではデスクトップのPCアイコンのプロパティから「コンピューターの基本的な情報の表示」を表示できます。C#ではSHGetKnownFolderIDListFOLDERID_ComputerFolderを与えてLPITEMIDLISTを取得した後、SEE_MASK_INVOKEIDLISTを指定してShellExecuteExWを呼び出すことでこれを表示できます。

using System;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    class Program
    {
        static void Main()
        {
            var pidlComputer = default(IntPtr);
            try
            {
                pidlComputer = NativeMethods.SHGetKnownFolderIDList(
                    FOLDERID_ComputerFolder,
                    KF_FLAG_DEFAULT,
                    IntPtr.Zero);

                var sei = new SHELLEXECUTEINFOW
                {
                    cbSize = (uint)Marshal.SizeOf<SHELLEXECUTEINFOW>(),
                    fMask = SEE_MASK_INVOKEIDLIST,
                    lpVerb = "properties",
                    lpIDList = pidlComputer
                };
                NativeMethods.ShellExecuteExW(ref sei);
            }
            finally
            {
                Marshal.FreeCoTaskMem(pidlComputer);
            }
        }

        private static class NativeMethods
        {
            [DllImport("shell32.dll", ExactSpelling = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool ShellExecuteExW(
                ref SHELLEXECUTEINFOW pExecInfo);

            [DllImport("shell32.dll", ExactSpelling = true, PreserveSig = false)]
            public static extern IntPtr SHGetKnownFolderIDList(
                [MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
                uint dwFlags,
                IntPtr hToken);
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct SHELLEXECUTEINFOW
        {
            public uint cbSize;
            public uint fMask;
            public IntPtr hwnd;
            public string lpVerb;
            public string lpFile;
            public string lpParameters;
            public string lpDirectory;
            public int nShow;
            public IntPtr hInstApp;
            public IntPtr lpIDList;
            public IntPtr lpClass;
            public IntPtr hkeyClass;
            public uint dwHotKey;
            public IntPtr hIconOrMonitor;
            public IntPtr hProcess;
        }

        private static readonly Guid FOLDERID_ComputerFolder = Guid.Parse(
            "{0AC0837C-BBF8-452A-850D-79D08E667CA7}");

        private const uint KF_FLAG_DEFAULT = 0;

        private const uint SEE_MASK_INVOKEIDLIST = 0x0000000C;
    }
}

Windows 10以外ではおそらく普通にPCのプロパティが表示されます。

アンマネージリソースとtry...finally

var pidlComputer = default(IntPtr);
try
{
    pidlComputer = NativeMethods.SHGetKnownFolderIDList(...);
    ...
}
finally
{
    Marshal.FreeCoTaskMem(pidlComputer);
}

SHGetKnownFolderIDListの戻り値であるpidlComputerはアンマネージリソースのポインタであり、Marshal.FreeCoTaskMemで解放する必要があります。tryの中でvar pidlComputer = ...とするとfinallyのスコープからはpidlComputerを参照できないので、tryの外側でpidlComputerを宣言しています。

この冗長さを回避するためにはSafeHandleの派生クラスを作成してusingと組み合わせます。

オブジェクト初期化子による構造体の初期化

var sei = new SHELLEXECUTEINFOW
{
    cbSize = ...
};

構造体はnew 型名 {field1 = ..., field2 = ..., ...}の形式で初期化できます。

構造体中のstringのP/Invoke

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct SHELLEXECUTEINFOW
{
    ...
    public string lpVerb;
    ...
]

P/Invoke時(DllImport属性を持つ関数の呼び出し時)、構造体中の文字列は自動的にIntPtr型へ変換・復元されます。IntPtrを指定して毎回Marshal.PtrToStringAnsi/Uniを呼び出すこともできますが、文字列を再利用しなければこちらの方が簡潔です。変換時のANSI/UNICODEはStructLayout属性のCharSetで指定します。

UnmanagedType.LPStruct

C#側で値渡しした構造体(Guid等)をP/Invoke時にそのポインタとして渡します。C++のREFCLSIDREFIIDにC#のtype(...).GUID等を渡すとき、ref Guid ...とすると必要になる一時的な変数に省略に使います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?