The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,262 other subscribers

Archive for February 23rd, 2021

Automatically closing ABBY Finereader 5.0 windows after scanning is completed

Posted by jpluimers on 2021/02/23

Both my Fujitsu ScanSnap ix500 and ix100 scanners can be used from Windows to automatically scan to PDF.

PDF conversion is done through the included ABBYY FineReader 5.0 software.

However, on each scan, it keeps a dialog open with the scan results, even if scanning went fine.

When scanning lots of documents, lots of dialogs are open, causing two problems:

  • a lot of memory and window handle resource usage
    • this can be ~100 megabytes per instance
  • a lot of disk usage:
    • it keeps both the non-OCR and OCR PDF files active (only when closing, the non-OCR PDF file is deleted)

I wanted to close that dialog automatically, but none of the configuration settings allow it.

So I wrote a quick and dirty solution, that could have been in any tool supporting the Windows API and call backs. The solution below should easily translate to tools other than Delphi.

These are the only Windows API functions used:

these types:

and these constants:

The basic structure is an EumWindows call passing a callback that gets called for all top level Windows, then in the callback, for matching captions: call EnumChildWindows with another callback. In that callback, for matching captions and child captions, perform a click or close.

Related posts:

Log of Windows related to both programs:

ParentHWnd=$00000000;HWnd=$00030602;IsVisible=-1;IsOwned=0;IsAppWindow=-1;WindowTextLength=33;WindowText="ABBYY FineReader for ScanSnap 5.0"
> Recursive child windows for ABBYY
  ParentHWnd=$00030602;HWnd=$000205E2;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=0;WindowText=""
  ParentHWnd=$00030602;HWnd=$000205E0;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=0;WindowText=""
  ParentHWnd=$00030602;HWnd=$000205EC;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=0;WindowText=""
  ParentHWnd=$00030602;HWnd=$000205EA;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=74;WindowText="Register your copy of ABBYY FineReader and receive the following benefits:"
  ParentHWnd=$00030602;HWnd=$000205E8;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=25;WindowText="- Free technical support;"
  ParentHWnd=$00030602;HWnd=$000205E6;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=51;WindowText="- Information about new versions of ABBYY products."
  ParentHWnd=$00030602;HWnd=$000205E4;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=12;WindowText="Registration"
  ParentHWnd=$00030602;HWnd=$000205FC;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=0;WindowText=""
  ParentHWnd=$00030602;HWnd=$000205FA;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=6;WindowText="&Close"
  > Child is Close button: clicking.
  < ParentHWnd=$00000000;HWnd=$00030602;IsVisible=-1;IsOwned=0;IsAppWindow=-1;WindowTextLength=33;WindowText="ABBYY FineReader for ScanSnap 5.0"
  ParentHWnd=$00030602;HWnd=$000205F6;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=34;WindowText="Processing finished (warnings: 1)."
  ParentHWnd=$00030602;HWnd=$000205F4;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=31;WindowText="Converting to searchable PDF..."
  ParentHWnd=$00030602;HWnd=$000205F0;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=0;WindowText=""
  ParentHWnd=$00030602;HWnd=$000205EE;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=0;WindowText=""
  ParentHWnd=$00030602;HWnd=$000205D2;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=63;WindowText="Page 1. Make sure the correct recognition language is selected."

ParentHWnd=$00000000;HWnd=$00010248;IsVisible=-1;IsOwned=-1;IsAppWindow=0;WindowTextLength=14;WindowText="Creative Cloud"
> Recursive child windows for Creative Cloud
  ParentHWnd=$00010248;HWnd=$0001024A;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=28;WindowText="Main Container Client Dialog"
  ParentHWnd=$00010248;HWnd=$0002034A;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=3;WindowText="IMS"
  ParentHWnd=$00010248;HWnd=$0001035A;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=0;WindowText=""
  ParentHWnd=$00010248;HWnd=$00020350;IsVisible=-1;IsOwned=0;IsAppWindow=0;WindowTextLength=18;WindowText="Sign in - Adobe ID"
  > Child is Signin button: closing parent.
  < ParentHWnd=$0003011A;HWnd=$00010248;IsVisible=-1;IsOwned=-1;IsAppWindow=0;WindowTextLength=14;WindowText="Creative Cloud"
    < ParentHWnd=$00000000;HWnd=$0003011A;IsVisible=0;IsOwned=0;IsAppWindow=0;WindowTextLength=4;WindowText="Core"

