Mashalling IntPtr into a byte array? I can see how to do it the other way around!

R

Robin Tucker

I need to marshal an IntPtr (which I've got from GlobalLock of an HGLOBAL)
into a byte array. I know the size of the array required and I've got a
pointer to the blob, but I can't see how to copy the memory across.

Using Marshal.PtrStructure doesn't work - it says my byte() array is not
blittable! (byte is a blittable type however). Cannot use Marshal.Copy,
because that works the other way around (for mashalling to COM, not from
it).

Any ideas?

Dim theLocked As IntPtr
Try

' Find out how big the HGLOBAL allocation returned is

Dim theAudioSize As Integer = GlobalSize(hAudio)

' an array to store the WAV

Dim theSound As System.Byte()

' Resize the array

ReDim theSound(theAudioSize)

' Now, lock its buffer so we can load it in to our variable.

theLocked = GlobalLock(hAudio)

' Marshal "theLocked" into the array

??????????????????????

Catch Ex As Exception

' Whoops

Finally
Marshal.FreeHGlobal(theLocked)
End Try
 
R

Robin Tucker

Yes, that was my first attempt, I wrote:

Marshal.PtrToStructure( myAudioPtr, theSoundByteArray)

Exception was: "The specified structure must be blittable or have layout
information."

I was under the impression that byte was blittable, as was the complex type
byte()?
 
R

Robin Tucker

I got it:

theLocked is my locked HGLOBAL

Sound is byte(theAudioSize)

then,

Marshal.Copy(theLocked, Sound, 0, theAudioSize)
 
K

Ken Tucker [MVP]

Hi,

I guess I should have read your message better. When I use the
netserverenum api it returns a pointer to an array. I have to read each
element of the array individually. Here is an example. I hope this helps.

Imports System.Runtime.InteropServices

Module Module1

Structure Computer_info_101

Public Platform_ID As Integer

<MarshalAsAttribute(UnmanagedType.LPWStr)> Public Name As String

Public Version_Major As Integer

Public Version_Minor As Integer

Public Type As Integer

<MarshalAsAttribute(UnmanagedType.LPWStr)> Public Comment As String

End Structure

Declare Unicode Function NetServerEnum Lib "Netapi32.dll" _

(ByVal Servername As Integer, ByVal level As Integer, _

ByRef buffer As Integer, ByVal PrefMaxLen As Integer, _

ByRef EntriesRead As Integer, ByRef TotalEntries As Integer, _

ByVal ServerType As Integer, ByVal DomainName As String, _

ByRef ResumeHandle As Integer) As Integer

Declare Function NetApiBufferFree Lib "Netapi32.dll" _

(ByVal lpBuffer As Integer) As Integer

Private Const SV_TYPE_SERVER As Integer = &H2 ' All Servers

Sub Main()

Dim ComputerInfo As Computer_info_101

Dim i, MaxLenPref, level, ret, EntriesRead, TotalEntries, ResumeHandle As
Integer

Dim BufPtr As Integer

Dim iPtr As IntPtr

MaxLenPref = -1

level = 101

ret = NetServerEnum(0, level, BufPtr, MaxLenPref, EntriesRead, TotalEntries,
_

SV_TYPE_SERVER, "MSHOME", ResumeHandle) ' Replace MSHOME with your workgroup
name

If ret <> 0 Then

Console.WriteLine("An Error has occured")

Return

End If



' loop thru the entries

For i = 0 To EntriesRead - 1

' copy the stuff into our structure

Dim ptr As IntPtr = New IntPtr(BufPtr)

computerInfo = CType(Marshal.PtrToStructure(ptr,
GetType(Computer_info_101)), _

Computer_info_101)

BufPtr = BufPtr + Len(ComputerInfo)

Console.WriteLine(computerInfo.Name)

Next

NetApiBufferFree(BufPtr)

Console.Write("Press Enter to End")

Dim s As String = Console.ReadLine()

End Sub





End Module

Ken
 
J

Jay B. Harlow [MVP - Outlook]

Robin,
In addition to Ken's other comments.

My understanding is that Marshal.PtrToStructure & Mashal.StructureToPtr are
used for COMPLEX types. COMPLEX Types as in Structures & Classes. Remember
that Byte is blittable, as its a primitive type. Primitive type as in its
native to the machine, the managed & unmanaged representation are the same
(a 32bit unmanaged int has the same physical layout as a 32bit managed int).
My understanding is you need to use Marshal.Copy to copy arrays of primitive
types.

There are overloaded Marshal.Copy functions that copy from a byte array to
an IntPtr and that copy from an IntPtr to a Byte array. Watch your source &
destination arguments and you should be fine.

Dim theLocked As IntPtr
Dim theSound As System.Byte()
Dim theSoundSize as Integer


' Copy from HGLOBAL to the byte array
Marshal.Copy(theLocked, theSound, 0, theSoundSize)

' Copy from the byte array to HGLOBAL
Marshal.Copy(theSound, 0, theLocked, theSoundSize)

With Marshal.Copy the source is the first parameter, followed by the
destination. (Note arrays have 2 actual parameters, the array & the starting
index).

Adam Nathan's book ".NET and COM - The Complete Interoperability Guide" from
SAMS Press, provides you will every thing you ever wanted to know about
Interop and then some.

Hope this helps
Jay
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top