Mostrando entradas con la etiqueta Microsoft. Mostrar todas las entradas
Mostrando entradas con la etiqueta Microsoft. Mostrar todas las entradas

miércoles, 25 de febrero de 2009

Paso de objetos como argumentos a funciones variadic en Visual Studio 2005

Advertencia: éste es un artículo técnico, escrito por y dirigido a expertos en C++. No intenten esto en casa.
Supongamos que tengo una clase CL, con sus correspondientes métodos imprescindibles (constructor, constructor de copia, operador de asignación, destructor), 32 bytes de datos y un método Print, y sean a, b y c instancias de CL. Supongamos también que tengo una función variadic que recibe una cantidad arbitraria de objetos de la clase CL y ejecuta su método Print.
En código:

void Funcion(int iN,...)
{

if(iN)
{
CL a;
va_list argumentos;

va_start(argumentos,iN);

while(iN--)
{
a = va_arg(argumentos,CL);
a.Print();
}
va_end(argumentos);
}

}

(Sé que esto es algo que no debería hacerse jamás; es una de esas cosas que C++ permite, pero cuyo resultado no está definido. Dicho eso, sigamos adelante).

El código anterior NO funciona en la implementación de C++ que se incluye en Visual Studio 2005, ya que el compilador hace trampa: siempre pasa los objetos como punteros, no importa cómo los declare uno. Vale decir, si uno declara:
foo(CL a);
lo que el compilador realmente pasa a la función es un puntero a un objeto creado al hacer la llamada, no un objeto en sí mismo. Eso tiene sentido, ya que al pasar un puntero sólo tiene que poner 4 bytes en el stack, en lugar de los N = sizeof(CL) que tendría que pasar si pusiera el objeto completo en el stack. Sin embargo, el hecho de que realmente pase un puntero en el stack hace que las funciones variadic recorran incorrectamente el stack y salten al hiperespacio.
Así, pues, si llamamos a Función así:

Funcion(3,a,b,c);

al hacer va_arg el puntero en el stack avanzará al menos 32 bytes (32 == sizeof (CL)), siendo que en el stack sólo hay 16 (tres punteros + un int), y saltará a un agujero negro. Mala cosa.

La manera de resolver el problema es, por lo tanto, recibir siempre los objetos como punteros en las funciones variadic. Nuestra función quedaría:

void Funcion(int iN,...)
{

if(iN)
{
CL *a;
va_list argumentos;

va_start(argumentos,iN);

while(iN--)
{
a = va_arg(argumentos,CL *);
a->Print();
}
va_end(argumentos);
}

}

y asunto resuelto.
Por supuesto, si uno va a hacer una cosa así, resulta más sensato pasar los punteros directamente a la función:

Funcion(3,&a,&b,&c);

aunque, como la función es variadic, el compilador no tiene manera de chequear la consistencia de los argumentos. Sin embargo, la función , tal como la definimos, tiene la curiosa propiedad de que funciona exactamente igual si es llamada con punteros o con objetos (o incluso con referencias); es decir, tanto

Funcion(3,a,&b,c);

como

Funcion(3,a,b,c);

tendrán el mismo resultado.

miércoles, 26 de noviembre de 2008

Adjuntos en Windows Mobile 6

Sí, es un artículo técnico.
Desde que comencé a programar para Windows CE, el 2001, he visto pasar cinco versiones del sistema operativo, todas incompatibles entre sí debido a pequeños cambios no documentados. Hace dos semanas, aproximadamente, me topé con el más reciente: el mecanismo utilizado en Windows Mobile 5 y anteriores para adjuntar un archivo a un correo ya no funciona en Windows Mobile 6. Lo que es mucho peor, lo que funciona en Windows Mobile 6 no funciona en las versiones anteriores. Como de costumbre, en Microsoft no hay indicación alguna de qué ha sucedido, ni por qué, ni de qué hacer.
Total, para eso estoy yo.
En resumen:

En Windows Mobile 6, un attachmente (un objeto Attach) debe tener una propiedad PR_MSG_STATUS, de valor (en ul) MSGSTATUS_RECTYPE_SMTP.
En Windows Mobile 5, un attachment puede tener una propiedad PR_MSG_STATUS.
En Windows Mobile 4 y anteriores, un attachment no debe tener una propiedad PR_MSG_STATUS.

Sencillo, ¿no? Lo único que tienes que hacer para que tu código funcione en cualquier versión de Windows Mobile es comprobar la versión del sistema operativo en tiempo de ejecución, y poner la propiedad PR_MSG_STATUS sólo cuando es posible.

Ahora bien, la propiedad PR_MSG_STATUS no es propia de los attachments. Todo parece indicar que es utilizada en el ejemplo del SDK porque tiene el mismo valor que otra constante, que no está definida en los archivos de cabecera de los entornos de desarrollo disponibles actualmente. En la próxima encarnación del Visual Studio estará incluida sin lugar a dudas; y el ejemplo incluido en el SDK será convenientemente modificado, sin que quede rastro de que fue distinto alguna vez. Ya sabes, Microsoft es así.