StructToVariant - VariantToStruct

Iniciado por F3B14N, 3 Noviembre 2010, 22:05 PM

0 Miembros y 1 Visitante están viendo este tema.

F3B14N

Hola gente, quería pedirle a los coders si se animan a reparar estas simples funciones. Ya que funcionan en local, pero al intentar cargar un variant guardado a una estructura en otro proyecto, da error.

Private Type ControlVB
    sType As String
    sName As Strin
End Type
Private Declare Function CopyBytes Lib "MSVBVM60" Alias "__vbaCopyBytes" (ByVal Size As Long, Dest As Any, Source As Any) As Long

Private Sub main()
    Dim dd As ControlVB
    Dim bb As ControlVB
    Dim aa As Variant
   
    dd.sName = "aaaaa"
    dd.sType = "TextBox"
   
    aa = StructToVariant(VarPtr(dd), LenB(dd))
    Call VariantToStruct(aa, VarPtr(bb))
   
    MsgBox bb.sName
End Sub

Private Function StructToVariant(ByVal StructPtr As Long, ByVal Size As Long) As Variant
    Dim Bin() As Byte
   
    ReDim Bin(Size)

    Call CopyBytes(Size, ByVal VarPtr(Bin(0)), ByVal StructPtr)
    StructToVariant = Bin
End Function

Private Function VariantToStruct(ByRef vVariant As Variant, ByVal StructPtr As Long)
    Call CopyBytes(LenB(vVariant) - 1, ByVal StructPtr, ByVal StrPtr(vVariant))
End Function


Gracias.

BlackZeroX

.
Yo personalemente solo cambiaria los punteros hacia las variables... igual no creo que nadie te ayude en la forma que lo pides el susodicho problema...

Dulces Lunas!¡.
The Dark Shadow is my passion.

F3B14N

Cita de: BlackZeroX▓▓▒▒░░ en  4 Noviembre 2010, 09:49 AM
.
Yo personalemente solo cambiaria los punteros hacia las variables... igual no creo que nadie te ayude en la forma que lo pides el susodicho problema...

Dulces Lunas!¡.

A que te referís 'en la forma que lo pides el susodicho problema', somos de distintos regiones :P, no en todos los lugares se habla/escribe de la forma que tu tenes incorporada.
No se a que te referís, pero me da la sensación, de que crees que lo pido de mala manera o faltando el respeto :S. Si es así, para nada es esa mi intención, discúlpenme si se mal entiende.

---

BlackZeroX entiendo lo que decís pero, para lo que estoy haciendo, es necesario guardar la estructura, esa estructura esta de ejemplo para que entiendan lo que intento hacer... Y ademas me da curiosidad, debería funcionar, ya que si lo hago con las funciones Get y Put trabajando con binarios, funciona.
El problema esta al sacar los datos de memoria :/

Gracias!

BlackZeroX

#3
.
Susodicho problema es el problema actual expuesto... soy de México y en españa me aprece que usan lo mismo...

mira que no miento:

http://www.wordreference.com/definicion/susodicho
http://www.google.com.mx/search?q=Susodicho+&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:es-MX:official&client=firefox-a.

Ahora ya vi mejor el codigo solo te dire que las variables de tipo string u otras tienden a tener constructores o similares esto por el SafeArray de VB6, aun no lo confirmo pero lo que si te puedo decir es que como estas COPIANDO solo los punteros al termino del proceso la variable N es destruida y como la variable Z tiene el mismo puntero intentara destruir algo que ya esta destruido, esto es con esactitud uno de los problemas que yo tube hace tiempo... lo resolvi cambiando punteros entre variables (  SwapPtr()  ); aun que viendolo mejor no es el mismo problema ya que la funcion StructureToVariant solo retorna un tipo de variable Array de byte, aun que se intento hacer algo similar...

Ahora TODO el codigo esta mal... la forma mas facil de pasar una variable "Struture" a un tipo "Variant" es esta

Código (Vb) [Seleccionar]


VariableVariant = VarianbleStructure



y viseversa (Solo del mismo tipo OJO con eso)

