Simular uniones C++

Tus preguntas. Algoritmos o Grupos de Comandos formando Programas Escripts.
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Simular uniones C++

Mensaje por Jonny »

Hola

Estoy haciendo una función, que utiliza una Api de Windows, que según veo en la documentación va a ser difícil, si no imposible.

Resulta, que la api requiere de una estructura, que hay que pasarle en uno de sus parámetros. La estructura es esta:

http://msdn.microsoft.com/en-us/library/aa924755.aspx

El problema de esa estructura, es que veo que hay una unión, y tengo entendido que en AutoIt no hay manera de crear uniones, ni nada que se le parezca, así como se pueden crear estructuras con DllStructCreate().

Entonces:
¿No podré utilizar esta api?...

O hay alguna forma de engañarla? :).

Acias,

Salu2!
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Simular uniones C++

Mensaje por Chefito »

Mmmmmm.....has buscado la definición de la unión en google???? :smt012 .
Cito de la página http://es.wikibooks.org/wiki/Programaci ... _y_Uniones:
Uniones
La definicion de "union" es similar a la de "estructura", La diferencia entre las dos es que en una estructura, los miembros ocupan diferentes areas de la memoria, pero en una union, los miembros ocupan la misma area de memoria. Entonces como ejemplo:

union {
int i;
double d;
} u;
El programador puede acceder a través de "u.i" o de "u.d", pero no de ambos al mismo tiempo. Como "u.i" y "u.d" ocupan la misma área de memoria, modificar uno modifica el valor del otro, algunas veces de maneras impredecibles.

El tamaño de una union es el de su miembro de mayor tamaño.
Está claro no? Pues eso, que varias variables utilizan la misma posición de memoria para almacenar y recuperar sus datos.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola

sí, busqué la definición y encontré esto, que fue lo que estuve mirando (aunque no entendí nada) :):

[ul]
http://www.zator.com/Cpp/E4_7.htm
[/ul]

La explicación que has puesto tú es más clara, aunque si es así no se para qué existen :P.

En el foro inglés de AutoIt, vi algunos post en los que hablaban de crear uniones. En uno de ellos ponían ejemplos como este:

Código: Seleccionar todo

$Union=DllStructCreate("byte[4]")
$IntUnion=DllStructCreate("int", DllStructGetPtr($Union))
$DWordUnion=DllStructCreate("dword", DllStructGetPtr($Union))
...
...
Imagino, que esto viene a confirmar la explicación que ponías, de que el tamaño de la unión es su tamaño máximo

Código: Seleccionar todo

$Union=DllStructCreate("byte[4]")
y que todas las variables se almacenan en la misma posición de la memoria:

Código: Seleccionar todo

$IntUnion=DllStructCreate("int", DllStructGetPtr($Union))
$DWordUnion=DllStructCreate("dword", DllStructGetPtr($Union))
Pero, ¿como haría para crear una unión con las dos variables del ejemplo anterior? ¿Quizá así?:

Código: Seleccionar todo

$Union=DllStructCreate("byte[4]")
$IntDWordUnion=DllStructCreate("int;dword", DllStructGetPtr($Union))
Entiendo que debe ser así... Que de esta manera, $IntDWordUnion tendrá un espacio total de 4 bytes, y que teóricamente he de poder acceder al elemento 1 y 2, normalmente, con DllStructSetData() y DllStructGetData() ¿no?.

Acias,

Salu2!
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Bueno....

Parece, que he hecho la estructura, con su unión, estructuras anidadas ...

Me ha quedado algo como esto:

Código: Seleccionar todo

Local $_MMTimeUnion, $_MMTimeUnionSize, $_MMTimeStruct
$_MMTimeUnionSize=DllStructCreate("int[256]")
$_MMTimeUnion=DllStructCreate("dword ms;dword sample;dword cb;dword ticks;"&DllStructCreate("byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2]")&";"&DllStructCreate("dword songptrpos"), DllStructGetPtr($_MMTimeUnionSize)
$_MMTimeStruct=DllStructCreate("uint wType;"&$_MMTimeUnion)

¡espero haberlo hecho bien!... pero esto es un lío de los gordos ...

Creo, que he puesto quizá un tamaño demasiado grande a la unión, pero como no se lo que puede llegar a necesitar, preferí pasarme un poco...

A ver que os parece, si está bien...

Salu2!
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola

Sorry, la forma en qué puse que había hecho la estructura no funciona...

Debería ser algo así:

Código: Seleccionar todo

Local $_MMTimeStruct, $_MMTimeUnionSize, $_MMTimeUnion, $_MMTime_Struct0, $_MMTime_Struct1
$_MMTimeUnionSize=DllStructCreate("int[256]")
$_MMTime_Struct0=DllStructCreate("byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2]")
$_MMTime_Struct1=DllStructCreate("dword songptrpos")
$_MMTimeUnion=DllStructCreate("dword ms;dword sample;dword cb;dword ticks"&$_MMTime_Struct0&$_MMTime_Struct1, DllStructGetPtr($_MMTimeUnionSize))
$_MMTimeStruct=DllStructCreate("uint wType"&$_MMTimeUnion)
Ahora sí, por lo menos al crear la estructura no hay errores. No se si estará bien hecha así, aunque no de errores.
El problema, biene a la hora de almacenar un dato en algún elemento de $_MMTimeUnion, $_MMTime_Struct0 o $_MMTime_Struct1. No se si es que la estructura está mal escrita (las funciones DllStructSetData() y DllStructGetData() no ponen @Error a 1), pero no va tal como lo hago.

He intentado algo como:

Código: Seleccionar todo

$Result=DllStructGetData($_MMTimeStruct, DllStructGetData($_MMTime_Union, "ms"))
Y al comprobar @Error, vale 2.

Y bueno; para almacenar un dato en algún miembro de la estructura no se me ocurre como hacerlo:

¿Quizá tendría que acceder con DllStructSetData() y DllStructGetData() a $_MMTimeUnion, $_MMTime_Struct1 o $_MMTime_Struct0 directamente?.

Acias,

Salu2!
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Simular uniones C++

Mensaje por Ximorro »

Es un poco lío pero creo que no es así, como te dice Chefito la unión puede que se declare como una estructura EN C, pero los campos que la componen usan el mismo espacio de memoria. Lo que tienes que hacer es crear una estructura que tenga el tamaño máximo de la unión, por ejemplo la unión:

Código: Seleccionar todo

union {
    DWORD palabra; 
    BYTE caracter;
}
debería ser declarada como
DllStructCreate("dword")
pues la unión ocupa sólo una palabra, aunque también tenga un campo de un byte. Ese byte ocupa el mismo espacio de memoria que el dword, así que si lo declaras en AutoIt se le reservará memoria, lo que es incorrecto. Solución: no ponerlo.
La función ya se encargará de manejar los campos palabra y caracter como toca. En realidad la parte fácil es declararla (una vez has calculado el tamaño, ponle un array de tantos bytes como sean y ya está, no te preocupes por los nombres de los campos que no los puedes usar desde la estructura)

La parte más difícil supongo que será luego extraer los datos de la estructura devuelta, si es que es modificada, supongo que habrá que pasar a binario y hacer estracciones, el problema será luego recrear el tipo, como AutoIt no tiene tipos será difícil decirle que tal ristra binaria es un entero sin signo, por ejemplo...
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola

uf, que lío de apis... :).

