# Scanning DLL - issue hosting in IE - security



## aqabbas (May 8, 2007)

I have created a very simple DLL in C# that scans (TWAIN) and saves the image to a temp file form which I read into a Picturebox.

When I use the DLL in a Windows form, it works perfectly. when I use it in an HTML page, the page scans but then everything hangs. The image is not saved to a temp file and nothing is rendered. Since it is only happening in IE, it seems to an issue with security.

The code for the scanner is below:

*FILE: DOTSCAN.CS*
using System;
using System.Collections;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Data;
using System.Windows.Forms;
using System.IO;
using System.Security;
using System.Security.Permissions;
using GdiPlusLib;
using TwainLib;

namespace DotScan
{
/// 
/// Summary description for UserControl1.
/// 
///

[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
[FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
public class DotScan : System.Windows.Forms.UserControl, IMessageFilter
{
private System.ComponentModel.IContainer components;
private System.Windows.Forms.Panel panel1;
private bool	msgfilter;
private Twain	tw;
IntPtr	bmpptr;
IntPtr	pixptr;
BITMAPINFOHEADER	bmi;
Rectangle bmprect;

private System.Windows.Forms.Button btnFile;
//private int picnumber = 0;

string imageFileName;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.PictureBox pictureBox1;

public DotScan()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();

// TODO: Add any initialization after the InitComponent call

}

/// 
/// Clean up any resources being used.
/// 
protected override void Dispose( bool disposing )
{
if( disposing )
{
tw.Finish();
if (components != null) 
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Component Designer generated code
/// 
/// Required method for Designer support - do not modify 
/// the contents of this method with the code editor.
/// 
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.button1 = new System.Windows.Forms.Button();
this.btnFile = new System.Windows.Forms.Button();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.panel1.SuspendLayout();
this.SuspendLayout();
// 
// panel1
// 
this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
this.panel1.Controls.Add(this.button1);
this.panel1.Controls.Add(this.btnFile);
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.DockPadding.All = 1;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(760, 56);
this.panel1.TabIndex = 1;
// 
// button1
// 
this.button1.Location = new System.Drawing.Point(144, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(136, 40);
this.button1.TabIndex = 33;
this.button1.Text = "Select Source";
this.button1.Click += new System.EventHandler(this.button1_Click);
// 
// btnFile
// 
this.btnFile.Location = new System.Drawing.Point(8, 8);
this.btnFile.Name = "btnFile";
this.btnFile.Size = new System.Drawing.Size(120, 40);
this.btnFile.TabIndex = 0;
this.btnFile.Text = "Scan";
this.btnFile.Click += new System.EventHandler(this.btnFile_Click);
// 
// pictureBox1
// 
this.pictureBox1.Location = new System.Drawing.Point(8, 56);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(744, 352);
this.pictureBox1.TabIndex = 2;
this.pictureBox1.TabStop = false;
// 
// DotScan
// 
this.BackColor = System.Drawing.SystemColors.ActiveCaptionText;
this.Controls.Add(this.pictureBox1);
this.Controls.Add(this.panel1);
this.Name = "DotScan";
this.Size = new System.Drawing.Size(760, 416);
this.Load += new System.EventHandler(this.DotScan_Load);
this.panel1.ResumeLayout(false);
this.ResumeLayout(false);

}
#endregion

private void DotScan_Load(object sender, System.EventArgs e)
{
//Initialize TWAIN
tw = new Twain();
tw.Init( this.Handle );
}

bool IMessageFilter.PreFilterMessage( ref Message m )
{
TwainCommand cmd = tw.PassMessage( ref m );
if( cmd == TwainCommand.Not )
return false;

switch( cmd )
{
case TwainCommand.CloseRequest:
{
EndingScan();
tw.CloseSrc();
break;
}
case TwainCommand.CloseOk:
{
EndingScan();
tw.CloseSrc();
break;
}
case TwainCommand.DeviceEvent:
{
break;
}
case TwainCommand.TransferReady:
{
ArrayList pics = tw.TransferPictures();
EndingScan();
tw.CloseSrc();

if (pics.Count>0)
{
imageFileName = Path.GetTempFileName();
File.Delete(imageFileName);
imageFileName = imageFileName.Substring(0, imageFileName.Length - 4);

for( int i = 0; i < pics.Count; i++ )
{
IntPtr img = (IntPtr) pics[ i ];
bmprect = new Rectangle( 0, 0, 0, 0 );
bmpptr = GlobalLock( img );
pixptr = GetPixelInfo( bmpptr );
Gdip.SaveDIBAs(imageFileName + ".TIF", bmpptr, pixptr );
pictureBox1.Image= Image.FromFile(imageFileName + ".TIF");
}
}
break;
}
}

return true;
}

private void EndingScan()
{
if( msgfilter )
{
Application.RemoveMessageFilter( this );
msgfilter = false;
this.Enabled = true;
}
}

protected IntPtr GetPixelInfo( IntPtr bmpptr )
{
bmi = new BITMAPINFOHEADER();
Marshal.PtrToStructure( bmpptr, bmi );

bmprect.X = bmprect.Y = 0;
bmprect.Width = bmi.biWidth;
bmprect.Height = bmi.biHeight;

if( bmi.biSizeImage == 0 )
bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight;

int p = bmi.biClrUsed;
if( (p == 0) && (bmi.biBitCount <= 8) )
p = 1 << bmi.biBitCount;
p = (p * 4) + bmi.biSize + (int) bmpptr;
return (IntPtr) p;
}

[DllImport("kernel32.dll", ExactSpelling=true)]
internal static extern IntPtr GlobalLock( IntPtr handle );

private void btnFile_Click(object sender, System.EventArgs e)
{
ScanPages();
}

private void ScanPages()
{
if( ! msgfilter )
{
this.Enabled = false;
msgfilter = true;
Application.AddMessageFilter( this );
}
tw.Acquire(); 
}

private void button1_Click(object sender, System.EventArgs e)
{
tw.Select();
}
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal class BITMAPINFOHEADER
{
public int biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;
public int biCompression;
public int biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int biClrImportant;
}

}

*FILE: GDIPLUSLIB.CS*
using System;
using System.IO;
using System.Collections;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Security;
using System.Security.Permissions;

namespace GdiPlusLib
{

[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
[FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
[UIPermission(SecurityAction.Assert, Unrestricted=true)]
[PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
public class Gdip
{
private static ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

private static bool GetCodecClsid( string filename, out Guid clsid )
{
//new FileIOPermission(PermissionState.Unrestricted).Assert();
clsid = Guid.Empty;
string ext = Path.GetExtension( filename );
if( ext == null )
return false;
ext = "*" + ext.ToUpper();
foreach( ImageCodecInfo codec in codecs )
{
if( codec.FilenameExtension.IndexOf( ext ) >= 0 )
{
clsid = codec.Clsid;
//CodeAccessPermission.RevertAssert();
return true;
}
}
//CodeAccessPermission.RevertAssert();
return false;
}

public static bool SaveDIBAs( string picname, IntPtr bminfo, IntPtr pixdat )
{
//SaveFileDialog sd = new SaveFileDialog();

//sd.FileName = picname;
//sd.Title = "Save bitmap as...";
//sd.Filter = "Bitmap file (*.bmp)|*.bmp|TIFF file (*.tif)|*.tif|JPEG file (*.jpg)|*.jpg|PNG file (*.png)|*.png|GIF file (*.gif)|*.gif|All files (*.*)|*.*";
//sd.FilterIndex = 1;
//if( sd.ShowDialog() != DialogResult.OK )
//	return false;

try
{
Guid clsid;
//new FileIOPermission(PermissionState.Unrestricted).Assert();
GetCodecClsid( picname, out clsid );

//if( ! GetCodecClsid( picname, out clsid ) )
//	{
//	MessageBox.Show( "Unknown picture format for extension " + Path.GetExtension( sd.FileName ),
// "Image Codec", MessageBoxButtons.OK, MessageBoxIcon.Information );
//	return false;
//	}

IntPtr img = IntPtr.Zero;
int st = GdipCreateBitmapFromGdiDib( bminfo, pixdat, ref img );
if( (st != 0) || (img == IntPtr.Zero) )
//CodeAccessPermission.RevertAssert();
return false;

st = GdipSaveImageToFile( img, picname, ref clsid, IntPtr.Zero );
GdipDisposeImage( img );
//CodeAccessPermission.RevertAssert();
return st == 0;
}
catch ( Exception e )
{
MessageBox.Show(e.ToString());
return false;
}
}

[DllImport("gdiplus.dll", ExactSpelling=true)]
internal static extern int GdipCreateBitmapFromGdiDib( IntPtr bminfo, IntPtr pixdat, ref IntPtr image );

[DllImport("gdiplus.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
internal static extern int GdipSaveImageToFile( IntPtr image, string filename, [In] ref Guid clsid, IntPtr encparams );

[DllImport("gdiplus.dll", ExactSpelling=true)]
internal static extern int GdipDisposeImage( IntPtr image );

}

} // namespace GdiPlusLib

*FILE: TWAINLIB.CS*
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Security;
using System.Security.Permissions;

namespace TwainLib
{
public enum TwainCommand
{
Not = -1,
Null = 0,
TransferReady	= 1,
CloseRequest	= 2,
CloseOk = 3,
DeviceEvent = 4
}

[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
[FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
[UIPermission(SecurityAction.Assert, Unrestricted=true)]
public class Twain
{
private const short CountryUSA = 1;
private const short LanguageUSA = 13;

public Twain()
{
appid = new TwIdentity();
appid.Id = IntPtr.Zero;
appid.Version.MajorNum	= 1;
appid.Version.MinorNum	= 1;
appid.Version.Language	= LanguageUSA;
appid.Version.Country	= CountryUSA;
appid.Version.Info = "Hack 1";
appid.ProtocolMajor = TwProtocol.Major;
appid.ProtocolMinor = TwProtocol.Minor;
appid.SupportedGroups	= (int)(TwDG.Image | TwDG.Control);
//appid.Manufacturer = "NETMaster";
//appid.ProductFamily = "Freeware";
//appid.ProductName = "Hack";

srcds = new TwIdentity();
srcds.Id = IntPtr.Zero;

evtmsg.EventPtr = Marshal.AllocHGlobal( Marshal.SizeOf( winmsg ) );
}

~Twain()
{
Marshal.FreeHGlobal( evtmsg.EventPtr );
}

public void Init( IntPtr hwndp )
{
Finish();
TwRC rc = DSMparent( appid, IntPtr.Zero, TwDG.Control, TwDAT.Parent, TwMSG.OpenDSM, ref hwndp );
if( rc == TwRC.Success )
{
rc = DSMident( appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetDefault, srcds );
if( rc == TwRC.Success )
hwnd = hwndp;
else
rc = DSMparent( appid, IntPtr.Zero, TwDG.Control, TwDAT.Parent, TwMSG.CloseDSM, ref hwndp );
}
}

public void Select()
{
TwRC rc;
CloseSrc();
if( appid.Id == IntPtr.Zero )
{
Init( hwnd );
if( appid.Id == IntPtr.Zero )
return;
}
rc = DSMident( appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.UserSelect, srcds );
}

public void Acquire()
{
TwRC rc;
CloseSrc();
if( appid.Id == IntPtr.Zero )
{
Init( hwnd );
if( appid.Id == IntPtr.Zero )
return;
}
rc = DSMident( appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.OpenDS, srcds );
if( rc != TwRC.Success )
return;

TwCapability cap = new TwCapability( TwCap.XferCount, 1 );
rc = DScap( appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, cap );
if( rc != TwRC.Success )
{
CloseSrc();
return;
}

TwUserInterface	guif = new TwUserInterface();
guif.ShowUI = 1;
guif.ModalUI = 1;
guif.ParentHand = hwnd;
rc = DSuserif( appid, srcds, TwDG.Control, TwDAT.UserInterface, TwMSG.EnableDS, guif );
if( rc != TwRC.Success )
{
CloseSrc();
return;
}
}

public ArrayList TransferPictures()
{
ArrayList pics = new ArrayList();
if( srcds.Id == IntPtr.Zero )
return pics;

TwRC rc;
IntPtr hbitmap = IntPtr.Zero;
TwPendingXfers pxfr = new TwPendingXfers();

do
{
pxfr.Count = 0;
hbitmap = IntPtr.Zero;

TwImageInfo	iinf = new TwImageInfo();
rc = DSiinf( appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf );
if( rc != TwRC.Success )
{
CloseSrc();
return pics;
}

rc = DSixfer( appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, ref hbitmap );
if( rc != TwRC.XferDone )
{
CloseSrc();
return pics;
}

rc = DSpxfer( appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.EndXfer, pxfr );
if( rc != TwRC.Success )
{
CloseSrc();
return pics;
}

pics.Add( hbitmap );
}
while( pxfr.Count != 0 );

rc = DSpxfer( appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.Reset, pxfr );
return pics;
}

public TwainCommand PassMessage( ref Message m )
{
if( srcds.Id == IntPtr.Zero )
return TwainCommand.Not;

int pos = GetMessagePos();

winmsg.hwnd = m.HWnd;
winmsg.message	= m.Msg;
winmsg.wParam	= m.WParam;
winmsg.lParam	= m.LParam;
winmsg.time = GetMessageTime();
winmsg.x = (short) pos;
winmsg.y = (short) (pos >> 16);

Marshal.StructureToPtr( winmsg, evtmsg.EventPtr, false );
evtmsg.Message = 0;
TwRC rc = DSevent( appid, srcds, TwDG.Control, TwDAT.Event, TwMSG.ProcessEvent, ref evtmsg );
if( rc == TwRC.NotDSEvent )
return TwainCommand.Not;
if( evtmsg.Message == (short) TwMSG.XFerReady )
return TwainCommand.TransferReady;
if( evtmsg.Message == (short) TwMSG.CloseDSReq )
return TwainCommand.CloseRequest;
if( evtmsg.Message == (short) TwMSG.CloseDSOK )
return TwainCommand.CloseOk;
if( evtmsg.Message == (short) TwMSG.DeviceEvent )
return TwainCommand.DeviceEvent;

return TwainCommand.Null;
}

public void CloseSrc()
{
TwRC rc;
if( srcds.Id != IntPtr.Zero )
{
TwUserInterface	guif = new TwUserInterface();
rc = DSuserif( appid, srcds, TwDG.Control, TwDAT.UserInterface, TwMSG.DisableDS, guif );
rc = DSMident( appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.CloseDS, srcds );
}
}

public void Finish()
{
TwRC rc;
CloseSrc();
if( appid.Id != IntPtr.Zero )
rc = DSMparent( appid, IntPtr.Zero, TwDG.Control, TwDAT.Parent, TwMSG.CloseDSM, ref hwnd );
appid.Id = IntPtr.Zero;
}

private IntPtr hwnd;
private TwIdentity	appid;
private TwIdentity	srcds;
private TwEvent evtmsg;
private WINMSG winmsg;

// ------ DSM entry point DAT_ variants:
[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSMparent( [In, Out] TwIdentity origin, IntPtr zeroptr, TwDG dg, TwDAT dat, TwMSG msg, ref IntPtr refptr );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSMident( [In, Out] TwIdentity origin, IntPtr zeroptr, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwIdentity idds );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSMstatus( [In, Out] TwIdentity origin, IntPtr zeroptr, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwStatus dsmstat );

// ------ DSM entry point DAT_ variants to DS:
[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSuserif( [In, Out] TwIdentity origin, [In, Out] TwIdentity dest, TwDG dg, TwDAT dat, TwMSG msg, TwUserInterface guif );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSevent( [In, Out] TwIdentity origin, [In, Out] TwIdentity dest, TwDG dg, TwDAT dat, TwMSG msg, ref TwEvent evt );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSstatus( [In, Out] TwIdentity origin, [In] TwIdentity dest, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwStatus dsmstat );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DScap( [In, Out] TwIdentity origin, [In] TwIdentity dest, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwCapability capa );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSiinf( [In, Out] TwIdentity origin, [In] TwIdentity dest, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwImageInfo imginf );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSixfer( [In, Out] TwIdentity origin, [In] TwIdentity dest, TwDG dg, TwDAT dat, TwMSG msg, ref IntPtr hbitmap );

[DllImport("twain_32.dll", EntryPoint="#1")]
private static extern TwRC DSpxfer( [In, Out] TwIdentity origin, [In] TwIdentity dest, TwDG dg, TwDAT dat, TwMSG msg, [In, Out] TwPendingXfers pxfr );

[DllImport("kernel32.dll", ExactSpelling=true)]
internal static extern IntPtr GlobalAlloc( int flags, int size );
[DllImport("kernel32.dll", ExactSpelling=true)]
internal static extern IntPtr GlobalLock( IntPtr handle );
[DllImport("kernel32.dll", ExactSpelling=true)]
internal static extern bool GlobalUnlock( IntPtr handle );
[DllImport("kernel32.dll", ExactSpelling=true)]
internal static extern IntPtr GlobalFree( IntPtr handle );

[DllImport("user32.dll", ExactSpelling=true)]
private static extern int GetMessagePos();
[DllImport("user32.dll", ExactSpelling=true)]
private static extern int GetMessageTime();

[DllImport("gdi32.dll", ExactSpelling=true)]
private static extern int GetDeviceCaps( IntPtr hDC, int nIndex );

[DllImport("gdi32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr CreateDC( string szdriver, string szdevice, string szoutput, IntPtr devmode );

[DllImport("gdi32.dll", ExactSpelling=true)]
private static extern bool DeleteDC( IntPtr hdc );

//public static int ScreenBitDepth {
//	get {
// IntPtr screenDC = CreateDC( "DISPLAY", null, null, IntPtr.Zero );
// int bitDepth = GetDeviceCaps( screenDC, 12 );
// bitDepth *= GetDeviceCaps( screenDC, 14 );
// DeleteDC( screenDC );
// return bitDepth;
// }
//	}

[StructLayout(LayoutKind.Sequential, Pack=4)]
internal struct WINMSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public int x;
public int y;
}

} // class Twain
}

*FILE: TWAINDEFS.CS*
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TwainLib
{

public class TwProtocol
{ // TWON_PROTOCOL...
public const short Major	= 1;
public const short Minor	= 9;
}

[Flags]
internal enum TwDG : short
{ // DG_.....
Control = 0x0001,
Image = 0x0002,
Audio = 0x0004
}

internal enum TwDAT : short
{ // DAT_....
Null = 0x0000,
Capability = 0x0001,
Event = 0x0002,
Identity = 0x0003,
Parent = 0x0004,
PendingXfers	= 0x0005,
SetupMemXfer	= 0x0006,
SetupFileXfer	= 0x0007,
Status = 0x0008,
UserInterface	= 0x0009,
XferGroup = 0x000a,
TwunkIdentity	= 0x000b,
CustomDSData	= 0x000c,
DeviceEvent = 0x000d,
FileSystem = 0x000e,
PassThru = 0x000f,

ImageInfo = 0x0101,
ImageLayout = 0x0102,
ImageMemXfer	= 0x0103,
ImageNativeXfer	= 0x0104,
ImageFileXfer	= 0x0105,
CieColor = 0x0106,
GrayResponse	= 0x0107,
RGBResponse = 0x0108,
JpegCompression	= 0x0109,
Palette8 = 0x010a,
ExtImageInfo	= 0x010b,

SetupFileXfer2	= 0x0301
}

internal enum TwMSG : short
{ // MSG_.....
Null = 0x0000,
Get = 0x0001,
GetCurrent = 0x0002,
GetDefault = 0x0003,
GetFirst = 0x0004,
GetNext = 0x0005,
Set = 0x0006,
Reset = 0x0007,
QuerySupport	= 0x0008,

XFerReady = 0x0101,
CloseDSReq = 0x0102,
CloseDSOK = 0x0103,
DeviceEvent = 0x0104,

CheckStatus = 0x0201,

OpenDSM = 0x0301,
CloseDSM = 0x0302,

OpenDS = 0x0401,
CloseDS = 0x0402,
UserSelect = 0x0403,

DisableDS = 0x0501,
EnableDS = 0x0502,
EnableDSUIOnly	= 0x0503,

ProcessEvent	= 0x0601,

EndXfer = 0x0701,
StopFeeder = 0x0702,

ChangeDirectory	= 0x0801,
CreateDirectory	= 0x0802,
Delete = 0x0803,
FormatMedia = 0x0804,
GetClose = 0x0805,
GetFirstFile	= 0x0806,
GetInfo = 0x0807,
GetNextFile = 0x0808,
Rename = 0x0809,
Copy = 0x080A,
AutoCaptureDir	= 0x080B,

PassThru = 0x0901
}

internal enum TwRC : short
{ // TWRC_....
Success = 0x0000,
Failure = 0x0001,
CheckStatus = 0x0002,
Cancel = 0x0003,
DSEvent = 0x0004,
NotDSEvent = 0x0005,
XferDone = 0x0006,
EndOfList = 0x0007,
InfoNotSupported	= 0x0008,
DataNotAvailable	= 0x0009
}

internal enum TwCC : short
{ // TWCC_....
Success = 0x0000,
Bummer = 0x0001,
LowMemory = 0x0002,
NoDS = 0x0003,
MaxConnections = 0x0004,
OperationError = 0x0005,
BadCap = 0x0006,
BadProtocol = 0x0009,
BadValue = 0x000a,
SeqError = 0x000b,
BadDest = 0x000c,
CapUnsupported = 0x000d,
CapBadOperation = 0x000e,
CapSeqError = 0x000f,
Denied = 0x0010,
FileExists = 0x0011,
FileNotFound = 0x0012,
NotEmpty = 0x0013,
PaperJam = 0x0014,
PaperDoubleFeed = 0x0015,
FileWriteError = 0x0016,
CheckDeviceOnline	= 0x0017
}

internal enum TwOn : short
{ // TWON_....
Array = 0x0003,
Enum = 0x0004,
One = 0x0005,
Range = 0x0006,
DontCare = -1
}

internal enum TwType : short
{ // TWTY_....
Int8 = 0x0000,
Int16 = 0x0001,
Int32 = 0x0002,
UInt8 = 0x0003,
UInt16 = 0x0004,
UInt32 = 0x0005,
Bool = 0x0006,
Fix32 = 0x0007,
Frame = 0x0008,
Str32 = 0x0009,
Str64 = 0x000a,
Str128 = 0x000b,
Str255 = 0x000c,
Str1024 = 0x000d,
Str512 = 0x000e
}

internal enum TwCap : short
{
XferCount = 0x0001, // CAP_XFERCOUNT
ICompression	= 0x0100, // ICAP_...
IPixelType = 0x0101,
IUnits = 0x0102,
IXferMech = 0x0103
}

// ------------------- STRUCTS --------------------------------------------

[StructLayout(LayoutKind.Sequential, Pack=2, CharSet=CharSet.Ansi)]
internal class TwIdentity
{ // TW_IDENTITY
public IntPtr Id;
public TwVersion	Version;
public short ProtocolMajor;
public short ProtocolMinor;
public int SupportedGroups;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=34)]
public string Manufacturer;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=34)]
public string ProductFamily;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=34)]
public string ProductName;
}

[StructLayout(LayoutKind.Sequential, Pack=2, CharSet=CharSet.Ansi)]
internal struct TwVersion
{ // TW_VERSION
public short MajorNum;
public short MinorNum;
public short Language;
public short Country;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=34)]
public string Info;
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal class TwUserInterface
{ // TW_USERINTERFACE
public short ShowUI; // bool is strictly 32 bit, so use short
public short ModalUI;
public IntPtr ParentHand;
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal class TwStatus
{ // TW_STATUS
public short ConditionCode; // TwCC
public short Reserved;
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal struct TwEvent
{ // TW_EVENT
public IntPtr EventPtr;
public short Message;
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal class TwImageInfo
{ // TW_IMAGEINFO
public int XResolution;
public int YResolution;
public int ImageWidth;
public int ImageLength;
public short SamplesPerPixel;
[MarshalAs( UnmanagedType.ByValArray, SizeConst=8)] 
public short[] BitsPerSample;
public short BitsPerPixel;
public short Planar;
public short PixelType;
public short Compression;
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal class TwPendingXfers
{ // TW_PENDINGXFERS
public short Count;
public int EOJ;
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal struct TwFix32
{ // TW_FIX32
public short Whole;
public ushort Frac;

public float ToFloat()
{
return (float) Whole + ( (float)Frac /65536.0f );
}
public void FromFloat( float f )
{
int i = (int)((f * 65536.0f) + 0.5f);
Whole = (short) (i >> 16);
Frac = (ushort) (i & 0x0000ffff);
}
}

[StructLayout(LayoutKind.Sequential, Pack=2)]
internal class TwCapability
{ // TW_CAPABILITY
public TwCapability( TwCap cap )
{
Cap = (short) cap;
ConType = -1;
}
public TwCapability( TwCap cap, short sval )
{
Cap = (short) cap;
ConType = (short) TwOn.One;
Handle = Twain.GlobalAlloc( 0x42, 6 );
IntPtr pv = Twain.GlobalLock( Handle );
Marshal.WriteInt16( pv, 0, (short) TwType.Int16 );
Marshal.WriteInt32( pv, 2, (int) sval );
Twain.GlobalUnlock( Handle );
}
~TwCapability()
{
if( Handle != IntPtr.Zero )
Twain.GlobalFree( Handle );
}
public short Cap;
public short ConType;
public IntPtr Handle;
}

} // namespace TwainLib


----------

