Вызов класса против ошибки структуры брошены
Может кто-нибудь объяснить, почему это работает:
<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)
И 2-й:
Dim newpoint As New Structures.MEMORYSTATUSEX(CType(Marshal.SizeOf(GetType(Structures.MEMORYSTATUSEX)), UInt32))
GlobalMemoryStatusEx(newpoint)
Они оба находятся внутри класса, когда я вызываю второй с параметром size, он вызывает" первый шанс AccessViolationException " на вызове GlobalMemoryStatusEx(newpoint)
и завершает работу приложения.
Я не могу понять, почему, так как значение dwLength инициализируется на обоих в конструкторе? Я так ведь?
Причина, по которой я хочу изменить первый пример, заключается в том, что я перемещаю все структуры в класс только структуры, и думал, что это было бы хорошей идеей, пока я не смог понять, почему это не сработало, так как одно и то же значение устанавливается перед вызовом API.
P / Invoke объявления:
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function GlobalMemoryStatusEx(lpBuffer As Structures.MEMORYSTATUSEX) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Подробности ошибки:
Первое случайное исключение типа ' System.AccessViolationException ' произошло в клиенте.exe
Дополнительная информация: попытка чтения или запишите защищенную память...
Если я нажму кнопку Продолжить:
Первое случайное исключение типа ' System.Отражение.TargetInvocationException ' произошло в mscorlib.dll
Дополнительная информация: исключение было вызвано целью вызова
1 ответ:
Private Shared Function GlobalMemoryStatusEx(lpBuffer As Structures.MEMORYSTATUSEX) ...
Аргумент
lpBuffer
являетсяуказателем . Требуется, чтобы функция могла записывать элементы структуры. Указатели хорошо спрятаны внутри VB.NET, они взрывают программы в пух и прах, когда они не используются должным образом. Множество возможных неудач, исключение AccessViolationException-это более мягкая разновидность.Два основных способа получить указатель в VB.NET можно объявить аргумент
Таким образом, допустимые комбинации - это структура, передаваемая ByRef, или класс, передаваемый ByVal. Класс также требует явногоByRef
, если аргумент является типом значения. Или если это ссылочный тип (ключевое слово класса), то ссылка автоматически становится указателем во время выполнения и должен быть переданByVal
.<StructLayout>
, чтобы принудить CLR упорядочивать свои поля предсказуемым образом. Вы получаете его бесплатно со структурой. Что, следовательно, является логическим выбором.Вы должны использовать My.Computer.Info, это уже pinvokes GlobalMemoryStatusEx () для вас.