10 puntos por GN⁺ 2025-05-12 | 3 comentarios | Compartir por WhatsApp
  • Este proyecto de código abierto es una aplicación ligera y nativa de Todo para Windows creada únicamente con C y la API Win32
  • Funciona con un tamaño mínimo (sin depender de frameworks), de hasta 26.5 KB, e implementa directamente una GUI avanzada de Windows y la integración con el sistema
  • Ofrece no solo funciones básicas como agregar, editar, eliminar y marcar como completadas las tareas, sino también funciones de productividad real como integración con la bandeja del sistema y opción de inicio automático
  • El almacenamiento persistente usa un archivo binario, y guarda hasta 100 listas de tareas en la carpeta AppData
  • Su fortaleza está en el enfoque clásico de programación, muy cercano al sistema operativo, sin grandes frameworks y con un entorno de ejecución ligero

🌟 Simple Todo (C / WinAPI)

Resumen del proyecto

  • Este proyecto crea una app moderna y nativa de Todo para Windows usando únicamente C y la API Win32
  • Demuestra capacidades avanzadas de programación GUI en Windows e integración con el sistema
  • El proyecto es muy pequeño (hasta 26.5 KB) y conserva intacta la apariencia nativa de Windows

✨ Funciones principales

  • Permite crear, editar y eliminar tareas
  • Se pueden marcar tareas como completadas
  • Se guardan de forma persistente en AppData, por lo que los datos siempre se conservan
  • Se integra con la bandeja del sistema y al minimizarse se mueve a la bandeja
  • Tiene una apariencia de estilo nativo de Windows
  • Incluye una opción para ejecutarse automáticamente al iniciar Windows

🛠️ Detalles técnicos

  • Todo está programado en C puro
  • Solo usa la API Win32 para implementar la GUI
  • Tamaño de ejecutable diminuto (26.5 KB con compresión UPX)
  • Función de integración con la bandeja del sistema
  • Aplicación de estilos visuales modernos mediante manifiesto

💾 Almacenamiento de datos

  • Todas las tareas se guardan en un solo archivo binario
  • Ruta de almacenamiento: %APPDATA%\\TodoApp\\todos.dat
  • Formato binario con capacidad para hasta 100 elementos

📋 Requisitos

  • Se requiere un entorno con sistema operativo Windows
  • Se necesitan MinGW-w64 (compilador GCC) y el Windows SDK

🎮 Cómo usarlo

  • Ejecuta bin/todo.exe y usa la interfaz para realizar las siguientes acciones
  • Agrega una nueva tarea con el botón "Add"
  • Selecciona un elemento y haz clic en "Edit" para modificarlo
  • Elimina un elemento con "Delete"
  • Márcalo como completado con "Complete"
  • Es posible asignar una prioridad a cada elemento

🏗️ Estructura del proyecto

  • En la carpeta src/ se encuentran el punto de entrada principal (main.c), la lógica de gestión de tareas (todo.c), la declaración de estructuras (todo.h) y la implementación de la GUI (gui.c)
  • El ejecutable compilado se ubica en bin/
  • Incluye el script de compilación (build.bat) y la documentación del proyecto

🔧 Elementos de desarrollo

  • API Win32: implementación de la gestión de ventanas y de toda la GUI
  • Common Controls: uso de elementos modernos de UI
  • UXTheme: soporte para aplicar estilos visuales de Windows
  • File I/O: hace posible el almacenamiento persistente de datos

📝 Licencia

  • Licencia MIT, con libertad de uso y modificación

🤝 Guía de contribución

  • Pull Requests bienvenidos
  • Cualquiera puede participar en el proyecto

📫 Contacto y enlaces

3 comentarios

 
aer0700 2025-05-13

