├── .gitignore ├── LICENSE ├── README.md └── source ├── AsyncGuardDemo.dpr ├── AsyncGuardDemo.dproj ├── AsyncSearch.pas ├── Main.Form.dfm └── Main.Form.pas /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | *.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | *.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | *.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | *.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | *.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | *.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | 60 | # Delphi history and backups 61 | __history/ 62 | __recovery/ 63 | *.~* 64 | 65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 66 | *.stat 67 | 68 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss 69 | modules/ 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Uwe Raabe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AsncTasksInVclProjects 2 | 3 | This project provides the sources to th article *Async Tasks in VCL Projects*: https://www.uweraabe.de/Blog/2021/11/07/async-tasks-in-vcl-projects/ 4 | -------------------------------------------------------------------------------- /source/AsyncGuardDemo.dpr: -------------------------------------------------------------------------------- 1 | program AsyncGuardDemo; 2 | 3 | uses 4 | Vcl.Forms, 5 | Main.Form in 'Main.Form.pas' {SearchForm}, 6 | AsyncSearch in 'AsyncSearch.pas'; 7 | 8 | {$R *.res} 9 | 10 | begin 11 | Application.Initialize; 12 | Application.MainFormOnTaskbar := True; 13 | Application.CreateForm(TSearchForm, SearchForm); 14 | Application.Run; 15 | end. 16 | -------------------------------------------------------------------------------- /source/AsyncGuardDemo.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {9F2DE166-FF54-4BBA-9A22-5FEB86D8EB8D} 4 | 19.2 5 | VCL 6 | True 7 | Debug 8 | Win32 9 | 1 10 | Application 11 | AsyncGuardDemo.dpr 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | true 44 | Cfg_2 45 | true 46 | true 47 | 48 | 49 | .\$(Platform)\$(Config) 50 | .\$(Platform)\$(Config) 51 | false 52 | false 53 | false 54 | false 55 | false 56 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 57 | $(BDS)\bin\delphi_PROJECTICON.ico 58 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 59 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 60 | AsyncGuardDemo 61 | 62 | 63 | DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;fsDB27;vclFireDAC;emsclientfiredac;bindcompvclsmp;tethering;svnui;DataSnapFireDAC;FireDACADSDriver;frx27;DBXMSSQLDriver;fsTee27;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;ComPortDrv;inetdb;RaizeComponentsVcl;fs27;FmxTeeUI;emsedge;TMSVCLUIPackPkgWizDXE13;fmx;FireDACIBDriver;fmxdae;RaizeComponentsVclDb;vcledge;vclib;FireDACDBXDriver;dbexpress;IndyCore;TMSVCLUIPackPkgXlsDXE13;vclx;frxTee27;dsnap;emsclient;DataSnapCommon;FireDACCommon;Package16;bdertl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;TMSVCLUIPackPkgDXE13;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;frxDB27;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;PngComponents;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;madExcept_;VirtualTreesR;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;frxIntIOIndy27;TeeDB;FireDAC;madBasic_;emshosting;frxIntIO27;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;CodeSiteLoggingPkg;ibxpress;CodeSiteDBToolsPkg;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;madDisAsm_;DBXSybaseASADriver;ibxbindings;CustomIPTransport;vcldsnap;bindcomp;appanalytics;frxADO27;DBXInformixDriver;IndyIPClient;fsADO27;bindcompvcl;vcldbx;frxe27;TeeUI;dbxcds;VclSmp;frxDBX27;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage) 64 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 65 | Debug 66 | true 67 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 68 | 1033 69 | $(BDS)\bin\default_app.manifest 70 | 71 | 72 | DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;bindcompvclsmp;tethering;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;ComPortDrv;inetdb;RaizeComponentsVcl;FmxTeeUI;emsedge;fmx;FireDACIBDriver;fmxdae;RaizeComponentsVclDb;vcledge;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;TMSVCLUIPackPkgDXE13;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;PngComponents;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;VirtualTreesR;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;DBXSybaseASADriver;ibxbindings;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage) 73 | 74 | 75 | DEBUG;$(DCC_Define) 76 | true 77 | false 78 | true 79 | true 80 | true 81 | 82 | 83 | false 84 | true 85 | PerMonitorV2 86 | 87 | 88 | false 89 | RELEASE;$(DCC_Define) 90 | 0 91 | 0 92 | 93 | 94 | true 95 | PerMonitorV2 96 | 97 | 98 | 99 | MainSource 100 | 101 | 102 |
SearchForm
103 | dfm 104 |
105 | 106 | 107 | Cfg_2 108 | Base 109 | 110 | 111 | Base 112 | 113 | 114 | Cfg_1 115 | Base 116 | 117 |
118 | 119 | Delphi.Personality.12 120 | Application 121 | 122 | 123 | 124 | AsyncGuardDemo.dpr 125 | 126 | 127 | 128 | 129 | 130 | AsyncGuardDemo.exe 131 | true 132 | 133 | 134 | 135 | 136 | 1 137 | 138 | 139 | Contents\MacOS 140 | 1 141 | 142 | 143 | 0 144 | 145 | 146 | 147 | 148 | classes 149 | 1 150 | 151 | 152 | classes 153 | 1 154 | 155 | 156 | 157 | 158 | res\xml 159 | 1 160 | 161 | 162 | res\xml 163 | 1 164 | 165 | 166 | 167 | 168 | library\lib\armeabi-v7a 169 | 1 170 | 171 | 172 | 173 | 174 | library\lib\armeabi 175 | 1 176 | 177 | 178 | library\lib\armeabi 179 | 1 180 | 181 | 182 | 183 | 184 | library\lib\armeabi-v7a 185 | 1 186 | 187 | 188 | 189 | 190 | library\lib\mips 191 | 1 192 | 193 | 194 | library\lib\mips 195 | 1 196 | 197 | 198 | 199 | 200 | library\lib\armeabi-v7a 201 | 1 202 | 203 | 204 | library\lib\arm64-v8a 205 | 1 206 | 207 | 208 | 209 | 210 | library\lib\armeabi-v7a 211 | 1 212 | 213 | 214 | 215 | 216 | res\drawable 217 | 1 218 | 219 | 220 | res\drawable 221 | 1 222 | 223 | 224 | 225 | 226 | res\values 227 | 1 228 | 229 | 230 | res\values 231 | 1 232 | 233 | 234 | 235 | 236 | res\values-v21 237 | 1 238 | 239 | 240 | res\values-v21 241 | 1 242 | 243 | 244 | 245 | 246 | res\values 247 | 1 248 | 249 | 250 | res\values 251 | 1 252 | 253 | 254 | 255 | 256 | res\drawable 257 | 1 258 | 259 | 260 | res\drawable 261 | 1 262 | 263 | 264 | 265 | 266 | res\drawable-xxhdpi 267 | 1 268 | 269 | 270 | res\drawable-xxhdpi 271 | 1 272 | 273 | 274 | 275 | 276 | res\drawable-xxxhdpi 277 | 1 278 | 279 | 280 | res\drawable-xxxhdpi 281 | 1 282 | 283 | 284 | 285 | 286 | res\drawable-ldpi 287 | 1 288 | 289 | 290 | res\drawable-ldpi 291 | 1 292 | 293 | 294 | 295 | 296 | res\drawable-mdpi 297 | 1 298 | 299 | 300 | res\drawable-mdpi 301 | 1 302 | 303 | 304 | 305 | 306 | res\drawable-hdpi 307 | 1 308 | 309 | 310 | res\drawable-hdpi 311 | 1 312 | 313 | 314 | 315 | 316 | res\drawable-xhdpi 317 | 1 318 | 319 | 320 | res\drawable-xhdpi 321 | 1 322 | 323 | 324 | 325 | 326 | res\drawable-mdpi 327 | 1 328 | 329 | 330 | res\drawable-mdpi 331 | 1 332 | 333 | 334 | 335 | 336 | res\drawable-hdpi 337 | 1 338 | 339 | 340 | res\drawable-hdpi 341 | 1 342 | 343 | 344 | 345 | 346 | res\drawable-xhdpi 347 | 1 348 | 349 | 350 | res\drawable-xhdpi 351 | 1 352 | 353 | 354 | 355 | 356 | res\drawable-xxhdpi 357 | 1 358 | 359 | 360 | res\drawable-xxhdpi 361 | 1 362 | 363 | 364 | 365 | 366 | res\drawable-xxxhdpi 367 | 1 368 | 369 | 370 | res\drawable-xxxhdpi 371 | 1 372 | 373 | 374 | 375 | 376 | res\drawable-small 377 | 1 378 | 379 | 380 | res\drawable-small 381 | 1 382 | 383 | 384 | 385 | 386 | res\drawable-normal 387 | 1 388 | 389 | 390 | res\drawable-normal 391 | 1 392 | 393 | 394 | 395 | 396 | res\drawable-large 397 | 1 398 | 399 | 400 | res\drawable-large 401 | 1 402 | 403 | 404 | 405 | 406 | res\drawable-xlarge 407 | 1 408 | 409 | 410 | res\drawable-xlarge 411 | 1 412 | 413 | 414 | 415 | 416 | res\values 417 | 1 418 | 419 | 420 | res\values 421 | 1 422 | 423 | 424 | 425 | 426 | 1 427 | 428 | 429 | Contents\MacOS 430 | 1 431 | 432 | 433 | 0 434 | 435 | 436 | 437 | 438 | Contents\MacOS 439 | 1 440 | .framework 441 | 442 | 443 | Contents\MacOS 444 | 1 445 | .framework 446 | 447 | 448 | 0 449 | 450 | 451 | 452 | 453 | 1 454 | .dylib 455 | 456 | 457 | 1 458 | .dylib 459 | 460 | 461 | 1 462 | .dylib 463 | 464 | 465 | Contents\MacOS 466 | 1 467 | .dylib 468 | 469 | 470 | Contents\MacOS 471 | 1 472 | .dylib 473 | 474 | 475 | 0 476 | .dll;.bpl 477 | 478 | 479 | 480 | 481 | 1 482 | .dylib 483 | 484 | 485 | 1 486 | .dylib 487 | 488 | 489 | 1 490 | .dylib 491 | 492 | 493 | Contents\MacOS 494 | 1 495 | .dylib 496 | 497 | 498 | Contents\MacOS 499 | 1 500 | .dylib 501 | 502 | 503 | 0 504 | .bpl 505 | 506 | 507 | 508 | 509 | 0 510 | 511 | 512 | 0 513 | 514 | 515 | 0 516 | 517 | 518 | 0 519 | 520 | 521 | 0 522 | 523 | 524 | Contents\Resources\StartUp\ 525 | 0 526 | 527 | 528 | Contents\Resources\StartUp\ 529 | 0 530 | 531 | 532 | 0 533 | 534 | 535 | 536 | 537 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 538 | 1 539 | 540 | 541 | 542 | 543 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 544 | 1 545 | 546 | 547 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 548 | 1 549 | 550 | 551 | 552 | 553 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 554 | 1 555 | 556 | 557 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 558 | 1 559 | 560 | 561 | 562 | 563 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 564 | 1 565 | 566 | 567 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 568 | 1 569 | 570 | 571 | 572 | 573 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 574 | 1 575 | 576 | 577 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 578 | 1 579 | 580 | 581 | 582 | 583 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 584 | 1 585 | 586 | 587 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 588 | 1 589 | 590 | 591 | 592 | 593 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 594 | 1 595 | 596 | 597 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 598 | 1 599 | 600 | 601 | 602 | 603 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 604 | 1 605 | 606 | 607 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 608 | 1 609 | 610 | 611 | 612 | 613 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 614 | 1 615 | 616 | 617 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 618 | 1 619 | 620 | 621 | 622 | 623 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 624 | 1 625 | 626 | 627 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 628 | 1 629 | 630 | 631 | 632 | 633 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 634 | 1 635 | 636 | 637 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 638 | 1 639 | 640 | 641 | 642 | 643 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 644 | 1 645 | 646 | 647 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 648 | 1 649 | 650 | 651 | 652 | 653 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 654 | 1 655 | 656 | 657 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 658 | 1 659 | 660 | 661 | 662 | 663 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 664 | 1 665 | 666 | 667 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 668 | 1 669 | 670 | 671 | 672 | 673 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 674 | 1 675 | 676 | 677 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 678 | 1 679 | 680 | 681 | 682 | 683 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 684 | 1 685 | 686 | 687 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 688 | 1 689 | 690 | 691 | 692 | 693 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 694 | 1 695 | 696 | 697 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 698 | 1 699 | 700 | 701 | 702 | 703 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 704 | 1 705 | 706 | 707 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 708 | 1 709 | 710 | 711 | 712 | 713 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 714 | 1 715 | 716 | 717 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 718 | 1 719 | 720 | 721 | 722 | 723 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 724 | 1 725 | 726 | 727 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 728 | 1 729 | 730 | 731 | 732 | 733 | 1 734 | 735 | 736 | 1 737 | 738 | 739 | 740 | 741 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 742 | 1 743 | 744 | 745 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 746 | 1 747 | 748 | 749 | 750 | 751 | ..\ 752 | 1 753 | 754 | 755 | ..\ 756 | 1 757 | 758 | 759 | 760 | 761 | 1 762 | 763 | 764 | 1 765 | 766 | 767 | 1 768 | 769 | 770 | 771 | 772 | ..\$(PROJECTNAME).launchscreen 773 | 64 774 | 775 | 776 | ..\$(PROJECTNAME).launchscreen 777 | 64 778 | 779 | 780 | 781 | 782 | 1 783 | 784 | 785 | 1 786 | 787 | 788 | 1 789 | 790 | 791 | 792 | 793 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 794 | 1 795 | 796 | 797 | 798 | 799 | ..\ 800 | 1 801 | 802 | 803 | ..\ 804 | 1 805 | 806 | 807 | 808 | 809 | Contents 810 | 1 811 | 812 | 813 | Contents 814 | 1 815 | 816 | 817 | 818 | 819 | Contents\Resources 820 | 1 821 | 822 | 823 | Contents\Resources 824 | 1 825 | 826 | 827 | 828 | 829 | library\lib\armeabi-v7a 830 | 1 831 | 832 | 833 | library\lib\arm64-v8a 834 | 1 835 | 836 | 837 | 1 838 | 839 | 840 | 1 841 | 842 | 843 | 1 844 | 845 | 846 | 1 847 | 848 | 849 | Contents\MacOS 850 | 1 851 | 852 | 853 | Contents\MacOS 854 | 1 855 | 856 | 857 | 0 858 | 859 | 860 | 861 | 862 | library\lib\armeabi-v7a 863 | 1 864 | 865 | 866 | 867 | 868 | 1 869 | 870 | 871 | 1 872 | 873 | 874 | 875 | 876 | Assets 877 | 1 878 | 879 | 880 | Assets 881 | 1 882 | 883 | 884 | 885 | 886 | Assets 887 | 1 888 | 889 | 890 | Assets 891 | 1 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | True 907 | False 908 | 909 | 910 | 911 | WinApi;System.Win;System;Data;Vcl 912 | 913 | 914 | 915 | 12 916 | 917 | 918 | 919 | 920 |
921 | -------------------------------------------------------------------------------- /source/AsyncSearch.pas: -------------------------------------------------------------------------------- 1 | unit AsyncSearch; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes; 7 | 8 | type 9 | ISearchTarget = interface 10 | procedure AddFiles(const AFiles: TArray); 11 | procedure BeginSearch; 12 | procedure EndSearch; 13 | end; 14 | 15 | type 16 | ICancel = interface 17 | procedure Cancel; 18 | function IsCancelled: Boolean; 19 | end; 20 | 21 | type 22 | TSearch = class 23 | type 24 | TCancel = class(TInterfacedObject, ICancel) 25 | private 26 | FSearch: TSearch; 27 | strict protected 28 | property Search: TSearch read FSearch implements ICancel; 29 | public 30 | constructor Create(ASearch: TSearch); 31 | destructor Destroy; override; 32 | end; 33 | private 34 | FCancelled: Boolean; 35 | FPath: string; 36 | FSearchPattern: string; 37 | FTarget: ISearchTarget; 38 | function IsCancelled: Boolean; 39 | procedure SearchFolder(const APath, ASearchPattern: string); 40 | strict protected 41 | procedure AddFiles(const AFiles: TArray); virtual; 42 | procedure BeginSearch; virtual; 43 | function CheckCancelled: Boolean; 44 | procedure EndSearch; virtual; 45 | procedure Execute(ACancel: ICancel); overload; virtual; 46 | public 47 | constructor Create(ATarget: ISearchTarget; const APath, ASearchPattern: string); 48 | procedure Cancel; 49 | procedure Execute; overload; 50 | class procedure Execute(ATarget: ISearchTarget; const APath, ASearchPattern: string; out ACancel: ICancel); overload; 51 | property Cancelled: Boolean read FCancelled; 52 | end; 53 | 54 | type 55 | TAsyncSearch = class(TSearch) 56 | strict protected 57 | procedure AddFiles(const AFiles: TArray); override; 58 | procedure BeginSearch; override; 59 | procedure EndSearch; override; 60 | procedure Execute(ACancel: ICancel); overload; override; 61 | public 62 | end; 63 | 64 | implementation 65 | 66 | uses 67 | System.IOUtils, System.Threading; 68 | 69 | constructor TSearch.Create(ATarget: ISearchTarget; const APath, ASearchPattern: string); 70 | begin 71 | inherited Create; 72 | Assert(ATarget <> nil, 'Target must not be nil!'); 73 | FTarget := ATarget; 74 | FPath := APath; 75 | FSearchPattern := ASearchPattern; 76 | end; 77 | 78 | procedure TSearch.AddFiles(const AFiles: TArray); 79 | begin 80 | if CheckCancelled then Exit; 81 | if Length(AFiles) = 0 then Exit; 82 | FTarget.AddFiles(AFiles); 83 | end; 84 | 85 | procedure TSearch.BeginSearch; 86 | begin 87 | if CheckCancelled then Exit; 88 | FTarget.BeginSearch; 89 | end; 90 | 91 | procedure TSearch.Cancel; 92 | begin 93 | FCancelled := True; 94 | end; 95 | 96 | function TSearch.CheckCancelled: Boolean; 97 | begin 98 | Result := FCancelled; 99 | if Result then 100 | FTarget := nil; 101 | end; 102 | 103 | procedure TSearch.EndSearch; 104 | begin 105 | if CheckCancelled then Exit; 106 | FTarget.EndSearch; 107 | end; 108 | 109 | procedure TSearch.Execute; 110 | begin 111 | BeginSearch; 112 | SearchFolder(FPath, FSearchPattern); 113 | EndSearch; 114 | end; 115 | 116 | class procedure TSearch.Execute(ATarget: ISearchTarget; const APath, ASearchPattern: string; out ACancel: ICancel); 117 | var 118 | instance: TSearch; 119 | begin 120 | instance := Self.Create(ATarget, APath, ASearchPattern); 121 | { TCancel is responsible for destroing instance } 122 | ACancel := TCancel.Create(instance); 123 | instance.Execute(ACancel); 124 | end; 125 | 126 | procedure TSearch.Execute(ACancel: ICancel); 127 | begin 128 | Execute; 129 | end; 130 | 131 | function TSearch.IsCancelled: Boolean; 132 | begin 133 | Result := FCancelled; 134 | end; 135 | 136 | procedure TSearch.SearchFolder(const APath, ASearchPattern: string); 137 | var 138 | arr: TArray; 139 | dir: string; 140 | begin 141 | arr := TDirectory.GetFiles(APath, ASearchPattern); 142 | AddFiles(arr); 143 | { release memory as early as possible } 144 | arr := nil; 145 | for dir in TDirectory.GetDirectories(APath) do begin 146 | if Cancelled then Exit; 147 | if not TDirectory.Exists(dir) then Continue; 148 | SearchFolder(dir, ASearchPattern); 149 | end; 150 | end; 151 | 152 | procedure TAsyncSearch.AddFiles(const AFiles: TArray); 153 | begin 154 | TThread.Synchronize(nil, procedure begin inherited; end); 155 | end; 156 | 157 | procedure TAsyncSearch.BeginSearch; 158 | begin 159 | TThread.Synchronize(nil, procedure begin inherited; end); 160 | end; 161 | 162 | procedure TAsyncSearch.EndSearch; 163 | begin 164 | TThread.Synchronize(nil, procedure begin inherited; end); 165 | end; 166 | 167 | procedure TAsyncSearch.Execute(ACancel: ICancel); 168 | begin 169 | TTask.Run( 170 | procedure 171 | begin 172 | { capture ACancel to keep the current during the lifetime of the async method } 173 | if not ACancel.IsCancelled then 174 | Execute; 175 | end); 176 | end; 177 | 178 | constructor TSearch.TCancel.Create(ASearch: TSearch); 179 | begin 180 | inherited Create; 181 | FSearch := ASearch; 182 | end; 183 | 184 | destructor TSearch.TCancel.Destroy; 185 | begin 186 | FSearch.Free; 187 | inherited Destroy; 188 | end; 189 | 190 | end. 191 | -------------------------------------------------------------------------------- /source/Main.Form.pas: -------------------------------------------------------------------------------- 1 | unit Main.Form; 2 | 3 | interface 4 | 5 | uses 6 | System.ImageList, System.Classes, System.Types, System.Diagnostics, 7 | Vcl.Forms, Vcl.ImgList, Vcl.VirtualImageList, Vcl.BaseImageCollection, Vcl.ImageCollection, Vcl.ExtCtrls, Vcl.StdCtrls, 8 | Vcl.WinXCtrls, Vcl.Controls, Vcl.ComCtrls, 9 | AsyncSearch; 10 | 11 | type 12 | TSearchForm = class(TForm, ISearchTarget) 13 | dspFiles: TListView; 14 | pnlTop: TPanel; 15 | edtSearchPattern: TSearchBox; 16 | lblSearchPattern: TLabel; 17 | lblRootFolder: TLabel; 18 | edtRootFolder: TButtonedEdit; 19 | imgCollection: TImageCollection; 20 | imgList: TVirtualImageList; 21 | btnNewSearchWindow: TButton; 22 | StatusBar: TStatusBar; 23 | procedure btnNewSearchWindowClick(Sender: TObject); 24 | procedure dspFilesData(Sender: TObject; Item: TListItem); 25 | procedure dspFilesDataFind(Sender: TObject; Find: TItemFind; const FindString: string; const FindPosition: TPoint; 26 | FindData: Pointer; StartIndex: Integer; Direction: TSearchDirection; Wrap: Boolean; var Index: Integer); 27 | procedure edtRootFolderRightButtonClick(Sender: TObject); 28 | procedure edtSearchPatternInvokeSearch(Sender: TObject); 29 | private 30 | FFiles: TStringList; 31 | FSearch: ICancel; 32 | FStopwatch: TStopwatch; 33 | class var 34 | FormIndex: Integer; 35 | function GetFiles: TStringList; 36 | procedure SelectRootFolder; 37 | procedure SetSearch(const Value: ICancel); 38 | procedure AddFiles(const AFiles: TArray); 39 | procedure BeginSearch; 40 | procedure CreateNewSearchWindow; 41 | procedure EndSearch; 42 | procedure StartSearch; 43 | protected 44 | property Files: TStringList read GetFiles; 45 | property Search: ICancel read FSearch write SetSearch; 46 | public 47 | destructor Destroy; override; 48 | end; 49 | 50 | var 51 | SearchForm: TSearchForm; 52 | 53 | implementation 54 | 55 | uses 56 | System.Threading, System.IOUtils, System.SysUtils, 57 | Vcl.FileCtrl; 58 | 59 | {$R *.dfm} 60 | 61 | destructor TSearchForm.Destroy; 62 | begin 63 | Search := nil; 64 | FFiles.Free; 65 | inherited; 66 | end; 67 | 68 | procedure TSearchForm.AddFiles(const AFiles: TArray); 69 | begin 70 | Files.AddStrings(AFiles); 71 | dspFiles.Items.Count := Files.Count; 72 | StatusBar.SimpleText := Format('%d files found', [Files.Count]); 73 | if Files.Count >= 10000 then begin 74 | EndSearch; // cancels search and releases interface 75 | end; 76 | end; 77 | 78 | procedure TSearchForm.BeginSearch; 79 | begin 80 | FStopWatch := TStopwatch.StartNew; 81 | dspFiles.Cursor := crHourGlass; 82 | end; 83 | 84 | procedure TSearchForm.btnNewSearchWindowClick(Sender: TObject); 85 | begin 86 | CreateNewSearchWindow; 87 | end; 88 | 89 | procedure TSearchForm.CreateNewSearchWindow; 90 | var 91 | form: TSearchForm; 92 | begin 93 | Inc(FormIndex); 94 | form := TSearchForm.Create(Application); 95 | form.Caption := Format('Search Window %d', [FormIndex]); 96 | form.Show; 97 | end; 98 | 99 | procedure TSearchForm.StartSearch; 100 | begin 101 | { cancel and release any active search } 102 | Search := nil; 103 | StatusBar.SimpleText := ''; 104 | dspFiles.Clear; 105 | Files.Clear; 106 | TAsyncSearch.Execute(Self, edtRootFolder.Text, edtSearchPattern.Text, FSearch); 107 | end; 108 | 109 | procedure TSearchForm.dspFilesData(Sender: TObject; Item: TListItem); 110 | begin 111 | Item.Caption := Files[Item.Index]; 112 | end; 113 | 114 | procedure TSearchForm.dspFilesDataFind(Sender: TObject; Find: TItemFind; const FindString: string; const FindPosition: TPoint; 115 | FindData: Pointer; StartIndex: Integer; Direction: TSearchDirection; Wrap: Boolean; var Index: Integer); 116 | begin 117 | Index := -1; 118 | case Find of 119 | ifData: ; 120 | ifPartialString: ; 121 | ifExactString: Index := Files.IndexOf(FindString); 122 | ifNearest: ; 123 | end; 124 | end; 125 | 126 | procedure TSearchForm.edtRootFolderRightButtonClick(Sender: TObject); 127 | begin 128 | SelectRootFolder; 129 | end; 130 | 131 | procedure TSearchForm.edtSearchPatternInvokeSearch(Sender: TObject); 132 | begin 133 | StartSearch; 134 | end; 135 | 136 | procedure TSearchForm.EndSearch; 137 | begin 138 | Search := nil; // cancel and release interface when search is complete or interrupted 139 | StatusBar.SimpleText := Format('%d files found (%d ms)', [Files.Count, FStopwatch.ElapsedMilliseconds]); 140 | dspFiles.Cursor := crDefault; 141 | end; 142 | 143 | function TSearchForm.GetFiles: TStringList; 144 | begin 145 | if FFiles = nil then begin 146 | FFiles := TStringList.Create; 147 | end; 148 | Result := FFiles; 149 | end; 150 | 151 | procedure TSearchForm.SelectRootFolder; 152 | var 153 | path: string; 154 | begin 155 | path := edtRootFolder.Text; 156 | if SelectDirectory('Select Root Folder', '', path) then 157 | edtRootFolder.Text := path; 158 | end; 159 | 160 | procedure TSearchForm.SetSearch(const Value: ICancel); 161 | begin 162 | if FSearch <> nil then 163 | FSearch.Cancel; 164 | FSearch := Value; 165 | end; 166 | 167 | end. 168 | --------------------------------------------------------------------------------