Single DTWAIN Session
For applications that must call DTWAIN_SysInitialize in one thread, and then call other DTWAIN functions in another thread using the same DTWAIN session, you must use the DTWAIN_StartThread at the start of the new thread with the previous value returned from DTWAIN_SysInitialize. This prevents DTWAIN from issuing the -1001 error for an uninitialized DLL. Before the thread exits, you should call DTWAIN_EndThread:
For example:
//Thread 1: DTWAIN_UseMultipleThreads(TRUE); // Must be called to ensure proper thread handling LONG Handle = DTWAIN_SysInitialize( ); DTWAIN_SOURCE Source = DTWAIN_SelectSource( ); //.... // Start of thread 2 (assume values from thread 1 have been passed to thread 2) DTWAIN_StartThread( Handle ); DTWAIN_CloseSource( Source ); // no -1001 error since we associated the handle in thread 1 with thread 2 //.... // before the end of thread 2 DTWAIN_EndThread( Handle ); // ....
Using the above scenario allows your application to call DTWAIN functions that returned a value in one thread in another completely different thread.
A final important note is that many TWAIN Sources do not work correctly if they are selected in one thread, and an image retrieval is attempted in another thread. Therefore it is highly recommended to use DTWAIN in a single thread, or use multiple instances of DTWAIN in multiple threads. This is more stable than using one instance of DTWAIN across multiple threads.
Also, as stated earlier, an acquisition must be started in the same thread as where the TWAIN session was created. A workaround to the problem of having to start a TWAIN session is to use the product name of the TWAIN Source to select and open the Source in the desired thread. The following psuedo-code should illustrate this.
//Thread 1: { char SourceName[255]; DTWAIN_UseMultipleThreads(TRUE); // Must be called to ensure proper thread handling LONG Handle = DTWAIN_SysInitialize( ); DTWAIN_SOURCE Source = DTWAIN_SelectSource( ); DTWAIN_SourceGetProductName( Source, SourceName, 255 ); DTWAIN_EndTwainSession( ); CreateThread( ... ); // Create and start Start thread 2 } //.... // Thread 2: { // Start of thread 2 (assume values from thread 1 have been passed to thread 2) DTWAIN_StartThread( Handle ); DTWAIN_SOURCE MySource = DTWAIN_SelectSourceByName( SourceName ); // reselect the source from thread 1. This also starts a TWAIN session DTWAIN_AcquireFile(...); // Acquire a file //.... // before the end of thread 2 DTWAIN_EndTwainSession( ); DTWAIN_EndThread( Handle ); // .... }
The code above initially queries the user for the Source to select in thread 1, records the source name, and ends the TWAIN session in thread 1. When thread 2 starts, the TWAIN session is started automatically by DTWAIN when the application reselects the Source using DTWAIN_SelectSourceByName. This ensures that the DTWAIN_AcquireFile will work correctly, since the TWAIN session has been started in the same thread as the "acquire" function. Alternately, you can explicitly start the TWAIN session by calling DTWAIN_StartTwainSession in the second thread.
Also, it is highly recommended that you use DTWAIN modeless processing if you desire to use a single instance of DTWAIN across multiple threads. |