1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 module dfl.control;
4 
5 import core.memory;
6 import core.sys.windows.windows;
7 import core.sys.windows.objidl;
8 import core.sys.windows.commctrl;
9 import core.stdc.stdlib;
10 
11 import dfl.application;
12 import dfl.base;
13 import dfl.collections;
14 import dfl.drawing;
15 import dfl.event;
16 import dfl.exception;
17 import dfl.form;
18 import dfl.internal.clib;
19 import dfl.internal.com;
20 import dfl.internal.dlib;
21 import dfl.internal.utf;
22 import dfl.internal.visualstyles: SetWindowTheme;
23 
24 //fix  from application: remve
25 enum UINT WNDCLASS_STYLE = 0x0008;
26 
27 version (NO_DRAG_DROP) version = DFL_NO_DRAG_DROP;
28 
29 version (DFL_NO_DRAG_DROP) {
30 } else {
31    import dfl.data;
32 }
33 
34 version (DFL_NO_MENUS) {
35 } else {
36    import dfl.menu;
37 }
38 
39 //version = RADIO_GROUP_LAYOUT;
40 version = DFL_NO_ZOMBIE_FORM;
41 
42 enum AnchorStyles : ubyte {
43    NONE = 0, ///
44    TOP = 1,
45    BOTTOM = 2,
46    LEFT = 4,
47    RIGHT = 8,/+
48       // Extras:
49       VERTICAL = TOP | BOTTOM,
50    HORIZONTAL = LEFT | RIGHT,
51    ALL = TOP | BOTTOM | LEFT | RIGHT,
52    DEFAULT = TOP | LEFT,
53    TOP_LEFT = TOP | LEFT,
54    TOP_RIGHT = TOP | RIGHT,
55    BOTTOM_LEFT = BOTTOM | LEFT,
56    BOTTOM_RIGHT = BOTTOM | RIGHT,
57    +/
58 
59 
60 
61 }
62 
63 /// Flags for setting control bounds.
64 enum BoundsSpecified : ubyte {
65    NONE = 0, ///
66    X = 1,
67    Y = 2,
68    LOCATION = 1 | 2,
69    WIDTH = 4,
70    HEIGHT = 8,
71    SIZE = 4 | 8,
72    ALL = 1 | 2 | 4 | 8,
73 }
74 
75 /// Layout docking style.
76 enum DockStyle : ubyte {
77    NONE, ///
78    BOTTOM, ///
79    FILL, ///
80    LEFT, ///
81    RIGHT, ///
82    TOP, ///
83 }
84 
85 private {
86    struct GetZIndex {
87       Control find;
88       int index = -1;
89       private int _tmp = 0;
90    }
91 
92    extern (Windows) BOOL getZIndexCallback(HWND hwnd, LPARAM lparam) {
93       GetZIndex* gzi = cast(GetZIndex*) lparam;
94       if (hwnd == gzi.find.hwnd) {
95          gzi.index = gzi._tmp;
96          return FALSE; // Stop, found it.
97       }
98 
99       Control ctrl;
100       ctrl = Control.fromHandle(hwnd);
101       if (ctrl && ctrl.parent is gzi.find.parent) {
102          gzi._tmp++;
103       }
104 
105       return TRUE; // Keep looking.
106    }
107 }
108 
109 /// Effect flags for drag/drop operations.
110 enum DragDropEffects : DWORD {
111    NONE = 0, ///
112    COPY = 1,
113    MOVE = 2,
114    LINK = 4,
115    SCROLL = 0x80000000,
116    ALL = COPY | MOVE | LINK | SCROLL,
117 }
118 
119 /// Drag/drop action.
120 enum DragAction : HRESULT {
121    CONTINUE = S_OK, ///
122    CANCEL = DRAGDROP_S_CANCEL,
123    DROP = DRAGDROP_S_DROP,
124 }
125 
126 // Flags.
127 deprecated enum UICues : uint {
128    NONE = 0,
129    SHOW_FOCUS = 1,
130    SHOW_KEYBOARD = 2,
131    SHOWN = SHOW_FOCUS | SHOW_KEYBOARD,
132    CHANGE_FOCUS = 4,
133    CHANGE_KEYBOARD = 8, // Key mnemonic underline cues are on.
134    CHANGED = CHANGE_FOCUS | CHANGE_KEYBOARD,
135 }
136 
137 // May be OR'ed together.
138 /// Style flags of a control.
139 enum ControlStyles : uint {
140    NONE = 0, ///
141 
142    CONTAINER_CONTROL = 0x1,
143 
144    // TODO: implement.
145    USER_PAINT = 0x2,
146 
147    OPAQUE = 0x4,
148    RESIZE_REDRAW = 0x10,
149    //FIXED_WIDTH =                      0x20, // TODO: implement.
150    //FIXED_HEIGHT =                     0x40, // TODO: implement.
151    STANDARD_CLICK = 0x100,
152    SELECTABLE = 0x200,
153 
154    // TODO: implement.
155    USER_MOUSE = 0x400,
156 
157    //SUPPORTS_TRANSPARENT_BACK_COLOR =  0x800, // Only if USER_PAINT and parent is derived from Control. TODO: implement.
158    STANDARD_DOUBLE_CLICK = 0x1000,
159    ALL_PAINTING_IN_WM_PAINT = 0x2000,
160    CACHE_TEXT = 0x4000,
161    ENABLE_NOTIFY_MESSAGE = 0x8000, // deprecated. Calls onNotifyMessage() for every message.
162    //DOUBLE_BUFFER =                    0x10000, // TODO: implement.
163 
164    WANT_TAB_KEY = 0x01000000,
165    WANT_ALL_KEYS = 0x02000000,
166 }
167 
168 /// Control creation parameters.
169 struct CreateParams {
170    Dstring className; ///
171    Dstring caption;
172    void* param;
173    HWND parent;
174    HMENU menu;
175    HINSTANCE inst;
176    int x;
177    int y;
178    int width;
179    int height;
180    DWORD classStyle;
181    DWORD exStyle;
182    DWORD style;
183 }
184 
185 deprecated class UICuesEventArgs : EventArgs {
186 deprecated:
187 
188    this(UICues uic) {
189       chg = uic;
190    }
191 
192    final UICues changed() {
193       return chg;
194    }
195 
196    final bool changeFocus() {
197       return (chg & UICues.CHANGE_FOCUS) != 0;
198    }
199 
200    final bool changeKeyboard() {
201       return (chg & UICues.CHANGE_KEYBOARD) != 0;
202    }
203 
204    final bool showFocus() {
205       return (chg & UICues.SHOW_FOCUS) != 0;
206    }
207 
208    final bool showKeyboard() {
209       return (chg & UICues.SHOW_KEYBOARD) != 0;
210    }
211 
212    private:
213    UICues chg;
214 }
215 
216 class ControlEventArgs : EventArgs {
217 
218    this(Control ctrl) {
219       this.ctrl = ctrl;
220    }
221 
222    final @property Control control() {
223       return ctrl;
224    }
225 
226    private:
227    Control ctrl;
228 }
229 
230 class HelpEventArgs : EventArgs {
231 
232    this(Point mousePos) {
233       mpos = mousePos;
234    }
235 
236    final @property void handled(bool byes) {
237       hand = byes;
238    }
239 
240    final @property bool handled() {
241       return hand;
242    }
243 
244    final @property Point mousePos() {
245       return mpos;
246    }
247 
248    private:
249    Point mpos;
250    bool hand = false;
251 }
252 
253 class InvalidateEventArgs : EventArgs {
254 
255    this(Rect invalidRect) {
256       ir = invalidRect;
257    }
258 
259    final @property Rect invalidRect() {
260       return ir;
261    }
262 
263    private:
264    Rect ir;
265 }
266 
267 // ///
268 // New dimensions before resizing.
269 deprecated class BeforeResizeEventArgs : EventArgs {
270 deprecated:
271 
272    this(int width, int height) {
273       this.w = width;
274       this.h = height;
275    }
276 
277    void width(int cx) {
278       w = cx;
279    }
280 
281    int width() {
282       return w;
283    }
284 
285    void height(int cy) {
286       h = cy;
287    }
288 
289    int height() {
290       return h;
291    }
292 
293    private:
294    int w, h;
295 }
296 
297 class LayoutEventArgs : EventArgs {
298 
299    this(Control affectedControl) {
300       ac = affectedControl;
301    }
302 
303    final @property Control affectedControl() {
304       return ac;
305    }
306 
307    private:
308    Control ac;
309 }
310 
311 version (DFL_NO_DRAG_DROP) {
312 } else {
313 
314    class DragEventArgs : EventArgs {
315 
316       this(IDataObject dataObj, int keyState, int x, int y,
317             DragDropEffects allowedEffect, DragDropEffects effect) {
318          _dobj = dataObj;
319          _keyState = keyState;
320          _x = x;
321          _y = y;
322          _allowedEffect = allowedEffect;
323          _effect = effect;
324       }
325 
326       final @property DragDropEffects allowedEffect() {
327          return _allowedEffect;
328       }
329 
330       final @property void effect(DragDropEffects newEffect) {
331          _effect = newEffect;
332       }
333 
334       final @property DragDropEffects effect() {
335          return _effect;
336       }
337 
338       final @property dfl.data.IDataObject data() {
339          return _dobj;
340       }
341 
342       // State of ctrl, alt, shift, and mouse buttons.
343       final @property int keyState() {
344          return _keyState;
345       }
346 
347       final @property int x() {
348          return _x;
349       }
350 
351       final @property int y() {
352          return _y;
353       }
354 
355       private:
356       dfl.data.IDataObject _dobj;
357       int _keyState;
358       int _x, _y;
359       DragDropEffects _allowedEffect, _effect;
360    }
361 
362    class GiveFeedbackEventArgs : EventArgs {
363 
364       this(DragDropEffects effect, bool useDefaultCursors) {
365          _effect = effect;
366          udefcurs = useDefaultCursors;
367       }
368 
369       final @property DragDropEffects effect() {
370          return _effect;
371       }
372 
373       final @property void useDefaultCursors(bool byes) {
374          udefcurs = byes;
375       }
376 
377       final @property bool useDefaultCursors() {
378          return udefcurs;
379       }
380 
381       private:
382       DragDropEffects _effect;
383       bool udefcurs;
384    }
385 
386    class QueryContinueDragEventArgs : EventArgs {
387 
388       this(int keyState, bool escapePressed, DragAction action) {
389          _keyState = keyState;
390          escp = escapePressed;
391          _action = action;
392       }
393 
394       final @property void action(DragAction newAction) {
395          _action = newAction;
396       }
397 
398       final @property DragAction action() {
399          return _action;
400       }
401 
402       final @property bool escapePressed() {
403          return escp;
404       }
405 
406       // State of ctrl, alt and shift.
407       final @property int keyState() {
408          return _keyState;
409       }
410 
411       private:
412       int _keyState;
413       bool escp;
414       DragAction _action;
415    }
416 }
417 
418 version (NO_WINDOWS_HUNG_WORKAROUND) {
419 } else {
420    version = WINDOWS_HUNG_WORKAROUND;
421 }
422 debug {
423    version = _DFL_WINDOWS_HUNG_WORKAROUND;
424 }
425 version (WINDOWS_HUNG_WORKAROUND) {
426    version = _DFL_WINDOWS_HUNG_WORKAROUND;
427 }
428 
429 version (_DFL_WINDOWS_HUNG_WORKAROUND) {
430    class WindowsHungDflException : DflException {
431       this(Dstring msg) {
432          super(msg);
433       }
434    }
435 }
436 
437 alias EnumWindowsCallback = BOOL delegate(HWND);
438 package struct EnumWindowsCallbackData {
439    EnumWindowsCallback callback;
440    DThrowable exception;
441 }
442 
443 // Callback for EnumWindows() and EnumChildWindows().
444 private extern (Windows) BOOL enumingWindows(HWND hwnd, LPARAM lparam) nothrow {
445    auto cbd = *(cast(EnumWindowsCallbackData*) lparam);
446    try {
447       return cbd.callback(hwnd);
448    }
449    catch (DThrowable e) {
450       cbd.exception = e;
451       return FALSE;
452    }
453    assert(0);
454 }
455 
456 private struct Efi {
457    HWND hwParent;
458    EnumWindowsCallbackData cbd;
459 }
460 
461 // Callback for EnumChildWindows(). -lparam- = pointer to Efi;
462 private extern (Windows) BOOL enumingFirstWindows(HWND hwnd, LPARAM lparam) nothrow {
463    auto efi = cast(Efi*) lparam;
464    if (efi.hwParent == GetParent(hwnd)) {
465       try {
466          return efi.cbd.callback(hwnd);
467       }
468       catch (DThrowable e) {
469          efi.cbd.exception = e;
470          return FALSE;
471       }
472    }
473    return TRUE;
474 }
475 
476 package BOOL enumWindows(EnumWindowsCallback dg) {
477    EnumWindowsCallbackData cbd;
478    cbd.callback = dg;
479    scope (exit)
480       if (cbd.exception) {
481          throw cbd.exception;
482       }
483    static assert((&cbd).sizeof <= LPARAM.sizeof);
484    return EnumWindows(&enumingWindows, cast(LPARAM)&cbd);
485 }
486 
487 package BOOL enumChildWindows(HWND hwParent, EnumWindowsCallback dg) {
488    EnumWindowsCallbackData cbd;
489    cbd.callback = dg;
490    scope (exit)
491       if (cbd.exception) {
492          throw cbd.exception;
493       }
494    static assert((&cbd).sizeof <= LPARAM.sizeof);
495    return EnumChildWindows(hwParent, &enumingWindows, cast(LPARAM)&cbd);
496 }
497 
498 // Only the parent's children, not its children.
499 package BOOL enumFirstChildWindows(HWND hwParent, EnumWindowsCallback dg) {
500    Efi efi;
501    efi.hwParent = hwParent;
502    efi.cbd.callback = dg;
503    scope (exit)
504       if (efi.cbd.exception) {
505          throw efi.cbd.exception;
506       }
507    return EnumChildWindows(hwParent, &enumingFirstWindows, cast(LPARAM)&efi);
508 }
509 
510 enum ControlFont : ubyte {
511    COMPATIBLE, ///
512    OLD,
513    NATIVE,
514 }
515 
516 debug {
517    import std.string;
518 }
519 
520 /// Control class.
521 class Control : DObject, IWindow {
522 
523    static class ControlCollection {
524       protected this(Control owner) {
525          _owner = owner;
526       }
527 
528       deprecated alias count = length;
529 
530       @property int length() {
531          if (_owner.isHandleCreated) {
532             // Inefficient :(
533             uint len = 0;
534             foreach (Control ctrl; this) {
535                len++;
536             }
537             return len;
538          } else {
539             return children.length;
540          }
541       }
542 
543       @property Control opIndex(int i) {
544          if (_owner.isHandleCreated) {
545             int oni = 0;
546             foreach (Control ctrl; this) {
547                if (oni == i) {
548                   return ctrl;
549                }
550                oni++;
551             }
552             // Index out of bounds, bad things happen.
553             assert(0);
554          } else {
555             return children[i];
556          }
557       }
558 
559       void add(Control ctrl) {
560          ctrl.parent = _owner;
561       }
562 
563       // opIn ?
564       bool contains(Control ctrl) {
565          return indexOf(ctrl) != -1;
566       }
567 
568       int indexOf(Control ctrl) {
569          if (_owner.isHandleCreated) {
570             int i = 0;
571             int foundi = -1;
572 
573             BOOL enuming(HWND hwnd) {
574                if (hwnd == ctrl.handle) {
575                   foundi = i;
576                   return false; // Stop.
577                }
578 
579                i++;
580                return true; // Continue.
581             }
582 
583             enumFirstChildWindows(_owner.handle, &enuming);
584             return foundi;
585          } else {
586             foreach (int i, Control onCtrl; children) {
587                if (onCtrl == ctrl) {
588                   return i;
589                }
590             }
591             return -1;
592          }
593       }
594 
595       void remove(Control ctrl) {
596          if (_owner.isHandleCreated) {
597             _removeCreated(ctrl.handle);
598          } else {
599             int i = indexOf(ctrl);
600             if (i != -1) {
601                _removeNotCreated(i);
602             }
603          }
604       }
605 
606       private void _removeCreated(HWND hwnd) {
607          DestroyWindow(hwnd); // ?
608       }
609 
610       package void _removeNotCreated(int i) {
611          if (!i) {
612             children = children[1 .. children.length];
613          } else if (i == children.length - 1) {
614             children = children[0 .. i];
615          } else {
616             children = children[0 .. i] ~ children[i + 1 .. children.length];
617          }
618       }
619 
620       void removeAt(int i) {
621          if (_owner.isHandleCreated) {
622             int ith = 0;
623             HWND hwndith;
624 
625             BOOL enuming(HWND hwnd) {
626                if (ith == i) {
627                   hwndith = hwnd;
628                   return false; // Stop.
629                }
630 
631                ith++;
632                return true; // Continue.
633             }
634 
635             enumFirstChildWindows(_owner.handle, &enuming);
636             if (hwndith) {
637                _removeCreated(hwndith);
638             }
639          } else {
640             _removeNotCreated(i);
641          }
642       }
643 
644       protected final @property Control owner() {
645          return _owner;
646       }
647 
648       int opApply(int delegate(ref Control) dg) {
649          int result = 0;
650 
651          if (_owner.isHandleCreated) {
652             BOOL enuming(HWND hwnd) {
653                Control ctrl = fromHandle(hwnd);
654                if (ctrl) {
655                   result = dg(ctrl);
656                   if (result) {
657                      return false; // Stop.
658                   }
659                }
660 
661                return true; // Continue.
662             }
663 
664             enumFirstChildWindows(_owner.handle, &enuming);
665          } else {
666             foreach (Control ctrl; children) {
667                result = dg(ctrl);
668                if (result) {
669                   break;
670                }
671             }
672          }
673 
674          return result;
675       }
676 
677       mixin OpApplyAddIndex!(opApply, Control);
678 
679 package:
680       Control _owner;
681       Control[] children; // Only valid if -owner- isn't created yet (or is recreating).
682 
683       /+
684          final void _array_swap(int ifrom, int ito) {
685             if(ifrom == ito ||
686                   ifrom < 0 || ito < 0 ||
687                   ifrom >= length || ito >= length) {
688                return;
689             }
690 
691             Control cto;
692             cto = children[ito];
693             children[ito] = children[ifrom];
694             children[ifrom] = cto;
695          }
696       +/
697 
698          final void _simple_front_one(int i) {
699             if (i < 0 || i >= length - 1) {
700                return;
701             }
702 
703             children = children[0 .. i] ~ children[i + 1 .. i + 2] ~ children[i .. i + 1] ~ children[i
704                + 2 .. children.length];
705          }
706 
707       final void _simple_front_one(Control c) {
708          return _simple_front_one(indexOf(c));
709       }
710 
711       final void _simple_back_one(int i) {
712          if (i <= 0 || i >= length) {
713             return;
714          }
715 
716          children = children[0 .. i - 1] ~ children[i + 1 .. i + 2] ~ children[i .. i + 1] ~ children[i
717             + 2 .. children.length];
718       }
719 
720       final void _simple_back_one(Control c) {
721          return _simple_back_one(indexOf(c));
722       }
723 
724       final void _simple_back(int i) {
725          if (i <= 0 || i >= length) {
726             return;
727          }
728 
729          children = children[i .. i + 1] ~ children[0 .. i] ~ children[i + 1 .. children.length];
730       }
731 
732       final void _simple_back(Control c) {
733          return _simple_back(indexOf(c));
734       }
735 
736       final void _simple_front(int i) {
737          if (i < 0 || i >= length - 1) {
738             return;
739          }
740 
741          children = children[0 .. i] ~ children[i + 1 .. children.length] ~ children[i .. i + 1];
742       }
743 
744       final void _simple_front(Control c) {
745          return _simple_front(indexOf(c));
746       }
747    }
748 
749    private void _ctrladded(ControlEventArgs cea) {
750       if (Application._compat & DflCompat.CONTROL_PARENT_096) {
751          if (!(_exStyle() & WS_EX_CONTROLPARENT)) {
752             if (!(cbits & CBits.FORM)) {
753                //if((cea.control._style() & WS_TABSTOP) || (cea.control._exStyle() & WS_EX_CONTROLPARENT))
754                _exStyle(_exStyle() | WS_EX_CONTROLPARENT);
755             }
756          }
757       } else {
758          assert(getStyle(ControlStyles.CONTAINER_CONTROL), "Control added to non-container parent");
759       }
760 
761       onControlAdded(cea);
762    }
763 
764    private void _ctrlremoved(ControlEventArgs cea) {
765       alayout(cea.control);
766 
767       onControlRemoved(cea);
768    }
769 
770    protected void onControlAdded(ControlEventArgs cea) {
771       controlAdded(this, cea);
772    }
773 
774    protected void onControlRemoved(ControlEventArgs cea) {
775       controlRemoved(this, cea);
776    }
777 
778    @property final HWindow handle() { // IWindow getter
779       if (!isHandleCreated) {
780          debug (APP_PRINT)
781             cprintf("Control created due to handle request.\n");
782 
783          createHandle();
784       }
785 
786       return hwnd;
787    }
788 
789    version (DFL_NO_DRAG_DROP) {
790    } else {
791       @property void allowDrop(bool byes) {
792          /+
793             if(dyes) {
794                _exStyle(_exStyle() | WS_EX_ACCEPTFILES);
795             } else {
796                _exStyle(_exStyle() & ~WS_EX_ACCEPTFILES);
797             }
798          +/
799 
800             if (byes) {
801                if (!droptarget) {
802                   droptarget = new DropTarget(this);
803                   if (isHandleCreated) {
804                      switch (RegisterDragDrop(hwnd, droptarget)) {
805                         case S_OK:
806                         case DRAGDROP_E_ALREADYREGISTERED: // Hmm.
807                            break;
808 
809                         default:
810                            droptarget = null;
811                            throw new DflException("Unable to register drag-drop");
812                      }
813                   }
814                }
815             } else {
816                delete droptarget;
817                droptarget = null;
818                RevokeDragDrop(hwnd);
819             }
820       }
821 
822       @property bool allowDrop() {
823          /+
824             return (_exStyle() & WS_EX_ACCEPTFILES) != 0;
825          +/
826 
827             return droptarget !is null;
828       }
829    }
830 
831    private void _propagateBackColorAmbience() {
832       Color bc;
833       bc = backColor;
834 
835       void pa(Control pc) {
836          foreach (Control ctrl; pc.ccollection) {
837             if (Color.empty == ctrl.backc) { // If default.
838                if (bc == ctrl.backColor) { // If same default.
839                   ctrl.deleteThisBackgroundBrush(); // Needs to be recreated with new color.
840                   ctrl.onBackColorChanged(EventArgs.empty);
841 
842                   pa(ctrl); // Recursive.
843                }
844             }
845          }
846       }
847 
848       pa(this);
849    }
850 
851    protected void onBackColorChanged(EventArgs ea) {
852       debug (EVENT_PRINT) {
853          cprintf("{ Event: onBackColorChanged - Control %.*s }\n", name);
854       }
855 
856       backColorChanged(this, ea);
857    }
858 
859    @property void backColor(Color c) {
860       if (backc == c) {
861          return;
862       }
863 
864       deleteThisBackgroundBrush(); // Needs to be recreated with new color.
865       backc = c;
866       onBackColorChanged(EventArgs.empty);
867 
868       _propagateBackColorAmbience();
869       if (isHandleCreated) {
870          invalidate(true); // Redraw!
871       }
872    }
873 
874    @property Color backColor() {
875       if (Color.empty == backc) {
876          if (parent) {
877             return parent.backColor;
878          }
879          return defaultBackColor;
880       }
881       return backc;
882    }
883 
884    final @property int bottom() {
885       return wrect.bottom;
886    }
887 
888    final @property void bounds(Rect r) {
889       setBoundsCore(r.x, r.y, r.width, r.height, BoundsSpecified.ALL);
890    }
891 
892    final @property Rect bounds() {
893       return wrect;
894    }
895 
896    protected void setBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
897       // Make sure at least one flag is set.
898       //if(!(specified & BoundsSpecified.ALL))
899       if (!specified) {
900          return;
901       }
902 
903       if (isHandleCreated) {
904          UINT swpf = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE;
905 
906          if (specified & BoundsSpecified.X) {
907             if (!(specified & BoundsSpecified.Y)) {
908                y = this.top();
909             }
910             swpf &= ~SWP_NOMOVE;
911          } else if (specified & BoundsSpecified.Y) {
912             x = this.left();
913             swpf &= ~SWP_NOMOVE;
914          }
915 
916          if (specified & BoundsSpecified.WIDTH) {
917             if (!(specified & BoundsSpecified.HEIGHT)) {
918                height = this.height();
919             }
920             swpf &= ~SWP_NOSIZE;
921          } else if (specified & BoundsSpecified.HEIGHT) {
922             width = this.width();
923             swpf &= ~SWP_NOSIZE;
924          }
925 
926          SetWindowPos(hwnd, HWND.init, x, y, width, height, swpf);
927          // Window events will update -wrect-.
928       } else {
929          if (specified & BoundsSpecified.X) {
930             wrect.x = x;
931          }
932          if (specified & BoundsSpecified.Y) {
933             wrect.y = y;
934          }
935          if (specified & BoundsSpecified.WIDTH) {
936             if (width < 0) {
937                width = 0;
938             }
939 
940             wrect.width = width;
941             wclientsz.width = width;
942          }
943          if (specified & BoundsSpecified.HEIGHT) {
944             if (height < 0) {
945                height = 0;
946             }
947 
948             wrect.height = height;
949             wclientsz.height = height;
950          }
951 
952          //oldwrect = wrect;
953       }
954    }
955 
956    final @property bool canFocus() {
957       /+
958          LONG wl = _style();
959       return /+ hwnd && +/ (wl & WS_VISIBLE) && !(wl & WS_DISABLED);
960       +/
961          //return visible && enabled;
962          // Don't need to check -isHandleCreated- because IsWindowVisible() will fail from a null HWND.
963          return  /+ isHandleCreated && +/ IsWindowVisible(hwnd) && IsWindowEnabled(hwnd);
964    }
965 
966    final @property bool canSelect()
967       out (result) {
968          if (result) {
969             assert(isHandleCreated);
970          }
971       }
972    body {
973       // All parent controls need to be visible and enabled, too.
974       // Don't need to check -isHandleCreated- because IsWindowVisible() will fail from a null HWND.
975       return  /+ isHandleCreated && +/ (ctrlStyle & ControlStyles.SELECTABLE)
976          && IsWindowVisible(hwnd) && IsWindowEnabled(hwnd);
977    }
978 
979    package final bool _hasSelStyle() {
980       return getStyle(ControlStyles.SELECTABLE);
981    }
982 
983    // Returns true if this control has the mouse capture.
984    final @property bool capture() {
985       return isHandleCreated && hwnd == GetCapture();
986    }
987 
988    final @property void capture(bool cyes) {
989       if (cyes) {
990          SetCapture(hwnd);
991       } else {
992          ReleaseCapture();
993       }
994    }
995 
996    // When true, validating and validated events are fired when the control
997    // receives focus. Typically set to false for controls such as a Help button.
998    // Default is true.
999    deprecated final bool causesValidation() {
1000       //return cvalidation;
1001       return false;
1002    }
1003 
1004    deprecated protected void onCausesValidationChanged(EventArgs ea) {
1005       //causesValidationChanged(this, ea);
1006    }
1007 
1008    deprecated final void causesValidation(bool vyes) {
1009       /+
1010          if(cvalidation == vyes) {
1011             return;
1012          }
1013 
1014       cvalidation = vyes;
1015 
1016       onCausesValidationChanged(EventArgs.empty);
1017       +/
1018    }
1019 
1020    final @property Rect clientRectangle() {
1021       return Rect(Point(0, 0), wclientsz);
1022    }
1023 
1024    final bool contains(Control ctrl) {
1025       //return ccollection.contains(ctrl);
1026       return ctrl && ctrl.parent is this;
1027    }
1028 
1029    final @property Size clientSize() {
1030       return wclientsz;
1031    }
1032 
1033    final @property void clientSize(Size sz) {
1034       setClientSizeCore(sz.width, sz.height);
1035    }
1036 
1037    protected void setClientSizeCore(int width, int height) {
1038       /*
1039          if(isHandleCreated) {
1040          setBoundsCore(0, 0, width, height, BoundsSpecified.SIZE);
1041          }
1042 
1043       //wclientsz = Size(width, height);
1044        */
1045 
1046       RECT r;
1047 
1048       r.left = 0;
1049       r.top = 0;
1050       r.right = width;
1051       r.bottom = height;
1052 
1053       AdjustWindowRectEx(&r, _style(), FALSE, _exStyle());
1054 
1055       setBoundsCore(0, 0, r.right - r.left, r.bottom - r.top, BoundsSpecified.SIZE);
1056    }
1057 
1058    // This window or one of its children has focus.
1059    final @property bool containsFocus() {
1060       if (!isHandleCreated) {
1061          return false;
1062       }
1063 
1064       HWND hwfocus = GetFocus();
1065       return hwfocus == hwnd || IsChild(hwnd, hwfocus);
1066    }
1067 
1068    version (DFL_NO_MENUS) {
1069    } else {
1070 
1071       protected void onContextMenuChanged(EventArgs ea) {
1072          contextMenuChanged(this, ea);
1073       }
1074 
1075       @property void contextMenu(ContextMenu menu) {
1076          if (cmenu is menu) {
1077             return;
1078          }
1079 
1080          cmenu = menu;
1081 
1082          if (isHandleCreated) {
1083             onContextMenuChanged(EventArgs.empty);
1084          }
1085       }
1086 
1087       @property ContextMenu contextMenu() {
1088          return cmenu;
1089       }
1090    }
1091 
1092    final @property ControlCollection controls() {
1093       //return new ControlCollection(this);
1094       return ccollection;
1095    }
1096 
1097    final @property bool created() {
1098       // To-do: only return true when createHandle finishes.
1099       // Will also need to update uses of created/isHandleCreated.
1100       // Return false again when disposing/killing.
1101       //return isHandleCreated;
1102       return isHandleCreated || recreatingHandle;
1103    }
1104 
1105    private void _propagateCursorAmbience() {
1106       Cursor cur;
1107       cur = cursor;
1108 
1109       void pa(Control pc) {
1110          foreach (Control ctrl; pc.ccollection) {
1111             if (ctrl.wcurs is null) { // If default.
1112                if (cur is ctrl.cursor) { // If same default.
1113                   ctrl.onCursorChanged(EventArgs.empty);
1114 
1115                   pa(ctrl); // Recursive.
1116                }
1117             }
1118          }
1119       }
1120 
1121       pa(this);
1122    }
1123 
1124    protected void onCursorChanged(EventArgs ea) {
1125       /+
1126          debug(EVENT_PRINT) {
1127             cprintf("{ Event: onCursorChanged - Control %.*s }\n", name);
1128          }
1129       +/
1130 
1131          if (isHandleCreated) {
1132             if (visible && enabled) {
1133                Point curpt = Cursor.position;
1134                if (hwnd == WindowFromPoint(curpt.point)) {
1135                   SendMessageA(hwnd, WM_SETCURSOR, cast(WPARAM) hwnd,
1136                         MAKELPARAM(SendMessageA(hwnd, WM_NCHITTEST, 0,
1137                               MAKELPARAM(curpt.x, curpt.y)), WM_MOUSEMOVE));
1138                }
1139             }
1140          }
1141 
1142       cursorChanged(this, ea);
1143    }
1144 
1145    @property void cursor(Cursor cur) {
1146       if (cur is wcurs) {
1147          return;
1148       }
1149 
1150       wcurs = cur;
1151       onCursorChanged(EventArgs.empty);
1152 
1153       _propagateCursorAmbience();
1154    }
1155 
1156    @property Cursor cursor() {
1157       if (!wcurs) {
1158          if (parent) {
1159             return parent.cursor;
1160          }
1161          return _defaultCursor;
1162       }
1163       return wcurs;
1164    }
1165 
1166    static @property Color defaultBackColor() {
1167       return Color.systemColor(COLOR_BTNFACE);
1168    }
1169 
1170    static @property Color defaultForeColor() {
1171       return Color.systemColor(COLOR_BTNTEXT);
1172    }
1173 
1174    private static Font _deffont = null;
1175 
1176    private static Font _createOldFont() {
1177       return new Font(cast(HFONT) GetStockObject(DEFAULT_GUI_FONT), false);
1178    }
1179 
1180    private static Font _createCompatibleFont() {
1181       Font result;
1182       result = _createOldFont();
1183 
1184       try {
1185          OSVERSIONINFOA osi;
1186          osi.dwOSVersionInfoSize = osi.sizeof;
1187          if (GetVersionExA(&osi) && osi.dwMajorVersion >= 5) {
1188             // "MS Shell Dlg" / "MS Shell Dlg 2" not always supported.
1189             result = new Font("MS Shell Dlg 2",
1190                   result.getSize(GraphicsUnit.POINT), GraphicsUnit.POINT);
1191          }
1192       }
1193       catch (Throwable) {
1194       }
1195 
1196       //if(!result)
1197       // result = _createOldFont();
1198       assert(result !is null);
1199 
1200       return result;
1201    }
1202 
1203    private static Font _createNativeFont() {
1204       Font result;
1205 
1206       NONCLIENTMETRICSA ncm;
1207       ncm.cbSize = ncm.sizeof;
1208       if (!SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, ncm.sizeof, &ncm, 0)) {
1209          result = _createCompatibleFont();
1210       } else {
1211          result = new Font(&ncm.lfMessageFont, true);
1212       }
1213 
1214       return result;
1215    }
1216 
1217    private static void _setDeffont(ControlFont cf) {
1218       synchronized {
1219          assert(_deffont is null);
1220          switch (cf) {
1221             case ControlFont.COMPATIBLE:
1222                _deffont = _createCompatibleFont();
1223                break;
1224             case ControlFont.NATIVE:
1225                _deffont = _createNativeFont();
1226                break;
1227             case ControlFont.OLD:
1228                _deffont = _createOldFont();
1229                break;
1230             default:
1231                assert(0);
1232          }
1233       }
1234    }
1235 
1236    deprecated alias controlFont = defaultFont;
1237 
1238    static @property void defaultFont(ControlFont cf) {
1239       if (_deffont) {
1240          throw new DflException("Control font already selected");
1241       }
1242       _setDeffont(cf);
1243    }
1244 
1245    static @property void defaultFont(Font f) {
1246       if (_deffont) {
1247          throw new DflException("Control font already selected");
1248       }
1249       _deffont = f;
1250    }
1251 
1252    static @property Font defaultFont() {
1253       if (!_deffont) {
1254          _setDeffont(ControlFont.COMPATIBLE);
1255       }
1256 
1257       return _deffont;
1258    }
1259 
1260    package static class SafeCursor : Cursor {
1261       this(HCURSOR hcur) {
1262          super(hcur, false);
1263       }
1264 
1265       override void dispose() {
1266       }
1267 
1268       /*
1269          ~this() {
1270          super.dispose();
1271          }
1272        */
1273    }
1274 
1275    package static @property Cursor _defaultCursor() {
1276       static Cursor def = null;
1277 
1278       if (!def) {
1279          synchronized {
1280             if (!def) {
1281                def = new SafeCursor(LoadCursor(HINSTANCE.init, IDC_ARROW));
1282             }
1283          }
1284       }
1285 
1286       return def;
1287    }
1288 
1289    @property Rect displayRectangle() {
1290       return clientRectangle;
1291    }
1292 
1293    //protected void onDockChanged(EventArgs ea)
1294    protected void onHasLayoutChanged(EventArgs ea) {
1295       if (parent) {
1296          parent.alayout(this);
1297       }
1298 
1299       //dockChanged(this, ea);
1300       hasLayoutChanged(this, ea);
1301    }
1302 
1303    alias onDockChanged = onHasLayoutChanged;
1304 
1305    private final void _alreadyLayout() {
1306       throw new DflException("Control already has a layout");
1307    }
1308 
1309    @property DockStyle dock() {
1310       return sdock;
1311    }
1312 
1313    @property void dock(DockStyle ds) {
1314       if (ds == sdock) {
1315          return;
1316       }
1317 
1318       DockStyle _olddock = sdock;
1319       sdock = ds;
1320       /+
1321          anch = AnchorStyles.NONE; // Can't be set at the same time.
1322       +/
1323 
1324          if (DockStyle.NONE == ds) {
1325             if (DockStyle.NONE != _olddock) { // If it was even docking before; don't unset hasLayout for something else.
1326                hasLayout = false;
1327             }
1328          } else {
1329             // Ensure not replacing some other layout, but OK if replacing another dock.
1330             if (DockStyle.NONE == _olddock) {
1331                if (hasLayout) {
1332                   _alreadyLayout();
1333                }
1334             }
1335             hasLayout = true;
1336          }
1337 
1338       /+ // Called by hasLayout.
1339          if(isHandleCreated) {
1340             onDockChanged(EventArgs.empty);
1341          }
1342       +/
1343    }
1344 
1345    /// Get or set whether or not this control currently has its bounds managed. Fires onHasLayoutChanged as needed.
1346    final @property bool hasLayout() {
1347       if (cbits & CBits.HAS_LAYOUT) {
1348          return true;
1349       }
1350       return false;
1351    }
1352 
1353    final @property void hasLayout(bool byes) {
1354       //if(byes == hasLayout)
1355       // return; // No! setting this property again must trigger onHasLayoutChanged again.
1356 
1357       if (byes) {
1358          cbits |= CBits.HAS_LAYOUT;
1359       } else {
1360          cbits &= ~CBits.HAS_LAYOUT;
1361       }
1362 
1363       if (byes) { // No need if layout is removed.
1364          if (isHandleCreated) {
1365             onHasLayoutChanged(EventArgs.empty);
1366          }
1367       }
1368    }
1369 
1370    package final void _venabled(bool byes) {
1371       if (isHandleCreated) {
1372          EnableWindow(hwnd, byes);
1373          // Window events will update -wstyle-.
1374       } else {
1375          if (byes) {
1376             wstyle &= ~WS_DISABLED;
1377          } else {
1378             wstyle |= WS_DISABLED;
1379          }
1380       }
1381    }
1382 
1383    final @property void enabled(bool byes) {
1384       if (byes) {
1385          cbits |= CBits.ENABLED;
1386       } else {
1387          cbits &= ~CBits.ENABLED;
1388       }
1389 
1390       /+
1391          if(!byes) {
1392             _venabled(false);
1393          } else {
1394             if(!parent || parent.enabled) {
1395                _venabled(true);
1396             }
1397          }
1398 
1399       _propagateEnabledAmbience();
1400       +/
1401 
1402          _venabled(byes);
1403    }
1404 
1405    final @property bool enabled() {
1406       /*
1407          return IsWindowEnabled(hwnd) ? true : false;
1408        */
1409 
1410       return (wstyle & WS_DISABLED) == 0;
1411    }
1412 
1413    private void _propagateEnabledAmbience() {
1414       /*  Isn't working...
1415           if(cbits & CBits.FORM) {
1416           return;
1417           }
1418 
1419           bool en = enabled;
1420 
1421           void pa(Control pc) {
1422           foreach(Control ctrl; pc.ccollection) {
1423           if(ctrl.cbits & CBits.ENABLED) {
1424           _venabled(en);
1425 
1426           pa(ctrl);
1427           }
1428           }
1429           }
1430 
1431           pa(this);
1432        */
1433    }
1434 
1435    final void enable() {
1436       enabled = true;
1437    }
1438 
1439    final void disable() {
1440       enabled = false;
1441    }
1442 
1443    @property bool focused() {
1444       //return isHandleCreated && hwnd == GetFocus();
1445       return created && fromChildHandle(GetFocus()) is this;
1446    }
1447 
1448    @property void font(Font f) {
1449       if (wfont is f) {
1450          return;
1451       }
1452 
1453       wfont = f;
1454       if (isHandleCreated) {
1455          SendMessageA(hwnd, WM_SETFONT, cast(WPARAM) wfont.handle, MAKELPARAM(true,
1456                   0));
1457       }
1458       onFontChanged(EventArgs.empty);
1459 
1460       _propagateFontAmbience();
1461    }
1462 
1463    @property Font font() {
1464       if (!wfont) {
1465          if (parent) {
1466             return parent.font;
1467          }
1468          return defaultFont;
1469       }
1470       return wfont;
1471    }
1472 
1473    private void _propagateForeColorAmbience() {
1474       Color fc;
1475       fc = foreColor;
1476 
1477       void pa(Control pc) {
1478          foreach (Control ctrl; pc.ccollection) {
1479             if (Color.empty == ctrl.forec) { // If default.
1480                if (fc == ctrl.foreColor) { // If same default.
1481                   ctrl.onForeColorChanged(EventArgs.empty);
1482 
1483                   pa(ctrl); // Recursive.
1484                }
1485             }
1486          }
1487       }
1488 
1489       pa(this);
1490    }
1491 
1492    protected void onForeColorChanged(EventArgs ea) {
1493       debug (EVENT_PRINT) {
1494          cprintf("{ Event: onForeColorChanged - Control %.*s }\n", name);
1495       }
1496 
1497       foreColorChanged(this, ea);
1498    }
1499 
1500    @property void foreColor(Color c) {
1501       if (c == forec) {
1502          return;
1503       }
1504 
1505       forec = c;
1506       onForeColorChanged(EventArgs.empty);
1507 
1508       _propagateForeColorAmbience();
1509       if (isHandleCreated) {
1510          invalidate(true); // Redraw!
1511       }
1512    }
1513 
1514    @property Color foreColor() {
1515       if (Color.empty == forec) {
1516          if (parent) {
1517             return parent.foreColor;
1518          }
1519          return defaultForeColor;
1520       }
1521       return forec;
1522    }
1523 
1524    // Doesn't cause a ControlCollection to be constructed so
1525    // it could improve performance when walking through children.
1526    final @property bool hasChildren() {
1527       //return isHandleCreated && GetWindow(hwnd, GW_CHILD) != HWND.init;
1528 
1529       if (isHandleCreated) {
1530          return GetWindow(hwnd, GW_CHILD) != HWND.init;
1531       } else {
1532          return ccollection.children.length != 0;
1533       }
1534    }
1535 
1536    final @property void height(int h) {
1537       /*
1538          RECT rect;
1539          GetWindowRect(hwnd, &rect);
1540          SetWindowPos(hwnd, HWND.init, 0, 0, rect.right - rect.left, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
1541        */
1542 
1543       setBoundsCore(0, 0, 0, h, BoundsSpecified.HEIGHT);
1544    }
1545 
1546    final @property int height() {
1547       return wrect.height;
1548    }
1549 
1550    final @property bool isHandleCreated() {
1551       return hwnd != HWND.init;
1552    }
1553 
1554    final @property void left(int l) {
1555       /*
1556          RECT rect;
1557          GetWindowRect(hwnd, &rect);
1558          SetWindowPos(hwnd, HWND.init, l, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
1559        */
1560 
1561       setBoundsCore(l, 0, 0, 0, BoundsSpecified.X);
1562    }
1563 
1564    final @property int left() {
1565       return wrect.x;
1566    }
1567 
1568    /// Property: get or set the X and Y location of the control.
1569    final @property void location(Point pt) {
1570       /*
1571          SetWindowPos(hwnd, HWND.init, pt.x, pt.y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
1572        */
1573 
1574       setBoundsCore(pt.x, pt.y, 0, 0, BoundsSpecified.LOCATION);
1575    }
1576 
1577    final @property Point location() {
1578       return wrect.location;
1579    }
1580 
1581    /// Currently depressed modifier keys.
1582    static @property Keys modifierKeys() {
1583       // Is there a better way to do this?
1584       Keys ks = Keys.NONE;
1585       if (GetAsyncKeyState(VK_SHIFT) & 0x8000) {
1586          ks |= Keys.SHIFT;
1587       }
1588       if (GetAsyncKeyState(VK_MENU) & 0x8000) {
1589          ks |= Keys.ALT;
1590       }
1591       if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
1592          ks |= Keys.CONTROL;
1593       }
1594       return ks;
1595    }
1596 
1597    /// Currently depressed mouse buttons.
1598    static @property MouseButtons mouseButtons() {
1599       MouseButtons result;
1600 
1601       result = MouseButtons.NONE;
1602       if (GetSystemMetrics(SM_SWAPBUTTON)) {
1603          if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) {
1604             result |= MouseButtons.RIGHT; // Swapped.
1605          }
1606          if (GetAsyncKeyState(VK_RBUTTON) & 0x8000) {
1607             result |= MouseButtons.LEFT; // Swapped.
1608          }
1609       } else {
1610          if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) {
1611             result |= MouseButtons.LEFT;
1612          }
1613          if (GetAsyncKeyState(VK_RBUTTON) & 0x8000) {
1614             result |= MouseButtons.RIGHT;
1615          }
1616       }
1617       if (GetAsyncKeyState(VK_MBUTTON) & 0x8000) {
1618          result |= MouseButtons.MIDDLE;
1619       }
1620 
1621       return result;
1622    }
1623 
1624    static @property Point mousePosition() {
1625       Point pt;
1626       GetCursorPos(&pt.point);
1627       return pt;
1628    }
1629 
1630    /// Property: get or set the name of this control used in code.
1631    final @property void name(Dstring txt) {
1632       _ctrlname = txt;
1633    }
1634 
1635    final @property Dstring name() {
1636       return _ctrlname;
1637    }
1638 
1639    protected void onParentChanged(EventArgs ea) {
1640       debug (EVENT_PRINT) {
1641          cprintf("{ Event: onParentChanged - Control %.*s }\n", name);
1642       }
1643 
1644       parentChanged(this, ea);
1645    }
1646 
1647    /*
1648 
1649    // ea is the new parent.
1650    protected void onParentChanging(ControlEventArgs ea) {
1651    }
1652     */
1653 
1654    final Form findForm() {
1655       Form f;
1656       Control c;
1657 
1658       c = this;
1659       for (;;) {
1660          f = cast(Form) c;
1661          if (f) {
1662             break;
1663          }
1664          c = c.parent;
1665          if (!c) {
1666             return null;
1667          }
1668       }
1669       return f;
1670    }
1671 
1672    final @property void parent(Control c) {
1673       if (c is wparent) {
1674          return;
1675       }
1676 
1677       if (!(_style() & WS_CHILD) || (_exStyle() & WS_EX_MDICHILD)) {
1678          throw new DflException("Cannot add a top level control to a control");
1679       }
1680 
1681       //scope ControlEventArgs pcea = new ControlEventArgs(c);
1682       //onParentChanging(pcea);
1683 
1684       Control oldparent;
1685       _FixAmbientOld oldinfo;
1686 
1687       oldparent = wparent;
1688 
1689       if (oldparent) {
1690          oldinfo.set(oldparent);
1691 
1692          if (!oldparent.isHandleCreated) {
1693             int oi = oldparent.controls.indexOf(this);
1694             //assert(-1 != oi); // Fails if the parent (and thus this) handles destroyed.
1695             if (-1 != oi) {
1696                oldparent.controls._removeNotCreated(oi);
1697             }
1698          }
1699       } else {
1700          oldinfo.set(this);
1701       }
1702 
1703       scope ControlEventArgs cea = new ControlEventArgs(this);
1704 
1705       if (c) {
1706          wparent = c;
1707 
1708          // I want the destroy notification. Don't need it anymore.
1709          //c._exStyle(c._exStyle() & ~WS_EX_NOPARENTNOTIFY);
1710 
1711          if (c.isHandleCreated) {
1712             cbits &= ~CBits.NEED_INIT_LAYOUT;
1713 
1714             //if(created)
1715             if (isHandleCreated) {
1716                SetParent(hwnd, c.hwnd);
1717             } else {
1718                // If the parent is created, create me!
1719                createControl();
1720             }
1721 
1722             onParentChanged(EventArgs.empty);
1723             if (oldparent) {
1724                oldparent._ctrlremoved(cea);
1725             }
1726             c._ctrladded(cea);
1727             _fixAmbient(&oldinfo);
1728 
1729             initLayout();
1730          } else {
1731             // If the parent exists and isn't created, need to add
1732             // -this- to its children array.
1733             c.ccollection.children ~= this;
1734 
1735             onParentChanged(EventArgs.empty);
1736             if (oldparent) {
1737                oldparent._ctrlremoved(cea);
1738             }
1739             c._ctrladded(cea);
1740             _fixAmbient(&oldinfo);
1741 
1742             cbits |= CBits.NEED_INIT_LAYOUT;
1743          }
1744       } else {
1745          assert(c is null);
1746          //wparent = c;
1747          wparent = null;
1748 
1749          if (isHandleCreated) {
1750             SetParent(hwnd, HWND.init);
1751          }
1752 
1753          onParentChanged(EventArgs.empty);
1754          assert(oldparent !is null);
1755          oldparent._ctrlremoved(cea);
1756          _fixAmbient(&oldinfo);
1757       }
1758    }
1759 
1760    final @property Control parent() {
1761       return wparent;
1762    }
1763 
1764    private final Control _fetchParent() {
1765       HWND hwParent = GetParent(hwnd);
1766       return fromHandle(hwParent);
1767    }
1768 
1769    // TODO: check implementation.
1770    private static HRGN dupHrgn(HRGN hrgn) {
1771       HRGN rdup = CreateRectRgn(0, 0, 1, 1);
1772       CombineRgn(rdup, hrgn, HRGN.init, RGN_COPY);
1773       return rdup;
1774    }
1775 
1776    final @property void region(Region rgn) {
1777       if (isHandleCreated) {
1778          // Need to make a copy of the region.
1779          SetWindowRgn(hwnd, dupHrgn(rgn.handle), true);
1780       }
1781 
1782       wregion = rgn;
1783    }
1784 
1785    final @property Region region() {
1786       return wregion;
1787    }
1788 
1789    private final Region _fetchRegion() {
1790       HRGN hrgn = CreateRectRgn(0, 0, 1, 1);
1791       GetWindowRgn(hwnd, hrgn);
1792       return new Region(hrgn); // Owned because GetWindowRgn() gives a copy.
1793    }
1794 
1795    final @property int right() {
1796       return wrect.right;
1797    }
1798 
1799    /+
1800       @property void rightToLeft(bool byes) {
1801          LONG wl = _exStyle();
1802          if(byes) {
1803             wl |= WS_EX_RTLREADING;
1804          } else {
1805             wl &= ~WS_EX_RTLREADING;
1806          }
1807          _exStyle(wl);
1808       }
1809 
1810 
1811    @property bool rightToLeft() {
1812       return (_exStyle() & WS_EX_RTLREADING) != 0;
1813    }
1814    +/
1815 
1816       deprecated @property void rightToLeft(bool byes) {
1817          rightToLeft = byes ? RightToLeft.YES : RightToLeft.NO;
1818       }
1819 
1820    package final void _fixRtol(RightToLeft val) {
1821       switch (val) {
1822          case RightToLeft.INHERIT:
1823             if (parent && parent.rightToLeft == RightToLeft.YES) {
1824                goto case RightToLeft.YES;
1825             }
1826             goto case RightToLeft.NO;
1827 
1828          case RightToLeft.YES:
1829             _exStyle(_exStyle() | WS_EX_RTLREADING);
1830             break;
1831 
1832          case RightToLeft.NO:
1833             _exStyle(_exStyle() & ~WS_EX_RTLREADING);
1834             break;
1835 
1836          default:
1837             assert(0);
1838       }
1839 
1840       //invalidate(true); // Children too in case they inherit.
1841       invalidate(false); // Since children are enumerated.
1842    }
1843 
1844    private void _propagateRtolAmbience() {
1845       RightToLeft rl;
1846       rl = rightToLeft;
1847 
1848       void pa(Control pc) {
1849          if (RightToLeft.INHERIT == pc.rtol) {
1850             //pc._fixRtol(rtol);
1851             pc._fixRtol(rl); // Set the specific parent value so it doesn't have to look up the chain.
1852 
1853             foreach (Control ctrl; pc.ccollection) {
1854                ctrl.onRightToLeftChanged(EventArgs.empty);
1855 
1856                pa(ctrl);
1857             }
1858          }
1859       }
1860 
1861       pa(this);
1862    }
1863 
1864    @property void rightToLeft(RightToLeft val) {
1865       if (rtol != val) {
1866          rtol = val;
1867          onRightToLeftChanged(EventArgs.empty);
1868          _propagateRtolAmbience(); // Also sets the class style and invalidates.
1869       }
1870    }
1871 
1872    // Returns YES or NO; if inherited, returns parent's setting.
1873    @property RightToLeft rightToLeft() {
1874       if (RightToLeft.INHERIT == rtol) {
1875          return parent ? parent.rightToLeft : RightToLeft.NO;
1876       }
1877       return rtol;
1878    }
1879 
1880    package struct _FixAmbientOld {
1881       Font font;
1882       Cursor cursor;
1883       Color backColor;
1884       Color foreColor;
1885       RightToLeft rightToLeft;
1886       //CBits cbits;
1887       bool enabled;
1888 
1889       void set(Control ctrl) {
1890          if (ctrl) {
1891             font = ctrl.font;
1892             cursor = ctrl.cursor;
1893             backColor = ctrl.backColor;
1894             foreColor = ctrl.foreColor;
1895             rightToLeft = ctrl.rightToLeft;
1896             //cbits = ctrl.cbits;
1897             enabled = ctrl.enabled;
1898          }
1899          /+else {
1900             font = null;
1901             cursor = null;
1902             backColor = Color.empty;
1903             foreColor = Color.empty;
1904             rightToLeft = RightToLeft.INHERIT;
1905             //cbits = CBits.init;
1906             enabled = true;
1907          }+/
1908       }
1909    }
1910 
1911    // This is called when the inherited ambience changes.
1912    package final void _fixAmbient(_FixAmbientOld* oldinfo) {
1913       // Note: exception will screw things up.
1914 
1915       _FixAmbientOld newinfo;
1916       if (parent) {
1917          newinfo.set(parent);
1918       } else {
1919          newinfo.set(this);
1920       }
1921 
1922       if (RightToLeft.INHERIT == rtol) {
1923          if (newinfo.rightToLeft !is oldinfo.rightToLeft) {
1924             onRightToLeftChanged(EventArgs.empty);
1925             _propagateRtolAmbience();
1926          }
1927       }
1928 
1929       if (Color.empty == backc) {
1930          if (newinfo.backColor !is oldinfo.backColor) {
1931             onBackColorChanged(EventArgs.empty);
1932             _propagateBackColorAmbience();
1933          }
1934       }
1935 
1936       if (Color.empty == forec) {
1937          if (newinfo.foreColor !is oldinfo.foreColor) {
1938             onForeColorChanged(EventArgs.empty);
1939             _propagateForeColorAmbience();
1940          }
1941       }
1942 
1943       if (!wfont) {
1944          if (newinfo.font !is oldinfo.font) {
1945             onFontChanged(EventArgs.empty);
1946             _propagateFontAmbience();
1947          }
1948       }
1949 
1950       if (!wcurs) {
1951          if (newinfo.cursor !is oldinfo.cursor) {
1952             onCursorChanged(EventArgs.empty);
1953             _propagateCursorAmbience();
1954          }
1955       }
1956 
1957       /+
1958          if(newinfo.enabled != oldinfo.enabled) {
1959             if(cbits & CBits.ENABLED) {
1960                _venabled(newinfo.enabled);
1961                _propagateEnabledAmbience();
1962             }
1963          }
1964       +/
1965    }
1966 
1967    /+
1968       package final void _fixAmbientChildren() {
1969          foreach(Control ctrl; ccollection.children) {
1970             ctrl._fixAmbient();
1971          }
1972       }
1973    +/
1974 
1975       final @property void size(Size sz) {
1976          /*
1977             SetWindowPos(hwnd, HWND.init, 0, 0, sz.width, sz.height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
1978           */
1979 
1980          setBoundsCore(0, 0, sz.width, sz.height, BoundsSpecified.SIZE);
1981       }
1982 
1983    final @property Size size() {
1984       return wrect.size; // struct Size, not sizeof.
1985    }
1986 
1987    /+
1988       final @property void tabIndex(int i) {
1989          // TODO: ?
1990       }
1991 
1992 
1993    final @property int tabIndex() {
1994       return tabidx;
1995    }
1996    +/
1997 
1998       // Use -zIndex- instead.
1999       // -tabIndex- may return different values in the future.
2000       deprecated int tabIndex() {
2001          return zIndex;
2002       }
2003 
2004    final @property int zIndex()
2005       out (result) {
2006          assert(result >= 0);
2007       }
2008    body {
2009       if (!parent) {
2010          return 0;
2011       }
2012 
2013       if (isHandleCreated) {
2014          GetZIndex gzi;
2015          gzi.find = this;
2016          int index;
2017          int tmp;
2018 
2019          BOOL getZIndexCallback(HWND hWnd) {
2020             if (hWnd is hwnd) {
2021                index = tmp;
2022                return FALSE; // Stop, found it.
2023             }
2024 
2025             auto ctrl = Control.fromHandle(hWnd);
2026             if (ctrl && ctrl.parent is parent) {
2027                tmp++;
2028             }
2029 
2030             return TRUE; // Keep looking.
2031          }
2032 
2033          enumChildWindows(parent.hwnd, &getZIndexCallback);
2034          return index;
2035       } else {
2036          return parent.controls.indexOf(this);
2037       }
2038    }
2039 
2040    // True if control can be tabbed to.
2041    final @property void tabStop(bool byes) {
2042       LONG wl = _style();
2043       if (byes) {
2044          wl |= WS_TABSTOP;
2045       } else {
2046          wl &= ~WS_TABSTOP;
2047       }
2048       _style(wl);
2049    }
2050 
2051    final @property bool tabStop() {
2052       return (_style() & WS_TABSTOP) != 0;
2053    }
2054 
2055    /// Property: get or set additional data tagged onto the control.
2056    final @property void tag(Object o) {
2057       otag = o;
2058    }
2059 
2060    final @property Object tag() {
2061       return otag;
2062    }
2063 
2064    private final Dstring _fetchText() {
2065       return dfl.internal.utf.getWindowText(hwnd);
2066    }
2067 
2068    @property void text(Dstring txt) {
2069       if (isHandleCreated) {
2070          if (ctrlStyle & ControlStyles.CACHE_TEXT) {
2071             //if(wtext == txt)
2072             // return;
2073             wtext = txt;
2074          }
2075 
2076          dfl.internal.utf.setWindowText(hwnd, txt);
2077       } else {
2078          wtext = txt;
2079       }
2080    }
2081 
2082    @property Dstring text() {
2083       if (isHandleCreated) {
2084          if (ctrlStyle & ControlStyles.CACHE_TEXT) {
2085             return wtext;
2086          }
2087 
2088          return _fetchText();
2089       } else {
2090          return wtext;
2091       }
2092    }
2093 
2094    final @property void top(int t) {
2095       setBoundsCore(0, t, 0, 0, BoundsSpecified.Y);
2096    }
2097 
2098    final @property int top() {
2099       return wrect.y;
2100    }
2101 
2102    /// Returns the topmost Control related to this control.
2103    // Returns the owner control that has no parent.
2104    // Returns this Control if no owner ?
2105    final @property Control topLevelControl() {
2106       if (isHandleCreated) {
2107          HWND hwCurrent = hwnd;
2108          HWND hwParent;
2109 
2110          for (;;) {
2111             hwParent = GetParent(hwCurrent); // This gets the top-level one, whereas the previous code jumped owners.
2112             if (!hwParent) {
2113                break;
2114             }
2115 
2116             hwCurrent = hwParent;
2117          }
2118 
2119          return fromHandle(hwCurrent);
2120       } else {
2121          Control ctrl;
2122          ctrl = this;
2123          while (ctrl.parent) {
2124             ctrl = ctrl.parent; // This shouldn't jump owners..
2125          }
2126          return ctrl;
2127       }
2128    }
2129 
2130    /+
2131       private DWORD _fetchVisible() {
2132          //return IsWindowVisible(hwnd) != FALSE;
2133          wstyle = GetWindowLongA(hwnd, GWL_STYLE);
2134          return wstyle & WS_VISIBLE;
2135       }
2136    +/
2137 
2138       final @property void visible(bool byes) {
2139          setVisibleCore(byes);
2140       }
2141 
2142    final @property bool visible() {
2143       //if(isHandleCreated)
2144       // wstyle = GetWindowLongA(hwnd, GWL_STYLE); // ...
2145       //return (wstyle & WS_VISIBLE) != 0;
2146       return (cbits & CBits.VISIBLE) != 0;
2147    }
2148 
2149    final @property void width(int w) {
2150       setBoundsCore(0, 0, w, 0, BoundsSpecified.WIDTH);
2151    }
2152 
2153    final @property int width() {
2154       return wrect.width;
2155    }
2156 
2157    final void sendToBack() {
2158       if (!isHandleCreated) {
2159          if (parent) {
2160             parent.ccollection._simple_front(this);
2161          }
2162          return;
2163       }
2164 
2165       SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2166    }
2167 
2168    final void bringToFront() {
2169       if (!isHandleCreated) {
2170          if (parent) {
2171             parent.ccollection._simple_back(this);
2172          }
2173          return;
2174       }
2175 
2176       SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2177       //BringWindowToTop(hwnd);
2178    }
2179 
2180    deprecated alias zIndexUp = bringUpOne;
2181 
2182    // Move up one.
2183    final void bringUpOne() {
2184       if (!isHandleCreated) {
2185          if (parent) {
2186             parent.ccollection._simple_front_one(this);
2187          }
2188          return;
2189       }
2190 
2191       HWND hw;
2192 
2193       // Need to move back twice because the previous one already precedes this one.
2194       hw = GetWindow(hwnd, GW_HWNDPREV);
2195       if (!hw) {
2196          hw = HWND_TOP;
2197       } else {
2198          hw = GetWindow(hw, GW_HWNDPREV);
2199          if (!hw) {
2200             hw = HWND_TOP;
2201          }
2202       }
2203 
2204       SetWindowPos(hwnd, hw, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2205    }
2206 
2207    deprecated alias zIndexDown = sendBackOne;
2208 
2209    // Move back one.
2210    final void sendBackOne() {
2211       if (!isHandleCreated) {
2212          if (parent) {
2213             parent.ccollection._simple_back_one(this);
2214          }
2215          return;
2216       }
2217 
2218       HWND hw;
2219 
2220       hw = GetWindow(hwnd, GW_HWNDNEXT);
2221       if (!hw) {
2222          hw = HWND_BOTTOM;
2223       }
2224 
2225       SetWindowPos(hwnd, hw, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2226    }
2227 
2228    // Note: true if no children, even if this not created.
2229    package final @property bool areChildrenCreated() {
2230       return !ccollection.children.length;
2231    }
2232 
2233    package final void createChildren() {
2234       assert(isHandleCreated);
2235 
2236       Control[] ctrls;
2237       ctrls = ccollection.children;
2238       ccollection.children = null;
2239 
2240       foreach (Control ctrl; ctrls) {
2241          assert(ctrl.parent is this);
2242          assert(!(ctrl is null));
2243          assert(ctrl);
2244          ctrl.createControl();
2245       }
2246    }
2247 
2248    // Force creation of the window and its child controls.
2249    final void createControl() {
2250       createHandle();
2251 
2252       // Called in WM_CREATE also.
2253       createChildren();
2254    }
2255 
2256    /// Returns a new Graphics object for this control, creating the control handle if necessary.
2257    final Graphics createGraphics() {
2258       HDC hdc = GetDC(handle); // Create handle as necessary.
2259       SetTextColor(hdc, foreColor.toRgb());
2260       return new CommonGraphics(hwnd, hdc);
2261    }
2262 
2263    version (DFL_NO_DRAG_DROP) {
2264    } else {
2265       private static class DropTarget : DflComObject, IDropTarget {
2266          this(Control ctrl) {
2267             this.ctrl = ctrl;
2268          }
2269 
2270          ~this() {
2271             if (dataObj) {
2272                GC.removeRoot(cast(void*) dataObj);
2273                destroy(dataObj);
2274             }
2275          }
2276 
2277          extern (Windows):
2278             override HRESULT QueryInterface(IID* riid, void** ppv) {
2279                if (*riid == IID_IDropTarget) {
2280                   *ppv = cast(void*) cast(IDropTarget) this;
2281                   AddRef();
2282                   return S_OK;
2283                } else if (*riid == IID_IUnknown) {
2284                   *ppv = cast(void*) cast(IUnknown) this;
2285                   AddRef();
2286                   return S_OK;
2287                } else {
2288                   *ppv = null;
2289                   return E_NOINTERFACE;
2290                }
2291             }
2292 
2293          HRESULT DragEnter(IDataObject pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) {
2294             HRESULT result;
2295 
2296             try {
2297                //dataObj = new ComToDdataObject(pDataObject);
2298                ensureDataObj(pDataObject);
2299 
2300                scope DragEventArgs ea = new DragEventArgs(dataObj,
2301                      cast(int) grfKeyState, pt.x, pt.y,
2302                      cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE);
2303                ctrl.onDragEnter(ea);
2304                *pdwEffect = ea.effect;
2305 
2306                result = S_OK;
2307             }
2308             catch (DThrowable e) {
2309                Application.onThreadException(e);
2310 
2311                result = E_UNEXPECTED;
2312             }
2313 
2314             return result;
2315          }
2316 
2317          HRESULT DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) {
2318             HRESULT result;
2319 
2320             try {
2321                assert(dataObj !is null);
2322 
2323                scope DragEventArgs ea = new DragEventArgs(dataObj,
2324                      cast(int) grfKeyState, pt.x, pt.y,
2325                      cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ?
2326                ctrl.onDragOver(ea);
2327                *pdwEffect = ea.effect;
2328 
2329                result = S_OK;
2330             }
2331             catch (DThrowable e) {
2332                Application.onThreadException(e);
2333 
2334                result = E_UNEXPECTED;
2335             }
2336 
2337             return result;
2338          }
2339 
2340          HRESULT DragLeave() {
2341             HRESULT result;
2342 
2343             try {
2344                ctrl.onDragLeave(EventArgs.empty);
2345 
2346                killDataObj();
2347 
2348                result = S_OK;
2349             }
2350             catch (DThrowable e) {
2351                Application.onThreadException(e);
2352 
2353                result = E_UNEXPECTED;
2354             }
2355 
2356             return result;
2357          }
2358 
2359          HRESULT Drop(IDataObject pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) {
2360             HRESULT result;
2361 
2362             try {
2363                //assert(dataObj !is null);
2364                ensureDataObj(pDataObject);
2365 
2366                scope DragEventArgs ea = new DragEventArgs(dataObj,
2367                      cast(int) grfKeyState, pt.x, pt.y,
2368                      cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ?
2369                ctrl.onDragDrop(ea);
2370                *pdwEffect = ea.effect;
2371 
2372                result = S_OK;
2373             }
2374             catch (DThrowable e) {
2375                Application.onThreadException(e);
2376 
2377                result = E_UNEXPECTED;
2378             }
2379 
2380             return result;
2381          }
2382 
2383          private:
2384 
2385          Control ctrl;
2386          //dfl.data.IDataObject dataObj;
2387          ComToDdataObject dataObj;
2388 
2389          void ensureDataObj(IDataObject pDataObject) {
2390             if (!dataObj) {
2391                dataObj = new ComToDdataObject(pDataObject);
2392                GC.addRoot(cast(void*) dataObj);
2393             } else if (!dataObj.isSameDataObject(pDataObject)) {
2394                GC.removeRoot(cast(void*) dataObj);
2395                dataObj = new ComToDdataObject(pDataObject);
2396                GC.addRoot(cast(void*) dataObj);
2397             }
2398          }
2399 
2400          void killDataObj() {
2401             // Can't do this because the COM object might still need to be released elsewhere.
2402             //delete dataObj;
2403             //dataObj = null;
2404          }
2405       }
2406 
2407       protected void onDragLeave(EventArgs ea) {
2408          dragLeave(this, ea);
2409       }
2410 
2411       protected void onDragEnter(DragEventArgs ea) {
2412          dragEnter(this, ea);
2413       }
2414 
2415       protected void onDragOver(DragEventArgs ea) {
2416          dragOver(this, ea);
2417       }
2418 
2419       protected void onDragDrop(DragEventArgs ea) {
2420          dragDrop(this, ea);
2421       }
2422 
2423       private static class DropSource : DflComObject, IDropSource {
2424          this(Control ctrl) {
2425             this.ctrl = ctrl;
2426             mbtns = Control.mouseButtons;
2427          }
2428 
2429          extern (Windows):
2430             override HRESULT QueryInterface(IID* riid, void** ppv) {
2431                if (*riid == IID_IDropSource) {
2432                   *ppv = cast(void*) cast(IDropSource) this;
2433                   AddRef();
2434                   return S_OK;
2435                } else if (*riid == IID_IUnknown) {
2436                   *ppv = cast(void*) cast(IUnknown) this;
2437                   AddRef();
2438                   return S_OK;
2439                } else {
2440                   *ppv = null;
2441                   return E_NOINTERFACE;
2442                }
2443             }
2444 
2445          HRESULT QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) {
2446             HRESULT result;
2447 
2448             try {
2449                DragAction act;
2450 
2451                if (fEscapePressed) {
2452                   act = cast(DragAction) DragAction.CANCEL;
2453                } else {
2454                   if (mbtns & MouseButtons.LEFT) {
2455                      if (!(grfKeyState & MK_LBUTTON)) {
2456                         act = cast(DragAction) DragAction.DROP;
2457                         goto qdoit;
2458                      }
2459                   } else {
2460                      if (grfKeyState & MK_LBUTTON) {
2461                         act = cast(DragAction) DragAction.CANCEL;
2462                         goto qdoit;
2463                      }
2464                   }
2465                   if (mbtns & MouseButtons.RIGHT) {
2466                      if (!(grfKeyState & MK_RBUTTON)) {
2467                         act = cast(DragAction) DragAction.DROP;
2468                         goto qdoit;
2469                      }
2470                   } else {
2471                      if (grfKeyState & MK_RBUTTON) {
2472                         act = cast(DragAction) DragAction.CANCEL;
2473                         goto qdoit;
2474                      }
2475                   }
2476                   if (mbtns & MouseButtons.MIDDLE) {
2477                      if (!(grfKeyState & MK_MBUTTON)) {
2478                         act = cast(DragAction) DragAction.DROP;
2479                         goto qdoit;
2480                      }
2481                   } else {
2482                      if (grfKeyState & MK_MBUTTON) {
2483                         act = cast(DragAction) DragAction.CANCEL;
2484                         goto qdoit;
2485                      }
2486                   }
2487 
2488                   act = cast(DragAction) DragAction.CONTINUE;
2489                }
2490 
2491 qdoit: scope QueryContinueDragEventArgs ea = new QueryContinueDragEventArgs(
2492              cast(int) grfKeyState, fEscapePressed != FALSE, act); // ?
2493        ctrl.onQueryContinueDrag(ea);
2494 
2495        result = cast(HRESULT) ea.action;
2496             }
2497             catch (DThrowable e) {
2498                Application.onThreadException(e);
2499 
2500                result = E_UNEXPECTED;
2501             }
2502 
2503             return result;
2504          }
2505 
2506          HRESULT GiveFeedback(DWORD dwEffect) {
2507             HRESULT result;
2508 
2509             try {
2510                scope GiveFeedbackEventArgs ea = new GiveFeedbackEventArgs(
2511                      cast(DragDropEffects) dwEffect, true);
2512                ctrl.onGiveFeedback(ea);
2513 
2514                result = ea.useDefaultCursors ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK;
2515             }
2516             catch (DThrowable e) {
2517                Application.onThreadException(e);
2518 
2519                result = E_UNEXPECTED;
2520             }
2521 
2522             return result;
2523          }
2524 
2525          private:
2526          Control ctrl;
2527          MouseButtons mbtns;
2528       }
2529 
2530       protected void onQueryContinueDrag(QueryContinueDragEventArgs ea) {
2531          queryContinueDrag(this, ea);
2532       }
2533 
2534       protected void onGiveFeedback(GiveFeedbackEventArgs ea) {
2535          giveFeedback(this, ea);
2536       }
2537 
2538       /// Perform a drag/drop operation.
2539       final DragDropEffects doDragDrop(dfl.data.IDataObject dataObj, DragDropEffects allowedEffects) {
2540          Object foo = cast(Object) dataObj; // Hold a reference to the Object...
2541 
2542          DWORD effect;
2543          DropSource dropsrc;
2544          IDataObject dropdata;
2545 
2546          dropsrc = new DropSource(this);
2547          dropdata = new DtoComDataObject(dataObj);
2548 
2549          // dataObj seems to be killed too early.
2550          switch (DoDragDrop(dropdata, dropsrc, cast(DWORD) allowedEffects, &effect)) {
2551             case DRAGDROP_S_DROP: // All good.
2552                break;
2553 
2554             case DRAGDROP_S_CANCEL:
2555                return DragDropEffects.NONE; // ?
2556 
2557             default:
2558                throw new DflException("Unable to complete drag-drop operation");
2559          }
2560 
2561          return cast(DragDropEffects) effect;
2562       }
2563 
2564       final DragDropEffects doDragDrop(Data obj, DragDropEffects allowedEffects) {
2565          dfl.data.IDataObject dd;
2566          dd = new DataObject;
2567          dd.setData(obj);
2568          return doDragDrop(dd, allowedEffects);
2569       }
2570    }
2571 
2572    override Dequ opEquals(Object o) {
2573       Control ctrl = cast(Control) o;
2574       if (!ctrl) {
2575          return 0; // Not equal.
2576       }
2577       return opEquals(ctrl);
2578    }
2579 
2580    Dequ opEquals(Control ctrl) {
2581       if (!isHandleCreated) {
2582          return super.opEquals(ctrl);
2583       }
2584       return hwnd == ctrl.hwnd;
2585    }
2586 
2587    override int opCmp(Object o) {
2588       Control ctrl = cast(Control) o;
2589       if (!ctrl) {
2590          return -1;
2591       }
2592       return opCmp(ctrl);
2593    }
2594 
2595    int opCmp(Control ctrl) {
2596       if (!isHandleCreated || hwnd != ctrl.hwnd) {
2597          return super.opCmp(ctrl);
2598       }
2599       return 0;
2600    }
2601 
2602    final bool focus() {
2603       return SetFocus(hwnd) != HWND.init;
2604    }
2605 
2606    /// Returns the Control instance from one of its window handles, or null if none.
2607    // Finds controls that own more than one handle.
2608    // A combo box has several HWNDs, this would return the
2609    // correct combo box control if any of those handles are
2610    // provided.
2611    static Control fromChildHandle(HWND hwChild) {
2612       Control result;
2613       for (;;) {
2614          if (!hwChild) {
2615             return null;
2616          }
2617 
2618          result = fromHandle(hwChild);
2619          if (result) {
2620             return result;
2621          }
2622 
2623          hwChild = GetParent(hwChild);
2624       }
2625    }
2626 
2627    /// Returns the Control instance from its window handle, or null if none.
2628    static Control fromHandle(HWND hw) {
2629       return Application.lookupHwnd(hw);
2630    }
2631 
2632    final Control getChildAtPoint(Point pt) {
2633       HWND hwChild;
2634       hwChild = ChildWindowFromPoint(hwnd, pt.point);
2635       if (!hwChild) {
2636          return null;
2637       }
2638       return fromChildHandle(hwChild);
2639    }
2640 
2641    final void hide() {
2642       setVisibleCore(false);
2643    }
2644 
2645    final void show() {
2646       /*
2647          ShowWindow(hwnd, SW_SHOW);
2648          doShow();
2649        */
2650 
2651       setVisibleCore(true);
2652    }
2653 
2654    package final void redrawEntire() {
2655       if (hwnd) {
2656          SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0,
2657                SWP_FRAMECHANGED | SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
2658       }
2659    }
2660 
2661    package final void recalcEntire() {
2662       if (hwnd) {
2663          SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0,
2664                SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
2665       }
2666    }
2667 
2668    final void invalidate() {
2669       if (!hwnd) {
2670          return;
2671       }
2672 
2673       RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN);
2674    }
2675 
2676    final void invalidate(bool andChildren) {
2677       if (!hwnd) {
2678          return;
2679       }
2680 
2681       RedrawWindow(hwnd, null, HRGN.init,
2682             RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN));
2683    }
2684 
2685    final void invalidate(Rect r) {
2686       if (!hwnd) {
2687          return;
2688       }
2689 
2690       RECT rect;
2691       r.getRect(&rect);
2692 
2693       RedrawWindow(hwnd, &rect, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN);
2694    }
2695 
2696    final void invalidate(Rect r, bool andChildren) {
2697       if (!hwnd) {
2698          return;
2699       }
2700 
2701       RECT rect;
2702       r.getRect(&rect);
2703 
2704       RedrawWindow(hwnd, &rect, HRGN.init,
2705             RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN));
2706    }
2707 
2708    final void invalidate(Region rgn) {
2709       if (!hwnd) {
2710          return;
2711       }
2712 
2713       RedrawWindow(hwnd, null, rgn.handle, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN);
2714    }
2715 
2716    final void invalidate(Region rgn, bool andChildren) {
2717       if (!hwnd) {
2718          return;
2719       }
2720 
2721       RedrawWindow(hwnd, null, rgn.handle,
2722             RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN));
2723    }
2724 
2725    // Redraws the entire control, including nonclient area.
2726    final void redraw() {
2727       if (!hwnd) {
2728          return;
2729       }
2730 
2731       RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);
2732    }
2733 
2734    /// Returns true if the window does not belong to the current thread.
2735    @property bool invokeRequired() {
2736       DWORD tid = GetWindowThreadProcessId(hwnd, null);
2737       return tid != GetCurrentThreadId();
2738    }
2739 
2740    private static void badInvokeHandle() {
2741       //throw new DflException("Must invoke after creating handle");
2742       throw new DflException("Must invoke with created handle");
2743    }
2744 
2745    /// Synchronously calls a delegate in this Control's thread. This function is thread safe and exceptions are propagated to the caller.
2746    // Exceptions are propagated back to the caller of invoke().
2747    final Object invoke(Object delegate(Object[]) dg, Object[] args...) {
2748       if (!hwnd) {
2749          badInvokeHandle();
2750       }
2751 
2752       InvokeData inv;
2753       inv.dg = dg;
2754       inv.args = args;
2755 
2756       if (LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE, cast(LRESULT)&inv)) {
2757          throw new DflException("Invoke failure");
2758       }
2759       if (inv.exception) {
2760          throw inv.exception;
2761       }
2762 
2763       return inv.result;
2764    }
2765 
2766    final void invoke(void delegate() dg) {
2767       if (!hwnd) {
2768          badInvokeHandle();
2769       }
2770 
2771       InvokeSimpleData inv;
2772       inv.dg = dg;
2773 
2774       if (LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl,
2775                WPARAM_DFL_INVOKE_SIMPLE, cast(LRESULT)&inv)) {
2776          throw new DflException("Invoke failure");
2777       }
2778       if (inv.exception) {
2779          throw inv.exception;
2780       }
2781    }
2782 
2783    /** Asynchronously calls a function after the window message queue processes its current messages.
2784      It is generally not safe to pass references to the delayed function.
2785      Exceptions are not propagated to the caller.
2786     **/
2787    // Extra.
2788    // Exceptions will be passed to Application.onThreadException() and
2789    // trigger the threadException event or the default exception dialog.
2790    final void delayInvoke(void function() fn) {
2791       if (!hwnd) {
2792          badInvokeHandle();
2793       }
2794 
2795       assert(!invokeRequired);
2796 
2797       static assert(fn.sizeof <= LPARAM.sizeof);
2798       PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE, cast(LPARAM) fn);
2799    }
2800 
2801    // Extra.
2802    // Exceptions will be passed to Application.onThreadException() and
2803    // trigger the threadException event or the default exception dialog.
2804    // Copy of params are passed to fn, they do not exist after it returns.
2805    // It is unsafe to pass references to a delayed function.
2806    final void delayInvoke(void function(Control, size_t[]) fn, size_t[] params...) {
2807       if (!hwnd) {
2808          badInvokeHandle();
2809       }
2810 
2811       assert(!invokeRequired);
2812 
2813       static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
2814 
2815       DflInvokeParam* p;
2816       p = cast(DflInvokeParam*) malloc(
2817             (DflInvokeParam.sizeof - size_t.sizeof) + params.length * size_t.sizeof);
2818       if (!p) {
2819          throw new OomException();
2820       }
2821 
2822       p.fp = fn;
2823       p.nparams = params.length;
2824       p.params.ptr[0 .. params.length] = params[];
2825 
2826       PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, cast(LPARAM) p);
2827    }
2828 
2829    deprecated alias beginInvoke = delayInvoke;
2830 
2831    static bool isMnemonic(dchar charCode, Dstring text) {
2832       uint ui;
2833       for (ui = 0; ui != text.length; ui++) {
2834          if ('&' == text[ui]) {
2835             if (++ui == text.length) {
2836                break;
2837             }
2838             if ('&' == text[ui]) { // && means literal & so skip it.
2839                continue;
2840             }
2841             dchar dch;
2842             dch = utf8stringGetUtf32char(text, ui);
2843             return utf32charToLower(charCode) == utf32charToLower(dch);
2844          }
2845       }
2846       return false;
2847    }
2848 
2849    /// Converts a screen Point to a client Point.
2850    final Point pointToClient(Point pt) {
2851       ScreenToClient(hwnd, &pt.point);
2852       return pt;
2853    }
2854 
2855    /// Converts a client Point to a screen Point.
2856    final Point pointToScreen(Point pt) {
2857       ClientToScreen(hwnd, &pt.point);
2858       return pt;
2859    }
2860 
2861    /// Converts a screen Rectangle to a client Rectangle.
2862    final Rect rectangleToClient(Rect r) {
2863       RECT rect;
2864       r.getRect(&rect);
2865 
2866       MapWindowPoints(HWND.init, hwnd, cast(POINT*)&rect, 2);
2867       return Rect(&rect);
2868    }
2869 
2870    /// Converts a client Rectangle to a screen Rectangle.
2871    final Rect rectangleToScreen(Rect r) {
2872       RECT rect;
2873       r.getRect(&rect);
2874 
2875       MapWindowPoints(hwnd, HWND.init, cast(POINT*)&rect, 2);
2876       return Rect(&rect);
2877    }
2878 
2879    // Return true if processed.
2880    bool preProcessMessage(ref Message msg) {
2881       return false;
2882    }
2883 
2884    final Size getAutoScaleSize(Font f) {
2885       Size result;
2886       Graphics g;
2887       g = createGraphics();
2888       result = g.getScaleSize(f);
2889       g.dispose();
2890       return result;
2891    }
2892 
2893    final Size getAutoScaleSize() {
2894       return getAutoScaleSize(font);
2895    }
2896 
2897    void refresh() {
2898       invalidate(true);
2899    }
2900 
2901    void resetBackColor() {
2902       //backColor = defaultBackColor;
2903       backColor = Color.empty;
2904    }
2905 
2906    void resetCursor() {
2907       //cursor = new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false);
2908       cursor = null;
2909    }
2910 
2911    void resetFont() {
2912       //font = defaultFont;
2913       font = null;
2914    }
2915 
2916    void resetForeColor() {
2917       //foreColor = defaultForeColor;
2918       foreColor = Color.empty;
2919    }
2920 
2921    void resetRightToLeft() {
2922       //rightToLeft = false;
2923       rightToLeft = RightToLeft.INHERIT;
2924    }
2925 
2926    void resetText() {
2927       //text = "";
2928       text = null;
2929    }
2930 
2931    // Just allow layout recalc, but don't do it right now.
2932    final void resumeLayout() {
2933       //_allowLayout = true;
2934       if (_disallowLayout) {
2935          _disallowLayout--;
2936       }
2937    }
2938 
2939    // Allow layout recalc, only do it now if -byes- is true.
2940    final void resumeLayout(bool byes) {
2941       if (_disallowLayout) {
2942          _disallowLayout--;
2943       }
2944 
2945       // This is correct.
2946       if (byes) {
2947          if (!_disallowLayout) {
2948             alayout(null);
2949          }
2950       }
2951    }
2952 
2953    final void suspendLayout() {
2954       //_allowLayout = false;
2955       _disallowLayout++;
2956    }
2957 
2958    final void performLayout(Control affectedControl) {
2959       alayout(affectedControl, false);
2960    }
2961 
2962    final void performLayout() {
2963       return performLayout(this);
2964    }
2965 
2966    /+
2967       // TODO: implement.
2968 
2969       // Scale both height and width to -ratio-.
2970       final void scale(float ratio) {
2971          scaleCore(ratio, ratio);
2972       }
2973 
2974 
2975    // Scale -width- and -height- ratios.
2976    final void scale(float width, float height) {
2977       scaleCore(width, height);
2978    }
2979 
2980 
2981    // Also scales child controls recursively.
2982    protected void scaleCore(float width, float height) {
2983       suspendLayout();
2984 
2985       // ...
2986 
2987       resumeLayout();
2988    }
2989    +/
2990 
2991       private static bool _eachild(HWND hw, bool delegate(HWND hw) callback,
2992             ref size_t xiter, bool nested) {
2993          for (; hw; hw = GetWindow(hw, GW_HWNDNEXT)) {
2994             if (!xiter) {
2995                return false;
2996             }
2997             xiter--;
2998 
2999             LONG st = GetWindowLongA(hw, GWL_STYLE);
3000             if (!(st & WS_VISIBLE)) {
3001                continue;
3002             }
3003             if (st & WS_DISABLED) {
3004                continue;
3005             }
3006 
3007             if (!callback(hw)) {
3008                return false;
3009             }
3010 
3011             if (nested) {
3012                //LONG exst = GetWindowLongA(hw, GWL_EXSTYLE);
3013                //if(exst & WS_EX_CONTROLPARENT) // It's no longer added.
3014                {
3015                   HWND hwc = GetWindow(hw, GW_CHILD);
3016                   if (hwc) {
3017                      //if(!_eachild(hwc, callback, xiter, nested))
3018                      if (!_eachild(hwc, callback, xiter, true)) {
3019                         return false;
3020                      }
3021                   }
3022                }
3023             }
3024          }
3025          return true;
3026       }
3027 
3028    package static void eachGoodChildHandle(HWND hwparent,
3029          bool delegate(HWND hw) callback, bool nested = true) {
3030       HWND hw = GetWindow(hwparent, GW_CHILD);
3031       size_t xiter = 2000;
3032       _eachild(hw, callback, xiter, nested);
3033    }
3034 
3035    private static bool _isHwndControlSel(HWND hw) {
3036       Control c = Control.fromHandle(hw);
3037       return c && c.getStyle(ControlStyles.SELECTABLE);
3038    }
3039 
3040    package static void _dlgselnext(Form dlg, HWND hwcursel, bool forward,
3041          bool tabStopOnly = true, bool selectableOnly = false, bool nested = true,
3042          bool wrap = true, HWND hwchildrenof = null) {
3043       //assert(cast(Form)Control.fromHandle(hwdlg) !is null);
3044 
3045       if (!hwchildrenof) {
3046          hwchildrenof = dlg.handle;
3047       }
3048       if (forward) {
3049          bool foundthis = false, tdone = false;
3050          HWND hwfirst;
3051          eachGoodChildHandle(hwchildrenof, (HWND hw) {
3052                assert(!tdone);
3053                if (hw == hwcursel) {
3054                foundthis = true;
3055                } else {
3056                if (!tabStopOnly || (GetWindowLongA(hw, GWL_STYLE) & WS_TABSTOP)) {
3057                if (!selectableOnly || _isHwndControlSel(hw)) {
3058                if (foundthis) {
3059                //DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hw, MAKELPARAM(true, 0));
3060                dlg._selectChild(hw);
3061                tdone = true;
3062                return false; // Break.
3063                } else {
3064                if (HWND.init == hwfirst) {
3065                hwfirst = hw;
3066                }
3067                }
3068                }
3069                }
3070                }
3071                return true; // Continue.
3072          }, nested);
3073          if (!tdone && HWND.init != hwfirst) {
3074             // If it falls through without finding hwcursel, let it select the first one, even if not wrapping.
3075             if (wrap || !foundthis) {
3076                //DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hwfirst, MAKELPARAM(true, 0));
3077                dlg._selectChild(hwfirst);
3078             }
3079          }
3080       } else {
3081          HWND hwprev;
3082          eachGoodChildHandle(hwchildrenof, (HWND hw) {
3083                if (hw == hwcursel) {
3084                if (HWND.init != hwprev) { // Otherwise, keep looping and get last one.
3085                return false; // Break.
3086                }
3087                if (!wrap) { // No wrapping, so don't get last one.
3088                assert(HWND.init == hwprev);
3089                return false; // Break.
3090                }
3091                }
3092                if (!tabStopOnly || (GetWindowLongA(hw, GWL_STYLE) & WS_TABSTOP)) {
3093                if (!selectableOnly || _isHwndControlSel(hw)) {
3094                hwprev = hw;
3095                }
3096                }
3097                return true; // Continue.
3098                }, nested);
3099          // If it falls through without finding hwcursel, let it select the last one, even if not wrapping.
3100          if (HWND.init != hwprev) //DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hwprev, MAKELPARAM(true, 0));
3101          {
3102             dlg._selectChild(hwprev);
3103          }
3104       }
3105    }
3106 
3107    package final void _selectNextControl(Form ctrltoplevel, Control ctrl,
3108          bool forward, bool tabStopOnly, bool nested, bool wrap) {
3109       if (!created) {
3110          return;
3111       }
3112 
3113       assert(ctrltoplevel !is null);
3114       assert(ctrltoplevel.isHandleCreated);
3115 
3116       _dlgselnext(ctrltoplevel, (ctrl
3117                && ctrl.isHandleCreated) ? ctrl.handle : null, forward, tabStopOnly,
3118             !tabStopOnly, nested, wrap, this.handle);
3119    }
3120 
3121    package final void _selectThisControl() {
3122 
3123    }
3124 
3125    // Only considers child controls of this control.
3126    final void selectNextControl(Control ctrl, bool forward, bool tabStopOnly, bool nested,
3127          bool wrap) {
3128       if (!created) {
3129          return;
3130       }
3131 
3132       auto ctrltoplevel = findForm();
3133       if (ctrltoplevel) {
3134          return _selectNextControl(ctrltoplevel, ctrl, forward, tabStopOnly, nested,
3135                wrap);
3136       }
3137    }
3138 
3139    final void select() {
3140       select(false, false);
3141    }
3142 
3143    // If -directed- is true, -forward- is used; otherwise, selects this control.
3144    // If -forward- is true, the next control in the tab order is selected,
3145    // otherwise the previous control in the tab order is selected.
3146    // Controls without style ControlStyles.SELECTABLE are skipped.
3147    void select(bool directed, bool forward) {
3148       if (!created) {
3149          return;
3150       }
3151 
3152       auto ctrltoplevel = findForm();
3153       if (ctrltoplevel && ctrltoplevel !is this) {
3154          /+ // Old...
3155             // Even if directed, ensure THIS one is selected first.
3156             if(!directed || hwnd != GetFocus()) {
3157                DefDlgProcA(ctrltoplevel.handle, WM_NEXTDLGCTL, cast(WPARAM)hwnd, MAKELPARAM(true, 0));
3158             }
3159 
3160          if(directed) {
3161             DefDlgProcA(ctrltoplevel.handle, WM_NEXTDLGCTL, !forward, MAKELPARAM(false, 0));
3162          }
3163          +/
3164 
3165             if (directed) {
3166                _dlgselnext(ctrltoplevel, this.handle, forward);
3167             } else {
3168                ctrltoplevel._selectChild(this);
3169             }
3170       } else {
3171          focus(); // This must be a form so just focus it ?
3172       }
3173    }
3174 
3175    final void setBounds(int x, int y, int width, int height) {
3176       setBoundsCore(x, y, width, height, BoundsSpecified.ALL);
3177    }
3178 
3179    final void setBounds(int x, int y, int width, int height, BoundsSpecified specified) {
3180       setBoundsCore(x, y, width, height, specified);
3181    }
3182 
3183    override Dstring toString() {
3184       return text;
3185    }
3186 
3187    final void update() {
3188       if (!created) {
3189          return;
3190       }
3191 
3192       UpdateWindow(hwnd);
3193    }
3194 
3195    // If mouseEnter, mouseHover and mouseLeave events are supported.
3196    // Returns true on Windows 95 with IE 5.5, Windows 98+ or Windows NT 4.0+.
3197    static @property bool supportsMouseTracking() {
3198       return trackMouseEvent != null;
3199    }
3200 
3201    package final Rect _fetchBounds() {
3202       RECT r;
3203       GetWindowRect(hwnd, &r);
3204       HWND hwParent = GetParent(hwnd);
3205       if (hwParent && (_style() & WS_CHILD)) {
3206          MapWindowPoints(HWND.init, hwParent, cast(POINT*)&r, 2);
3207       }
3208       return Rect(&r);
3209    }
3210 
3211    package final Size _fetchClientSize() {
3212       RECT r;
3213       GetClientRect(hwnd, &r);
3214       return Size(r.right, r.bottom);
3215    }
3216 
3217    deprecated protected void onInvalidated(InvalidateEventArgs iea) {
3218       //invalidated(this, iea);
3219    }
3220 
3221    protected void onPaint(PaintEventArgs pea) {
3222       paint(this, pea);
3223    }
3224 
3225    protected void onMoving(MovingEventArgs cea) {
3226       moving(this, cea);
3227    }
3228 
3229    protected void onMove(EventArgs ea) {
3230       move(this, ea);
3231    }
3232 
3233    /+
3234       protected void onLocationChanged(EventArgs ea) {
3235          locationChanged(this, ea);
3236       }
3237    +/
3238       alias onLocationChanged = onMove;
3239 
3240    protected void onSizing(SizingEventArgs cea) {
3241       sizing(this, cea);
3242    }
3243 
3244    protected void onResize(EventArgs ea) {
3245       resize(this, ea);
3246    }
3247 
3248    /+
3249       protected void onSizeChanged(EventArgs ea) {
3250          sizeChanged(this, ea);
3251       }
3252    +/
3253       alias onSizeChanged = onResize;
3254 
3255    /+
3256       // ///
3257       // Allows comparing before and after dimensions, and also allows modifying the new dimensions.
3258       deprecated protected void onBeforeResize(BeforeResizeEventArgs ea) {
3259       }
3260    +/
3261 
3262       protected void onMouseEnter(MouseEventArgs mea) {
3263          mouseEnter(this, mea);
3264       }
3265 
3266    protected void onMouseMove(MouseEventArgs mea) {
3267       mouseMove(this, mea);
3268    }
3269 
3270    protected void onKeyDown(KeyEventArgs kea) {
3271       keyDown(this, kea);
3272    }
3273 
3274    protected void onKeyPress(KeyPressEventArgs kea) {
3275       keyPress(this, kea);
3276    }
3277 
3278    protected void onKeyUp(KeyEventArgs kea) {
3279       keyUp(this, kea);
3280    }
3281 
3282    protected void onMouseWheel(MouseEventArgs mea) {
3283       mouseWheel(this, mea);
3284    }
3285 
3286    protected void onMouseHover(MouseEventArgs mea) {
3287       mouseHover(this, mea);
3288    }
3289 
3290    protected void onMouseLeave(MouseEventArgs mea) {
3291       mouseLeave(this, mea);
3292    }
3293 
3294    protected void onMouseDown(MouseEventArgs mea) {
3295       mouseDown(this, mea);
3296    }
3297 
3298    protected void onMouseUp(MouseEventArgs mea) {
3299       mouseUp(this, mea);
3300    }
3301 
3302    protected void onClick(EventArgs ea) {
3303       click(this, ea);
3304    }
3305 
3306    protected void onDoubleClick(EventArgs ea) {
3307       doubleClick(this, ea);
3308    }
3309 
3310    protected void onGotFocus(EventArgs ea) {
3311       gotFocus(this, ea);
3312    }
3313    /+
3314       deprecated protected void onEnter(EventArgs ea) {
3315          //enter(this, ea);
3316       }
3317 
3318 
3319    deprecated protected void onLeave(EventArgs ea) {
3320       //leave(this, ea);
3321    }
3322 
3323 
3324    deprecated protected void onValidated(EventArgs ea) {
3325       //validated(this, ea);
3326    }
3327 
3328 
3329    deprecated protected void onValidating(CancelEventArgs cea) {
3330       /+
3331          foreach(CancelEventHandler.Handler handler; validating.handlers()) {
3332             handler(this, cea);
3333 
3334             if(cea.cancel) {
3335                return;   // Not validated.
3336             }
3337          }
3338 
3339       onValidated(EventArgs.empty);
3340       +/
3341    }
3342    +/
3343 
3344       protected void onLostFocus(EventArgs ea) {
3345          lostFocus(this, ea);
3346       }
3347 
3348    protected void onEnabledChanged(EventArgs ea) {
3349       enabledChanged(this, ea);
3350    }
3351 
3352    protected void onTextChanged(EventArgs ea) {
3353       textChanged(this, ea);
3354    }
3355 
3356    private void _propagateFontAmbience() {
3357       Font fon;
3358       fon = font;
3359 
3360       void pa(Control pc) {
3361          foreach (Control ctrl; pc.ccollection) {
3362             if (!ctrl.wfont) { // If default.
3363                if (fon is ctrl.font) { // If same default.
3364                   if (ctrl.isHandleCreated) {
3365                      SendMessageA(ctrl.hwnd, WM_SETFONT,
3366                            cast(WPARAM) fon.handle, MAKELPARAM(true, 0));
3367                   }
3368                   ctrl.onFontChanged(EventArgs.empty);
3369 
3370                   pa(ctrl); // Recursive.
3371                }
3372             }
3373          }
3374       }
3375 
3376       pa(this);
3377    }
3378 
3379    protected void onFontChanged(EventArgs ea) {
3380       debug (EVENT_PRINT) {
3381          cprintf("{ Event: onFontChanged - Control %.*s }\n", name);
3382       }
3383 
3384       fontChanged(this, ea);
3385    }
3386 
3387    protected void onRightToLeftChanged(EventArgs ea) {
3388       debug (EVENT_PRINT) {
3389          cprintf("{ Event: onRightToLeftChanged - Control %.*s }\n", name);
3390       }
3391 
3392       rightToLeftChanged(this, ea);
3393    }
3394 
3395    protected void onVisibleChanged(EventArgs ea) {
3396       if (wparent) {
3397          wparent.vchanged();
3398          suspendLayout(); // Note: exception could cause failure to restore.
3399          wparent.alayout(this);
3400          resumeLayout(false);
3401       }
3402       if (visible) {
3403          alayout(this);
3404       }
3405 
3406       visibleChanged(this, ea);
3407 
3408       if (visible) {
3409          // If no focus or the focused control is hidden, try to select something...
3410          HWND hwfocus = GetFocus();
3411          if (!hwfocus || (hwfocus == hwnd
3412                   && !getStyle(ControlStyles.SELECTABLE)) || !IsWindowVisible(hwfocus)) {
3413             selectNextControl(null, true, true, true, false);
3414          }
3415       }
3416    }
3417 
3418    protected void onHelpRequested(HelpEventArgs hea) {
3419       debug (EVENT_PRINT) {
3420          cprintf("{ Event: onHelpRequested - Control %.*s }\n", name);
3421       }
3422 
3423       helpRequested(this, hea);
3424    }
3425 
3426    protected void onSystemColorsChanged(EventArgs ea) {
3427       debug (EVENT_PRINT) {
3428          cprintf("{ Event: onSystemColorsChanged - Control %.*s }\n", name);
3429       }
3430 
3431       systemColorsChanged(this, ea);
3432    }
3433 
3434    protected void onHandleCreated(EventArgs ea) {
3435       if (!(cbits & CBits.VSTYLE)) {
3436          _disableVisualStyle();
3437       }
3438 
3439       Font fon;
3440       fon = font;
3441       if (fon) {
3442          SendMessageA(hwnd, WM_SETFONT, cast(WPARAM) fon.handle, 0);
3443       }
3444 
3445       if (wregion) {
3446          // Need to make a copy of the region.
3447          SetWindowRgn(hwnd, dupHrgn(wregion.handle), true);
3448       }
3449 
3450       version (DFL_NO_DRAG_DROP) {
3451       } else {
3452          if (droptarget) {
3453             if (S_OK != RegisterDragDrop(hwnd, droptarget)) {
3454                droptarget = null;
3455                throw new DflException("Unable to register drag-drop");
3456             }
3457          }
3458       }
3459 
3460       debug {
3461          _handlecreated = true;
3462       }
3463    }
3464 
3465    protected void onHandleDestroyed(EventArgs ea) {
3466       handleDestroyed(this, ea);
3467    }
3468 
3469    protected void onPaintBackground(PaintEventArgs pea) {
3470       RECT rect;
3471       pea.clipRectangle.getRect(&rect);
3472       FillRect(pea.graphics.handle, &rect, hbrBg);
3473    }
3474 
3475    private static MouseButtons wparamMouseButtons(WPARAM wparam) {
3476       MouseButtons result;
3477       if (wparam & MK_LBUTTON) {
3478          result |= MouseButtons.LEFT;
3479       }
3480       if (wparam & MK_RBUTTON) {
3481          result |= MouseButtons.RIGHT;
3482       }
3483       if (wparam & MK_MBUTTON) {
3484          result |= MouseButtons.MIDDLE;
3485       }
3486       return result;
3487    }
3488 
3489    package final void prepareDc(HDC hdc) {
3490       //SetBkMode(hdc, TRANSPARENT); // ?
3491       //SetBkMode(hdc, OPAQUE); // ?
3492       SetBkColor(hdc, backColor.toRgb());
3493       SetTextColor(hdc, foreColor.toRgb());
3494    }
3495 
3496    // Message copy so it cannot be modified.
3497    deprecated protected void onNotifyMessage(Message msg) {
3498    }
3499 
3500    /+
3501       /+package+/ LRESULT customMsg(ref CustomMsg msg) { // package
3502          return 0;
3503       }
3504    +/
3505 
3506       protected void onReflectedMessage(ref Message m) {
3507          switch (m.msg) {
3508             case WM_CTLCOLORSTATIC:
3509             case WM_CTLCOLORLISTBOX:
3510             case WM_CTLCOLOREDIT:
3511             case WM_CTLCOLORSCROLLBAR:
3512             case WM_CTLCOLORBTN:
3513                //case WM_CTLCOLORDLG: // ?
3514                //case 0x0019: //WM_CTLCOLOR; obsolete.
3515                prepareDc(cast(HDC) m.wParam);
3516                //assert(GetObjectA(hbrBg, 0, null));
3517                m.result = cast(LRESULT) hbrBg;
3518                break;
3519 
3520             default:
3521          }
3522       }
3523 
3524    // ChildWindowFromPoint includes both hidden and disabled.
3525    // This includes disabled windows, but not hidden.
3526    // Here is a point in this control, see if it's over a visible child.
3527    // Returns null if not even in this control's client.
3528    final HWND pointOverVisibleChild(Point pt) { // package
3529       if (pt.x < 0 || pt.y < 0) {
3530          return HWND.init;
3531       }
3532       if (pt.x > wclientsz.width || pt.y > wclientsz.height) {
3533          return HWND.init;
3534       }
3535 
3536       // Note: doesn't include non-DFL windows... TO-DO: fix.
3537       foreach (Control ctrl; ccollection) {
3538          if (!ctrl.visible) {
3539             continue;
3540          }
3541          if (!ctrl.isHandleCreated) { // Shouldn't..
3542             continue;
3543          }
3544          if (ctrl.bounds.contains(pt)) {
3545             return ctrl.hwnd;
3546          }
3547       }
3548 
3549       return hwnd; // Just over this control.
3550    }
3551 
3552    version (_DFL_WINDOWS_HUNG_WORKAROUND) {
3553       DWORD ldlgcode = 0;
3554    }
3555 
3556    protected void wndProc(ref Message msg) {
3557       //if(ctrlStyle & ControlStyles.ENABLE_NOTIFY_MESSAGE)
3558       // onNotifyMessage(msg);
3559 
3560       switch (msg.msg) {
3561          case WM_PAINT: {
3562                            // This can't be done in BeginPaint() becuase part might get
3563                            // validated during this event ?
3564                            //RECT uprect;
3565                            //GetUpdateRect(hwnd, &uprect, true);
3566                            //onInvalidated(new InvalidateEventArgs(Rect(&uprect)));
3567 
3568                            PAINTSTRUCT ps;
3569                            BeginPaint(msg.hWnd, &ps);
3570                            try {
3571                               //onInvalidated(new InvalidateEventArgs(Rect(&uprect)));
3572 
3573                               scope PaintEventArgs pea = new PaintEventArgs(new Graphics(ps.hdc,
3574                                        false), Rect(&ps.rcPaint));
3575 
3576                               // Probably because ControlStyles.ALL_PAINTING_IN_WM_PAINT.
3577                               if (ps.fErase) {
3578                                  prepareDc(ps.hdc);
3579                                  onPaintBackground(pea);
3580                               }
3581 
3582                               prepareDc(ps.hdc);
3583                               onPaint(pea);
3584                            }
3585                            finally {
3586                               EndPaint(hwnd, &ps);
3587                            }
3588                         }
3589                         return;
3590 
3591          case WM_ERASEBKGND:
3592                         if (ctrlStyle & ControlStyles.OPAQUE) {
3593                            msg.result = 1; // Erased.
3594                         } else if (!(ctrlStyle & ControlStyles.ALL_PAINTING_IN_WM_PAINT)) {
3595                            RECT uprect;
3596                            /+
3597                               GetUpdateRect(hwnd, &uprect, false);
3598                            +/
3599                               uprect.left = 0;
3600                            uprect.top = 0;
3601                            uprect.right = clientSize.width;
3602                            uprect.bottom = clientSize.height;
3603 
3604                            prepareDc(cast(HDC) msg.wParam);
3605                            scope PaintEventArgs pea = new PaintEventArgs(new Graphics(cast(HDC) msg.wParam,
3606                                     false), Rect(&uprect));
3607                            onPaintBackground(pea);
3608                            msg.result = 1; // Erased.
3609                         }
3610                         return;
3611 
3612          case WM_PRINTCLIENT:
3613                         prepareDc(cast(HDC) msg.wParam);
3614                         scope PaintEventArgs pea = new PaintEventArgs(new Graphics(cast(HDC) msg.wParam,
3615                                  false), Rect(Point(0, 0), wclientsz));
3616                         onPaint(pea);
3617                         return;
3618 
3619          case WM_CTLCOLORSTATIC:
3620          case WM_CTLCOLORLISTBOX:
3621          case WM_CTLCOLOREDIT:
3622          case WM_CTLCOLORSCROLLBAR:
3623          case WM_CTLCOLORBTN:
3624                         //case WM_CTLCOLORDLG: // ?
3625                         //case 0x0019: //WM_CTLCOLOR; obsolete.
3626                         {
3627                            Control ctrl = fromChildHandle(cast(HWND) msg.lParam);
3628                            if (ctrl) {
3629                               //ctrl.prepareDc(cast(HDC)msg.wParam);
3630                               //msg.result = cast(LRESULT)ctrl.hbrBg;
3631                               ctrl.onReflectedMessage(msg);
3632                               return;
3633                            }
3634                         }
3635                         break;
3636 
3637          case WM_WINDOWPOSCHANGED: {
3638                                       WINDOWPOS* wp = cast(WINDOWPOS*) msg.lParam;
3639                                       bool needLayout = false;
3640 
3641                                       //if(!wp.hwndInsertAfter)
3642                                       // wp.flags |= SWP_NOZORDER; // ?
3643 
3644                                       bool didvis = false;
3645                                       if (wp.flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) {
3646                                          needLayout = true; // Only if not didvis / if not recreating.
3647                                          if (!recreatingHandle) { // Note: suppresses onVisibleChanged
3648                                             if (wp.flags & SWP_HIDEWINDOW) { // Hiding.
3649                                                _clicking = false;
3650                                             }
3651                                             onVisibleChanged(EventArgs.empty);
3652                                             didvis = true;
3653                                             //break; // Showing min/max includes other flags.
3654                                          }
3655                                       }
3656 
3657                                       if (!(wp.flags & SWP_NOZORDER) /+ || (wp.flags & SWP_SHOWWINDOW) +/ ) {
3658                                          if (wparent) {
3659                                             wparent.vchanged();
3660                                          }
3661                                       }
3662 
3663                                       if (!(wp.flags & SWP_NOMOVE)) {
3664                                          onMove(EventArgs.empty);
3665                                       }
3666 
3667                                       if (!(wp.flags & SWP_NOSIZE)) {
3668                                          if (szdraw) {
3669                                             invalidate(true);
3670                                          }
3671 
3672                                          onResize(EventArgs.empty);
3673 
3674                                          needLayout = true;
3675                                       }
3676 
3677                                       // Frame change results in a new client size.
3678                                       if (wp.flags & SWP_FRAMECHANGED) {
3679                                          if (szdraw) {
3680                                             invalidate(true);
3681                                          }
3682 
3683                                          needLayout = true;
3684                                       }
3685 
3686                                       if (!didvis) { // onVisibleChanged already triggers layout.
3687                                          if ( /+ (wp.flags & SWP_SHOWWINDOW) || +/ !(wp.flags & SWP_NOSIZE)
3688                                                || !(wp.flags & SWP_NOZORDER)) { // z-order determines what is positioned first.
3689                                             suspendLayout(); // Note: exception could cause failure to restore.
3690                                             if (wparent) {
3691                                                wparent.alayout(this);
3692                                             }
3693                                             resumeLayout(false);
3694                                             needLayout = true;
3695                                          }
3696 
3697                                          if (needLayout) {
3698                                             alayout(this);
3699                                          }
3700                                       }
3701                                    }
3702                                    break;
3703 
3704          case WM_WINDOWPOSCHANGING: {
3705                                        WINDOWPOS* wp = cast(WINDOWPOS*) msg.lParam;
3706 
3707                                        if (!(wp.flags & SWP_NOMOVE) && (location.x != wp.x || location.y != wp.y)) {
3708                                           scope e = new MovingEventArgs(Point(wp.x, wp.y));
3709                                           onMoving(e);
3710                                           wp.x = e.x;
3711                                           wp.y = e.y;
3712                                        }
3713                                        if (!(wp.flags & SWP_NOSIZE) && (width != wp.cx || height != wp.cy)) {
3714                                           scope e = new SizingEventArgs(Size(wp.cx, wp.cy));
3715                                           onSizing(e);
3716                                           wp.cx = e.width;
3717                                           wp.cy = e.height;
3718                                        }
3719                                     }
3720                                     break;
3721 
3722          case WM_MOUSEMOVE:
3723                                     if (_clicking) {
3724                                        if (!(msg.wParam & MK_LBUTTON)) {
3725                                           _clicking = false;
3726                                        }
3727                                     }
3728 
3729                                     if (trackMouseEvent) { // Requires Windows 95 with IE 5.5, 98 or NT4.
3730                                        if (!menter) {
3731                                           menter = true;
3732 
3733                                           POINT pt;
3734                                           GetCursorPos(&pt);
3735                                           MapWindowPoints(HWND.init, hwnd, &pt, 1);
3736                                           scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam),
3737                                                 0, pt.x, pt.y, 0);
3738                                           onMouseEnter(mea);
3739 
3740                                           TRACKMOUSEEVENT tme;
3741                                           tme.cbSize = TRACKMOUSEEVENT.sizeof;
3742                                           tme.dwFlags = TME_HOVER | TME_LEAVE;
3743                                           tme.hwndTrack = msg.hWnd;
3744                                           tme.dwHoverTime = HOVER_DEFAULT;
3745                                           trackMouseEvent(&tme);
3746                                        }
3747                                     }
3748 
3749                                     onMouseMove(new MouseEventArgs(wparamMouseButtons(msg.wParam), 0,
3750                                              cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0));
3751                                     break;
3752 
3753          case WM_SETCURSOR:
3754                                     // Just update it so that Control.defWndProc() can set it correctly.
3755                                     if (cast(HWND) msg.wParam == hwnd) {
3756                                        Cursor cur;
3757                                        cur = cursor;
3758                                        if (cur) {
3759                                           if (cast(HCURSOR) GetClassLongA(hwnd, GCL_HCURSOR) != cur.handle) {
3760                                              SetClassLongA(hwnd, GCL_HCURSOR, cast(LONG) cur.handle);
3761                                           }
3762                                        } else {
3763                                           if (cast(HCURSOR) GetClassLongA(hwnd, GCL_HCURSOR) != HCURSOR.init) {
3764                                              SetClassLongA(hwnd, GCL_HCURSOR, cast(LONG) cast(HCURSOR) null);
3765                                           }
3766                                        }
3767                                        Control.defWndProc(msg);
3768                                        return;
3769                                     }
3770                                     break;
3771 
3772                                     /+
3773          case WM_NEXTDLGCTL:
3774                                        if(!LOWORD(msg.lParam)) {
3775                                           select(true, msg.wParam != 0);
3776                                           return;
3777                                        }
3778                                        break;
3779                                        +/
3780 
3781          case WM_KEYDOWN:
3782          case WM_KEYUP:
3783          case WM_CHAR:
3784          case WM_SYSKEYDOWN:
3785          case WM_SYSKEYUP:
3786          case WM_SYSCHAR:
3787                                           //case WM_IMECHAR:
3788                                           /+
3789                                              if(processKeyEventArgs(msg)) {
3790                                                 // The key was processed.
3791                                                 msg.result = 0;
3792                                                 return;
3793                                              }
3794                                           msg.result = 1; // The key was not processed.
3795                                           break;
3796                                           +/
3797                                              msg.result = !processKeyEventArgs(msg);
3798                                           return;
3799 
3800          case WM_MOUSEWHEEL: { // Requires Windows 98 or NT4.
3801                                 scope MouseEventArgs mea = new MouseEventArgs(
3802                                       wparamMouseButtons(LOWORD(msg.wParam)), 0,
3803                                       cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam),
3804                                       cast(short) HIWORD(msg.wParam));
3805                                 onMouseWheel(mea);
3806                              }
3807                              break;
3808 
3809          case WM_MOUSEHOVER: { // Requires Windows 95 with IE 5.5, 98 or NT4.
3810                                 scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam),
3811                                       0, cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
3812                                 onMouseHover(mea);
3813                              }
3814                              break;
3815 
3816          case WM_MOUSELEAVE: { // Requires Windows 95 with IE 5.5, 98 or NT4.
3817                                 menter = false;
3818 
3819                                 POINT pt;
3820                                 GetCursorPos(&pt);
3821                                 MapWindowPoints(HWND.init, hwnd, &pt, 1);
3822                                 scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam),
3823                                       0, pt.x, pt.y, 0);
3824                                 onMouseLeave(mea);
3825                              }
3826                              break;
3827 
3828          case WM_LBUTTONDOWN: {
3829                                  _clicking = true;
3830 
3831                                  scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 1,
3832                                        cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
3833                                  onMouseDown(mea);
3834 
3835                                  //if(ctrlStyle & ControlStyles.SELECTABLE)
3836                                  // SetFocus(hwnd); // No, this goofs up stuff, including the ComboBox dropdown.
3837                               }
3838                               break;
3839 
3840          case WM_RBUTTONDOWN: {
3841                                  scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT,
3842                                        1, cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
3843                                  onMouseDown(mea);
3844                               }
3845                               break;
3846 
3847          case WM_MBUTTONDOWN: {
3848                                  scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE,
3849                                        1, cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
3850                                  onMouseDown(mea);
3851                               }
3852                               break;
3853 
3854          case WM_LBUTTONUP: {
3855                                if (msg.lParam == -1) {
3856                                   break;
3857                                }
3858 
3859                                // Use temp in case of exception.
3860                                bool wasClicking = _clicking;
3861                                _clicking = false;
3862 
3863                                scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 1,
3864                                      cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
3865                                onMouseUp(mea);
3866 
3867                                if (wasClicking && (ctrlStyle & ControlStyles.STANDARD_CLICK)) {
3868                                   // See if the mouse up was over the control.
3869                                   if (Rect(0, 0, wclientsz.width, wclientsz.height).contains(mea.x, mea.y)) {
3870                                      // Now make sure there's no child in the way.
3871                                      //if(ChildWindowFromPoint(hwnd, Point(mea.x, mea.y).point) == hwnd) // Includes hidden windows.
3872                                      if (pointOverVisibleChild(Point(mea.x, mea.y)) == hwnd) {
3873                                         onClick(EventArgs.empty);
3874                                      }
3875                                   }
3876                                }
3877                             }
3878                             break;
3879 
3880                             version (CUSTOM_MSG_HOOK) {
3881                             } else {
3882                                case WM_DRAWITEM: {
3883                                                     Control ctrl;
3884 
3885                                                     DRAWITEMSTRUCT* dis = cast(DRAWITEMSTRUCT*) msg.lParam;
3886                                                     if (dis.CtlType == ODT_MENU) {
3887                                                        // dis.hwndItem is the HMENU.
3888                                                     } else {
3889                                                        ctrl = Control.fromChildHandle(dis.hwndItem);
3890                                                        if (ctrl) {
3891                                                           //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
3892                                                           ctrl.onReflectedMessage(msg);
3893                                                           return;
3894                                                        }
3895                                                     }
3896                                                  }
3897                                                  break;
3898 
3899                                case WM_MEASUREITEM: {
3900                                                        Control ctrl;
3901 
3902                                                        MEASUREITEMSTRUCT* mis = cast(MEASUREITEMSTRUCT*) msg.lParam;
3903                                                        if (!(mis.CtlType == ODT_MENU)) {
3904                                                           ctrl = Control.fromChildHandle(cast(HWND) mis.CtlID);
3905                                                           if (ctrl) {
3906                                                              //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
3907                                                              ctrl.onReflectedMessage(msg);
3908                                                              return;
3909                                                           }
3910                                                        }
3911                                                     }
3912                                                     break;
3913 
3914                                case WM_COMMAND: {
3915                                                    /+
3916                                                       switch(LOWORD(msg.wParam)) {
3917                                                          case IDOK:
3918                                                          case IDCANCEL:
3919                                                             if(parent) {
3920                                                                parent.wndProc(msg);
3921                                                             }
3922                                                             //break;
3923                                                             return; // ?
3924 
3925                                                          default:
3926                                                       }
3927                                                    +/
3928 
3929                                                       Control ctrl;
3930 
3931                                                    ctrl = Control.fromChildHandle(cast(HWND) msg.lParam);
3932                                                    if (ctrl) {
3933                                                       //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
3934                                                       ctrl.onReflectedMessage(msg);
3935                                                       return;
3936                                                    } else {
3937                                                       version (DFL_NO_MENUS) {
3938                                                       } else {
3939                                                          MenuItem m;
3940 
3941                                                          m = cast(MenuItem) Application.lookupMenuID(LOWORD(msg.wParam));
3942                                                          if (m) {
3943                                                             //msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
3944                                                             m._reflectMenu(msg);
3945                                                             //return; // ?
3946                                                          }
3947                                                       }
3948                                                    }
3949                                                 }
3950                                                 break;
3951 
3952                                case WM_NOTIFY: {
3953                                                   Control ctrl;
3954                                                   NMHDR* nmh;
3955                                                   nmh = cast(NMHDR*) msg.lParam;
3956 
3957                                                   ctrl = Control.fromChildHandle(nmh.hwndFrom);
3958                                                   if (ctrl) {
3959                                                      //msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
3960                                                      ctrl.onReflectedMessage(msg);
3961                                                      return;
3962                                                   }
3963                                                }
3964                                                break;
3965 
3966                                                version (DFL_NO_MENUS) {
3967                                                } else {
3968                                                   case WM_MENUSELECT: {
3969                                                                          UINT mflags;
3970                                                                          UINT uitem;
3971                                                                          int mid;
3972                                                                          MenuItem m;
3973 
3974                                                                          mflags = HIWORD(msg.wParam);
3975                                                                          uitem = LOWORD(msg.wParam); // Depends on the flags.
3976 
3977                                                                          if (mflags & MF_SYSMENU) {
3978                                                                             break;
3979                                                                          }
3980 
3981                                                                          if (mflags & MF_POPUP) {
3982                                                                             // -uitem- is an index.
3983                                                                             mid = GetMenuItemID(cast(HMENU) msg.lParam, uitem);
3984                                                                          } else {
3985                                                                             // -uitem- is the item identifier.
3986                                                                             mid = uitem;
3987                                                                          }
3988 
3989                                                                          m = cast(MenuItem) Application.lookupMenuID(mid);
3990                                                                          if (m) {
3991                                                                             //msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
3992                                                                             m._reflectMenu(msg);
3993                                                                             //return;
3994                                                                          }
3995                                                                       }
3996                                                                       break;
3997 
3998                                                   case WM_INITMENUPOPUP:
3999                                                                       if (HIWORD(msg.lParam)) {
4000                                                                          // System menu.
4001                                                                       } else {
4002                                                                          MenuItem m;
4003 
4004                                                                          //m = cast(MenuItem)Application.lookupMenuID(GetMenuItemID(cast(HMENU)msg.wParam, LOWORD(msg.lParam)));
4005                                                                          m = cast(MenuItem) Application.lookupMenu(cast(HMENU) msg.wParam);
4006                                                                          if (m) {
4007                                                                             //msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
4008                                                                             m._reflectMenu(msg);
4009                                                                             //return;
4010                                                                          }
4011                                                                       }
4012                                                                       break;
4013 
4014                                                   case WM_INITMENU: {
4015                                                                        ContextMenu m;
4016 
4017                                                                        m = cast(ContextMenu) Application.lookupMenu(cast(HMENU) msg.wParam);
4018                                                                        if (m) {
4019                                                                           //msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
4020                                                                           m._reflectMenu(msg);
4021                                                                           //return;
4022                                                                        }
4023                                                                     }
4024                                                                     break;
4025                                                }
4026                             }
4027 
4028          case WM_RBUTTONUP: {
4029                                scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT,
4030                                      1, cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
4031                                onMouseUp(mea);
4032                             }
4033                             break;
4034 
4035          case WM_MBUTTONUP: {
4036                                scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE,
4037                                      1, cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
4038                                onMouseUp(mea);
4039                             }
4040                             break;
4041 
4042          case WM_LBUTTONDBLCLK: {
4043                                    scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 2,
4044                                          cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
4045                                    onMouseDown(mea);
4046 
4047                                    if (
4048                                          (ctrlStyle & (ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK)) == (
4049                                             ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK)) {
4050                                       onDoubleClick(EventArgs.empty);
4051                                    }
4052                                 }
4053                                 break;
4054 
4055          case WM_RBUTTONDBLCLK: {
4056                                    scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT,
4057                                          2, cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
4058                                    onMouseDown(mea);
4059                                 }
4060                                 break;
4061 
4062          case WM_MBUTTONDBLCLK: {
4063                                    scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE,
4064                                          2, cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam), 0);
4065                                    onMouseDown(mea);
4066                                 }
4067                                 break;
4068 
4069          case WM_SETFOCUS:
4070                                 _wmSetFocus();
4071                                 // defWndProc* Form focuses a child.
4072                                 break;
4073 
4074          case WM_KILLFOCUS:
4075                                 _wmKillFocus();
4076                                 break;
4077 
4078          case WM_ENABLE:
4079                                 onEnabledChanged(EventArgs.empty);
4080 
4081                                 // defWndProc*
4082                                 break;
4083 
4084                                 /+
4085          case WM_NEXTDLGCTL:
4086                                    if(msg.wParam && !LOWORD(msg.lParam)) {
4087                                       HWND hwf;
4088                                       hwf = GetFocus();
4089                                       if(hwf) {
4090                                          Control hwc;
4091                                          hwc = Control.fromHandle(hwf);
4092                                          if(hwc) {
4093                                             if(hwc._rtype() & 0x20) { // TabControl
4094                                                hwf = GetWindow(hwf, GW_CHILD);
4095                                                if(hwf) {
4096                                                   // Can't do this because it could be modifying someone else's memory.
4097                                                   //msg.wParam = cast(WPARAM)hwf;
4098                                                   //msg.lParam = MAKELPARAM(1, 0);
4099                                                   msg.result = DefWindowProcA(msg.hWnd, WM_NEXTDLGCTL, cast(WPARAM)hwf, MAKELPARAM(TRUE, 0));
4100                                                   return;
4101                                                }
4102                                             }
4103                                          }
4104                                       }
4105                                    }
4106                                    break;
4107                                    +/
4108 
4109          case WM_SETTEXT:
4110                                       defWndProc(msg);
4111 
4112                                       // Need to fetch it because cast(char*)lparam isn't always accessible ?
4113                                       // Should this go in _wndProc()? Need to defWndProc() first ?
4114                                       if (ctrlStyle & ControlStyles.CACHE_TEXT) {
4115                                          wtext = _fetchText();
4116                                       }
4117 
4118                                       onTextChanged(EventArgs.empty);
4119                                       return;
4120 
4121          case WM_SETFONT:
4122                                       // Don't replace -wfont- if it's the same one, beacuse the old Font
4123                                       // object will get garbage collected and probably delete the HFONT.
4124 
4125                                       //onFontChanged(EventArgs.empty);
4126 
4127                                       // defWndProc*
4128                                       return;
4129 
4130                                       /+
4131          case WM_STYLECHANGED: {
4132                                   //defWndProc(msg);
4133 
4134                                   STYLESTRUCT* ss = cast(STYLESTRUCT*)msg.lParam;
4135                                   DWORD changed = ss.styleOld ^ ss.styleNew;
4136 
4137                                   if(msg.wParam == GWL_EXSTYLE) {
4138                                      //if(changed & WS_EX_RTLREADING)
4139                                      // onRightToLeftChanged(EventArgs.empty);
4140                                   }
4141                                }
4142                                       break;
4143                                       +/
4144 
4145          case WM_ACTIVATE:
4146                                          switch (LOWORD(msg.wParam)) {
4147                                             case WA_INACTIVE:
4148                                                _clicking = false;
4149                                                break;
4150 
4151                                             default:
4152                                          }
4153                                          break;
4154 
4155                                          version (DFL_NO_MENUS) {
4156                                          } else {
4157                                             case WM_CONTEXTMENU:
4158                                                if (hwnd == cast(HWND) msg.wParam) {
4159                                                   if (cmenu) {
4160                                                      // Shift+F10 causes xPos and yPos to be -1.
4161 
4162                                                      Point point;
4163 
4164                                                      if (msg.lParam == -1) {
4165                                                         point = pointToScreen(Point(0, 0));
4166                                                      } else {
4167                                                         point = Point(cast(short) LOWORD(msg.lParam), cast(short) HIWORD(msg.lParam));
4168                                                      }
4169 
4170                                                      SetFocus(handle); // ?
4171                                                      cmenu.show(this, point);
4172 
4173                                                      return;
4174                                                   }
4175                                                }
4176                                                break;
4177                                          }
4178 
4179          case WM_HELP: {
4180                           HELPINFO* hi = cast(HELPINFO*) msg.lParam;
4181 
4182                           scope HelpEventArgs hea = new HelpEventArgs(Point(hi.MousePos.x, hi.MousePos.y));
4183                           onHelpRequested(hea);
4184                           if (hea.handled) {
4185                              msg.result = TRUE;
4186                              return;
4187                           }
4188                        }
4189                        break;
4190 
4191          case WM_SYSCOLORCHANGE:
4192                        onSystemColorsChanged(EventArgs.empty);
4193 
4194                        // Need to send the message to children for some common controls to update properly.
4195                        foreach (Control ctrl; ccollection) {
4196                           SendMessageA(ctrl.handle, WM_SYSCOLORCHANGE, msg.wParam, msg.lParam);
4197                        }
4198                        break;
4199 
4200          case WM_SETTINGCHANGE:
4201                        // Send the message to children.
4202                        foreach (Control ctrl; ccollection) {
4203                           SendMessageA(ctrl.handle, WM_SETTINGCHANGE, msg.wParam, msg.lParam);
4204                        }
4205                        break;
4206 
4207          case WM_PALETTECHANGED:
4208                        /+
4209                           if(cast(HWND)msg.wParam != hwnd) {
4210                              // Realize palette.
4211                           }
4212                        +/
4213 
4214                           // Send the message to children.
4215                           foreach (Control ctrl; ccollection) {
4216                              SendMessageA(ctrl.handle, WM_PALETTECHANGED, msg.wParam, msg.lParam);
4217                           }
4218                        break;
4219 
4220                        //case WM_QUERYNEWPALETTE: // Send this message to children ?
4221 
4222                        /+
4223                           // Moved this stuff to -parent-.
4224          case WM_PARENTNOTIFY:
4225                           switch(LOWORD(msg.wParam)) {
4226                              case WM_DESTROY:
4227                                 Control ctrl = fromChildHandle(cast(HWND)msg.lParam);
4228                                 if(ctrl) {
4229                                    _ctrlremoved(new ControlEventArgs(ctrl));
4230 
4231                                    // ?
4232                                    vchanged();
4233                                    //alayout(ctrl); // This is already being called from somewhere else..
4234                                 }
4235                                 break;
4236 
4237                                 /+
4238                              case WM_CREATE:
4239                                    initLayout();
4240                                    break;
4241                                    +/
4242 
4243                              default:
4244                           }
4245                           break;
4246                           +/
4247 
4248          case WM_CREATE:
4249                              /+
4250                                 if(wparent) {
4251                                    initLayout();   // ?
4252                                 }
4253                              +/
4254                                 if (cbits & CBits.NEED_INIT_LAYOUT) {
4255                                    if (visible) {
4256                                       if (wparent) {
4257                                          wparent.vchanged();
4258                                          suspendLayout(); // Note: exception could cause failure to restore.
4259                                          wparent.alayout(this);
4260                                          resumeLayout(false);
4261                                       }
4262                                       alayout(this);
4263                                    }
4264                                 }
4265                              break;
4266 
4267          case WM_DESTROY:
4268                              onHandleDestroyed(EventArgs.empty);
4269                              break;
4270 
4271          case WM_GETDLGCODE: {
4272                                 version (_DFL_WINDOWS_HUNG_WORKAROUND) {
4273                                    /+
4274                                       if(ctrlStyle & ControlStyles.CONTAINER_CONTROL) {
4275                                          if(!(_exStyle & WS_EX_CONTROLPARENT)) {
4276                                             assert(0);
4277                                          }
4278                                       }
4279                                    +/
4280 
4281                                       DWORD dw;
4282                                    dw = GetTickCount();
4283                                    if (ldlgcode < dw - 1020) {
4284                                       ldlgcode = dw - 1000;
4285                                    } else {
4286                                       ldlgcode += 50;
4287                                       if (ldlgcode > dw) {
4288                                          // Probably a problem with WS_EX_CONTROLPARENT and WS_TABSTOP.
4289                                          if (ldlgcode >= ldlgcode.max - 10_000) {
4290                                             ldlgcode = 0;
4291                                             throw new WindowsHungDflException("Windows hung");
4292                                          }
4293                                          //msg.result |= 0x0004 | 0x0002 | 0x0001; //DLGC_WANTALLKEYS | DLGC_WANTTAB | DLGC_WANTARROWS;
4294                                          ldlgcode = ldlgcode.max - 10_000;
4295                                          return;
4296                                       }
4297                                    }
4298                                 }
4299 
4300                                 /+
4301                                    if(msg.lParam) {
4302                                       Message m;
4303                                       m._winMsg = *cast(MSG*)msg.lParam;
4304                                       if(processKeyEventArgs(m)) {
4305                                          return;
4306                                       }
4307                                    }
4308                                 +/
4309 
4310                                    defWndProc(msg);
4311 
4312                                 if (ctrlStyle & ControlStyles.WANT_ALL_KEYS) {
4313                                    msg.result |= DLGC_WANTALLKEYS;
4314                                 }
4315 
4316                                 // Only want chars if ALT isn't down, because it would break mnemonics.
4317                                 if (!(GetKeyState(VK_MENU) & 0x8000)) {
4318                                    msg.result |= DLGC_WANTCHARS;
4319                                 }
4320 
4321                              }
4322                              return;
4323 
4324          case WM_CLOSE:
4325                              /+ {
4326                                 if(parent) {
4327                                    Message mp;
4328                                    mp = msg;
4329                                    mp.hWnd = parent.handle;
4330                                    parent.wndProc(mp); // Pass to parent so it can decide what to do.
4331                                 }
4332                              }+/
4333                              return; // Prevent defWndProc from destroying the window!
4334 
4335          case 0: // WM_NULL
4336                              // Don't confuse with failed RegisterWindowMessage().
4337                              break;
4338 
4339          default:
4340                              //defWndProc(msg);
4341                              version (DFL_NO_WM_GETCONTROLNAME) {
4342                              } else {
4343                                 if (msg.msg == wmGetControlName) {
4344                                    //cprintf("WM_GETCONTROLNAME: %.*s; wparam: %d\n", cast(uint)name.length, name.ptr, msg.wParam);
4345                                    if (msg.wParam && this.name.length) {
4346                                       OSVERSIONINFOA osver;
4347                                       osver.dwOSVersionInfoSize = OSVERSIONINFOA.sizeof;
4348                                       if (GetVersionExA(&osver)) {
4349                                          try {
4350                                             if (osver.dwPlatformId <= VER_PLATFORM_WIN32_WINDOWS) {
4351                                                if (dfl.internal.utf.useUnicode) {
4352                                                } else {
4353                                                   // ANSI.
4354                                                   Dstring ansi;
4355                                                   ansi = dfl.internal.utf.toAnsi(this.name);
4356                                                   if (msg.wParam <= ansi.length) {
4357                                                      ansi = ansi[0 .. msg.wParam - 1];
4358                                                   }
4359                                                   (cast(char*) msg.lParam)[0 .. ansi.length] = ansi[];
4360                                                   (cast(char*) msg.lParam)[ansi.length] = 0;
4361                                                   msg.result = ansi.length + 1;
4362                                                }
4363                                             } else {
4364                                                // Unicode.
4365                                                Dwstring uni;
4366                                                uni = dfl.internal.utf.toUnicode(this.name);
4367                                                if (msg.wParam <= uni.length) {
4368                                                   uni = uni[0 .. msg.wParam - 1];
4369                                                }
4370                                                (cast(wchar*) msg.lParam)[0 .. uni.length] = uni[];
4371                                                (cast(wchar*) msg.lParam)[uni.length] = 0;
4372                                                msg.result = uni.length + 1;
4373                                             }
4374                                          }
4375                                          catch (Throwable) {
4376                                          }
4377                                          return;
4378                                       }
4379                                    }
4380                                 }
4381                              }
4382       }
4383 
4384       defWndProc(msg);
4385 
4386       if (msg.msg == WM_CREATE) {
4387          EventArgs ea;
4388          ea = EventArgs.empty;
4389          onHandleCreated(ea);
4390 
4391          debug {
4392             assert(_handlecreated,
4393                   "If overriding onHandleCreated(), be sure to call super.onHandleCreated()!");
4394          }
4395          handleCreated(this, ea);
4396          debug {
4397             _handlecreated = false; // Reset.
4398          }
4399       }
4400    }
4401 
4402    package final void _wmSetFocus() {
4403       //onEnter(EventArgs.empty);
4404 
4405       onGotFocus(EventArgs.empty);
4406 
4407       // defWndProc* Form focuses a child.
4408    }
4409 
4410    package final void _wmKillFocus() {
4411       _clicking = false;
4412 
4413       //onLeave(EventArgs.empty);
4414 
4415       //if(cvalidation)
4416       // onValidating(new CancelEventArgs);
4417 
4418       onLostFocus(EventArgs.empty);
4419    }
4420 
4421    protected void defWndProc(ref Message msg) {
4422       //msg.result = DefWindowProcA(msg.hWnd, msg.msg, msg.wParam, msg.lParam);
4423       msg.result = dfl.internal.utf.defWindowProc(msg.hWnd, msg.msg, msg.wParam, msg.lParam);
4424    }
4425 
4426    // Always called right when destroyed, before doing anything else.
4427    // hwnd is cleared after this step.
4428    void _destroying() { // package
4429       //wparent = null; // ?
4430    }
4431 
4432    // This function must be called FIRST for EVERY message to this
4433    // window in order to keep the correct window state.
4434    // This function must not throw exceptions.
4435    package final void mustWndProc(ref Message msg) {
4436       if (needCalcSize) {
4437          needCalcSize = false;
4438          RECT crect;
4439          GetClientRect(msg.hWnd, &crect);
4440          wclientsz.width = crect.right;
4441          wclientsz.height = crect.bottom;
4442       }
4443 
4444       switch (msg.msg) {
4445          case WM_NCCALCSIZE:
4446             needCalcSize = true;
4447             break;
4448 
4449          case WM_WINDOWPOSCHANGED: {
4450                                       WINDOWPOS* wp = cast(WINDOWPOS*) msg.lParam;
4451 
4452                                       if (!recreatingHandle) {
4453                                          //wstyle = GetWindowLongA(hwnd, GWL_STYLE); // ..WM_SHOWWINDOW.
4454                                          if (wp.flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) {
4455                                             //wstyle = GetWindowLongA(hwnd, GWL_STYLE);
4456                                             cbits |= CBits.VISIBLE;
4457                                             wstyle |= WS_VISIBLE;
4458                                             if (wp.flags & SWP_HIDEWINDOW) { // Hiding.
4459                                                cbits &= ~CBits.VISIBLE;
4460                                                wstyle &= ~WS_VISIBLE;
4461                                             }
4462                                             //break; // Showing min/max includes other flags.
4463                                          }
4464                                       }
4465 
4466                                       //if(!(wp.flags & SWP_NOMOVE))
4467                                       // wrect.location = Point(wp.x, wp.y);
4468                                       if (!(wp.flags & SWP_NOSIZE) || !(wp.flags & SWP_NOMOVE) || (wp.flags & SWP_FRAMECHANGED)) {
4469                                          //wrect = _fetchBounds();
4470                                          wrect = Rect(wp.x, wp.y, wp.cx, wp.cy);
4471                                          wclientsz = _fetchClientSize();
4472                                       }
4473 
4474                                       if ((wp.flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW)) || !(wp.flags & SWP_NOSIZE)) {
4475                                          DWORD rstyle;
4476                                          rstyle = GetWindowLongA(msg.hWnd, GWL_STYLE);
4477                                          rstyle &= WS_MAXIMIZE | WS_MINIMIZE;
4478                                          wstyle &= ~(WS_MAXIMIZE | WS_MINIMIZE);
4479                                          wstyle |= rstyle;
4480                                       }
4481                                    }
4482                                    break;
4483 
4484                                    /+
4485          case WM_WINDOWPOSCHANGING:
4486                                       //oldwrect = wrect;
4487                                       break;
4488                                       +/
4489 
4490                                          /+
4491          case WM_SETFONT:
4492                                          //wfont = _fetchFont();
4493                                          break;
4494                                          +/
4495 
4496          case WM_STYLECHANGED: {
4497                                   STYLESTRUCT* ss = cast(STYLESTRUCT*) msg.lParam;
4498 
4499                                   if (msg.wParam == GWL_STYLE) {
4500                                      wstyle = ss.styleNew;
4501                                   } else if (msg.wParam == GWL_EXSTYLE) {
4502                                      wexstyle = ss.styleNew;
4503                                   }
4504 
4505                                   /+
4506                                      wrect = _fetchBounds();
4507                                   wclientsz = _fetchClientSize();
4508                                   +/
4509                                }
4510                                          break;
4511 
4512                                          /+
4513                                             // NOTE: this is sent even if the parent is shown.
4514          case WM_SHOWWINDOW:
4515                                             if(!msg.lParam) {
4516                                                /+ {
4517                                                   cbits &= ~(CBits.SW_SHOWN | CBits.SW_HIDDEN);
4518                                                   DWORD rstyle;
4519                                                   rstyle = GetWindowLongA(msg.hWnd, GWL_STYLE);
4520                                                   if(cast(BOOL)msg.wParam) {
4521                                                      //wstyle |= WS_VISIBLE;
4522                                                      if(!(WS_VISIBLE & wstyle) && (WS_VISIBLE & rstyle)) {
4523                                                         wstyle = rstyle;
4524                                                         cbits |= CBits.SW_SHOWN;
4525 
4526                                                         try {
4527                                                            createChildren(); // Might throw.
4528                                                         } catch(DThrowable e) {
4529                                                            Application.onThreadException(e);
4530                                                         }
4531                                                      }
4532                                                      wstyle = rstyle;
4533                                                   } else
4534                                                   {
4535                                                      //wstyle &= ~WS_VISIBLE;
4536                                                      if((WS_VISIBLE & wstyle) && !(WS_VISIBLE & rstyle)) {
4537                                                         wstyle = rstyle;
4538                                                         cbits |= CBits.SW_HIDDEN;
4539                                                      }
4540                                                      wstyle = rstyle;
4541                                                   }
4542                                                }
4543                                                +/
4544                                                   wstyle = GetWindowLongA(msg.hWnd, GWL_STYLE);
4545                                                //if(cbits & CBits.FVISIBLE)
4546                                                // wstyle |= WS_VISIBLE;
4547                                             }
4548                                             break;
4549                                             +/
4550 
4551          case WM_ENABLE:
4552                                                /+
4553                                                   //if(IsWindowEnabled(hwnd))
4554                                                   if(cast(BOOL)msg.wParam) {
4555                                                      wstyle &= ~WS_DISABLED;
4556                                                   } else {
4557                                                      wstyle |= WS_DISABLED;
4558                                                   }
4559                                                +/
4560                                                   wstyle = GetWindowLongA(hwnd, GWL_STYLE);
4561                                                break;
4562 
4563                                                /+
4564          case WM_PARENTNOTIFY:
4565                                                   switch(LOWORD(msg.wParam)) {
4566                                                      case WM_DESTROY:
4567                                                         // ...
4568                                                         break;
4569 
4570                                                      default:
4571                                                   }
4572                                                   break;
4573                                                   +/
4574 
4575          case WM_NCCREATE: {
4576                               //hwnd = msg.hWnd;
4577 
4578                               /+
4579                                  // Not using CREATESTRUCT for window bounds because it can contain
4580                                  // CW_USEDEFAULT and other magic values.
4581 
4582                                  CREATESTRUCTA* cs;
4583                               cs = cast(CREATESTRUCTA*)msg.lParam;
4584 
4585                               //wrect = Rect(cs.x, cs.y, cs.cx, cs.cy);
4586                               +/
4587 
4588                                  wrect = _fetchBounds();
4589                               //oldwrect = wrect;
4590                               wclientsz = _fetchClientSize();
4591                            }
4592                                                   break;
4593 
4594          case WM_CREATE:
4595                                                   try {
4596                                                      cbits |= CBits.CREATED;
4597 
4598                                                      //hwnd = msg.hWnd;
4599 
4600                                                      CREATESTRUCTA* cs;
4601                                                      cs = cast(CREATESTRUCTA*) msg.lParam;
4602                                                      /+
4603                                                         // Done in WM_NCCREATE now.
4604                                                         //wrect = _fetchBounds();
4605                                                         wrect = Rect(cs.x, cs.y, cs.cx, cs.cy);
4606                                                      wclientsz = _fetchClientSize();
4607                                                      +/
4608 
4609                                                         // If class style was changed, update.
4610                                                         if (_fetchClassLong() != wclassStyle) {
4611                                                            SetClassLongA(hwnd, GCL_STYLE, wclassStyle);
4612                                                         }
4613 
4614                                                      // Need to update clientSize in case of styles in createParams().
4615                                                      wclientsz = _fetchClientSize();
4616 
4617                                                      //finishCreating(msg.hWnd);
4618 
4619                                                      if (!(ctrlStyle & ControlStyles.CACHE_TEXT)) {
4620                                                         wtext = null;
4621                                                      }
4622 
4623                                                      /+
4624                                                         // Gets created on demand instead.
4625                                                         if(Color.empty != backc) {
4626                                                            hbrBg = backc.createBrush();
4627                                                         }
4628                                                      +/
4629 
4630                                                         /+
4631                                                         // ?
4632                                                         wstyle = cs.style;
4633                                                      wexstyle = cs.dwExStyle;
4634                                                      +/
4635 
4636                                                         createChildren(); // Might throw. Used to be commented-out.
4637 
4638                                                      if (recreatingHandle) {
4639                                                         // After existing messages and functions are done.
4640                                                         delayInvoke(function(Control cthis, size_t[] params) {
4641                                                               cthis.cbits &= ~CBits.RECREATING;
4642                                                               });
4643                                                      }
4644                                                   }
4645                                                   catch (DThrowable e) {
4646                                                      Application.onThreadException(e);
4647                                                   }
4648                                                   break;
4649 
4650          case WM_DESTROY:
4651                                                   cbits &= ~CBits.CREATED;
4652                                                   if (!recreatingHandle) {
4653                                                      cbits &= ~CBits.FORMLOADED;
4654                                                   }
4655                                                   _destroying();
4656                                                   //if(!killing)
4657                                                   if (recreatingHandle) {
4658                                                      fillRecreationData();
4659                                                   }
4660                                                   break;
4661 
4662          case WM_NCDESTROY:
4663                                                   Application.removeHwnd(hwnd);
4664                                                   hwnd = HWND.init;
4665                                                   break;
4666 
4667          default:
4668                                                   /+
4669                                                      if(msg.msg == wmDfl) {
4670                                                         switch(msg.wParam) {
4671                                                            case WPARAM_DFL_:
4672 
4673                                                            default:
4674                                                         }
4675                                                      }
4676                                                   +/
4677       }
4678    }
4679 
4680    package final void _wndProc(ref Message msg) {
4681       //mustWndProc(msg); // Done in dflWndProc() now.
4682       wndProc(msg);
4683    }
4684 
4685    package final void _defWndProc(ref Message msg) {
4686       defWndProc(msg);
4687    }
4688 
4689    package final void doShow() {
4690       if (wparent) { // Exclude owner.
4691          SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0,
4692                SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
4693       } else {
4694          SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
4695       }
4696    }
4697 
4698    package final void doHide() {
4699       SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0,
4700             SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOZORDER);
4701    }
4702 
4703    //EventHandler backColorChanged;
4704    Event!(Control, EventArgs) backColorChanged; ///
4705    // EventHandler backgroundImageChanged;
4706    /+
4707       deprecated EventHandler causesValidationChanged;
4708    deprecated InvalidateEventHandler invalidated;
4709    deprecated EventHandler validated;
4710    deprecated CancelEventHandler validating; // Once cancel is true, remaining events are suppressed (including validated).
4711    deprecated EventHandler enter; // Cascades up. TODO: fix implementation.
4712    deprecated EventHandler leave; // Cascades down. TODO: fix implementation.
4713    deprecated UICuesEventHandler changeUICues; // TODO: properly fire.
4714    +/
4715       //EventHandler click;
4716       Event!(Control, EventArgs) click; ///
4717    version (DFL_NO_MENUS) {
4718    } else {
4719       //EventHandler contextMenuChanged;
4720       Event!(Control, EventArgs) contextMenuChanged; ///
4721    }
4722    //ControlEventHandler controlAdded;
4723    Event!(Control, ControlEventArgs) controlAdded; ///
4724    //ControlEventHandler controlRemoved;
4725    Event!(Control, ControlEventArgs) controlRemoved; ///
4726    //EventHandler cursorChanged;
4727    Event!(Control, EventArgs) cursorChanged; ///
4728    //EventHandler disposed;
4729    Event!(Control, EventArgs) disposed; ///
4730    //EventHandler dockChanged;
4731    //Event!(Control, EventArgs) dockChanged; ///
4732    Event!(Control, EventArgs) hasLayoutChanged; ///
4733    alias dockChanged = hasLayoutChanged;
4734    //EventHandler doubleClick;
4735    Event!(Control, EventArgs) doubleClick; ///
4736    //EventHandler enabledChanged;
4737    Event!(Control, EventArgs) enabledChanged; ///
4738    //EventHandler fontChanged;
4739    Event!(Control, EventArgs) fontChanged; ///
4740    //EventHandler foreColorChanged;
4741    Event!(Control, EventArgs) foreColorChanged; ///
4742    //EventHandler gotFocus; // After enter.
4743    Event!(Control, EventArgs) gotFocus; ///
4744    //EventHandler handleCreated;
4745    Event!(Control, EventArgs) handleCreated; ///
4746    //EventHandler handleDestroyed;
4747    Event!(Control, EventArgs) handleDestroyed; ///
4748    //HelpEventHandler helpRequested;
4749    Event!(Control, HelpEventArgs) helpRequested; ///
4750    //KeyEventHandler keyDown;
4751    Event!(Control, KeyEventArgs) keyDown; ///
4752    //KeyEventHandler keyPress;
4753    Event!(Control, KeyPressEventArgs) keyPress; ///
4754    //KeyEventHandler keyUp;
4755    Event!(Control, KeyEventArgs) keyUp; ///
4756    //LayoutEventHandler layout;
4757    Event!(Control, LayoutEventArgs) layout; ///
4758    //EventHandler lostFocus;
4759    Event!(Control, EventArgs) lostFocus; ///
4760    //MouseEventHandler mouseDown;
4761    Event!(Control, MouseEventArgs) mouseDown; ///
4762    //MouseEventHandler mouseEnter;
4763    Event!(Control, MouseEventArgs) mouseEnter; ///
4764    //MouseEventHandler mouseHover;
4765    Event!(Control, MouseEventArgs) mouseHover; ///
4766    //MouseEventHandler mouseLeave;
4767    Event!(Control, MouseEventArgs) mouseLeave; ///
4768    //MouseEventHandler mouseMove;
4769    Event!(Control, MouseEventArgs) mouseMove; ///
4770    //MouseEventHandler mouseUp;
4771    Event!(Control, MouseEventArgs) mouseUp; ///
4772    //MouseEventHandler mouseWheel;
4773    Event!(Control, MouseEventArgs) mouseWheel; ///
4774    //EventHandler moving;
4775    Event!(Control, MovingEventArgs) moving; ///
4776    //EventHandler move;
4777    Event!(Control, EventArgs) move; ///
4778    //EventHandler locationChanged;
4779    alias locationChanged = move;
4780    //PaintEventHandler paint;
4781    Event!(Control, PaintEventArgs) paint; ///
4782    //EventHandler parentChanged;
4783    Event!(Control, EventArgs) parentChanged; ///
4784    //EventHandler sizing;
4785    Event!(Control, SizingEventArgs) sizing; ///
4786    //EventHandler resize;
4787    Event!(Control, EventArgs) resize; ///
4788    //EventHandler sizeChanged;
4789    alias sizeChanged = resize;
4790    //EventHandler rightToLeftChanged;
4791    Event!(Control, EventArgs) rightToLeftChanged; ///
4792    // EventHandler styleChanged;
4793    //EventHandler systemColorsChanged;
4794    Event!(Control, EventArgs) systemColorsChanged; ///
4795    // EventHandler tabIndexChanged;
4796    // EventHandler tabStopChanged;
4797    //EventHandler textChanged;
4798    Event!(Control, EventArgs) textChanged; ///
4799    //EventHandler visibleChanged;
4800    Event!(Control, EventArgs) visibleChanged; ///
4801 
4802    version (DFL_NO_DRAG_DROP) {
4803    } else {
4804       //DragEventHandler dragDrop;
4805       Event!(Control, DragEventArgs) dragDrop; ///
4806       //DragEventHandler dragEnter;
4807       Event!(Control, DragEventArgs) dragEnter; ///
4808       //EventHandler dragLeave;
4809       Event!(Control, EventArgs) dragLeave; ///
4810       //DragEventHandler dragOver;
4811       Event!(Control, DragEventArgs) dragOver; ///
4812       //GiveFeedbackEventHandler giveFeedback;
4813       Event!(Control, GiveFeedbackEventArgs) giveFeedback; ///
4814       //QueryContinueDragEventHandler queryContinueDrag;
4815       Event!(Control, QueryContinueDragEventArgs) queryContinueDrag; ///
4816    }
4817 
4818    /// Construct a new Control instance.
4819    this() {
4820       //name = DObject.toString(); // ?
4821 
4822       wrect.size = defaultSize;
4823       //oldwrect = wrect;
4824 
4825       /+
4826          backc = defaultBackColor;
4827       forec = defaultForeColor;
4828       wfont = defaultFont;
4829       wcurs = new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false);
4830       +/
4831          backc = Color.empty;
4832       forec = Color.empty;
4833       wfont = null;
4834       wcurs = null;
4835 
4836       ccollection = createControlsInstance();
4837    }
4838 
4839    this(Dstring text) {
4840       this();
4841       wtext = text;
4842 
4843       ccollection = createControlsInstance();
4844    }
4845 
4846    this(Control cparent, Dstring text) {
4847       this();
4848       wtext = text;
4849       parent = cparent;
4850 
4851       ccollection = createControlsInstance();
4852    }
4853 
4854    this(Dstring text, int left, int top, int width, int height) {
4855       this();
4856       wtext = text;
4857       wrect = Rect(left, top, width, height);
4858 
4859       ccollection = createControlsInstance();
4860    }
4861 
4862    this(Control cparent, Dstring text, int left, int top, int width, int height) {
4863       this();
4864       wtext = text;
4865       wrect = Rect(left, top, width, height);
4866       parent = cparent;
4867 
4868       ccollection = createControlsInstance();
4869    }
4870 
4871    /+
4872       // Used internally.
4873       this(HWND hwnd)
4874       in {
4875          assert(hwnd);
4876       }
4877    body {
4878       this.hwnd = hwnd;
4879       owned = false;
4880 
4881       ccollection = new ControlCollection(this);
4882    }
4883    +/
4884 
4885       ~this() {
4886          debug (APP_PRINT)
4887             cprintf("~Control %p\n", cast(void*) this);
4888 
4889          version (DFL_NO_ZOMBIE_FORM) {
4890          } else {
4891             Application.zombieKill(this); // Does nothing if not zombie.
4892          }
4893 
4894          //dispose(false);
4895          destroyHandle();
4896          deleteThisBackgroundBrush();
4897       }
4898 
4899    /+ package +/ /+ protected +/ int _rtype() { // package
4900       return 0;
4901    }
4902 
4903    void dispose() {
4904       dispose(true);
4905    }
4906 
4907    protected void dispose(bool disposing) {
4908       if (disposing) {
4909          killing = true;
4910 
4911          version (DFL_NO_MENUS) {
4912          } else {
4913             cmenu = cmenu.init;
4914          }
4915          _ctrlname = _ctrlname.init;
4916          otag = otag.init;
4917          wcurs = wcurs.init;
4918          wfont = wfont.init;
4919          wparent = wparent.init;
4920          wregion = wregion.init;
4921          wtext = wtext.init;
4922          deleteThisBackgroundBrush();
4923          //ccollection.children = null; // Not GC-safe in dtor.
4924          //ccollection = null; // ? Causes bad things. Leaving it will do just fine.
4925       }
4926 
4927       if (!isHandleCreated) {
4928          return;
4929       }
4930 
4931       destroyHandle();
4932       /+
4933          //assert(hwnd == HWND.init); // Zombie trips this. (Not anymore with the hwnd-prop)
4934          if(hwnd) {
4935             assert(!IsWindow(hwnd));
4936             hwnd = HWND.init;
4937          }
4938       +/
4939          assert(hwnd == HWND.init);
4940 
4941       onDisposed(EventArgs.empty);
4942    }
4943 
4944    protected:
4945 
4946    @property Size defaultSize() {
4947       return Size(0, 0);
4948    }
4949 
4950    /+
4951       // TODO: implement.
4952       @property EventHandlerList events() {
4953       }
4954    +/
4955 
4956       /+
4957       // TODO: implement. Is this worth implementing?
4958 
4959       // Set to -1 to reset cache.
4960       final @property void fontHeight(int fh) {
4961 
4962       }
4963 
4964 
4965    final @property int fontHeight() {
4966       return fonth;
4967    }
4968    +/
4969 
4970       //final void resizeRedraw(bool byes)
4971       public final @property void resizeRedraw(bool byes) {
4972          /+
4973             // These class styles get lost sometimes so don't rely on them.
4974             LONG cl = _classStyle();
4975          if(byes) {
4976             cl |= CS_HREDRAW | CS_VREDRAW;
4977          } else {
4978             cl &= ~(CS_HREDRAW | CS_VREDRAW);
4979          }
4980 
4981          _classStyle(cl);
4982          +/
4983             szdraw = byes;
4984       }
4985 
4986    final @property bool resizeRedraw() {
4987       //return (_classStyle() & (CS_HREDRAW | CS_VREDRAW)) != 0;
4988       return szdraw;
4989    }
4990 
4991    /+
4992       // ///
4993       // I don't think this is reliable.
4994       final bool hasVisualStyle() {
4995          bool result = false;
4996          HWND hw = handle; // Always reference handle.
4997          HMODULE huxtheme = GetModuleHandleA("uxtheme.dll");
4998          //HMODULE huxtheme = LoadLibraryA("uxtheme.dll");
4999          if(huxtheme) {
5000             auto getwintheme = cast(typeof(&GetWindowTheme))GetProcAddress(huxtheme, "GetWindowTheme");
5001             if(getwintheme) {
5002                result = getwintheme(hw) != null;
5003             }
5004             //FreeLibrary(huxtheme);
5005          }
5006          return result;
5007       }
5008    +/
5009 
5010       package final void _disableVisualStyle() {
5011          assert(isHandleCreated);
5012 
5013          HMODULE hmuxt;
5014          hmuxt = GetModuleHandleA("uxtheme.dll");
5015          if (hmuxt) {
5016             auto setWinTheme = cast(typeof(&SetWindowTheme)) GetProcAddress(hmuxt, "SetWindowTheme");
5017             if (setWinTheme) {
5018                setWinTheme(hwnd, " "w.ptr, " "w.ptr); // Clear the theme.
5019             }
5020          }
5021       }
5022 
5023    public final void disableVisualStyle(bool byes = true) {
5024       if (!byes) {
5025          if (cbits & CBits.VSTYLE) {
5026             return;
5027          }
5028          cbits |= CBits.VSTYLE;
5029 
5030          if (isHandleCreated) {
5031             _crecreate();
5032          }
5033       } else {
5034          if (!(cbits & CBits.VSTYLE)) {
5035             return;
5036          }
5037          cbits &= ~CBits.VSTYLE;
5038 
5039          if (isHandleCreated) {
5040             _disableVisualStyle();
5041          }
5042       }
5043    }
5044 
5045    deprecated public final void enableVisualStyle(bool byes = true) {
5046       return disableVisualStyle(!byes);
5047    }
5048 
5049    ControlCollection createControlsInstance() {
5050       return new ControlCollection(this);
5051    }
5052 
5053    deprecated package final void createClassHandle(Dstring className) {
5054       if (!wparent || !wparent.handle || killing) {
5055 create_err:
5056          throw new DflException("Control creation failure");
5057       }
5058 
5059       // This is here because referencing wparent.handle might create me.
5060       //if(created)
5061       if (isHandleCreated) {
5062          return;
5063       }
5064 
5065       Application.creatingControl(this);
5066       hwnd = dfl.internal.utf.createWindowEx(wexstyle, className, wtext,
5067             wstyle, wrect.x, wrect.y, wrect.width, wrect.height, wparent.handle,
5068             HMENU.init, Application.getInstance(), null);
5069       if (!hwnd) {
5070          goto create_err;
5071       }
5072    }
5073 
5074    // Override to change the creation parameters.
5075    // Be sure to call super.createParams() or all the create params will need to be filled.
5076    protected void createParams(ref CreateParams cp) {
5077       with (cp) {
5078          className = CONTROL_CLASSNAME;
5079          caption = wtext;
5080          param = null;
5081          //parent = wparent.handle;
5082          parent = wparent ? wparent.handle : HWND.init;
5083          menu = HMENU.init;
5084          inst = Application.getInstance();
5085          x = wrect.x;
5086          y = wrect.y;
5087          width = wrect.width;
5088          height = wrect.height;
5089          classStyle = wclassStyle;
5090          exStyle = wexstyle;
5091          wstyle |= WS_VISIBLE;
5092          if (!(cbits & CBits.VISIBLE)) {
5093             wstyle &= ~WS_VISIBLE;
5094          }
5095          style = wstyle;
5096       }
5097    }
5098 
5099    protected void createHandle() {
5100       // Note: if modified, Form.createHandle() should be modified as well.
5101 
5102       if (isHandleCreated) {
5103          return;
5104       }
5105 
5106       //createClassHandle(CONTROL_CLASSNAME);
5107 
5108       /+
5109          if(!wparent || !wparent.handle || killing) {
5110 create_err:
5111             //throw new DflException("Control creation failure");
5112             throw new DflException(Object.toString() ~ " creation failure"); // ?
5113          }
5114       +/
5115 
5116          debug {
5117             Dstring er;
5118          }
5119       if (killing) {
5120          debug {
5121             er = "the control is being disposed";
5122          }
5123 
5124          debug (APP_PRINT) {
5125             cprintf("Creating Control handle while disposing.\n");
5126          }
5127 
5128 create_err:
5129          Dstring kmsg = "Control creation failure";
5130          if (name.length) {
5131             kmsg ~= " (" ~ name ~ ")";
5132          }
5133          debug {
5134             if (er.length) {
5135                kmsg ~= " - " ~ er;
5136             }
5137          }
5138          throw new DflException(kmsg);
5139          //throw new DflException(Object.toString() ~ " creation failure"); // ?
5140       }
5141 
5142       // Need the parent's handle to exist.
5143       if (wparent) {
5144          wparent.createHandle();
5145       }
5146 
5147       // This is here because wparent.createHandle() might create me.
5148       //if(created)
5149       if (isHandleCreated) {
5150          return;
5151       }
5152 
5153       CreateParams cp;
5154       /+
5155          DWORD prevClassStyle;
5156       prevClassStyle = wclassStyle;
5157       +/
5158 
5159          createParams(cp);
5160       assert(!isHandleCreated); // Make sure the handle wasn't created in createParams().
5161 
5162       with (cp) {
5163          wtext = caption;
5164          //wrect = Rect(x, y, width, height); // This gets updated in WM_CREATE.
5165          wclassStyle = classStyle;
5166          wexstyle = exStyle;
5167          wstyle = style;
5168 
5169          //if(style & WS_CHILD) // Breaks context-help.
5170          if ((ctrlStyle & ControlStyles.CONTAINER_CONTROL) && (style & WS_CHILD)) {
5171             exStyle |= WS_EX_CONTROLPARENT;
5172          }
5173 
5174          bool vis = (style & WS_VISIBLE) != 0;
5175 
5176          Application.creatingControl(this);
5177          hwnd = dfl.internal.utf.createWindowEx(exStyle, className, caption,
5178                (style & ~WS_VISIBLE), x, y, width, height, parent, menu, inst, param);
5179          if (!hwnd) {
5180             debug (APP_PRINT) {
5181                cprintf(
5182                      "CreateWindowEx failed." ~ " (exStyle=0x%X, className=`%.*s`, caption=`%.*s`, style=0x%X, x=%d, y=%d, width=%d, height=%d," ~ " parent=0x%X, menu=0x%X, inst=0x%X, param=0x%X)\n",
5183                      exStyle, className.ptr, caption.ptr, style, x, y, width,
5184                      height, parent, menu, inst, param);
5185             }
5186 
5187             debug {
5188                er = std..string.format(
5189                      "CreateWindowEx failed {className=%s;exStyle=0x%X;style=0x%X;parent=0x%X;menu=0x%X;inst=0x%X;}",
5190                      className, exStyle, style, cast(void*) parent,
5191                      cast(void*) menu, cast(void*) inst);
5192             }
5193 
5194             goto create_err;
5195          }
5196 
5197          if (vis) {
5198             doShow(); // Properly fires onVisibleChanged.
5199          }
5200       }
5201 
5202       //onHandleCreated(EventArgs.empty); // Called in WM_CREATE now.
5203    }
5204 
5205    package final void _createHandle() {
5206       createHandle();
5207    }
5208 
5209    public final @property bool recreatingHandle() {
5210       if (cbits & CBits.RECREATING) {
5211          return true;
5212       }
5213       return false;
5214    }
5215 
5216    private void _setAllRecreating() {
5217       cbits |= CBits.RECREATING;
5218       foreach (Control cc; controls) {
5219          cc._setAllRecreating();
5220       }
5221    }
5222 
5223    protected void recreateHandle()
5224       in {
5225          assert(!recreatingHandle);
5226       }
5227    body {
5228       if (!isHandleCreated) {
5229          return;
5230       }
5231 
5232       if (recreatingHandle) {
5233          return;
5234       }
5235 
5236       bool hfocus = focused;
5237       HWND prevHwnd = GetWindow(hwnd, GW_HWNDPREV);
5238 
5239       _setAllRecreating();
5240       //scope(exit)
5241       // cbits &= ~CBits.RECREATING; // Now done from WM_CREATE.
5242 
5243       destroyHandle();
5244       createHandle();
5245 
5246       if (prevHwnd) {
5247          SetWindowPos(hwnd, prevHwnd, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
5248       } else {
5249          SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
5250       }
5251       if (hfocus) {
5252          select();
5253       }
5254    }
5255 
5256    void destroyHandle() {
5257       if (!isHandleCreated) {
5258          return;
5259       }
5260 
5261       DestroyWindow(hwnd);
5262 
5263       // This stuff is done in WM_DESTROY because DestroyWindow() could be called elsewhere..
5264       //hwnd = HWND.init; // Done in WM_DESTROY.
5265       //onHandleDestroyed(EventArgs.empty); // Done in WM_DESTROY.
5266    }
5267 
5268    private final void fillRecreationData() {
5269       //cprintf(" { fillRecreationData %.*s }\n", name);
5270 
5271       if (!(ctrlStyle & ControlStyles.CACHE_TEXT)) {
5272          wtext = _fetchText();
5273       }
5274 
5275       //wclassStyle = _fetchClassLong(); // ?
5276 
5277       // Fetch children.
5278       Control[] ccs;
5279       foreach (Control cc; controls) {
5280          ccs ~= cc;
5281       }
5282       ccollection.children = ccs;
5283    }
5284 
5285    protected void onDisposed(EventArgs ea) {
5286       disposed(this, ea);
5287    }
5288 
5289    protected final bool getStyle(ControlStyles flag) {
5290       return (ctrlStyle & flag) != 0;
5291    }
5292 
5293    protected final void setStyle(ControlStyles flag, bool value) {
5294       if (flag & ControlStyles.CACHE_TEXT) {
5295          if (value) {
5296             wtext = _fetchText();
5297          } else {
5298             wtext = null;
5299          }
5300       }
5301 
5302       if (value) {
5303          ctrlStyle |= flag;
5304       } else {
5305          ctrlStyle &= ~flag;
5306       }
5307    }
5308 
5309    // Only for setStyle() styles that are part of hwnd and wndclass styles.
5310    protected final void updateStyles() {
5311       LONG newClassStyles = _classStyle();
5312       LONG newWndStyles = _style();
5313 
5314       if (ctrlStyle & ControlStyles.STANDARD_DOUBLE_CLICK) {
5315          newClassStyles |= CS_DBLCLKS;
5316       } else {
5317          newClassStyles &= ~CS_DBLCLKS;
5318       }
5319 
5320       /+
5321          if(ctrlStyle & ControlStyles.RESIZE_REDRAW) {
5322             newClassStyles |= CS_HREDRAW | CS_VREDRAW;
5323          } else {
5324             newClassStyles &= ~(CS_HREDRAW | CS_VREDRAW);
5325          }
5326       +/
5327 
5328          /+
5329          if(ctrlStyle & ControlStyles.SELECTABLE) {
5330             newWndStyles |= WS_TABSTOP;
5331          } else {
5332             newWndStyles &= ~WS_TABSTOP;
5333          }
5334       +/
5335 
5336          _classStyle(newClassStyles);
5337       _style(newWndStyles);
5338    }
5339 
5340    final bool getTopLevel() {
5341       // return GetParent(hwnd) == HWND.init;
5342       return wparent is null;
5343    }
5344 
5345    package final void alayout(Control ctrl, bool vcheck = true) {
5346       if (vcheck && !visible) {
5347          return;
5348       }
5349 
5350       if (cbits & CBits.IN_LAYOUT) {
5351          return;
5352       }
5353 
5354       //if(_allowLayout)
5355       if (!_disallowLayout) {
5356          //cprintf("alayout\n");
5357          scope LayoutEventArgs lea = new LayoutEventArgs(ctrl);
5358          onLayout(lea);
5359       }
5360    }
5361 
5362    // Z-order of controls has changed.
5363    package final void vchanged() {
5364       // Z-order can't change if it's not created or invisible.
5365       //if(!isHandleCreated || !visible)
5366       // return;
5367 
5368       version (RADIO_GROUP_LAYOUT) {
5369          //cprintf("vchanged\n");
5370 
5371          bool foundRadio = false;
5372 
5373          foreach (Control ctrl; ccollection) {
5374             if (!ctrl.visible) {
5375                continue;
5376             }
5377 
5378             if (ctrl._rtype() & 1) { // Radio type.
5379                LONG wlg;
5380                wlg = ctrl._style();
5381                if (foundRadio) {
5382                   if (wlg & WS_GROUP) //ctrl._style(wlg & ~WS_GROUP);
5383                   {
5384                      ctrl._style(wlg & ~(WS_GROUP | WS_TABSTOP));
5385                   }
5386                } else {
5387                   foundRadio = true;
5388 
5389                   if (!(wlg & WS_GROUP)) //ctrl._style(wlg | WS_GROUP);
5390                   {
5391                      ctrl._style(wlg | WS_GROUP | WS_TABSTOP);
5392                   }
5393                }
5394             } else {
5395                // Found non-radio so reset group.
5396                // Update: only reset group if found ctrl with WS_EX_CONTROLPARENT.
5397                // TODO: check if correct implementation.
5398                if (ctrl._exStyle() & WS_EX_CONTROLPARENT) {
5399                   foundRadio = false;
5400                }
5401             }
5402          }
5403       }
5404    }
5405 
5406    // Called after adding the control to a container.
5407    protected void initLayout() {
5408       assert(wparent !is null);
5409       if (visible && created) { // ?
5410          wparent.vchanged();
5411          wparent.alayout(this);
5412       }
5413    }
5414 
5415    protected void onLayout(LayoutEventArgs lea) {
5416       // Note: exception could cause failure to restore.
5417       //suspendLayout();
5418       cbits |= CBits.IN_LAYOUT;
5419 
5420       debug (EVENT_PRINT) {
5421          cprintf("{ Event: onLayout - Control %.*s }\n", name);
5422       }
5423 
5424       Rect area;
5425       area = displayRectangle;
5426 
5427       foreach (Control ctrl; ccollection) {
5428          if (!ctrl.visible || !ctrl.created) {
5429             continue;
5430          }
5431          if (ctrl._rtype() & (2 | 4)) { // Mdichild | Tabpage
5432             continue;
5433          }
5434 
5435          //Rect prevctrlbounds;
5436          //prevctrlbounds = ctrl.bounds;
5437          //ctrl.suspendLayout(); // Note: exception could cause failure to restore.
5438          switch (ctrl.sdock) {
5439             case DockStyle.NONE:
5440                /+
5441                   if(ctrl.anch & (AnchorStyles.RIGHT | AnchorStyles.BOTTOM)) { // If none of these are set, no point in doing any anchor code.
5442                      Rect newb;
5443                      newb = ctrl.bounds;
5444                      if(ctrl.anch & AnchorStyles.RIGHT) {
5445                         if(ctrl.anch & AnchorStyles.LEFT) {
5446                            newb.width += bounds.width - originalBounds.width;
5447                         } else {
5448                            newb.x += bounds.width - originalBounds.width;
5449                         }
5450                      }
5451                      if(ctrl.anch & AnchorStyles.BOTTOM) {
5452                         if(ctrl.anch & AnchorStyles.LEFT) {
5453                            newb.height += bounds.height - originalBounds.height;
5454                         } else {
5455                            newb.y += bounds.height - originalBounds.height;
5456                         }
5457                      }
5458                      if(newb != ctrl.bounds) {
5459                         ctrl.bounds = newb;
5460                      }
5461                   }
5462                +/
5463                   break;
5464 
5465             case DockStyle.LEFT:
5466                ctrl.setBoundsCore(area.x, area.y, 0,
5467                      area.height, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT));
5468                area.x = area.x + ctrl.width;
5469                area.width = area.width - ctrl.width;
5470                break;
5471 
5472             case DockStyle.TOP:
5473                ctrl.setBoundsCore(area.x, area.y, area.width, 0,
5474                      cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH));
5475                area.y = area.y + ctrl.height;
5476                area.height = area.height - ctrl.height;
5477                break;
5478 
5479             case DockStyle.FILL:
5480                //ctrl.bounds(Rect(area.x, area.y, area.width, area.height));
5481                ctrl.bounds = area;
5482                // area = ?
5483                break;
5484 
5485             case DockStyle.BOTTOM:
5486                ctrl.setBoundsCore(area.x,
5487                      area.bottom - ctrl.height, area.width, 0,
5488                      cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH));
5489                area.height = area.height - ctrl.height;
5490                break;
5491 
5492             case DockStyle.RIGHT:
5493                ctrl.setBoundsCore(area.right - ctrl.width,
5494                      area.y, 0, area.height,
5495                      cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT));
5496                area.width = area.width - ctrl.width;
5497                break;
5498 
5499             default:
5500                assert(0);
5501          }
5502          //ctrl.resumeLayout(true);
5503          //ctrl.resumeLayout(prevctrlbounds != ctrl.bounds);
5504       }
5505 
5506       layout(this, lea);
5507 
5508       //resumeLayout(false);
5509       cbits &= ~CBits.IN_LAYOUT;
5510    }
5511 
5512    /+
5513       // Not sure what to do here.
5514       deprecated bool isInputChar(char charCode) {
5515          return false;
5516       }
5517    +/
5518 
5519       void setVisibleCore(bool byes) {
5520          if (isHandleCreated) {
5521             //wstyle = GetWindowLongA(hwnd, GWL_STYLE);
5522             if (visible == byes) {
5523                return;
5524             }
5525 
5526             //ShowWindow(hwnd, byes ? SW_SHOW : SW_HIDE);
5527             if (byes) {
5528                doShow();
5529             } else {
5530                doHide();
5531             }
5532          } else {
5533             if (byes) {
5534                cbits |= CBits.VISIBLE;
5535                wstyle |= WS_VISIBLE;
5536                createControl();
5537             } else {
5538                cbits &= ~CBits.VISIBLE;
5539                wstyle &= ~WS_VISIBLE;
5540                return; // Not created and being hidden..
5541             }
5542          }
5543       }
5544 
5545    package final bool _wantTabKey() {
5546       if (ctrlStyle & ControlStyles.WANT_TAB_KEY) {
5547          return true;
5548       }
5549       return false;
5550    }
5551 
5552    // Return true if processed.
5553    protected bool processKeyEventArgs(ref Message msg) {
5554       switch (msg.msg) {
5555          case WM_KEYDOWN: {
5556                              scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys));
5557 
5558                              ushort repeat = msg.lParam & 0xFFFF; // First 16 bits.
5559                              for (; repeat; repeat--) {
5560                                 //kea.handled = false;
5561                                 onKeyDown(kea);
5562                              }
5563 
5564                              if (kea.handled) {
5565                                 return true;
5566                              }
5567                           }
5568                           break;
5569 
5570          case WM_KEYUP: {
5571                            // Repeat count is always 1 for key up.
5572                            scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys));
5573                            onKeyUp(kea);
5574                            if (kea.handled) {
5575                               return true;
5576                            }
5577                         }
5578                         break;
5579 
5580          case WM_CHAR: {
5581                           scope KeyPressEventArgs kpea = new KeyPressEventArgs(cast(dchar) msg.wParam,
5582                                 modifierKeys);
5583                           onKeyPress(kpea);
5584                           if (kpea.handled) {
5585                              return true;
5586                           }
5587                        }
5588                        break;
5589 
5590          default:
5591       }
5592 
5593       defWndProc(msg);
5594       return !msg.result;
5595    }
5596 
5597    package final bool _processKeyEventArgs(ref Message msg) {
5598       return processKeyEventArgs(msg);
5599    }
5600 
5601    /+
5602       bool processKeyPreview(ref Message m) {
5603          if(wparent) {
5604             return wparent.processKeyPreview(m);
5605          }
5606          return false;
5607       }
5608 
5609 
5610    protected bool processDialogChar(dchar charCode) {
5611       if(wparent) {
5612          return wparent.processDialogChar(charCode);
5613       }
5614       return false;
5615    }
5616    +/
5617 
5618       protected bool processMnemonic(dchar charCode) {
5619          return false;
5620       }
5621 
5622    package bool _processMnemonic(dchar charCode) {
5623       return processMnemonic(charCode);
5624    }
5625 
5626    // Retain DFL 0.9.5 compatibility.
5627    public deprecated void setDFL095() {
5628       version (SET_DFL_095) {
5629          pragma(msg, "DFL: DFL 0.9.5 compatibility set at compile time");
5630       } else {
5631          //_compat = CCompat.DFL095;
5632          Application.setCompat(DflCompat.CONTROL_RECREATE_095);
5633       }
5634    }
5635 
5636    private enum CCompat : ubyte {
5637       NONE = 0,
5638       DFL095 = 1,
5639    }
5640 
5641    version (SET_DFL_095)
5642       package enum _compat = CCompat.DFL095;
5643    else version (DFL_NO_COMPAT)
5644       package enum _compat = CCompat.NONE;
5645    else
5646       package @property CCompat _compat() {
5647          if (Application._compat & DflCompat.CONTROL_RECREATE_095) {
5648             return CCompat.DFL095;
5649          }
5650          return CCompat.NONE;
5651       }
5652 
5653    package final void _crecreate() {
5654       if (CCompat.DFL095 != _compat) {
5655          if (!recreatingHandle) {
5656             recreateHandle();
5657          }
5658       }
5659    }
5660 
5661 package:
5662    HWND hwnd;
5663    //AnchorStyles anch = cast(AnchorStyles)(AnchorStyles.TOP | AnchorStyles.LEFT);
5664    //bool cvalidation = true;
5665    version (DFL_NO_MENUS) {
5666    } else {
5667       ContextMenu cmenu;
5668    }
5669    DockStyle sdock = DockStyle.NONE;
5670    Dstring _ctrlname;
5671    Object otag;
5672    Color backc, forec;
5673    Rect wrect;
5674    //Rect oldwrect;
5675    Size wclientsz;
5676    Cursor wcurs;
5677    Font wfont;
5678    Control wparent;
5679    Region wregion;
5680    ControlCollection ccollection;
5681    Dstring wtext; // After creation, this isn't used unless ControlStyles.CACHE_TEXT.
5682    ControlStyles ctrlStyle = ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK /+ | ControlStyles.RESIZE_REDRAW +/ ;
5683    HBRUSH _hbrBg;
5684    RightToLeft rtol = RightToLeft.INHERIT;
5685    uint _disallowLayout = 0;
5686 
5687    version (DFL_NO_DRAG_DROP) {
5688    } else {
5689       DropTarget droptarget = null;
5690    }
5691 
5692    // Note: WS_VISIBLE is not reliable.
5693    LONG wstyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; // Child, visible and enabled by default.
5694    LONG wexstyle;
5695    LONG wclassStyle = WNDCLASS_STYLE;
5696 
5697    enum CBits : uint {
5698       NONE = 0x0,
5699       MENTER = 0x1, // Is mouse entered? Only valid if -trackMouseEvent- is non-null.
5700       KILLING = 0x2,
5701       OWNED = 0x4,
5702       //ALLOW_LAYOUT = 0x8,
5703       CLICKING = 0x10,
5704       NEED_CALC_SIZE = 0x20,
5705       SZDRAW = 0x40,
5706       OWNEDBG = 0x80,
5707       HANDLE_CREATED = 0x100, // debug only
5708       SW_SHOWN = 0x200,
5709       SW_HIDDEN = 0x400,
5710       CREATED = 0x800,
5711       NEED_INIT_LAYOUT = 0x1000,
5712       IN_LAYOUT = 0x2000,
5713       FVISIBLE = 0x4000,
5714       VISIBLE = 0x8000,
5715       NOCLOSING = 0x10000,
5716       ASCROLL = 0x20000,
5717       ASCALE = 0x40000,
5718       FORM = 0x80000,
5719       RECREATING = 0x100000,
5720       HAS_LAYOUT = 0x200000,
5721       VSTYLE = 0x400000, // If not forced off.
5722       FORMLOADED = 0x800000, // If not forced off.
5723       ENABLED = 0x1000000, // Enabled state, not considering the parent.
5724    }
5725 
5726    //CBits cbits = CBits.ALLOW_LAYOUT;
5727    //CBits cbits = CBits.NONE;
5728    CBits cbits = CBits.VISIBLE | CBits.VSTYLE | CBits.ENABLED;
5729 
5730 final:
5731 
5732    @property void menter(bool byes) {
5733       if (byes) {
5734          cbits |= CBits.MENTER;
5735       } else {
5736          cbits &= ~CBits.MENTER;
5737       }
5738    }
5739 
5740    @property bool menter() {
5741       return (cbits & CBits.MENTER) != 0;
5742    }
5743 
5744    @property void killing(bool byes) //{ if(byes) cbits |= CBits.KILLING; else cbits &= ~CBits.KILLING; }
5745 {
5746    assert(byes);
5747    if (byes) {
5748       cbits |= CBits.KILLING;
5749    }
5750 }
5751 
5752 @property bool killing() {
5753    return (cbits & CBits.KILLING) != 0;
5754 }
5755 
5756 @property void owned(bool byes) {
5757    if (byes) {
5758       cbits |= CBits.OWNED;
5759    } else {
5760       cbits &= ~CBits.OWNED;
5761    }
5762 }
5763 
5764 @property bool owned() {
5765    return (cbits & CBits.OWNED) != 0;
5766 }
5767 
5768 /+
5769 void _allowLayout(bool byes) {
5770    if(byes) {
5771       cbits |= CBits.ALLOW_LAYOUT;
5772    } else {
5773       cbits &= ~CBits.ALLOW_LAYOUT;
5774    }
5775 }
5776 bool _allowLayout() {
5777    return (cbits & CBits.ALLOW_LAYOUT) != 0;
5778 }
5779 +/
5780 
5781 @property void _clicking(bool byes) {
5782    if (byes) {
5783       cbits |= CBits.CLICKING;
5784    } else {
5785       cbits &= ~CBits.CLICKING;
5786    }
5787 }
5788 
5789 @property bool _clicking() {
5790    return (cbits & CBits.CLICKING) != 0;
5791 }
5792 
5793 @property void needCalcSize(bool byes) {
5794    if (byes) {
5795       cbits |= CBits.NEED_CALC_SIZE;
5796    } else {
5797       cbits &= ~CBits.NEED_CALC_SIZE;
5798    }
5799 }
5800 
5801 @property bool needCalcSize() {
5802    return (cbits & CBits.NEED_CALC_SIZE) != 0;
5803 }
5804 
5805 @property void szdraw(bool byes) {
5806    if (byes) {
5807       cbits |= CBits.SZDRAW;
5808    } else {
5809       cbits &= ~CBits.SZDRAW;
5810    }
5811 }
5812 
5813 @property bool szdraw() {
5814    return (cbits & CBits.SZDRAW) != 0;
5815 }
5816 
5817 @property void ownedbg(bool byes) {
5818    if (byes) {
5819       cbits |= CBits.OWNEDBG;
5820    } else {
5821       cbits &= ~CBits.OWNEDBG;
5822    }
5823 }
5824 
5825 @property bool ownedbg() {
5826    return (cbits & CBits.OWNEDBG) != 0;
5827 }
5828 
5829 debug {
5830    @property void _handlecreated(bool byes) {
5831       if (byes) {
5832          cbits |= CBits.HANDLE_CREATED;
5833       } else {
5834          cbits &= ~CBits.HANDLE_CREATED;
5835       }
5836    }
5837 
5838    @property bool _handlecreated() {
5839       return (cbits & CBits.HANDLE_CREATED) != 0;
5840    }
5841 }
5842 
5843 @property LONG _exStyle() {
5844    // return GetWindowLongA(hwnd, GWL_EXSTYLE);
5845    return wexstyle;
5846 }
5847 
5848 @property void _exStyle(LONG wl) {
5849    if (isHandleCreated) {
5850       SetWindowLongA(hwnd, GWL_EXSTYLE, wl);
5851    }
5852 
5853    wexstyle = wl;
5854 }
5855 
5856 @property LONG _style() {
5857    // return GetWindowLongA(hwnd, GWL_STYLE);
5858    return wstyle;
5859 }
5860 
5861 @property void _style(LONG wl) {
5862    if (isHandleCreated) {
5863       SetWindowLongA(hwnd, GWL_STYLE, wl);
5864    }
5865 
5866    wstyle = wl;
5867 }
5868 
5869 @property HBRUSH hbrBg() {
5870    if (_hbrBg) {
5871       return _hbrBg;
5872    }
5873    if (backc == Color.empty && parent && backColor == parent.backColor) {
5874       ownedbg = false;
5875       _hbrBg = parent.hbrBg;
5876       return _hbrBg;
5877    }
5878    hbrBg = backColor.createBrush(); // Call hbrBg's setter and set ownedbg.
5879    return _hbrBg;
5880 }
5881 
5882 @property void hbrBg(HBRUSH hbr)
5883    in {
5884       if (hbr) {
5885          assert(!_hbrBg);
5886       }
5887    }
5888 body {
5889    _hbrBg = hbr;
5890    ownedbg = true;
5891 }
5892 
5893 void deleteThisBackgroundBrush() {
5894    if (_hbrBg) {
5895       if (ownedbg) {
5896          DeleteObject(_hbrBg);
5897       }
5898       _hbrBg = HBRUSH.init;
5899    }
5900 }
5901 
5902 LRESULT defwproc(UINT msg, WPARAM wparam, LPARAM lparam) {
5903    //return DefWindowProcA(hwnd, msg, wparam, lparam);
5904    return dfl.internal.utf.defWindowProc(hwnd, msg, wparam, lparam);
5905 }
5906 
5907 LONG _fetchClassLong() {
5908    return GetClassLongA(hwnd, GCL_STYLE);
5909 }
5910 
5911 LONG _classStyle() {
5912    // return GetClassLongA(hwnd, GCL_STYLE);
5913    // return wclassStyle;
5914 
5915    if (isHandleCreated) {
5916       // Always fetch because it's not guaranteed to be accurate.
5917       wclassStyle = _fetchClassLong();
5918    }
5919 
5920    return wclassStyle;
5921 }
5922 
5923 package void _classStyle(LONG cl) {
5924    if (isHandleCreated) {
5925       SetClassLongA(hwnd, GCL_STYLE, cl);
5926    }
5927 
5928    wclassStyle = cl;
5929 }
5930 }
5931 
5932 package abstract class ControlSuperClass : Control {
5933    // Call previous wndProc().
5934    abstract protected void prevWndProc(ref Message msg);
5935 
5936    protected override void wndProc(ref Message msg) {
5937       switch (msg.msg) {
5938          case WM_PAINT:
5939             RECT uprect;
5940             //GetUpdateRect(hwnd, &uprect, true);
5941             //onInvalidated(new InvalidateEventArgs(Rect(&uprect)));
5942 
5943             //if(!msg.wParam)
5944             GetUpdateRect(hwnd, &uprect, false); // Preserve.
5945 
5946             prevWndProc(msg);
5947 
5948             // Now fake a normal paint event...
5949 
5950             scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd));
5951             //scope Graphics gpx = new CommonGraphics(hwnd, msg.wParam ? cast(HDC)msg.wParam : GetDC(hwnd), msg.wParam ? false : true);
5952             HRGN hrgn;
5953 
5954             hrgn = CreateRectRgnIndirect(&uprect);
5955             SelectClipRgn(gpx.handle, hrgn);
5956             DeleteObject(hrgn);
5957 
5958             scope PaintEventArgs pea = new PaintEventArgs(gpx, Rect(&uprect));
5959 
5960             // Can't erase the background now, Windows just painted..
5961             //if(ps.fErase)
5962             //{
5963             // prepareDc(gpx.handle);
5964             // onPaintBackground(pea);
5965             //}
5966 
5967             prepareDc(gpx.handle);
5968             onPaint(pea);
5969             break;
5970 
5971          case WM_PRINTCLIENT:
5972             prevWndProc(msg);
5973 
5974             scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd));
5975             scope PaintEventArgs pea = new PaintEventArgs(gpx, Rect(Point(0, 0),
5976                      wclientsz));
5977 
5978             prepareDc(pea.graphics.handle);
5979             onPaint(pea);
5980             break;
5981 
5982          case WM_PRINT:
5983             Control.defWndProc(msg);
5984             break;
5985 
5986          case WM_ERASEBKGND:
5987             Control.wndProc(msg);
5988             break;
5989 
5990          case WM_NCACTIVATE:
5991          case WM_NCCALCSIZE:
5992          case WM_NCCREATE:
5993          case WM_NCPAINT:
5994             prevWndProc(msg);
5995             break;
5996 
5997          case WM_KEYDOWN:
5998          case WM_KEYUP:
5999          case WM_CHAR:
6000          case WM_SYSKEYDOWN:
6001          case WM_SYSKEYUP:
6002          case WM_SYSCHAR:
6003             //case WM_IMECHAR:
6004             super.wndProc(msg);
6005             return;
6006 
6007          default:
6008             prevWndProc(msg);
6009             super.wndProc(msg);
6010       }
6011    }
6012 
6013    override void defWndProc(ref Message m) {
6014       switch (m.msg) {
6015          case WM_KEYDOWN:
6016          case WM_KEYUP:
6017          case WM_CHAR:
6018          case WM_SYSKEYDOWN:
6019          case WM_SYSKEYUP:
6020          case WM_SYSCHAR:
6021             //case WM_IMECHAR: // ?
6022             prevWndProc(m);
6023             break;
6024 
6025          default:
6026       }
6027    }
6028 
6029    protected override void onPaintBackground(PaintEventArgs pea) {
6030       Message msg;
6031 
6032       msg.hWnd = handle;
6033       msg.msg = WM_ERASEBKGND;
6034       msg.wParam = cast(WPARAM) pea.graphics.handle;
6035 
6036       prevWndProc(msg);
6037 
6038       // Don't paint the background twice.
6039       //super.onPaintBackground(pea);
6040 
6041       // Event ?
6042       //paintBackground(this, pea);
6043    }
6044 }
6045 
6046 
6047 class ScrollableControl : Control {
6048 
6049    final @property Size autoScaleBaseSize() {
6050       return autossz;
6051    }
6052 
6053    final @property void autoScaleBaseSize(Size newSize)
6054       in {
6055          assert(newSize.width > 0);
6056          assert(newSize.height > 0);
6057       }
6058    body {
6059       autossz = newSize;
6060    }
6061 
6062    final @property void autoScale(bool byes) {
6063       if (byes) {
6064          cbits |= CBits.ASCALE;
6065       } else {
6066          cbits &= ~CBits.ASCALE;
6067       }
6068    }
6069 
6070    final @property bool autoScale() {
6071       return (cbits & CBits.ASCALE) == CBits.ASCALE;
6072    }
6073 
6074    final @property Point scrollPosition() {
6075       return Point(xspos, yspos);
6076    }
6077 
6078    static Size calcScale(Size area, Size toScale, Size fromScale) // package
6079 
6080 
6081 
6082       in {
6083          assert(fromScale.width);
6084          assert(fromScale.height);
6085       }
6086    body {
6087       area.width = cast(int)(
6088             cast(float) area.width / cast(float) fromScale.width * cast(float) toScale.width);
6089       area.height = cast(int)(
6090             cast(float) area.height / cast(float) fromScale.height * cast(float) toScale.height);
6091       return area;
6092    }
6093 
6094    Size calcScale(Size area, Size toScale) { // package
6095       return calcScale(area, toScale, DEFAULT_SCALE);
6096    }
6097 
6098    final void _scale(Size toScale) { // package
6099       bool first = true;
6100 
6101       // Note: doesn't get to-scale for nested scrollable-controls.
6102       void xscale(Control c, Size fromScale) {
6103          c.suspendLayout();
6104 
6105          if (first) {
6106             first = false;
6107             c.size = calcScale(c.size, toScale, fromScale);
6108          } else {
6109             Point pt;
6110             Size sz;
6111             sz = calcScale(Size(c.left, c.top), toScale, fromScale);
6112             pt = Point(sz.width, sz.height);
6113             sz = calcScale(c.size, toScale, fromScale);
6114             c.bounds = Rect(pt, sz);
6115          }
6116 
6117          if (c.hasChildren) {
6118             ScrollableControl scc;
6119             foreach (Control cc; c.controls) {
6120                scc = cast(ScrollableControl) cc;
6121                if (scc) {
6122                   if (scc.autoScale) { // ?
6123                      xscale(scc, scc.autoScaleBaseSize);
6124                      scc.autoScaleBaseSize = toScale;
6125                   }
6126                } else {
6127                   xscale(cc, fromScale);
6128                }
6129             }
6130          }
6131 
6132          //c.resumeLayout(true);
6133          c.resumeLayout(false); // Should still be perfectly proportionate if it was properly laid out before scaling.
6134       }
6135 
6136       xscale(this, autoScaleBaseSize);
6137       autoScaleBaseSize = toScale;
6138    }
6139 
6140    final void _scale() { // package
6141       return _scale(getAutoScaleSize());
6142    }
6143 
6144    override protected void onControlAdded(ControlEventArgs ea) {
6145       super.onControlAdded(ea);
6146 
6147       if (created) // ?
6148          if (isHandleCreated) {
6149             auto sc = cast(ScrollableControl) ea.control;
6150             if (sc) {
6151                if (sc.autoScale) {
6152                   sc._scale();
6153                }
6154             } else {
6155                if (autoScale) {
6156                   _scale();
6157                }
6158             }
6159          }
6160    }
6161 
6162    //override final Rect displayRectangle()
6163    override @property Rect displayRectangle() {
6164       Rect result = clientRectangle;
6165 
6166       // Subtract dock padding.
6167       result.x = result.x + dpad.left;
6168       result.width = result.width - dpad.right - dpad.left;
6169       result.y = result.y + dpad.top;
6170       result.height = result.height - dpad.bottom - dpad.top;
6171 
6172       // Add scroll width.
6173       if (scrollSize.width > clientSize.width) {
6174          result.width = result.width + (scrollSize.width - clientSize.width);
6175       }
6176       if (scrollSize.height > clientSize.height) {
6177          result.height = result.height + (scrollSize.height - clientSize.height);
6178       }
6179 
6180       // Adjust scroll position.
6181       result.location = Point(result.location.x - scrollPosition.x,
6182             result.location.y - scrollPosition.y);
6183 
6184       return result;
6185    }
6186 
6187    final @property void scrollSize(Size sz) {
6188       scrollsz = sz;
6189       _fixScrollBounds(); // Implies _adjustScrollSize().
6190    }
6191 
6192    final @property Size scrollSize() {
6193       return scrollsz;
6194    }
6195 
6196    class DockPaddingEdges {
6197       private:
6198 
6199          int _left, _top, _right, _bottom;
6200          int _all;
6201          //package void delegate() changed;
6202 
6203 final:
6204 
6205          void changed() {
6206             dpadChanged();
6207          }
6208 
6209       public:
6210 
6211          @property void all(int x) {
6212             _bottom = _right = _top = _left = _all = x;
6213 
6214             changed();
6215          }
6216 
6217          final @property int all() {
6218             return _all;
6219          }
6220 
6221          @property void left(int x) {
6222             _left = x;
6223 
6224             changed();
6225          }
6226 
6227          @property int left() {
6228             return _left;
6229          }
6230 
6231          @property void top(int x) {
6232             _top = x;
6233 
6234             changed();
6235          }
6236 
6237          @property int top() {
6238             return _top;
6239          }
6240 
6241          @property void right(int x) {
6242             _right = x;
6243 
6244             changed();
6245          }
6246 
6247          @property int right() {
6248             return _right;
6249          }
6250 
6251          @property void bottom(int x) {
6252             _bottom = x;
6253 
6254             changed();
6255          }
6256 
6257          @property int bottom() {
6258             return _bottom;
6259          }
6260    }
6261 
6262    final @property DockPaddingEdges dockPadding() {
6263       return dpad;
6264    }
6265 
6266    this() {
6267       super();
6268       _init();
6269    }
6270 
6271    enum DEFAULT_SCALE = Size(5, 13);
6272 
6273    final @property void hScroll(bool byes) {
6274       LONG wl = _style();
6275       if (byes) {
6276          wl |= WS_HSCROLL;
6277       } else {
6278          wl &= ~WS_HSCROLL;
6279       }
6280       _style(wl);
6281 
6282       if (isHandleCreated) {
6283          redrawEntire();
6284       }
6285    }
6286 
6287    final @property bool hScroll() {
6288       return (_style() & WS_HSCROLL) != 0;
6289    }
6290 
6291    final @property void vScroll(bool byes) {
6292       LONG wl = _style();
6293       if (byes) {
6294          wl |= WS_VSCROLL;
6295       } else {
6296          wl &= ~WS_VSCROLL;
6297       }
6298       _style(wl);
6299 
6300       if (isHandleCreated) {
6301          redrawEntire();
6302       }
6303    }
6304 
6305    final @property bool vScroll() {
6306       return (_style() & WS_VSCROLL) != 0;
6307    }
6308 
6309    protected:
6310 
6311    /*
6312       override void onLayout(LayoutEventArgs lea) {
6313       super.onLayout(lea);
6314       }
6315     */
6316 
6317    /*
6318       override void scaleCore(float width, float height) {
6319    // Might not want to call super.scaleCore().
6320    }
6321     */
6322 
6323    override void wndProc(ref Message m) {
6324       switch (m.msg) {
6325          case WM_VSCROLL: {
6326                              SCROLLINFO si = void;
6327                              si.cbSize = SCROLLINFO.sizeof;
6328                              si.fMask = SIF_ALL;
6329                              if (GetScrollInfo(m.hWnd, SB_VERT, &si)) {
6330                                 int delta, maxp;
6331                                 maxp = scrollSize.height - clientSize.height;
6332                                 switch (LOWORD(m.wParam)) {
6333                                    case SB_LINEDOWN:
6334                                       if (yspos >= maxp) {
6335                                          return;
6336                                       }
6337                                       delta = maxp - yspos;
6338                                       if (autossz.height < delta) {
6339                                          delta = autossz.height;
6340                                       }
6341                                       break;
6342                                    case SB_LINEUP:
6343                                       if (yspos <= 0) {
6344                                          return;
6345                                       }
6346                                       delta = yspos;
6347                                       if (autossz.height < delta) {
6348                                          delta = autossz.height;
6349                                       }
6350                                       delta = -delta;
6351                                       break;
6352                                    case SB_PAGEDOWN:
6353                                       if (yspos >= maxp) {
6354                                          return;
6355                                       }
6356                                       if (yspos >= maxp) {
6357                                          return;
6358                                       }
6359                                       delta = maxp - yspos;
6360                                       if (clientSize.height < delta) {
6361                                          delta = clientSize.height;
6362                                       }
6363                                       break;
6364                                    case SB_PAGEUP:
6365                                       if (yspos <= 0) {
6366                                          return;
6367                                       }
6368                                       delta = yspos;
6369                                       if (clientSize.height < delta) {
6370                                          delta = clientSize.height;
6371                                       }
6372                                       delta = -delta;
6373                                       break;
6374                                    case SB_THUMBTRACK:
6375                                    case SB_THUMBPOSITION:
6376                                       //delta = cast(int)HIWORD(m.wParam) - yspos; // Limited to 16-bits.
6377                                       delta = si.nTrackPos - yspos;
6378                                       break;
6379                                    case SB_BOTTOM:
6380                                       delta = maxp - yspos;
6381                                       break;
6382                                    case SB_TOP:
6383                                       delta = -yspos;
6384                                       break;
6385                                    default:
6386                                 }
6387                                 yspos += delta;
6388                                 SetScrollPos(m.hWnd, SB_VERT, yspos, TRUE);
6389                                 ScrollWindow(m.hWnd, 0, -delta, null, null);
6390                              }
6391                           }
6392                           break;
6393 
6394          case WM_HSCROLL: {
6395                              SCROLLINFO si = void;
6396                              si.cbSize = SCROLLINFO.sizeof;
6397                              si.fMask = SIF_ALL;
6398                              if (GetScrollInfo(m.hWnd, SB_HORZ, &si)) {
6399                                 int delta, maxp;
6400                                 maxp = scrollSize.width - clientSize.width;
6401                                 switch (LOWORD(m.wParam)) {
6402                                    case SB_LINERIGHT:
6403                                       if (xspos >= maxp) {
6404                                          return;
6405                                       }
6406                                       delta = maxp - xspos;
6407                                       if (autossz.width < delta) {
6408                                          delta = autossz.width;
6409                                       }
6410                                       break;
6411                                    case SB_LINELEFT:
6412                                       if (xspos <= 0) {
6413                                          return;
6414                                       }
6415                                       delta = xspos;
6416                                       if (autossz.width < delta) {
6417                                          delta = autossz.width;
6418                                       }
6419                                       delta = -delta;
6420                                       break;
6421                                    case SB_PAGERIGHT:
6422                                       if (xspos >= maxp) {
6423                                          return;
6424                                       }
6425                                       if (xspos >= maxp) {
6426                                          return;
6427                                       }
6428                                       delta = maxp - xspos;
6429                                       if (clientSize.width < delta) {
6430                                          delta = clientSize.width;
6431                                       }
6432                                       break;
6433                                    case SB_PAGELEFT:
6434                                       if (xspos <= 0) {
6435                                          return;
6436                                       }
6437                                       delta = xspos;
6438                                       if (clientSize.width < delta) {
6439                                          delta = clientSize.width;
6440                                       }
6441                                       delta = -delta;
6442                                       break;
6443                                    case SB_THUMBTRACK:
6444                                    case SB_THUMBPOSITION:
6445                                       //delta = cast(int)HIWORD(m.wParam) - xspos; // Limited to 16-bits.
6446                                       delta = si.nTrackPos - xspos;
6447                                       break;
6448                                    case SB_RIGHT:
6449                                       delta = maxp - xspos;
6450                                       break;
6451                                    case SB_LEFT:
6452                                       delta = -xspos;
6453                                       break;
6454                                    default:
6455                                 }
6456                                 xspos += delta;
6457                                 SetScrollPos(m.hWnd, SB_HORZ, xspos, TRUE);
6458                                 ScrollWindow(m.hWnd, -delta, 0, null, null);
6459                              }
6460                           }
6461                           break;
6462 
6463          default:
6464       }
6465 
6466       super.wndProc(m);
6467    }
6468 
6469    override void onMouseWheel(MouseEventArgs ea) {
6470       int maxp = scrollSize.height - clientSize.height;
6471       int delta;
6472 
6473       UINT wlines;
6474       if (!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &wlines, 0)) {
6475          wlines = 3;
6476       }
6477 
6478       if (ea.delta < 0) {
6479          if (yspos < maxp) {
6480             delta = maxp - yspos;
6481             if (autossz.height * wlines < delta) {
6482                delta = autossz.height * wlines;
6483             }
6484 
6485             yspos += delta;
6486             SetScrollPos(hwnd, SB_VERT, yspos, TRUE);
6487             ScrollWindow(hwnd, 0, -delta, null, null);
6488          }
6489       } else {
6490          if (yspos > 0) {
6491             delta = yspos;
6492             if (autossz.height * wlines < delta) {
6493                delta = autossz.height * wlines;
6494             }
6495             delta = -delta;
6496 
6497             yspos += delta;
6498             SetScrollPos(hwnd, SB_VERT, yspos, TRUE);
6499             ScrollWindow(hwnd, 0, -delta, null, null);
6500          }
6501       }
6502 
6503       super.onMouseWheel(ea);
6504    }
6505 
6506    override void onHandleCreated(EventArgs ea) {
6507       xspos = 0;
6508       yspos = 0;
6509 
6510       super.onHandleCreated(ea);
6511 
6512       //_adjustScrollSize(FALSE);
6513       if (hScroll || vScroll) {
6514          _adjustScrollSize(FALSE);
6515          recalcEntire(); // Need to recalc frame.
6516       }
6517    }
6518 
6519    override void onVisibleChanged(EventArgs ea) {
6520       if (visible) {
6521          _adjustScrollSize(FALSE);
6522       }
6523 
6524       super.onVisibleChanged(ea);
6525    }
6526 
6527    private void _fixScrollBounds() {
6528       if (hScroll || vScroll) {
6529          int ydiff = 0, xdiff = 0;
6530 
6531          if (yspos > scrollSize.height - clientSize.height) {
6532             ydiff = (clientSize.height + yspos) - scrollSize.height;
6533             yspos -= ydiff;
6534             if (yspos < 0) {
6535                ydiff += yspos;
6536                yspos = 0;
6537             }
6538          }
6539 
6540          if (xspos > scrollSize.width - clientSize.width) {
6541             xdiff = (clientSize.width + xspos) - scrollSize.width;
6542             xspos -= xdiff;
6543             if (xspos < 0) {
6544                xdiff += xspos;
6545                xspos = 0;
6546             }
6547          }
6548 
6549          if (isHandleCreated) {
6550             if (xdiff || ydiff) {
6551                ScrollWindow(hwnd, xdiff, ydiff, null, null);
6552             }
6553 
6554             _adjustScrollSize();
6555          }
6556       }
6557    }
6558 
6559    override void onResize(EventArgs ea) {
6560       super.onResize(ea);
6561 
6562       _fixScrollBounds();
6563    }
6564 
6565    private:
6566    //Size scrollmargin, scrollmin;
6567    //Point autoscrollpos;
6568    DockPaddingEdges dpad;
6569    Size autossz = DEFAULT_SCALE;
6570    Size scrollsz = Size(0, 0);
6571    int xspos = 0, yspos = 0;
6572 
6573    void _init() {
6574       dpad = new DockPaddingEdges;
6575       //dpad.changed = &dpadChanged;
6576    }
6577 
6578    void dpadChanged() {
6579       alayout(this);
6580    }
6581 
6582    void _adjustScrollSize(BOOL fRedraw = TRUE) {
6583       assert(isHandleCreated);
6584 
6585       if (!hScroll && !vScroll) {
6586          return;
6587       }
6588 
6589       SCROLLINFO si;
6590       //if(vScroll)
6591       {
6592          si.cbSize = SCROLLINFO.sizeof;
6593          si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
6594          si.nPos = yspos;
6595          si.nMin = 0;
6596          si.nMax = clientSize.height;
6597          si.nPage = clientSize.height;
6598          if (scrollSize.height > clientSize.height) {
6599             si.nMax = scrollSize.height;
6600          }
6601          if (si.nMax) {
6602             si.nMax--;
6603          }
6604          SetScrollInfo(hwnd, SB_VERT, &si, fRedraw);
6605       }
6606       //if(hScroll)
6607       {
6608          si.cbSize = SCROLLINFO.sizeof;
6609          si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
6610          si.nPos = xspos;
6611          si.nMin = 0;
6612          si.nMax = clientSize.width;
6613          si.nPage = clientSize.width;
6614          if (scrollSize.width > clientSize.width) {
6615             si.nMax = scrollSize.width;
6616          }
6617          if (si.nMax) {
6618             si.nMax--;
6619          }
6620          SetScrollInfo(hwnd, SB_HORZ, &si, fRedraw);
6621       }
6622    }
6623 }
6624 
6625 interface IContainerControl {
6626 
6627    @property Control activeControl();
6628 
6629    deprecated void activeControl(Control);
6630 
6631    deprecated bool activateControl(Control);
6632 }
6633 
6634 class ContainerControl : ScrollableControl, IContainerControl {
6635 
6636    @property Control activeControl() {
6637       /+
6638          HWND hwfocus, hw;
6639       hw = hwfocus = GetFocus();
6640       while(hw) {
6641          if(hw == this.hwnd) {
6642             return Control.fromChildHandle(hwfocus);
6643          }
6644          hw = GetParent(hw);
6645       }
6646       return null;
6647       +/
6648          Control ctrlfocus, ctrl;
6649       ctrl = ctrlfocus = Control.fromChildHandle(GetFocus());
6650       while (ctrl) {
6651          if (ctrl is this) {
6652             return ctrlfocus;
6653          }
6654          ctrl = ctrl.parent;
6655       }
6656       return null;
6657    }
6658 
6659    @property void activeControl(Control ctrl) {
6660       if (!activateControl(ctrl)) {
6661          throw new DflException("Unable to activate control");
6662       }
6663    }
6664 
6665    // Returns true if successfully activated.
6666    final bool activateControl(Control ctrl) {
6667       // Not sure if this is correct.
6668 
6669       if (!ctrl.canSelect) {
6670          return false;
6671       }
6672       //if(!SetActiveWindow(ctrl.handle))
6673       // return false;
6674       ctrl.select();
6675       return true;
6676    }
6677 
6678    final @property Form parentForm() {
6679       Control par;
6680       Form f;
6681 
6682       for (par = parent; par; par = par.parent) {
6683          f = cast(Form) par;
6684          if (f) {
6685             return f;
6686          }
6687       }
6688 
6689       return null;
6690    }
6691 
6692    /+
6693       final bool validate() {
6694          // ...
6695       }
6696    +/
6697 
6698       this() {
6699          super();
6700          _init();
6701       }
6702 
6703    /+
6704       // Used internally.
6705       this(HWND hwnd) {
6706          super(hwnd);
6707          _init();
6708       }
6709    +/
6710 
6711       private void _init() {
6712          //wexstyle |= WS_EX_CONTROLPARENT;
6713          ctrlStyle |= ControlStyles.CONTAINER_CONTROL;
6714       }
6715 
6716    protected:
6717    /*
6718       override bool processDialogChar(char charCode) {
6719    // Not sure if this is correct.
6720    return false;
6721    }
6722     */
6723 
6724    /*
6725       deprecated protected override bool processMnemonic(dchar charCode) {
6726       return false;
6727       }
6728 
6729 
6730       bool processTabKey(bool forward) {
6731       if(isHandleCreated) {
6732    //SendMessageA(hwnd, WM_NEXTDLGCTL, !forward, 0);
6733    //return true;
6734    select(true, forward);
6735    }
6736    return false;
6737    }
6738     */
6739 }
6740 
6741 import std.traits;
6742 import std.typecons;
6743 
6744 private template hasLocalAliasing(T...) {
6745    static if (!T.length) {
6746       enum hasLocalAliasing = false;
6747    } else
6748       enum hasLocalAliasing = std.traits.hasLocalAliasing!(T[0])
6749          || dfl.control.hasLocalAliasing!(T[1 .. $]);
6750 }
6751 
6752 shared class SharedControl {
6753    private:
6754       Control _ctrl;
6755 
6756       LPARAM makeParam(ARGS...)(void function(Control, ARGS) fn, Tuple!(ARGS)* args) if (ARGS.length) {
6757          static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
6758          static struct InvokeParam {
6759             void function(Control, ARGS) fn;
6760             ARGS args;
6761          }
6762 
6763          // FIX: alias malloc = dfl.internal.clib.malloc;
6764          // FIX: alias free = dfl.internal.clib.free;
6765 
6766          auto param = cast(InvokeParam*) malloc(InvokeParam.sizeof);
6767          param.fn = fn;
6768          param.args = args.field;
6769 
6770          if (!param) {
6771             throw new OomException();
6772          }
6773 
6774          auto p = cast(DflInvokeParam*) malloc(DflInvokeParam.sizeof);
6775 
6776          if (!p) {
6777             throw new OomException();
6778          }
6779 
6780          static void fnentry(Control c, size_t[] p) {
6781             auto param = cast(InvokeParam*) p[0];
6782             param.fn(c, param.args);
6783             free(param);
6784          }
6785 
6786          p.fp = &fnentry;
6787          p.nparams = 1;
6788          p.params[0] = cast(size_t) param;
6789 
6790          return cast(LPARAM) p;
6791       }
6792 
6793       LPARAM makeParamNoneArgs(void function(Control) fn) {
6794          static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
6795          // FIX: alias malloc = dfl.internal.clib.malloc;
6796          // FIX: alias free = dfl.internal.clib.free;
6797 
6798          auto p = cast(DflInvokeParam*) malloc(DflInvokeParam.sizeof);
6799 
6800          if (!p) {
6801             throw new OomException();
6802          }
6803 
6804          static void fnentry(Control c, size_t[] p) {
6805             auto fn = cast(void function(Control)) p[0];
6806             fn(c);
6807          }
6808 
6809          p.fp = &fnentry;
6810          p.nparams = 1;
6811          p.params[0] = cast(size_t) fn;
6812 
6813          return cast(LPARAM) p;
6814       }
6815 
6816    public:
6817 
6818       this(Control ctrl) {
6819          assert(ctrl);
6820          _ctrl = cast(shared) ctrl;
6821       }
6822 
6823       void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) if (ARGS.length
6824             && !hasLocalAliasing!(ARGS)) {
6825          auto ctrl = cast(Control) _ctrl;
6826          auto hwnd = ctrl.handle;
6827 
6828          if (!hwnd) {
6829             Control.badInvokeHandle();
6830          }
6831 
6832          auto t = tuple(args);
6833          auto p = makeParam(fn, &t);
6834          SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
6835       }
6836 
6837       void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) if (!ARGS.length) {
6838          auto ctrl = cast(Control) _ctrl;
6839          auto hwnd = ctrl.handle;
6840 
6841          if (!hwnd) {
6842             Control.badInvokeHandle();
6843          }
6844 
6845          auto p = makeParamNoneArgs(fn);
6846          SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
6847       }
6848 
6849       void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) if (
6850             ARGS.length && !hasLocalAliasing!(ARGS)) {
6851          auto ctrl = cast(Control) _ctrl;
6852          auto hwnd = ctrl.handle;
6853 
6854          if (!hwnd) {
6855             Control.badInvokeHandle();
6856          }
6857 
6858          auto t = tuple(args);
6859          auto p = makeParam(fn, &t);
6860          PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
6861       }
6862 
6863       void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args) if (!ARGS.length) {
6864          auto ctrl = cast(Control) _ctrl;
6865          auto hwnd = ctrl.handle;
6866 
6867          if (!hwnd) {
6868             Control.badInvokeHandle();
6869          }
6870 
6871          auto p = makeParamNoneArgs(fn);
6872          PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
6873       }
6874 }