VictorJAM.zapto.org
Programación 

2025-02-09

Uso de Recursos

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 código, 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ística 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 incluido 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 recursos 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 identificar 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 fácil 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 elegir el que mas te guste si solo soporta uno u otro deberás hacer los reemplazos necesarios en el código 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 programa.

#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 múltiples 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 día 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 deberá 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é explícitamente 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.

Algunas notas fuera del tutorial

Aquí empecé a estudiar como hacer que el compilador de Borland pudiera compilar recursos y como añadirlos a mi código fuente.

Por un lado, el compilador tiene un programa llamado brc32.exe que es el encarado de compilar el archivo .rc y convertirlo en .res. Basta con coger el archivo .rc y pasárselo como parámetro al programa y ya tenemos nuestro archivo de recursos.

La forma más fácil de incluir nuestro archivo .res en Borland es añadir el recurso utilizando la directiva pragma:

#pragma resource "archivo.res"

Definitivamente, hay un problema para editar recursos ya que a mano es un problema ya que se complica mucho y los editores de recursos están pensados para visual studio. Mi recomendación es usar un programa de recursos a tu gusto y luego modificar el archivo a mano.

Los programas que recomiendo son:

Borland BCC workshop

Risho Editor

Digital Mars RSudio

Workshop funciona en windows 10 pero cuando lo lanzamos normalmente el editor de dialogos da un error de .DLL y no deja editar. Para evitar esto debemos ejecutar como administrador.

Referencias

Código fuente de la lección.