Click to See Complete Forum and Search --> : Scanning with TWAIN
Marman
February 18th, 2010, 01:09 PM
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:
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:
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.
HanneSThEGreaT
February 19th, 2010, 01:30 AM
Weclome to the forums! :wave:
When posting code, please make use of [CODE] tags, as explained here :
http://www.codeguru.com/forum/showthread.php?t=403073
Thank you
Hannes
Marman
February 19th, 2010, 10:04 AM
Sorry, didn't see the option for 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
<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.
Cimperiali
February 20th, 2010, 07:11 PM
have you seen this?
http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=1551&lngWId=10
Marman
February 22nd, 2010, 10:49 AM
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
typedef struct {
TW_UINT16 ItemType;
TW_UINT32 Item;
} TW_ONEVALUE, FAR * pTW_ONEVALUE;
I tried viewing the bytes returned (for the width) using this:
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:
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
Cimperiali
February 22nd, 2010, 03:51 PM
Never played too much with pointers, but to get the pointer of a structure
you might try
Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(YourStructure))
while YourStructure.Handle is not a pointer for a structure, but only for a window
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...
Marman
February 23rd, 2010, 08:42 AM
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!
Marman
February 23rd, 2010, 12:28 PM
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:
Marshal.PtrToStructure(twCapability.Handle, twOneValue)
But this works (explicitly copying members manually)
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!!!
Cimperiali
February 24th, 2010, 03:06 PM
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...
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.