1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 /// 6 module dfl.application; 7 8 private import dfl.internal.dlib, dfl.internal.clib; 9 10 private import dfl.base, dfl.form, dfl.internal.winapi, dfl.event; 11 private import dfl.control, dfl.drawing, dfl.label; 12 private import dfl.button, dfl.textbox, dfl.internal.wincom, dfl.environment; 13 private import dfl.internal.utf; 14 15 version(DFL_NO_RESOURCES) 16 { 17 } 18 else 19 { 20 private import dfl.resources; 21 } 22 23 version(DFL_NO_MENUS) 24 { 25 } 26 else 27 { 28 private import dfl.menu; 29 } 30 31 32 version = DFL_NO_ZOMBIE_FORM; 33 34 //debug = APP_PRINT; 35 //debug = SHOW_MESSAGE_INFO; // Slow. 36 37 debug(APP_PRINT) 38 { 39 pragma(msg, "DFL: debug app print"); 40 41 version(DFL_LIB) 42 static assert(0); 43 } 44 45 46 private extern(C) void abort(); 47 48 49 /// 50 class ApplicationContext // docmain 51 { 52 /// 53 this() 54 { 55 } 56 57 58 /// 59 // If onMainFormClose isn't overridden, the message 60 // loop terminates when the main form is destroyed. 61 this(Form mainForm) 62 { 63 mform = mainForm; 64 mainForm.closed ~= &onMainFormClosed; 65 } 66 67 68 /// 69 final @property void mainForm(Form mainForm) // setter 70 { 71 if(mform) 72 mform.closed.removeHandler(&onMainFormClosed); 73 74 mform = mainForm; 75 76 if(mainForm) 77 mainForm.closed ~= &onMainFormClosed; 78 } 79 80 /// ditto 81 final @property Form mainForm() nothrow // getter 82 { 83 return mform; 84 } 85 86 87 /// 88 Event!(Object, EventArgs) threadExit; 89 90 91 /// 92 final void exitThread() 93 { 94 exitThreadCore(); 95 } 96 97 98 protected: 99 100 /// 101 void exitThreadCore() 102 { 103 threadExit(this, EventArgs.empty); 104 //ExitThread(0); 105 } 106 107 108 /// 109 void onMainFormClosed(Object sender, EventArgs args) 110 { 111 exitThreadCore(); 112 } 113 114 115 private: 116 Form mform; // The context form. 117 } 118 119 120 private extern(Windows) nothrow 121 { 122 alias UINT function(LPCWSTR lpPathName, LPCWSTR lpPrefixString, UINT uUnique, 123 LPWSTR lpTempFileName) GetTempFileNameWProc; 124 alias DWORD function(DWORD nBufferLength, LPWSTR lpBuffer) GetTempPathWProc; 125 alias HANDLE function(PACTCTXW pActCtx) CreateActCtxWProc; 126 alias BOOL function(HANDLE hActCtx, ULONG_PTR* lpCookie) ActivateActCtxProc; 127 } 128 129 130 version(NO_WINDOWS_HUNG_WORKAROUND) 131 { 132 } 133 else 134 { 135 version = WINDOWS_HUNG_WORKAROUND; 136 } 137 138 139 // Compatibility with previous DFL versions. 140 // Set version=DFL_NO_COMPAT to disable. 141 enum DflCompat 142 { 143 NONE = 0, 144 145 // Adding to menus is the old way. 146 MENU_092 = 0x1, 147 148 // Controls don't recreate automatically when necessary. 149 CONTROL_RECREATE_095 = 0x2, 150 151 // Nothing. 152 CONTROL_KEYEVENT_096 = 0x4, 153 154 // When a Form is in showDialog, changing the dialogResult from NONE doesn't close the form. 155 FORM_DIALOGRESULT_096 = 0x8, 156 157 // Call onLoad/load and focus a control at old time. 158 FORM_LOAD_096 = 0x10, 159 160 // Parent controls now need to be container-controls; this removes that limit. 161 CONTROL_PARENT_096 = 0x20, 162 } 163 164 165 /// 166 final class Application // docmain 167 { 168 private this() {} 169 170 171 static: 172 173 /// 174 // Should be called before creating any controls. 175 // This is typically the first function called in main(). 176 // Does nothing if not supported. 177 void enableVisualStyles() 178 { 179 enum MANIFEST = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` "\r\n" 180 `<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">` "\r\n" 181 `<description>DFL manifest</description>` "\r\n" 182 `<dependency>` "\r\n" 183 `<dependentAssembly>` "\r\n" 184 `<assemblyIdentity ` 185 `type="win32" ` 186 `name="Microsoft.Windows.Common-Controls" ` 187 `version="6.0.0.0" ` 188 `processorArchitecture="X86" ` 189 `publicKeyToken="6595b64144ccf1df" ` 190 `language="*" ` 191 `/>` "\r\n" 192 `</dependentAssembly>` "\r\n" 193 `</dependency>` "\r\n" 194 `</assembly>` "\r\n"; 195 196 HMODULE kernel32; 197 kernel32 = GetModuleHandleA("kernel32.dll"); 198 //if(kernel32) 199 assert(kernel32); 200 { 201 CreateActCtxWProc createActCtxW; 202 createActCtxW = cast(CreateActCtxWProc)GetProcAddress(kernel32, "CreateActCtxW"); 203 if(createActCtxW) 204 { 205 GetTempPathWProc getTempPathW; 206 GetTempFileNameWProc getTempFileNameW; 207 ActivateActCtxProc activateActCtx; 208 209 getTempPathW = cast(GetTempPathWProc)GetProcAddress(kernel32, "GetTempPathW"); 210 assert(getTempPathW !is null); 211 getTempFileNameW = cast(GetTempFileNameWProc)GetProcAddress(kernel32, "GetTempFileNameW"); 212 assert(getTempFileNameW !is null); 213 activateActCtx = cast(ActivateActCtxProc)GetProcAddress(kernel32, "ActivateActCtx"); 214 assert(activateActCtx !is null); 215 216 DWORD pathlen; 217 wchar[MAX_PATH] pathbuf = void; 218 //if(pathbuf) 219 { 220 pathlen = getTempPathW(pathbuf.length, pathbuf.ptr); 221 if(pathlen) 222 { 223 DWORD manifestlen; 224 wchar[MAX_PATH] manifestbuf = void; 225 //if(manifestbuf) 226 { 227 manifestlen = getTempFileNameW(pathbuf.ptr, "dmf", 0, manifestbuf.ptr); 228 if(manifestlen) 229 { 230 HANDLE hf; 231 hf = CreateFileW(manifestbuf.ptr, GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, HANDLE.init); 232 if(hf != INVALID_HANDLE_VALUE) 233 { 234 DWORD written; 235 if(WriteFile(hf, MANIFEST.ptr, MANIFEST.length, &written, null)) 236 { 237 CloseHandle(hf); 238 239 ACTCTXW ac; 240 HANDLE hac; 241 242 ac.cbSize = ACTCTXW.sizeof; 243 //ac.dwFlags = 4; // ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID 244 ac.dwFlags = 0; 245 ac.lpSource = manifestbuf.ptr; 246 //ac.lpAssemblyDirectory = pathbuf; // ? 247 248 hac = createActCtxW(&ac); 249 if(hac != INVALID_HANDLE_VALUE) 250 { 251 ULONG_PTR ul; 252 activateActCtx(hac, &ul); 253 254 _initCommonControls(ICC_STANDARD_CLASSES); // Yes. 255 //InitCommonControls(); // No. Doesn't work with common controls version 6! 256 257 // Ensure the actctx is actually associated with the message queue... 258 PostMessageA(null, wmDfl, 0, 0); 259 { 260 MSG msg; 261 PeekMessageA(&msg, null, wmDfl, wmDfl, PM_REMOVE); 262 } 263 } 264 else 265 { 266 debug(APP_PRINT) 267 cprintf("CreateActCtxW failed.\n"); 268 } 269 } 270 else 271 { 272 CloseHandle(hf); 273 } 274 } 275 276 DeleteFileW(manifestbuf.ptr); 277 } 278 } 279 } 280 } 281 } 282 } 283 } 284 285 286 /+ 287 // /// 288 @property bool visualStyles() nothrow // getter 289 { 290 // IsAppThemed: 291 // "Do not call this function during DllMain or global objects contructors. 292 // This may cause invalid return values in Microsoft Windows Vista and may cause Windows XP to become unstable." 293 } 294 +/ 295 296 297 /// Path of the executable including its file name. 298 @property Dstring executablePath() // getter 299 { 300 return dfl.internal.utf.getModuleFileName(HMODULE.init); 301 } 302 303 304 /// Directory containing the executable. 305 @property Dstring startupPath() // getter 306 { 307 return pathGetDirName(dfl.internal.utf.getModuleFileName(HMODULE.init)); 308 } 309 310 311 // Used internally. 312 Dstring getSpecialPath(Dstring name) // package 313 { 314 HKEY hk; 315 if(ERROR_SUCCESS != RegOpenKeyA(HKEY_CURRENT_USER, 316 r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders".ptr, &hk)) 317 { 318 bad_path: 319 throw new DflException("Unable to obtain " ~ name ~ " directory information"); 320 } 321 scope(exit) 322 RegCloseKey(hk); 323 Dstring result; 324 result = regQueryValueString(hk, name); 325 if(!result.length) 326 goto bad_path; 327 return result; 328 } 329 330 331 /// Application data base directory path, usually `C:\Documents and Settings\<user>\Application Data`; this directory might not exist yet. 332 @property Dstring userAppDataBasePath() // getter 333 { 334 return getSpecialPath("AppData"); 335 } 336 337 338 /// 339 @property bool messageLoop() nothrow // getter 340 { 341 return (threadFlags & TF.RUNNING) != 0; 342 } 343 344 345 /// 346 void addMessageFilter(IMessageFilter mf) 347 { 348 //filters ~= mf; 349 350 IMessageFilter[] fs = filters; 351 fs ~= mf; 352 filters = fs; 353 } 354 355 /// ditto 356 void removeMessageFilter(IMessageFilter mf) 357 { 358 uint i; 359 for(i = 0; i != filters.length; i++) 360 { 361 if(mf is filters[i]) 362 { 363 if(!i) 364 filters = filters[1 .. filters.length]; 365 else if(i == filters.length - 1) 366 filters = filters[0 .. i]; 367 else 368 filters = filters[0 .. i] ~ filters[i + 1 .. filters.length]; 369 break; 370 } 371 } 372 } 373 374 375 package bool _doEvents(bool* keep) 376 { 377 if(threadFlags & (TF.STOP_RUNNING | TF.QUIT)) 378 return false; 379 380 try 381 { 382 Message msg; 383 384 //while(PeekMessageA(&msg._winMsg, HWND.init, 0, 0, PM_REMOVE)) 385 while(dfl.internal.utf.peekMessage(&msg._winMsg, HWND.init, 0, 0, PM_REMOVE)) 386 { 387 gotMessage(msg); 388 389 if(msg.msg == WM_QUIT) 390 { 391 threadFlags = threadFlags | TF.QUIT; 392 return false; 393 } 394 if(threadFlags & TF.STOP_RUNNING) 395 { 396 return false; 397 } 398 if(!*keep) 399 { 400 break; 401 } 402 } 403 404 // Execution continues after this so it's not idle. 405 } 406 catch(DThrowable e) 407 { 408 onThreadException(e); 409 } 410 411 return (threadFlags & TF.QUIT) == 0; 412 } 413 414 415 /// Process all messages in the message queue. Returns false if the application should exit. 416 bool doEvents() 417 { 418 bool keep = true; 419 return _doEvents(&keep); 420 } 421 422 /// ditto 423 bool doEvents(uint msDelay) 424 { 425 if(msDelay <= 3) 426 return doEvents(); 427 struct TMR { public import dfl.timer; } 428 scope tmr = new TMR.Timer(); 429 bool keep = true; 430 tmr.interval = msDelay; 431 tmr.tick ~= (TMR.Timer sender, EventArgs ea) { sender.stop(); keep = false; }; 432 tmr.start(); 433 while(keep) 434 { 435 Application.waitForEvent(); 436 if(!_doEvents(&keep)) 437 return false; 438 } 439 return true; 440 } 441 442 443 /// Run the application. 444 void run() 445 { 446 run(new ApplicationContext); 447 } 448 449 /// ditto 450 void run(void delegate() whileIdle) 451 { 452 run(new ApplicationContext, whileIdle); 453 } 454 455 /// ditto 456 void run(ApplicationContext appcon) 457 { 458 void whileIdle() 459 { 460 waitForEvent(); 461 } 462 463 464 run(appcon, &whileIdle); 465 } 466 467 /// ditto 468 // -whileIdle- is called repeatedly while there are no messages in the queue. 469 // Application.idle events are suppressed; however, the -whileIdle- handler 470 // may manually fire the Application.idle event. 471 void run(ApplicationContext appcon, void delegate() whileIdle) 472 { 473 if(threadFlags & TF.RUNNING) 474 { 475 //throw new DflException("Cannot have more than one message loop per thread"); 476 assert(0, "Cannot have more than one message loop per thread"); 477 } 478 479 if(threadFlags & TF.QUIT) 480 { 481 assert(0, "The application is shutting down"); 482 } 483 484 version(CUSTOM_MSG_HOOK) 485 { 486 HHOOK _msghook = SetWindowsHookExA(WH_CALLWNDPROCRET, &globalMsgHook, null, GetCurrentThreadId()); 487 if(!_msghook) 488 throw new DflException("Unable to get window messages"); 489 msghook = _msghook; 490 } 491 492 493 void threadJustExited(Object sender, EventArgs ea) 494 { 495 exitThread(); 496 } 497 498 499 ctx = appcon; 500 ctx.threadExit ~= &threadJustExited; 501 try 502 { 503 threadFlags = threadFlags | TF.RUNNING; 504 505 if(ctx.mainForm) 506 { 507 //ctx.mainForm.createControl(); 508 ctx.mainForm.show(); 509 } 510 511 for(;;) 512 { 513 try 514 { 515 still_running: 516 while(!(threadFlags & (TF.QUIT | TF.STOP_RUNNING))) 517 { 518 Message msg; 519 520 //while(PeekMessageA(&msg._winMsg, HWND.init, 0, 0, PM_REMOVE)) 521 while(dfl.internal.utf.peekMessage(&msg._winMsg, HWND.init, 0, 0, PM_REMOVE)) 522 { 523 gotMessage(msg); 524 525 if(msg.msg == WM_QUIT) 526 { 527 threadFlags = threadFlags | TF.QUIT; 528 break still_running; 529 } 530 531 if(threadFlags & (TF.QUIT | TF.STOP_RUNNING)) 532 break still_running; 533 } 534 535 whileIdle(); 536 } 537 538 // Stopped running. 539 threadExit(typeid(Application), EventArgs.empty); 540 threadFlags = threadFlags & ~(TF.RUNNING | TF.STOP_RUNNING); 541 return; 542 } 543 catch(DThrowable e) 544 { 545 onThreadException(e); 546 } 547 } 548 } 549 finally 550 { 551 threadFlags = threadFlags & ~(TF.RUNNING | TF.STOP_RUNNING); 552 553 ApplicationContext tctx; 554 tctx = ctx; 555 ctx = null; 556 557 version(CUSTOM_MSG_HOOK) 558 UnhookWindowsHookEx(msghook); 559 560 tctx.threadExit.removeHandler(&threadJustExited); 561 } 562 } 563 564 /// ditto 565 // Makes the form -mainForm- visible. 566 void run(Form mainForm, void delegate() whileIdle) 567 { 568 ApplicationContext appcon = new ApplicationContext(mainForm); 569 //mainForm.show(); // Interferes with -running-. 570 run(appcon, whileIdle); 571 } 572 573 /// ditto 574 void run(Form mainForm) 575 { 576 ApplicationContext appcon = new ApplicationContext(mainForm); 577 //mainForm.show(); // Interferes with -running-. 578 run(appcon); 579 } 580 581 582 /// 583 void exit() 584 { 585 PostQuitMessage(0); 586 } 587 588 589 /// Exit the thread's message loop and return from run. 590 // Actually only stops the current run() loop. 591 void exitThread() 592 { 593 threadFlags = threadFlags | TF.STOP_RUNNING; 594 } 595 596 597 // Will be null if not in a successful Application.run. 598 package @property ApplicationContext context() nothrow // getter 599 { 600 return ctx; 601 } 602 603 604 /// 605 HINSTANCE getInstance() 606 { 607 if(!hinst) 608 _initInstance(); 609 return hinst; 610 } 611 612 /// ditto 613 void setInstance(HINSTANCE inst) 614 { 615 if(hinst) 616 { 617 if(inst != hinst) 618 throw new DflException("Instance is already set"); 619 return; 620 } 621 622 if(inst) 623 { 624 _initInstance(inst); 625 } 626 else 627 { 628 _initInstance(); // ? 629 } 630 } 631 632 633 // ApartmentState oleRequired() ... 634 635 636 private static class ErrForm: Form 637 { 638 protected override void onLoad(EventArgs ea) 639 { 640 okBtn.focus(); 641 } 642 643 644 protected override void onClosing(CancelEventArgs cea) 645 { 646 cea.cancel = !errdone; 647 } 648 649 650 enum PADDING = 10; 651 652 653 void onOkClick(Object sender, EventArgs ea) 654 { 655 errdone = true; 656 ctnu = true; 657 //close(); 658 dispose(); 659 } 660 661 662 void onCancelClick(Object sender, EventArgs ea) 663 { 664 errdone = true; 665 ctnu = false; 666 //close(); 667 dispose(); 668 } 669 670 671 this(Dstring errmsg) 672 { 673 text = "Error"; 674 clientSize = Size(340, 150); 675 startPosition = FormStartPosition.CENTER_SCREEN; 676 formBorderStyle = FormBorderStyle.FIXED_DIALOG; 677 minimizeBox = false; 678 maximizeBox = false; 679 controlBox = false; 680 681 Label label; 682 with(label = new Label) 683 { 684 bounds = Rect(PADDING, PADDING, this.clientSize.width - PADDING * 2, 40); 685 label.text = "An application exception has occured. Click Continue to allow " 686 "the application to ignore this error and attempt to continue."; 687 parent = this; 688 } 689 690 with(errBox = new TextBox) 691 { 692 text = errmsg; 693 bounds = Rect(PADDING, 40 + PADDING, this.clientSize.width - PADDING * 2, 50); 694 errBox.backColor = this.backColor; 695 readOnly = true; 696 multiline = true; 697 parent = this; 698 } 699 700 with(okBtn = new Button) 701 { 702 width = 100; 703 location = Point(this.clientSize.width - width - PADDING - width - PADDING, 704 this.clientSize.height - height - PADDING); 705 text = "&Continue"; 706 parent = this; 707 click ~= &onOkClick; 708 } 709 acceptButton = okBtn; 710 711 with(new Button) 712 { 713 width = 100; 714 location = Point(this.clientSize.width - width - PADDING, 715 this.clientSize.height - height - PADDING); 716 text = "&Quit"; 717 parent = this; 718 click ~= &onCancelClick; 719 } 720 721 autoScale = true; 722 } 723 724 725 /+ 726 private int inThread2() 727 { 728 try 729 { 730 // Create in this thread so that it owns the handle. 731 assert(!isHandleCreated); 732 show(); 733 SetForegroundWindow(handle); 734 735 MSG msg; 736 assert(isHandleCreated); 737 // Using the unicode stuf here messes up the redrawing for some reason. 738 while(GetMessageA(&msg, HWND.init, 0, 0)) // TODO: unicode ? 739 //while(dfl.internal.utf.getMessage(&msg, HWND.init, 0, 0)) 740 { 741 if(!IsDialogMessageA(handle, &msg)) 742 //if(!dfl.internal.utf.isDialogMessage(handle, &msg)) 743 { 744 TranslateMessage(&msg); 745 DispatchMessageA(&msg); 746 //dfl.internal.utf.dispatchMessage(&msg); 747 } 748 749 if(!isHandleCreated) 750 break; 751 } 752 } 753 finally 754 { 755 dispose(); 756 assert(!isHandleCreated); 757 758 thread1 = null; 759 } 760 761 return 0; 762 } 763 764 private void tinThread2() { inThread2(); } 765 766 767 private Thread thread1; 768 769 bool doContinue() 770 { 771 assert(!isHandleCreated); 772 773 // Need to use a separate thread so that all the main thread's messages 774 // will be there still when the exception is recovered from. 775 // This is very important for some messages, such as socket events. 776 thread1 = Thread.getThis(); // Problems with DMD 2.x 777 Thread thd; 778 thd = new Thread(&inThread2); 779 thd.start(); 780 do 781 { 782 Sleep(200); 783 } 784 while(thread1); 785 786 return ctnu; 787 } 788 +/ 789 790 bool doContinue() 791 { 792 assert(!isHandleCreated); 793 794 show(); 795 796 Message msg; 797 for(;;) 798 { 799 WaitMessage(); 800 if(PeekMessageA(&msg._winMsg, handle, 0, 0, PM_REMOVE | PM_NOYIELD)) 801 { 802 /+ 803 //if(!IsDialogMessageA(handle, &msg._winMsg)) // Back to the old problems. 804 { 805 TranslateMessage(&msg._winMsg); 806 DispatchMessageA(&msg._winMsg); 807 } 808 +/ 809 gotMessage(msg); 810 } 811 812 if(!isHandleCreated) 813 break; 814 } 815 816 return ctnu; 817 } 818 819 820 override Dstring toString() 821 { 822 return errBox.text; 823 } 824 825 826 private: 827 bool errdone = false; 828 bool ctnu = false; 829 Button okBtn; 830 TextBox errBox; 831 } 832 833 834 /// 835 bool showDefaultExceptionDialog(Object e) 836 { 837 /+ 838 if(IDYES == MessageBoxA(null, 839 "An application exception has occured. Click Yes to allow\r\n" 840 "the application to ignore this error and attempt to continue.\r\n" 841 "Click No to quit the application.\r\n\r\n"~ 842 e.toString(), 843 null, MB_ICONWARNING | MB_TASKMODAL | MB_YESNO)) 844 { 845 except = false; 846 return; 847 } 848 +/ 849 850 //try 851 { 852 if((new ErrForm(getObjectString(e))).doContinue()) 853 { 854 return true; 855 } 856 } 857 /+ 858 catch 859 { 860 MessageBoxA(null, "Error displaying error message", "DFL", MB_ICONERROR | MB_TASKMODAL); 861 } 862 +/ 863 864 return false; 865 } 866 867 868 /// 869 void onThreadException(DThrowable e) nothrow 870 { 871 try 872 { 873 static bool except = false; 874 875 version(WINDOWS_HUNG_WORKAROUND) 876 { 877 version(WINDOWS_HUNG_WORKAROUND_NO_IGNORE) 878 { 879 } 880 else 881 { 882 if(cast(WindowsHungDflException)e) 883 return; 884 } 885 } 886 887 if(except) 888 { 889 cprintf("Error: %.*s\n", cast(int)getObjectString(e).length, getObjectString(e).ptr); 890 891 abort(); 892 return; 893 } 894 895 except = true; 896 //if(threadException.handlers.length) 897 if(threadException.hasHandlers) 898 { 899 threadException(typeid(Application), new ThreadExceptionEventArgs(e)); 900 except = false; 901 return; 902 } 903 else 904 { 905 // No thread exception handlers, display a dialog. 906 if(showDefaultExceptionDialog(e)) 907 { 908 except = false; 909 return; 910 } 911 } 912 //except = false; 913 914 //throw e; 915 cprintf("Error: %.*s\n", cast(int)getObjectString(e).length, getObjectString(e).ptr); 916 //exitThread(); 917 Environment.exit(EXIT_FAILURE); 918 } 919 catch (DThrowable e) 920 { 921 } 922 } 923 924 925 /// 926 Event!(Object, EventArgs) idle; // Finished processing and is now idle. 927 /// 928 Event!(Object, ThreadExceptionEventArgs) threadException; 929 /// 930 Event!(Object, EventArgs) threadExit; 931 932 933 /// 934 void addHotkey(Keys k,void delegate(Object sender, KeyEventArgs ea) dg) 935 { 936 if (auto pkid = k in hotkeyId) 937 { 938 immutable kid = *pkid; 939 hotkeyHandler[kid] ~= dg; 940 } 941 else 942 { 943 int kid = 0; 944 foreach (aak, aav; hotkeyHandler) 945 { 946 if (!aav.hasHandlers) 947 { 948 kid = aak; 949 break; 950 } 951 ++kid; 952 } 953 immutable mod = (k&Keys.MODIFIERS)>>16, 954 keycode = k&Keys.KEY_CODE; 955 if (RegisterHotKey(null, kid, mod, keycode)) 956 { 957 hotkeyId[k] = kid; 958 if (auto h = kid in hotkeyHandler) 959 { 960 *h ~= dg; 961 } 962 else 963 { 964 typeof(hotkeyHandler[kid]) e; 965 e ~= dg; 966 hotkeyHandler[kid] = e; 967 } 968 } 969 else 970 { 971 throw new DflException("Hotkey cannot resistered."); 972 } 973 } 974 } 975 976 977 /// 978 void removeHotkey(Keys k, void delegate(Object sender, KeyEventArgs ea) dg) 979 { 980 if (auto pkid = k in hotkeyId) 981 { 982 immutable kid = *pkid; 983 hotkeyHandler[kid].removeHandler(dg); 984 if (!hotkeyHandler[kid].hasHandlers) 985 { 986 if (UnregisterHotKey(null, kid) == 0) 987 { 988 throw new DflException("Hotkey cannot unresistered."); 989 } 990 hotkeyHandler.remove(kid); 991 hotkeyId.remove(k); 992 } 993 } 994 } 995 996 997 /// 998 void removeHotkey(Keys k) 999 { 1000 if (auto pkid = k in hotkeyId) 1001 { 1002 immutable kid = *pkid; 1003 foreach (hnd; hotkeyHandler[kid]) 1004 { 1005 hotkeyHandler[kid].removeHandler(hnd); 1006 } 1007 assert(!hotkeyHandler[kid].hasHandlers); 1008 if (UnregisterHotKey(null, kid) == 0) 1009 { 1010 throw new DflException("Hotkey cannot unresistered."); 1011 } 1012 hotkeyHandler.remove(kid); 1013 hotkeyId.remove(k); 1014 } 1015 } 1016 1017 1018 /// 1019 struct HotkeyRegister 1020 { 1021 static: 1022 /// 1023 alias void delegate(Object c, KeyEventArgs e) Handler; 1024 1025 1026 /// 1027 void addHandler(Keys k, Handler dg) 1028 { 1029 addHotkey(k, dg); 1030 } 1031 1032 1033 /// 1034 struct IndexedCatAssigner 1035 { 1036 Keys k; 1037 1038 1039 /// 1040 void opCatAssign(Handler dg) 1041 { 1042 addHandler(k, dg); 1043 } 1044 } 1045 1046 1047 /// 1048 IndexedCatAssigner opIndex(Keys k) 1049 { 1050 return IndexedCatAssigner(k); 1051 } 1052 1053 1054 /// 1055 void removeHandler(Keys k, Handler dg) 1056 { 1057 removeHotkey(k, dg); 1058 } 1059 1060 1061 /// 1062 void removeHandler(Keys k) 1063 { 1064 removeHotkey(k); 1065 } 1066 } 1067 1068 1069 /// helper 1070 HotkeyRegister hotkeys; 1071 1072 1073 static ~this() 1074 { 1075 foreach (key; hotkeyId.keys) 1076 { 1077 removeHotkey(key); 1078 } 1079 hotkeyId = null; 1080 } 1081 1082 // Returns null if not found. 1083 package Control lookupHwnd(HWND hwnd) nothrow 1084 { 1085 //if(hwnd in controls) 1086 // return controls[hwnd]; 1087 auto pc = hwnd in controls; 1088 if(pc) 1089 return *pc; 1090 return null; 1091 } 1092 1093 1094 // Also makes a great zombie. 1095 package void removeHwnd(HWND hwnd) 1096 { 1097 //delete controls[hwnd]; 1098 controls.remove(hwnd); 1099 } 1100 1101 1102 version(DFL_NO_ZOMBIE_FORM) 1103 { 1104 } 1105 else 1106 { 1107 package enum ZOMBIE_PROP = "DFL_Zombie"; 1108 1109 // Doesn't do any good since the child controls still reference this control. 1110 package void zombieHwnd(Control c) 1111 in 1112 { 1113 assert(c !is null); 1114 assert(c.isHandleCreated); 1115 assert(lookupHwnd(c.handle)); 1116 } 1117 body 1118 { 1119 SetPropA(c.handle, ZOMBIE_PROP.ptr, cast(HANDLE)cast(void*)c); 1120 removeHwnd(c.handle); 1121 } 1122 1123 1124 package void unzombieHwnd(Control c) 1125 in 1126 { 1127 assert(c !is null); 1128 assert(c.isHandleCreated); 1129 assert(!lookupHwnd(c.handle)); 1130 } 1131 body 1132 { 1133 RemovePropA(c.handle, ZOMBIE_PROP.ptr); 1134 controls[c.handle] = c; 1135 } 1136 1137 1138 // Doesn't need to be a zombie. 1139 package void zombieKill(Control c) 1140 in 1141 { 1142 assert(c !is null); 1143 } 1144 body 1145 { 1146 if(c.isHandleCreated) 1147 { 1148 RemovePropA(c.handle, ZOMBIE_PROP.ptr); 1149 } 1150 } 1151 } 1152 1153 1154 version(DFL_NO_MENUS) 1155 { 1156 } 1157 else 1158 { 1159 // Returns its new unique menu ID. 1160 package int addMenuItem(MenuItem menu) 1161 { 1162 if(nmenus == END_MENU_ID - FIRST_MENU_ID) 1163 throw new DflException("Out of menus"); 1164 1165 typeof(menus) tempmenus; 1166 1167 // TODO: sort menu IDs in 'menus' so that looking for free ID is much faster. 1168 1169 prevMenuID++; 1170 if(prevMenuID >= END_MENU_ID || prevMenuID <= FIRST_MENU_ID) 1171 { 1172 prevMenuID = FIRST_MENU_ID; 1173 previdloop: 1174 for(;;) 1175 { 1176 for(size_t iw; iw != nmenus; iw++) 1177 { 1178 MenuItem mi; 1179 mi = cast(MenuItem)menus[iw]; 1180 if(mi) 1181 { 1182 if(prevMenuID == mi._menuID) 1183 { 1184 prevMenuID++; 1185 continue previdloop; 1186 } 1187 } 1188 } 1189 break; 1190 } 1191 } 1192 tempmenus = cast(Menu*)dfl.internal.clib.realloc(menus, Menu.sizeof * (nmenus + 1)); 1193 if(!tempmenus) 1194 { 1195 //throw new OutOfMemory; 1196 throw new DflException("Out of memory"); 1197 } 1198 menus = tempmenus; 1199 1200 menus[nmenus++] = menu; 1201 1202 return prevMenuID; 1203 } 1204 1205 1206 package void addContextMenu(ContextMenu menu) 1207 { 1208 if(nmenus == END_MENU_ID - FIRST_MENU_ID) 1209 throw new DflException("Out of menus"); 1210 1211 typeof(menus) tempmenus; 1212 int idx; 1213 1214 idx = nmenus; 1215 nmenus++; 1216 tempmenus = cast(Menu*)dfl.internal.clib.realloc(menus, Menu.sizeof * nmenus); 1217 if(!tempmenus) 1218 { 1219 nmenus--; 1220 //throw new OutOfMemory; 1221 throw new DflException("Out of memory"); 1222 } 1223 menus = tempmenus; 1224 1225 menus[idx] = menu; 1226 } 1227 1228 1229 package void removeMenu(Menu menu) 1230 { 1231 uint idx; 1232 1233 for(idx = 0; idx != nmenus; idx++) 1234 { 1235 if(menus[idx] is menu) 1236 { 1237 goto found; 1238 } 1239 } 1240 return; 1241 1242 found: 1243 if(nmenus == 1) 1244 { 1245 dfl.internal.clib.free(menus); 1246 menus = null; 1247 nmenus--; 1248 } 1249 else 1250 { 1251 if(idx != nmenus - 1) 1252 menus[idx] = menus[nmenus - 1]; // Move last one in its place 1253 1254 nmenus--; 1255 menus = cast(Menu*)dfl.internal.clib.realloc(menus, Menu.sizeof * nmenus); 1256 assert(menus != null); // Memory shrink shouldn't be a problem. 1257 } 1258 } 1259 1260 1261 package MenuItem lookupMenuID(int menuID) 1262 { 1263 uint idx; 1264 MenuItem mi; 1265 1266 for(idx = 0; idx != nmenus; idx++) 1267 { 1268 mi = cast(MenuItem)menus[idx]; 1269 if(mi && mi._menuID == menuID) 1270 return mi; 1271 } 1272 return null; 1273 } 1274 1275 1276 package Menu lookupMenu(HMENU hmenu) 1277 { 1278 uint idx; 1279 1280 for(idx = 0; idx != nmenus; idx++) 1281 { 1282 if(menus[idx].handle == hmenu) 1283 return menus[idx]; 1284 } 1285 return null; 1286 } 1287 } 1288 1289 1290 package void creatingControl(Control ctrl) nothrow 1291 { 1292 TlsSetValue(tlsControl, cast(Control*)ctrl); 1293 } 1294 1295 1296 version(DFL_NO_RESOURCES) 1297 { 1298 } 1299 else 1300 { 1301 /// 1302 @property Resources resources() // getter 1303 { 1304 static Resources rc = null; 1305 1306 if(!rc) 1307 { 1308 synchronized 1309 { 1310 if(!rc) 1311 { 1312 rc = new Resources(getInstance()); 1313 } 1314 } 1315 } 1316 return rc; 1317 } 1318 } 1319 1320 1321 private UINT gctimer = 0; 1322 private DWORD gcinfo = 1; 1323 1324 1325 /// 1326 @property void autoCollect(bool byes) // setter 1327 { 1328 if(byes) 1329 { 1330 if(!autoCollect) 1331 { 1332 gcinfo = 1; 1333 } 1334 } 1335 else 1336 { 1337 if(autoCollect) 1338 { 1339 gcinfo = 0; 1340 KillTimer(HWND.init, gctimer); 1341 gctimer = 0; 1342 } 1343 } 1344 } 1345 1346 /// ditto 1347 @property bool autoCollect() nothrow // getter 1348 { 1349 return gcinfo > 0; 1350 } 1351 1352 1353 package void _waitMsg() 1354 { 1355 if(threadFlags & (TF.STOP_RUNNING | TF.QUIT)) 1356 return; 1357 1358 idle(typeid(Application), EventArgs.empty); 1359 WaitMessage(); 1360 } 1361 1362 package deprecated alias _waitMsg waitMsg; 1363 1364 1365 /// 1366 // Because waiting for an event enters an idle state, 1367 // this function fires the -idle- event. 1368 void waitForEvent() 1369 { 1370 if(!autoCollect) 1371 { 1372 _waitMsg(); 1373 return; 1374 } 1375 1376 if(1 == gcinfo) 1377 { 1378 gcinfo = gcinfo.max; 1379 assert(!gctimer); 1380 gctimer = SetTimer(HWND.init, 0, 200, &_gcTimeout); 1381 } 1382 1383 _waitMsg(); 1384 1385 if(GetTickCount() > gcinfo) 1386 { 1387 gcinfo = 1; 1388 } 1389 } 1390 1391 1392 version(DFL_NO_COMPAT) 1393 package enum _compat = DflCompat.NONE; 1394 else 1395 package DflCompat _compat = DflCompat.NONE; 1396 1397 1398 deprecated void setCompat(DflCompat dflcompat) 1399 { 1400 version(DFL_NO_COMPAT) 1401 { 1402 assert(0, "Compatibility disabled"); // version=DFL_NO_COMPAT 1403 } 1404 else 1405 { 1406 if(messageLoop) 1407 { 1408 assert(0, "setCompat"); // Called too late, must enable compatibility sooner. 1409 } 1410 1411 _compat |= dflcompat; 1412 } 1413 } 1414 1415 1416 private static size_t _doref(void* p, int by) 1417 { 1418 assert(1 == by || -1 == by); 1419 1420 size_t result; 1421 1422 synchronized 1423 { 1424 auto pref = p in _refs; 1425 if(pref) 1426 { 1427 size_t count; 1428 count = *pref; 1429 1430 assert(count || -1 != by); 1431 1432 if(-1 == by) 1433 count--; 1434 else 1435 count++; 1436 1437 if(!count) 1438 { 1439 result = 0; 1440 _refs.remove(p); 1441 } 1442 else 1443 { 1444 result = count; 1445 _refs[p] = count; 1446 } 1447 } 1448 else if(1 == by) 1449 { 1450 _refs[p] = 1; 1451 result = 1; 1452 } 1453 } 1454 1455 return result; 1456 } 1457 1458 1459 package size_t refCountInc(void* p) 1460 { 1461 return _doref(p, 1); 1462 } 1463 1464 1465 // Returns the new ref count. 1466 package size_t refCountDec(void* p) 1467 { 1468 return _doref(p, -1); 1469 } 1470 1471 1472 package void ppin(void* p) 1473 { 1474 dfl.internal.dlib.gcPin(p); 1475 } 1476 1477 1478 package void punpin(void* p) 1479 { 1480 dfl.internal.dlib.gcUnpin(p); 1481 } 1482 1483 1484 private: 1485 static: 1486 size_t[void*] _refs; 1487 IMessageFilter[] filters; 1488 DWORD tlsThreadFlags; 1489 DWORD tlsControl; 1490 DWORD tlsFilter; // IMessageFilter[]*. 1491 version(CUSTOM_MSG_HOOK) 1492 DWORD tlsHook; // HHOOK. 1493 Control[HWND] controls; 1494 HINSTANCE hinst; 1495 ApplicationContext ctx = null; 1496 int[Keys] hotkeyId; 1497 Event!(Object, KeyEventArgs)[int] hotkeyHandler; 1498 1499 version(DFL_NO_MENUS) 1500 { 1501 } 1502 else 1503 { 1504 // Menus. 1505 enum short FIRST_MENU_ID = 200; 1506 enum short END_MENU_ID = 10000; 1507 1508 // Controls. 1509 enum ushort FIRST_CTRL_ID = END_MENU_ID + 1; 1510 enum ushort LAST_CTRL_ID = 65500; 1511 1512 1513 ushort prevMenuID = FIRST_MENU_ID; 1514 // malloc() is needed so the menus can be garbage collected. 1515 uint nmenus = 0; // Number of -menus-. 1516 Menu* menus = null; // WARNING: malloc()'d memory! 1517 1518 1519 // Destroy all menu handles at program exit because Windows will not 1520 // unless it is assigned to a window. 1521 // Note that this is probably just a 16bit issue, but it still appeared in the 32bit docs. 1522 private void sdtorFreeAllMenus() 1523 { 1524 foreach(Menu m; menus[0 .. nmenus]) 1525 { 1526 DestroyMenu(m.handle); 1527 } 1528 nmenus = 0; 1529 dfl.internal.clib.free(menus); 1530 menus = null; 1531 } 1532 } 1533 1534 1535 private struct TlsFilterValue 1536 { 1537 IMessageFilter[] filters; 1538 } 1539 1540 1541 /+ 1542 @property void filters(IMessageFilter[] filters) // setter 1543 { 1544 // The TlsFilterValue is being garbage collected! 1545 1546 TlsFilterValue* val = cast(TlsFilterValue*)TlsGetValue(tlsFilter); 1547 if(!val) 1548 val = new TlsFilterValue; 1549 val.filters = filters; 1550 TlsSetValue(tlsFilter, cast(LPVOID)val); 1551 } 1552 1553 1554 @property IMessageFilter[] filters() nothrow // getter 1555 { 1556 TlsFilterValue* val = cast(TlsFilterValue*)TlsGetValue(tlsFilter); 1557 if(!val) 1558 return null; 1559 return val.filters; 1560 } 1561 +/ 1562 1563 1564 version(CUSTOM_MSG_HOOK) 1565 { 1566 @property void msghook(HHOOK hhook) // setter 1567 { 1568 TlsSetValue(tlsHook, cast(LPVOID)hhook); 1569 } 1570 1571 1572 @property HHOOK msghook() nothrow // getter 1573 { 1574 return cast(HHOOK)TlsGetValue(tlsHook); 1575 } 1576 } 1577 1578 1579 Control getCreatingControl() nothrow 1580 { 1581 return cast(Control)cast(Control*)TlsGetValue(tlsControl); 1582 } 1583 1584 1585 // Thread flags. 1586 enum TF: DWORD 1587 { 1588 RUNNING = 1, // Application.run is in affect. 1589 STOP_RUNNING = 2, 1590 QUIT = 4, // Received WM_QUIT. 1591 } 1592 1593 1594 @property TF threadFlags() nothrow // getter 1595 { 1596 return cast(TF)cast(DWORD)TlsGetValue(tlsThreadFlags); 1597 } 1598 1599 1600 @property void threadFlags(TF flags) // setter 1601 { 1602 if(!TlsSetValue(tlsThreadFlags, cast(LPVOID)cast(DWORD)flags)) 1603 assert(0); 1604 } 1605 1606 1607 void gotMessage(ref Message msg) 1608 { 1609 //debug(SHOW_MESSAGE_INFO) 1610 // showMessageInfo(msg); 1611 void handleHotkey() 1612 { 1613 immutable kid = cast(int)msg.wParam, 1614 mod = cast(uint) (msg.lParam&0x0000ffff), 1615 keycode = cast(uint)((msg.lParam&0xffff0000)>>16); 1616 assert(kid < hotkeyHandler.length); 1617 hotkeyHandler[kid]( 1618 typeid(Application), 1619 new KeyEventArgs(cast(Keys)((mod << 16) | keycode))); 1620 } 1621 // Don't bother with this extra stuff if there aren't any filters. 1622 if(filters.length) 1623 { 1624 try 1625 { 1626 // Keep a local reference so that handlers 1627 // may be added and removed during filtering. 1628 IMessageFilter[] local = filters; 1629 1630 foreach(IMessageFilter mf; local) 1631 { 1632 // Returning true prevents dispatching. 1633 if(mf.preFilterMessage(msg)) 1634 { 1635 Control ctrl; 1636 ctrl = lookupHwnd(msg.hWnd); 1637 if(ctrl) 1638 { 1639 ctrl.mustWndProc(msg); 1640 } 1641 else if (msg.msg == WM_HOTKEY) 1642 { 1643 handleHotkey(); 1644 } 1645 return; 1646 } 1647 } 1648 } 1649 catch(DThrowable o) 1650 { 1651 Control ctrl; 1652 ctrl = lookupHwnd(msg.hWnd); 1653 if(ctrl) 1654 ctrl.mustWndProc(msg); 1655 throw o; 1656 } 1657 } 1658 if (msg.msg == WM_HOTKEY) 1659 { 1660 handleHotkey(); 1661 } 1662 TranslateMessage(&msg._winMsg); 1663 //DispatchMessageA(&msg._winMsg); 1664 dfl.internal.utf.dispatchMessage(&msg._winMsg); 1665 } 1666 } 1667 1668 1669 package: 1670 1671 1672 extern(Windows) void _gcTimeout(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) nothrow 1673 { 1674 KillTimer(hwnd, Application.gctimer); 1675 Application.gctimer = 0; 1676 1677 //cprintf("Auto-collecting\n"); 1678 dfl.internal.dlib.gcFullCollect(); 1679 1680 Application.gcinfo = GetTickCount() + 4000; 1681 } 1682 1683 1684 // Note: phobos-only. 1685 debug(SHOW_MESSAGE_INFO) 1686 { 1687 private import std.stdio, std.string; 1688 1689 1690 void showMessageInfo(ref Message m) 1691 { 1692 void writeWm(Dstring wmName) 1693 { 1694 writef("Message %s=%d(0x%X)\n", wmName, m.msg, m.msg); 1695 } 1696 1697 1698 switch(m.msg) 1699 { 1700 case WM_NULL: writeWm("WM_NULL"); break; 1701 case WM_CREATE: writeWm("WM_CREATE"); break; 1702 case WM_DESTROY: writeWm("WM_DESTROY"); break; 1703 case WM_MOVE: writeWm("WM_MOVE"); break; 1704 case WM_SIZE: writeWm("WM_SIZE"); break; 1705 case WM_ACTIVATE: writeWm("WM_ACTIVATE"); break; 1706 case WM_SETFOCUS: writeWm("WM_SETFOCUS"); break; 1707 case WM_KILLFOCUS: writeWm("WM_KILLFOCUS"); break; 1708 case WM_ENABLE: writeWm("WM_ENABLE"); break; 1709 case WM_SETREDRAW: writeWm("WM_SETREDRAW"); break; 1710 case WM_SETTEXT: writeWm("WM_SETTEXT"); break; 1711 case WM_GETTEXT: writeWm("WM_GETTEXT"); break; 1712 case WM_GETTEXTLENGTH: writeWm("WM_GETTEXTLENGTH"); break; 1713 case WM_PAINT: writeWm("WM_PAINT"); break; 1714 case WM_CLOSE: writeWm("WM_CLOSE"); break; 1715 case WM_QUERYENDSESSION: writeWm("WM_QUERYENDSESSION"); break; 1716 case WM_QUIT: writeWm("WM_QUIT"); break; 1717 case WM_QUERYOPEN: writeWm("WM_QUERYOPEN"); break; 1718 case WM_ERASEBKGND: writeWm("WM_ERASEBKGND"); break; 1719 case WM_SYSCOLORCHANGE: writeWm("WM_SYSCOLORCHANGE"); break; 1720 case WM_ENDSESSION: writeWm("WM_ENDSESSION"); break; 1721 case WM_SHOWWINDOW: writeWm("WM_SHOWWINDOW"); break; 1722 //case WM_WININICHANGE: writeWm("WM_WININICHANGE"); break; 1723 case WM_SETTINGCHANGE: writeWm("WM_SETTINGCHANGE"); break; 1724 case WM_DEVMODECHANGE: writeWm("WM_DEVMODECHANGE"); break; 1725 case WM_ACTIVATEAPP: writeWm("WM_ACTIVATEAPP"); break; 1726 case WM_FONTCHANGE: writeWm("WM_FONTCHANGE"); break; 1727 case WM_TIMECHANGE: writeWm("WM_TIMECHANGE"); break; 1728 case WM_CANCELMODE: writeWm("WM_CANCELMODE"); break; 1729 case WM_SETCURSOR: writeWm("WM_SETCURSOR"); break; 1730 case WM_MOUSEACTIVATE: writeWm("WM_MOUSEACTIVATE"); break; 1731 case WM_CHILDACTIVATE: writeWm("WM_CHILDACTIVATE"); break; 1732 case WM_QUEUESYNC: writeWm("WM_QUEUESYNC"); break; 1733 case WM_GETMINMAXINFO: writeWm("WM_GETMINMAXINFO"); break; 1734 case WM_NOTIFY: writeWm("WM_NOTIFY"); break; 1735 case WM_INPUTLANGCHANGEREQUEST: writeWm("WM_INPUTLANGCHANGEREQUEST"); break; 1736 case WM_INPUTLANGCHANGE: writeWm("WM_INPUTLANGCHANGE"); break; 1737 case WM_TCARD: writeWm("WM_TCARD"); break; 1738 case WM_HELP: writeWm("WM_HELP"); break; 1739 case WM_USERCHANGED: writeWm("WM_USERCHANGED"); break; 1740 case WM_NOTIFYFORMAT: writeWm("WM_NOTIFYFORMAT"); break; 1741 case WM_CONTEXTMENU: writeWm("WM_CONTEXTMENU"); break; 1742 case WM_STYLECHANGING: writeWm("WM_STYLECHANGING"); break; 1743 case WM_STYLECHANGED: writeWm("WM_STYLECHANGED"); break; 1744 case WM_DISPLAYCHANGE: writeWm("WM_DISPLAYCHANGE"); break; 1745 case WM_GETICON: writeWm("WM_GETICON"); break; 1746 case WM_SETICON: writeWm("WM_SETICON"); break; 1747 case WM_NCCREATE: writeWm("WM_NCCREATE"); break; 1748 case WM_NCDESTROY: writeWm("WM_NCDESTROY"); break; 1749 case WM_NCCALCSIZE: writeWm("WM_NCCALCSIZE"); break; 1750 case WM_NCHITTEST: writeWm("WM_NCHITTEST"); break; 1751 case WM_NCPAINT: writeWm("WM_NCPAINT"); break; 1752 case WM_NCACTIVATE: writeWm("WM_NCACTIVATE"); break; 1753 case WM_GETDLGCODE: writeWm("WM_GETDLGCODE"); break; 1754 case WM_NCMOUSEMOVE: writeWm("WM_NCMOUSEMOVE"); break; 1755 case WM_NCLBUTTONDOWN: writeWm("WM_NCLBUTTONDOWN"); break; 1756 case WM_NCLBUTTONUP: writeWm("WM_NCLBUTTONUP"); break; 1757 case WM_NCLBUTTONDBLCLK: writeWm("WM_NCLBUTTONDBLCLK"); break; 1758 case WM_NCRBUTTONDOWN: writeWm("WM_NCRBUTTONDOWN"); break; 1759 case WM_NCRBUTTONUP: writeWm("WM_NCRBUTTONUP"); break; 1760 case WM_NCRBUTTONDBLCLK: writeWm("WM_NCRBUTTONDBLCLK"); break; 1761 case WM_NCMBUTTONDOWN: writeWm("WM_NCMBUTTONDOWN"); break; 1762 case WM_NCMBUTTONUP: writeWm("WM_NCMBUTTONUP"); break; 1763 case WM_NCMBUTTONDBLCLK: writeWm("WM_NCMBUTTONDBLCLK"); break; 1764 case WM_KEYDOWN: writeWm("WM_KEYDOWN"); break; 1765 case WM_KEYUP: writeWm("WM_KEYUP"); break; 1766 case WM_CHAR: writeWm("WM_CHAR"); break; 1767 case WM_DEADCHAR: writeWm("WM_DEADCHAR"); break; 1768 case WM_SYSKEYDOWN: writeWm("WM_SYSKEYDOWN"); break; 1769 case WM_SYSKEYUP: writeWm("WM_SYSKEYUP"); break; 1770 case WM_SYSCHAR: writeWm("WM_SYSCHAR"); break; 1771 case WM_SYSDEADCHAR: writeWm("WM_SYSDEADCHAR"); break; 1772 case WM_IME_STARTCOMPOSITION: writeWm("WM_IME_STARTCOMPOSITION"); break; 1773 case WM_IME_ENDCOMPOSITION: writeWm("WM_IME_ENDCOMPOSITION"); break; 1774 case WM_IME_COMPOSITION: writeWm("WM_IME_COMPOSITION"); break; 1775 case WM_INITDIALOG: writeWm("WM_INITDIALOG"); break; 1776 case WM_COMMAND: writeWm("WM_COMMAND"); break; 1777 case WM_SYSCOMMAND: writeWm("WM_SYSCOMMAND"); break; 1778 case WM_TIMER: writeWm("WM_TIMER"); break; 1779 case WM_HSCROLL: writeWm("WM_HSCROLL"); break; 1780 case WM_VSCROLL: writeWm("WM_VSCROLL"); break; 1781 case WM_INITMENU: writeWm("WM_INITMENU"); break; 1782 case WM_INITMENUPOPUP: writeWm("WM_INITMENUPOPUP"); break; 1783 case WM_MENUSELECT: writeWm("WM_MENUSELECT"); break; 1784 case WM_MENUCHAR: writeWm("WM_MENUCHAR"); break; 1785 case WM_ENTERIDLE: writeWm("WM_ENTERIDLE"); break; 1786 case WM_CTLCOLORMSGBOX: writeWm("WM_CTLCOLORMSGBOX"); break; 1787 case WM_CTLCOLOREDIT: writeWm("WM_CTLCOLOREDIT"); break; 1788 case WM_CTLCOLORLISTBOX: writeWm("WM_CTLCOLORLISTBOX"); break; 1789 case WM_CTLCOLORBTN: writeWm("WM_CTLCOLORBTN"); break; 1790 case WM_CTLCOLORDLG: writeWm("WM_CTLCOLORDLG"); break; 1791 case WM_CTLCOLORSCROLLBAR: writeWm("WM_CTLCOLORSCROLLBAR"); break; 1792 case WM_CTLCOLORSTATIC: writeWm("WM_CTLCOLORSTATIC"); break; 1793 case WM_MOUSEMOVE: writeWm("WM_MOUSEMOVE"); break; 1794 case WM_LBUTTONDOWN: writeWm("WM_LBUTTONDOWN"); break; 1795 case WM_LBUTTONUP: writeWm("WM_LBUTTONUP"); break; 1796 case WM_LBUTTONDBLCLK: writeWm("WM_LBUTTONDBLCLK"); break; 1797 case WM_RBUTTONDOWN: writeWm("WM_RBUTTONDOWN"); break; 1798 case WM_RBUTTONUP: writeWm("WM_RBUTTONUP"); break; 1799 case WM_RBUTTONDBLCLK: writeWm("WM_RBUTTONDBLCLK"); break; 1800 case WM_MBUTTONDOWN: writeWm("WM_MBUTTONDOWN"); break; 1801 case WM_MBUTTONUP: writeWm("WM_MBUTTONUP"); break; 1802 case WM_MBUTTONDBLCLK: writeWm("WM_MBUTTONDBLCLK"); break; 1803 case WM_PARENTNOTIFY: writeWm("WM_PARENTNOTIFY"); break; 1804 case WM_ENTERMENULOOP: writeWm("WM_ENTERMENULOOP"); break; 1805 case WM_EXITMENULOOP: writeWm("WM_EXITMENULOOP"); break; 1806 case WM_NEXTMENU: writeWm("WM_NEXTMENU"); break; 1807 case WM_SETFONT: writeWm("WM_SETFONT"); break; 1808 case WM_GETFONT: writeWm("WM_GETFONT"); break; 1809 case WM_USER: writeWm("WM_USER"); break; 1810 case WM_NEXTDLGCTL: writeWm("WM_NEXTDLGCTL"); break; 1811 case WM_CAPTURECHANGED: writeWm("WM_CAPTURECHANGED"); break; 1812 case WM_WINDOWPOSCHANGING: writeWm("WM_WINDOWPOSCHANGING"); break; 1813 case WM_WINDOWPOSCHANGED: writeWm("WM_WINDOWPOSCHANGED"); break; 1814 case WM_DRAWITEM: writeWm("WM_DRAWITEM"); break; 1815 case WM_CLEAR: writeWm("WM_CLEAR"); break; 1816 case WM_CUT: writeWm("WM_CUT"); break; 1817 case WM_COPY: writeWm("WM_COPY"); break; 1818 case WM_PASTE: writeWm("WM_PASTE"); break; 1819 case WM_MDITILE: writeWm("WM_MDITILE"); break; 1820 case WM_MDICASCADE: writeWm("WM_MDICASCADE"); break; 1821 case WM_MDIICONARRANGE: writeWm("WM_MDIICONARRANGE"); break; 1822 case WM_MDIGETACTIVE: writeWm("WM_MDIGETACTIVE"); break; 1823 case WM_MOUSEWHEEL: writeWm("WM_MOUSEWHEEL"); break; 1824 case WM_MOUSEHOVER: writeWm("WM_MOUSEHOVER"); break; 1825 case WM_MOUSELEAVE: writeWm("WM_MOUSELEAVE"); break; 1826 case WM_PRINT: writeWm("WM_PRINT"); break; 1827 case WM_PRINTCLIENT: writeWm("WM_PRINTCLIENT"); break; 1828 case WM_MEASUREITEM: writeWm("WM_MEASUREITEM"); break; 1829 1830 default: 1831 if(m.msg >= WM_USER && m.msg <= 0x7FFF) 1832 { 1833 writeWm("WM_USER+" ~ std..string.toString(m.msg - WM_USER)); 1834 } 1835 else if(m.msg >=0xC000 && m.msg <= 0xFFFF) 1836 { 1837 writeWm("RegisterWindowMessage"); 1838 } 1839 else 1840 { 1841 writeWm("?"); 1842 } 1843 } 1844 1845 Control ctrl; 1846 ctrl = Application.lookupHwnd(m.hWnd); 1847 writef("HWND=%d(0x%X) %s WPARAM=%d(0x%X) LPARAM=%d(0x%X)\n\n", 1848 cast(size_t)m.hWnd, cast(size_t)m.hWnd, 1849 ctrl ? ("DFLname='" ~ ctrl.name ~ "'") : "<nonDFL>", 1850 m.wParam, m.wParam, 1851 m.lParam, m.lParam); 1852 1853 debug(MESSAGE_PAUSE) 1854 { 1855 Sleep(50); 1856 } 1857 } 1858 } 1859 1860 1861 extern(Windows) LRESULT dflWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) nothrow 1862 { 1863 //cprintf("HWND %p; WM %d(0x%X); WPARAM %d(0x%X); LPARAM %d(0x%X);\n", hwnd, msg, msg, wparam, wparam, lparam, lparam); 1864 1865 if(msg == wmDfl) 1866 { 1867 switch(wparam) 1868 { 1869 case WPARAM_DFL_INVOKE: 1870 { 1871 InvokeData* pinv; 1872 pinv = cast(InvokeData*)lparam; 1873 try 1874 { 1875 pinv.result = pinv.dg(pinv.args); 1876 } 1877 catch(DThrowable e) 1878 { 1879 //Application.onThreadException(e); 1880 try 1881 { 1882 pinv.exception = e; 1883 } 1884 catch(DThrowable e2) 1885 { 1886 Application.onThreadException(e2); 1887 } 1888 } 1889 } 1890 return LRESULT_DFL_INVOKE; 1891 1892 case WPARAM_DFL_INVOKE_SIMPLE: 1893 { 1894 InvokeSimpleData* pinv; 1895 pinv = cast(InvokeSimpleData*)lparam; 1896 try 1897 { 1898 pinv.dg(); 1899 } 1900 catch(DThrowable e) 1901 { 1902 //Application.onThreadException(e); 1903 try 1904 { 1905 pinv.exception = e; 1906 } 1907 catch(DThrowable e2) 1908 { 1909 Application.onThreadException(e2); 1910 } 1911 } 1912 } 1913 return LRESULT_DFL_INVOKE; 1914 1915 case WPARAM_DFL_DELAY_INVOKE: 1916 try 1917 { 1918 (cast(void function())lparam)(); 1919 } 1920 catch(DThrowable e) 1921 { 1922 Application.onThreadException(e); 1923 } 1924 break; 1925 1926 case WPARAM_DFL_DELAY_INVOKE_PARAMS: 1927 { 1928 DflInvokeParam* p; 1929 p = cast(DflInvokeParam*)lparam; 1930 try 1931 { 1932 p.fp(Application.lookupHwnd(hwnd), p.params.ptr[0 .. p.nparams]); 1933 } 1934 catch(DThrowable e) 1935 { 1936 Application.onThreadException(e); 1937 } 1938 dfl.internal.clib.free(p); 1939 } 1940 break; 1941 1942 default: 1943 } 1944 } 1945 1946 Message dm = Message(hwnd, msg, wparam, lparam); 1947 Control ctrl; 1948 1949 debug(SHOW_MESSAGE_INFO) 1950 showMessageInfo(dm); 1951 1952 if(msg == WM_NCCREATE) 1953 { 1954 ctrl = Application.getCreatingControl(); 1955 if(!ctrl) 1956 { 1957 debug(APP_PRINT) 1958 cprintf("Unable to add window 0x%X.\n", hwnd); 1959 return dm.result; 1960 } 1961 Application.creatingControl(null); // Reset. 1962 1963 Application.controls[hwnd] = ctrl; 1964 ctrl.hwnd = hwnd; 1965 debug(APP_PRINT) 1966 cprintf("Added window 0x%X.\n", hwnd); 1967 1968 //ctrl.finishCreating(hwnd); 1969 goto do_msg; 1970 } 1971 1972 ctrl = Application.lookupHwnd(hwnd); 1973 1974 if(!ctrl) 1975 { 1976 // Zombie... 1977 //return 1; // Returns correctly for most messages. e.g. WM_QUERYENDSESSION, WM_NCACTIVATE. 1978 dm.result = 1; 1979 version(DFL_NO_ZOMBIE_FORM) 1980 { 1981 } 1982 else 1983 { 1984 ctrl = cast(Control)cast(void*)GetPropA(hwnd, Application.ZOMBIE_PROP.ptr); 1985 if(ctrl) 1986 ctrl.mustWndProc(dm); 1987 } 1988 return dm.result; 1989 } 1990 1991 if(ctrl) 1992 { 1993 do_msg: 1994 try 1995 { 1996 ctrl.mustWndProc(dm); 1997 if(!ctrl.preProcessMessage(dm)) 1998 ctrl._wndProc(dm); 1999 } 2000 catch (DThrowable e) 2001 { 2002 Application.onThreadException(e); 2003 } 2004 } 2005 return dm.result; 2006 } 2007 2008 2009 version(CUSTOM_MSG_HOOK) 2010 { 2011 alias CWPRETSTRUCT CustomMsg; 2012 2013 2014 // Needs to be re-entrant. 2015 extern(Windows) LRESULT globalMsgHook(int code, WPARAM wparam, LPARAM lparam) 2016 { 2017 if(code == HC_ACTION) 2018 { 2019 CustomMsg* msg = cast(CustomMsg*)lparam; 2020 Control ctrl; 2021 2022 switch(msg.message) 2023 { 2024 // ... 2025 } 2026 } 2027 2028 return CallNextHookEx(Application.msghook, code, wparam, lparam); 2029 } 2030 } 2031 else 2032 { 2033 /+ 2034 struct CustomMsg 2035 { 2036 HWND hwnd; 2037 UINT message; 2038 WPARAM wParam; 2039 LPARAM lParam; 2040 } 2041 +/ 2042 } 2043 2044 2045 enum LRESULT LRESULT_DFL_INVOKE = 0x95FADF; // Magic number. 2046 2047 2048 struct InvokeData 2049 { 2050 Object delegate(Object[]) dg; 2051 Object[] args; 2052 Object result; 2053 DThrowable exception = null; 2054 } 2055 2056 2057 struct InvokeSimpleData 2058 { 2059 void delegate() dg; 2060 DThrowable exception = null; 2061 } 2062 2063 2064 UINT wmDfl; 2065 2066 enum: WPARAM 2067 { 2068 WPARAM_DFL_INVOKE = 78, 2069 WPARAM_DFL_DELAY_INVOKE = 79, 2070 WPARAM_DFL_DELAY_INVOKE_PARAMS = 80, 2071 WPARAM_DFL_INVOKE_SIMPLE = 81, 2072 } 2073 2074 struct DflInvokeParam 2075 { 2076 void function(Control, size_t[]) fp; 2077 size_t nparams; 2078 size_t[1] params; 2079 } 2080 2081 2082 version(DFL_NO_WM_GETCONTROLNAME) 2083 { 2084 } 2085 else 2086 { 2087 UINT wmGetControlName; 2088 } 2089 2090 2091 extern(Windows) 2092 { 2093 alias BOOL function(LPTRACKMOUSEEVENT lpEventTrack) TrackMouseEventProc; 2094 alias BOOL function(HWND, COLORREF, BYTE, DWORD) SetLayeredWindowAttributesProc; 2095 2096 alias HTHEME function(HWND) GetWindowThemeProc; 2097 alias BOOL function(HTHEME hTheme, int iPartId, int iStateId) IsThemeBackgroundPartiallyTransparentProc; 2098 alias HRESULT function(HWND hwnd, HDC hdc, RECT* prc) DrawThemeParentBackgroundProc; 2099 alias void function(DWORD dwFlags) SetThemeAppPropertiesProc; 2100 } 2101 2102 2103 // Set version = SUPPORTS_MOUSE_TRACKING if it is guaranteed to be supported. 2104 TrackMouseEventProc trackMouseEvent; 2105 2106 // Set version = SUPPORTS_OPACITY if it is guaranteed to be supported. 2107 SetLayeredWindowAttributesProc setLayeredWindowAttributes; 2108 2109 /+ 2110 GetWindowThemeProc getWindowTheme; 2111 IsThemeBackgroundPartiallyTransparentProc isThemeBackgroundPartiallyTransparent; 2112 DrawThemeParentBackgroundProc drawThemeParentBackground; 2113 SetThemeAppPropertiesProc setThemeAppProperties; 2114 +/ 2115 2116 2117 enum CONTROL_CLASSNAME = "DFL_Control"; 2118 enum FORM_CLASSNAME = "DFL_Form"; 2119 enum TEXTBOX_CLASSNAME = "DFL_TextBox"; 2120 enum LISTBOX_CLASSNAME = "DFL_ListBox"; 2121 //enum LABEL_CLASSNAME = "DFL_Label"; 2122 enum BUTTON_CLASSNAME = "DFL_Button"; 2123 enum MDICLIENT_CLASSNAME = "DFL_MdiClient"; 2124 enum RICHTEXTBOX_CLASSNAME = "DFL_RichTextBox"; 2125 enum COMBOBOX_CLASSNAME = "DFL_ComboBox"; 2126 enum TREEVIEW_CLASSNAME = "DFL_TreeView"; 2127 enum TABCONTROL_CLASSNAME = "DFL_TabControl"; 2128 enum LISTVIEW_CLASSNAME = "DFL_ListView"; 2129 enum STATUSBAR_CLASSNAME = "DFL_StatusBar"; 2130 enum PROGRESSBAR_CLASSNAME = "DFL_ProgressBar"; 2131 2132 WNDPROC textBoxPrevWndProc; 2133 WNDPROC listboxPrevWndProc; 2134 //WNDPROC labelPrevWndProc; 2135 WNDPROC buttonPrevWndProc; 2136 WNDPROC mdiclientPrevWndProc; 2137 WNDPROC richtextboxPrevWndProc; 2138 WNDPROC comboboxPrevWndProc; 2139 WNDPROC treeviewPrevWndProc; 2140 WNDPROC tabcontrolPrevWndProc; 2141 WNDPROC listviewPrevWndProc; 2142 WNDPROC statusbarPrevWndProc; 2143 WNDPROC progressbarPrevWndProc; 2144 2145 LONG textBoxClassStyle; 2146 LONG listboxClassStyle; 2147 //LONG labelClassStyle; 2148 LONG buttonClassStyle; 2149 LONG mdiclientClassStyle; 2150 LONG richtextboxClassStyle; 2151 LONG comboboxClassStyle; 2152 LONG treeviewClassStyle; 2153 LONG tabcontrolClassStyle; 2154 LONG listviewClassStyle; 2155 LONG statusbarClassStyle; 2156 LONG progressbarClassStyle; 2157 2158 HMODULE hmodRichtextbox; 2159 2160 // DMD 0.93: CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS is not an expression 2161 //enum UINT WNDCLASS_STYLE = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; 2162 //enum UINT WNDCLASS_STYLE = 11; 2163 2164 //enum UINT WNDCLASS_STYLE = CS_DBLCLKS; 2165 // DMD 0.106: CS_DBLCLKS is not an expression 2166 enum UINT WNDCLASS_STYLE = 0x0008; 2167 2168 2169 extern(Windows) 2170 { 2171 alias BOOL function(LPINITCOMMONCONTROLSEX lpInitCtrls) InitCommonControlsExProc; 2172 } 2173 2174 2175 // For this to work properly on Windows 95, Internet Explorer 4.0 must be installed. 2176 void _initCommonControls(DWORD dwControls) 2177 { 2178 version(SUPPORTS_COMMON_CONTROLS_EX) 2179 { 2180 pragma(msg, "DFL: extended common controls supported at compile time"); 2181 2182 alias InitCommonControlsEx initProc; 2183 } 2184 else 2185 { 2186 // Make sure InitCommonControlsEx() is in comctl32.dll, 2187 // otherwise use the old InitCommonControls(). 2188 2189 HMODULE hmodCommonControls; 2190 InitCommonControlsExProc initProc; 2191 2192 hmodCommonControls = LoadLibraryA("comctl32.dll"); 2193 if(!hmodCommonControls) 2194 // throw new DflException("Unable to load 'comctl32.dll'"); 2195 goto no_comctl32; 2196 2197 initProc = cast(InitCommonControlsExProc)GetProcAddress(hmodCommonControls, "InitCommonControlsEx"); 2198 if(!initProc) 2199 { 2200 //FreeLibrary(hmodCommonControls); 2201 no_comctl32: 2202 InitCommonControls(); 2203 return; 2204 } 2205 } 2206 2207 INITCOMMONCONTROLSEX icce; 2208 icce.dwSize = INITCOMMONCONTROLSEX.sizeof; 2209 icce.dwICC = dwControls; 2210 initProc(&icce); 2211 } 2212 2213 2214 extern(C) 2215 { 2216 size_t C_refCountInc(void* p) 2217 { 2218 return Application._doref(p, 1); 2219 } 2220 2221 2222 // Returns the new ref count. 2223 size_t C_refCountDec(void* p) 2224 { 2225 return Application._doref(p, -1); 2226 } 2227 } 2228 2229 2230 static this() 2231 { 2232 dfl.internal.utf._utfinit(); 2233 2234 Application.tlsThreadFlags = TlsAlloc(); 2235 Application.tlsControl = TlsAlloc(); 2236 Application.tlsFilter = TlsAlloc(); 2237 version(CUSTOM_MSG_HOOK) 2238 Application.tlsHook = TlsAlloc(); 2239 2240 wmDfl = RegisterWindowMessageA("WM_DFL"); 2241 if(!wmDfl) 2242 wmDfl = WM_USER + 0x7CD; 2243 2244 version(DFL_NO_WM_GETCONTROLNAME) 2245 { 2246 } 2247 else 2248 { 2249 wmGetControlName = RegisterWindowMessageA("WM_GETCONTROLNAME"); 2250 } 2251 2252 //InitCommonControls(); // Done later. Needs to be linked with comctl32.lib. 2253 OleInitialize(null); // Needs to be linked with ole32.lib. 2254 2255 HMODULE user32 = GetModuleHandleA("user32.dll"); 2256 2257 version(SUPPORTS_MOUSE_TRACKING) 2258 { 2259 pragma(msg, "DFL: mouse tracking supported at compile time"); 2260 2261 trackMouseEvent = &TrackMouseEvent; 2262 } 2263 else 2264 { 2265 trackMouseEvent = cast(TrackMouseEventProc)GetProcAddress(user32, "TrackMouseEvent"); 2266 if(!trackMouseEvent) // Must be Windows 95; check if common controls has it (IE 5.5). 2267 trackMouseEvent = cast(TrackMouseEventProc)GetProcAddress(GetModuleHandleA("comctl32.dll"), "_TrackMouseEvent"); 2268 } 2269 2270 version(SUPPORTS_OPACITY) 2271 { 2272 pragma(msg, "DFL: opacity supported at compile time"); 2273 2274 setLayeredWindowAttributes = &SetLayeredWindowAttributes; 2275 } 2276 else 2277 { 2278 setLayeredWindowAttributes = cast(SetLayeredWindowAttributesProc)GetProcAddress(user32, "SetLayeredWindowAttributes"); 2279 } 2280 } 2281 2282 2283 static ~this() 2284 { 2285 version(DFL_NO_MENUS) 2286 { 2287 } 2288 else 2289 { 2290 Application.sdtorFreeAllMenus(); 2291 } 2292 2293 if(hmodRichtextbox) 2294 FreeLibrary(hmodRichtextbox); 2295 } 2296 2297 2298 void _unableToInit(Dstring what) 2299 { 2300 /+if(what.length > 4 2301 && what[0] == 'D' && what[1] == 'F' 2302 && what[2] == 'L' && what[3] == '_')+/ 2303 what = what[4 .. what.length]; 2304 throw new DflException("Unable to initialize " ~ what); 2305 } 2306 2307 2308 void _initInstance() 2309 { 2310 return _initInstance(GetModuleHandleA(null)); 2311 } 2312 2313 2314 void _initInstance(HINSTANCE inst) 2315 in 2316 { 2317 assert(!Application.hinst); 2318 assert(inst); 2319 } 2320 body 2321 { 2322 Application.hinst = inst; 2323 2324 dfl.internal.utf.WndClass wc; 2325 wc.wc.style = WNDCLASS_STYLE; 2326 wc.wc.hInstance = inst; 2327 wc.wc.lpfnWndProc = &dflWndProc; 2328 2329 // Control wndclass. 2330 wc.className = CONTROL_CLASSNAME; 2331 if(!dfl.internal.utf.registerClass(wc)) 2332 _unableToInit(CONTROL_CLASSNAME); 2333 2334 // Form wndclass. 2335 wc.wc.cbWndExtra = DLGWINDOWEXTRA; 2336 wc.className = FORM_CLASSNAME; 2337 if(!dfl.internal.utf.registerClass(wc)) 2338 _unableToInit(FORM_CLASSNAME); 2339 } 2340 2341 2342 extern(Windows) 2343 { 2344 void _initTextBox() 2345 { 2346 if(!textBoxPrevWndProc) 2347 { 2348 dfl.internal.utf.WndClass info; 2349 textBoxPrevWndProc = superClass(HINSTANCE.init, "EDIT", TEXTBOX_CLASSNAME, info); 2350 if(!textBoxPrevWndProc) 2351 _unableToInit(TEXTBOX_CLASSNAME); 2352 textBoxClassStyle = info.wc.style; 2353 } 2354 } 2355 2356 2357 void _initListbox() 2358 { 2359 if(!listboxPrevWndProc) 2360 { 2361 dfl.internal.utf.WndClass info; 2362 listboxPrevWndProc = superClass(HINSTANCE.init, "LISTBOX", LISTBOX_CLASSNAME, info); 2363 if(!listboxPrevWndProc) 2364 _unableToInit(LISTBOX_CLASSNAME); 2365 listboxClassStyle = info.wc.style; 2366 } 2367 } 2368 2369 2370 /+ 2371 void _initLabel() 2372 { 2373 if(!labelPrevWndProc) 2374 { 2375 dfl.internal.utf.WndClass info; 2376 labelPrevWndProc = superClass(HINSTANCE.init, "STATIC", LABEL_CLASSNAME, info); 2377 if(!labelPrevWndProc) 2378 _unableToInit(LABEL_CLASSNAME); 2379 labelClassStyle = info.wc.style; 2380 } 2381 } 2382 +/ 2383 2384 2385 void _initButton() 2386 { 2387 if(!buttonPrevWndProc) 2388 { 2389 dfl.internal.utf.WndClass info; 2390 buttonPrevWndProc = superClass(HINSTANCE.init, "BUTTON", BUTTON_CLASSNAME, info); 2391 if(!buttonPrevWndProc) 2392 _unableToInit(BUTTON_CLASSNAME); 2393 buttonClassStyle = info.wc.style; 2394 } 2395 } 2396 2397 2398 void _initMdiclient() 2399 { 2400 if(!mdiclientPrevWndProc) 2401 { 2402 dfl.internal.utf.WndClass info; 2403 mdiclientPrevWndProc = superClass(HINSTANCE.init, "MDICLIENT", MDICLIENT_CLASSNAME, info); 2404 if(!mdiclientPrevWndProc) 2405 _unableToInit(MDICLIENT_CLASSNAME); 2406 mdiclientClassStyle = info.wc.style; 2407 } 2408 } 2409 2410 2411 void _initRichtextbox() 2412 { 2413 if(!richtextboxPrevWndProc) 2414 { 2415 if(!hmodRichtextbox) 2416 { 2417 hmodRichtextbox = LoadLibraryA("riched20.dll"); 2418 if(!hmodRichtextbox) 2419 throw new DflException("Unable to load 'riched20.dll'"); 2420 } 2421 2422 Dstring classname; 2423 if(dfl.internal.utf.useUnicode) 2424 classname = "RichEdit20W"; 2425 else 2426 classname = "RichEdit20A"; 2427 2428 dfl.internal.utf.WndClass info; 2429 richtextboxPrevWndProc = superClass(HINSTANCE.init, classname, RICHTEXTBOX_CLASSNAME, info); 2430 if(!richtextboxPrevWndProc) 2431 _unableToInit(RICHTEXTBOX_CLASSNAME); 2432 richtextboxClassStyle = info.wc.style; 2433 } 2434 } 2435 2436 2437 void _initCombobox() 2438 { 2439 if(!comboboxPrevWndProc) 2440 { 2441 dfl.internal.utf.WndClass info; 2442 comboboxPrevWndProc = superClass(HINSTANCE.init, "COMBOBOX", COMBOBOX_CLASSNAME, info); 2443 if(!comboboxPrevWndProc) 2444 _unableToInit(COMBOBOX_CLASSNAME); 2445 comboboxClassStyle = info.wc.style; 2446 } 2447 } 2448 2449 2450 void _initTreeview() 2451 { 2452 if(!treeviewPrevWndProc) 2453 { 2454 _initCommonControls(ICC_TREEVIEW_CLASSES); 2455 2456 dfl.internal.utf.WndClass info; 2457 treeviewPrevWndProc = superClass(HINSTANCE.init, "SysTreeView32", TREEVIEW_CLASSNAME, info); 2458 if(!treeviewPrevWndProc) 2459 _unableToInit(TREEVIEW_CLASSNAME); 2460 treeviewClassStyle = info.wc.style; 2461 } 2462 } 2463 2464 2465 void _initTabcontrol() 2466 { 2467 if(!tabcontrolPrevWndProc) 2468 { 2469 _initCommonControls(ICC_TAB_CLASSES); 2470 2471 dfl.internal.utf.WndClass info; 2472 tabcontrolPrevWndProc = superClass(HINSTANCE.init, "SysTabControl32", TABCONTROL_CLASSNAME, info); 2473 if(!tabcontrolPrevWndProc) 2474 _unableToInit(TABCONTROL_CLASSNAME); 2475 tabcontrolClassStyle = info.wc.style; 2476 } 2477 } 2478 2479 2480 void _initListview() 2481 { 2482 if(!listviewPrevWndProc) 2483 { 2484 _initCommonControls(ICC_LISTVIEW_CLASSES); 2485 2486 dfl.internal.utf.WndClass info; 2487 listviewPrevWndProc = superClass(HINSTANCE.init, "SysListView32", LISTVIEW_CLASSNAME, info); 2488 if(!listviewPrevWndProc) 2489 _unableToInit(LISTVIEW_CLASSNAME); 2490 listviewClassStyle = info.wc.style; 2491 } 2492 } 2493 2494 2495 void _initStatusbar() 2496 { 2497 if(!statusbarPrevWndProc) 2498 { 2499 _initCommonControls(ICC_WIN95_CLASSES); 2500 2501 dfl.internal.utf.WndClass info; 2502 statusbarPrevWndProc = superClass(HINSTANCE.init, "msctls_statusbar32", STATUSBAR_CLASSNAME, info); 2503 if(!statusbarPrevWndProc) 2504 _unableToInit(STATUSBAR_CLASSNAME); 2505 statusbarClassStyle = info.wc.style; 2506 } 2507 } 2508 2509 2510 void _initProgressbar() 2511 { 2512 if(!progressbarPrevWndProc) 2513 { 2514 _initCommonControls(ICC_PROGRESS_CLASS); 2515 2516 dfl.internal.utf.WndClass info; 2517 progressbarPrevWndProc = superClass(HINSTANCE.init, "msctls_progress32", PROGRESSBAR_CLASSNAME, info); 2518 if(!progressbarPrevWndProc) 2519 _unableToInit(PROGRESSBAR_CLASSNAME); 2520 progressbarClassStyle = info.wc.style; 2521 } 2522 } 2523 } 2524 2525 2526 WNDPROC _superClass(HINSTANCE hinst, Dstring className, Dstring newClassName, out WNDCLASSA getInfo) // deprecated 2527 { 2528 WNDPROC wndProc; 2529 2530 if(!GetClassInfoA(hinst, unsafeStringz(className), &getInfo)) // TODO: unicode. 2531 throw new DflException("Unable to obtain information for window class '" ~ className ~ "'"); 2532 2533 wndProc = getInfo.lpfnWndProc; 2534 getInfo.lpfnWndProc = &dflWndProc; 2535 2536 getInfo.style &= ~CS_GLOBALCLASS; 2537 getInfo.hCursor = HCURSOR.init; 2538 getInfo.lpszClassName = unsafeStringz(newClassName); 2539 getInfo.hInstance = Application.getInstance(); 2540 2541 if(!RegisterClassA(&getInfo)) // TODO: unicode. 2542 //throw new DflException("Unable to register window class '" ~ newClassName ~ "'"); 2543 return null; 2544 return wndProc; 2545 } 2546 2547 2548 public: 2549 2550 // Returns the old wndProc. 2551 // This is the old, unsafe, unicode-unfriendly function for superclassing. 2552 deprecated WNDPROC superClass(HINSTANCE hinst, Dstring className, Dstring newClassName, out WNDCLASSA getInfo) // package 2553 { 2554 return _superClass(hinst, className, newClassName, getInfo); 2555 } 2556 2557 2558 deprecated WNDPROC superClass(HINSTANCE hinst, Dstring className, Dstring newClassName) // package 2559 { 2560 WNDCLASSA info; 2561 return _superClass(hinst, className, newClassName, info); 2562 } 2563 2564 2565 // Returns the old wndProc. 2566 WNDPROC superClass(HINSTANCE hinst, Dstring className, Dstring newClassName, out dfl.internal.utf.WndClass getInfo) // package 2567 { 2568 WNDPROC wndProc; 2569 2570 if(!dfl.internal.utf.getClassInfo(hinst, className, getInfo)) 2571 throw new DflException("Unable to obtain information for window class '" ~ className ~ "'"); 2572 2573 wndProc = getInfo.wc.lpfnWndProc; 2574 getInfo.wc.lpfnWndProc = &dflWndProc; 2575 2576 getInfo.wc.style &= ~CS_GLOBALCLASS; 2577 getInfo.wc.hCursor = HCURSOR.init; 2578 getInfo.className = newClassName; 2579 getInfo.wc.hInstance = Application.getInstance(); 2580 2581 if(!dfl.internal.utf.registerClass(getInfo)) 2582 //throw new DflException("Unable to register window class '" ~ newClassName ~ "'"); 2583 return null; 2584 return wndProc; 2585 } 2586