y para cambiar un puntero de variable por otra  puedes usar esta funcion que me hice para evitar un tipo crash con destruccion de variables al finalizar el proceso...

Código (Vb) [Seleccionar]


Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)

Public Sub SwapPtr(ByVal lngPtrOne As Long, ByVal lngPtrTwo As Long, Optional LenOFStructure As Long = 4)
If LenOFStructure < 1 Then Exit Sub
Dim Byt_Bytes()                     As Long
    ReDim Byt_Bytes(1 To LenOFStructure)
    Call CopyMemory(ByVal VarPtr(Byt_Bytes(1)), ByVal lngPtrOne, LenOFStructure)
    Call CopyMemory(ByVal lngPtrOne, ByVal lngPtrTwo, LenOFStructure)
    Call CopyMemory(ByVal lngPtrTwo, ByVal VarPtr(Byt_Bytes(1)), LenOFStructure)
End Sub



Dulces Lunas!¡.
The Dark Shadow is my passion.

F3B14N

Gracias por interesarte y ayudarme BlackZeroX  ;-)
Pero no era eso, sino que, el problemín es la funcion Len() de VB6 que devuelve el tamaño de la estructura erroneamente  :-\.

Con este ejemplo lo pueden confirmar:

Private Type st
    ss As String
    ll As Long
End Type

Private Sub Form_Load()
    Dim stt As st
    stt.ss = "aaaaaa"
    stt.ll = 500
    MsgBox Len(stt)
    End
End Sub


Si cambian el "a.." por algo mas/menos largo, el retorno de Len() vá a ser el mismo siempre... y ese es el problema para pasar la estructura a un array byte.

Si alguien supiera como solucionar esto, estaria COMPLETAMENTE agradecio si me ayudaran a resolver el problemita.

Gracias!

LeandroA

Las estructuras deben tener un tamaño fijo, esto queire decir que si utilizas string vas a tener que darle una dimencion

Private Type st
    ss As String * 50
    ll As Long
End Type


de todas formas "creo" que aveces esto puede no funcionar, no recuerdo si era porque mesclaba integer, pero no me funciono.

creo que lo mas adecuado seria utilizar array de bits,

Private Type st
    tamañocadena as long
    cadena() as byte
    otracosa As Long
End Type


entonces en tamañocadena pones la dimencion del array de cadena().

bue nose igual proba con lo otro primero.

saludos.

F3B14N

Cita de: LeandroA en 13 Noviembre 2010, 02:29 AM
Las estructuras deben tener un tamaño fijo, esto queire decir que si utilizas string vas a tener que darle una dimencion

Private Type st
    ss As String * 50
    ll As Long
End Type


de todas formas "creo" que aveces esto puede no funcionar, no recuerdo si era porque mesclaba integer, pero no me funciono.

creo que lo mas adecuado seria utilizar array de bits,

Private Type st
    tamañocadena as long
    cadena() as byte
    otracosa As Long
End Type


entonces en tamañocadena pones la dimencion del array de cadena().

bue nose igual proba con lo otro primero.

saludos.

Si, es cierto al darle las dimensiones funciona sin problemas, pero en ambos casos Strings o ByteArrays, sucede lo mismo al dejarlos dinamicos :/
Se me ocurre hacer una funcion que busque a partir del puntero que se le pasa, "el prototipo de cierre de un structure" osea "las instrucciones", voy a investigar un poco aver si logro algo :P
Ojala alguno de los expertos que rondan por aca me ayuden :A

Gracias

BlackZeroX

#7

EDITO IMPORTANTE:

OJO en una structura donde aya Strings, Arragles o similares que no tengan longitud de bites definidos previamente se sustituyen con el puntero hacia otra parte de la memoria es decir que se sustituyen por 4 bytes en cada uno donde aparezca (Punteros <<Long>>),

Código (Vb) [Seleccionar]


Private Type st
   ss As String
   ll As Long
End Type



Son 8 bytes por que? sencillo mira

4 bytes de puntero a la estructura de 8 bytes que contiene a si ves los punteros a los elementos de la estructura es decir:

Código (vb) [Seleccionar]


Dim a as st  
dim lng_ptr as long

