Skip to content

Commit bcfbfb1

Browse files
committed
Add utility class for event hooks, stubbed code in VBE.
1 parent f891c71 commit bcfbfb1

File tree

3 files changed

+257
-1
lines changed

3 files changed

+257
-1
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Runtime.InteropServices;
5+
using System.Text;
6+
7+
namespace Rubberduck.VBEditor.Native
8+
{
9+
public static class WinEvents
10+
{
11+
#region Debugging symbol lookups
12+
public static readonly Dictionary<uint, string> EventNameLookup = new Dictionary<uint, string>
13+
{
14+
{0x1, "EVENT_SYSTEM_SOUND"},
15+
{0x2, "EVENT_SYSTEM_ALERT"},
16+
{0x3, "EVENT_SYSTEM_FOREGROUND"},
17+
{0x4, "EVENT_SYSTEM_MENUSTART"},
18+
{0x5, "EVENT_SYSTEM_MENUEND"},
19+
{0x6, "EVENT_SYSTEM_MENUPOPUPSTART"},
20+
{0x7, "EVENT_SYSTEM_MENUPOPUPEND"},
21+
{0x8, "EVENT_SYSTEM_CAPTURESTART"},
22+
{0x9, "EVENT_SYSTEM_CAPTUREEND"},
23+
{0xa, "EVENT_SYSTEM_MOVESIZESTART"},
24+
{0xb, "EVENT_SYSTEM_MOVESIZEEND"},
25+
{0xc, "EVENT_SYSTEM_CONTEXTHELPSTART"},
26+
{0xd, "EVENT_SYSTEM_CONTEXTHELPEND"},
27+
{0xe, "EVENT_SYSTEM_DRAGDROPSTART"},
28+
{0xf, "EVENT_SYSTEM_DRAGDROPEND"},
29+
{0x10, "EVENT_SYSTEM_DIALOGSTART"},
30+
{0x11, "EVENT_SYSTEM_DIALOGEND"},
31+
{0x12, "EVENT_SYSTEM_SCROLLINGSTART"},
32+
{0x13, "EVENT_SYSTEM_SCROLLINGEND"},
33+
{0x14, "EVENT_SYSTEM_SWITCHSTART"},
34+
{0x15, "EVENT_SYSTEM_SWITCHEND"},
35+
{0x16, "EVENT_SYSTEM_MINIMIZESTART"},
36+
{0x17, "EVENT_SYSTEM_MINIMIZEEND"},
37+
{0x8000, "EVENT_OBJECT_CREATE"},
38+
{0x8001, "EVENT_OBJECT_DESTROY"},
39+
{0x8002, "EVENT_OBJECT_SHOW"},
40+
{0x8003, "EVENT_OBJECT_HIDE"},
41+
{0x8004, "EVENT_OBJECT_REORDER"},
42+
{0x8005, "EVENT_OBJECT_FOCUS"},
43+
{0x8006, "EVENT_OBJECT_SELECTION"},
44+
{0x8007, "EVENT_OBJECT_SELECTIONADD"},
45+
{0x8008, "EVENT_OBJECT_SELECTIONREMOVE"},
46+
{0x8009, "EVENT_OBJECT_SELECTIONWITHIN"},
47+
{0x800A, "EVENT_OBJECT_STATECHANGE"},
48+
{0x800B, "EVENT_OBJECT_LOCATIONCHANGE"},
49+
{0x800C, "EVENT_OBJECT_NAMECHANGE"},
50+
{0x800D, "EVENT_OBJECT_DESCRIPTIONCHANGE"},
51+
{0x800E, "EVENT_OBJECT_VALUECHANGE"},
52+
{0x800F, "EVENT_OBJECT_PARENTCHANGE"},
53+
{0x8010, "EVENT_OBJECT_HELPCHANGE"},
54+
{0x8011, "EVENT_OBJECT_DEFACTIONCHANGE"},
55+
{0x8012, "EVENT_OBJECT_ACCELERATORCHANGE"},
56+
};
57+
58+
public static readonly Dictionary<uint, string> ObjectIdNameLookup = new Dictionary<uint, string>
59+
{
60+
{ 0x00000000, "OBJID_WINDOW" },
61+
{ 0xFFFFFFFF, "OBJID_SYSMENU" },
62+
{ 0xFFFFFFFE, "OBJID_TITLEBAR" },
63+
{ 0xFFFFFFFD, "OBJID_MENU" },
64+
{ 0xFFFFFFFC, "OBJID_CLIENT" },
65+
{ 0xFFFFFFFB, "OBJID_VSCROLL" },
66+
{ 0xFFFFFFFA, "OBJID_HSCROLL" },
67+
{ 0xFFFFFFF9, "OBJID_SIZEGRIP" },
68+
{ 0xFFFFFFF8, "OBJID_CARET" },
69+
{ 0xFFFFFFF7, "OBJID_CURSOR" },
70+
{ 0xFFFFFFF6, "OBJID_ALERT" },
71+
{ 0xFFFFFFF5, "OBJID_SOUND" },
72+
{ 0xFFFFFFF4, "OBJID_QUERYCLASSNAMEIDX" },
73+
{ 0xFFFFFFF0, "OBJID_NATIVEOM" },
74+
};
75+
#endregion
76+
77+
#region System enumerations
78+
// ReSharper disable InconsistentNaming
79+
//See https://msdn.microsoft.com/en-us/library/windows/desktop/dd318066(v=vs.85).aspx
80+
public enum EventConstant : uint
81+
{
82+
EVENT_MIN = 0x1,
83+
EVENT_SYSTEM_SOUND = 0x1,
84+
EVENT_SYSTEM_ALERT = 0x2,
85+
EVENT_SYSTEM_FOREGROUND = 0x3,
86+
EVENT_SYSTEM_MENUSTART = 0x4,
87+
EVENT_SYSTEM_MENUEND = 0x5,
88+
EVENT_SYSTEM_MENUPOPUPSTART = 0x6,
89+
EVENT_SYSTEM_MENUPOPUPEND = 0x7,
90+
EVENT_SYSTEM_CAPTURESTART = 0x8,
91+
EVENT_SYSTEM_CAPTUREEND = 0x9,
92+
EVENT_SYSTEM_MOVESIZESTART = 0xa,
93+
EVENT_SYSTEM_MOVESIZEEND = 0xb,
94+
EVENT_SYSTEM_CONTEXTHELPSTART = 0xc,
95+
EVENT_SYSTEM_CONTEXTHELPEND = 0xd,
96+
EVENT_SYSTEM_DRAGDROPSTART = 0xe,
97+
EVENT_SYSTEM_DRAGDROPEND = 0xf,
98+
EVENT_SYSTEM_DIALOGSTART = 0x10,
99+
EVENT_SYSTEM_DIALOGEND = 0x11,
100+
EVENT_SYSTEM_SCROLLINGSTART = 0x12,
101+
EVENT_SYSTEM_SCROLLINGEND = 0x13,
102+
EVENT_SYSTEM_SWITCHSTART = 0x14,
103+
EVENT_SYSTEM_SWITCHEND = 0x15,
104+
EVENT_SYSTEM_MINIMIZESTART = 0x16,
105+
EVENT_SYSTEM_MINIMIZEEND = 0x17,
106+
EVENT_OEM_DEFINED_START = 0x0101,
107+
EVENT_OEM_DEFINED_END = 0x01FF,
108+
EVENT_AIA_START = 0xA000,
109+
EVENT_AIA_END = 0xAFFF,
110+
EVENT_UIA_EVENTID_START = 0x4E00,
111+
EVENT_UIA_EVENTID_END = 0x4EFF,
112+
EVENT_UIA_PROPID_START = 0x7500,
113+
EVENT_UIA_PROPID_END = 0x75FF,
114+
EVENT_OBJECT_START = 0x8000,
115+
EVENT_OBJECT_CREATE = 0x8000,
116+
EVENT_OBJECT_DESTROY = 0x8001,
117+
EVENT_OBJECT_SHOW = 0x8002,
118+
EVENT_OBJECT_HIDE = 0x8003,
119+
EVENT_OBJECT_REORDER = 0x8004,
120+
EVENT_OBJECT_FOCUS = 0x8005,
121+
EVENT_OBJECT_SELECTION = 0x8006,
122+
EVENT_OBJECT_SELECTIONADD = 0x8007,
123+
EVENT_OBJECT_SELECTIONREMOVE = 0x8008,
124+
EVENT_OBJECT_SELECTIONWITHIN = 0x8009,
125+
EVENT_OBJECT_STATECHANGE = 0x800A,
126+
EVENT_OBJECT_LOCATIONCHANGE = 0x800B,
127+
EVENT_OBJECT_NAMECHANGE = 0x800C,
128+
EVENT_OBJECT_DESCRIPTIONCHANGE = 0x800D,
129+
EVENT_OBJECT_VALUECHANGE = 0x800E,
130+
EVENT_OBJECT_PARENTCHANGE = 0x800F,
131+
EVENT_OBJECT_HELPCHANGE = 0x8010,
132+
EVENT_OBJECT_DEFACTIONCHANGE = 0x8011,
133+
EVENT_OBJECT_ACCELERATORCHANGE = 0x8012,
134+
EVENT_OBJECT_INVOKED = 0x8013,
135+
EVENT_OBJECT_CONTENTSCROLLED = 0x8015,
136+
EVENT_SYSTEM_ARRANGMENTPREVIEW = 0x8016,
137+
EVENT_OBJECT_LIVEREGIONCHANGED = 0x8019,
138+
EVENT_OBJECT_HOSTEDOBJECTSINVALIDATED = 0x8020,
139+
EVENT_OBJECT_DRAGSTART = 0x8021,
140+
EVENT_OBJECT_DRAGCANCEL = 0x8022,
141+
EVENT_OBJECT_DRAGCOMPLETE = 0x8023,
142+
EVENT_OBJECT_DRAGENTER = 0x8024,
143+
EVENT_OBJECT_DRAGLEAVE = 0x8025,
144+
EVENT_OBJECT_DRAGDROPPED = 0x8026,
145+
EVENT_OBJECT_IME_SHOW = 0x8027,
146+
EVENT_OBJECT_IME_HIDE = 0x8028,
147+
EVENT_OBJECT_IME_CHANGE = 0x8029,
148+
EVENT_OBJECT_TEXTEDIT_CONVERSIONTARGETCHANGED = 0x8030,
149+
EVENT_OBJECT_TEXTSELECTIONCHANGED = 0x8014,
150+
EVENT_OBJECT_END = 0x80FF,
151+
EVENT_MAX = 0x7FFFFFFF
152+
}
153+
// possible marshaling unmanaged type conflict/problem between 32/64 bit
154+
155+
public enum ObjId : uint
156+
{
157+
OBJID_WINDOW = 0x00000000,
158+
OBJID_SYSMENU = 0xFFFFFFFF,
159+
OBJID_TITLEBAR = 0xFFFFFFFE,
160+
OBJID_MENU = 0xFFFFFFFD,
161+
OBJID_CLIENT = 0xFFFFFFFC,
162+
OBJID_VSCROLL = 0xFFFFFFFB,
163+
OBJID_HSCROLL = 0xFFFFFFFA,
164+
OBJID_SIZEGRIP = 0xFFFFFFF9,
165+
OBJID_CARET = 0xFFFFFFF8,
166+
OBJID_CURSOR = 0xFFFFFFF7,
167+
OBJID_ALERT = 0xFFFFFFF6,
168+
OBJID_SOUND = 0xFFFFFFF5,
169+
OBJID_QUERYCLASSNAMEIDX = 0xFFFFFFF4,
170+
OBJID_NATIVEOM = 0xFFFFFFF0
171+
}
172+
173+
public enum WinEventFlags : uint
174+
{
175+
WINEVENT_OUTOFCONTEXT = 0x0000,
176+
WINEVENT_SKIPOWNTHREAD = 0x0001,
177+
WINEVENT_SKIPOWNPROCESS = 0x0002,
178+
WINEVENT_INCONTEXT = 0x0004
179+
}
180+
// ReSharper restore InconsistentNaming
181+
#endregion
182+
183+
#region API declarations
184+
185+
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, uint idObject, uint idChild, uint dwEventThread, uint dwmsEventTime);
186+
187+
[DllImport("user32.dll")]
188+
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, IntPtr lpfnWinEventProc, uint idProcess,
189+
uint idThread, uint dwFlags);
190+
191+
[DllImport("user32.dll")]
192+
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
193+
194+
[DllImport("user32.dll")]
195+
public static extern bool UnhookWinEvent(IntPtr hWinEventHook);
196+
197+
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
198+
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
199+
200+
#endregion
201+
202+
#region Extension methods
203+
204+
public static string ToObjectIdString(this uint objectId)
205+
{
206+
return ObjectIdNameLookup.ContainsKey(objectId) ? ObjectIdNameLookup[objectId] : objectId.ToString(CultureInfo.InvariantCulture);
207+
}
208+
209+
public static string ToEventIdString(this uint eventId)
210+
{
211+
return EventNameLookup.ContainsKey(eventId) ? EventNameLookup[eventId] : eventId.ToString(CultureInfo.InvariantCulture);
212+
}
213+
214+
public static string ToClassName(this IntPtr hwnd)
215+
{
216+
var buffer = new StringBuilder(256);
217+
if (hwnd != IntPtr.Zero)
218+
{
219+
return GetClassName(hwnd, buffer, buffer.Capacity) != 0 ? buffer.ToString() : string.Empty;
220+
}
221+
return string.Empty;
222+
}
223+
224+
#endregion
225+
}
226+
}

