-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathNativeMethods.cs
237 lines (191 loc) · 6.59 KB
/
NativeMethods.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
namespace Menees.Windows.Forms
{
#region Using Directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
#endregion
internal static class NativeMethods
{
#region Public Methods
public static Rectangle GetNormalWindowBounds(IWin32Window window)
{
WINDOWPLACEMENT placement = default;
placement.length = Marshal.SizeOf(placement);
if (!GetWindowPlacement(new HandleRef(null, window.Handle), ref placement))
{
throw CreateExceptionForLastError();
}
// See the notes in our WINDOWPLACEMENT struct for why the original
// RECT isn't the same as a .NET Rectangle and why we have to de-skew it.
Rectangle skewed = placement.rcNormalPosition;
Rectangle result = new(
skewed.Left,
skewed.Top,
skewed.Width - skewed.Left,
skewed.Height - skewed.Top);
return result;
}
public static int GetScrollPos(IWin32Window control, bool bHorz)
{
const int SB_HORZ = 0;
const int SB_VERT = 1;
const int SIF_POS = 0x0004;
int result = 0;
ScrollInfo info = ScrollInfo.Create(SIF_POS);
if (GetScrollInfo(control.Handle, bHorz ? SB_HORZ : SB_VERT, ref info) != 0)
{
result = info.pos;
}
return result;
}
public static int SendMessage(IWin32Window control, int iMsg, int wParam)
{
int result = SendMessage(control, iMsg, wParam, 0);
return result;
}
public static int SendMessage(IWin32Window control, int iMsg, int wParam, int lParam)
{
int result = (int)SendMessage(control.Handle, iMsg, (IntPtr)wParam, (IntPtr)lParam);
return result;
}
public static int SendMessage(IWin32Window control, int iMsg, int wParam, ref int lParam)
{
IntPtr lParamPtr = (IntPtr)lParam;
IntPtr result = SendMessage(control.Handle, iMsg, (IntPtr)wParam, ref lParamPtr);
lParam = (int)lParamPtr;
return (int)result;
}
public static int SendMessage(IWin32Window control, int iMsg, ref int wParam, ref int lParam)
{
IntPtr wParamPtr = (IntPtr)wParam;
IntPtr lParamPtr = (IntPtr)lParam;
IntPtr result = SendMessage(control.Handle, iMsg, ref wParamPtr, ref lParamPtr);
wParam = (int)wParamPtr;
lParam = (int)lParamPtr;
return (int)result;
}
public static int SendMessage(IWin32Window control, int iMsg, int wParam, ref IntPtr lParam)
{
IntPtr result = SendMessage(control.Handle, iMsg, (IntPtr)wParam, ref lParam);
return (int)result;
}
public static void SetBorderStyle(Control control, BorderStyle borderStyle)
{
IntPtr handle = control.Handle;
// http://www.codeproject.com/Articles/8489/Getting-a-quot-Handle-quot-on-the-MDI-Client
const int GWL_STYLE = -16;
const int GWL_EXSTYLE = -20;
const int WS_BORDER = 0x00800000;
const int WS_EX_CLIENTEDGE = 0x00000200;
// Get styles using Win32 calls
int style = GetWindowLong(handle, GWL_STYLE);
int exStyle = GetWindowLong(handle, GWL_EXSTYLE);
// Add or remove style flags as necessary.
switch (borderStyle)
{
case BorderStyle.Fixed3D:
exStyle |= WS_EX_CLIENTEDGE;
style &= ~WS_BORDER;
break;
case BorderStyle.FixedSingle:
exStyle &= ~WS_EX_CLIENTEDGE;
style |= WS_BORDER;
break;
case BorderStyle.None:
style &= ~WS_BORDER;
exStyle &= ~WS_EX_CLIENTEDGE;
break;
}
// Set the styles using Win32 calls
if (SetWindowLong(handle, GWL_STYLE, style) == 0)
{
throw CreateExceptionForLastError();
}
if (SetWindowLong(handle, GWL_EXSTYLE, exStyle) == 0)
{
throw CreateExceptionForLastError();
}
// Force the control to repaint.
control.Invalidate();
}
#endregion
#region Public Dll Imports
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetDialogBaseUnits();
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);
#endregion
#region Private Dll Imports
[DllImport("user32.dll")]
private static extern int GetScrollInfo(IntPtr hWnd, int nBar, ref ScrollInfo Info);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowPlacement(HandleRef hWnd, ref WINDOWPLACEMENT lpwndpl);
// We have to import this function multiple ways because sometimes the parameters
// are pointers (i.e. references), and sometimes they're not.
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, ref IntPtr wParam, ref IntPtr lParam);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref IntPtr lParam);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowLong(IntPtr hWnd, int Index);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr hWnd, int Index, int Value);
#endregion
#region Private Methods
private static Win32Exception CreateExceptionForLastError()
{
Win32Exception result = Exceptions.Log(new Win32Exception(Marshal.GetLastWin32Error()));
return result;
}
#endregion
#region Private Structures
[StructLayout(LayoutKind.Sequential)]
private struct ScrollInfo
{
#pragma warning disable CC0074 // Make field readonly
public uint size;
public uint mask;
public int min;
public int max;
public uint page;
public int pos;
public int trackPos;
#pragma warning restore CC0074 // Make field readonly
public static ScrollInfo Create(uint mask)
{
ScrollInfo info = default;
info.size = (uint)Marshal.SizeOf(typeof(ScrollInfo));
info.mask = mask;
return info;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct WINDOWPLACEMENT
{
#pragma warning disable CC0074 // Make field readonly
public int length;
public int flags;
public int showCmd;
public Point ptMinPosition;
public Point ptMaxPosition;
// Note: This is actually a Win32 RECT, which is NOT a .NET Rectangle.
// RECT stores {Left, Top, Right, Bottom}, which will get marshaled back
// into Rectangle's {Left, Top, Width, Height} fields. So the Rectangle's
// size will be skewed by an offset of {Left, Top}.
public Rectangle rcNormalPosition;
#pragma warning restore CC0074 // Make field readonly
}
#endregion
}
}