问题
Which parts of the communication with TWAIN can be put into another thread, e.g. a BackgroundWorker? Or: Is it possible to split the loop that handles the image transfer?
Some scanner drivers scan all images before returning to the calling application which forces the application to handle all images at once. This results in e.g. OutOfMemoryException or weird behavior in my WPF application when suddenly all events (raised after every scanned image) have to be handled at once. Additionally the application hangs until the transfer was completed.
I am using TwainDotNet: http://code.google.com/p/twaindotnet/ but I'm also looking for a generic solution describing the message filter and the interaction with TWAIN independant of TwainDotNet. A workflow containing the TWAIN messages would suffice. Other languages are also welcome, preferrable something like C or Deplhi.
The current implementation of the message filter in DataSourceManager can be described as following:
- Get message info from window handle (hwnd)
- Complicate filter, send stuff to TWAIN etc.
- if message close (e.g. when pressing the cancel button in the TWAIN UI)
- Close data source
- Disable filter
- Call ScanningComplete event
- if message transfer ready:
- In a loop (until the ADF is empty etc., this blocks the message filter)
- Get image
- Convert image pointer to GDI+ image
- Call TransferImage event with image as parameter
- Reset transfer
- Close data source etc. (same as message close)
- Notify windows, that the message has been handled
I've tested this with several scanners:
- A Fujitsu fi-5120C calls the TransferImage event every time a page has been transferred. The image pops up immediately in an image list in my WPF application.
- A Canon DR-5010C blocks my WPF application until all images have been scanned (until the loop ends). Windows even says, the WPF application is not responding. After all images have been transferred, only few images are displayed and the selection in the image list flickers etc..
I am not concerned about the display problems, but rather about the blocked window and the memory problems. Putting the loop that transfers the images into a BackgroundWorker caused several crashes, that I could not debug. Of cause I considered the threading issues of WPF. I also don't know how to split the transfer loop, so that, after transferring one image, the program returns to the message filter and the message can be marked as handled.
回答1:
I work for Atalasoft, but I don't know WPF, or even that much about DotTwain!
I can tell you that generally TWAIN scanning can be done on a separate scanning thread, but you have to take some care. The simplest approach is to do all TWAIN operations on the scanning thread - don't mix TWAIN calls between two threads.
The scanning thread has to have a message pump or be a 'UI' thread, whatever that takes in your environment. It is not just a worker thread.
TWAIN expects to be given a window handle (old-fashioned Win32 HWND) to use as the parent window for the scanner's UI. I recommend creating a 'scanning parent' window for this purpose, on the scanning thread. You can make it visible or not as you choose, and destroy it at the end of the scan job.
If your scan jobs can be very big (e.g. 50 pages of 400 DPI color) you have to make sure the scanning process does not fill up either logical memory or RAM. If you fill up logical memory (a 32-bit Windows process gets about 2GB of address space to work with) allocations will fail. If you fill up RAM, the code that is consuming/disposing of the incoming images may start to swap, slowing down radically, then scanning runs ahead and fills up logical memory. So you need to either:
- Completely process and dispose of each incoming image on the scan thread, or
- Throttle the flow of images from the scan thread so it cannot run too far ahead of their processing/disposition.
I usually find I want to be able to cancel the scan thread, which requires some patience since TWAIN calls cannot be interrupted, and some of them are heavy. As you've noticed with your Canon. On the other hand if you force-kill a thread inside a TWAIN call, the scanner may require a power-cycle or even a system restart, and TWAIN itself will block until the TWAIN manager DLL is unloaded from memory and reloaded. Usually best to shut down TWAIN very politely.
来源:https://stackoverflow.com/questions/4453351/how-can-i-scan-and-transfer-images-from-a-document-feeder-asynchronously