AsyncCalls - Delphi asynchronous function call framework
With AsyncCalls you can execute multiple functions at the same time and synchronize them with an IAsyncCall interface. This allows you to execute time consuming code in a different thread whos result is needed at a later time.
The AsyncCalls.pas unit offers a variety of function prototypes to call asynchronous functions.
Inlined VCL/main thread synchronization is supported. With this you can implement the code that calls a VCL function directly in your thread method without having to use a helper method and TThread.Synchronize. You have full access to all local variables. For Delphi 2009 and newer the TAsyncCalls class utilizes generics and anonymous methods.
Documentation
See DOCUMENTATION.md
Requirements
- Supported compilers: Delphi 5 to 10.1
- Supported platforms: Win32, Win64
Installation
Add the AsyncCalls.pas unit to your project's uses-clause.
Example
Using an anonymous function
procedure TForm1.Button3Click(Sender: TObject);
var
Value: Integer;
begin
TAsyncCalls.Invoke(procedure
begin
// Executed in a thread
Value := 10;
TAsyncCalls.VCLInvoke(procedure
begin
ShowMessage('The value may not equal 10: ' + IntToStr(Value));
end);
Value := 20;
TAsyncCalls.VCLSync(procedure
begin
ShowMessage('The value equals 20: ' + IntToStr(Value));
end);
Value := 30;
end);
Sleep(1000);
end; // If the async. function is run yet, the "end" will sync it
Using a global function
function GetFiles(Directory: string; Filenames: TStrings): Integer;
var
h: THandle;
FindData: TWin32FindData;
begin
h := FindFirstFile(PChar(Directory + '\*.*'), FindData);
if h <> INVALID_HANDLE_VALUE then
begin
repeat
if (StrComp(FindData.cFileName, '.') <> 0) and (StrComp(FindData.cFileName, '..') <> 0) then
begin
Filenames.Add(Directory + '\' + FindData.cFileName);
if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
GetFiles(Filenames[Filenames.Count - 1], Filenames);
end;
until not FindNextFile(h, FindData);
Windows.FindClose(h);
end;
Result := 0;
end;
procedure TFormMain.ButtonGetFilesClick(Sender: TObject);
var
Dir1, Dir2, Dir3: IAsyncCall;
Dir1Files, Dir2Files, Dir3Files: TStrings;
begin
Dir1Files := TStringList.Create;
Dir2Files := TStringList.Create;
Dir3Files := TStringList.Create;
ButtonGetFiles.Enabled := False;
try
Dir1 := TAsyncCalls.Invoke<string, TStrings>(GetFiles, 'C:\Windows\System32', Dir1Files);
Dir2 := TAsyncCalls.Invoke<string, TStrings>(GetFiles, 'D:\Html', Dir2Files);
Dir3 := TAsyncCalls.Invoke<string, TStrings>(GetFiles, 'E:', Dir3Files);
{ Wait until both async functions have finished their work. While waiting make the UI
reacting on user interaction. }
while AsyncMultiSync([Dir1, Dir2], True, 10) = WAIT_TIMEOUT do
Application.ProcessMessages;
Dir3.Sync; // Force the Dir3 function to finish here
MemoFiles.Lines.Assign(Dir1Files);
MemoFiles.Lines.AddStrings(Dir2Files);
MemoFiles.Lines.AddStrings(Dir3Files);
finally
ButtonGetFiles.Enabled := True;
Dir3Files.Free;
Dir2Files.Free;
Dir1Files.Free;
end;
end;