entonces, debería declarar un elemento, con el tipo de mayor tamaño como habeis dicho y ya está. y crear en él un array, con tantos elementos como miembros tenga la unión (si no he entendido mal).

Entonces, ¿No es necesario pasar el puntero de otra estructura en el segundo parámetro de DllStructCreate() como hacía yo?...

Creo que lo entiendo mejor ahora. El problema, creo, seguirá siendo el mismo. poner esa unión, dentro de una estructura...

¿Como se haría?

Por ejemplo:

Código: Seleccionar todo

$StructGlobal=DllStructCreate("uint wType")
$Union=DllStructCreate("word key[4]")
¿Como pondría $Union dentro de $StructGlobal?. Y ¿Cómo accedería luego a la unión?, porque la estructura que tengo que hacer para usar la api que estaba programando en mi función, es algo así: una estructura, que contiene una unión, que a su vez contiene dos estructuras...

Por cierto... que si uno de los miembros de la unión es una estructura, se supone, que este será el elemento de mayor tamaño, y por tanto la unión debería tener el tamaño de dicha estructura ¿no?.
entonces ¿como se declararía la estructura?.

Imagino, que calculando el tamaño de la estructura con DllStructGetSize(), ¿haciéndo quizá un array con el resultado de DllStructGetSize()? o algo así.

Pero ¿que tipo de datos sería?, ¿byte?...

Salu2!
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola

Bueno, pues ... dándole vueltas y vueltas, solo se me ocurre que la maldita estructura:

Código: Seleccionar todo

typedef struct mmtime_tag {
  UINT wType; 
  union {
    DWORD ms; 
    DWORD sample; 
    DWORD cb; 
    DWORD ticks; 
    struct {
      BYTE hour; 
      BYTE min; 
      BYTE sec; 
      BYTE frame; 
      BYTE fps; 
      BYTE dummy; 
      BYTE pad[2]
    } smpte; 
    struct {
      DWORD songptrpos;
    } midi; 
  } u; 
} MMTIME;
se haga así:

Código: Seleccionar todo

$_MMTimeStruct=DllStructCreate("uint wType;dword[4];byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2];dword songptrpos")
Pero creo que tampoco está bien, pues al cerrar el programa autoit peta ... con eso de los informes de errores.

¿qué os parece?... ¿Lo hice bien?... ¡pa darse un tiro!.

Salu2!
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Simular uniones C++

Mensaje por Chefito »

Haber. Esto último que has puesto ya me gusta más :smt001 .
El otro día le eché un vistazo rápido a la estructura que pusiste y ví que me equivoqué en el post, asique lo he corregido.......por si no os habíais fijado :smt002 . Pensé que la unión englobaba solamente a los 4 primeros parámetros tipo dword. No me fijé bien y me equivoqué :smt021 . Siento esto por si he liado a alguien :smt022 .

Como no se exactamente como se comportan las uniones en estas estructuras se me ocurren varias formas de intentarlo.
La primera sería como tu has puesto, pero separando los 4 parámetros dword por si acaso se lía la cosa. No creo pero yo lo haría así. Los parámetros quedan más claros a la vista.

Código: Seleccionar todo

$_MMTimeStruct=DllStructCreate("uint wType;DWORD ms;DWORD sample;DWORD cb;DWORD ticks;byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2];dword songptrpos")
Esto funcionaría si no es necesarío que el único dato que puede tomar la estructura sea necesariamente en la misma posición de memoría, con un mismo principio. Pero quien sabe :smt017 . Piensa que al crear la estructura del modo que la hemos creado, cada parámetro tiene una posición propia.

Todo lo que voy a exponer a continuación es referente a la parte de la unión:

Si necesariamente va a coger la misma posición de memoría para un dato u otro tendremos que crear una estructura algo liosa pero a medida. Analicemos la estructura. Vemos que el mayor tamaño de memoria lo tiene la subestructura smpte, el cual es de 8 bytes (6 parámetros de 1 byte y 1 de dos, un array de 2 elementos). Sabiendo esto podemos intentar una locura :smt005 , y es crear una estructura con el máximo de elementos que puede poseer una subestructura (8) y el máximo de tamaño que puede tener cada elemento (El primero dword y los 7 restantes bytes). No creo que funcione porque seguramente cuando tenga que leer la subestructura smpte cogerá 8 bytes, y como al principio hay un dword (4 bytes), se va a liar gorda. Para los demás parámetros si funcionaría. Pero por probar no se pierde nada, no sea que coja parámetro por parámetro por alguna casualidad :smt005 .

Código: Seleccionar todo

$_MMTimeStruct=DllStructCreate("uint wType;DWORD generico;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2]")
Bueno, después de ver la chapuza anterior, se nos puede ocurrir la mejor idea :smt003 . Porque no hacemos una función que según el parámetro que le pasemos nos haga una estructura u otra? Pues eso, porque no :smt005 .

Código: Seleccionar todo

Func _MMTimeStruct($ParamDword=1)
              Local $_MMTimeStruct
	If $ParamDword Then
		$_MMTimeStruct=DllStructCreate("uint wType;DWORD ParamDword")
	Else
		$_MMTimeStruct=DllStructCreate("uint wType;byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2]")
	EndIf
              Return $_MMTimeStruct
EndFunc
Ya se que la función es un tanto raquítica, pero solamente es la idea principal. Yo creo que esto si debe funcionar, actue como actue la unión, ya que le decimos que si lo que le vamos a pasar es un parámetro dword que almacene solamente ese parámetro (son todos, incluida la última estructura, menos la estructura smpte). Yo le he puesto que le diga esto si $ParamDword no es 0. La otra posibilidad es que si le queremos pasar los parámetros de la estructura smpte, cree una estructura con sus parámetros. En la función se haría poniendo $ParamDword=0.
Lo malo de esto es que hay que tener en cuenta que siempre que se quiera cambiar de un parámetro dword a la estructura smpte y viceversa se debería destruir la estructura anterior (Ejemplo: $_MMTimeStruct=0) y volver a crearla.

Si esto no funciona, puffffff.....pues no se, tocando las direcciones de memoria directamente? Puffffffffffffffffffffffff.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola
Como no se exactamente como se comportan las uniones en estas estructuras se me ocurren varias formas de intentarlo.
La primera sería como tu has puesto, pero separando los 4 parámetros dword por si acaso se lía la cosa. No creo pero yo lo haría así. Los parámetros quedan más claros a la vista.

