C# - クイックアクセスにピン留めする

# やりたいこと

エクスプローラの[クイックアクセスのピン留めが時々勝手に外れる](https://www.google.co.jp/search?q=%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9+%E5%8B%9D%E6%89%8B%E3%81%AB%E6%B6%88%E3%81%88%E3%82%8B)。（多分Windows10の不具合）
対策として、プログラムから一発登録できるようにしたい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/cdb39876-3d9c-5c0c-5b7f-03cdfa794248.png)


# 要点

後述のソースコードの下記の部分で、指定されたフォルダに対するピン留めを実現している。

```csharp

var folder = shell.NameSpace(path);
var item = folder.Self;
item.InvokeVerb("pintohome");
```

# ソースコード

コマンドラインオプションで指定したフォルダ（またはフォルダへのショートカット）を入力として、そのフォルダをクイックアクセスにピン止めします。

```csharp


using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

class SampleProgram
{
    static void PinToQuickAccess(string[] paths)
    {
        if ( paths.Length > 0 ) {
            Type type = Type.GetTypeFromProgID("Shell.Application");
            dynamic shell = Activator.CreateInstance(type);
            foreach ( string tmp in paths ) {
                string path = Path.GetFullPath(tmp);
                if ( File.Exists(path) && path.EndsWith(".lnk",true,null) ) {
                    // lnk file
                    path = GetTargetPath(path) ?? "";
                }
                if ( Directory.Exists(path) ) {
                    var folder = shell.NameSpace(path);
                    var item = folder.Self;
                    item.InvokeVerb("pintohome");
                }
            }
        }

        // COMオブジェクト解放 ... これでいいはず
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

    // ※ピン止めされていないものもリストアップされる
    static string[] GetEntriesOfQuickAccess()
    {
        var paths = new List<string>();

        {
            Type type = Type.GetTypeFromProgID("Shell.Application");
            dynamic shell = Activator.CreateInstance(type);
            dynamic folder = shell.NameSpace("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}");

            if ( folder != null ) {
                foreach (dynamic folderItem in folder.Items()) {
                    string s = folderItem.Path;
                    paths.Add(s);
                    Console.WriteLine(s);
                }
            }
        }

        GC.Collect();
        GC.WaitForPendingFinalizers();

        return paths.ToArray();
    }

    // .lnkファイルからパスを取得する
    static string GetTargetPath(string fullPath)
    {
        {
            Type type = Type.GetTypeFromProgID("WScript.Shell");
            dynamic shell = Activator.CreateInstance(type);// IWshRuntimeLibrary.WshShell
            dynamic lnk = shell.CreateShortcut(fullPath);// IWshRuntimeLibrary.IWshShortcut

            if (string.IsNullOrEmpty(lnk.TargetPath)) {
                return null;
            }

            return lnk.TargetPath;
        }
    }


    [STAThread]
    static void Main(string[] args)
    {
        GetEntriesOfQuickAccess();
        PinToQuickAccess(args);
    }
}
```


# 参考サイト

- [エクスプローラ クイックアクセス ピン留め C# - C# と VB.NET の質問掲示板](http://bbs.wankuma.com/index.cgi?mode=al2&namber=88813&KLOG=153)
- [Shell.NameSpace - Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/win32/shell/shell-namespace)
- [PowerShell でクイックアクセスにフォルダーをピン止めする - MURA](https://www.vwnet.jp/Windows/w10/2017020201/Pin2QuickAccess.htm)
- [C# で Windows 10 のクイック アクセスを列挙する - アプ件](https://www.upken.jp/kb/enumerate-quick-access.html)
- [C# ショートカットを作成する - プログラミングテクニック集キヤミー](https://cammy.co.jp/technical/2017/05/30/c-%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B/)
- [C# - Windowsのリンクファイル(.lnk)からリンク先情報を取得する / Drag&Dropサンプル - Qiita](https://qiita.com/kob58im/items/bb562a072811b2a0325b)