This project has moved. For the latest updates, please go here.

"Index out of bound" on the Twain.GetImage(0);

Aug 22, 2013 at 2:33 PM
Edited Aug 22, 2013 at 2:47 PM
Hello,

I tried to use your Saraff.twain.dll
public static string Scan(string strFullPathOut)
{
    Twain32 myTwain = new Twain32();
    try
    {
        myTwain.OpenDSM();
        myTwain.CloseDataSource();
        myTwain.SourceIndex = 0; 
        myTwain.OpenDataSource();

        myTwain.ShowUI = false;

        myTwain.Acquire();
        Image myPicture = myTwain.GetImage(0);
        myPicture.Save(@"C:\Divalto\MyscanTwain.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
       
        return "ok";

    }
    catch (Exception Ex)
    {
        return ("Erreur TWAIN : " + Ex.Message);
    }

}   
After acquiring, the line
Image myPicture = myTwain.GetImage(0);
Give me an exception : "Index out of bounds for the parameter : index".

In addition, i tried to use the eventhandler, but, i never go on the event ! I read at the sample 3 without success :(

Have you any tips please for avoid my error ?

Thanks a lot,

Best regards,

Nixeus

Edit : my scanner is compatible TWAIN, is plugged, and when the programme execute the myTwain.Acquire() line, my scanner acquire really.
Coordinator
Aug 22, 2013 at 6:07 PM
Hello, Nixeus.
Method Acquire for winforms application is asynchronous (for console application it synchronous). So, get an image immediately after the call Acquire impossible. You need to handle the event AcquireCompleted.
May be, the following code will help you.
private Twain32 _twain32;

public static Twain32 Twain{
    get{
        if(_twain32==null){
            _twain32=new Twain32();
            _twain32.OpenDSM();
            _twain32.CloseDataSource();
            _twain32.SourceIndex = 0; 
            _twain32.OpenDataSource();
    
            _twain32.ShowUI = false;
    
            _twain32.AcquireCompleted+=AcquireCompletedEventHandler;
        }
        return _twain32;
    }
}

public static string Scan(string strFullPathOut){
    try{
        Twain.Acquire();
        return "Acquire begining";
    }
    catch (Exception Ex){
        return ("Erreur TWAIN : " + Ex.Message);
    }

}

public static void AcquireCompletedEventHandler(object sender,EventArg e){
    Image myPicture = Twain.GetImage(0);
    myPicture.Save(@"C:\Divalto\MyscanTwain.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
Marked as answer by SARAFF on 6/23/2014 at 12:45 PM
Aug 22, 2013 at 8:55 PM
Hello Saraff,

Thanks a lot for your answer, nevertheless, my code is for a dll. I saw in debug that the acquire method is synchronous, si i don't need the event. Could You explain me why i have this exception please ?

best regards,

nixeus
Coordinator
Aug 22, 2013 at 10:12 PM
Hello, Nixeus.
Event processing is necessary in any case (even if the method behaves as a synchronous). This exception (index out of bound) indicates that the image is not yet obtained from the scanner (that is, a list of the acquired images is empty).
You must be remembered that the twain implemented via windows messages, therefore synchronous operation with them is not possible.
Aug 23, 2013 at 9:10 AM
Hello,

I said an error : My scanner don't acquire on the Acquire Method if i use my code, or your code in a DLL.
If i use my code, or your code in a winform, there is no problem.

I need to use this code in a dll :(

In order to explain my problem i created a little sample code: A form with a button, and, behind this button, i call a "SCAN" function in my DLL.
The error is the same.

Could you look at my sample project please ? It will be very nice :)

Here is my upload : http://www.multiupload.nl/SSAX32Z63F

Thanks a lot Saraff,

Best regards,

Nixeus
Coordinator
Aug 23, 2013 at 12:47 PM
Hello, Nixeus.
I looked your sample project. I want to say that the solution Saraff.Twain.NET was designed for use directly in the client application. Nevertheless, your project may be implemented as shown below:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using DLL_Numerize;

namespace WIA_test {

    public partial class Form1:Form {

        public Form1() {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) {
            string strFileName=Environment.GetFolderPath(Environment.SpecialFolder.Desktop).Trim()+@"\MyDocScannedW_"+Environment.TickCount.ToString().Substring(Environment.TickCount.ToString().Length-4).Trim()+".png";
            //string strErr=DLL_Numerize.Scanners.Scan(strFileName);
            //if(strErr=="ok") {
            //    Process.Start(new ProcessStartInfo(strFileName));
            //} else {
            //    System.Windows.Forms.MessageBox.Show(strErr, "Action-Informatique", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            //}

            DLL_Numerize.Scanners.Scan_v2(strFileName, fileName => Process.Start(new ProcessStartInfo(fileName)), ex => MessageBox.Show(ex.Message, "Action-Informatique", MessageBoxButtons.OK, MessageBoxIcon.Exclamation));
        }

        private void label2_Click(object sender, EventArgs e) {

        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
using WIA;
using Saraff.Twain;
using System.Drawing.Imaging;


namespace DLL_Numerize {

    public static class Scanners {
        private static Twain32 _twain;

        public static string Scan(string strFullPathOut) {

            Twain32 myTwain=new Twain32();
            try {
                myTwain.OpenDSM();
                if(myTwain.SourcesCount>0) {
                    myTwain.CloseDataSource();
                    myTwain.SourceIndex=0; // On sélectionne le premier scanner
                    myTwain.OpenDataSource();

                    myTwain.ShowUI=false;

                    myTwain.Acquire();

                    Image myPicture=myTwain.GetImage(0);
                    myPicture.Save(strFullPathOut, System.Drawing.Imaging.ImageFormat.Jpeg);
                    return "ok";
                } else {
                    return "No Twain";
                }

            } catch(Exception Ex) {
                return ("Erreur TWAIN : "+Ex.Message);
            }

        }

        public static void Scan_v2(string fileName, Action<string> acquireCallback, Action<Exception> exeptionCallback) {
            Scanners.AcquireHandler.Create(fileName, acquireCallback, exeptionCallback);
            Scanners.Twain.Acquire();
        }

        private static Twain32 Twain {
            get {
                if(Scanners._twain==null) {
                    Scanners._twain=new Twain32();
                    Scanners._twain.OpenDSM();
                    if(Scanners._twain.SourcesCount>0) {
                        Scanners._twain.SourceIndex=0; // On sélectionne le premier scanner
                        Scanners._twain.OpenDataSource();
                        Scanners._twain.ShowUI=false;
                    } else {
                        throw new InvalidOperationException("DS not found.");
                    }
                }
                return Scanners._twain;
            }
        }

        private sealed class AcquireHandler {
            private string _fileName;
            private Action<string> _acquireCallback;
            private Action<Exception> _exeptionCallback;

            private AcquireHandler() {
            }

            internal static AcquireHandler Create(string fileName, Action<string> acquireCallback, Action<Exception> exeptionCallback) {
                var _handler=new AcquireHandler {_fileName=fileName,_acquireCallback=acquireCallback,_exeptionCallback=exeptionCallback};
                Scanners.Twain.AcquireCompleted+=_handler.AcquireCompletedEventHandler;
                return _handler;
            }

            private void AcquireCompletedEventHandler(object sender, EventArgs e) {
                try {
                    try {
                        if(Scanners.Twain.ImageCount>0) {
                            Scanners.Twain.GetImage(0).Save(this._fileName, ImageFormat.Jpeg);
                        }
                    } finally {
                        Scanners.Twain.AcquireCompleted-=this.AcquireCompletedEventHandler;
                    }
                    this._acquireCallback(this._fileName);
                } catch(Exception ex) {
                    this._exeptionCallback(ex);
                }
            }
        }
    }
}
Aug 23, 2013 at 1:31 PM
Edited Aug 23, 2013 at 1:32 PM
Thanks a lot, now my acquire function is ok and i see my scanned document.

I have an other question :

For this function :
   DLL_Numerize .Scanners.Scan_v2(strFileName, fileName => Process.Start(new ProcessStartInfo(fileName)), ex => MessageBox.Show(ex.Message, "Action-Informatique", MessageBoxButtons.OK, MessageBoxIcon.Exclamation));
I would like to modify in order to having this :
   DLL_Numerize.Scanners.Scan_v2(strFileName, string out MyStringReturn);
In the MyStringReturn i would like to set "ok" if acquire method is successfull and the ex.message if error.

Why i need this ? Because my DLL is for calling from a non-.Net program, so it's important for me to get a string with "ok" or Exception message in order to get it in my client program.

I don't know how to modify your AcquireHandler class.

Could you help me please ? It will be very nice.

Thanks a lot for your help,

Best regards,

Nixeus
Coordinator
Aug 23, 2013 at 2:05 PM
Hello, Nixeus.
In this case, the application is better design as a command line utility. The arguments are passed on the command line. The result redirected from standard output to a pipe.
The following code may help you:
void CRegistrationHelper::_Exec(BSTR AppName){
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    //SECURITY_ATTRIBUTES saAttr;
    HANDLE hStdoutReadPipe,hStdoutWriteHandle;
#define PipeSize 1048576 //размер канала 1Mb
    char* lpszBuf=new char[PipeSize];

    CreatePipe(&hStdoutReadPipe,&hStdoutWriteHandle,NULL,PipeSize); //канал для связи с консолью
    SetHandleInformation(hStdoutWriteHandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);

    ZeroMemory(&si,sizeof(si));
    ZeroMemory(&pi,sizeof(pi));

    si.hStdOutput=hStdoutWriteHandle;
    si.hStdError=hStdoutWriteHandle;
    si.wShowWindow=SW_HIDE;
    si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;

    if(CreateProcess(NULL,CW2A(AppName),NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)!=0){
        WaitForSingleObject(pi.hProcess,INFINITE);

        DWORD num;
        ZeroMemory(lpszBuf,PipeSize);
        if(GetFileSize(hStdoutReadPipe,NULL)>0){ //если была произведена запись в консоль, то показываем окно журнала
            ReadFile(hStdoutReadPipe,lpszBuf,PipeSize-1,&num,NULL);
            OemToChar(lpszBuf,lpszBuf);
            this->m_pLog->ShowLog();
            this->m_pLog->CreatePartition(); //создаем новый раздел в журнале

            for(LPSTR lpszPos=lpszBuf;strchr(lpszPos,'\r');lpszPos=strchr(lpszPos,'\r')+2){ //разбваем весь вывод на строки
#define MessageSize 1024 //размер строки сообщения 1kb
                char szMes[MessageSize];

                ZeroMemory(szMes,MessageSize);
                strncpy_s(szMes,MessageSize-1,lpszPos,strchr(lpszPos,'\r')-lpszPos);
                if(strlen(szMes))this->m_pLog->WriteMessage(LogType::Error,szMes);
            }
        }

        delete[] lpszBuf;
        CloseHandle(hStdoutReadPipe);
        CloseHandle(hStdoutWriteHandle);
    }
}
or
ProcessStartInfo _startInfo=new ProcessStartInfo();
_startInfo.CreateNoWindow=true;
_startInfo.WorkingDirectory=this.DjvuLibrePath;
_startInfo.Arguments=string.Format("-slice 72+11+10+10 -bpp 0.25,0.5,1 \"{0}\" \"{1}\"",_tempJpgPath,_tempDjvuPath);
_startInfo.FileName=string.Format("{0}\\c44.exe",this.DjvuLibrePath);
_startInfo.UseShellExecute=false;
_startInfo.RedirectStandardError=true;
using(Process _proc=Process.Start(_startInfo)) {
    string _error_output=_proc.StandardError.ReadToEnd();
    _proc.WaitForExit();
    if(_proc.ExitCode==0) {
        return File.ReadAllBytes(_tempDjvuPath);
    } else {
        throw new Exception(_error_output);
    }
}
Aug 23, 2013 at 3:27 PM
Edited Aug 23, 2013 at 3:28 PM
Thanks a lot Saraff,

I solved my problem with your help.

A little question :
  • Is there a way to know if a TWAIN device is a scanner ? Because some camera or phone can be detected as twain. But is there a way to know if a twain device is a scanner ?
Thanks again,

Best regards,

Nixeus
Coordinator
Aug 23, 2013 at 8:06 PM
Hello, Nixeus.
Whether the device is a scanner is impossible determine, but you can determine capabilities of device using the methods IsCapSupported, GetCap and SetCap.