Sobre Byref

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

Sobre Byref

Mensaje por Jonny »

A ver si sabéis explicarme esta keyword, para que termine de entenderla en AutoIt, porque la ayuda habla de ella muy de pasada.

Parece, que Byref es para pasar un parámetro por referencia, a una función.

Entonces, teniendo en cuenta que "pasar parámetros por referencia" es ni más ni menos que pasar la dirección de memoria de una variable, supongo que eso será exactamente lo que se haga con Byref ¿no? (aunque en AutoIt no se pueda manipular esa dirección de memoria como en C).

Pero, la duda es, si puede sacarse de la función que la recibe, esa dirección de memoria.
Por ejemplo:

Si hago esto:

Código: Seleccionar todo

Global $MyVar=1234

RecibeNumero($MyVar)

Func RecibeNumero(Byref $Arg)
Return $Arg
EndFunc
¿"RecibeNumero()" qué devuelve, el contenido de "$MyVar" o la dirección de memoria?. Ya se, que para AutoIt devuelve "1234", que es lo que hay en $MyVar, que al fin y al cabo es lo mismo que hay en esa dirección de memoria, pero me refiero internamente...
O, por ejemplo: en el ejemplo anterior, "RecibeNumero()" ¿Podría pasar "$Arg" a una dll, por ejemplo, para que esta accediera a "$MyVar"?.
Vaya, me refiero a que si pasara "$Arg" a una dll ¿le estaría pasando realmente la dirección de memoria?.

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

Re: Sobre Byref

Mensaje por Ximorro »

Olvídate de los punteros, cuando una variable se pasa por referencia efectivamente lo que se hace es indicar dónde está esa variable para que la función la pueda modificar. Efectivamente se pasa el puntero (la referencia) pero eso es para uso interno de la función, para que la pueda referenciar, de ahí el nombre.
La alternativa es pasar el parámetro por valor (por defecto, cuando no se pone ByRef), enconces la función no puede modificar la variable original.

Y esa es la diferencia: que se pueda modificar la variable original o no. No es que tengas acceso a la posición de memoria de la variable, aunque internamente la función debe tenerla.

Por ejemplo:

Código: Seleccionar todo

Global $var = 3
MsgBox(0, "Info", $var)
_Incrementa($var)
MsgBox(0, "Info", $var)

Func _Incrementa(ByRef $variable)
	$variable += 1
EndFunc
En este caso mira que la variable $var ha sido modificada en el programa principal. Si no se pone ByRef no se modifica, pues se pasaría una copia del valor de la variable, no la variable en sí.
Fíjate también que la función no devuelve nada. Podría devolver algo o no, eso es independiente del tratamiento por valor o referencia de los parámetros.
De hecho si devolviera Return $variable ¡estaría devolviendo una copia del valor! El valor de retorno de la función es independiente de los parámetros, aunque los estés usando para calcular ese valor de retorno.

Por supuesto cuando se pasa un parámetro por referencia, éste ha de ser necesariamente una variable, las constantes o expresiones sólo se pueden pasar por valor. Si en mi función hago _Incrementa(1) o _Incrementa(3+4) dará error.

Por lo tanto la utilidad de ByRef es: poder modificar las variables que se pasan como parámetros a la función.
Parece raro pero a veces se usa, por ejemplo para devolver múltiples valores (algunas funciones de fecha/hora lo hacen, por ejemplo mirad _TicksToTime)

NO es un mecanismo para acceder a la dirección de la variable. Para eso quizás podrías meter la variables en una DLLSctruct y pasar el puntero de esa estructura con DllStructGetPtr, no estarías pasando la dirección de la variable original pero estarías construyendo una nueva de la que sí estarías pasando la dirección.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
jamaro
Hacker del Foro
Mensajes: 253
Registrado: 03 Nov 2010, 23:04

Re: Sobre Byref

Mensaje por jamaro »

Quizás no sea continuación de este hilo (si es necesario empiezo otro) pero, aunque en varios de mis códigos utilizo DllStructCreate en la Función My_WM_Notify_Events($hWnd, $MsgID, $wParam, $lParam), realmente desconozco su utilidad.

¿No hay otra manera de leer los datos si no es creando una estructura y tomando los datos después de ella? ¿no se puede trabajar con variables?

Utilizo esa función arrastrándola de "copia-pega" de funciones anteriores, pero realmente no sé cómo se utiliza, cuándo y por qué.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Sobre Byref

Mensaje por Ximorro »

No sé cómo usas DllStructCreate en una función de gestión de mensaje, supongo que es para desempaquetar las dos palabras de wparam.
En principio, como su nombre indica, DllStructCreate es para crear una estructura de tipo de datos Struct de C para pasar a una DLL. Una estructura es un conjunto ordenado de varias variables (campos) que pueden ser de diferente tipo (puedes tener un número entero sin signo, un real y un carácter, por ejemplo). Los tipos son los de C, que son mucho más cercanos a la máquina que en AutoIt, por eso son más específicos.

Aunque está pensado para pasar parámetros a DLL que usan estructuras, se pueden hacer algunos trucos con ellos. Por ejemplo en una función de mensaje como la que pones wparam suele ser dos palabras de 16 bits empaquetadas en el mismo entero de 32 bits. Por ejemplo en el mensaje WM_COMMAND la primera palabra (posición alta) suele ser el código del submensaje, y la segunda (la baja) el identificador del control.

Para extraerlos sí hay otra manera, de hecho yo lo hago de otra manera: con operaciones booleanas. Por ejemplo para extraer la parte baja ponemos a cero los 16bits altos y así nos quedamos con los bajos:
$iIDFrom = BitAND($wParam, 0x0000FFFF)
(yo pongo 0xFFFF pero con los ceros se ve más claro dónde hace ceros el AND binario)
Para tomar la parte alta se hace por ejemplo un desplazamiento de 16 bits (en los desplazamientos se pierden los bits, a diferencia de las rotaciones, con lo que nos deshacemos de la palabra baja y ponemos la alta en su lugar:
$iCode = BitShift($wParam, 16)

Otra forma de hacer eso es usando una DLLStruct, yo creo que es más sencillo lo anterior, pero supongo que lo que tienes es una estructura de dos enteros de 16 bits (¿de qué tipo son? ¿short?), al rellenar esa estructura con el entero de 32 bits (wparam) puedes tomar cada una de sus partes con un DllStructGetData. Realmente ese número de 32 bits no es un número directamente, sino que es la unión de dos números de 16 bits, con la estructura se especifica esa, eeeh, estructura, valga la redundancia ;-), y luego se extraen los campos individuales con el GetData

Espero no haber liado más la cosa...
(Si vamos a seguir discutiendo casi pasamos esto a otro hilo antes de que Jonny nos riña).
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Responder