抛出调用类与结构错误

时间:2014-06-27 16:47:37

标签: vb.net winapi structure

有人可以解释为什么会有效:

 <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

这不是:

 <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

从另一个类调用这两个结构/类时:

 Dim newpoint As New Structures.MEMORYSTATUSEX()

        GlobalMemoryStatusEx(newpoint) 

第二名:

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

            GlobalMemoryStatusEx(newpoint) 

他们都在一个类中,当我使用size参数调用第二个时,它会在GlobalMemoryStatusEx(newpoint)调用时抛出“AccessViolationException的第一次机会”并使应用程序崩溃。

我无法理解为什么因为dwLength值在构造函数中都被初始化了?我是对的吗?

我想改变第一个例子的原因是因为我将所有结构移动到仅结构类,并认为这是一个好主意,直​​到我不明白为什么这不起作用,因为在调用API之前设置相同的值。

P / Invoke声明:

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

错误的详细信息:

Client.exe

中出现'System.AccessViolationException'类型的第一次机会异常

附加信息:尝试读取或写入受保护的内存...

如果我点击继续:

mscorlib.dll中出现'System.Reflection.TargetInvocationException'类型的第一次机会异常

附加信息:调用目标抛出了异常

1 个答案:

答案 0 :(得分:2)

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

lpBuffer参数是指针。必需,以便该函数可以编写结构成员。指针在VB.NET中隐藏得很好,当它们没有正确使用时,它们会将程序打到碎片上。很多可能的事故,AccessViolationException是更温和的变种。

在VB.NET中获取指针的两种基本方法。如果参数是值类型,则可以声明参数ByRef。或者如果它是引用类型(Class关键字),那么引用会在运行时自动成为指针,并且应该传递ByVal

因此,有效组合是传递ByRef的结构或传递ByVal的类。类还需要显式<StructLayout>来强制CLR以可预测的方式对其字段进行排序。你可以免费获得一个结构。因此,这是合乎逻辑的选择。

您应该使用My.Computer.Info,它已经为您调整了GlobalMemoryStatusEx()。