Debe introducir al menos 3 caracteres en el buscador.
Inicio / Wikis / Tutoriales / Los rincones del API Win32: El caché de WinInet - Mi asignatura pendiente: Mensajes de error

Los rincones del API Win32: El caché de WinInet - Mi asignatura pendiente: Mensajes de error

 ----- 
Creative Commons Tutorial de Juan Manuel - 27 de Agosto de 2005
Temas Relacionados: Programación estructurada
13. Mi asignatura pendiente: Mensajes de error
Ya hace unos cuantos meses que estoy escribiendo sobre WinInet, y la verdad es que he aprendido bastante desde aquel primer artículo. Una de las cosas que no expliqué en el artículo introductorio era cómo obtener el mensaje de error a partir de su código. Es decir: siempre hemos dicho la mayoría de las funciones retornan FALSE cuando ocurre un error, y para obtener el código de error hay que llamar a GetLastError. Cada código de error tiene un mensaje descriptivo asociado, aunque hasta ahora no sabía cómo hacer para obtenerlo. No se puede saber todo desde el principio ¿no? Mis averiguaciones se habían atascado en el punto en que sabía que los mensajes estaban almacenados como recursos de cadena dentro del archivo "wininet.dll". Lo que no sabía era cómo localizar el recurso adecuado a partir de un código de error concreto. Después de pasar muchas horas consultando el MSDN, pude encontrar la clave del asunto. La cuestión está en una función que no pertenece al API WinInet, sino al API genérico de Win32: FormatMessage. Esta función trabaja de distintas formas, obteniendo el mensaje (teniendo en cuenta el idioma instalado) de un error genérico de Win32, formateando una cadena con máscaras al estilo "printf", u obteniendo un mensaje a partir de una librería independiente. Ahí está el asunto. Podemos obtener los mensajes que están almacenados como recursos dentro de la librería "wininet.dll", localizándolos a partir del código de error.

Lo primero que necesitamos es un descriptor de la librería, bien abriéndola con LoadLibrary, o intentando obtener un descriptor ya creado por el proceso, a través de la función GetModuleHandle. También podemos hacer una solución mixta, intentando obtener un descriptor ya creado, y si no existe, crearlo nosotros.

El siguiente paso es llamar a la función FormatMessage. La sintaxis es la siguiente, aunque sólo voy a explicarla superficialmente porque esta función tiene muchas formas de trabajar:

