2BrightSparks

FindOnClick Scripting

Author: Michael J. Leaver, 2BrightSparks Pte. Ltd.

FindOnClick V3 introduced a powerful new feature: scripting. Scripting lets the user define exactly what files and/or folders to include in the search results. Although FindOnClick already provides the user with numerous advanced filtering options, with scripting you can extend that with almost limitless flexibility. The scripting language used in FindOnClick is the same as the Pascal scripting available in SyncBackPro.

What Is Scripting?

Scripting is a way in which the searching functionality of FindOnClick can be changed or extended by writing a small script. A script is a set of instructions and is similar to the macro support in Microsoft Office and Java Script in web pages. It is also similar to plug-ins in other software. FindOnClick can use scripts written in Pascal.

In simple terms, FindOnClick calls defined functions in a script for each file/folder that has been found (and not already filtered out by the search settings). When the functions are called, data about the file/folder is given to the script function, e.g. the filename, size, attributes, etc. The functions can then decide if the file/folder should be filtered out or not.

How FindOnClick Searches

For each drive (or path) that FindOnClick must search, it has a two-stage search:

First, it gets a list of the files and folders. Those files/folders are then filtered using the search settings. For example, you may have search settings that say you only want files over 100MB that have been modified today. Any files and folders that do not match those search settings are filtered out from the search results. This is repeated for each drive/path that needs to be searched.

Once all the drives/paths have been searched, it then performs post-processing on the resulting files and folders. The second stage (post-processing) is optional, depending on the search settings. A second stage is only required when something needs to be done with the contents of a file, e.g. file hashing, searching the contents, getting MP3 information or retrieving the version number of a file.

With scripting you can change the search results during both stages. So, in summary:

  1. For each drive/path to be searched:
    • The drive/path is searched and it's files and folders are added to the search results.
    • Files and folders in the search results are filtered out based on the search settings, e.g. size, dates & times, etc.

  2. Once a complete list of all files and folders has been created and filtered:
    • Items in the list are further filtered out and/or processed based on the search settings, e.g. hash values are calculated, contents are searched, etc.

How FindOnClick Uses Scripts

With scripting, we can change the search results. For each file & folder, that has not already been filtered out by the search results, FindOnClick calls the script. The script can then decide to filter out the item or not. This is achieved by having a script that defines certain functions. All of the functions are optional, depending on how you want the script filtering to be performed.

