| | | Join Date: Feb 2010
Posts: 7
| |
Hello,
I am trying to get some data from a C Dll via a structure and I am getting incorrect values back. I tried a couple of examples I found but they do not work. Since I do not know the proper way. I do not know how to fix it. Can anyone give me any advice, hints, redirection or any assistance what-so-ever. I've been struggling with this for weeks now so I will appreciate any kind of guidance (so will my boss :).
|
I found out that a pointer to a structure is not the same as a pointer to the memory that the structure occupies. Changed my code to copy the members explicitly. -
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(Runtime.InteropServices.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
 | | | Join Date: Mar 2008 Location: Arizona, USA
Posts: 3,476
| | | re: Marshaling data between managed VB.NET and an unmanaged C Dll | | | | Join Date: Feb 2010
Posts: 7
| | | re: Marshaling data between managed VB.NET and an unmanaged C Dll
Thanks for the reply. For the record I searched through quite a few pages on this site which took a couple of hours and found NOTHING helpful. Perhaps no one used the same keywords I used, although it did pick up several quotes that contained the keywords which the article had no relation.
And that link you provided doesn't provide anything useful, besides it discusses C#, NOT VB. since the problem I am having involves passing data from one language to another, including a third unnecessarily complicates things. Perhaps I need to give more detailed information, here goes:
I am writing a VB.NET application that uses TWAIN (dumb dll). When I call the function and get data back it is incorrect. What I don't know is what I am doing wrong. Here are the C structures: -
typedef unsigned short TW_UINT16, FAR *pTW_UINT16;
-
typedef unsigned long TW_UINT32, FAR *pTW_UINT32;
-
typedef HANDLE TW_HANDLE;
-
-
typedef struct {
-
TW_UINT16 Cap; /* id of capability to set or get, e.g. CAP_BRIGHTNESS */
-
TW_UINT16 ConType; /* TWON_ONEVALUE, _RANGE, _ENUMERATION or _ARRAY */
-
TW_HANDLE hContainer; /* Handle to container of type Dat */
-
} TW_CAPABILITY, FAR * pTW_CAPABILITY;
-
-
typedef struct {
-
TW_UINT16 ItemType;
-
TW_UINT32 Item;
-
} TW_ONEVALUE, FAR * pTW_ONEVALUE;
-
-
Which have been converted to VB.NET structure/class: - <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
-
-
<StructLayout(LayoutKind.Sequential, Pack:=4)> Friend Class TW_ONEVALUE
-
Public ItemType As Short
-
Public Item As Integer
-
End Class
-
Then I run this routine and get back 64356640 for the physical height and width: - 'Call into the C library
-
<DllImport("twain_32.dll", EntryPoint:="#1")> 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
-
-
'Start here:
-
...previous code
-
twCapability = New twsCapability
-
With twCapability
-
.Cap = twCap.IPhysicalWidth
-
.ConType = twContainerTyoe.One '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)
-
...more 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
-
-
Private Function GetOneValueNew(ByVal twCapability As twsCapability) As String
-
-
Dim rc As twRC
-
Dim pOneValue As Integer
-
Dim pTemp As Integer
-
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
-
pOneValue = GlobalLock(twCapability.Handle)
-
pTemp = VarPtr(twOneValue)
-
CopyMemory(pTemp, pOneValue, Marshal.SizeOf(twOneValue))
-
GlobalUnlock(twCapability.Handle)
-
strTemp = CType(twOneValue.Item, String)
-
Case Else
-
MsgBox("Error, one value expected; " & twCapability.ConType & " returned.")
-
End Select
-
GlobalFree(twCapability.Handle)
-
Return strTemp
-
Else
-
ErrorStatus()
-
Return vbNullString
-
End If
-
-
End Function
-
I included the function GetOneValueNew( because I found that method somewhere on the net, but it was written in VB6. Unfortunately I get 0 back from that.
I tried searching the net but didn't find my answer. I used "VB.NET marshal structure C dll". I included this incase someone may have a better search string.
I even tried writing the code to access the dll in C++. But I get an error in the VB routine that calls it "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." I presume that is also a problem form the unmanaged C dll trying to write to memory allocated in managed C++.
Thanks for looking!
| | | | Join Date: Feb 2010
Posts: 7
| | | re: Marshaling data between managed VB.NET and an unmanaged C Dll
I found out that a pointer to a structure is not the same as a pointer to the memory that the structure occupies. Changed my code to copy the members explicitly. -
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(Runtime.InteropServices.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
|  | | | |