DWORD FormatMessage( DWORD dwOpciones, LPCVOID lpOrigen, DWORD dwCódigoError, DWORD dwIdioma, LPTSTR lpBuffer, DWORD dwLongitudBuffer, va_list *argumentos );

  • dwOpciones: es una máscara de bits que indican cómo debe comportarse la función. Se puede utilizar una combinación de los siguientes valores:
    • FORMAT_MESSAGE_ALLOCATE_BUFFER: la función reservará memoria en el montón por defecto del proceso (¿alguien se acuerda del artículo sobre “Los montones”?) para almacenar el mensaje. El que llame a FormatMessage con este parámetro es el responsable de liberar el buffer resultante con la función HeapFree(GetProcessHeap(), buffer)
    • FORMAT_MESSAGE_FROM_STRING: hace que la función actúe como un "fprintf", es decir, formateando una cadena que contiene máscaras.
    • FORMAT_MESSAGE_FROM_HMODULE: el mensaje de obtiene de una librería independiente, buscando en los recursos de cadena. Este es el valor que nos interesa para buscar los mensajes en "wininet.dll"
    • FORMAT_MESSAGE_FROM_SYSTEM: se busca en los mensajes de sistema el código indicado. Este parámetro nos sirve para conseguir la mayoría de los mensajes de funciones básicas de Win32, como CreateFile, CloseHandle, etc.
  • lpOrigen: se trata de un puntero genérico en el que podemos pasar distintos valores. El tipo de dato que debemos pasar depende de las constantes que hayamos pasado en el parámetro dwOpciones, pudiendo ser:
    • FORMAT_MESSAGE_FROM_STRING: un puntero a una cadena que será formateada.
    • FORMAT_MESSAGE_FROM_HMODULE: un descriptor de librería, obtenido con LoadLibrary o GetModuleHandle.
    • cualquier otro: este parámetro debe ser NULL.
  • dwCódigoError: el código numérico del error. Normalmente lo obtenemos con GetLastError.
  • dwIdioma: Se trata de un valor numérico que identifica el idioma en que queremos obtener el mensaje. Este valor lo podemos obtener con las funciones GetSystemDefaultLangID ó GetUserDefaultLangID, las constantes LANG_SYSTEM_DEFAULT o LANG_USER_DEFAULT. Podemos pasar el valor 0 para obtener el mensaje en el idioma por defecto del usuario o sistema.
  • lpBuffer: en este parámetro se pasa un puntero a una cadena de caracteres en la que se copiará el mensaje obtenido. Si hemos pasado el valor FORMAT_MESSAGE_ALLOCATE_BUFFER en el parámetro dwOpciones, en realidad lo que se debe pasar es la dirección de un puntero a cadena. En esa dirección se copiará a su vez la posición de memoria donde se ha creado el nuevo buffer.
  • dwLongitudBuffer: este parámetro puede contener el tamaño del buffer pasado en "lpBuffer", o el tamaño mínimo a reservar por la función, esto último sólo si hemos pasado FORMAT_MESSAGE_ALLOCATE_BUFFER en el parámetro dwOpciones.
  • argumentos: se trata de una lista de argumentos variables que se utilizarán par sustituir las máscaras de la cadena, si hemos utilizado la opción FORMAT_MESSAGE_FROM_STRING. En caso de no necesitar este parámetro, podemos pasar el valor NULL.

La función retorna el número de caracteres que se ha copiado en el buffer de salida, o 0 en caso de error. Se puede llamar a GetLastError() para averiguar la causa del error.

De todas formas, en el mundo de la programación, un ejemplo vale más que mil palabras, así que aquí tenéis un algoritmo típico para obtener el mensaje de un código de error que retorne GetLastError:

{ LPTSTR buff; HMODULE hLib; DWORD err = GetLastError(); BOOL liberar = FALSE; se obtiene el descriptor de la librería hLib = GetModuleHandle("wininet.dll"); if (!hLib) { hLib = LoadLibrary("wininet.dll"); liberar = TRUE; if (!hLib) return; } FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER, opciones hLib, librería err, código de error LANG_SYSTEM_DEFAULT, idioma buff, , buffer y longitud NULL sin parámetros ); MessageBox(GetActiveWindow(), buff, "Error", MB_ICONERROR); se libera el buffer que ha reservado FormatMessage HeapFree(GetProcessHeap(), , buff); se libera la librería if (liberar) FreeLibrary(hLib); return; }
Autor y licencia de 'Los rincones del API Win32: El caché de WinInet - Mi asignatura pendiente: Mensajes de error'
Juan Manuel Extraído de: http://www.lawebdejm.com

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Este contenido ha sido recopilado por el equipo de Wikilearning. Todo el contenido recopilado se ha obtenido respetando y comunicando en nuestro site la licencia de cada fuente.
Wikilearning tiene permiso expreso por escrito de los autores para publicar los contenidos que ha extraído de otras webs, incluyendo su uso comercial.

Wikis relacionados con 'Los rincones del API Win32: El caché de WinInet - Mi asignatura pendiente: Mensajes de error'

Comienzo con un nuevo tema dentro dentro de la serie Los rincones del API Win32.... Más »
Entramos en temas interesantes: el acceso a recursos remotos a través del protocolo de aplicación... Más »
En el anterior curso dejamos muchos temas en el tintero, así que voy a terminar... Más »
Damos una visión detallada de una de las características más interesantes de esta tecnología de... Más »
Curso que profundiza en el gestor de montones (o montículos) dentro de Win32, así como... Más »
¿Estás seguro de que deseas eliminar este capítulo?