Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - .NET

Страница: 1 |

 

  Вопрос: структуры Добавлено: 01.07.06 19:33  

Автор вопроса:  Sacred Phoenix | ICQ: 304238252 
Есть такая структура данных (специально привёл под vb6):

Private Type SPort
   High As Byte
   Low As Byte
   Gravity As Byte
   FreezeZonks As Byte
   FreezeEnemyes As Byte
   Unused As Byte
End Type

Private Type Level
   Data(59, 23) As Byte
   Unused1 As Long
   Gravitation As Byte
   Unused2 As Byte
   Title(22) As Byte
   FreezeZonks As Byte
   InfotronsNeeded As Byte
   SPortsNumber As Byte
   SPorts(9) As SPort
   Unused3 As Long
End Type

Как нетрудно вычислить, размер она имеет 1536 байт. Вопрос: как "перегнать" структуру под vb2005 и под ним же читать бинарный файл (данные в нём разложены на такие структуры)?

Ответить

  Ответы Всего ответов: 7  

Номер ответа: 1
Автор ответа:
 EROS



Вопросов: 58
Ответов: 4255
 Профиль | | #1 Добавлено: 02.07.06 17:53
Тут вся беда в Data(59, 23) As Byte ...
Размер структуры определяется через Marshal.SizeOf, и при определении этого 2-мерного массива можно было бы указать аттрибут
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1440)>

но в этом случае при передаче структуры через Marshal.Copy теряется размерность массива и он становится 1-мерным. Поэтому я был вынужден пометить массив как SafeArray. Но тогда не получается корректно определить размер структуры, поэтому я ввел в структуру константу..
Вообщем смотри, что у меня получилось, разбирайся...

З.Ы. Если найдешь, как грамотно обойти 2-мерный (чтобы и размерность не терялась и корректно определялся размер)массив-отпишись..

Ответить

Номер ответа: 2
Автор ответа:
 EROS



Вопросов: 58
Ответов: 4255
 Профиль | | #2 Добавлено: 02.07.06 17:53
Option Strict On

Imports System.Text
Imports System.Text.Encoding
Imports System.Runtime.InteropServices