Rubberduck.VBEEditor/Rubberduck.VBEditor.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
<Compile Include="Events\ProjectEventArgs.cs" />
128128
<Compile Include="Events\ProjectRenamedEventArgs.cs" />
129129
<Compile Include="Extensions\MSAccessComponentTypeExtensions.cs" />
130+
<Compile Include="Native\WinEvents.cs" />
130131
<Compile Include="SafeComWrappers\Abstract\ISafeComWrapper.cs" />
131132
<Compile Include="SafeComWrappers\Abstract\IVBComponentsEventsSink.cs" />
132133
<Compile Include="SafeComWrappers\Abstract\IVBProjectsEventsSink.cs" />

Rubberduck.VBEEditor/SafeComWrappers/VBA/VBE.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Linq;
34
using System.Runtime.InteropServices;
5+
using Rubberduck.VBEditor.Native;
46
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
57
using Rubberduck.VBEditor.SafeComWrappers.Office.Core;
68
using Rubberduck.VBEditor.SafeComWrappers.Office.Core.Abstract;
9+
using IAddIns = Rubberduck.VBEditor.SafeComWrappers.Abstract.IAddIns;
10+
using IWindow = Rubberduck.VBEditor.SafeComWrappers.Abstract.IWindow;
11+
using IWindows = Rubberduck.VBEditor.SafeComWrappers.Abstract.IWindows;
712
using VB = Microsoft.Vbe.Interop;
813

