10 pontos por GN⁺ 2025-05-12 | 3 comentários | Compartilhar no WhatsApp
  • Este projeto open source é um aplicativo leve e nativo de Todo para Windows feito apenas com C e a API Win32
  • Funciona com tamanho mínimo e sem depender de frameworks (até 26,5 KB), implementando diretamente uma GUI avançada do Windows e integração com o sistema
  • Além das funções básicas, como adicionar, editar, excluir e marcar tarefas como concluídas, oferece recursos de produtividade reais, como integração com a bandeja do sistema e opção de inicialização automática
  • O armazenamento é persistente em arquivo binário, salvando até 100 listas de tarefas na pasta AppData
  • O grande diferencial é a programação clássica, muito próxima do sistema operacional, sem frameworks pesados e com ambiente de execução leve

🌟 Simple Todo (C / WinAPI)

Visão geral do projeto

  • Este projeto cria um app moderno e nativo de Todo para Windows usando apenas C e a API Win32
  • Ele demonstra habilidades avançadas de programação de GUI no Windows e integração com o sistema
  • O projeto é muito pequeno (até 26,5 KB) e mantém integralmente a aparência nativa do Windows

✨ Principais recursos

  • Permite criar, editar e excluir tarefas
  • É possível marcar tarefas como concluídas
  • Os dados ficam salvos de forma persistente no AppData, então nunca se perdem
  • Integra-se à bandeja do sistema, indo para a bandeja ao minimizar
  • Tem aparência no estilo nativo do Windows
  • Oferece opção de execução automática na inicialização do Windows

🛠️ Detalhes técnicos

  • Todo o código foi escrito em C puro
  • Usa apenas a API Win32 para implementar a GUI
  • Tamanho minúsculo do executável (26,5 KB com compressão UPX)
  • Recurso de integração com a bandeja do sistema
  • Aplicação de estilos visuais modernos por meio de manifesto

💾 Armazenamento de dados

  • Todas as tarefas são armazenadas em um único arquivo binário
  • Caminho de armazenamento: %APPDATA%\TodoApp\todos.dat
  • O formato é binário e suporta até 100 itens

📋 Requisitos

  • É necessário um ambiente com sistema operacional Windows
  • São necessários MinGW-w64 (compilador GCC) e o Windows SDK

🎮 Como usar

  • Execute bin/todo.exe e use a interface para realizar as ações abaixo
  • Adicione uma nova tarefa com o botão "Add"
  • Selecione um item e clique em "Edit" para modificá-lo
  • Exclua um item com "Delete"
  • Use "Complete" para marcá-lo como concluído
  • É possível definir a prioridade de cada item

🏗️ Estrutura do projeto

  • A pasta src/ contém o ponto de entrada principal (main.c), a lógica de gerenciamento de tarefas (todo.c), a declaração das estruturas (todo.h) e a implementação da GUI (gui.c)
  • O executável compilado fica em bin/
  • Inclui o script de build (build.bat) e a documentação do projeto

🔧 Elementos de desenvolvimento

  • API Win32: implementação de gerenciamento de janelas e da GUI como um todo
  • Common Controls: uso de elementos modernos de UI
  • UXTheme: suporte à aplicação dos estilos visuais do Windows
  • File I/O: persistência dos dados

📝 Licença

  • Pode ser usado e modificado livremente sob a licença MIT

🤝 Contribuição

  • Pull Requests são bem-vindos
  • Qualquer pessoa pode participar do projeto

📫 Contato e links

3 comentários

 
aer0700 2025-05-13

