1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2008 Novell, Inc.
23 // Peter Dennis Bartok pbartok@novell.com
24 // Ivan N. Zlatev <contact@i-nz.net>
30 //#define ExternalExceptionHandler
32 using System.Runtime.Remoting;
33 using System.Runtime.InteropServices;
34 using System.Runtime.CompilerServices;
35 using System.Threading;
36 using System.Collections;
37 using System.Diagnostics;
39 namespace System.Windows.Forms
41 public class NativeWindow : MarshalByRefObject
46 IntPtr window_handle = IntPtr.Zero;
47 static Hashtable window_collection = new Hashtable();
50 static NativeWindow WindowCreating;
52 #region Public Constructors
55 window_handle=IntPtr.Zero;
57 #endregion // Public Constructors
59 #region Public Instance Properties
60 public IntPtr Handle {
65 #endregion // Public Instance Properties
67 #region Public Static Methods
68 public static NativeWindow FromHandle(IntPtr handle)
70 return FindFirstInTable (handle);
72 #endregion // Public Static Methods
74 #region Private and Internal Methods
75 internal void InvalidateHandle()
77 RemoveFromTable (this);
78 window_handle = IntPtr.Zero;
82 #region Public Instance Methods
83 public void AssignHandle(IntPtr handle)
85 RemoveFromTable (this);
86 window_handle = handle;
91 private static void AddToTable (NativeWindow window)
93 IntPtr handle = window.Handle;
94 if (handle == IntPtr.Zero)
97 lock (window_collection) {
98 object current = window_collection[handle];
99 if (current == null) {
100 window_collection.Add (handle, window);
102 NativeWindow currentWindow = current as NativeWindow;
103 if (currentWindow != null) {
104 if (currentWindow != window) {
105 ArrayList windows = new ArrayList ();
106 windows.Add (currentWindow);
107 windows.Add (window);
108 window_collection[handle] = windows;
110 } else { // list of windows
111 ArrayList windows = (ArrayList) window_collection[handle];
112 if (!windows.Contains (window))
113 windows.Add (window);
119 private static void RemoveFromTable (NativeWindow window)
121 IntPtr handle = window.Handle;
122 if (handle == IntPtr.Zero)
125 lock (window_collection) {
126 object current = window_collection[handle];
127 if (current != null) {
128 NativeWindow currentWindow = current as NativeWindow;
129 if (currentWindow != null) {
130 window_collection.Remove (handle);
131 } else { // list of windows
132 ArrayList windows = (ArrayList) window_collection[handle];
133 windows.Remove (window);
134 if (windows.Count == 0)
135 window_collection.Remove (handle);
136 else if (windows.Count == 1)
137 window_collection[handle] = windows[0];
143 private static NativeWindow FindFirstInTable (IntPtr handle)
145 if (handle == IntPtr.Zero)
148 NativeWindow window = null;
149 lock (window_collection) {
150 object current = window_collection[handle];
151 if (current != null) {
152 window = current as NativeWindow;
153 if (window == null) {
154 ArrayList windows = (ArrayList) current;
155 if (windows.Count > 0)
156 window = (NativeWindow) windows[0];
163 public virtual void CreateHandle(CreateParams cp)
166 WindowCreating = this;
167 window_handle=XplatUI.CreateWindow(cp);
168 WindowCreating = null;
170 if (window_handle != IntPtr.Zero)
176 public void DefWndProc(ref Message m)
178 m.Result=XplatUI.DefWndProc(ref m);
181 public virtual void DestroyHandle()
183 if (window_handle != IntPtr.Zero) {
184 XplatUI.DestroyWindow(window_handle);
188 public virtual void ReleaseHandle()
190 RemoveFromTable (this);
191 window_handle=IntPtr.Zero;
195 #endregion // Public Instance Methods
197 #region Protected Instance Methods
202 protected virtual void OnHandleChange()
206 protected virtual void OnThreadException(Exception e)
208 Application.OnThreadException(e);
211 protected virtual void WndProc(ref Message m)
216 internal static IntPtr WndProc(IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam)
218 IntPtr result = IntPtr.Zero;
219 Message m = new Message();
224 m.Result = IntPtr.Zero;
227 Console.WriteLine("NativeWindow.cs ({0}, {1}, {2}, {3}): result {4}", hWnd, msg, wParam, lParam, m.Result);
229 NativeWindow window = null;
232 object current = null;
233 lock (window_collection) {
234 current = window_collection[hWnd];
237 window = current as NativeWindow;
239 window = EnsureCreated (window, hWnd);
241 if (window != null) {
242 window.WndProc (ref m);
244 } else if (current is ArrayList) {
245 ArrayList windows = (ArrayList) current;
247 if (windows.Count > 0) {
248 window = EnsureCreated ((NativeWindow)windows[0], hWnd);
249 window.WndProc (ref m);
250 // the first one is the control's one. all others are synthetic,
251 // so we want only the result from the control
253 for (int i=1; i < windows.Count; i++)
254 ((NativeWindow)windows[i]).WndProc (ref m);
258 result = XplatUI.DefWndProc (ref m);
261 catch (Exception ex) {
262 #if !ExternalExceptionHandler
264 window.OnThreadException (ex);
270 Console.WriteLine("NativeWindow.cs: Message {0}, result {1}", msg, m.Result);
276 private static NativeWindow EnsureCreated (NativeWindow window, IntPtr hWnd)
278 // we need to do this AssignHandle here instead of relying on
279 // Control.WndProc to do it, because subclasses can override
280 // WndProc, install their own WM_CREATE block, and look at
281 // this.Handle, and it needs to be set. Otherwise, we end up
282 // recursively creating windows and emitting WM_CREATE.
283 if (window == null && WindowCreating != null) {
284 window = WindowCreating;
285 WindowCreating = null;
286 if (window.Handle == IntPtr.Zero)
287 window.AssignHandle (hWnd);
291 #endregion // Protected Instance Methods