Puedes mirar los apéndices al final del tutorial para mas información sobre el uso de recursos con VC++ y BC++.
Antes de ver el tema en profundidad voy a cubrir el tema de recursos así no tendré que reescribir el mismo en cada sección. Por ahora no necesitas compilar el codigo, solo es un ejemplo.
Los recursos son porciones pre-definidas de datos que se almacenan en formato binario dentro de los archivos ejecutables y se organizan dentro de un archivo con extensión ".rc" (resource script). Los compiladores comerciales cuentan con un editor visual de recursos que permite crear recursos sin editar manualmente este archivo. A veces la única manera de poder crear un recurso es editar este archivo manualmente sobre todo si tu compilador no tiene un editor visual o no soporta la caracterísitica exacta que necesitas.
Desafortunadamente, no todos los compiladores manejan los recursos de la misma manera. Haré lo mejor que pueda para explicar las características mas comunes que son necesarias para trabajar con recursos en forma general.
El editor de recursos incluído con MSVC++ hace muy difícil la tarea de editar los recursos manualmente, debido a que fuerza un formato propio en ellos y si intentas guardar uno que has creado manualmente estropea completamente el archivo. En general no deberías preocuparte por crear archivos de recursos desde cero, pero conocer como modificarlos manualmente puede ser muy útil. Otra incomodidad es que MSVC++ nombrará el archivo de recuros por default con el nombre "resource.h" aún si deseas llamarlo con otro nombre. Utilizaremos este con el propósito de simplicidad para este documento, pero te mostraré como cambiarlo en el apéndice sobre compiladores.
Primero miremos un archivo de recursos bastante simple, con solo un ícono:
#include "resource.h" IDI_MYICON ICON "my_icon.ico"
Este es todo el archivo. IDI_MYICON
es el identificador del recurso, ICON
es el tipo de recurso y "my_icon.ico
" es el nombre del archivo externo que contiene al ícono. Esto debería funcionar en cualquier compilador.
¿Que hay acerca de #include "resource .h"
?. Bien tu programa necesita una forma de indentificar el ícono y la mejor forma de hacerlo es asignándole a este un único ID (IDI_MYICON
). Podemos hacer esto creando el archivo de cabecera "resource.h
" e incluir éste tanto en el archivo de recursos (.rc) como en el programa (.c)
#define IDI_MYICON 101
Como puedes ver, hemos asignado a IDI_MYICON
el valor 101
. De ahora en mas podríamos olvidarnos del identificador y simplemente usar 101
cada vez que necesitamos referenciar el ícono. Pero IDI_MYICON
es un poco mas claro, mas representativo y mas facil de recordar, sobre todo si estamos trabajando con una gran cantidad de recursos.
Ahora supongamos que agregamos un recurso MENU
:
#include "resource.h" IDI_MYICON ICON "my_icon.ico" IDR_MYMENU MENU BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", ID_FILE_EXIT END END
Nuevamente IDR_MYMENU
es el nombre del recurso y menú es el tipo. Ahora observa el BEGIN
y el END
. Algunos editores o compiladores utilizan la llave que abre {
en lugar de BEGIN
y la llave que cierra }
en lugar de END
. Si tu compilador soporta ambos, puedes elejir el que mas te guste si solo soporta uno u otro debrerás hacer los reemplazos necesarios en el codigo fuente para que esto funcione.
También he agregado un nuevo identificador, ID_FILE_EXIT
, por lo tanto necesitamos agregarlo al archivo de cabecera de los recursos (resource.h) para poder usarlo dentro de nuestro porgrama.
#define IDI_MYICON 101 #define ID_FILE_EXIT 4001
Generar y mantener un registro de todos los identificadores de recursos puede ser una tarea costosa cuando trabajamos con grandes proyectos, esta es la razón por la que muchas personas utilizan un editor visual de recursos, el cual se encarga de hacer todo este trabajo por nosotros. Aunque pueden generar problemas de vez en cuando y podrías finalizar con multiples recursos con el mismo ID o problemas similares, es bueno ser capaz de ir y poder corregir esos errores uno mismo.
Ahora veamos un ejemplo de como usar un recurso dentro de un programa.
HICON hMyIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON));
El primer parámetro de LoadIcon( )
y muchos otros recursos que utilizan funciones es el handle a la instancia actual (la que obtenemos en WinMain( )
y que también puede ser recuperada utilizando la función GetModuleHandle( )
, como lo demostramos en secciones anteriores). El segundo es el identificador del recurso.
Probablemente te estés preguntando que es MAKEINTRESOURCE( )
y posiblemente por qué LoadIcon()
toma un parámetro de tipo LPCTSTR
en vez de, por ejemplo UINT
, cuando le estamos pasando un ID. Todo lo que MAKEINTRESOURCE
hace es convertir un entero (el tipo de nuestro ID) a un LPCTSTR
que es lo que LoadIcon( )
espera. Esto nos da una segunda forma de identificar recursos: utilizando strings. Hoy en dia casi nadie hace esto, por lo tanto no voy a entrar mucho en detalle. Básicamente si no utilizas #define
para asignar un valor entero a tus recursos, entonces el nombre es interpretado como un string y podemos referenciar los recursos dentro de nuestro programa de la siguiente manera:
HICON hMyIcon = LoadIcon(hInstance, "MYICON");
Cuando se les pasa un valor entero LoadIcon( )
y otras APIs que cargan recursos pueden identificar la diferencia entre un entero y un puntero a un entero chequeando la palabra superior de dicho valor. Si es cero (como podría ser el caso de un entero con un valor menor a 65535) entonces asume que se trata del ID de un recurso. Esto efectivamente nos limita a usar IDs inferiores a 65535, que a menos que tengas una gran cantidad de recursos, no deberiá ser un problema. Si es distinto de cero, entonces asume que el valor es
un puntero y busca el recurso por el nombre. Nunca le confíes este trabajo a la API a menos que esté explicitamente establecido en la documentación.
Por ejemplo, esto no funciona para comandos del menú como ID_FILE_EXIT
debido a que solo pueden ser enteros.
Versión en Español: Federico Pizarro - 2003