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 :
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 updateTaskBarHelper
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?