Código: Seleccionar todo

$_MMTimeStruct=DllStructCreate("uint wType;DWORD ms;DWORD sample;DWORD cb;DWORD ticks;byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2];dword songptrpos")
Esto funcionaría si no es necesarío que el único dato que puede tomar la estructura sea necesariamente en la misma posición de memoría, con un mismo principio. Pero quien sabe
entonces, en definitiva, no es tan difícil como lo hacía yo. No hay que anidar DllStructCreate() y cosas de esas, jajaja.
Se hace como si fuera una estructura simple...

¿A qué te refieres con "liarse la cosa"?. ¿A la api que use la estructura?.
. Piensa que al crear la estructura del modo que la hemos creado, cada parámetro tiene una posición propia.
Por eso, no entendía que pudiera hacerse así, porque teóricamente no se cumple la teoría de la unión (que todos los miembros residen en la misma posición de memoria) :).

Todo lo que voy a exponer a continuación es referente a la parte de la unión:
[/quote]

¡muy buena explicación!.

Lo que no entiendo es, lo de la función... Si es para una llamada a una función de la api de Windows, se supone que la estructura deberá ser siempre la misma ¿no?... Entonces, debería crearse siempre de la misma forma...

Pero, seguro que tiene su lógica. de Hecho, esta estructura la vi en el foro inglés implementada también así, con una función, aunque algo diferente:

http://www.autoitscript.com/forum/topic ... ntry576074
pero me pasó igual, no entendía como creaban la estructura, ni se qué es el parámetro que le pasan a la función.

Salu2!
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Simular uniones C++

Mensaje por Ximorro »

Vamo a vé.
Por lo que recuerdo de uniones en C: todos los campos de una unión ocupan la misma posición de memoria.
Con DllStructCreate realmente lo que hacemos es reservar memoria para nuestro tipo de datos, si se trata de una unión no hay que poner todos los campos, porque entonces estamos reservando más memoria de la que toca.

Esa estructura está compuesta por un UINT (wtype) y una unión, así que hay que hacer:
DllStructCreate("uint wType; byte union[tamaño_unión_en_bytes]")

La unión tiene 6 campos que usan las mismas posiciones de memoria: 4 dword y dos estructuras.

NO podemos reservar cuatro palabras para ms, sample, cb y ticks ¡porque los cuatro comparten la misma palabra (4 bytes) en memoria !
Para simplificar supongamos que la unión sólo está formada por esos primeros 4 campos, entonces nuestra declaración en AutoIt sería:
DllStructCreate("uint wType; dword ms_Y_sample_Y_cb_Y_ticks")
Le pondría un nombre más corto pero es para especificar que ese dword es el mismo para todos ;-)
Con el sistema de bytes, que aquí no haría falta por ser tan simple:
DllStructCreate("uint wType; byte union[4]")
(en realidad a la DLL le da igual pero a AutoIt no, a la hora de leer/escribir datos desde AutoIT la cosa es muy diferente, de eso hablo al final, y es a lo que me refería en el comentario anterior con "la parte difícil")

Sigamos pues, salto a la última estructura de la unión, por ser más simple, vemos que está compuesta también por un sólo dword, eso quiere decir que esa estructura ocupa exactamente ese mismo espacio de memoria que cualquiera de los primeros 4 campos, con lo que con las declaraciones anteriores también la estamos contemplando.
La estructura central tiene más chicha, pero si contamos vemos que tenemos que reservar 8 bytes (6 campos de un byte más un array de dos bytes). Así que finalmente para reservar la memoria de nuestra unión necesitamos reservar 8bytes, que es el tamaño del campo más grande (esta estructura del medio). Los primeros cuatro bytes de la unión están compartidos con los otros campos.

Conclusión: para crear una estructura que la DLL pueda manejar correctamente debemos darle un campo (la unión) de 8 bytes:
DllStructCreate("uint wType; byte union[8]")

Como decía ésta es la parte "fácil", pues a la DLL le da igual cómo llamemos a esos campos en AutoIt, lo que quiere es que le pases una zona de memoria con el tamaño correcto. Realmente esto funciona igual si hacemos:
DllStructCreate("byte union[12]") (un uint también son 4 bytes)

Claro, el problema gordo está en cómo leer/escribir esos datos DESDE AUTOIT.
Pues para eso se usa el método que ha puesto Chefito, dependiendo de qué datos necesitemos la declararemos de una manera u otra, dando los nombres según nos interese.
¿Cómo se sabe esto? ESTUDIÁNDOSE LA DOCUMENTACIÓN. Hay que entender cómo se maneja esa estructura, sin saber qué significan los campos y cuándo se usan no podemos hacer nada. Mirando esa documentación que Jonny nos enlaza (¡y que espero que él se haya estudiado!) puedo ver por ejemplo:

Si wType es TIME_MS (para AutoIT habrá que buscar el valor numéricos correspondiente), el campo que se usa es ms, que tiene el tiempo en milisegundos, así que declararíamos:
DllStructCreate("uint wType; dword ms; byte[4]")
Como la unión es de 8 bytes pero sólo usamos los 4 primeros para ms, reservamos los otros 4 para que tenga el tamaño correcto de MMTIME, aunque no se use, pues la estructura debe tener ese tamaño.

Por ir a la parte complicada, si wType is TIME_SMPTE entonces se usa la estructura esa cañera, entonces podemos hacer:
DllStructCreate("uint wType; byte hour; byte min; byte sec; byte frame; byte fps; byte dummy; byte pad[2]")
En realidad los últimos 3 bytes son relleno, están ahí porque los datos a rellenar en la estructura son 5 bytes y seguramente para ayudar al hardware han decidido reservar 64bits, así que yo incluso pasaría de darles nombre (dummy significa inútil y pad relleno, así que imagináos):
DllStructCreate("uint wType; byte hour; byte min; byte sec; byte frame; byte fps; byte[3]")

Así si al hacer la llamada desde AutoIt ya sabemos qué vale wType (y de hecho tendremos que asignarlo) pues ya montamos la estructura con los campos significativos para almacenar los datos con sus nombres adecuados y así poder acceder a ellos desde AutoIt.

¿Y si la estructura MMTIME es de escritura y no sabemos que forma va a tener hasta que nos la devuelva la DLL?
Pues tendremos que reservar para wType y genéricamente para la unión:
$mmtime = DllStructCreate("uint wType; byte union[8]")
Cuando acaba la DLL miramos qué vale wType, si por ejemplo vale TIME_SMPTE en la unión nos han pasado la estructura smpte. Yo remapearía la unión a la estructura que nos interesa, no lo he probado pero creo que esto funcionaría, ya me diréis:

Código: Seleccionar todo

$union = DllStructGetData($mmtime, "union") ;$union es un array de 8 bytes
$union_stru = DllStructCreate("byte union[8]") ;estructura temporal para poder crear un puntero a nuestros datos
DllStructSetData($union_stru, "union", $union) ;metemos nuestros datos sacados de $mmtime
;Ahora podemos hacer otra estructura con los datos con forma y nombre como nos interesa, rellenados con los datos de la que acabamos de crear:
$smpte = DllStructCreate("byte hour; byte min; byte sec; byte frame; byte fps; byte[3]", DllStructGetPtr($union_stru))
Quizás se pueda simplificar pero creo que DllStructGetPtr sólo se puede usar con variables creadas con DllStructCreate, si tomara el puntero de datos AutoIT directamente se podría pasar de esa estructura intermedia y hacer smpte con DllStructGetPtr($union), pero no creo que se pueda...

Pues hala, espero no haber metido la gamba, sobre todo esta segunda parte ya digo que es complicada y esta es una solución que se me ocurre que a lo mejor hay que mejorar o incluso reparar porque no la he probado y se me puede haber escapado algo. Sobre la primera parte de crear la estructura sí lo tengo bastante claro...

saludosss
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Simular uniones C++

Mensaje por Ximorro »

Hum, pensándolo un poco más creo que eso último lo he hecho un poco complicado, aunque lo que necesitamos es sólo la unión (wType ya lo hemos leído) podemos usar la estructura $mmtime inicial para no tener que crear subestructuras intermedias:

Código: Seleccionar todo

$mmtime = DllStructCreate("uint wType; byte union[8]")
;Ahora se llama a la DLL, la cual escribe en la estructura
;Leemos wType y resulta que vale TIME_SMPTE así que remapeamos toda la estructura
$nueva_mmtime = DllStructCreate("uint wType; byte hour; byte min; byte sec; byte frame; byte fps; byte[3]", DllStructGetPtr($mmtime))
Creo que para este caso es mucho mejor así, de todas maneras el método anterior (si funciona :smt002 ) será útil para extraer una subestructura de una estructura así que lo dejo por si hace falta.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Simular uniones C++

Mensaje por Chefito »

Aaaaahhhhh colegas! Es que yo no sabía que era una estructura que recibía datos de una función (waveOutGetPosition). Esa información es muy muy importante.
Yo diseñé la última función pensando que a la estructura se le debían asignar los valores, que es muy diferente :smt021 . Entonces así sí sabemos seguro que la función siempre le asignara una única posición de memoría a los datos de la estructura. Con esto vemos que los esperimentos iniciales no vale, ya que los quería probar por si acaso, pero para pasar los datos nosotros a la estructura. Y mira que estuve a punto de preguntarselo a Jonny, que pusiese la función y su definición donde se aplicaba esta estructura.

Ximorro, buen planteamiento, pero no va ha funcionar lo que dices :smt005 . No puedes declarar un vector con 8 elementos tipo byte y dejarlo así. Tienes que remapear la estructura según sea el parámetro wType. Te puede dar problemas en la recuperación de los tipo dword, ya que en este caso tendrías que remapear la estructura, cosa que no haces. Por que te puede dar problemas si no remapeas a dword? Por que no es lo mismo recuperar cuatro posiciones de memoria tipo byte que una tipo dword. No podemos pensar que se pueden recuperar y unir así por las buenas. No confundamos la longitud de los datos en memoría con los tipos de datos que le pasas.
Voy a poner un ejemplo con dos posiciones de memoria consecutivas byte y esa misma posición word (2 bytes). Un tipo byte va de 0 a 255 (256) y un word de 0 a 65535 (65536). Si en esa posición de memoria se almacena el número 45000, en binario se almacenaría como 1010111111001000 (2 bytes). Si recuperamos eso con un tipo word nos lo va a devolver entero, siendo en decimal el número 45000. Si lo recuperamos en dos partes (2 tipos bytes), en uno nos va a devolver 10101111 el cual será 175 y el otro 11001000 que será 200. Si nos lo devolviese en binario se podrían juntar y tener 45000, pero como no es así no funcionaría. Tendríamos que utilizar sistemas de conversión para que nos diese el valor real. En este caso se podría hacer (175*256)+200=45000 para la conversión. Un rollo. Antetodo espero no haberme equivoca. Es un tema que no lo tengo 100% claro y me puedo equivocar :smt016 .

Lo que haría falta antes para crear bien la estructura, es saber el valor de wType. Según este valor se crea una estructura con una variable tipo dword o con 8 variables tipo byte (o un vecto de 8 elementos, da igual). Esto lo hace la función de ProgAndy que nos a puesto Jonny: http://www.autoitscript.com/forum/topic ... ntry576076
Jonny escribió:no entendía como creaban la estructura, ni se qué es el parámetro que le pasan a la función.
EDITADO PORQUE MI PLANTEAMIENTO ANTERIOR ERA UNA BASURA Y VOY A CONFUNDIR A LA GENTE
Espero que esta explicación sea la correcta :smt001 . Vamos otra vez:
Primeramente se debe crear la estructura MMTIME como vamos diciendo en los anteriores post. Después se le debe dar el valor al parámetro wType de la estructura de lo que queremos recuperar (ya se han puesto los valores que puede recibir. Están declarados en la función de ProgAndy). Cuando le damos el valor deseado, le pasamos el puntero de la estructura (DllStructGetPtr($mmtime_que_hemos_creado_al_principio)) que hemos creado a la función de ProgAndy para que pueda analizar el primer valor (wType que es de tipo uint), y según su valor, lo compara con un switch case y crea la estructura adecuada. Esto emula la unión.
Una vez hecho esto, mirando la declaración de la función:
MMRESULT waveOutGetPosition(
HWAVEOUT hwo,
LPMMTIME pmmt,
UINT cbmmt
);
vemos que le tenemos que pasar al parámetro pmmt el puntero de la estructura definitiva que ha creado la función de ProgAndy (DllStructGetPtr($mmtime_que_ha_creado_la_funcion)).
Al final, te devolverá los parámetros de la estructura creada por la función con los datos asignados. Solo tendrás que recuperarlos y sefiní.

Veo que si quieres utilizar la función tienes que crear inicialmente una estructura que luego tienes que desechar. Puedes evitarte este paso generando tú directamente la estructura si sabes el parámetro wType (algo parecido a mi última función del post anterior).
Lo que tu veas.
FIN DE LA EDICION

Se podría acortar poniendo algo como lo que yo puse, que si es de tipo $TIME_SMPTE crease el vector de 8 elementos tipo byte, y si es de cualquier otro tipo crease un tipo dword. Pero la función de ProgAndy ofrece más claridad y te lía menos :smt003 .

Código: Seleccionar todo

Global Const $TIME_BYTES = 0x4
Global Const $TIME_MIDI = 0x10
Global Const $TIME_MS = 0x1
Global Const $TIME_SAMPLES = 0x2
Global Const $TIME_SMPTE = 0x8
Global Const $TIME_TICKS = 0x20

Func _Create_mmtime_tag_Ex($ptr)
    Local $type = DllStructCreate("uint",$ptr)
    If	DllStructGetData($type,1) Then
            Return DllStructCreate("UINT wType; BYTE hour; BYTE min; BYTE sec; BYTE frame; BYTE fps; BYTE dummy; BYTE pad[2]",$ptr)
    Else
            Return DllStructCreate("UINT wType; DWORD general",$ptr)
    EndIf
    Return SetError(1,0,0)
EndFunc
Pero al final tendrías que mirar el valor de wType para saber a que pertenece el dato dword. Asíque creo que no merece la pena.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola

Puf...
Aaaaahhhhh colegas! Es que yo no sabía que era una estructura que recibía datos de una función (waveOutGetPosition). Esa información es muy muy importante.
UUuuuups... ¡sorry!, que no lo dije.... :).

Exacto, esta estructura es para WaveOutGetPosition(), que parece que consulta y almacena datos en ella (que rebuscados los de Microsoft) :P.
Lo que haría falta antes para crear bien la estructura, es saber el valor de wType. Según este valor se crea una estructura con una variable tipo dword o con 8 variables tipo byte (o un vecto de 8 elementos, da igual). Esto lo hace la función de ProgAndy que nos a puesto Jonny:
mm... wType puede ser uno de los siguientes valores, según la documentación de la estructura:

Código: Seleccionar todo

Global Const $_Time_Bytes=4
Global Const $_Time_Midi=16
Global Const $_Time_Ms=1
Global Const $_Time_Samples=2
Global Const $_Time_Smpte=8
Global Const $_Time_Ticks=32
que por cierto: ¿Son los mismos que pone ProgAndy en su función?

Salu2!
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Simular uniones C++

Mensaje por Chefito »

Primeramente perdón, perdón, perdón. En este post la estoy cagando pero bien :smt021 . He editado mi post anterior porque ponía cosas erroneas, mal explicadas, y a causa de esto podía confundiar a la gente.

Con tu permiso Jonny, también he editado tu post anterior (mejor dicho, borrado) refiriendose a cosas de mi antigua explicación. He visto que te he confundido por mis errores cuando tu ibas por el buen camino :smt012 . Lo siento.
Te pido que lo vuelvas a leer, y si quieres algún ejemplo dimelo y te intentaré poner uno.
Jonny escribió:mm... wType puede ser uno de los siguientes valores, según la documentación de la estructura:


Código: Seleccionar todo
Global Const $_Time_Bytes=4
Global Const $_Time_Midi=16
Global Const $_Time_Ms=1
Global Const $_Time_Samples=2
Global Const $_Time_Smpte=8
Global Const $_Time_Ticks=32


que por cierto: ¿Son los mismos que pone ProgAndy en su función?
Supongo. Estas constantes son siempre iguales.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola
Primeramente perdón, perdón, perdón. En este post la estoy cagando pero bien
Tranqui, no pasa nada. Esto tiene miga aunque no lo parece :).
. He editado mi post anterior porque ponía cosas erroneas, mal explicadas, y a causa de esto podía confundiar a la gente.
Ya lo he leído y ahora sí, me cuadra todo más :P.
Te pido que lo vuelvas a leer, y si quieres algún ejemplo dimelo y te intentaré poner uno.
Como tengo la función teóricamente lista, modificaré la parte de la estructura, tal como explicas en el post que has editado y la pongo a ver si está bien.
Si no, sí, irá bien un ejemplillo :P.
Veo que si quieres utilizar la función tienes que crear inicialmente una estructura que luego tienes que desechar. Puedes evitarte este paso generando tú directamente la estructura si sabes el parámetro wType (algo parecido a mi última función del post anterior).
Lo que tu veas.
Esto no lo entiendo bien. Estoy implementando las apis estas en forma de librería, por lo que en el caso de esta función, el usuario debería especificar el valor de wType, ya que es el formato de tiempo en el que desea recibir la posición de la reproducción de sonido. Osea, que este valor en principio lo conozco:

-Recibo el formato de tiempo en que el usuario quiere recibir la posición.
-Lo almaceno en el elemento wType de la estructura.
...
y en principio, la api se encargará de leer ese valor y actuar en consecuencia.

Cuando modifique la función y la cuelgue, a ver si lo planteé bien...

Salu2!
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Simular uniones C++

Mensaje por Chefito »

Jonny escribió:Estoy implementando las apis estas en forma de librería, por lo que en el caso de esta función, el usuario debería especificar el valor de wType, ya que es el formato de tiempo en el que desea recibir la posición de la reproducción de sonido. Osea, que este valor en principio lo conozco:

-Recibo el formato de tiempo en que el usuario quiere recibir la posición.
-Lo almaceno en el elemento wType de la estructura.
...
y en principio, la api se encargará de leer ese valor y actuar en consecuencia.

Cuando modifique la función y la cuelgue, a ver si lo planteé bien...
Exactamente :smt023 .
Chefito escribió:Veo que si quieres utilizar la función tienes que crear inicialmente una estructura que luego tienes que desechar. Puedes evitarte este paso generando tú directamente la estructura si sabes el parámetro wType (algo parecido a mi última función del post anterior).
Lo que tu veas.
Otra cagada de las mías por no pararme a pensar en el código :smt021 . No hay que destruir la primera estructura que creas, ya que la función trabaja con ésta a través de punteros que apuntan a esta estructura. Esto hace que puedas variarla con la función siempre que quieras sin destruir nada. Olvida lo de destruirla :smt009 .

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Simular uniones C++

Mensaje por Ximorro »

¿Quién ha dicho que yo no remapeo la estructura y no tengo en cuenta los cambios de tipos de datos? de hecho incluso he utilizado esas palabras en los comentarios... vaya no están numerados, bueno, en mis dos últimos ;-)

Por ejemplo en el código que remapea:

Código: Seleccionar todo

$mmtime = DllStructCreate("uint wType; byte union[8]")
   ;Ahora se llama a la DLL, la cual escribe en la estructura
   ;[b]Leemos wType y resulta que vale TIME_SMPTE así que remapeamos toda la estructura:[/b]
$nueva_mmtime = DllStructCreate("uint wType; byte hour; byte min; byte sec; byte frame; byte fps; byte[3]", DllStructGetPtr($mmtime))
Claro que tengo en cuenta los cambios de datos, precisamente por eso decía que no era importante para la DLL porque la podíamos llamar con la estructura incorrecta mientras tenga el tamaño correcto, la DLL la rellenará bien... ¡pero que la estructura correcta era importantísima para poder leer/escribir en AutoIt! Por eso he hecho lo del remapeo...

