CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9
  1. #1
    Join Date
    Feb 2010
    Posts
    7

    Scanning with TWAIN

    Hello

    I am making an application to scan with TWAIN. I can get to state 4 OK, and scan with the UI. But I need to hide the UI. When I do this the scanner does nothing. I believe it needs some capabilities set (like height and width). So I try to get the physical height and width so I can set them. Herein lies the problem. I get 18874402 back for the physical height and width. (neither can I get the units). I get RC=SUCCESS. I don't think it could be a signed/unsigned issue because what boundary is at 18 million +/- with whatever units? I tried some other code I found but that returns 0. I can't figure out what I am doing wrong. Here's the code:

    Code:
        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
    And here's how I call it:

    Code:
                twCapability = New twsCapability
                With twCapability
                    .Cap = twCap.IPhysicalWidth
                    .ConType = twContainerTyoe.One   'TWON_DONTCARE16
                    '.Handle = Nothing
                End With
                strWidth = GetOneValue(twCapability)
    If I can get it to work I will post the class here for others to use. Any help is appreciated, thanks for looking.
    Last edited by HanneSThEGreaT; February 19th, 2010 at 02:25 AM. Reason: [CODE tags!

  2. #2
    Join Date
    Jul 2001
    Location
    Sunny South Africa
    Posts
    11,284

    Re: Scanning with TWAIN

    Weclome to the forums!

    When posting code, please make use of [CODE] tags, as explained here :

    http://www.codeguru.com/forum/showthread.php?t=403073

    Thank you

    Hannes

  3. #3
    Join Date
    Feb 2010
    Posts
    7

    Question Re: Scanning with TWAIN

    Sorry, didn't see the option for [CODE] tags so I thought I wasn't authorized to use them.


    I just searched the forum for marshaling but didn't find anything that matches my situation. I suspect it may be an issue marshaling data between managed code and unmanaged code.

    Does anyone know how to get a member of a structure pointed to by a pointer in another structure that is allocated by unmanaged code and returned to managed code via a pointer? Can anyone understand my question? I think that is what I am doing wrong in the above code. I will post the structures.

    I allocate this structure; Handle will point to a structure (TW_ONEVALUE) allocated by the unmanaged C dll (TWAIN_32.dll)
    Code:
        <StructLayout(LayoutKind.Sequential, Pack:=4)> Private Structure twsCapability
            Public Cap As twCap         'short
            Public ConType As twContainerTyoe   'short
            Public Handle As IntPtr     'Pointer to a container
        End Structure
    TWAIN_32.dll allocates this one
    Code:
        <StructLayout(LayoutKind.Sequential, Pack:=4)> Friend Class TW_ONEVALUE
            Public ItemType As Short
            Public Item As Integer
        End Class
    Any help is appreciated. Thanks for looking.

  4. #4
    Join Date
    Jul 2000
    Location
    Milano, Italy
    Posts
    7,726

    Re: Scanning with TWAIN

    ...at present time, using mainly Net 4.0, Vs 2010



    Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
    all the other wonderful people who made and make Codeguru a great place.
    Come back soon, you Gurus.

  5. #5
    Join Date
    Feb 2010
    Posts
    7

    Re: Scanning with TWAIN

    Thanks cimp for your reply. Unfortunately I have seen that. That is the most common solution posted to a number of forums, and rightly so, it does work. However, that solution uses the driver provided with the scanner for a user interface. The application that I am working on needs to hide the implementation from the user (the user will have other things to keep them occupied). As soon as I hide the UI, the scanner refuses to operate. Best I can get from the TWAIN spec is that some scanners require some settings to be set before they will "go". Since the UI requires the user to select the scan area, I presumed that the scanner requires this to be set. That's when I run into problems. I try to get the physical width and height, but get garbage. Structure TW_ONEVALUE is 8 bytes long (added Pack:=4 to make it 8 bytes because it was 6 and C++ reported its structure as 8).

    This is the C struc that gets allocated by the dumb dll and gets a pointer to it put in the handle property of twsCapability
    Code:
    typedef struct {
       TW_UINT16  ItemType;
       TW_UINT32  Item;
    } TW_ONEVALUE, FAR * pTW_ONEVALUE;
    I tried viewing the bytes returned (for the width) using this:
    Code:
    BitConverter.GetBytes(Marshal.ReadInt64(twCapability.Handle))
    and I got this:
    {232, 28, 35, 0, 48, 1, 198, 3}
    ran it again and got this:
    {216, 252, 34, 0, 56, 1, 198, 3}

    So either I am getting garbage back from the call to TWAIN, or I am doing something wrong with the Marshaling (I used Int64 to view the eight bytes belonging to the structure), I use this call to get a structure that I can use in VB:
    Code:
    Marshal.PtrToStructure(twCapability.Handle, twOneValue)
    I get the same data back with either call to Marshal.whatever. Is there a different way to get the data?

    I presume bytes 3 and 4 are the padding bytes? Does anyone know how VB.NET will store the structure in memory? How about C? Shouldn't they store the structures the same way? Can they be doing it different and that be the problem?

    Thanks for looking

  6. #6
    Join Date
    Jul 2000
    Location
    Milano, Italy
    Posts
    7,726

    Re: Scanning with TWAIN

    Never played too much with pointers, but to get the pointer of a structure
    you might try
    Code:
    Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(YourStructure))
    while YourStructure.Handle is not a pointer for a structure, but only for a window
    Code:
     Public Handle As IntPtr     'Pointer to a container
    and if I understood it correctly, the window is what you do not have here. This is a shot in the dark, of course...
    Last edited by Cimperiali; February 22nd, 2010 at 05:14 PM.
    ...at present time, using mainly Net 4.0, Vs 2010



    Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
    all the other wonderful people who made and make Codeguru a great place.
    Come back soon, you Gurus.

  7. #7
    Join Date
    Feb 2010
    Posts
    7

    Re: Scanning with TWAIN

    Thanks Cimp, a shot in the dark is better than no shot at all

    This is the first time I had to really deal with pointers myself, hence the difficulty. The C++ people don't know VB so they can't help and the VB people look up at the sky when I mention pointers.

    But to respond to your suggestion (maybe you may have another one) I don't allocate the structure, twain_32.dll allocates TW_ONEVALUE. Here's the steps:

    1) Call twain_32.dll passing it a MSG_Get to inform it that you are retrieving a value and in the same call send it a twsCapability structure with its Cap member set to the value of the capability you wish to retrive.
    2) twain_32.dll will allocate a structure of the correct type, set the member ConType to indicate what kind of structure it allocated and set Handle to a reference to this container.
    3) When the call returns, ConType should be examined to determine what kind of container you got, then you just get the data.

    Sounds simple. Could there be any overhead bytes? Do I need to add an offset to the Handle?
    I sure don't know!

  8. #8
    Join Date
    Feb 2010
    Posts
    7

    Re: Scanning with TWAIN

    I found out that a pointer to a structure is not the same as a pointer to the memory that a structure occupies. This won't work:
    Code:
    Marshal.PtrToStructure(twCapability.Handle, twOneValue)
    But this works (explicitly copying members manually)
    Code:
    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 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
    
                    Case Else
                        MsgBox("Unexpected One Value.  Ignored")
    
                End Select
    
                GlobalUnlock(twCapability.Handle)
    
                Return strValue
    
            End If
    
        End Function
    Yeah!!!

  9. #9
    Join Date
    Jul 2000
    Location
    Milano, Italy
    Posts
    7,726

    Re: Scanning with TWAIN

    Quote Originally Posted by Marman View Post
    I found out that a pointer to a structure is not the same as a pointer to the memory that a structure occupies.!
    oh, yes: structures are not like array: they are value type, not reference ones; thus a pointer to a structure means you should first box it, and then get the boxer pointer...
    ...at present time, using mainly Net 4.0, Vs 2010



    Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
    all the other wonderful people who made and make Codeguru a great place.
    Come back soon, you Gurus.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured