1
+ using System ;
2
+ using System . Drawing ;
3
+ using System . Runtime . InteropServices ;
4
+ using System . Threading . Tasks ;
5
+ using System . Windows . Forms ;
6
+
7
+ namespace SvgFileTypePlugin
8
+ {
9
+ /// <summary>
10
+ /// Parent centered MessageBox dialog in C#
11
+ /// </summary>
12
+ internal static class MessageBoxEx
13
+ {
14
+ private static IWin32Window _owner ;
15
+ private static readonly HookProc _hookProc = MessageBoxHookProc ;
16
+ private static IntPtr _hHook = IntPtr . Zero ;
17
+
18
+ public static DialogResult Show ( string text )
19
+ {
20
+ Initialize ( ) ;
21
+ return MessageBox . Show ( text ) ;
22
+ }
23
+
24
+ public static DialogResult Show ( string text , string caption )
25
+ {
26
+ Initialize ( ) ;
27
+ return MessageBox . Show ( text , caption ) ;
28
+ }
29
+
30
+ public static DialogResult Show ( string text , string caption , MessageBoxButtons buttons )
31
+ {
32
+ Initialize ( ) ;
33
+ return MessageBox . Show ( text , caption , buttons ) ;
34
+ }
35
+
36
+ public static DialogResult Show ( string text , string caption , MessageBoxButtons buttons , MessageBoxIcon icon )
37
+ {
38
+ Initialize ( ) ;
39
+ return MessageBox . Show ( text , caption , buttons , icon ) ;
40
+ }
41
+
42
+ public static DialogResult Show ( string text , string caption , MessageBoxButtons buttons , MessageBoxIcon icon ,
43
+ MessageBoxDefaultButton defButton )
44
+ {
45
+ Initialize ( ) ;
46
+ return MessageBox . Show ( text , caption , buttons , icon , defButton ) ;
47
+ }
48
+
49
+ public static DialogResult Show ( string text , string caption , MessageBoxButtons buttons , MessageBoxIcon icon ,
50
+ MessageBoxDefaultButton defButton , MessageBoxOptions options )
51
+ {
52
+ Initialize ( ) ;
53
+ return MessageBox . Show ( text , caption , buttons , icon , defButton , options ) ;
54
+ }
55
+
56
+ public static DialogResult Show ( IWin32Window owner , string text )
57
+ {
58
+ _owner = owner ;
59
+ Initialize ( ) ;
60
+ return MessageBox . Show ( owner , text ) ;
61
+ }
62
+
63
+ public static DialogResult Show ( IWin32Window owner , string text , string caption )
64
+ {
65
+ _owner = owner ;
66
+ Initialize ( ) ;
67
+ return MessageBox . Show ( owner , text , caption ) ;
68
+ }
69
+
70
+ public static DialogResult Show ( IWin32Window owner , string text , string caption , MessageBoxButtons buttons )
71
+ {
72
+ _owner = owner ;
73
+ Initialize ( ) ;
74
+ return MessageBox . Show ( owner , text , caption , buttons ) ;
75
+ }
76
+
77
+ public static DialogResult Show ( IWin32Window owner , string text , string caption , MessageBoxButtons buttons ,
78
+ MessageBoxIcon icon )
79
+ {
80
+ _owner = owner ;
81
+ Initialize ( ) ;
82
+ return MessageBox . Show ( owner , text , caption , buttons , icon ) ;
83
+ }
84
+
85
+ public static DialogResult Show ( IWin32Window owner , string text , string caption , MessageBoxButtons buttons ,
86
+ MessageBoxIcon icon , MessageBoxDefaultButton defButton )
87
+ {
88
+ _owner = owner ;
89
+ Initialize ( ) ;
90
+ return MessageBox . Show ( owner , text , caption , buttons , icon , defButton ) ;
91
+ }
92
+
93
+ public static DialogResult Show ( IWin32Window owner , string text , string caption , MessageBoxButtons buttons ,
94
+ MessageBoxIcon icon , MessageBoxDefaultButton defButton , MessageBoxOptions options )
95
+ {
96
+ _owner = owner ;
97
+ Initialize ( ) ;
98
+ return MessageBox . Show ( owner , text , caption , buttons , icon ,
99
+ defButton , options ) ;
100
+ }
101
+
102
+ public delegate IntPtr HookProc ( int nCode , IntPtr wParam , IntPtr lParam ) ;
103
+
104
+ public const int WH_CALLWNDPROCRET = 12 ;
105
+ public const int WH_CALLWNDPROC = 4 ;
106
+
107
+ public enum CbtHookAction
108
+ {
109
+ HCBT_MOVESIZE = 0 ,
110
+ HCBT_MINMAX = 1 ,
111
+ HCBT_QS = 2 ,
112
+ HCBT_CREATEWND = 3 ,
113
+ HCBT_DESTROYWND = 4 ,
114
+ HCBT_ACTIVATE = 5 ,
115
+ HCBT_CLICKSKIPPED = 6 ,
116
+ HCBT_KEYSKIPPED = 7 ,
117
+ HCBT_SYSCOMMAND = 8 ,
118
+ HCBT_SETFOCUS = 9
119
+ }
120
+
121
+ private static class NativeMethods
122
+ {
123
+ [ DllImport ( "user32" , SetLastError = true ) ]
124
+ public static extern uint GetWindowThreadProcessId ( IntPtr hWnd , out uint lpdwProcessId ) ;
125
+
126
+ [ DllImport ( "user32" , SetLastError = true ) ]
127
+ public static extern bool GetWindowRect ( IntPtr hWnd , ref Rectangle lpRect ) ;
128
+
129
+ [ DllImport ( "user32" , SetLastError = true ) ]
130
+ public static extern bool SetWindowPos ( IntPtr hWnd , IntPtr hWndInsertAfter , int x , int y , int cx , int cy ,
131
+ SetWindowPosFlags uFlags ) ;
132
+
133
+ [ DllImport ( "user32" , SetLastError = true ) ]
134
+ public static extern IntPtr SetWindowsHookEx ( int idHook , HookProc lpfn , IntPtr hInstance , uint threadId ) ;
135
+
136
+ [ DllImport ( "user32" , SetLastError = true ) ]
137
+ public static extern int UnhookWindowsHookEx ( IntPtr idHook ) ;
138
+
139
+ [ DllImport ( "user32" , SetLastError = true ) ]
140
+ public static extern IntPtr CallNextHookEx ( IntPtr idHook , int nCode , IntPtr wParam , IntPtr lParam ) ;
141
+ }
142
+
143
+ [ StructLayout ( LayoutKind . Sequential ) ]
144
+ public struct CWPRETSTRUCT
145
+ {
146
+ public IntPtr lResult ;
147
+ public IntPtr lParam ;
148
+ public IntPtr wParam ;
149
+ public uint message ;
150
+ public IntPtr hwnd ;
151
+ } ;
152
+
153
+ private static void Initialize ( )
154
+ {
155
+ if ( _hHook != IntPtr . Zero )
156
+ {
157
+ throw new NotSupportedException ( "multiple calls are not supported" ) ;
158
+ }
159
+
160
+ if ( _owner == null )
161
+ return ;
162
+
163
+ IntPtr ptr = _owner . Handle ;
164
+ _hHook = NativeMethods . SetWindowsHookEx ( WH_CALLWNDPROCRET , _hookProc , IntPtr . Zero ,
165
+ NativeMethods . GetWindowThreadProcessId ( ptr , out uint _ ) ) ;
166
+ }
167
+
168
+ private static IntPtr MessageBoxHookProc ( int nCode , IntPtr wParam , IntPtr lParam )
169
+ {
170
+ if ( nCode < 0 )
171
+ {
172
+ return NativeMethods . CallNextHookEx ( _hHook , nCode , wParam , lParam ) ;
173
+ }
174
+
175
+ CWPRETSTRUCT msg = ( CWPRETSTRUCT ) Marshal . PtrToStructure ( lParam , typeof ( CWPRETSTRUCT ) ) ;
176
+ IntPtr hook = _hHook ;
177
+
178
+ if ( msg . message == ( int ) CbtHookAction . HCBT_ACTIVATE )
179
+ {
180
+ try
181
+ {
182
+ CenterWindow ( msg . hwnd ) ;
183
+ }
184
+ finally
185
+ {
186
+ NativeMethods . UnhookWindowsHookEx ( _hHook ) ;
187
+ _hHook = IntPtr . Zero ;
188
+ }
189
+ }
190
+
191
+ return NativeMethods . CallNextHookEx ( hook , nCode , wParam , lParam ) ;
192
+ }
193
+
194
+ private static void CenterWindow ( IntPtr hChildWnd )
195
+ {
196
+ Rectangle recChild = new Rectangle ( 0 , 0 , 0 , 0 ) ;
197
+ bool success = NativeMethods . GetWindowRect ( hChildWnd , ref recChild ) ;
198
+
199
+ int width = recChild . Width - recChild . X ;
200
+ int height = recChild . Height - recChild . Y ;
201
+
202
+ Rectangle recParent = new Rectangle ( 0 , 0 , 0 , 0 ) ;
203
+ success = NativeMethods . GetWindowRect ( _owner . Handle , ref recParent ) ;
204
+
205
+ if ( ! success ||
206
+ ( recParent . X == - 32000 && recParent . Y == - 32000 ) )
207
+ {
208
+ // https://blogs.msdn.microsoft.com/oldnewthing/20041028-00/?p=37453
209
+ NativeMethods . UnhookWindowsHookEx ( _hHook ) ;
210
+ return ;
211
+ }
212
+
213
+ Point ptCenter = new Point
214
+ {
215
+ X = recParent . X + ( recParent . Width - recParent . X ) / 2 ,
216
+ Y = recParent . Y + ( recParent . Height - recParent . Y ) / 2
217
+ } ;
218
+
219
+ Point ptStart = new Point
220
+ {
221
+ X = ptCenter . X - width / 2 ,
222
+ Y = ptCenter . Y - height / 2
223
+ } ;
224
+
225
+ //ptStart.X = ptStart.X < 0 ? 0 : ptStart.X;
226
+ //ptStart.Y = ptStart.Y < 0 ? 0 : ptStart.Y;
227
+
228
+ //int result = NativeMethods.MoveWindow(hChildWnd, ptStart.X, ptStart.Y, width, height, false);
229
+ Task . Factory . StartNew ( ( ) =>
230
+ {
231
+ NativeMethods . SetWindowPos ( hChildWnd , IntPtr . Zero , ptStart . X , ptStart . Y , width , height ,
232
+ SetWindowPosFlags . AsynchronousWindowPosition |
233
+ SetWindowPosFlags . IgnoreResize |
234
+ SetWindowPosFlags . DoNotActivate |
235
+ SetWindowPosFlags . DoNotChangeOwnerZOrder |
236
+ SetWindowPosFlags . IgnoreZOrder ) ;
237
+ } ) ;
238
+ }
239
+
240
+ [ Flags ]
241
+ private enum SetWindowPosFlags : uint
242
+ {
243
+ /// <summary>If the calling thread and the thread that owns the window are attached to different input queues,
244
+ /// the system posts the request to the thread that owns the window. This prevents the calling thread from
245
+ /// blocking its execution while other threads process the request.</summary>
246
+ /// <remarks>SWP_ASYNCWINDOWPOS</remarks>
247
+ AsynchronousWindowPosition = 0x4000 ,
248
+
249
+ /// <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
250
+ /// <remarks>SWP_DEFERERASE</remarks>
251
+ DeferErase = 0x2000 ,
252
+
253
+ /// <summary>Draws a frame (defined in the window's class description) around the window.</summary>
254
+ /// <remarks>SWP_DRAWFRAME</remarks>
255
+ DrawFrame = 0x0020 ,
256
+
257
+ /// <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to
258
+ /// the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE
259
+ /// is sent only when the window's size is being changed.</summary>
260
+ /// <remarks>SWP_FRAMECHANGED</remarks>
261
+ FrameChanged = 0x0020 ,
262
+
263
+ /// <summary>Hides the window.</summary>
264
+ /// <remarks>SWP_HIDEWINDOW</remarks>
265
+ HideWindow = 0x0080 ,
266
+
267
+ /// <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the
268
+ /// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
269
+ /// parameter).</summary>
270
+ /// <remarks>SWP_NOACTIVATE</remarks>
271
+ DoNotActivate = 0x0010 ,
272
+
273
+ /// <summary>Discards the entire contents of the client area. If this flag is not specified, the valid
274
+ /// contents of the client area are saved and copied back into the client area after the window is sized or
275
+ /// repositioned.</summary>
276
+ /// <remarks>SWP_NOCOPYBITS</remarks>
277
+ DoNotCopyBits = 0x0100 ,
278
+
279
+ /// <summary>Retains the current position (ignores X and Y parameters).</summary>
280
+ /// <remarks>SWP_NOMOVE</remarks>
281
+ IgnoreMove = 0x0002 ,
282
+
283
+ /// <summary>Does not change the owner window's position in the Z order.</summary>
284
+ /// <remarks>SWP_NOOWNERZORDER</remarks>
285
+ DoNotChangeOwnerZOrder = 0x0200 ,
286
+
287
+ /// <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to
288
+ /// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent
289
+ /// window uncovered as a result of the window being moved. When this flag is set, the application must
290
+ /// explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
291
+ /// <remarks>SWP_NOREDRAW</remarks>
292
+ DoNotRedraw = 0x0008 ,
293
+
294
+ /// <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
295
+ /// <remarks>SWP_NOREPOSITION</remarks>
296
+ DoNotReposition = 0x0200 ,
297
+
298
+ /// <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
299
+ /// <remarks>SWP_NOSENDCHANGING</remarks>
300
+ DoNotSendChangingEvent = 0x0400 ,
301
+
302
+ /// <summary>Retains the current size (ignores the cx and cy parameters).</summary>
303
+ /// <remarks>SWP_NOSIZE</remarks>
304
+ IgnoreResize = 0x0001 ,
305
+
306
+ /// <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
307
+ /// <remarks>SWP_NOZORDER</remarks>
308
+ IgnoreZOrder = 0x0004 ,
309
+
310
+ /// <summary>Displays the window.</summary>
311
+ /// <remarks>SWP_SHOWWINDOW</remarks>
312
+ ShowWindow = 0x0040 ,
313
+ }
314
+ }
315
+ }
0 commit comments