|
TwainLib.vb
Imports System
Imports System.Collections
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Namespace TwainLib
Public Enum TwainCommand
[Not] = -1
Null = 0
TransferReady = 1
CloseRequest = 2
CloseOk = 3
DeviceEvent = 4
Failure = 5
End Enum
Public Class Twain
Private hwnd As IntPtr
Private appid As TwIdentity
Private srcds As TwIdentity
Private evtmsg As TwEvent
Private winmsg_m As WINMSG_S
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSMparent(<[In](), Out()> ByVal origin As TwIdentity, ByVal zeroptr As IntPtr, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, ByRef refptr As IntPtr) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSMident(<[In](), Out()> ByVal origin As TwIdentity, ByVal zeroptr As IntPtr, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal idds As TwIdentity) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSMstatus(<[In](), Out()> ByVal origin As TwIdentity, ByVal zeroptr As IntPtr, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal dsmstat As TwStatus) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSuserif(<[In](), Out()> ByVal origin As TwIdentity, <[In](), Out()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, ByVal guif As TwUserInterface) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSevent(<[In](), Out()> ByVal origin As TwIdentity, <[In](), Out()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, ByRef evt As TwEvent) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSstatus(<[In](), Out()> ByVal origin As TwIdentity, <[In]()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal dsmstat As TwStatus) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DScap(<[In](), Out()> ByVal origin As TwIdentity, <[In]()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal capa As TwCapability) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSiinf(<[In](), Out()> ByVal origin As TwIdentity, <[In]()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal imginf As TwImageInfo) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSixfer(<[In](), Out()> ByVal origin As TwIdentity, <[In]()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, ByRef hbitmap As IntPtr) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSpxfer(<[In](), Out()> ByVal origin As TwIdentity, <[In]()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal pxfr As TwPendingXfers) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSilayout(<[In](), Out()> ByVal origin As TwIdentity, <[In](), Out()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal imglo As TwImageLayout) As TwRC
End Function
<DllImport("twain_32.dll", EntryPoint:="#1")> Private Shared Function DSMlayout(<[In](), Out()> ByVal origin As TwIdentity, <[In](), Out()> ByVal dest As TwIdentity, ByVal dg As TwDG, ByVal dat As TwDAT, ByVal msg As TwMSG, <[In](), Out()> ByVal imglo As IntPtr) As TwRC
End Function
<DllImport("kernel32.dll", ExactSpelling:=True)> Friend Shared Function GlobalAlloc(ByVal flags As Integer, ByVal size As Integer) As IntPtr
End Function
<DllImport("kernel32.dll", ExactSpelling:=True)> Friend Shared Function GlobalLock(ByVal handle As IntPtr) As IntPtr
End Function
<DllImport("kernel32.dll", ExactSpelling:=True)> Friend Shared Function GlobalUnlock(ByVal handle As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", ExactSpelling:=True)> Friend Shared Function GlobalFree(ByVal handle As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", ExactSpelling:=True)> Private Shared Function GetMessagePos() As Integer
End Function
<DllImport("user32.dll", ExactSpelling:=True)> Private Shared Function GetMessageTime() As Integer
End Function
<DllImport("gdi32.dll", ExactSpelling:=True)> Private Shared Function GetDeviceCaps(ByVal hDC As IntPtr, ByVal nIndex As Integer) As Integer
End Function
<DllImport("gdi32.dll", CharSet:=CharSet.Auto)> Private Shared Function CreateDC(ByVal szdriver As String, ByVal szdevice As String, ByVal szoutput As String, ByVal devmode As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll", ExactSpelling:=True)> Private Shared Function DeleteDC(ByVal hdc As IntPtr) As Boolean
End Function
Private Const CountryUSA As Short = 1
Private Const LanguageUSA As Short = 13
Public Sub New()
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 = "TWAIN Scanner"
appid.ProtocolMajor = TwProtocol.Major
appid.ProtocolMinor = TwProtocol.Minor
appid.SupportedGroups = CType(TwDG.Image Or TwDG.Control, Integer)
appid.Manufacturer = "Kod Efisien Sdn Bhd"
appid.ProductFamily = "TWAIN 32 Scanner"
appid.ProductName = "ScanSoft"
srcds = New TwIdentity
srcds.Id = IntPtr.Zero
evtmsg.EventPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winmsg_m))
End Sub
Public Sub Dispose()
Marshal.FreeHGlobal(evtmsg.EventPtr)
End Sub
Protected Overrides Sub Finalize()
Marshal.FreeHGlobal(evtmsg.EventPtr)
End Sub
Public Sub Init(ByVal hwndp As IntPtr)
Finish()
Dim rc As TwRC = DSMparent(appid, IntPtr.Zero, TwDG.Control, TwDAT.Parent, TwMSG.OpenDSM, hwndp)
If (rc = TwRC.Success) Then
rc = DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetDefault, srcds)
If (rc = TwRC.Success) Then
hwnd = hwndp
Else
rc = DSMparent(appid, IntPtr.Zero, TwDG.Control, TwDAT.Parent, TwMSG.CloseDSM, hwndp)
End If
End If
End Sub
Public Sub [Select](Optional ByRef Model As String = "")
Dim rc As TwRC
CloseSrc()
If Equals(appid.Id, IntPtr.Zero) = True Then
Init(hwnd)
If Equals(appid.Id, IntPtr.Zero) = True Then
Return
End If
End If
rc = DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.UserSelect, srcds)
Model = srcds.ProductName.ToString
End Sub
Public Sub [SelectDefault](Optional ByRef Model As String = "")
Dim rc As TwRC
CloseSrc()
If Equals(appid.Id, IntPtr.Zero) = True Then
Init(hwnd)
If Equals(appid.Id, IntPtr.Zero) = True Then
Return
End If
End If
rc = DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetDefault, srcds)
Model = srcds.ProductName.ToString
End Sub
Public Sub Acquire(Optional ByVal PaperSize As TwSS = TwSS.TwSS_A4, Optional ByVal XScale As Single = 1, _
Optional ByVal YScale As Single = 1, Optional ByVal SColor As TwColourType = TwColourType.twRGB, _
Optional ByVal TopMargin As Single = 0.0, Optional ByVal LeftMargin As Single = 0.0, _
Optional ByVal RightMargin As Single = 0.0, Optional ByVal BottomMargin As Single = 0.0, _
Optional ByVal FrameNumber As Integer = 1, Optional ByVal PageNumber As Integer = 1, _
Optional ByVal DocumentNumber As Integer = 1)
Dim rc As TwRC
CloseSrc()
If Equals(appid.Id, IntPtr.Zero) = True Then
Init(hwnd)
If Equals(appid.Id, IntPtr.Zero) = True Then
Return
End If
End If
rc = DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.OpenDS, srcds)
If (rc <> TwRC.Success) Then
Return
End If
'Set Unit to Pixels
Dim Pixels As TwUnit = TwUnit.twPIXELS
Dim capUnit As TwCapability = New TwCapability(TwCap.IUnits, Pixels, TwType.Int16)
rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, capUnit)
If rc <> TwRC.Success Then
CloseSrc()
Return
End If
''Set X Resolution
'Dim XResolution As Single = 1
'Dim capX As TwCapability = New TwCapability(TwCap.XResolution, XResolution, TwType.Fix32)
'rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, capX)
'If rc <> TwRC.Success Then
' CloseSrc()
' Return
'End If
''Set Y Resolution
'Dim capY As TwCapability = New TwCapability(TwCap.YResolution, YResolution, TwType.Fix32)
'rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, capY)
'If rc <> TwRC.Success Then
' CloseSrc()
' Return
'End If
Dim xcap As TwCapability = New TwCapability(TwCap.XScaling, XScale, TwType.Fix32)
rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, xcap)
If rc <> TwRC.Success Then
CloseSrc()
Return
End If
xcap = New TwCapability(TwCap.YScaling, YScale, TwType.Fix32)
rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, xcap)
If rc <> TwRC.Success Then
CloseSrc()
Return
End If
Dim ps As TwCapability = New TwCapability(TwCap.SupportedSizes, PaperSize, TwType.Int16)
rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, ps)
If rc <> TwRC.Success Then
CloseSrc()
Return
End If
'Set Layout
Dim Layout As TwImageLayout = New TwImageLayout
rc = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, Layout)
If rc <> TwRC.Success Then
CloseSrc()
Return
End If
If TopMargin > 0 Then
Layout.Frame.Top.FromFloat(CSng(TopMargin))
End If
If LeftMargin > 0 Then
Layout.Frame.Left.FromFloat(CSng(LeftMargin))
End If
If RightMargin > 0 Then
Layout.Frame.Right.FromFloat(CSng(RightMargin))
End If
If BottomMargin > 0 Then
Layout.Frame.Bottom.FromFloat(CSng(BottomMargin))
End If
Layout.FrameNumber = 1
Layout.PageNumber = 1
Layout.DocumentNumber = 1
rc = Me.DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Set, Layout)
If rc <> TwRC.Success Then
CloseSrc()
Return
End If
'Dim ptr1 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Layout))
'Marshal.StructureToPtr(Layout, ptr1, False)
'rc = Me.DSMlayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, ptr1)
'If rc <> TwRC.Success Then
' CloseSrc()
' Return
'End If
''Dim ptr2 As IntPtr = ptr1
'Marshal.PtrToStructure(ptr1, Layout)
'If TopMargin > 0 Then
' Layout.Frame.Top.FromFloat(CSng(TopMargin))
'End If
'If LeftMargin > 0 Then
' Layout.Frame.Left.FromFloat(CSng(LeftMargin))
'End If
'If RightMargin > 0 Then
' Layout.Frame.Right.FromFloat(CSng(RightMargin))
'End If
'If BottomMargin > 0 Then
' Layout.Frame.Bottom.FromFloat(CSng(BottomMargin))
'End If
'Layout.FrameNumber = 1
'Layout.PageNumber = 1
'Layout.DocumentNumber = 1
'Marshal.StructureToPtr(Layout, ptr1, True)
'rc = Me.DSMlayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Set, ptr1)
'If rc <> TwRC.Success Then
' CloseSrc()
' Return
'End If
'Scan Colour
Dim Ccap As TwCapability = New TwCapability(TwCap.IPixelType, SColor, TwType.UInt16)
rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, Ccap)
If (rc <> TwRC.Success) Then
CloseSrc()
Return
End If
Dim cap As TwCapability = New TwCapability(TwCap.XferCount, 1, TwType.Int16)
rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, cap)
If (rc <> TwRC.Success) Then
CloseSrc()
Return
End If
Dim guif As TwUserInterface = 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) Then
CloseSrc()
Return
End If
End Sub
Public Function TransferPictures() As ArrayList
Dim pics As ArrayList = New ArrayList
If Equals(srcds.Id, IntPtr.Zero) Then
Return pics
End If
Dim rc As TwRC
Dim hbitmap As IntPtr = IntPtr.Zero
Dim pxfr As TwPendingXfers = New TwPendingXfers
Do
pxfr.Count = 0
hbitmap = IntPtr.Zero
Dim iinf As TwImageInfo = New TwImageInfo
rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf)
If (rc <> TwRC.Success) Then
CloseSrc()
Return pics
End If
'StartScan
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, hbitmap)
If (rc <> TwRC.XferDone) Then
CloseSrc()
Return pics
End If
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.EndXfer, pxfr)
If (rc <> TwRC.Success) Then
CloseSrc()
Return pics
End If
pics.Add(hbitmap)
Loop While (pxfr.Count <> 0)
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.Reset, pxfr)
Return pics
End Function
Public Function PassMessage(ByVal m As Message) As TwainCommand
If Equals(srcds.Id, IntPtr.Zero) Then
Return TwainCommand.Not
End If
Dim pos As Integer = GetMessagePos()
winmsg_m.hwnd = m.HWnd
winmsg_m.message = m.Msg
winmsg_m.wParam = m.WParam
winmsg_m.lParam = m.LParam
winmsg_m.time = GetMessageTime()
winmsg_m.x = pos 'CType(pos, Short)
winmsg_m.y = Int(pos / 2 ^ 16) 'CType(Int(pos / 2 ^ 16), Short)
Marshal.StructureToPtr(winmsg_m, evtmsg.EventPtr, False)
evtmsg.Message = 0
Dim rc As TwRC = DSevent(appid, srcds, TwDG.Control, TwDAT.Event, TwMSG.ProcessEvent, evtmsg)
If (rc = TwRC.NotDSEvent) Then
Return TwainCommand.Not
End If
If (rc = TwRC.Failure) Then
Return TwainCommand.Failure
End If
If (evtmsg.Message = CType(TwMSG.XFerReady, Short)) Then
Return TwainCommand.TransferReady
End If
If (evtmsg.Message = CType(TwMSG.CloseDSReq, Short)) Then
Return TwainCommand.CloseRequest
End If
If (evtmsg.Message = CType(TwMSG.CloseDSOK, Short)) Then
Return TwainCommand.CloseOk
End If
If (evtmsg.Message = CType(TwMSG.DeviceEvent, Short)) Then
Return TwainCommand.DeviceEvent
End If
Return TwainCommand.Null
End Function
Public Sub CloseSrc()
Dim rc As TwRC
If Not Equals(srcds.Id, IntPtr.Zero) Then
Dim guif As TwUserInterface = 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)
End If
End Sub
Public Sub Finish()
Dim rc As TwRC
CloseSrc()
If Not Equals(appid.Id, IntPtr.Zero) Then
rc = DSMparent(appid, IntPtr.Zero, TwDG.Control, TwDAT.Parent, TwMSG.CloseDSM, hwnd)
End If
appid.Id = IntPtr.Zero
End Sub
Public Shared ReadOnly Property ScreenBitDepth() As Integer
Get
Dim screenDC As IntPtr = CreateDC("DISPLAY", Nothing, Nothing, IntPtr.Zero)
Dim bitDepth As Integer = GetDeviceCaps(screenDC, 12)
bitDepth *= GetDeviceCaps(screenDC, 14)
DeleteDC(screenDC)
Return bitDepth
End Get
End Property
<StructLayout(LayoutKind.Sequential, Pack:=4)> Friend Structure WINMSG_S
Public hwnd As IntPtr
Public message As Integer
Public wParam As IntPtr
Public lParam As IntPtr
Public time As Integer
Public x As Integer
Public y As Integer
End Structure
End Class
End Namespace
|
|
|
|
|
TwainDefs.vb
Imports System
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Namespace TwainLib
Public Class TwProtocol
Public Const Major As Short = 1
Public Const Minor As Short = 9
End Class
#Region " Enums "
<Flags()> Friend Enum TwDG As Short
Control = &H1
Image = &H2
Audio = &H4
End Enum
Friend Enum TwDAT As Short
Null = &H0
Capability = &H1
[Event] = &H2
Identity = &H3
Parent = &H4
PendingXfers = &H5
SetupMemXfer = &H6
SetupFileXfer = &H7
Status = &H8
UserInterface = &H9
XferGroup = &HA
TwunkIdentity = &HB
CustomDSData = &HC
DeviceEvent = &HD
FileSystem = &HE
PassThru = &HF
ImageInfo = &H101
ImageLayout = &H102
ImageMemXfer = &H103
ImageNativeXfer = &H104
ImageFileXfer = &H105
CieColor = &H106
GrayResponse = &H107
RGBResponse = &H108
JpegCompression = &H109
Palette8 = &H10A
ExtImageInfo = &H10B
SetupFileXfer2 = &H301
End Enum
Friend Enum TwMSG As Short
Null = &H0
[Get] = &H1
GetCurrent = &H2
GetDefault = &H3
GetFirst = &H4
GetNext = &H5
[Set] = &H6
Reset = &H7
QuerySupport = &H8
XFerReady = &H101
CloseDSReq = &H102
CloseDSOK = &H103
DeviceEvent = &H104
CheckStatus = &H201
OpenDSM = &H301
CloseDSM = &H302
OpenDS = &H401
CloseDS = &H402
UserSelect = &H403
DisableDS = &H501
EnableDS = &H502
EnableDSUIOnly = &H503
ProcessEvent = &H601
EndXfer = &H701
StopFeeder = &H702
ChangeDirectory = &H801
CreateDirectory = &H802
Delete = &H803
FormatMedia = &H804
GetClose = &H805
GetFirstFile = &H806
GetInfo = &H807
GetNextFile = &H808
Rename = &H809
Copy = &H80A
AutoCaptureDir = &H80B
PassThru = &H901
End Enum
Friend Enum TwRC As Short
Success = &H0
Failure = &H1
CheckStatus = &H2
Cancel = &H3
DSEvent = &H4
NotDSEvent = &H5
XferDone = &H6
EndOfList = &H7
InfoNotSupported = &H8
DataNotAvailable = &H9
End Enum
Friend Enum TwCC As Short
Success = &H0
Bummer = &H1
LowMemory = &H2
NoDS = &H3
MaxConnections = &H4
OperationError = &H5
BadCap = &H6
BadProtocol = &H9
BadValue = &HA
SeqError = &HB
BadDest = &HC
CapUnsupported = &HD
CapBadOperation = &HE
CapSeqError = &HF
Denied = &H10
FileExists = &H11
FileNotFound = &H12
NotEmpty = &H13
PaperJam = &H14
PaperDoubleFeed = &H15
FileWriteError = &H16
CheckDeviceOnline = &H17
End Enum
Friend Enum TwOn As Short
Array = &H3
[Enum] = &H4
One = &H5
Range = &H6
DontCare = -1
End Enum
Friend Enum TwType As Short
Int8 = &H0
Int16 = &H1
Int32 = &H2
UInt8 = &H3
UInt16 = &H4
UInt32 = &H5
Bool = &H6
Fix32 = &H7
Frame = &H8
Str32 = &H9
Str64 = &HA
Str128 = &HB
Str255 = &HC
Str1024 = &HD
Str512 = &HE
End Enum
Friend Enum TwCap As Short
XferCount = &H1
ICompression = &H100
IPixelType = &H101
IUnits = &H102
IXferMech = &H103
BitDepth = &H112B
ImageFileFormat = &H110C
XResolution = &H1118
YResolution = &H1119
ImageWidth = &H1116
ImageLength = &H1117
SupportedSizes = &H1122
XScaling = &H1124
YScaling = &H1125
End Enum
Public Enum TwSS As Short
TwSS_None = &H0
TwSS_A4 = &H1
TwSS_B5Letter = &H2
TwSS_USLetter = &H3
End Enum
Public Enum TwColourType As Short
twBW = 0
twGREY = 1
twRGB = 2
End Enum
Public Enum TwUnit As Short
tw_PICAS = 2
twCENTIMETERS = 1
twINCHES = 0
twPIXELS = 5
twPOINTS = 3
twTWIPS = 4
End Enum
#End Region
<StructLayout(LayoutKind.Sequential, Pack:=2, CharSet:=CharSet.Ansi)> Friend Class TwIdentity
Public Id As IntPtr
Public Version As TwVersion
Public ProtocolMajor As Short
Public ProtocolMinor As Short
Public SupportedGroups As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=34)> Public Manufacturer As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=34)> Public ProductFamily As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=34)> Public ProductName As String
End Class
<StructLayout(LayoutKind.Sequential, Pack:=2, CharSet:=CharSet.Ansi)> Friend Structure TwVersion
Public MajorNum As Short
Public MinorNum As Short
Public Language As Short
Public Country As Short
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=34)> Public Info As String
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Class TwUserInterface
Public ShowUI As Short
Public ModalUI As Short
Public ParentHand As IntPtr
End Class
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Class TwStatus
Public ConditionCode As Short
Public Reserved As Short
End Class
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Structure TwEvent
Public EventPtr As IntPtr
Public Message As Short
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Class TwImageInfo
Public XResolution As Int32
Public YResolution As Int32
Public ImageWidth As Int32
Public ImageLength As Int32
Public SamplesPerPixel As Int16
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=8)> Public BitsPerSample() As Short
Public BitsPerPixel As Int16
Public Planar As Boolean
Public PixelType As Int16
Public Compression As Short
End Class
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Class TwPendingXfers
Public Count As Short
Public EOJ As Integer
End Class
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Structure TwFix32
Public Whole As System.Int16
Public Frac As System.UInt32
Public Function ToFloat() As Single
Dim frac_sng As Single
frac_sng = System.Convert.ToSingle(Frac)
Return CType(Whole + (CType(frac_sng, Single) / 65536.0F), Single)
End Function
Public Sub FromFloat(ByVal f As Single)
Dim i As Int32 = CType(((f * 65536.0F) + 0.5F), Int32)
Whole = System.Convert.ToInt16(i / 2 ^ 16)
Frac = System.Convert.ToUInt32((i Or &HFFFF))
End Sub
End Structure
<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
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Class TwImageLayout
Public Frame As TwFrame
Public DocumentNumber As Integer
Public PageNumber As Integer
Public FrameNumber As Integer
End Class
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Class TwCapability
Public Cap As Short
Public ConType As Short
Public Handle As IntPtr
Public Sub TwCapability(ByVal capIn As TwCap)
Cap = CType(capIn, Short)
ConType = -1
End Sub
Public Sub New(ByVal capIn As TwCap, ByVal sval As Short, ByVal TWType As TwType)
Cap = CType(capIn, Short)
ConType = CType(TwOn.One, Short)
Handle = Twain.GlobalAlloc(&H42, 6)
Dim pv As IntPtr = Twain.GlobalLock(Handle)
Marshal.WriteInt16(pv, 0, CType(TWType, Short))
Marshal.WriteInt32(pv, 2, CType(sval, Short))
Twain.GlobalUnlock(Handle)
End Sub
Public Sub Dispose()
If Not Equals(Handle, IntPtr.Zero) Then
Twain.GlobalFree(Handle)
End If
End Sub
Protected Overrides Sub Finalize()
If Not Equals(Handle, IntPtr.Zero) Then
Twain.GlobalFree(Handle)
End If
End Sub
End Class
End Namespace
|
|
|
|
|
ScantoImage.Vb
Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Namespace ScanSoft
<StructLayout(LayoutKind.Sequential, Pack:=2)> Friend Class BITMAPINFOHEADER
Public biSize As Integer
Public biWidth As Integer
Public biHeight As Integer
Public biPlanes As Short
Public biBitCount As Short
Public biCompression As Integer
Public biSizeImage As Integer
Public biXPelsPerMeter As Integer
Public biYPelsPerMeter As Integer
Public biClrUsed As Integer
Public biClrImportant As Integer
End Class
Public Class scanToImage
<DllImport("gdi32.dll", ExactSpelling:=True)> Friend Shared Function SetDIBitsToDevice(ByVal hdc As IntPtr, ByVal xdst As Integer, ByVal ydst As Integer, ByVal width As Integer, ByVal height As Integer, ByVal xsrc As Integer, ByVal ysrc As Integer, ByVal start As Integer, ByVal lines As Integer, ByVal bitsptr As IntPtr, ByVal bmiptr As IntPtr, ByVal color As Integer) As Integer
End Function
<DllImport("kernel32.dll", ExactSpelling:=True)> Friend Shared Function GlobalLock(ByVal handle As IntPtr) As IntPtr
End Function
<DllImport("kernel32.dll", ExactSpelling:=True)> Friend Shared Function GlobalFree(ByVal handle As IntPtr) As IntPtr
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> Public Shared Sub OutputDebugString(ByVal outstr As String)
End Sub
Dim bmi As BITMAPINFOHEADER
Dim bmprect As Rectangle
Dim dibhand As IntPtr
Dim bmpptr As IntPtr
Dim pixptr As IntPtr
Public Sub New(ByVal dibhandp As IntPtr)
bmprect = New Rectangle(0, 0, 0, 0)
dibhand = dibhandp
bmpptr = GlobalLock(dibhand)
pixptr = GetPixelInfo(bmpptr)
End Sub
Protected Function GetPixelInfo(ByVal bmpptr As IntPtr) As IntPtr
bmi = New BITMAPINFOHEADER
Marshal.PtrToStructure(bmpptr, bmi)
bmprect.X = bmprect.Y = 0
bmprect.Width = bmi.biWidth
bmprect.Height = bmi.biHeight
If (bmi.biSizeImage = 0) Then
bmi.biSizeImage = Int((((bmi.biWidth * bmi.biBitCount) + 31) & Hex(Not (31))) / 2 ^ 3) * bmi.biHeight
End If
Dim p As Integer = bmi.biClrUsed
If ((p = 0) And (bmi.biBitCount <= 8)) Then
p = Int(1 * 2 ^ bmi.biBitCount)
End If
p = (p * 4) + bmi.biSize + CType(bmpptr.ToInt32, Integer)
Return New IntPtr(p)
End Function
Public Function ImgToBitmap(ByVal dibhandp As IntPtr) As Bitmap
bmprect = New Rectangle(0, 0, 0, 0)
dibhand = dibhandp
bmpptr = GlobalLock(dibhand)
pixptr = GetPixelInfo(bmpptr)
Dim TempBMP As Bitmap = New Bitmap(bmprect.Width, bmprect.Height)
Dim TempGrap As Graphics = Graphics.FromImage(TempBMP)
Dim hdc As IntPtr = TempGrap.GetHdc
SetDIBitsToDevice(hdc, 0, 0, bmprect.Width, bmprect.Height, 0, 0, 0, bmprect.Height, pixptr, bmpptr, 0)
TempGrap.ReleaseHdc(hdc)
TempGrap.Dispose()
GlobalFree(dibhand)
dibhand = IntPtr.Zero
Return (TempBMP)
End Function
End Class
End Namespace
|
|
|
|
|
Hello,
Guys please help. I am stuck. I've read all posts here, but I did not find solution closer than this.
I need form with two buttons. First is for select source, and second is for scanning of one picture and then to get return of that picture as image.
I solved first task by calling "tw.Select()", but second task I do not know how to accomplish.
I have tried everything.
For example:
"Dim newpic As scanToImage = New scanToImage(0)
picBox.Image = newpic.ImgToBitmap(0)"
Please help me. I have almost completed app for my office archive. Just need a class that I can call to perform scanning and then to put image from return to picturebox and store it to database.
Thank You very very very much.
I lose my mind on trying to understand this twain stuff but always more I look more get confused.
Sorry for my bad English.
Grateful forever
|
|
|
|
|
svincetic1 wrote: Guys please help. I am stuck. I've read all posts here, but I did not find solution closer than this.
I need form with two buttons. First is for select source, and second is for scanning of one picture and then to get return of that picture as image.
I solved first task by calling "tw.Select()", but second task I do not know how to accomplish.
I have tried everything.
find this code snippet
Case TwainCommand.TransferReady
Dim pics As ArrayList = tw.TransferPictures()
EndingScan()
tw.CloseSrc()
picnumber += 1
Dim i As Integer
For i = 0 To pics.Count - 1 Step 1
Dim img As IntPtr = CType(pics(i), IntPtr)
Dim newpic As PicForm = New PicForm(img)
newpic.MdiParent = Me
Dim picnum As Integer = i + 1
newpic.Text = "ScanPass" + picnumber.ToString() + "_Pic" + picnum.ToString()
and make it
Case TwainCommand.TransferReady
Dim pics As ArrayList = tw.TransferPictures()
EndingScan()
tw.CloseSrc()
picnumber += 1
Dim i As Integer
For i = 0 To pics.Count - 1 Step 1
Dim img As IntPtr = CType(pics(i), IntPtr)
Dim newpic As PicForm = New PicForm(img)
newpic.MdiParent = Me
Dim picnum As Integer = i + 1
newpic.Text = "ScanPass" + picnumber.ToString() + "_Pic" + picnum.ToString()
GdiPlusLib.Gdip.SaveDIBAs((newpic.Text & ".bmp"), PicForm.bmpptr, PicForm.pixptr)
newpic.show()
hope i helped
|
|
|
|
|
how can I turn it into a pdf rather than an image . Also is there a way to call the auto select of the scanner software rather than opening it's GUI. I have a problem eliminating the extra white edges and i keep trying to crop the image after it's created but i can't include all colors since some pixels turn into shades of white and gray . PLEASE HELPP - I need to complete this project ASAP
|
|
|
|
|
I want to be able to scan from an HTML page using this .net code, but it seems to need some .net permissions in the .net configuration console on the client machines.
¿Is there a way to change this code in order to generate an .ocx file?
|
|
|
|
|
Hi
I've some problems with configure the scan area. I use code wrote by cmchuan
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct TwFrame {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
//set the scan area using a call like this
TwImageLayout layout = new TwImageLayout();
//Get the default layout
TwRC rc = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, Layout);
Layout.Frame.Top = 0; //Set the top margin
Layout.Frame.Left = 0; //Set left margin
Layout.Frame.Right = 0; //Set right margin
Layout.Frame.Bottom = 0; //Set bottom margin
Layout.FrameNumber = 1;
Layout.PageNumber = 1;
Layout.DocumentNumber = 1;
rc = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Set, layout);
TwStatus s = new TwStatus();
rc = DSstatus(appid, srcds, TwDG.Control, TwDAT.Status, TwMSG.Get, s);
if( rc != TwRC.Success )
{
CloseSrc();
return false;
}
I change margins but it's always scan all area. What should i do to scan small fragment?
|
|
|
|
|
I have post full VB.NET code in above.
|
|
|
|
|
Could You mark fragment responsible for selecting and setuping area?
Regards
alien250
|
|
|
|
|
One the things that I found difficult about developing my Twain application was that I often could not get the excellent code posted here to work. Often I would get 'success' returned from trying to set the dpi or the bitdepth or other capabilities but the effect was zero.
I have noticed that many others have the same problem. I finally went to the web site (http://www.twain.org/docs/Spec1_9_197.pdf) for Twain and actually read the document setting out the standards.
I was developing an Optical Mark Recognition application for which I had written an algorithm and was adding the Twain standard so I could scan and read forms. I needed to set the DPI, the bit depth and the resolution and tried using the code here to do so. I could scan but was unsuccessful in setting the different elements. The application would return 'success' but the final scan woull not reflect the changes.
It turns out that the capabilities of the scanner should be set in sequence according to the standard. For example, you have to set the pixel type before the bitdepth before the x and y resolution. This is strictly enforced on many systems, particularly on high end scanners like the Fujitsu I am using.
A system will return 'success' because you have made the right call but do nothing because you have not set the caps in the right order.
Following the changes in line with the Twain standard I have just successfully scanned and processed 500 forms consisting of a total of 3,000 pages.
Hopefully this will work for others.
Alan
'Nemo me impune Lacessit'
|
|
|
|
|
hello there, i saw ur article, it seems u r the person that can help.
i m making an application to scan multiple forms, 100 pages per minute using twain in black & white.
so far the application made scans only 1 page, i want to scan and save multiple pages to the directory i want. can u guide me what steps shall i perform in order to achieve that,
|
|
|
|
|
Did anyone find a way how to scan image directly without showing user interface of the source? Is that property related with CAP_AUTOSCAN capability, if so how i will set this capability to true using the interface above written by NetMaster.
I need ur helps...
|
|
|
|
|
The following is a function that populates an internal ArrayList(_Sources) of TwIdentity and returns number of sources found. You can then use this ArrayList to select the source of choice.
public int GetDataSources()
{
//ArrayList ds = new ArrayList();
_Sources = new ArrayList();
TwIdentity scanner = new TwIdentity();
TwIdentity defScanner = new TwIdentity();
CloseSrc();
if (appid.Id == IntPtr.Zero)
{
Init(hwnd);
if (appid.Id == IntPtr.Zero)
return _Sources.Count;
}
//Get the default
if (DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetDefault, defScanner) != TwRC.Success)
return _Sources.Count;
if (DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetFirst, scanner) == TwRC.Success)
{
//Select default data source
if (scanner.Id == defScanner.Id)
_SelectedSource = _Sources.Count;
_Sources.Add(scanner);
//Loop through and find all sources and add to array
scanner = new TwIdentity();
while (DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetNext, scanner) == TwRC.Success)
{
//Select default data source
if (scanner.Id == defScanner.Id)
_SelectedSource = _Sources.Count;
_Sources.Add(scanner);
scanner = new TwIdentity();
}
}
return _Sources.Count;
}
To Select the desired Datasource you could to do the following:
public bool SelectSource(int SourceIndex)
{
//Select correct datasource
srcds = (TwIdentity)_Sources[SourceIndex];
//Close Datasource
CloseSrc();
//Invoke set command of datasource
rc = DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.Set, srcds);
if (rc != TwRC.Success)
return false;
}
Hope that helps
|
|
|
|
|
hi ,,
I want to change the way to select source device and for that i have added a combobox in my application and to work with this i found your code which may help me but when i implemented it give some error.
1.what is "SelectedSource" in your code
2.SelectSource function error--not all code paths return a value.
but i have done some little modification
which give only one error that is "SelectedSource"
please help me which place i have to add this function and further procedure for implement this feature.
please help me
|
|
|
|
|
hello, i have download the code and learn many thing for it.
i want to change the scan UI in the code, but don't know TWAIN exactly.
i find the Acquire sub is very important, and some structure or Inherits some function from TWAIN will finish it.
thank you very much for your help
MSN: zhangjiuheng@hotmail.com
web: www.hengjiu.cc
MSN: zhangjiuheng@hotmail.com
web: www.hengjiu.cc
|
|
|
|
|
thank you for this great article
i want to handle scanner event like paperjam in my application but i dont know how to do this i tried some way like setting deviceevent capability
but it doesnt work and returnz sfailure message when im setting
please some body help me
|
|
|
|
|
Hi,
Is there any way to suppress the user interfaces from twain driver?
First, I want to handle the error while scanning, opening data source or closing data source. Is this can do by not showing UI?
Second is, while scanning, scanning process progressbar is pops up. Can we invisible this UI?
Urgent help needed!!
bg
|
|
|
|
|
|
|
thanks for the reference, I've moved that code to http://www.codeplex.com/openTwain as gotdotnet is closing.
|
|
|
|
|
This class extends what m@u had posted.
[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
[FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
public class TwainManager : NativeWindow, IDisposable
{
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GlobalFree(IntPtr handle);
private Twain _scanner;
private List<fileinfo> _files;
private TwainConfig _scannerConfig;
private bool _ready = false;
private byte[] _binaryImage;
public byte[] BinaryImage
{
get
{
return _binaryImage;
}
}
public bool Ready
{
get
{
return _ready;
}
}
public TwainManager()
{
_scannerConfig = TwainConfig.GetConfig();
CreateParams cp = new CreateParams();
cp.Parent = new IntPtr(-3);
//cp.ClassName = "Window";
cp.Caption = "";
this.CreateHandle(cp);
_scanner = new Twain();
_scanner.Init(Handle);
if (string.IsNullOrEmpty(_scannerConfig.ActiveDevice))
_scannerConfig.ActiveDevice = _scanner.ActiveDeviceName;
else
{
if (!_scanner.SelectByName(_scannerConfig.ActiveDevice))
{
_scanner.Init(Handle);
_scannerConfig.ActiveDevice = _scanner.ActiveDeviceName;
}
}
_scannerConfig.Save();
}
public bool SelectScanner()
{
_ready = _scanner.Select();
if (_ready)
{
_scannerConfig.ActiveDevice = _scanner.ActiveDeviceName;
_scannerConfig.Save();
}
return _ready;
}
private void AddScan()
{
if (_scanner.Acquire() != TwRC.Success)
{
EndScanning();
throw new Exception("Document could not be scanned");
}
}
public void Scan()
{
if (_ready)
{
_files = new List<fileinfo>();
_binaryImage = null;
if (_scanner.Acquire() != TwRC.Success)
{
EndScanning();
throw new Exception("Document could not be scanned");
}
}
else
{
if (SelectScanner())
Scan();
}
}
private void AnalyzeImage(IntPtr pic)
{
IntPtr bmpPtr = IntPtr.Zero;
IntPtr pixPtr = IntPtr.Zero;
string tempFile = Path.GetTempFileName().Replace(".tmp", ".tif");
try
{
if (pic.Equals(IntPtr.Zero))
{
EndScanning();
_scanner.CloseSrc();
return;
}
bmpPtr = GlobalLock(pic);
pixPtr = GetPixelInfo(bmpPtr);
GdiPlusLib.SaveDIBAs(tempFile, bmpPtr, pixPtr);
FileInfo fi = new FileInfo(tempFile);
if (fi.Exists)
_files.Add(fi);
}
catch (Exception ex)
{
throw ex;
}
}
private IntPtr GetPixelInfo(IntPtr bmpptr)
{
Rectangle bmprect = default(Rectangle);
BITMAPINFOHEADER 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;
}
protected override void WndProc(ref Message m)
{
if (_scanner != null)
{
TwainCommand cmd = _scanner.PassMessage(ref m);
if (cmd == TwainCommand.Not)
return;
switch (cmd)
{
case TwainCommand.CloseRequest:
EndScanning();
_scanner.CloseSrc();
break;
case TwainCommand.CloseOk:
EndScanning();
_scanner.CloseSrc();
break;
case TwainCommand.DeviceEvent:
break;
case TwainCommand.TransferReady:
ScanImage();
break;
}
}
base.WndProc(ref m);
}
private void ScanImage()
{
IntPtr pic = IntPtr.Zero;
try
{
pic = _scanner.TransferPicture();
AnalyzeImage(pic);
if (_scanner.HasMorePages)
ScanImage();
else
{
_scanner.CloseSrc();
if (DialogResult.No == MessageBox.Show(
"Would you like to add more pages?", "Continue Scanning?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question))
{
BuildTiff();
}
else
{
AddScan();
}
}
}
catch (Exception ex)
{
throw ex;
}
}
private void EndScanning()
{
}
private EncoderParameters GetEncoderParameters(EncoderValue SaveFlag, EncoderValue Compression)
{
EncoderParameters enParams = new EncoderParameters(2);
enParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)SaveFlag);
enParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)Compression);
return enParams;
}
private ImageCodecInfo GetEncoderInfo(String mimeType)
{
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < encoders.Length; i++)
{
if (String.Compare(mimeType, encoders[i].MimeType, true) == 0)
{
return encoders[i];
}
}
return null;
}
private void BuildTiff()
{
string tiffPath = Path.GetTempFileName().Replace(".tmp", ".tif");
Bitmap b = null;
if (_files.Count > 0)
{
b = (Bitmap)Bitmap.FromFile(_files[0].FullName);
if (b.PixelFormat == PixelFormat.Format1bppIndexed)
b.Save(tiffPath, GetEncoderInfo("image/tiff"), GetEncoderParameters(EncoderValue.MultiFrame, EncoderValue.CompressionCCITT4));
else
b.Save(tiffPath, GetEncoderInfo("image/tiff"), GetEncoderParameters(EncoderValue.MultiFrame, EncoderValue.CompressionLZW));
for (int i = 1; i < _files.Count; i++)
{
Image image = Image.FromFile(_files[i].FullName);
if (image.PixelFormat == PixelFormat.Format1bppIndexed)
b.SaveAdd(image, GetEncoderParameters(EncoderValue.FrameDimensionPage, EncoderValue.CompressionCCITT4));
else
b.SaveAdd(image, GetEncoderParameters(EncoderValue.FrameDimensionPage, EncoderValue.CompressionLZW));
}
b.Dispose();
b = null;
}
else
throw new Exception("No document scanned.");
FileStream fs = new FileStream(tiffPath, FileMode.Open, FileAccess.Read);
_binaryImage = new Byte[fs.Length];
fs.Read(_binaryImage, 0, (int)fs.Length);
fs.Close();
fs.Dispose();
fs = null;
b = null;
if (_binaryImage == null || _binaryImage.Length < 1)
throw new Exception("No document could be scanned.");
}
#region IDisposable Member
public void Dispose()
{
try
{
if(_scanner != null)
_scanner.CloseSrc();
}
catch { }
_scanner = null;
}
#endregion
}
Breaking your theories
Sully
|
|
|
|
|
I have created a Class Library. I scan and save the image to a file. Then I read from the file to display in a picturebox. When I use the library in a form, it scans, saves image to a file and displays the image in the picturebox.
When I use the DLL (library) in a HTML page, it scans, but the (user specified) file is not created. Instead, it creates a file in TEMP called TwainDS.tif and then the program hangs.
Anyone have any idea why?
|
|
|
|
|
Interesting!
I am having a very similar scenario. My problem is that when I run the code from an ActiveX wrapper, the scanner never receives the command to scan. In other words, the PreFilterMessage never catches any message! I even tried with WndProc method, but no success. But when the code is ran from directly (running the .exe or debugging within Visual Studio), all works perfectly!
I assume it has something to do with the fact that the parent process (owner) is IE8... I am not sure...
Any ideas?
|
|
|
|
|
Hi,I have the same issue,any ideas for me?
Thanks advanced.
|
|
|
|
|