0

Context

Due to the security policy on the work machine, I can't pin application that is on network drive. However, I've found a workaround to this, which is to pin a safe application, like any from system32, and edit the shortcut(.lnk) file that is created under %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar to make it point to the desired application, and update its icon and name.

Problem

Now, I have successfully reproduced almost all of programmatically, except the last step, which is to rename the shortcut with the name of application we want to pin.

But here's the tricky part, if you've pinned an application and just went rename it normally(rclick->rename->type something->hit enter) in %appdata%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar, you have corrupted it. If you kill exporer.exe and start it again, you will notice that the pinned item has become unusable like :

blank file

The proper way is by going through rclick->properties->general->change file name->press ok. But, how can we reproduce this programmatically?

Code

If your system language is other than fr-FR, you will need to update TaskBarHelper initializer. Instructions is provided in exception and comment near where it is thrown.

public static class TaskBarHelper
{
    // this solution is dependent on the os language, so we need to check if we are using the correct text for the os language
    private static readonly string PinActionText, UnpinActionText;
    static TaskBarHelper()
    {
        switch (CultureInfo.InstalledUICulture.Name)
        {
            case "fr-FR": 
                PinActionText = "Épingler à la &barre des tâches";
                UnpinActionText = "Détacher de la b&arre des tâches";
                break;

            default: // find the action text for this language
                var appPath = Directory.GetFiles(Environment.SystemDirectory, "*.exe").First();
                var actions = GetItemVers(appPath);

                throw new NotSupportedException("Please add the right actions' text from the followings : \n" + 
                    string.Join("\n", actions.Select(x => x.Name)));
        }
    }

    public static void Pin(string appPath)
    {
        if (!File.Exists(appPath)) throw new FileNotFoundException(appPath);

        GetItemVers(appPath)
            .First(x => x.Name == PinActionText)
            .DoIt();
    }
    public static void Unpin(string appPath)
    {
        if (!File.Exists(appPath)) throw new FileNotFoundException(appPath);

        GetItemVers(appPath)
            .First(x => x.Name == UnpinActionText)
            .DoIt();
    }

    public static void PinNetworkApplication(string appPath)
    {
        if (!File.Exists(appPath)) throw new FileNotFoundException(appPath);

        //pin a random application from sys32
        var randomApp = new DirectoryInfo(Environment.SystemDirectory).GetFiles("*.exe").First();
        //if (TaskBarHelper.GetPinnedFolderItems().Any(x => randomApp.FullName.Equals(x.GetLink().Path, StringComparison.InvariantCultureIgnoreCase)))
        try { Unpin(randomApp.FullName); } catch { }
        Pin(randomApp.FullName);

        //find its lnk file in the pinned items
        var pinFile = TaskBarHelper.GetPinnedFolderItems().Single(x => randomApp.FullName.Equals(x.GetLink().Path, StringComparison.InvariantCultureIgnoreCase));
        var pinLink = pinFile.GetLink();

        //DispatchUtility.GetType(pinFile as object, false).GetMethods().Select(m => m.Name).Dump("File");
        //DispatchUtility.GetType(pinLink as object, false).GetMethods().Select(m => m.Name).Dump("Link");
        //ExposeMethods(pinFile as object);
        //ExposeMethods(pinLink as object);

        //rename the lnk file, but we can't rename it *properly*
        pinLink.Path = appPath;
        pinLink.SetIconLocation(appPath, 0);
        pinLink.Save();

        //all these corrupt the taskbar
        //pinFile.Name = Path.GetFileNameWithoutExtension(appPath);
        //File.Move(pinFile.Path, Path.Combine(
        //Path.GetDirectoryName(pinFile.Path), 
        //      Path.GetFileNameWithoutExtension(appPath) + ".lnk")); 
        //Util.Cmd(string.Format("rename \"{0}\" \"{1}\"", //btw, this is basically like Win+R
        //      pinFile.Path as string, 
        //      Path.GetFileNameWithoutExtension(appPath) + ".lnk").Dump());
    }

    public static void Refresh()
    {
        foreach (var process in Process.GetProcessesByName("explorer"))
            process.Kill();

        Process.Start(Path.Combine(Environment.GetEnvironmentVariable("windir"), "explorer.exe"));
    }

    //get all item from the file's context menu in explorer
    private static IEnumerable<dynamic> GetItemVers(string appPath) //FolderItemVerb
    {
        var fi = new FileInfo(appPath);
        if (!fi.Exists) throw new FileNotFoundException(fi.FullName);

        dynamic shell = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
        var folder = shell.NameSpace(fi.Directory.FullName);
        var file = folder.ParseName(fi.Name);

        var actions = file.Verbs();
        for(int i = 0; i < actions.Count(); i++)
            yield return actions.Item(i);
    }

    //get all pinned items from task bar
    public static IEnumerable<dynamic> GetPinnedFolderItems()
    {
        var taskBarPath = Path.Combine(
            Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData),
            @"Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar");

        dynamic shell = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
        var folder = shell.NameSpace(taskBarPath);

        return new DirectoryInfo(taskBarPath).GetFiles("*.lnk")
            .Select(x => folder.ParseName(x.Name));
    }
}

TL;DR

How to reproduce rclick->properties->general->change file name->press ok programmatically?

Xiaoy312
  • 13,354
  • 1
  • 26
  • 37
  • Your "TL;DR" is your actual question. The rest is unnecessary fluff, with no useful relation to "how do I rename a file programmatically." I'd suggest you edit your question accordingly - except that there's [an existing question](http://stackoverflow.com/questions/3218910/rename-a-file-in-c-sharp) that answers your problem. – Dan Puzey Feb 18 '15 at 22:44
  • I have specifically mentioned in the problem section that, usually way of copying/moving/renaming including `System.IO.File.Move` from the answer you provided, does not work and corrupts the taskbar pinning. And, I've already tried such method(2nd attempt in `PinNetworkApplication`). There is a reason why I wasted so much time to document the problem, please take time to read it. – Xiaoy312 Feb 18 '15 at 22:59
  • Actually, you've not mentioned `System.IO.File.Move` in your question at all. Could you edit the question to concisely include the actual issue (that is, presumably, that using `System.IO.File.Move` doesn't rename a `.lnk` file, but instead renames the file pointed to by the link)? – Dan Puzey Feb 19 '15 at 12:16

0 Answers0