914
namespace Rubberduck.VBEditor.SafeComWrappers.VBA
1015
{
1116
public class VBE : SafeComWrapper<VB.VBE>, IVBE
1217
{
18+
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
19+
//private readonly WinEvents.WinEventDelegate _events;
20+
//private static IntPtr _hook;
21+
1322
public VBE(VB.VBE target)
1423
:base(target)
1524
{
25+
//_events = WinEventProc;
26+
//uint proc;
27+
//WinEvents.GetWindowThreadProcessId(new IntPtr(target.MainWindow.HWnd), out proc);
28+
//_hook = WinEvents.SetWinEventHook((uint) WinEvents.EventConstant.EVENT_MIN,
29+
// (uint) WinEvents.EventConstant.EVENT_MAX, IntPtr.Zero, Marshal.GetFunctionPointerForDelegate(_events), proc, 0,
30+
// (uint) WinEvents.WinEventFlags.WINEVENT_OUTOFCONTEXT);
1631
}
1732

1833
public string Version
@@ -86,11 +101,12 @@ public IWindows Windows
86101

87102
public override void Release(bool final = false)
88103
{
104+
//WinEvents.UnhookWinEvent(_hook);
89105
if (!IsWrappingNullReference)
90106
{
91107
VBProjects.Release();
92108
CodePanes.Release();
93-
//CommandBars.Release();
109+
CommandBars.Release();
94110
Windows.Release();
95111
AddIns.Release();
96112
base.Release(final);
@@ -130,5 +146,18 @@ public static void SetSelection(IVBProject vbProject, Selection selection, strin
130146
var pane = module.CodePane;
131147
pane.Selection = selection;
132148
}
149+
150+
//private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, uint idObject, uint idChild, uint dwEventThread, uint dwmsEventTime)
151+
//{
152+
////I don't care about the mouse pointer right now.
153+
//if (idObject == (uint)WinEvents.ObjId.OBJID_CURSOR) return;
154+
155+
//Debug.WriteLine("Intercepted event {0} for hwnd {1:X8} ({4}), object {2}, child {3}.",
156+
// eventType.ToEventIdString(),
157+
// hwnd.ToInt32(),
158+
// idObject.ToObjectIdString(),
159+
// idChild,
160+
// hwnd.ToClassName());
161+
//}
133162
}
134163
}

0 commit comments

Comments
 (0)