Tiene su encanto.

 
GN⁺ 2025-05-12
Comentarios de Hacker News
  • hay una parte de la programación de GUI con Win32 que me gusta, aunque sea un poco peculiar; si lees el blog de Raymond Chen se entiende por qué. La API de Win32 viene desde la era del procesador 8088, y había trucos como ahorrar 40 bytes de código o usar un registro menos si lo hacías de cierta manera. Hace tiempo escribí muchas apps GUI simples mirando MinGW y el libro de Petzold. Era muy divertido hacer todo a mano: controles personalizados, dibujo de gráficos/texto, manejo de scroll, hit testing, etc. Vi que en tu app usas strcpy y sprintf; si estás programando en serio, de verdad deberías usar siempre variantes con verificación de longitud. Me sorprende que el compilador no te haya lanzado advertencias de inmediato. La API de Win32 tiene muchas funciones que reemplazan funciones estándar de la librería C. Si quieres reducir aún más el tamaño del ejecutable, te recomiendo probar escribirlo usando solo <Windows.h> y sin cstdlib. Puedes usar ZeroMemory en lugar de memset y CopyMemory en lugar de memcpy. Claro, programar en C puro se vuelve tremendamente doloroso a partir de cierto punto, pero hacerlo así las primeras veces ayuda muchísimo a aprender. Te da intuición para manejar estos detalles pequeños. Si quieres seguir explorando programación GUI con Win32, también te recomendaría WTL (Windows Template Library), que envuelve la API de Win32 en C++ y hace mucho más fácil entender cómo funciona
    • hoy en día, como mínimo deberías usar strncpy en vez de strcpy; si no, todo el mundo te lo va a seguir señalando. Una de las grandes razones para usar Zig es justamente que reduce estos errores tan comunes. Igual C también está bien
    • sobre lo de usar ZeroMemory en vez de memset y CopyMemory en vez de memcpy: los intrínsecos de MSVC usan instrucciones rep stos/movs, así que el código termina siendo más pequeño que una llamada a función, y además se reduce el tamaño de la tabla de imports
    • yo también hacía mucho esto antes y, siendo sincero, extraño la habilidad de desarrollar UI nativa con código nativo
    • pregunto por qué existen ZeroMemory y CopyMemory en lugar de simplemente usar la librería estándar de C; me da curiosidad por qué hicieron eso en vez de reutilizar lo que ya existía
  • antes, en vez de llamar a CreateWindow una y otra vez, era común escribir recursos de diálogo en archivos .rc (Visual Studio incluso trae editor de diálogos) y usar CreateDialog; así todos los controles se crean de una sola vez. Si además agregas el manifest de la aplicación, también puedes soportar estilo de UI moderno y DPI alto
    • con este enfoque también obtienes automáticamente soporte para atajos de teclado como moverte con Tab entre controles. Eso sí, cosas como el redimensionamiento siguen siendo manuales, pero el código se puede ampliar rápido y no es difícil
    • también sale en el libro de Petzold, así que te recomiendo echarle un vistazo
  • yo hice algo parecido hace tiempo para Linux, en menos de 2 KiB de ensamblador. Si lo escribes en C y enlazas dinámicamente, en Linux se puede hacer fácilmente por debajo de 20 KiB. Creo que en Windows debería ser todavía más fácil porque trae muchas cosas integradas. Por eso me dan ganas de apoyar este tipo de intento. Si revisas las opciones de linking al final del artículo, seguramente podrás bajarle más el tamaño
  • hacerlo sin framework implica fuentes borrosas al escalar por DPI, sin soporte para Tab, sin muchas funciones básicas que hasta frameworks premodernos tenían por defecto como seleccionar todo con Ctrl-A en campos de texto, errores al agregar filas, etc. Entonces me pregunto en qué sentido esto es “moderno”
    • adjunto un ejemplo de configuración de DPI awareness; el código intenta configurar el reconocimiento de DPI usando distintas funciones de Windows según la versión (user32:SetProcessDpiAwarenessContext, shcore:SetProcessDpiAwareness, user32:SetProcessDPIAware). Si la versión es realmente muy antigua, no llama a ninguna
    • no le queda eso de “moderno”; ocupa demasiado para lo poco que hace (moverse con Tab entre controles sería fácil de implementar a mano)
  • como alguien que programó en 6502, me duele la realidad de que ahora 278 KB ya se consideren livianos
    • estuve analizando el tamaño del binario y el primer obstáculo fue que build.bat no funciona bien con core.autocrlf=false; lo cambié a core.autocrlf=true, volví a clonar y ahí sí compiló. Cierta toolchain de MinGW genera un .exe de 102 KB, o sea mucho más eficiente que 278 KB. Si quieres reducirlo más, puedes pasarle flags extra a GCC. Con gcc -s -Oz -flto incluso se puede llegar a 47 KB. Si lo único que te importa es el tamaño del binario, todavía hay mucho margen de mejora
    • que termine pesando eso se debe a la plataforma y al formato del ejecutable. Cosas como la información para stack traces, la infraestructura de enlace dinámico, tablas de manejo de excepciones y demás ocupan espacio
    • quiero pedir una nueva categoría en las competencias de la demoscene: “app TODO de 64KB”
    • sinceramente me sorprende que pese tanto; recuerdo que antes, incluso quitando el ícono, quedaban más chicos. Me pregunto si será por MinGW
    • ¿6502? Eso era lujo; en mis tiempos muchas veces ni siquiera había CPU
    • me hace recordar esa época en que la programación en ensamblador para Win32 se puso repentinamente de moda, sobre todo cuando las descargas shareware empezaron a crecer de tamaño. También me hace pensar en la programación temprana para Palm Pilot 68k. Fue como el último destello del ensamblador no retro
    • hubo alguien que incluso hizo un quickrun.exe de 15 KB usando solo C y la API pura de Win32. No hay truco mágico para reducir el binario, usó el compilador Mingw32. Es una app GUI para lanzar apps rápido mediante alias
    • esta noche justo estoy depurando mi emulador de un sistema Z80 con 64 KB de RAM. A veces uno se da cuenta de cuánto han cambiado los años y el entorno, aunque también siento que hemos logrado avances enormes proporcionales al aumento de tamaño
    • de arquitecturas de 8 bits a 64 bits, con solo ver los punteros de dirección ya crecieron 8 veces. Mejor no te quejes y aprecia que este cambio en sí mismo es arte
    • 278 KB apenas caben en un disquete de 5 1/4 pulgadas
  • esta app la hice solo por diversión, por el gusto de hacerla yo mismo. Como señalan en los comentarios, seguramente habría sido más razonable hacerla en C++ u otro lenguaje, pero para mí la gracia era simplemente intentarlo
    • hace como 30 años yo hice casi exactamente lo mismo como mi primer programa para Windows. La diferencia es que usé un compilador de C++. En esa época, la documentación oficial incluso guiaba a escribir código estilo C con compilador de C++, porque C++ era compatible hacia arriba con C y Microsoft también tendía a hacerlo así
    • sinceramente, me dan muchas más ganas de usar tu app que la app de tareas por defecto de Windows 11
    • al usar la API de Win32, no cambia tanto la esencia sin importar qué lenguaje uses. De hecho, cambiar de lenguaje puede volver todo más confuso. Si te obsesionas con el estilo C++, para alguien que recién aprende Win32 API puede ser todavía más confuso. Familiarizarse con Win32 API mediante un proyecto personal simple y bonito como este me parece parte de la base formativa de un desarrollador
    • aparte, también tengo otra app llamada YoutubeGO; me alegraría si le das una mirada
    • proyectos así, con una UI nativa limpia, también fueron lo que me motivó a aprender a programar, así que empatizo y lo aplaudo
  • hoy en la web y en el software hay mucha cultura de cargar megabytes de JS o C# para enviar 278 KB de telemetría, así que este tipo de intento se siente refrescante
    • una app similar hecha con C# + WinForms ocupa menos de 10 KB en disco y solo usa 6 MB de RAM; esta usa 1.5 MB de RAM. Ambas aparecen de inmediato al ejecutarse
  • por cómo se ve ahora, parece que enlazaste librerías estáticas. Si enlazaras con DLL, podrías reducir drásticamente el tamaño de la app
    • eso es más bien al revés. Si tienes que distribuir obligatoriamente las DLL junto con el programa (cuando la DLL no viene incluida en el OS), cada DLL trae su propio runtime de C, así que termina siendo todavía más grande. Si metes todo estáticamente en un solo EXE, solo incluyes una copia del runtime de C y además es fácil eliminar las funciones no usadas. Las DLL solo ahorran espacio cuando varios programas comparten la misma DLL
    • enlazar el CRT (runtime library) de forma estática incluso ayuda a reducir código innecesario. Si enlazas dinámicamente la DLL, además puede que tengas que instalar por separado las VCRUNTIME DLL de Microsoft. En Visual Studio también puede ser complicado enlazar dinámicamente contra MSVCRT, aunque esto cambia si necesitas cumplir con LGPL
  • me recordó a File Pilot, un explorador de archivos rápido lanzado hace poco, hecho en C y que pesa apenas 1.8 MB
  • lo llaman una app Todo de Windows “moderna” y “nativa”, pero de verdad me pregunto qué tiene de moderna. Además, si lo escribieras en C++ podrías prevenir varios problemas y eliminar variables globales. Si usas std::string, std::array, std::list, namespaces anónimos y eliminas malloc, probablemente terminarías con la mitad del código y menos bugs
    • las variables globales casi no importan en una app de unas 500 líneas y su propósito está clarísimo. Cambiar a std::string o std::list no significa que el resultado real en ensamblador vaya a ser el mismo; se nota que no entiendes de verdad lo que pasa internamente
    • incluso el libro de Petzold, en sus ediciones más recientes, compila en modo C++ con Visual C++ y recomienda sintaxis común entre C/C++. Ya en la época de Windows 95 casi nadie escribía exclusivamente en C; el mainstream ya se había movido a VB, Delphi y C++
    • sobre la idea de usar string o array/list estándar: si ya vas a usar WinAPI directamente, encaja mejor con la API usar LPWSTR (wide string) que std::string, y es lo recomendado. Mucho mejor LPWSTR que métodos antiguos como char[]; no creo que std::array o list vayan a mejorar realmente el código
    • no es moderno, pero este tipo de programación más cercana a la base ayuda a entender bien cómo funcionan las cosas por debajo. Además, el problema es simple y por eso es fácil de comprender. Me parece un muy buen proyecto de aprendizaje. También me daría curiosidad ver una versión de una app así implementada en ensamblador completamente
 
roxie 2025-05-16

Se siente como si el aliento nasal de los panas llegara hasta aquí...