OJO con la función de ProgAndy, sé que este tío es un gurú del AutoIt y hace muchísimo tiempo que se ganó todo mi respeto, pero en este caso creo que hay un pequeño fallo, y es que no crea la estructura con todo el tamaño correcto, si haces:
Return DllStructCreate("UINT wType; DWORD ms",$ptr)
Te falta reservar 4 bytes. Ciertamente si la función está bien escrita no intentará acceder a ese espacio de memoria, pero si quisiera (por ejemplo un soft malintencionado) podría hacerlo pues la estructura que debe ser pasada ha de ser de tipo MMTIME, ¡y eso tiene 4 bytes más que la creada en AutoIt!
Es como el típico fallo de seguridad de acceso a índices fuera de matriz... pero con campos fuera de estructura.

Ahí hay que añadir un campo byte[4], así si la función intenta escribir ahí al menos lo hará en unos bytes "vacíos" que le hemos reservado nosotros, y no fuera de nuestra estructura.

Y mira, después de todo mi código es precisamente la idea de ProgAndy de recrear la estructura, sólo que yo no desarrollé todas las posibilidades, sólo indiqué cómo hacerlo (hice el caso más complicado).

Y lo de escribir primero en wType sin saber lo que va después no lo hice muy explícito pero sabiéndolo de antemano ya creas la estructura que necesitas y se la pasas a la DLL, no hay que remapear nada.
La segunda parte que puse con el remapeo es por si no sabemos de qué tipo son los datos, pero si se sabe el valor de wType desde el principio es más fácil, simplemente se crea la estructura según nos interesa y ya está (pero rellenando para que la estructura de AutoIt ocupe lo mismo que la declarada en C, como decía en los párrafos anteriores)
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Jonny
Profesional del Autoit
Mensajes: 1042
Registrado: 30 Jun 2008, 20:08

Re: Simular uniones C++

Mensaje por Jonny »

Hola

Bueno, ya he modificado la función.

Adelanto, que tal como yo la hice (sin usar la función de ProgAndy), solo creando la estructura:

Código: Seleccionar todo

$_MMTimeStruct=DllStructCreate("uint wType;dword[4];byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2];dword songptrpos")
parecía funcionar la api, por lo menos devolvía 0...

Ahora con la modificación que le he hecho para crear la estructura con la función de ProgAndy, devuelve 1 (en la documentación no especifican ese valor en los valores de retorno).

De todas formas, ahí va, para que veais lo que he hecho, a ver si os parece que está bien así....

Código: Seleccionar todo

  ;Constantes relativas a errores:
  Global Const $_Err_Dll=-1
  Global Const $_MMSysErr_Base=0
  Global Const $_WavErr_Base=32
  Global Const $_MMSysErr_NoError=0
  Global Const $_MMSysErr_InValHandle=($_MMSysErr_Base+5)
  Global Const $_MMSysErr_NoDriver=($_MMSysErr_Base+6)
  Global Const $_MMSysErr_NoMem=($_MMSysErr_Base+7)
  Global Const $_WavErr_StillPlaying=($_WavErr_Base+1)
  Global Const $_MMSysErr_BadDeviceID=($_MMSysErr_Base+2)
  Global Const $_MMSysErr_NotSupported=($_MMSysErr_Base+8)
  Global Const $_WavErr_BadFormat=($_WavErr_Base+0)
  Global Const $_WavErr_Sync=($_WavErr_Base+3)
  Global Const $_MaxErrorLength=256
  ;Fin de constantes relativas a errores.

  ;Constantes relativas a posición de reproducción del dispositivo de salida de audio:
  Global Const $_Time_Bytes=4
  Global Const $_Time_Midi=16
  Global Const $_Time_Ms=1
  Global Const $_Time_Samples=2
  Global Const $_Time_Smpte=8
  Global Const $_Time_Ticks=32
  ;Fin de constantes relativas a posición de reproducción del dispositivo de salida de audio.

Func WaveOutGetPosition($HandDevice, $ArgTimeFormat=$_Time_Ms)
 #CS

  ----------

  Descripción: Devuelve la posición de la reproducción del dispositivo de salida de audio indicado.
  Argumentos:
   -$HandDevice:
    Handle del dispositivo de salida de audio del que se desea obtener la posición de reproducción.
   -$ArgTimeFormat: Formato de tiempo en el que se desea obtener la posición de reproducción del dispositivo de salida de audio:
     -$_Time_Bytes: Compensación del byte actual desde el principio del archivo.
     -$_Time_Midi: Tiempo midi.
     -$_Time_Ms: Tiempo en milisegundos.
     -$_Time_Samples: Número de samples reproducidos.
     -$_Time_Ticks: Ticks en una secuencia de midis.
  Valor(es) de retorno:
   -$_Err_Dll: Ocurrió un error al consultar la posición de la reproducción del dispositivo de salida de audio indicado.
   -$_MMSysErr_NoError: No se está reproduciendo sonido en el dispositivo de salida de audio indicado.
   -$_MMSysErr_InValHandle: El handle del dispositivo de salida de audio indicado es incorrecto.
   -$_MMSysErr_NoDriver: No hay dispositivos de salida de audio en el equipo.
   -$_MMSysErr_NoMem: Imposible asignar memoria.
   -<>$_Err_Dll/$_MMSysErr_NoError/$_MMSysErr_InValHandle/$_MMSysErr_NoDriver/$_MMSysErr_NoMem: Array con datos de la posición de la reproducción del dispositivo de salida de audio indicado:
    -[0]: Formato de tiempo en el que se devuelve la posición de reproducción.
    Nota: Si el formato de tiempo indicado no está soportado por el dispositivo de salida de audio, la función establecerá un formato de tiempo alternativo.
    -[1]: Posición de reproducción del dispositivo de salida de audio expresada en el formato indicado, o el establecido alternativamente por la función.

  ----------

 #CE
  Local $CallFunc, $_MMTimeStruct
  Local $SetTimeFormat, $_Ret[2]
  Local $_MMTimeStructPtr, $Get_MMTimeStruct
   If (($HandDevice=="" Or $ArgTimeFormat=="") _
    Or ($ArgTimeFormat<>$_Time_Bytes And $ArgTimeFormat<>$_Time_Midi And $ArgTimeFormat<>$_Time_Ms And $ArgTimeFormat<>$_Time_Samples And $ArgTimeFormat<>$_Time_Smpte And $ArgTimeFormat<>$_Time_Ticks)) Then Return $_Err_Dll
   $_MMTimeStruct=DllStructCreate("uint wType;byte[8]")
   $SetTimeFormat=DllStructSetData($_MMTimeStruct, "wType", $ArgTimeFormat)
   If ($_MMTimeStruct==0 Or ($SetTimeFormat==0 And @Error<>0)) Then Return $_Err_Dll
   $_MMTimeStructPtr=DllStructGetPtr($_MMTimeStruct)
   If ($_MMTimeStructPtr==0 And @Error<>0) Then Return $_Err_Dll
   $Get_MMTimeStruct=_AddMMTimeStruct($_MMTimeStruct, $_MMTimeStructPtr)
   If $Get_MMTimeStruct==0 Then Return $_Err_Dll
   $CallFunc=DllCall($WinmmDLL, "int", "waveOutGetPosition", "hwnd", $HandDevice, "ptr", DllStructGetPtr($Get_MMTimeStruct), "uint", DllStructGetSize($Get_MMTimeStruct))
   If @Error<>0 Then Return $_Err_Dll
   If $CallFunc[0]<>0 Then
    Return $CallFunc[0]
     Else
      $_Ret[0]=DllStructGetData($Get_MMTimeStruct, 1)
      Switch($ArgTimeFormat)
       Case $_Time_Bytes
        $_Ret[1]=DllStructGetData($Get_MMTimeStruct, 2, 3)
       Case $_Time_Midi
        $_Ret[1]=DllStructGetData($Get_MMTimeStruct, 10)
       Case $_Time_Ms
        $_Ret[1]=DllStructGetData($Get_MMTimeStruct, 2, 1)
       Case $_Time_Samples
        $_Ret[1]=DllStructGetData($Get_MMTimeStruct, 2, 2)
       Case $_Time_Ticks
        $_Ret[1]=DllStructGetData($Get_MMTimeStruct, 2, 4)
      EndSwitch
      Return $_Ret
   EndIf
