TWAIN Working Group

Newsletter Signup
Donate
Help keep TWAIN free
  • About TWAIN
    • What’s New?
    • News
    • Events
    • Membership
    • Consider a Donation
    • Contact Us
  • Why TWAIN?
  • Developers
    • Driver Developer
    • Application Developer
    • TWAIN Features
    • Specification & Tools
    • Self Certification Process
  • Support Forums
  • Scanner End-User
  • Find Certified Drivers
    • Facebook
    • LinkedIn
    • Vimeo

Using TWAIN from VB

Forums › TWAIN Classic › Using TWAIN from VB

  • This topic has 7 replies, 2 voices, and was last updated 10 years, 11 months ago by Mar.
Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • February 11, 2010 at 6:25 pm #22578 Reply
    Mar
    Participant
    • Topics - 2
    • Replies - 10
    • Total Posts - 12

    Hello,

    I am working on using TWAIN from VB.NET. I have gotten to state 4 successfully, but have been unable to set or get capabilities. The project spec requires the source UI to be hidden. But when I hide it, the scanner appears to be waiting for something. I assumed it was some capabilities, but haven’t figured out how to get them, let alone set them. I have an attached scanner that has issues, but I am using it for testing since the scanner that will be used is unavailable to me in debug mode.

    I am using Win XP SP3 and VB.NET in Visual Studio 2005. I believe I am making a mistake copying the structure because I get 18874402 for the physical width and height and I get this error when I try to get the units (enumeration) “Attempted to read or write protected memory. This is often an indication that other memory is corrupt.” I tried getting the “OveValue” by changing (hacking) the variable types to different values, the closest I came to reasonalbe values were Width and Hieght = 33, since the scanner is a flatbed scanner (11″ x 8.5″) those values are wrong. I am trying to figure out how to write a class in C++ to see if the returned values are any different. I tried changing twsCapability from a structure to a class, but that fails to return anything.

    I read the twain specification and looked at all the examples I can find, but I must be missing something. (Do structure members translate to identicle types between VB and C?) Here is my code:

             Private Shared Function DS_Capability( _
    <[In](), Out()> ByVal pOrigin As twsIdentity, _
    <[In]()> ByVal pSource As twsIdentity, _
    ByVal dg As twDG, _
    ByVal dat As twDAT, _
    ByVal msg As twMSG, _
    <[In](), Out()> ByRef pData As twsCapability) As twRC
    End Function

    Private Structure twsCapability
    Public Cap As twCap
    Public ConType As twContainerTyoe
    Public Handle As IntPtr 'Pointer to a container
    End Structure

    Friend Class TW_ONEVALUE
    Public ItemType As Short
    Public Item As Integer
    End Class


    Public Sub NegotiateCapabilities()

    ...Other Code

    twCapability = New twsCapability
    With twCapability
    .Cap = twCap.IPhysicalWidth
    '.ConType = 7 'TWON_DONTCARE16
    '.Handle = Nothing
    End With
    strWidth = GetOneValue(twCapability)

    With twCapability
    .Cap = twCap.IPhysicalHeight
    '.ConType = 7 'TWON_DONTCARE16
    '.Handle = Nothing
    End With
    strHeight = GetOneValue(twCapability)

    'Here strWidth and strHeight = 18874402

    ...Other Code

    End Sub

    Private Function GetOneValue(ByVal twCapability As twsCapability) As String

    Dim rc As twRC
    Dim strTemp As String
    Dim twOneValue As TW_ONEVALUE


    rc = DS_Capability(mtwApp, mtwSource, twDG.Control, twDAT.Capability, twMSG.Get, twCapability)
    If rc = twRC.Success Then
    strTemp = vbNullString
    Select Case twCapability.ConType
    Case twContainerTyoe.One
    twOneValue = New TW_ONEVALUE
    Marshal.PtrToStructure(twCapability.Handle, twOneValue)
    strTemp = CType(twOneValue.Item, String)
    Case Else
    MsgBox("Error, one value expected; " & twCapability.ConType & " returned.")
    End Select
    Marshal.FreeHGlobal(twCapability.Handle)
    Return strTemp
    Else
    ErrorStatus()
    Return vbNullString
    End If

    End Function

    Any assistance is appreciated. I will read anything, no matter how dull, to resolve this, so any links anyone knows of on how to marshall complex structures between VB managed and C unmanaged code will be helpful if no one knows what I am doing wrong. Thanks for looking 🙂 .

    February 15, 2010 at 2:24 pm #25155 Reply
    Mar
    Participant
    • Topics - 2
    • Replies - 10
    • Total Posts - 12

    Just got some more info. I am going to try to call the dll from C, but I ran into a problem. This structure (TW_IDENTITY) reports 160 bytes (from sizeof):

     typedef unsigned short TW_UINT16;
    typedef unsigned long TW_UINT32;
    typedef char TW_STR32[34];

    struct TW_VERSION{
    TW_UINT16 MajorNum; /* Major revision number of the software. */
    TW_UINT16 MinorNum; /* Incremental revision number of the software. */
    TW_UINT16 Language; /* e.g. TWLG_SWISSFRENCH */
    TW_UINT16 Country; /* e.g. TWCY_SWITZERLAND */
    TW_STR32 Info; /* e.g. "1.0b3 Beta release" */
    };

    struct TW_IDENTITY{
    TW_UINT32 Id; /* Unique number. In Windows, application hWnd */
    TW_VERSION Version; /* Identifies the piece of code */
    TW_UINT16 ProtocolMajor; /* Application and DS must set to TWON_PROTOCOLMAJOR */
    TW_UINT16 ProtocolMinor; /* Application and DS must set to TWON_PROTOCOLMINOR */
    TW_UINT32 SupportedGroups; /* Bit field OR combination of DG_ constants */
    TW_STR32 Manufacturer; /* Manufacturer name, e.g. "Hewlett-Packard" */
    TW_STR32 ProductFamily; /* Product family name, e.g. "ScanJet" */
    TW_STR32 ProductName; /* Product name, e.g. "ScanJet Plus" */
    };

    In VB.NET, twsIdentity reports 156 bytes (from Marshal.SizeOf):

         Friend Class twsIdentity
    Public Id As IntPtr '4
    Public Version As twsVersion '42
    Public ProtocolMajor As Short '2
    Public ProtocolMinor As Short '2
    Public SupportedGroups As Integer '4
    Public Manufacturer As String
    Public ProductFamily As String
    Public ProductName As String

    Public Sub New()
    MyBase.New()
    Version = New twsVersion
    End Sub
    End Class

    Friend Class twsVersion
    Public MajorNum As Short
    Public MinorNum As Short
    Public Language As Short
    Public Country As Short
    Public Info As String
    End Class

    Because of this discrepency, I can’t pass it between VB.NET and C++. I don’t want to have to rewrite it in C++ (mainly because then I have to learn C++) but as of right now that may be my only choice. I’ve searched the web several times and posted to 3 forums and it appears that I’ve stumbled upon the most difficult programming task in the world, because everyone is clueless on how to correct this.

    Any guidance at all would be appreciated. Thanks for at least looking. [/code]

    February 19, 2010 at 3:26 pm #25156 Reply
    Mar
    Participant
    • Topics - 2
    • Replies - 10
    • Total Posts - 12

    Just an update and a couple of questions.

    I am wondering why no one responded, I can think of 3 reasons but the right one may not be included in the 3.

    1) My question is unclear.
    2) My question is too big for anyone to read (posted too much code).
    3) No one has a clue to the answer.
    4) ???

    Since my boss insists on using TWAIN and my skills lie in VB I have no choice but to keep struggling.

    The good news is I made some progress. I changed the Pack parameter from 2 to 4 and now the sizes are equal (both 160).

     

    However this still fails the same way, so I don’t know if that was a problem or not. Since I just started using the NET framework a couple of months ago, I suspect the problem lies somewhere in there. Does anyone know if the way I am marshaling the structure is correct? any suggestions of ANYTHING to try? (I’ll stand on my head if it would make it work!! lol)

    Thanks for looking.

    February 19, 2010 at 6:11 pm #25157 Reply
    Mar
    Participant
    • Topics - 2
    • Replies - 10
    • Total Posts - 12

    OK maybe someone can answer this. I tried to manually marshal the data back from a Get capability call for both the physical width and physical height. Both calls return the same data. And RC=SUCCESS. How can this be possible?

    It is setting the container type to 5 (one value).

    Data returned:
    0=32, 1=109, 2=34, 3=0, 4=48, 5=1, 6=214, 7=3,
    0=32, 1=109, 2=34, 3=0, 4=48, 5=1, 6=214, 7=3,

    Here’s the code I inserted into the above procedure GetOneValue,. Does TWAIN_32 allocates 8 bytes for a TW_ONEVALUE?

                        Marshal.PtrToStructure(twCapability.Handle, twOneValue)
    ReDim byt(7)
    Marshal.Copy(twCapability.Handle, byt, 0, 8)
    For r = 0 To 7 : Console.Write(r & "=" & byt(r) & ", ") : Next : Console.WriteLine()
    strTemp = CType(twOneValue.Item, String)

    Is this a problem with the scanner? The manufacturer’s driver? Am I chasing my tail?

    February 22, 2010 at 12:05 pm #25158 Reply
    gabe
    Participant
    • Topics - 9
    • Replies - 583
    • Total Posts - 592

    Sorry you’ve been having trouble and that it seems as if you’re alone. Have you had a look at codeplex.com/openTwain?
    The definitions from that project are correct as are the Imports. If you’re having trouble in vb.net past that let me know.

    .

    February 22, 2010 at 7:32 pm #25159 Reply
    Mar
    Participant
    • Topics - 2
    • Replies - 10
    • Total Posts - 12

    Thanks gabe, I do feel quite alone. I asked on 8 forums and nobody has a clue whats going on. If I can’t get the answer on twainforum then I will have good cause to tell my boss that it can’t be done!! But I didn’t give up yet. I downloaded the code you pointed out, but without instructions I can’t run it. I would like to step through it, so if anyone knows how I can do that, I may be able to answer my own question. That code has ONEVALUE defined like this (I pruned it a bit):

       Public Class twOneValue

    Public ItemType As Enumerations.ItemType
    Public Item As Object

    Friend Function baseSize() As Int32
    Return 2
    End Function

    End Class

    Enumerations.ItemType is defined as UInt16. And how do I get a valid value for Item if it is an object? This doesn’t match the spec, but if it works I’ll be happy to use it.

    I tried this

    Marshal.PtrToStructure(Marshal.ReadInt32(twCapability.Handle), twOneValue)

    and got:
    ?twOneValue.Item
    32768
    ?twOneValue.ItemType
    7

    It just doesn’t make sense. Can I have another structure besides ONEVALUE? Can the ConType be wrong? Anything else I can do to inspect data?

    Any help is appreciated, thanks for looking.

    February 22, 2010 at 9:23 pm #25160 Reply
    gabe
    Participant
    • Topics - 9
    • Replies - 583
    • Total Posts - 592

    If you set the guiharness as your startup project, then set a breakpoint in cTwain.vb method UpdateCapabilities() you should see the sample get the values for a couple capabilities with the methods Update_DeviceOnline, Update_EnableDsUiOnly(), Update_AvailableXferMechs(), Update_AvailableImageFileFormats() and Update_CurrentImageFileFormat().

    More specifically if you’re looking for the code that gathers a oneValue you’ll have to dig through the twCapability class, but I think you you set a breakpoint at UpdateCapabilities you’ll see how the code determines the values. Lemme know when/if you have more questions.

    .

    February 23, 2010 at 6:01 pm #25161 Reply
    Mar
    Participant
    • Topics - 2
    • Replies - 10
    • Total Posts - 12

    Thanks gabe!! That was what I needed.

    My mistake was using this:

    Marshal.PtrToStructure(twCapability.Handle, twOneValue)

    Bad code. Doesn’t work.

    Here is code I copied from http://opentwain.codeplex.com(with modifications and its sloppy, still under work):

    Private Function GetOneValueZ(ByVal twCapability As twsCapability) As String

    Dim rc As twRC
    Dim pOneValue As IntPtr
    Dim pPosition As Int32 = 0
    Dim strValue As String
    Dim twFix32 As twsFix32
    Dim twOneValue As TW_ONEVALUE


    rc = DS_Capability(mtwApp, mtwSource, twDG.Control, twDAT.Capability, twMSG.Get, twCapability)
    If rc = twRC.Success Then

    twOneValue = New TW_ONEVALUE
    pOneValue = GlobalLock(twCapability.Handle)
    twOneValue.ItemType = CType(Marshal.ReadInt16(pOneValue, pPosition), ItemType)
    pPosition += 2

    Select Case twOneValue.ItemType

    Case (other cases omitted for space)

    Case ItemType.Fix32
    Dim origFrac As Int32
    twFix32 = New twsFix32

    twOneValue.Item = Marshal.ReadInt16(pOneValue, pPosition)
    twFix32.Whole = twOneValue.Item
    pPosition += 2


    origFrac = Marshal.ReadInt16(pOneValue, pPosition)
    If origFrac < 0 Then
    origFrac += 65536
    End If
    pPosition += 2

    'twFix32.Frac = CUShort(origFrac)
    strValue = (twFix32.Whole + (origFrac / 65536)).ToString

    End Select

    GlobalUnlock(twCapability.Handle)

    Return strValue

    End If

    End Function

    But now I get 8.5 back for the width and 11.whatever back for the height!! Now I can move forward!!

    Thanks again gabe!!

  • Author
    Posts
Viewing 8 posts - 1 through 8 (of 8 total)
Reply To: Using TWAIN from VB
Your information:




Quick Links

Service Providers
TWAIN Support Forums
Membership
Contact Us
Privacy Policy

Newsletter Signup

TWAIN Working Group Family

TWAIN Working Group
TWAIN Direct®
TWAIN Resources
TWAIN Certified Drivers
PDF/raster

  • Facebook
  • GitHub
  • LinkedIn
  • Vimeo

Recent Topics

  • EPSON V600 TWAIN and WIA on Windows 10
  • When and how to use WaitForEvents command ?
  • Problem enumerating list of installed scanners in windows server 2012
  • Failed to create TWAIN progress! Error code is 1260.
  • To get the list of scanners from javascript client side (browser)
  • Quarterly Newsletter
  • TWAIN Working Group Membership
  • Logo Usage
  • TWAIN License
  • Contact Us
Privacy Policy • Privacy Tools • Copyright © 2021 TWAIN Working Group • by iHwy, LLC • Log in

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.