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