EndFunc

Func _AddMMTimeStruct($StructPtr)
 #CS

  ----------

  Descripción: Crea la estructura adecuada para WaveOutGetPosition(), según el formato de tiempo especificado en esta.
  Argumentos:
   -$StructPtr:
    Puntero de la estructura MMTime.
  Valor(es) de retorno:
   -$_Err_Dll: Ocurrió un error al crear la estructura.
   -<>$_Err_Dll: Estructura para ser usada en WaveOutGetPosition().
  Autor:
   -Original: ProgAndy.
   -Modificación: Jonny.
  Link:
   -http://www.autoitscript.com/forum/topic/79986-reading-a-wav-file-and-playing-the-raw-pcm-audio-data/page__p__576076#entry576076

  ----------

 #CE
  Local $_Struct = DllStructCreate("uint", $StructPtr)
  Switch(DllStructGetData($_Struct, 1))
   Case $_Time_Ms
    Return DllStructCreate("uint wType;dword ms", $StructPtr)
   Case $_Time_Samples
    Return DllStructCreate("uint wType;dword sample", $StructPtr)
   Case $_Time_Bytes
    Return DllStructCreate("uint wType;dword cb", $StructPtr)
   Case $_Time_Ticks
    Return DllStructCreate("uint wType;dword ticks", $StructPtr)
   Case $_Time_Smpte
    Return DllStructCreate("uint wType;byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2]", $StructPtr)
   Case $_Time_Midi
    Return DllStructCreate("uint wType;dword midi", $StructPtr)
  EndSwitch
  Return $_Err_Dll
EndFunc
En la función de ProgAndy, he modificado algunas cosas. Por ejemplo:

Código: Seleccionar todo

Local $type = DllStructCreate("uint",$ptr)
Lo he quitado, porque no veo que haga nada en la función (no se por qué estará).

Además, le he puesto un control de errores para la recepción de los argumentos y, como la función en mi caso es para usarla en una UDF, la he adaptado a la forma en qué estoy haciendo esta.
Así pues, le he añadido un argumento, para recibir la estructura MMTime (creada con la función WaveOutGetPosition()) inicialmente. El otro argumento, que ya lo tenía la función, recibe el puntero de esa estructura.

sí, podría haber declarado una variable global y crear ahí la estructura... pero me dió por hacerla en la misma función. Además, no tenía pensado crear así la estructura :P.

Editado, porque ya creo entender como funciona, ahora que me lo ha dicho Chefito.

Por otro lado, los valores de las constantes del formato de tiempo que mencionan en la documentación de la estructura, y que tanto yo como ProgAndy hemos implementado, las he sacado de un archivo de cabecera que parece que utiliza la dll. He estado mirando los valores que he declarado yo en las constantes y los que ha declarado ProgAndy, y coinciden todos menos:

Código: Seleccionar todo

Global Const $_Time_Midi
donde yo pongo "16", y ProgAndy "0x10".

Código: Seleccionar todo

Global Const $_Time_Ticks
donde yo pongo "32", y ProgAndy "0x20".

¿Son valores diferentes ¿no?...

No dije nada, ¡lapsus!.

No se si pudiera ser esto lo que hace que la api devuelva 1 (aunque no lo creo), pero entonces no entiendo el porqué.

Salu2!
Última edición por Jonny el 16 Ene 2011, 01:45, editado 1 vez en total.
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Simular uniones C++

Mensaje por Chefito »

