NEWS

[C#] Hook Right context menu windows (ex: Pin and Unpin Taskbar)

[C#] Hook Right context menu windows (ex: Pin and Unpin Taskbar)
Đăng bởi: Thảo Meo - Lượt xem: 4894 13:01:19, 24/02/2020C#   In bài viết

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách Hook Menu chuột phải Context Menu của từng ứng dụng trên Windows Explorer C#.

[C#] Hook Right context menu windows (ex: Pin and Unpin Taskbar)

Cụ thể ở bài viết demo này chức năng Pin và UnPin một ứng dụng vào thanh taskbar Windows.

context_menu

Trên từng item của mỗi menu trong windows explorer sẽ có một mã ID.

Vd:

pin to taskbar => 5386

Unpin from taskbar => 5387

shell32_code

Các bạn có thể tham khảo thêm các mã khác ở link sau:

http://www.win7dll.info/shell32_dll.html

 

Các bạn xem giao diện demo ứng dụng mình dưới đây:

pin_unpin_demo

Trong bài viết này các bạn nhìn hình ở trên khi mình right click chuột phải vào ứng dụng HOB 2015.exe, thì các bạn thấy được một danh sách treeview mình trả về giống hình bên tay phải các bạn.

Khi các bạn nhấn vào từng item node trên treeview này nó sẽ thực hiện hành động (action) giống như khi các bạn click vào menu trên windows explorer vậy.

Để pin được ứng dụng vào thanh taskbar, các bạn phải cần giả lập ứng dụng của bạn đang chạy là "Windows Explorer" thì nó mới cho phép. 

Nên trong bài viết mình có để hàm sẵn trên là ChangeImagePathName() và truyền vào là đường dẫn của Windows Explorer, nếu các bạn không thêm hàm này vào sẽ không thấy được menu Pin to Taskbar nhé.

Demo ứng dụng Pin and unPin taskbar C#:

pin_unpin_taskbar

Đầu tiên các bạn cần tạo một class Utils.cs, với nội dung như sau:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace PinToTaskbar
{
    static public class Utils
    {
        [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 List<string> PinUnpinTaskbar(string filePath, bool pin, string action = "")
        {
            if (!File.Exists(filePath)) 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);
            dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
            dynamic directory = shellApplication.NameSpace(path);
            dynamic link = directory.ParseName(fileName);
            List<string> lists = new List<string>();
            dynamic verbs = link.Verbs();

            for (int i = 0; i < verbs.Count(); i++)
            {
                dynamic verb = verbs.Item(i);
                var name = verb.Name;
           
                lists.Add(name);
                if (string.IsNullOrEmpty(action))
                {
                    if (verb.Name.Equals(localizedVerb))
                    {
                        verb.DoIt();
                    }
                }
                else
                {
                    if (verb.Name.Equals(action))
                    {
                        verb.DoIt();
                    }
                }
               
            }

            return lists;       
        }

        static string originalImagePathName;
        static int unicodeSize = IntPtr.Size * 2;
        static bool changed;

        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);      
            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");
          
            var ptr = imageBuffer;
            foreach (var unicodeChar in newImagePathName)
            {
                Marshal.WriteInt16(ptr, unicodeChar);
                ptr = ptr.Increment(2);
            }
            changed = true;
            Marshal.WriteInt16(ptr, 0);       
            Marshal.WriteInt16(imageOffset, (short)(newImagePathName.Length * 2));
        }

        internal static void RestoreImagePathName()
        {
            if (!changed) return;
            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;
        }
    }
}

Và dưới đây là source code của form chính:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PinToTaskbar
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        string filename;
        private void btn_pinTaskbar_Click(object sender, EventArgs e)
        {          
            filename = @"C:Program Files (x86)HOABINH COMPANY LIMITEDHOB METRO UI 2018HOB 2015.exe";         
            List<string> list = new List<string>();
            treeView.Nodes.Clear();
            try
            {
                Utils.ChangeImagePathName(@"C:Windowsexplorer.exe");
                list = Utils.PinUnpinTaskbar(filename, true);
            }
            finally
            {
                Utils.RestoreImagePathName();
            }
            foreach (var item in list)
            {
                TreeNode newNode = new TreeNode(item);
                treeView.Nodes.Add(newNode);

            }

           
        }

      

        private void btn_unpin_Click(object sender, EventArgs e)
        {
            Utils.ChangeImagePathName("explorer.exe");
            List<string> list = new List<string>();
            list.Clear();
            list = Utils.PinUnpinTaskbar(filename, false);
            treeView.Nodes.Clear();
            foreach (var item in list)
            {
                TreeNode newNode = new TreeNode(item);
                treeView.Nodes.Add(newNode);
            }
        }

        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            var text = e.Node.Text;

            Utils.PinUnpinTaskbar(filename, false, text);
        }
    }
}

Thanks for watching!

 

DOWNLOAD SOURCE

THÔNG TIN TÁC GIẢ

BÀI VIẾT LIÊN QUAN

[C#] Hook Right context menu windows (ex: Pin and Unpin Taskbar)
Đăng bởi: Thảo Meo - Lượt xem: 4894 13:01:19, 24/02/2020C#   In bài viết

CÁC BÀI CÙNG CHỦ ĐỀ

Đọc tiếp
.