|
Hi!
I have a problem with this code(Twain Manager for .NET ActiveX)
What is TwainConfig?
Could you public or mail complete source of ActiveX decision?
Thanks.
Vasig
|
|
|
|
|
Hi,
I want to list available scanners in my own listbox, not in twain's gui. Becuse i want to use alias names of scanners.
Is there anyway to get scanner list shown in the SelctSource() dialog box?
Thanks.
bg
|
|
|
|
|
Hi
First of all, i really love that class
I needed to use Twain and didn't want to handle the Messages in the Main - Form.
here's how to do it:
<br />
public class ImageScannedEventArgs:EventArgs<br />
{<br />
private Bitmap image;<br />
public Bitmap Image<br />
{<br />
get<br />
{<br />
return image;<br />
}<br />
}<br />
public ImageScannedEventArgs(Bitmap Image)<br />
{<br />
image = Image;<br />
}<br />
}<br />
public delegate void ImageScannedEventHandler(object sender, ImageScannedEventArgs e);<br />
[StructLayout(LayoutKind.Sequential, Pack=2)]<br />
internal class BITMAPINFOHEADER<br />
{<br />
public int biSize;<br />
public int biWidth;<br />
public int biHeight;<br />
public short biPlanes;<br />
public short biBitCount;<br />
public int biCompression;<br />
public int biSizeImage;<br />
public int biXPelsPerMeter;<br />
public int biYPelsPerMeter;<br />
public int biClrUsed;<br />
public int biClrImportant;<br />
}<br />
public class TwainMan:NativeWindow,IDisposable<br />
{<br />
[DllImport("kernel32.dll", ExactSpelling=true)]<br />
internal static extern IntPtr GlobalLock( IntPtr handle );<br />
[DllImport("kernel32.dll", ExactSpelling=true)]<br />
internal static extern IntPtr GlobalFree( IntPtr handle );<br />
private Twain tw;<br />
private BITMAPINFOHEADER bmi;<br />
private Rectangle bmprect;<br />
private bool ready = false;<br />
public event ImageScannedEventHandler ImageScanned;<br />
public bool Ready<br />
{<br />
get<br />
{<br />
return ready;<br />
}<br />
}<br />
public TwainMan()<br />
{<br />
CreateParams cp = new CreateParams();<br />
cp.Parent = new IntPtr(-3);<br />
cp.Caption = "";<br />
this.CreateHandle(cp);<br />
tw = new Twain();<br />
tw.Init(Handle);<br />
}<br />
public void Select()<br />
{<br />
ready = tw.Select();<br />
}<br />
public void Scan()<br />
{<br />
if (ready)<br />
{<br />
tw.Acquire();<br />
}<br />
}<br />
protected IntPtr GetPixelInfo( IntPtr bmpptr )<br />
{<br />
bmi = new BITMAPINFOHEADER();<br />
Marshal.PtrToStructure( bmpptr, bmi );<br />
bmprect = Rectangle.Empty;<br />
bmprect.X = bmprect.Y = 0;<br />
bmprect.Width = bmi.biWidth;<br />
bmprect.Height = bmi.biHeight;<br />
<br />
if( bmi.biSizeImage == 0 )<br />
bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight;<br />
<br />
int p = bmi.biClrUsed;<br />
if( (p == 0) && (bmi.biBitCount <= 8) )<br />
p = 1 << bmi.biBitCount;<br />
p = (p * 4) + bmi.biSize + (int) bmpptr;<br />
return (IntPtr) p;<br />
}<br />
protected virtual void onImageScanned(ImageScannedEventArgs e)<br />
{<br />
if (ImageScanned != null)<br />
{<br />
ImageScanned(this,e);<br />
}<br />
}<br />
protected override void WndProc(ref Message m)<br />
{<br />
if (tw != null)<br />
{<br />
TwainCommand cmd = tw.PassMessage( ref m );<br />
if( cmd != TwainCommand.Not )<br />
{<br />
switch( cmd )<br />
{<br />
case TwainCommand.CloseRequest:<br />
{<br />
tw.CloseSrc();<br />
ready = false;<br />
break;<br />
}<br />
case TwainCommand.CloseOk:<br />
{<br />
tw.CloseSrc();<br />
ready = false;<br />
break;<br />
}<br />
case TwainCommand.DeviceEvent:<br />
{<br />
break;<br />
}<br />
case TwainCommand.TransferReady:<br />
{<br />
ArrayList pics = tw.TransferPictures();<br />
tw.CloseSrc();<br />
for( int i = 0; i < pics.Count; i++ )<br />
{<br />
IntPtr img = (IntPtr) pics[ i ];<br />
IntPtr bmpt = GlobalLock(img);<br />
IntPtr pi = GetPixelInfo(bmpt);<br />
IntPtr imgH = IntPtr.Zero;<br />
int Ret = GdiPlusLib.Gdip.GdipCreateBitmapFromGdiDib(bmpt,pi,ref imgH);<br />
if (img != IntPtr.Zero)<br />
{<br />
Bitmap bmp = (Bitmap)typeof(Bitmap).InvokeMember("FromGDIplus", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { imgH });<br />
onImageScanned(new ImageScannedEventArgs(bmp.Clone() as Bitmap));<br />
}<br />
}<br />
break;<br />
}<br />
}<br />
}<br />
}<br />
base.WndProc(ref m);<br />
}<br />
#region IDisposable Member<br />
<br />
public void Dispose()<br />
{<br />
try<br />
{<br />
tw.CloseSrc();<br />
}<br />
catch{}<br />
tw = null;<br />
}<br />
<br />
#endregion<br />
}<br />
now i only have to create an instance of TwainMan and it does the Messagehandling for me
M@u
-- modified at 11:59 Friday 15th December, 2006
|
|
|
|
|
Could you help me out by explaining where you put this code and how you used it?
Thanks!
|
|
|
|
|
hi
ok here's an example, how you can use it. create a new windowApplication - Project, add a new class, and replace the code with the stuff in my post.
then add a reference to the twainlibrary of this article.
new change to the form and put a Button and a PictureBox on it.
change to the code view and add a member - Variable:
<br />
private TwainMan Scanner;<br />
now change the Constructor. add after InitializeComponent(); the following line:
<br />
Scanner = new TwainMan();<br />
Scanner.ImageScanned += new ImageScannedEventHandler(Scanner_ImageScanned);<br />
now implement the Method Scanner_ImageScanned like this:
<br />
private void Scanner_ImageScanned(object Sender, ImageScannedEventArgs e)<br />
{<br />
pictureBox1.Image = e.Image;<br />
}<br />
now add the ClickEvent - Handler to the Button on the form by doubleclicking it.
the click - Handler of the button should look like this:
<br />
private void button1_Click(object sender, EventArgs e)<br />
{<br />
Scanner.Select();<br />
if (Scanner.Ready)<br />
{<br />
Scanner.Scan();<br />
}<br />
}<br />
that should be it.
greets
m@u
|
|
|
|
|
Error Cannot implicitly convert type 'void' to 'bool'
|
|
|
|
|
Dear m@u,
Is there any way todo this topic without NativeWindow interface? Only by events?
Thanks.
bg
|
|
|
|
|
Hi bgunes
you could implement the whole stuff in a control, override the wncproc according to the code i posted and handle the events in the parent-window
greets
m@u
|
|
|
|
|
take a closer look at openTwain, I wrapped up all of the messageloop handling in the library so you can scan without a form and without modifying your messageloop. it's event driven and works from console and windows service project. the sample code in the library includes a console and winforms project.
|
|
|
|
|
hi M@U could you put this into VB Format?
|
|
|
|
|
I really appreciate what you did to wrap the twainlib class. I have a question, I would like to know how to call TransferPictures asynchronously so that the class that contains TwainMan doesn't have to wait on the scanner to acquire picture, we would just wait for the ImageScanned event. I've been playing around with it and can't figure out how to do it. The TransferPictures fails on:
rc = DSiinf( appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf );
Any help would be appreciated,
Jose
|
|
|
|
|
Hi
Well Actually that's the way this class should work...
you call Scan() , the scanner scans, and when it's done you get the event...
how do you use the class?
greets
m@u
|
|
|
|
|
I call Scan(), but if the TransferPictures function(that is called in WndProc) is not on another thread the UI is not updated during transfer process so the form "locks up" during image scanning, which is something I would like to avoid aesthetically. I tried some type of Multi-threading but I couldn't get it to work. I think it has to do with the windows handle of the calling application(or thread).
Any ideas would help.
|
|
|
|
|
ok..
i think you could get it to work with something like this:
<br />
using System;<br />
using System.Threading;<br />
using System.Collections<br />
public class MTScan<br />
{<br />
private Thread scanThread;<br />
TwainMan scanner;<br />
public MTScan()<br />
{<br />
scanThread = new Thread(startScanApp);<br />
}<br />
private void startScanApp()<br />
{<br />
Application.Idle = new EventHandler(Application_Idle);<br />
Application.Start();<br />
}<br />
private void Application_Idle(object sender, EventArgs e)<br />
{<br />
scanner = new TwainMan();<br />
scanner.ImageScanned += new ImageScannedEventHandler(scanner_ImageScanned);<br />
}<br />
private void scanner_ImageScanned(object sender, ImageScannedEventArgs e)<br />
{<br />
onImageScanned(e);<br />
}<br />
protected virtual void onImageScanned(ImageScannedEventArgs e)<br />
{<br />
if (ImageScanned != null)<br />
{<br />
ImageScanned(this, e);<br />
}<br />
}<br />
public void Select()<br />
{<br />
scanner.Invoke(new ThreadStart(scanner.Select));<br />
}<br />
public void Scan()<br />
{<br />
scanner.Invoke(new ThreadStart(scanner.Scan));<br />
}<br />
public void Dispose()<br />
{<br />
scanner.Invoke(new ThreadStart(dispose));<br />
}<br />
private void dispose()<br />
{<br />
scanner.Dispose();<br />
Application.ExitThread();<br />
}<br />
}<br />
public class ImageScannedEventArgs:EventArgs<br />
{<br />
private Bitmap image;<br />
public Bitmap Image<br />
{<br />
get<br />
{<br />
return image;<br />
}<br />
}<br />
public ImageScannedEventArgs(Bitmap Image)<br />
{<br />
image = Image;<br />
}<br />
}<br />
public delegate void ImageScannedEventHandler(object sender, ImageScannedEventArgs e);<br />
[StructLayout(LayoutKind.Sequential, Pack=2)]<br />
internal class BITMAPINFOHEADER<br />
{<br />
public int biSize;<br />
public int biWidth;<br />
public int biHeight;<br />
public short biPlanes;<br />
public short biBitCount;<br />
public int biCompression;<br />
public int biSizeImage;<br />
public int biXPelsPerMeter;<br />
public int biYPelsPerMeter;<br />
public int biClrUsed;<br />
public int biClrImportant;<br />
}<br />
public class TwainMan:NativeWindow,IDisposable<br />
{<br />
private class InvokeHolder<br />
{<br />
private Delegate target;<br />
private object[] args;<br />
public InvokeHolder(Delegate Target, object[] Args)<br />
{<br />
target = Target;<br />
args = Args;<br />
}<br />
public void Run()<br />
{<br />
target.DynamicInvoke(args);<br />
}<br />
}<br />
[DllImport("kernel32.dll", ExactSpelling=true)]<br />
internal static extern IntPtr GlobalLock( IntPtr handle );<br />
[DllImport("kernel32.dll", ExactSpelling=true)]<br />
internal static extern IntPtr GlobalFree( IntPtr handle );<br />
private const int WM_USER = 0x400;<br />
private const int WM_Invoke = WM_USER+5;<br />
[DllImport("user32.dll", EntryPoint="PostThreadMessageA")]<br />
public static extern int PostThreadMessage ( <br />
int idThread,<br />
int msg,<br />
int wParam,<br />
int lParam);<br />
private Twain tw;<br />
private BITMAPINFOHEADER bmi;<br />
private Rectangle bmprect;<br />
private bool ready = false;<br />
public event ImageScannedEventHandler ImageScanned;<br />
private int threadID;<br />
private Queue delegateQueue;<br />
public bool Ready<br />
{<br />
get<br />
{<br />
return ready;<br />
}<br />
}<br />
public TwainMan()<br />
{<br />
CreateParams cp = new CreateParams();<br />
cp.Parent = new IntPtr(-3);<br />
cp.Caption = "";<br />
this.CreateHandle(cp);<br />
tw = new Twain();<br />
tw.Init(Handle);<br />
threadID = AppDomain.GetCurrentThreadId();<br />
delegateQueue = new Queue();<br />
}<br />
public void Invoke(Delegate Target, params object[] args)<br />
{<br />
delegateQueue.Enqueue(new InvokeHolder(Target, args);<br />
PostThreadMessage(threadID, WM_Invoke,0,0);<br />
}<br />
public void Select()<br />
{<br />
ready = tw.Select();<br />
}<br />
public void Scan()<br />
{<br />
if (ready)<br />
{<br />
tw.Acquire();<br />
}<br />
}<br />
protected IntPtr GetPixelInfo( IntPtr bmpptr )<br />
{<br />
bmi = new BITMAPINFOHEADER();<br />
Marshal.PtrToStructure( bmpptr, bmi );<br />
bmprect = Rectangle.Empty;<br />
bmprect.X = bmprect.Y = 0;<br />
bmprect.Width = bmi.biWidth;<br />
bmprect.Height = bmi.biHeight;<br />
<br />
if( bmi.biSizeImage == 0 )<br />
bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight;<br />
<br />
int p = bmi.biClrUsed;<br />
if( (p == 0) && (bmi.biBitCount <= 8) )<br />
p = 1 << bmi.biBitCount;<br />
p = (p * 4) + bmi.biSize + (int) bmpptr;<br />
return (IntPtr) p;<br />
}<br />
protected virtual void onImageScanned(ImageScannedEventArgs e)<br />
{<br />
if (ImageScanned != null)<br />
{<br />
ImageScanned(this,e);<br />
}<br />
}<br />
protected override void WndProc(ref Message m)<br />
{<br />
if (tw != null)<br />
{<br />
TwainCommand cmd = tw.PassMessage( ref m );<br />
if( cmd != TwainCommand.Not )<br />
{<br />
switch( cmd )<br />
{<br />
case TwainCommand.CloseRequest:<br />
{<br />
tw.CloseSrc();<br />
ready = false;<br />
break;<br />
}<br />
case TwainCommand.CloseOk:<br />
{<br />
tw.CloseSrc();<br />
ready = false;<br />
break;<br />
}<br />
case TwainCommand.DeviceEvent:<br />
{<br />
break;<br />
}<br />
case TwainCommand.TransferReady:<br />
{<br />
ArrayList pics = tw.TransferPictures();<br />
tw.CloseSrc();<br />
for( int i = 0; i < pics.Count; i++ )<br />
{<br />
IntPtr img = (IntPtr) pics[ i ];<br />
IntPtr bmpt = GlobalLock(img);<br />
IntPtr pi = GetPixelInfo(bmpt);<br />
IntPtr imgH = IntPtr.Zero;<br />
int Ret = GdiPlusLib.Gdip.GdipCreateBitmapFromGdiDib(bmpt,pi,ref imgH);<br />
if (img != IntPtr.Zero)<br />
{<br />
Bitmap bmp = (Bitmap)typeof(Bitmap).InvokeMember("FromGDIplus", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { imgH });<br />
onImageScanned(new ImageScannedEventArgs(bmp.Clone() as Bitmap));<br />
}<br />
}<br />
break;<br />
}<br />
case WM_Invoke:<br />
{<br />
if (invokeQueue.Count != 0)<br />
{<br />
do<br />
{<br />
InvokeHolder h = invokeQueue.Dequeue() as InvokeHolder;<br />
h.Run();<br />
}while(invokeQueue.Count != 0);<br />
}<br />
break;<br />
}<br />
}<br />
}<br />
}<br />
base.WndProc(ref m);<br />
}<br />
#region IDisposable Member<br />
<br />
public void Dispose()<br />
{<br />
try<br />
{<br />
tw.CloseSrc();<br />
}<br />
catch{}<br />
tw = null;<br />
}<br />
<br />
#endregion<br />
}<br />
this code should theoretically start a different thread where the whole scanning should be handled.
it's not testet, so maybe it contains some syntax / logical errors. but i think the solution for scanning in a different thread is something like that..
greets
m@u
|
|
|
|
|
Hello,
I have used this class this is a very good class it works as you said. then I have tried to create a user control out of it that also works on windows applications. but I was trying to put on web application using object tag there i get security error. I think native window call back message loop dose not works here. Do you have any solution for this.
The Error I got is as follows:
<b>
Stack Trace:</b>
System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
at UserControlScan.UserControlScan.button2_Click(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
The action that failed was:
InheritanceDemand
The type of the first permission that failed was:
System.Security.Permissions.SecurityPermission
The Zone of the assembly that failed was:
Intranet
Error text
Application attempted to perform an operation not allowed by the security policy. To grant this application the required permission, contact your system administrator or use the Microsoft .NET Framework Configuration tool
Please give some alternative for this
|
|
|
|
|
Dear Sir,
I used above code to scan documents
however i can't select the device(which is printer+scanner) after tw.select().
what should i do to select the device to scan..
thank you,
Bibek
|
|
|
|
|
Hi. First of all I want to apologyze for my English in advance. I'm from Argentina, and I'm working with a HP scanner. The problem is that the driver displays a splash screen with the HP logo every time I need to make a scan and i want to remove it. Do you know if that's possible programatically?. Thanks!!!
|
|
|
|
|
I've been asked to create a custom scanning app that will capture a US-Letter (8.5"x11") that saves to server w/ a specific filename format.
I've been successful with 8" width, and the scanner bed is almost 9" wide.
Attempts to set PaperSize fail (not supported for Canon CanoScan 4200F?)
capPS As TwCapability = _
New TwCapability(TwCap.SupportedSizes, TwSS.TwSS_USLetter, TwType.Int16)
Setting the Frame to 8" (or imageWidth) succeeds:
Dim myLayout As New TwImageLayout
With myLayout.Frame
.Right = 8
'other properties here..
End With
rc = Me.DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Set, myLayout) 'returns checkStatus
rc = Me.DSstatus(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, s) 'returns success
<structlayout(layoutkind.sequential, pack:="2)"> Friend Structure TwFrame
Public Left As Int32
Public Top As Int32
Public Right As Int32
Public Bottom As Int32
End Structure
I need a frame structure that will accept decimal values?
Using the structure below (from other posts), I'm running into problems:
<structlayout(layoutkind.sequential, pack:="2)"> Friend Structure TwFrame
Public Left As TwFix32
Public Top As TwFix32
Public Right As TwFix32
Public Bottom As TwFix32
End Structure
Setting the frame using:
Frame.Bottom.FromFloat(11.0)
Frame.Right.FromFloat(8.5)
'*don't set top & left as they are 0*
returns (after settings have successfully been sent to scanner)
Frame.Bottom.Whole=11
Frame.Bottom.Frac=786431
Frame.Left.Whole=0
Frame.Left.Frac=0
Frame.Right.Whole=8
Frame.Right.Frac=589823
Frame.Top.Whole=0
Frame.Top.Frac=3579117570 *why isn't this 0? perhaps structure isn't what scanner is eexpeting?*
The scanned area is not even close to what is desired.
length starts ~2" from edge and is ~9"
width starts at edge but is ~2.8"
I'd appreciate any help as I (foolishly) promised this app for the users by mid-December.
Thanks!
Paul Elstone, Queensway-Carleton Hospital, Ottawa, Canada [pElstone@qch.on.ca]
|
|
|
|
|
How would I get the program to close (using Close(); ) after you have saved the images... I'm trying to automate the thing so it runs, scans, saves and exits... very difficult without throwing loaderlock exceptions!
Please make sure you have a solution (i.e. you tried it and it worked) before posting back to me.
Qjay
|
|
|
|
|
Hi,
First of all congratulations on writing this article. Recently I have been working on creating an ActiveX DLL which could be invoked using a Javascript call from an HTML page and the scanned image could be displayed within the page. I got most of the things but when I invoke the TWAIN driver, it displays the scanning control, I can perform New Scan multiple times within it but when I click at Accept nothing happens, the same code works perfectly when I invoke it from a Windows Form.
I trapped Windows Messages, it seems that when I do a call to the ActiveX from HTML it does not send any message back when I click Accept in the Scanning control.
Help would be highly appreciated.
Regards,
|
|
|
|
|
Use the code m@u created in thread "Usage of Twain without a Form [modified]". Your problem is that IE is not a .NET Application, so System.Windows.Forms.Application.AddMessageFilter(...) doesn't work. I haven't tried m@u's code but using the NativeWindow to handle the message sounds like it will work just fine.
Breaking your theories
Sully
|
|
|
|
|
Thanks a lot finally I have successfully addressed the issue.
|
|
|
|
|
How exactly did you solve it? I have the same problem, but am having trouble getting the code to be recognized as ActiveX
|
|
|
|
|
Hi,
Can you please let me know whether this works as web application. If so can u please instruct me on the same..
I'm struggling a lot sir from many days of night outs.. Please do help me.
Thanks
Regards.....
Bharath.
|
|
|
|
|
Yep, having a very similar issue here and would be VERY gratefull if anyone could help.
In fact my problem is that it works well until I call the code from an ActiveX wrapper class, i.e., when Internet Explorer instantiates the ActiveXObject which calls the MainFrame Form. I do get to the scanner's Twain GUI, but when I click the "Scan" button, no message is ever caught in the PreFilterMessage method.
Thank you in advance for helping.
|
|
|
|
|