using System; //using System.Collections.Generic; using System.IO; //using System.Linq; using System.Runtime.InteropServices; using System.Text; //using Shell32; using IWshRuntimeLibrary; //using System.Threading.Tasks; namespace PinTo10v2 { static public class Utils { // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static string originalImagePathName; static int unicodeSize = IntPtr.Size * 2; static void GetPointers(out IntPtr imageOffset, out IntPtr imageBuffer) { IntPtr pebBaseAddress = GetBasicInformation().PebBaseAddress; var processParameters = Marshal.ReadIntPtr(pebBaseAddress, 4 * IntPtr.Size); imageOffset = processParameters.Increment(4 * 4 + 5 * IntPtr.Size + unicodeSize + IntPtr.Size + unicodeSize); imageBuffer = Marshal.ReadIntPtr(imageOffset, IntPtr.Size); } internal static void ChangeImagePathName(string newFileName) { IntPtr imageOffset, imageBuffer; GetPointers(out imageOffset, out imageBuffer); //Read original data var imageLen = Marshal.ReadInt16(imageOffset); originalImagePathName = Marshal.PtrToStringUni(imageBuffer, imageLen / 2); var newImagePathName = Path.Combine(Path.GetDirectoryName(originalImagePathName), newFileName); if (newImagePathName.Length > originalImagePathName.Length) throw new Exception("new ImagePathName cannot be longer than the original one"); //Write the string, char by char var ptr = imageBuffer; foreach (var unicodeChar in newImagePathName) { Marshal.WriteInt16(ptr, unicodeChar); ptr = ptr.Increment(2); } Marshal.WriteInt16(ptr, 0); //Write the new length Marshal.WriteInt16(imageOffset, (short)(newImagePathName.Length * 2)); } internal static void RestoreImagePathName() { IntPtr imageOffset, ptr; GetPointers(out imageOffset, out ptr); foreach (var unicodeChar in originalImagePathName) { Marshal.WriteInt16(ptr, unicodeChar); ptr = ptr.Increment(2); } Marshal.WriteInt16(ptr, 0); Marshal.WriteInt16(imageOffset, (short)(originalImagePathName.Length * 2)); } public static ProcessBasicInformation GetBasicInformation() { uint status; ProcessBasicInformation pbi; int retLen; var handle = System.Diagnostics.Process.GetCurrentProcess().Handle; if ((status = NtQueryInformationProcess(handle, 0, out pbi, Marshal.SizeOf(typeof(ProcessBasicInformation)), out retLen)) >= 0xc0000000) throw new Exception("Windows exception. status=" + status); return pbi; } [DllImport("ntdll.dll")] public static extern uint NtQueryInformationProcess( [In] IntPtr ProcessHandle, [In] int ProcessInformationClass, [Out] out ProcessBasicInformation ProcessInformation, [In] int ProcessInformationLength, [Out] [Optional] out int ReturnLength ); public static IntPtr Increment(this IntPtr ptr, int value) { unchecked { if (IntPtr.Size == sizeof(Int32)) return new IntPtr(ptr.ToInt32() + value); else return new IntPtr(ptr.ToInt64() + value); } } [StructLayout(LayoutKind.Sequential)] public struct ProcessBasicInformation { public uint ExitStatus; public IntPtr PebBaseAddress; public IntPtr AffinityMask; public int BasePriority; public IntPtr UniqueProcessId; public IntPtr InheritedFromUniqueProcessId; } // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] internal static extern IntPtr LoadLibrary(string lpLibFileName); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] internal static extern int LoadString(IntPtr hInstance, uint wID, StringBuilder lpBuffer, int nBufferMax); // ////////////////////////////////////////////////////////////////////// public static void CreateShortcut(string targetFileLocation) { string currentuserstart = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\Microsoft\Windows\Start Menu\Programs"; string wholefileName = Path.GetFileName(targetFileLocation); string extension = Path.GetExtension(wholefileName); string filenamenoextension = Path.GetFileNameWithoutExtension(wholefileName); string DirectoryName = Path.GetDirectoryName(targetFileLocation); string shortcutLocation = currentuserstart + @"\" + filenamenoextension + ".lnk"; //System.IO.Path.Combine(Environment.SpecialFolder.StartMenu.ToString(), "Dummy.lnk"); WshShell shell = new WshShell(); IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutLocation); //shortcut.Description = ""; // The description of the shortcut shortcut.WorkingDirectory = DirectoryName; // The "Start in" path of the new shortcut shortcut.TargetPath = targetFileLocation; // The path of the file that will launch when the shortcut is run shortcut.Save(); // Save the shortcut } public static bool PinUnpinTaskbar(string filePath, bool pin) { if (!System.IO.File.Exists(filePath)) { Console.WriteLine("\n\r" + "Specified file not found. Exiting..."); Environment.Exit(1); }; //throw new FileNotFoundException(filePath); int MAX_PATH = 255; var actionIndex = pin ? 5386 : 5387; // 5386 is the DLL index for"Pin to Tas&kbar", ref. http://www.win7dll.info/shell32_dll.html StringBuilder szPinToStartLocalized = new StringBuilder(MAX_PATH); IntPtr hShell32 = LoadLibrary("Shell32.dll"); LoadString(hShell32, (uint)actionIndex, szPinToStartLocalized, MAX_PATH); string localizedVerb = szPinToStartLocalized.ToString(); string path = Path.GetDirectoryName(filePath); string fileName = Path.GetFileName(filePath); // create the shell application object dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application")); dynamic directory = shellApplication.NameSpace(path); dynamic link = directory.ParseName(fileName); dynamic verbs = link.Verbs(); for (int i = 0; i < verbs.Count(); i++) { dynamic verb = verbs.Item(i); var name = verb.Name; //Console.WriteLine("Verb Name = " + name); if (verb.Name.Equals(localizedVerb)) { //Console.WriteLine("Trying to do it..."); verb.DoIt(); return true; } } return false; } // ////////////////////////////////////////////////////////////////////// public static bool PinUnpinStart(string filePath, bool pin) { //Console.WriteLine("Pinning to Start..."); if (!System.IO.File.Exists(filePath)) throw new FileNotFoundException(filePath); int MAX_PATH = 255; StringBuilder szPinToStartLocalized = new StringBuilder(MAX_PATH); StringBuilder szInvPinToStartLocalized = new StringBuilder(MAX_PATH); IntPtr hShell32 = LoadLibrary("Shell32.dll"); string osversionfromreg = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion", "ProductName", "nullvalue").ToString(); string win10 = "Windows 10"; string win7 = "Windows 7"; bool iswin10 = osversionfromreg.Contains(win10); bool iswin7 = osversionfromreg.Contains(win7); var actionIndex = pin ? 51201 : 51394; var invActionIndex = pin ? 51394 : 51201; if (iswin10) { actionIndex = pin ? 51201 : 51394; invActionIndex = pin ? 51394 : 51201; } if (iswin7) { actionIndex = pin ? 5381 : 5382; invActionIndex = pin ? 5382 : 5381; } LoadString(hShell32, (uint)actionIndex, szPinToStartLocalized, MAX_PATH); string localizedVerb = szPinToStartLocalized.ToString(); LoadString(hShell32, (uint)invActionIndex, szInvPinToStartLocalized, MAX_PATH); string invLocalizedVerb = szInvPinToStartLocalized.ToString(); string path = Path.GetDirectoryName(filePath); string fileName = Path.GetFileName(filePath); // create the shell application object dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application")); dynamic directory = shellApplication.NameSpace(path); dynamic link = directory.ParseName(fileName); dynamic verbs = link.Verbs(); int counter = 0; while (1 == 1) // setup a loop to keep trying to pin to start - will try 20 times at 500ms interval and then fail if not successful { shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application")); directory = shellApplication.NameSpace(path); link = directory.ParseName(fileName); verbs = link.Verbs(); for (int i = 0; i < verbs.Count(); i++) { dynamic verb = verbs.Item(i); if (verb.Name.Equals(localizedVerb)) { verb.DoIt(); System.Threading.Thread.Sleep(500); counter = counter = + 1; } if (verb.Name.Equals(invLocalizedVerb)) // check for the existance of the opposite verb to confirm if it's been successful { //Console.WriteLine("I think it's done! Exiting..."); return true; } if (counter == 20) // Try 20 times (10 seconds) and then fail... { return false; } } } } public static bool CheckifVerbExists(string filePath, bool pin, bool startmenu) { //Console.WriteLine("Pinning to Start..."); if (!System.IO.File.Exists(filePath)) throw new FileNotFoundException(filePath); int MAX_PATH = 255; StringBuilder szPinToStartLocalized = new StringBuilder(MAX_PATH); StringBuilder szInvPinToStartLocalized = new StringBuilder(MAX_PATH); IntPtr hShell32 = LoadLibrary("Shell32.dll"); string osversionfromreg = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion", "ProductName", "nullvalue").ToString(); string win10 = "Windows 10"; string win7 = "Windows 7"; bool iswin10 = osversionfromreg.Contains(win10); bool iswin7 = osversionfromreg.Contains(win7); var actionIndex = pin ? 51201 : 51394; var invActionIndex = pin ? 51394 : 51201; if (iswin10) { if (startmenu) { actionIndex = pin ? 51201 : 51394; } if (!startmenu) { actionIndex = pin ? 5386 : 5387; } } if (iswin7) { if (startmenu) { actionIndex = pin ? 5381 : 5382; } if (!startmenu) { actionIndex = pin ? 5386 : 5387; } } LoadString(hShell32, (uint)actionIndex, szPinToStartLocalized, MAX_PATH); string localizedVerb = szPinToStartLocalized.ToString(); string path = Path.GetDirectoryName(filePath); string fileName = Path.GetFileName(filePath); // create the shell application object dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application")); dynamic directory = shellApplication.NameSpace(path); dynamic link = directory.ParseName(fileName); dynamic verbs = link.Verbs(); for (int i = 0; i < verbs.Count(); i++) { dynamic verb = verbs.Item(i); var name = verb.Name; //Console.WriteLine("Verb name = " + name); if (verb.Name.Equals(localizedVerb)) { // verb.DoIt(); return true; } } return false; } } }