C#のプログラムで自分自身をPin止めする(5)

前回のAppUserModelIDが設定できたように見えてもWin8でアイコンが分裂する問題は未解決ですが、その後もいろいろ調べていたら新たに2点ほどわかったことがありました。

その1.
C#のプログラムで自分自身をPin止めする(1)

それでも#if falseでくくったほうの英語の名称をそのままマッチングするよりは遥かにマシなのですが、この辺のもっとうまいやり方を知ってる方はコメントいただけるとありがたいです。

と書いたのですが、

をもとに検証してみたところ、OSの言語に関係なくFolderItem.InvokeVerb("taskbarpin")(または"startpin")で良いことが判明しました。

その2.

まずタスクバーへのPin止めの実体であるショートカットファイルをチェックするためにIWshRuntimeLibrary.WshShelを使用し、

これについては今までもさんざん使っていたWindows7 API Code PackのShellProperties Classで代用できることがわかりました。
これでWindows Script Host Object Modelの参照も不要となります。

以上の成果をもとにPinned()メソッドを書き直したものが以下です。
返り値としてPin止め後のショートカットファイルのフルパスが返ってきますので、それをそのまま前回作成したSetApplicationIdForShortcut()に渡せます。

using System.IO;
using System.Text.RegularExpressions;
using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

        /// <summary>
        /// プログラムによるピン止め(改良版)
        /// </summary>
        /// <param name="filePath">Pin止めするプログラムのフルパス</param>
        /// <param name="pinTaskbar">Pin止め先:True=タスクバー, False=スタートメニュー</param>
        /// <returns>Pin止め後のショートカットファイルのフルパス</returns>
        public static string Pinned(string filePath, bool pinTaskbar)
        {
            if (!File.Exists(filePath)) throw new FileNotFoundException(filePath);

            // UserPinnedフォルダの取得
            string userPinnedPath = Path.Combine(KnownFolders.UserPinned.Path,
                (pinTaskbar ? "TaskBar" : "StartMenu")
            );

            // 既にピン止めされている?
            if (GetLinkFile(userPinnedPath, filePath) != null) return null;

            // Shell.Applicationオブジェクトの作成
            dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));

            string path = Path.GetDirectoryName(filePath);
            string fileName = Path.GetFileName(filePath);

            dynamic directory = shellApplication.NameSpace(path);
            dynamic link = directory.ParseName(fileName);

            // ピン止め(これだけで良い!)
            link.InvokeVerb((pinTaskbar ? "taskbarpin" : "startpin"));

            shellApplication = null;

            // ピン止め後ショートカットファイル検索
            return GetLinkFile(userPinnedPath, filePath);
        }

        // ショートカットファイル検索(ShellProperties Class使用)
        private string GetLinkFile(string lnkDir, string filePath)
        {
            foreach (string lnkFile in Directory.EnumerateFiles(lnkDir, "*.lnk"))
            {
                ShellProperties property = ShellFile.FromFilePath(lnkFile).Properties;
                if (filePath.Equals(property.System.Link.TargetParsingPath.Value, StringComparison.CurrentCultureIgnoreCase))
                    return lnkFile;
            }

            return null;
        }