Dios!!!!!!!!!!! Por segunda vez tengo que escribir toda la respuesta entera. Si es que no aprendo. Mierda de ie :smt005 . He dejado demasiado tiempo abierta la respuesta, y cuando me he puesto a continuar escribiendo (un buen tocho) y a mandarlo, resulta que me había desreristrado!!!! Y he perdido la respuesta.
Joder, por que no lo hago directamente con Opera??? Porque soy tonto :smt005 . Opera si recupera lo escrito si le das a la página anterior.
Bueno, después de haberme desahogado un poco, vamos otra vez:
Ximorro escribió:¿Quién ha dicho que yo no remapeo la estructura y no tengo en cuenta los cambios de tipos de datos? de hecho incluso he utilizado esas palabras en los comentarios... vaya no están numerados, bueno, en mis dos últimos Por ejemplo en el código que remapea:Código: Seleccionar todo$mmtime = DllStructCreate("uint wType; byte union[8]")   ;Ahora se llama a la DLL, la cual escribe en la estructura   ;Leemos wType y resulta que vale TIME_SMPTE así que remapeamos toda la estructura:$nueva_mmtime = DllStructCreate("uint wType; byte hour; byte min; byte sec; byte frame; byte fps; byte[3]", DllStructGetPtr($mmtime))Claro que tengo en cuenta los cambios de datos, precisamente por eso decía que no era importante para la DLL porque la podíamos llamar con la estructura incorrecta mientras tenga el tamaño correcto, la DLL la rellenará bien... ¡pero que la estructura correcta era importantísima para poder leer/escribir en AutoIt! Por eso he hecho lo del remapeo...
Ya se que habías puesto todo eso, pero pensé que el ejemplo que pusiste no era adecuado o estaba incompleto. Has redefinido la estructura inicial DllStructCreate("uint wType; byte union[8]") a DllStructCreate("uint wType; byte hour; byte min; byte sec; byte frame; byte fps; byte[3]", DllStructGetPtr($mmtime)) cuando el argumento wType es igual a TIME_SMPTE. Pienso que ese ejemplo, aunque hay que hacerlo, es el menos importante, ya que incluso si no la reestructuras puedes recuperar los datos directamente por su índice al haberla definido con un vector de 8 bytes :smt002 . Digamos que deberías haber puesto como ejemplo el otro caso, o haber completado la explicación poniendo el otro caso también, que sería que cuando wType es distinto de TIME_SMPT, hay que reestructurar (redefinir, remapear, etc) la estructura inicial poniendo un segundo parámetro tipo dword, DllStructCreate("uint wType;dword general", DllStructGetPtr($mmtime)). Así quedaba la cosa más clara.
Por eso puse todo ese rollo, para dejar la cosa clara. Tampoco podía saber yo si se te había pasado el ponerlo, si te habías confundido (conociendote suponía que no :smt002 ), o si era un pequeño ejemplo de como se podía realizar la estructura, mostrando solamente uno de los casos (creo que era esto por lo que pones más abajo en tu post anterior). Pero hay que reconocer que si llegas a añadir eso la cosa hubiese quedado más clara :smt002 .
Ximorro escribió:OJO con la función de ProgAndy, sé que este tío es un gurú del AutoIt y hace muchísimo tiempo que se ganó todo mi respeto, pero en este caso creo que hay un pequeño fallo, y es que no crea la estructura con todo el tamaño correcto, si haces:Return DllStructCreate("UINT wType; DWORD ms",$ptr)Te falta reservar 4 bytes. Ciertamente si la función está bien escrita no intentará acceder a ese espacio de memoria, pero si quisiera (por ejemplo un soft malintencionado) podría hacerlo pues la estructura que debe ser pasada ha de ser de tipo MMTIME, ¡y eso tiene 4 bytes más que la creada en AutoIt!Es como el típico fallo de seguridad de acceso a índices fuera de matriz... pero con campos fuera de estructura.
Pienso igual que tú, ProgAndy es la ostia, entre varios más del foro de habla inglesa. Pero claro, esos tíos saben mucho más que nosotros AutoIt. También saben c y c++ y que se yo que lenguajes más. Además, muchos de ellos han contribuido (y siguen haciendolo) a la creación/actualización de AutoIt. Como para saber más que ellos!!!!! :smt005 . Pero también digo una cosa, hasta el más sabio se puede equivocar :smt005 .
Sobre lo otro que comentas, pienso que la función esta perfectamente definida. No tiene porque dar ningún tipo de problemas. No creo que tenga importancia que defina o no esos 4 bytes que pueden quedar libres, ya que en ningún momento se van a utilizar.
Sobre lo de los virus, pienso que tampoco tendríamos que ser tan paranoicos :smt003 . Tendría que ser un virus muy específico no? :smt002 . Ademas, veo peor que se meta en los bytes que utiliza la función poniendo valores distintos para cambiar el resultado o petar el programa, que escriba sobre unos bytes vacios que no se van a utilizar :smt002 . Encima esos bytes van a ser escritos por la función que utilize la estructura. Machacarían lo que escribiese cualquier programa malicioso. En resumen, no podemos pensar en esas cosas tan rebuscadas, porque entonces no programaríamos nada :smt005 .
Ximorro escribió:La segunda parte que puse con el remapeo es por si no sabemos de qué tipo son los datos, pero si se sabe el valor de wType desde el principio es más fácil, simplemente se crea la estructura según nos interesa y ya está (pero rellenando para que la estructura de AutoIt ocupe lo mismo que la declarada en C, como decía en los párrafos anteriores)
Estoy deacuerdo contigo. Pero si lo que se pretende es hacer una udf con estas funciones, estructuras y demás, se debe utilizar una función para que el usuario la defina cuando quiera de la forma más facil posible......pienso yo.

Ahora contesto al post de Jonny:
Te mato!!!!! Te mato!!!! Te maaaaaaaaaaaaaaaatooooooooooooooo!!!!
Jonny, tu has leído los post que te hemos escrito Ximorro y yo sobre el tamaño de la estructura y demás????
Pero que clase de definición inicial de la estructura es esta:
Jonny escribió:$_MMTimeStruct=DllStructCreate("uint wType;dword[4];byte hour;byte min;byte sec;byte frame;byte fps;byte dummy;byte pad[2];dword songptrpos")
Te lo digo yo, una caca :smt005 .
Lo hemos repetido hasta la saciedad.....inicialmente define el segundo parámetro de un tamaño máximo de 8 bytes!!!!! Defínelo como quieras, con 8 bytes, con 2 dword, con 4 word, con lo que quieras que formen 8 bytes, pero que el 2º parámetro reserve 8 bytes!!!!! Para que más. Para desperdiciar memoria y definir fatal la estructura? Aunque luego te funcione porque con la función redefine luego bien los parámetros, y utilizará solamente esos bytes, no es escusa de hacerlo mal.
De la forma que la has definido, utilizas 24 bytes de más, que no los necesitas para nada!!!!!.
Anda y cambialo.
Jonny escribió:parecía funcionar la api, por lo menos devolvía 0...
Pues te aseguro que no funcionaría. Funcionaría pero mal. Los datos dword si los alamacenaría bien en el primer elemento, pero si wType era TIME_SMPT, no podrías recuperar los datos bien porque no la tenías bien definada (tienes que cambiar el dword por los 8 elementos tipo byte).
Jonny escribió:Ahora con la modificación que le he hecho para crear la estructura con la función de ProgAndy, devuelve 1 (en la documentación no especifican ese valor en los valores de retorno).
Mejor no la toque que está bien definida. Es ahora la tuya la que está mal definida con argumentos innecesarios :smt012 .
Jonny escribió:En la función de ProgAndy, he modificado algunas cosas. Por ejemplo:Código: Seleccionar todoLocal $type = DllStructCreate("uint",$ptr)Lo he quitado, porque no veo que haga nada en la función (no se por qué estará).
Para matarte :smt005 . Como quitas eso? Con eso accede al primer argumento de la estructura (wType, lo que pasa que no pone el nombre del parámetro, solo pone su tipo uint) para luego poder recuperar su valor y compararlo con el switch case.
Tu te lo has cargado y has tenido que meter un argumento de más a la función para acceder a la estructura original directamente (sin puntero) y poder recuperar wType. No hagas eso!!!! :smt005 . Y si no sabes pregunta que es gratis.
Jonny escribió:Global Const $_Time_Mididonde yo pongo "16", y ProgAndy "0x10".Código: Seleccionar todoGlobal Const $_Time_Ticksdonde yo pongo "32", y ProgAndy "0x20".
Jonny, cuando te digo a veces que te falta base para hacer estas cosas, me sueltas cosas de estas y veo que no me equivoco :smt005 . Hombre, esos valores, los de PorgAndy y los tuyos, son totalmente iguales. Lo que pasa que tu los representas en decimal (del 0 al 9) y él de hexadecimal (del 0 al F (F=15)). Mira en google la representación de números en hexadecimal, que para un programador es esencial.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Responder