Las aplicaciones que usan sólo la APIs pueden minimizarse en tamaño enormemente. Si una aplicación mínima en Builder, tipo consola, pesa 46k, podemos dejarla en 4k. Si posteriormente la comprimimos podrá ocupar 1k.
La forma de conseguir este objetivo es minimizar las librerías y módulos .obj que se enlazan al ejecutable.
Una aplicación normal presenta en el archivo de proyecto la siguiente fracción:
<LINKER> <ALLOBJ value="c0w32.obj sysinit.obj $(OBJFILES)"/> <ALLRES value="$(RESFILES)"/> <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib"/> </LINKER>
Como se ve, se enlazan c0w32.obj, sysinit.obj y las librerías import32.lib cp32mt.lib. Se puede prescindir de todos los archivos excepto de import32.lib.
c0w32.obj - 2.302 bytes
sysinit.obj - 3.113 bytes
cp32mt.lib - 1.727.488 bytes (no se enlazan todas las funciones)
c0w32.obj se encarga de inicializar las librerías del Builder. Se enlazan partes de las librerías RTL que se incluyen en el ejecutable, aunque luego el programa no haga uso de ellas.
Si evitamos que se enlacen los módulos que no nos hacen falta conseguiremos una reducción considerable en el peso final del programa:
<LINKER> <ALLOBJ value="$(OBJFILES)"/> <ALLRES value="$(RESFILES)"/> <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib"/> </LINKER>
Pero la cosa no es tan sencilla, habrá que hacer algún cambio mas. Tendremos que reescribir la entrada a la aplicación:
MAIN.ASM:
.586p Locals jumps .model flat, stdcall extrn _main : PROC .data .code Entry: JMP _main End Entry
La anterior rutina inicia el programa y llama a la función C main(), que se encargará de preparar los parámetros para llamar a la clásica función WinMain, esta ya conocida y familiar.
_MAIN.CPP:
#include <windows.h> // Punto de entrada al programa // !! PREVIO a WinMain !! extern "C" void Main() { STARTUPINFO info; HINSTANCE hinstance; TCHAR *CmdLine; GetStartupInfo( &info); hinstance = GetModuleHandle(NULL); CmdLine = GetCommandLine(); int n = 0; if(*CmdLine==char(34)) while(CmdLine[++n]!=34); while(CmdLine[n++]!=char(32)); CmdLine = n==lstrlen(CmdLine) ? 0 : CmdLine+n; ExitProcess(WinMain(hinstance, NULL, CmdLine, info.wShowWindow)); }
Ahora sólo queda escribir la función WinMain:
WinMain.cpp:
//--------------------------------------------------------------------------- #include <windows.h> #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MessageBox(0, "Hola, Mundo!!", "MiniAPP", MB_OK); return 0; } //---------------------------------------------------------------------------
El resultado es un ejecutable que ocupa 4k (4.096 bytes) sin compresión alguna. Si usamos compresores de código podremos alcanzar 1k.
Podemos crear también aplicaciones con ventanas usando sólo la API de Windows.
Sin embargo este sistema tiene un pequeño inconveniente, no funcionan algunas funciones de las C/C++ estándar como las de manejo de memoria y cadenas, que no estén implementadas en la API. Por ejemplo, no funciona el operador new ni la función strlen. En este último caso podremos usar lstrlen que es el equivalente que tiene Windows. Para manejar la memoria podemos usar VirtualAlloc que nos permitirá reservar memoria sin dificultad.
En definitiva, es un método de ahorrar tamaño en los ejecutables pequeños, que perderá su sentido en aplicaciones mayores en las que el uso amplio e intensivo de la RTL la hará rentable desde el punto de vista del espacio.
Adjunto los archivos descritos y el de proyecto para Builder5 con dos versiones del ejecutable, una de 4.096 bytes y otra, comprimida, de 929 bytes.
Espero que esta información sea de utilidad y de aclaración del funcionamiento interno del Builder.
Saludos.
Edito para resubir archivo adjunto corrupto y reparar caracteres dañados en el texto