-
Notifications
You must be signed in to change notification settings - Fork 1
/
win_utils.cs
133 lines (118 loc) · 4.8 KB
/
win_utils.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WinUtils
{
// NOTE: we could remove this class's dependency on winforms by p/invoking
// to create the native window and spin the msg pump.
//
public static class WindowHelper
{
public delegate void CreatedWindowDelegate(IntPtr handle);
public delegate void WndProcDelegate(ref Message msg);
static object _lock = new object();
static IntPtr _handle = IntPtr.Zero;
static HiddenWindow _hiddenwindow;
// this property lets the mainline app, communicate to other libraries
// whether it will create a window or not.
//
public static bool ApplicationWillCreateWindow;
// the handle to the hooked window. if ApplicationWillCreateWindow is
// true and window has been created, it will be stored here. if
// ApplicationWillCreateWindow is false and CreateHiddenWindow() has
// been called, the hidden window handle will be here.
//
public static IntPtr Handle
{
get
{
return _handle;
}
set
{
lock (_lock)
{
if (value == IntPtr.Zero)
throw new ArgumentNullException("WindowHandle");
if (_handle != IntPtr.Zero)
throw new InvalidOperationException("WindowHandle is already set");
_handle = value;
if (ApplicationWillCreateWindow)
_HookWindow(_handle);
if (CreatedWindow != null)
CreatedWindow(_handle);
}
}
}
// fired when Handle is set.
//
public static event CreatedWindowDelegate CreatedWindow;
// if you want to process windows messages, hook up to this event.
//
public static event WndProcDelegate WndProc;
// call this if ApplicationWillCreateWindow is false and you want to
// use WndProc, call this to create a hidden window and a bg thread to
// spin a msg pump.
//
public static void CreateHiddenWindow()
{
if (ApplicationWillCreateWindow)
throw new InvalidOperationException("silly to create a hidden window if application is going to create a window");
new Thread((ThreadStart)delegate
{
lock (_lock)
{
if (_hiddenwindow != null)
return;
// Console.WriteLine("WindowHelper: Creating hidden window");
_hiddenwindow = new HiddenWindow();
Handle = _hiddenwindow.Handle;
}
Application.Run();
}) { IsBackground = true }.Start();
}
class HiddenWindow : NativeWindow
{
public HiddenWindow()
{
var cp = new CreateParams();
cp.Caption = "WindowHelper Hidden Window";
cp.ExStyle |= 0x00000008; // WS_EX_TOPMOST, so we are the first to get WM_DEVICECHANGE messages
CreateHandle(cp);
}
protected override void WndProc(ref Message msg)
{
base.WndProc(ref msg);
// Console.WriteLine("WindowHelper: hidden window got message");
if (WinUtils.WindowHelper.WndProc != null)
WinUtils.WindowHelper.WndProc(ref msg);
}
}
static IntPtr _oldwndproc;
static void _HookWindow(IntPtr hwnd)
{
// Console.WriteLine("WindowHelper: Hooking GUI window");
Win32WndProc newwndproc = delegate(IntPtr h, int msg, int wparam, int lparam)
{
// Console.WriteLine("WindowHelper: gui window got message");
if (WndProc != null)
{
var m = new Message() {
HWnd = h,
Msg = msg,
WParam = new IntPtr(wparam),
LParam = new IntPtr(lparam)
};
WndProc(ref m);
}
return CallWindowProc(_oldwndproc, h, msg, wparam, lparam);
};
_oldwndproc = SetWindowLong(hwnd, GWL_WNDPROC, newwndproc);
}
const int GWL_WNDPROC = -4;
delegate int Win32WndProc(IntPtr hwnd, int msg, int wparam, int lparam);
[DllImport("user32")] static extern IntPtr SetWindowLong(IntPtr hwnd, int nindex, Win32WndProc newproc);
[DllImport("user32")] static extern int CallWindowProc(IntPtr lpprevwndfunc, IntPtr hwnd, int msg, int wparam, int lparam);
}
}