Script functions are called in this order (and all are optional, i.e. they don't need to be defined in the script):

  1. SearchBegin is called before each drive and/or path is searched. This means it may be called multiple times.

  2. Include is called for each item found that has not already been filtered out by the search settings. So SearchBegin is called before a drive/path is searched, it is then searched, and Include is then called for each item found, and not filtered out, on the drive/path.

  3. Steps 1 and 2 are repeated for each drive/path to be searched.

  4. Once all the drives/paths have been searched and filtered, FindOnClick does post-processing. Post-processing is done after a complete list of files has been filtered and produced. Post-processing is when hash values are calculated and file contents are searched, for example. As these are resource intensive they are only done once we have filtered out as many files as possible.

  5. Once file contents have been searched, and hashes calculated, etc., PostIncludeEx is called. This lets the script tell FindOnClick which files to include based on their filename. This is done by giving a list (TFileList) containing the filenames.

  6. If DoPostFiltering is defined, and returns TRUE, then PostInclude is called for each item that has not already been filtered.

  7. SearchEnd is called once post-processing has completed and we now have the final list of files and folders that is displayed to the user. It is only called once.

As mentioned, all the functions are optional. For example, you may not care if the search has completed, so there is no need to include the function SearchEnd in your script. You may only want to do post-processing, so many of the other functions may not be required.

The OnClick Help File explains in detail what each of the functions are for and how they are used.

Supporting Functions, Classes, etc.

With just the basic Pascal scripting language, a script would be limited in what it could do. So to help a script be more functional, FindOnClick provides a number of supporting functions and classes. For example, a number of functions are available to the script to manipulate filenames, compare dates & times, use regular expressions, etc.

Scripts can also use COM objects and DLL's, meaning that functions provided by Windows (or other programs, utilities or developed by yourself) can be used.

The OnClick Help File explains in detail the support functions, classes, constants, etc. are available to scripts.

Script Performance

Scripting has an impact on search performance. Small, simple scripts may slightly increase search time, but complex scripts can significantly increase the search time. This is unavoidable as processing a script is a non-trivial task. However, there are things you can do in the script to reduce the impact:

  • Reduce the complexity and size of the script.
  • Include and PostInclude are called the most, so concentrate on optimizing those functions.
  • Use post-processing, if possible, as it's likely to be called the least (as the most number of items possible will already have been filtererd out).
  • If possible, use PostIncludeEx instead of PostInclude.

Loading and Editing Scripts

Loading a script is simple:

  • Start FindOnClick and the Search window will appear automatically (if not click the Search button).
  • Go to the Script tab and tick the checkbox "Filter using a script". This tells FindOnClick you want to use a script.
  • Right-click on the script edit box (below the checkbox) and select Load... from the pop-up menu. Select the script you'd like to use.
  • You can then change the other search parameters in the other search tabs and click Search to begin the search.

While editing a script you can edit it and save the changes. Pressing F9, while editing a script, compiles it. Compilation makes sure the script doesn't have any obvious mistakes.

Example Scripts

FindOnClick comes with a number of simple example scripts. For example, SameNameAsParent.pas:

// // Only include files that have the same name as their parent folder, e.g. // // C:\abc\def\def will return TRUE, because the filename 'def' is the same name as the parent folder // C:\abc\def\ghi will return FALSE // function Include(fname, DOSfname, fsize, fattrs, fcreate, faccess, fmod, fstreams, fhash, fver); begin if (fattrs and FILE_ATTRIBUTE_DIRECTORY = 0) then Result:=SameStr(ExtractFileName(ExtractFileDir(fname)), ExtractFileName(fname)) else Result:=FALSE; end;

This very simple script shows how to filter based on the filename. First, it checks to see if the item is a file or a folder (fattrs and FILE_ATTRIBUTE_DIRECTORY = 0). If it's a file (because it does not have the FILE_ATTRIBUTE_DIRECTORY file system attribute) then we see if it's filename is the same as the name of the folder the file is in. If not, then FALSE is returned (meaning it is filtered out). If it's a folder, then it is filtered out (Result:=FALSE).

Another slightly more complex example script is OldestFile.pas:

// // This script will look for the oldest file or folder (based on last modification date & time) // var OldestFile; function Include(fname, DOSfname, fsize, fattrs, fcreate, faccess, fmod, fstreams, fhash, fver); begin Result:=(CompareDateTime(fmod, OldestFile) = LessThanValue); if Result then OldestFile:=fmod; end; // Tell FindOnClick to call PostInclude function DoPostFiltering; begin Result:=TRUE; end; function PostInclude(fname, DOSfname, fsize, fattrs, fcreate, faccess, fmod, fstreams, fhash, fver); begin Result:=(CompareDateTime(fmod, OldestFile) = EqualsValue); end; procedure SearchBegin(SearchPath, IsSlowSearch); begin if not Assigned(OldestFile) then OldestFile:=Now; end;

This script introduces more concepts:

  • It has a global variable (OldestFile) which is used to store state between each call to the script.
  • It has SearchBegin, which initializes the global variable.
  • As well as filtering via Include, it also has post-processing filtering (DoPostFiltering and PostInclude).

MostFiles.pas shows how to use PostIncludeEx and TFileList to keep track of many values:

// // This script will list the folders that contain the most child folders and files // var FList: TFileList; function Include(fname, DOSfname, fsize, fattrs, fcreate, faccess, fmod, fstreams, fhash, fver); begin FList.AddInc(ExtractParentDirectory(fname)); end; // Give FindOnClick a list of names function PostIncludeEx(var FilterList); begin FList.RemoveNotValue(FList.Highest); FilterList:=FList; Result:=TRUE; end; procedure SearchBegin(SearchPath, IsSlowSearch); begin if not Assigned(FList) then FList:=TFileList.Create(EFLT_FullPath) else // We must now be searching the second, third, etc. drive/path // So remove entries that cannot be included now before we continue the search FList.RemoveNotValue(FList.Highest); end; procedure SearchEnd; begin FList.Free; end;

This script introduces more concepts:

  • It has a global variable (FList) which is a special TFileList object. It is used to store a numeric value for each unique string (in this case a path).
  • Include is not used for filtering, but to populate the values in FList. This keeps a count of how many files and child folders are in each folder.
  • PostIncludeEx passes the list (FList) to FindOnClick, so that FindOnClick itself can do the filtering. This greatly improves performance as FindOnClick can filter the items in one go instead of calling the script for each item.
  • SearchBegin is used not just to initialize the script, but to also improve performance by removing entries from the list. By removing entries we can improve the performance when more than one drive or path is being searched.
  • SearchEnd is used to clean-up (free the memory used by FList).

Conclusion

The addition of scripting into FindOnClick introduces new possibilities to find exactly the files and folders you need to find.

Noted Customers

© 2003-2020 2BrightSparks Pte. Ltd.  | Home | Support | Privacy | Terms

Home | Support | Privacy | Terms
© 2003-2020 2BrightSparks Pte. Ltd.

Back to top