Valhalla Legends Forums Archive | .NET Platform | CopyMemory / Bitconverter - VB6 Structures

AuthorMessageTime
Grok
I am converting a VB6 library (DLL) project to .NET, and it does a large number of structure copies from areas using pointers returned from standard C DLLs.  Here is one example where I am getting a list of what is in a "File Cabinet".  In another thread someone said CopyMemory should be retired in favor of Bitconverter class.  Does that apply to working with old structures?  Can someone give me a pointer (pun intended) in the right direction for converting (again intended) this bit to Bitconverter?

[code]
    Type KGI_FILE_LIST0
        file_Entries As Long                    'Number of entries in File Cabinet
        file_Keywords As Long                   'Number of keywords in File Cabinet
        file_Flags As Integer                   'File Cabinet Flags
        file_ProtectFlags  As Integer  ' Mask for Protection flags; Added by Anubha because structure
        '....snipped many more fields
    End Type
    Public Const KGI_FILE_LIST_SIZE0 = 198

    Dim File_List As KGI_FILE_LIST0

    'We can only put so many file cabinet structures in memory!
    'Use Fix to just return the integer portion
    maxentries = Fix(65535 / KGI_FILE_LIST_SIZE0)

        'The following returns a handle to the memory location containing the file cabinet structures.
        hCabinet = KGI_ListFileCabinets(m_Session, Count)

        lpAddr = GlobalLock(hCabinet)               'lock the area in memory so that it does not get corrupted

        'is just a version of CopyMemory
        Call KGI_MemoryRead(File_List, lpAddr, KGI_FILE_LIST_SIZE0)

        'do stuff with the File_List structure
        Call DoStuff(File_List)

        'Unlock and free the memory
        retcode = GlobalUnlock(hCabinet)
        retcode = GlobalFree(hCabinet)

[/code]
December 7, 2005, 12:29 PM
Myndfyr
Well there are a few suggestions I can provide (we should talk on MSN, because this is frustrating in the interim, but I can't atm) and you can evaluate them based on your situation.

1.) I could suggest a type derived from System.IO.Stream that would function the way you wanted to.  Streams can operate essentially like pointers with an offset given from the beginning of the file (rather than the starting memory location).  You could then use something like BinaryReader to read your values out of the stream.  For example, you could create a function to read your header:
[code]
Public Sub ReadFileList0(ByVal str As Stream, ByRef entries As Long, ByRef keywords As Long, ByRef flags As Integer, ByRef protectFlags As Integer)
  Dim br As New BinaryReader(str)
  entries = br.ReadInt64()
  keywords = br.ReadInt64()
  flags = br.ReadInt32()
  protectFlags = br.ReadInt32()
End Sub
[/code]

That might be non-optimal for your situation. 
2.) This might work better for you if you're using byte arrays in-memory already and you have a lot of stuff to read:
[code]
Imports System.Runtime.InteropServices

Public Function ConvertToFileList(ByVal data() As Byte) As KGI_FILE_LIST0
  Dim rawSize As Integer = Marshal.SizeOf( GetType(KGI_FILE_LIST0) )
  If rawSize > data.Length Then
    Throw New ArgumentException("Data length too short.")
  End If

  Dim handle As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned)
  IntPtr buffer = handle.AddrOfPinnedObject()
  Dim returnValue As KGI_FILE_LIST0 = CType(Marshal.PtrToStructure(buffer, GetType(KGI_FILE_LIST0)), KGI_FILE_LIST0)

  handle.Free()
  ConvertToFileList = returnValue
End Function
[/code]
That seems a little cumbersome too.  In C# I'd just do a byte copy via pointers, but VB users aren't allowed access to pointers.  Sucks for you. :P

Oh, and finally, if you were getting data in via a function like so:
[code]
extern "C" __declspec(dllexport) void get_file_list(KGI_FILE_LIST0* pFileList);
[/code]
which it actually looks like you might be doing with KGI_ListFileCabinets (although I can't tell for sure), then you *can* do this through a neat little structure trick.

[code]
Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Explicit)>_
Public Struct KGI_FILE_LIST0
  <FieldOffset(0)> Public file_Entries As Long
  <FieldOffset(8)> Public file_Keywords As Long
  <FieldOffset(16)> Public file_Flags As Integer ' or Flags enumeration?
  <FieldOffset(20)> Public file_ProtectFlags As Integer
' etc.
End Struct

' Then later:
<DllImport("theDll.dll")>_
Public Shared Sub DoSomeImportedFunction( _
  <MarshalAs(UnmanagedType.LPStruct)> ByVal fileList As KGI_FILE_LIST)
[/code]
December 7, 2005, 4:39 PM

Search