It appears that ABBYY has a different set of booleans than Creative Cloud.

This is kind of odd, as delphi – How to get captions of actual windows currently running? – Stack Overflow points to Window Features – Windows applications | Microsoft Docs: Owned Windows stating:

The Shell creates a button on the taskbar whenever an application creates a window that isn’t owned. To ensure that the window button is placed on the taskbar, create an unowned window with the WS_EX_APPWINDOW extended style. To prevent the window button from being placed on the taskbar, create the unowned window with the WS_EX_TOOLWINDOW extended style. As an alternative, you can create a hidden window and make this hidden window the owner of your visible window.

Apparently, ABBYY fully plays by the rules, but Creatheive Cloud cheats a bit: none of the Windows are WS_EX_APPWINDOW, but the hidden unowned “Core” owner of the “Creative Cloud” still makes it appear on the taskbar.

–jeroen

Read the rest of this entry »

Posted in Delphi, Development, Fujitsu ScanSnap, Hardware, ix100, ix500, Power User, Scanners, Software Development, Windows Development | Leave a Comment »

Unittesting FizzBuzz

Posted by jpluimers on 2021/02/23

Keep a version history of how you approach the below TDD driven approach, then discuss it with one of your co-workers.

Note there is no “right” approach, though probably you will experience that some environments and approaches may lead to code that is better, for instance because it is:

  • easier to explain
  • shorter
  • more performant

The above 3 might points bite each other (;

Based on FizzBuzz: One Simple Interview Question – YouTube.

Write initial tests

Write unit tests for this unit under test in pseudo code:

type OutputMethod: method(string Value)
class FizzBuzzGame:
    method Construct(OutputMethod Value)
    method Process(int Value)

Unit test that captures Output with a certain set of Values, then tests for the four possible combinations:

  • number
  • Fizz
  • Buzz
  • FizzBuzz

and also ensures that the passed OutputMethod is being called once for each call to Process.

Extend the tests

Now extend the tests to cover the below multiples and all the permutations caused by the longer list. Think carefully about the permutations.

  • 3 -> Fizz
  • 5 -> Buzz
  • 7 -> Fuzz
  • 11 -> Bizz
  • 13 -> Biff

Write the unit under test

The least tricky bit should be this step.

Be sure to test the solution with your co-workers as well.

Non positive numbers.

Did you think about negative numbers?

Did you think about the number zero?

What would you do about them in the tests and unit under test?

–jeroen

Read the rest of this entry »

Posted in Conference Topics, Conferences, Development, Event, Software Development | Leave a Comment »

Delphi intrinsic functions that evaluate to consts

Posted by jpluimers on 2021/02/23

A long time ago, I wondered Are these really Windows compiler unsupported Delphi Intrinsic Routines about [WayBack/Archive.is] Delphi Intrinsic Routines – RAD Studio.

Today, I limited the documented intrinsic list to the constant intrinsic functions:

const
  _Abs = System.Abs(1);
  _Chr = System.Chr(1);
  _Concat = System.Concat(1);
  _Hi = System.Hi(1);
  _High = System.High(1);
  _Length = System.Length('');
  _Lo = System.Lo(1);
  _Low = System.Low(1);
  _Odd = System.Odd(1);
  _Ord = System.Ord(1);
  _Pi = System.Pi();
  _Pred = System.Pred(1);
  _Ptr = System.Ptr(1);
  _Round = System.Round(1);
  _SizeOf = System.SizeOf(1);
  _Sqr = System.Sqr(1);
  _Succ = System.Succ(1);
  _Swap = System.Swap(1);
  _Trunc = System.Trunc(1);

The limited table is below the fold.

There is also a set of undocumented generic intrinsics that I wrote about in Source: Delphi Compiler Intrinsics can help you collapse generated code for generics a lot.

Of the those undocumented functions, these are constant intrinsic functions:

const // undocumented compiler intrinsics
  _Default = Default(Integer);
  _IsManagedType = IsManagedType(1);
  _GetTypeKind = GetTypeKind(1);
  _IsConstValue = IsConstValue(1);

–jeroen

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development, Undocumented Delphi | 2 Comments »