|
-
February 18th, 2010, 02:09 PM
#1
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!
-
February 19th, 2010, 02:30 AM
#2
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
-
February 19th, 2010, 11:04 AM
#3
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.
-
February 20th, 2010, 08:11 PM
#4
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.
-
February 22nd, 2010, 11:49 AM
#5
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
-
February 22nd, 2010, 04:51 PM
#6
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.
-
February 23rd, 2010, 09:42 AM
#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!
-
February 23rd, 2010, 01:28 PM
#8
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!!!
-
February 24th, 2010, 04:06 PM
#9
Re: Scanning with TWAIN
 Originally Posted by Marman
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|