lng_ptr = Varptr(a)  ' <--- Puntero a la estructura es decir 4 bytes de tipo long



ese puntero ( el almacenado en -> lng_ptr) apunta a el puntero del inicio de tu estructura donde hay

4 bytes del String (Puntero)
4 bytes del tipo long (No es un putero ya es la variable)

= 12 bytes + los bytes a donde apuntan los 4 del string

Es decir Len() esta haciendo correctamente su trabajo... solo que actua de esta manera como lenb()

.

gracias a esto la estructura tiene un tamaño fijo y cada elemento es un apuntador (para los string u otros que no sean numeros), por lo tanto si quieres leer algo de X elemento y cambiar a otra estructura o variable etc puedes obtener esos 4 bytes del string e intercambiarlos con los de otra variable string o dentro de otra estructura de distinto tipo

Ejemplo:

Código (Vb) [Seleccionar]


Option Explicit

Private Type Estruct1
   st1 As String
   in1 As Long
   st2 As String
End Type

Private Type Estruct2
   st1 As String
   in1 As Long
   st2 As String
   in2 As Long
   st3 As String
End Type

Private Sub Form_Load()
Dim st1 As Estruct1
Dim st2 As Estruct2
Dim S   As String

   S = "BlackZeroX"
   st1.st1 = "infrangelux"
   Call SwapPtr(VarPtr(S), VarPtr(st1.st1), 4)
   Call SwapPtr(VarPtr(st1.st1), VarPtr(st2.st3), 4)
   MsgBox S
   MsgBox st1.st1
   MsgBox st2.st3
End Sub



en un modulo cualquiera...

Código (Vb) [Seleccionar]


Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)

Public Sub SwapPtr(ByVal lngPtrOne As Long, ByVal lngPtrTwo As Long, Optional LenOFStructure As Long = 4)
If LenOFStructure < 1 Then Exit Sub
Dim Byt_Bytes()                     As Long
   ReDim Byt_Bytes(1 To LenOFStructure)
   Call CopyMemory(ByVal VarPtr(Byt_Bytes(1)), ByVal lngPtrOne, LenOFStructure)
   Call CopyMemory(ByVal lngPtrOne, ByVal lngPtrTwo, LenOFStructure)
   Call CopyMemory(ByVal lngPtrTwo, ByVal VarPtr(Byt_Bytes(1)), LenOFStructure)
End Sub



Dulces Lunas!¡.
The Dark Shadow is my passion.

BlackZeroX

#8
.
Mas claro aqui lo dejo explicado:

Código (Vb) [Seleccionar]

Private Type st
    ss As String
    ll As Long
End Type

Private Sub Form_Load()
    Dim stt As st
    '   //  [ stt.ss ] Cada caracter esta separado por un "chr(0)" y _
    solo por esto cada caracter = 2 bytes en este caso son 12 bytes
    stt.ss = "aaaaaa"
    stt.ll = 500
    '   //  [ len() ] La estructura consta de 2 parametros por asi decirlo _
    y uno de ellos es Un "String" de longitud No declarada _
    entonces esto significa que en ese lugar hay Un puntero a el primer digito _
    de la "string" es decir en otra parte de la memoria esta la "String". _
    mientras que el tipo "long" ya se sabe que son 4 bytes por ende No se _
    nesesita crear en otra parte es decir son 8 bytes de la estructura _
    y solo uno de los campos es "String" de longitud NO DECLARADA _
    por ende es creado en otra parte, y sustituido po su puntero al mismo!¡.
    MsgBox Len(stt) + LenB(stt.ss) - 4  '   //  El 4 es el puntero al string
    '   //  (4 bytes = long) +  LenB(stt.ss) = bytes Reales
    '   //  Es decir en este caso: _
    4 + 6*2 -4  ( ya que el primer 4 es long, El 6*2 es que son 4 caracteres pero cada _
    caracter termina por Until chr(0) por eso es por 2 ) y el -4 es el puntero Dela estructura.
End Sub



Dulces Lunas!¡.
The Dark Shadow is my passion.

F3B14N

Perfecto ahora si entendí como funciona, muchas gracias!   :D