Tem um certo romantismo nisso.

 
GN⁺ 2025-05-12
Comentários do Hacker News
  • Há coisas na programação de GUI com Win32 que eu gosto, embora seja um pouco peculiar. Dá para entender o motivo lendo o blog do Raymond Chen: a API Win32 começou na era do processador 8088, então certas decisões existem para economizar 40 bytes de código ou poupar um registrador. Antigamente eu escrevia muitos apps GUI simples por conta própria usando mingw e o livro do Petzold. Era muito divertido fazer tudo manualmente: controles personalizados, desenho de gráficos/texto, tratamento de scroll, hit testing etc. Vi que no seu app você usa strcpy e sprintf; se isso for programação séria, você realmente precisa usar variantes com verificação de tamanho. Fiquei surpreso que o compilador não tenha reclamado imediatamente. A API Win32 tem muitas funções que substituem as funções padrão da biblioteca C. Se quiser reduzir ainda mais o tamanho do executável, recomendo tentar escrever só com <Windows.h>, sem cstdlib. Dá para usar ZeroMemory no lugar de memset e CopyMemory no lugar de memcpy. Claro, codar em C puro fica extremamente doloroso em certo ponto, mas fazer isso em C puro nas primeiras vezes ajuda muito no aprendizado. Você desenvolve uma noção de composição ao lidar com esses detalhes. Se quiser explorar mais programação GUI com Win32, também recomendo WTL (Windows Template Library), que encapsula a API Win32 em C++ e facilita bastante entender como tudo funciona
    • Hoje em dia, no mínimo, troque strcpy por strncpy; caso contrário, todo mundo vai continuar apontando isso. Um dos grandes motivos para usar Zig é justamente reduzir esse tipo de erro comum. Mas claro, C também é válido
    • Sobre usar ZeroMemory em vez de memset e CopyMemory em vez de memcpy: os intrinsics do MSVC usam instruções rep stos/movs, então o código fica menor do que com chamada de função, e a tabela de imports também diminui
    • Eu também fazia muito isso antigamente e, sinceramente, sinto falta da habilidade de desenvolver UI nativa com código nativo
    • Pergunta sobre o motivo de existirem ZeroMemory e CopyMemory em vez de simplesmente usar a biblioteca padrão C já existente; queria entender por que criaram isso
  • Antigamente, em vez de chamar CreateWindow manualmente toda vez, muita gente escrevia recursos de diálogo em arquivos .rc (o Visual Studio inclusive oferece um editor de diálogos) e usava CreateDialog. Aí todos os controles são criados de uma vez. Se você adicionar apenas o manifest da aplicação, também consegue estilo de UI moderno e suporte a DPI alto
    • Com essa abordagem, suporte a atalhos de teclado como navegação com Tab entre controles também vem automaticamente. Só o redimensionamento ainda precisa ser feito manualmente, mas o código cresce rápido e não é difícil
    • Isso também aparece no livro do Petzold, então vale a pena procurar
  • Eu também já implementei algo parecido para Linux em assembly com menos de 2 KiB. Se escrever em C e fizer linkagem dinâmica, no Linux dá para ficar facilmente abaixo de 20 KiB. Acho que no Windows seria até mais fácil, já que há muito mais funcionalidade embutida. Então quero apoiar esse tipo de tentativa. Consultando as opções de linkagem no fim do texto, deve ser fácil reduzir ainda mais o tamanho
  • Sem framework, aparecem problemas como fonte borrada com scaling de DPI, falta de suporte a Tab, ausência de várias funcionalidades básicas de frameworks pré-modernos como Ctrl-A para selecionar texto em campos de texto, erro ao adicionar linhas etc. Então fico me perguntando em que sentido isso seria "moderno"
    • Exemplo anexado de configuração de reconhecimento de DPI: o código tenta ativar DPI awareness usando diferentes funções do Windows conforme a versão (user32:SetProcessDpiAwarenessContext, shcore:SetProcessDpiAwareness, user32:SetProcessDPIAware); se for uma versão realmente antiga, não chama nada
    • O termo moderno não combina, porque ele é grande demais em tamanho e insuficiente em funcionalidades (embora navegação com Tab entre controles seja fácil de implementar manualmente)
  • Como alguém que já programou em 6502, é doloroso perceber que agora até 278 KB é considerado leve
    • Fui analisar o tamanho do binário e o primeiro obstáculo foi que o build.bat não funcionava direito com core.autocrlf=false. Depois de mudar para core.autocrlf=true e clonar de novo, a build funcionou. Um certo toolchain do mingw gerou um .exe de 102 KB, ou seja, bem mais eficiente que 278 KB. Se quiser reduzir ainda mais, dá para passar flags extras para o GCC: com gcc -s -Oz -flto dá até para chegar a 47 KB. Se o único interesse for tamanho de binário, ainda há bastante margem para melhorar
    • Esse tamanho existe por causa da plataforma e do formato do executável. Informações de stack trace, infraestrutura de linkagem dinâmica, tabelas de tratamento de exceções e outras coisas ocupam espaço
    • Quero pedir a criação de uma categoria “app TODO de 64 KB” nas competições da demoscene
    • Sinceramente, esse tamanho me surpreende. Tenho a impressão de que antigamente, tirando o ícone, ficava menor. Será que é por causa do MinGw?
    • 6502? Isso era luxo. Na minha época muitas vezes nem CPU havia
    • Isso me faz lembrar da época em que programação em assembly para Win32 virou moda de repente, especialmente quando downloads shareware começaram a crescer. Também me lembra o início da programação 68k para Palm Pilot. Pareceu a última faísca do assembly não retrô
    • Alguém chegou a fazer um quickrun.exe de 15 KB, usando apenas C e a API Win32 pura. Não há nenhum truque especial para reduzir o binário, compilado com Mingw32; é um app GUI para iniciar apps rapidamente via alias
    • Hoje à noite estou depurando meu emulador que emula um sistema Z80 com 64 KB de RAM. Às vezes isso faz perceber de novo o quanto o tempo e o ambiente mudaram. Ainda assim, também tivemos avanços imensos na mesma proporção em que o tamanho cresceu
    • De arquiteturas de 8 bits até 64 bits, só um ponteiro de endereço já ficou 8 vezes maior. Em vez de reclamar, tente apreciar que essa mudança em si é uma forma de arte
    • 278 KB mal cabem em um disquete de 5 1/4
  • Esse app foi feito só por diversão, apenas para experimentar. Como apontaram nos comentários, provavelmente seria mais razoável usar C++ ou outra linguagem, mas para mim o prazer estava justamente em tentar
    • Uns 30 anos atrás eu também fiz meu primeiro programa para Windows quase exatamente assim. A diferença é que eu usei um compilador C++. Naquela época, escrever código em estilo C com compilador C++ era o método recomendado pela documentação oficial. Como C++ era compatível com C, a Microsoft também tendia a seguir essa linha
    • Sinceramente, eu preferiria muito mais usar o seu app do que o app padrão de tarefas do Windows 11
    • Ao usar a API Win32, a essência não muda tanto independentemente da linguagem. Trocar de linguagem pode até deixar tudo mais confuso. Se você insistir demais no estilo C++, isso pode confundir ainda mais quem está aprendendo a API Win32 pela primeira vez. Acredito que se acostumar com a API Win32 por meio de projetinhos simples e bonitinhos como este faz parte da base de um desenvolvedor
    • Também tenho outro app chamado YoutubeGO; ficaria feliz se você desse uma olhada
    • Entendo e elogio isso, porque projetos com UI nativa limpa desse tipo também foram o que me motivaram a aprender programação
  • Em uma cultura de web e software em que se carrega JavaScript ou C# de vários megabytes para enviar 278 KB de telemetria, esse tipo de tentativa é refrescante
    • Um app parecido feito em C# + WinForms ocupa menos de 10 KB em disco e consome só 6 MB de RAM; este app usa 1,5 MB de RAM. Ambos abrem instantaneamente
  • Pelo que vejo agora, parece que foi feito link estático de bibliotecas. Se fizer linkagem com DLL, o tamanho do app pode cair drasticamente
    • Na verdade é um pouco o contrário. Se você precisar distribuir as DLLs junto com o programa (ou seja, se elas não vierem no sistema operacional), cada DLL inclui seu próprio runtime C, então no fim tudo pode ficar maior. Se colocar tudo estaticamente dentro de um único EXE, você inclui apenas uma cópia do runtime C, e funções não usadas podem ser removidas facilmente. DLL só reduz tamanho quando vários programas compartilham a mesma DLL
    • Fazer link estático do CRT (biblioteca de runtime) pode, na verdade, ajudar a eliminar código desnecessário. Se você fizer link dinâmico com DLL, pode acabar exigindo que o usuário instale separadamente a VCRUNTIME DLL da Microsoft. No Visual Studio, fazer link dinâmico com MSVCRT também não é tão simples. A exceção seria quando for necessário cumprir LGPL
  • Isso me lembrou o File Pilot, um explorador de arquivos rápido lançado recentemente, feito em C e com apenas 1,8 MB
  • Dizem que é um app TODO para Windows “moderno” e “nativo”, mas fico em dúvida sobre o que exatamente há de moderno nisso. E se fosse escrito em C++, vários problemas poderiam ser evitados, além de eliminar variáveis globais. Se usar std::string, std::array, std::list, namespaces anônimos e remover malloc, o resultado provavelmente seria metade do código e menos bugs
    • Variáveis globais quase não fazem diferença em um app de cerca de 500 linhas, e o propósito delas é claro. Trocar para std::string e std::list não significa que o assembly gerado será igual; isso mostra desconhecimento real do funcionamento interno
    • Até mesmo a edição mais recente do livro do Petzold compila em modo C++ com Visual C++ e recomenda sintaxe comum a C/C++. Já na época do Windows 95, quase ninguém escrevia tudo puramente em C; VB, Delphi e C++ já tinham se tornado as linguagens principais
    • Sobre a sugestão de usar string, array/list padrão: se você já vai usar WinAPI diretamente, faz mais sentido usar LPWSTR (wide string) no lugar de std::string, porque combina melhor com a API. Recomendo LPWSTR em vez de abordagens antigas como char[]. Não acho que std::array ou list tornariam o código melhor
    • Não é moderno, mas esse tipo de programação mais próxima da base ajuda a entender corretamente como as coisas funcionam por baixo. Os problemas também são simples, então é fácil de compreender. Acho um bom projeto de aprendizado. Também tenho curiosidade sobre exemplos de implementação desse tipo de app em assembly inteiro
 
roxie 2025-05-16

Irmãos, dá até para sentir o bafo de vocês chegando até aqui...