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