Public Class Form1

    <StructLayout(LayoutKind.Sequential)> _
    Structure SPort

        Public High As Byte
        Public Low As Byte
        Public Gravity As Byte
        Public FreezeZonks As Byte
        Public FreezeEnemyes As Byte
        Public Unused As Byte

    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Structure Level

        Sub New(ByVal Initialize As Boolean)
            If Initialize Then
                ReDim Me.Data(59, 23)
                ReDim Me.Title(22)
                ReDim Me.SPorts(9)
            End If
        End Sub

        <MarshalAs(UnmanagedType.SafeArray)> _
        Public Data(,) As Byte                '1440
        Public Unused1 As Int32               '4
        Public Gravitation As Byte            '1
        Public Unused2 As Byte                '1
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=23)> _
        Public Title() As Byte                '23
        Public FreezeZonks As Byte            '1
        Public InfotronsNeeded As Byte        '1
        Public SPortsNumber As Byte           '1
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> _
        Public SPorts() As SPort              '10*6=60
        Public Unused3 As Int32               '4

        Public Shared Length As Int32 = 1536
    End Structure

    '// ЗАГЛУШКА
    '// Реальный массив байт будешь читать из Stream файла
    Dim bytesStructure(Level.Length - 1) As Byte

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        '// Создаем заглушку

        '// Создаем экземляр структуры заполняем его данными
        Dim tempLevel As New Level(True)

        '// Байтовое представление строки
        Dim bytesTitle() As Byte = UTF8.GetBytes("Test structure Level";) '// <= 23 bytes
        With tempLevel
            '// Копируем в структуру. (через присвоение нельзя, иначе изменится размер)
            Array.Copy(bytesTitle, .Title, bytesTitle.Length)
            .Gravitation = 7
            .InfotronsNeeded = 3
            .Unused1 = 12345
            .Data(12, 12) = 222
        End With

        '// Выделяем блок памяти нужного размера и получаем Handle
        Dim memoryHandle As IntPtr = Marshal.AllocCoTaskMem(Level.Length)
        '// Копируем структуру в память
        Marshal.StructureToPtr(tempLevel, memoryHandle, True)
        '// Берем из памяти блок байт и переносим его в наш массив-заглушку
        Marshal.Copy(memoryHandle, bytesStructure, 0, Level.Length)
        '// Освобождаем память
        Marshal.FreeCoTaskMem(memoryHandle)

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        '// Выделяем блок памяти нужного размера и полyчaем Handle
        Dim memoryHandle As IntPtr = Marshal.AllocCoTaskMem(Level.Length)

        '// Копируем массив-заглушку по указанному адресу
        Marshal.Copy(bytesStructure, 0, memoryHandle, Level.Length)

        '// Заполняем нашу структуру
        Dim myLevel As Level = CType(Marshal.PtrToStructure(memoryHandle, GetType(Level)), Level)

        '// Освобождаем память
        Marshal.FreeCoTaskMem(memoryHandle)

        '// Check & Show Results
        Dim stringTitle As String = UTF8.GetString(myLevel.Title)
        '// Обрезаем до нужной длинны
        Dim NullCharPos As Int32 = stringTitle.IndexOf(vbNullChar)
        If NullCharPos <> -1 Then stringTitle = stringTitle.Substring(0, NullCharPos)
        '// Формируем строку
        Dim stringBuilder As New StringBuilder
        With stringBuilder
            .AppendLine(String.Format("Title: {0}", stringTitle))
            .AppendLine(String.Format("Gravitation: {0}", myLevel.Gravitation))
            .AppendLine(String.Format("InfotronsNeeded: {0}", myLevel.InfotronsNeeded))
            .AppendLine(String.Format("Unused1: {0}", myLevel.Unused1))
            .AppendLine(String.Format(";Data(12, 12): {0}", myLevel.Data(12, 12)))
        End With

        MessageBox.Show(stringBuilder.ToString, "Check & Show Results", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

End Class

Ответить

Номер ответа: 3
Автор ответа:
 EROS



Вопросов: 58
Ответов: 4255
 Профиль | | #3 Добавлено: 02.07.06 17:58
прочитать файл и разбить его на блоки по 1536 байт, я думаю, для тебя труда не составит..

Ответить

Номер ответа: 4
Автор ответа:
 Sacred Phoenix



ICQ: 304238252 

Вопросов: 52
Ответов: 927
 Профиль | | #4 Добавлено: 02.07.06 21:21
2 EROS: пасиба большое, щас будем разбираться...
Кста, теоретически, двумерный массив можно заменить одномерным как Data(1439) As Byte. На задачу это не повлияет.

Ответить

Номер ответа: 5
Автор ответа:
 EROS



Вопросов: 58
Ответов: 4255
 Профиль | | #5 Добавлено: 02.07.06 21:33
двумерный массив можно заменить одномерным как Data(1439) As Byte

Тогда вообще никаких проблем!!
Тебе надо будет именить следующе..
-Изиенить аттрибут у Data
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=1440)> _
        Public Data() As Byte

-Изменить Инициализацию массива
ReDim Me.Data(1439)

-Изменить тестовые строки
.Data(12, 12) = 222
.AppendLine(String.Format(";Data(12, 12): {0}", myLevel.Data(12, 12)))

И после этого.. Marshal.SizeOf корректно просчитает размер.. так что константа Length уже, в принципе, не нужна..

Ответить

Номер ответа: 6
Автор ответа:
 EROS



Вопросов: 58
Ответов: 4255
 Профиль | | #6 Добавлено: 02.07.06 21:35
Да, и вот еще что.. Объявления структур вынеси ЗА пределы формы...

Ответить

Номер ответа: 7
Автор ответа:
 EROS



Вопросов: 58
Ответов: 4255
 Профиль | | #7 Добавлено: 02.07.06 21:48
Еще как вариант, если не хочешь на прямую работать с памятью, мо можно сделать следующее:
 В структуре сделать конструктор, который на вход получает массив байт (длиной 1536). И непосредственно в самом конструктуре разложить все эти байты по полочкам.. к примеру: первый 1440 байт это Data, затем берем следующие 4 байта, делаем из них Int32 и загоняем в Unused1. Ну и т.д.. до тех пор, пока не заполним всю структуру..
Но сам понимаешь, это будет несколько медленне, чем через Marshal.Copy...

Ответить

Страница: 1 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам