2

Can someone explain why this works:

 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Public Class MEMORYSTATUSEX

         Public Sub New()
            Me.dwLength = CType(Marshal.SizeOf(GetType(MEMORYSTATUSEX)), UInt32)
        End Sub

        Public dwLength As UInt32

        Public dwMemoryLoad As UInt32

        Public ullTotalPhys As UInt64

        Public ullAvailPhys As UInt64

        Public ullTotalPageFile As UInt64

        Public ullAvailPageFile As UInt64

        Public ullTotalVirtual As UInt64

        Public ullAvailVirtual As UInt64

        Public ullAvailExtendedVirtual As UInt64
    End Class

And this doesn't:

 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Structure MEMORYSTATUSEX

        Public Sub New(ByVal dwlength As UInt32)
            Me.dwLength = dwlength
        End Sub

        Public dwLength As UInt32

        Public dwMemoryLoad As UInt32

        Public ullTotalPhys As UInt64

        Public ullAvailPhys As UInt64

        Public ullAvailPageFile As UInt64

        Public ullTotalVirtual As UInt64

        Public ullAvailVirtual As UInt64

        Public ullAvailExtendedVirtual As UInt64
    End Structure

When calling both structures/class from another class like this:

 Dim newpoint As New Structures.MEMORYSTATUSEX()

        GlobalMemoryStatusEx(newpoint) 

And the 2nd:

 Dim newpoint As New Structures.MEMORYSTATUSEX(CType(Marshal.SizeOf(GetType(Structures.MEMORYSTATUSEX)), UInt32))

            GlobalMemoryStatusEx(newpoint) 

They're both inside a class, when i call the second with the size parameter it throws "A first chance of AccessViolationException" on the GlobalMemoryStatusEx(newpoint) call and crashes the application.

I can't understand why since the dwLength value is initialized on both in the constructor? Am i right?

The reason i want to change the first example is because i'm moving all Structures to a Structure-Only class, and thought this would be a good idea until i coudln't understand why this didn't work, since the same value is set before the call to the API occurs.

P/Invoke declarations:

    <DllImport("kernel32.dll", SetLastError:=True)> _
    Private Shared Function GlobalMemoryStatusEx(lpBuffer As Structures.MEMORYSTATUSEX) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

Error's Detail:

A first chance exception of type 'System.AccessViolationException' occurred in Client.exe

Additional information: Attempt of read or write protected memory...

If i click continue:

A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

Additional information: exception has been thrown by the target of an invocation

SomeNickName
  • 511
  • 6
  • 32
  • possible duplicate of [What is the difference between a reference type and value type in c#?](http://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value-type-in-c) From [MSDN](http://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx): `lpBuffer [in, out]` _"A **pointer** to a MEMORYSTATUSEX structure that receives information about current memory availability."_ – Bjørn-Roger Kringsjå Jun 27 '14 at 17:28
  • Post your p/invoke declarations. – tcarvin Jun 27 '14 at 17:57

1 Answers1

2
  Private Shared Function GlobalMemoryStatusEx(lpBuffer As Structures.MEMORYSTATUSEX) ...

The lpBuffer argument is a pointer. Required so that the function can write the structure members. Pointers are well-hidden in VB.NET, they blow programs to smithereens when they are not used properly. Lots of possible mishaps, an AccessViolationException is the milder variety.

Two basic ways to get a pointer in VB.NET. You can declare an argument ByRef if the argument is a value type. Or if it is reference type (Class keyword) then a reference automatically becomes a pointer at runtime and should be passed ByVal.

So valid combinations are a Structure passed ByRef or a Class passed ByVal. A Class also requires an explicit <StructLayout> to force the CLR to order its fields in a predictable manner. You get it for free with a Structure. Which is therefore the logical choice.

You should be using My.Computer.Info, it already pinvokes GlobalMemoryStatusEx() for you.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks ! I didn't know about the Byref thing on structures since i don't use them alot and usually is for Pinvoke so i just copy from pinvoke.net. But it makes sense now, i'm not using My.Computer.Info because i just want the % of the available memory and i believe My.Computer.Info doesn't provide that afaik. – SomeNickName Jun 27 '14 at 19:09