使用快捷键调用Visual Studio工具程序

在使用OFFCIE办公软件的过程中,许多用户或许希望可以通过快捷键调用Visual Studio工具程序,并以此为工作带来便利。比如一个客户希望可以使用键盘快捷键调用OFFCIE办公软件Visual Studio工具程序。我翻阅了许多源程序代码片段,但未找到可以实现该功能的程序,为此我自己写下来下面一段程序以方便有此需求的用户使用:

一、程序目的:

1. 可以使用快捷键

2. 将快捷键和自己想要使用的Visual Studio工具程序挂钩。即将Visual Studio工具程序转变为office办公软件使用时的“钩子(Hook)”程序

二、“钩子”程序简介:

钩子(Hook)其实就是windows下替换DOS下的“中断”功能的一种机制。什么是钩子呢?说白了,就是我们在某个进程上挂上我们的钩子(我们自己的程序),那么在该进程执行的时候,他首先会引起我们的钩子程序的运行。

用户态API挂钩技术

在windows下,系统主要依赖三个子系统:win32、POSIX、OS/2。每个子系统有一套比较完备的API库。一个进程可以通过这些API访问到OS。Win32应用程序主要使用Kernel32、user32、Gui32、Advapi.dll等几个DLL文件将请求发送到系统核心。 应用程序在调用到这些.DLL文件的导出函数时,需要把这些DLL文件加载到内存中,并且把他们在内存的地址写入自己的导入表(Import Address Table)中,当进程需要访问时,直接跳到IAT的地址。

由于应用程序把DLL加载到介于0x00010000和0x7FE00000之间的私有地址之间,所以只要我们能够访问到应用程序的私有地址,我们就可以随意改变应用程序的IAT的地址,这就是API钩子。

三、步骤:

1. 添加键盘快捷键

添加键盘快捷键过程主要是赋予键盘快捷键宏命令程序。通过这个过程,用户在使用快捷键时可以调用设置好的宏命令程序。

2. 将快捷键和自己想要使用的Visual Studio工具程序挂钩

在介绍程序“挂钩”的过程中,我将以使用快捷键“Ctrl+A”来执行显示消息窗口的功能为例。在下面这段程序中,可以通过调用设置钩子程序功能函数(SetHook function)来设置钩子程序,也可以使用调用释放钩子程序(ReleaseHook function)来释放先前设置好的快捷键。

其主要程序如下:

using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.Excel;
namespace Hooking
{
public class InterceptKeys
{
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static Microsoft.Office.Tools.CustomTaskPane ctpRef = null;

//Declare the mouse hook constant.
//For other hook types, you can obtain these values from Winuser.h in the Microsoft SDK.

private const int WH_KEYBOARD = 2;
private const int HC_NOREMOVE = 3;
public static void SetHook()
{
_hookID = SetWindowsHookEx(WH_KEYBOARD, _proc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());
}
public static void ReleaseHook()
{
UnhookWindowsHookEx(_hookID);
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if ((nCode >= 0))
{
uint flags = (uint)lParam;
Keys keyData = (Keys)wParam;
if (nCode == HC_NOREMOVE)
{
if (Functions.IsKeyDown(Keys.ControlKey) && keyData == Keys.A)
{
MessageBox.Show("You pressed Ctrl+A");
}
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
}
public class Functions
{
public static bool IsKeyDown(Keys keys)
{
return (GetKeyState((int)keys) & 0x8000) == 0x8000;
}
[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);
}
}