在VSTO Excel加载项中,当单击交叉表中的特定坐标时,我需要在工作表的交叉表中呈现内容(并在再次单击相同坐标时再次删除内容)。
因此,我正在使用通过SetWindowsHookEx注册的MouseProc回调函数:
_hMouseHook = WinApi.SetWindowsHookEx(WinApi.WH_MOUSE, _mouseHookProcedure,
WinApi.GetModuleHandle(module.ModuleName), (int)WinApi.GetCurrentThreadId());
不幸的是,似乎Excel的行为异常,并分别触发了两次WM_LBUTTONDOWN和WM_LBUTTONUP消息(可能还触发了其他消息)。
MouseProc回调的外观如下:
private int MouseHookProcedure(int nCode, Int32 wParam, IntPtr lParam)
{
if (nCode == WinApi.HC_ACTION)
{
var mouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
WinApi.WindowMessage message = (WinApi.WindowMessage)wParam;
if (message == WinApi.WindowMessage.WM_LBUTTONDOWN)
{
Debug.WriteLine($"WH_MOUSE_Hook: WM_LBUTTONDOWN - nCode:{nCode} WParam:{wParam} LParam:{lParam} X:{mouseHookStruct.pt.X} Y:{mouseHookStruct.pt.Y} " +
$"Handle:{(IntPtr)mouseHookStruct.hwnd} Message:{message} HitTestCode:{mouseHookStruct.wHitTestCode} ExtraInfo:{mouseHookStruct.dwExtraInfo}");
}
else if (message == WinApi.WindowMessage.WM_LBUTTONUP)
{
Debug.WriteLine($"WH_MOUSE_Hook: WM_LBUTTONUP - nCode:{nCode} WParam:{wParam} LParam:{lParam} X:{mouseHookStruct.pt.X} Y:{mouseHookStruct.pt.Y} " +
$"Handle:{(IntPtr)mouseHookStruct.hwnd} Message:{message} HitTestCode:{mouseHookStruct.wHitTestCode} ExtraInfo:{mouseHookStruct.dwExtraInfo}");
}
}
try
{
// event not handled, call next Hook to process / delegate event
return WinApi.CallNextHookEx(_hMouseHook, nCode, wParam, lParam);
}
catch
{
return 0;
}
}
我还知道某些Excel安装上的行为可能有所不同,因此WM_LBUTTONDOWN消息有时仅发送一次。不幸的是,我不知道Excel行为变化的原因。
在使用Subclassing而不是钩子时,它可以很好地工作,但是不幸的是,这是没有选择的,因为Subclassing引起了与也使用它的其他加载项的兼容性问题。
我创建了一个小型VSTO测试插件,通过将事件记录到控制台来演示该问题:
WH_MOUSE_Hook:WM_LBUTTONDOWN-nCode:0 WParam:513 LParam:55637568 ... WH_MOUSE_Hook:WM_LBUTTONDOWN-nCode:0 WParam:513 LParam:55637568 ... 子类:WM_LBUTTONDOWN-WParam:1 LParam:17957938消息:513 ... WH_MOUSE_Hook:WM_LBUTTONUP-nCode:0 WParam:514 LParam:55633504 ... WH_MOUSE_Hook:WM_LBUTTONUP-nCode:0 WParam:514 LParam:55633504 ...
我的代码有什么问题可以解释这种现象吗?还是有人已经面临这个问题并想出了一个好的/替代解决方案来解决这个问题?
可在此处找到测试加载项源代码:OneDrive Link