C GUI no Windows: do printf ao MessageBox com LLVM e Make

Muito painel de chão ainda é Windows embarcado ou PC industrial com Windows. Enquanto o estudo irmão c_gui_linux parte do GTK3, o repositório c_gui_win treina a mesma disciplina no ecossistema Microsoft: toolchain explícita + dois programas mínimos — console e GUI Win32.

Este texto é estudo próprio de bancada. Sem métrica inventada, sem screenshot gerado por IA, sem pitch de produto web. O que importa é o que o código e o README documentam, e como isso se traduz em ferramenta de oficina: utilitário que o técnico abre no notebook de manutenção, confirma uma ação e fecha — sem depender do Visual Studio completo nem de runtime Python.

Dependências que o README fixa

Três peças, nessa ordem mental:

  1. Chocolatey — gerenciador de pacotes no Windows (chocolatey.org/install).
  2. choco install make — traz make para repetir o mesmo hábito de build usado no Linux.
  3. LLVM — downloads oficiais em releases.llvm.org; o makefile do repo chama clang.

A decisão de projeto por trás disso: não depender do Visual Studio completo só para um hello GUI. Em notebook de engenharia ou imagem enxuta de manutenção, Chocolatey + LLVM + Make cabem no SOP. Quem já tem MSVC pode adaptar; o estudo escolhe Clang de propósito, alinhado ao makefile do c_gui_linux (CC = clang).

Na prática de TI industrial, Chocolatey exige política de admin. Trate isso como requisito de comissionamento da bancada, não como “atalho pessoal”: documente quem pode instalar, qual versão do LLVM foi validada na imagem, e se o antivírus precisa de exclusão para a pasta de build. Ferramenta de oficina que só o autor consegue compilar não é ferramenta — é hobby no pen drive.

Duas pastas, dois contratos com o SO

hello/       → processo de console
hello_gui/   → processo de janela (subsystem GUI / WinMain)

Essa divisão é o coração pedagógico do repo. Console e GUI no Windows não são o mesmo tipo de processo. Trocar main por WinMain e incluir windows.h muda entry point, subsystem do linker e expectativas sobre stdout. Quem ignora isso passa uma tarde achando que “o MessageBox não funciona” quando o problema é PATH do clang ou makefile rodando na pasta errada.

hello — validar a toolchain antes da GUI

hello.c é o mínimo absoluto:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf("hello");
    return 0;
}

Makefile:

all: hello.c
    clang -o hello hello.c

Por que isso existe num repo de “C GUI”? Porque metade dos problemas de “não abre a janela” na bancada Windows são, na verdade, PATH, clang, make ou antivírus atrapalhando o build. Se hello.exe imprime hello no console, a ferramenta de compilação está viva. Só então você sobe para Win32.

Roteiro de isolamento (pass/fail, sem métrica de tempo):

  1. where clang e where make no Prompt — ambos resolvem?
  2. cd hello && make — gera hello.exe?
  3. Rodar hello.exe — imprime hello?
  4. Só então cd ../hello_gui && make.

Se o passo 1 falha, pare. Instalar LLVM e reabrir o terminal (PATH novo). Se o passo 2 falha com erro de comando, o problema ainda não é Win32. Subir complexidade cedo demais é o jeito mais caro de aprender.

hello_gui — o salto para a API de usuário

#include <stdio.h>
#include <windows.h>

#pragma comment (lib, "User32.lib")

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
{
    printf("hello");
    MessageBox(NULL, "Goodbye, cruel world!", "Note", MB_OK);
    return 0;
}

Makefile idêntico em espírito:

all: hello_gui.c
    clang -o hello_gui hello_gui.c

Pontos técnicos que o estudo força você a notar:

Detalhe Por que importa
WinMain em vez de main Entry point de aplicativo Windows com parâmetros de instância e show
windows.h Porta de entrada das APIs Win32
#pragma comment (lib, "User32.lib") Pede link com User32 (MessageBox mora aí); com Clang/MinGW o link às vezes exige flag explícita — anote o que funcionar na sua instalação
MessageBox(..., MB_OK) Diálogo modal nativo: bloqueia até o operador clicar

O printf("hello") dentro do WinMain é detalhe de aprendizado: em binário GUI puro, stdout pode não ter console. Em debug com terminal anexado, você ainda vê a linha. Em deploy de painel, use log em arquivo ou OutputDebugString — não conte com console do operador. O técnico de campo não vai abrir o Prompt para ver se o utilitário “falou hello”.

Sobre o #pragma comment: em ecossistema MSVC ele é idiomático. Com Clang no Windows, o comportamento depende de como o LLVM foi instalado e de qual linker entra na jogada. Se o link falhar reclamando de MessageBox, o próximo passo honesto é acrescentar flag de link explícita no makefile (-luser32 ou caminho equivalente) e documentar no README da ferramenta o que funcionou naquela imagem — não ficar com “no meu PC compila” eterno.

Ponte industrial: Windows no chão vs Linux no painel

Na prática da Wilson Tecnologia e de muita oficina brasileira, o mapa costuma ser:

  • PC de engenharia / manutenção — Windows; drivers de IHM, software de CLP, Excel, PDF.
  • Painel Linux — imagem controlada, menos “surpresa” de update, bom para app nativo GTK.
  • HMI do fabricante — caixa fechada; você não reescreve o runtime.

c_gui_win treina a camada em que você escreve ferramenta auxiliar no Windows: utilitário que abre, mostra um status, confirma uma ação, talvez depois leia um CSV ou manda um comando serial. Não substitui SCADA. Complementa.

Exemplos de encaixe realista (escopo pequeno):

  • diálogo “Confirma gravação do parâmetro X?” antes de um script de manutenção;
  • aviso modal quando arquivo de receita não foi encontrado;
  • hello estendido depois com campos mínimos (IP, porta, caminho de log) numa janela própria;
  • launcher que dispara outro .exe de diagnóstico e reporta código de saída.

Exemplos de não encaixe:

  • reescrever a IHM touch da célula;
  • trilha de auditoria multiestação;
  • qualquer coisa com requisito de segurança de máquina atribuído à UI.

Comparando com o irmão Linux:

c_gui_linux c_gui_win
Toolkit GTK3 Win32 (MessageBox / User32)
Entry main + gtk_main / GtkApplication WinMain
Build pkg-config + clang clang + make via Chocolatey
Próximo passo natural widgets GTK, CSS, .desktop janela própria (CreateWindow), message loop, controles

O paralelo pedagógico é intencional: mesmo rigor de makefile, duas famílias de API. Quem domina os dois não fica refém de “só roda no meu Ubuntu” ou “só no Visual Studio da fábrica”.

Message loop: o que o repo ainda não mostra (e você precisa saber)

MessageBox é atalho: a API cria a janela modal e o loop interno. Um painel de verdade exige:

  1. Registrar classe de janela (WNDCLASS / WNDCLASSEX).
  2. CreateWindowEx.
  3. Loop GetMessage / TranslateMessage / DispatchMessage.
  4. WndProc tratando WM_COMMAND, WM_CLOSE, WM_DESTROYPostQuitMessage.

Esse é o equivalente Win32 do gtk_main() e dos sinais GObject. O repo para no primeiro diálogo de propósito — igual ao activate vazio do startGtkApp.c no Linux. O valor está em fechar o ambiente e o primeiro binário GUI linkado.

Por que parar no MessageBox não é preguiça: é controle de escopo de laboratório. O message loop completo introduz imediatamente subclassificação de controles, recursos (LoadIcon, LoadCursor), e decisões de Unicode (W vs A). Tudo isso importa — mas só depois que clang, make e o link com User32 estão estáveis. Empilhar “hello incompleto + CreateWindow + serial + log” no mesmo fim de semana é receita de repo abandonado.

Quando for além do MessageBox, priorize nesta ordem:

  1. Janela vazia que fecha limpo (WM_DESTROYPostQuitMessage).
  2. Um botão e um estático de texto — feedback visível de clique.
  3. Separar I/O bloqueante do WndProc (mesmo problema do callback GTK: não travar o loop).
  4. Só então falar com equipamento.

Antivírus, PATH e a realidade do PC de manutenção

Três atritos recorrentes em Windows de oficina, todos fora do código-fonte:

  1. SmartScreen / antivírus.exe novo sem assinatura assusta política corporativa. Planeje como o binário chega ao PC (pasta aprovada, hash documentado, não “baixe do Zap”).
  2. PATH de sessão — instalou LLVM, mas o Prompt aberto ainda é o antigo. Feche e abra o terminal; confirme com where clang.
  3. Mistura de toolchains — MinGW de uma instalação, LLVM de outra, Make do Chocolatey. O makefile curto do repo ajuda porque não esconde flags em vinte variáveis; ainda assim, anote qual clang respondeu.

Nenhum desses problemas se resolve com mais widget. Resolvem com SOP de bancada.

Empacote mental para oficina

Antes de crescer o código, documente no SOP da bancada:

  1. Instalar Chocolatey (política de admin).
  2. choco install make.
  3. Instalar LLVM e garantir clang no PATH.
  4. cd hello && make → validar.
  5. cd hello_gui && make → validar MessageBox.
  6. Só então criar pasta ferramenta_xyz com o mesmo padrão de makefile.

Para distribuição ao técnico de campo: um .exe + DLLs do runtime (se houver) + README de versão. Evite depender de “abra o Visual Studio e rode”. Make + Clang aproximam o fluxo Windows do fluxo Linux — o mesmo cérebro opera os dois painéis.

Checklist de entrega (conteúdo, não marketing):

  • nome do utilitário e o que ele não faz;
  • versão do LLVM/Clang usada no build;
  • comando make e pasta de origem;
  • comportamento esperado do MessageBox / da janela;
  • como reportar falha (print da mensagem de erro, não “não abriu”).

Quando escolher esta trilha

Escolha C + Win32 quando:

  • o PC alvo é Windows e você quer binário nativo sem runtime Python;
  • a UI é enxuta (status, confirmação, poucos campos);
  • auditoria e dependências mínimas importam mais que velocidade de prototipagem;
  • o time já pensa em C no restante da bancada (MCU, drivers, utilitários).

Prefira PyQt6 (pyqt6_book) quando o formulário cresce (menus, PDF, grids, temas). Prefira Kivy (kivy_Framework) quando o operador trabalha em touch full-screen e o objetivo ainda é protótipo de interação. Prefira GTK no Linux (c_gui_linux) quando o painel já é Debian/Ubuntu LTS.

Há também o meio-termo honesto: protótipo em PyQt6, utilitário crítico mínimo em Win32. Não é dogma — é reconhecer que produtividade de formulário e previsibilidade de deploy não sempre cabem na mesma stack.

Ligação com o restante da família de estudos

A série de GUIs do portfólio não compete consigo mesma; ela marca contratos:

  • c_gui_win — entry Win32 + toolchain Chocolatey/LLVM;
  • c_gui_linux — GTK3 + pkg-config;
  • pyqt6_book — formulário de engenharia + PDF + PyInstaller;
  • kivy_Framework — canvas/touch + .kv + dor de --add-data.

Usar o MessageBox como “HMI final” seria overclaim. Usar o MessageBox como prova de que a ponte console→GUI está viva é exatamente o tamanho do repo. Em conteúdo técnico para oficina, tamanho certo gera mais confiança do que feature inventada.

Do MessageBox ao utilitário de manutenção: escopo controlado

Depois que hello_gui.exe mostra o diálogo, a tentação é abrir tutorial de common controls e desenhar um painel inteiro numa tarde. Em oficina, o caminho mais seguro é outro: um utilitário, uma responsabilidade.

Exemplos de escopo que cabem na evolução natural deste repo sem virar SCADA:

  • ler um arquivo de configuração local e exibir três campos em labels;
  • pedir confirmação modal antes de sobrescrever receita;
  • gravar um timestamp em log texto quando o operador confirma;
  • falhar de forma visível se o arquivo não existe (MessageBox de erro, não crash silencioso).

O que adiar de propósito:

  • login/senha sofisticado (outro domínio de requisito);
  • comunicação com CLP antes da janela fechar limpo;
  • temas visuais e owner-draw — primeiro texto legível e botão que responde.

Essa contenção parece conservadora. É operacional: cada feature nova no Win32 puxa mais superfície de Unicode, recursos e teste em máquina limpa. O laboratório c_gui_win existe para deixar a base inegociável — toolchain e primeiro binário GUI — antes da lista de desejos da planta.

Conclusão

c_gui_win é o exercício de disciplina: Chocolatey, Make, LLVM, hello e hello_gui. Do printf ao MessageBox você valida a ponte entre console e GUI no Windows — base para utilitários de manutenção e futuros painéis simples. O HMI industrial completo virá de requisitos (tags, alarme, receita); a bancada começa aqui, com toolchain que você controla. Se o build não repete em máquina limpa, o widget seguinte é irrelevante. Se repete, você tem o mesmo tipo de fundamento que o makefile GTK oferece no Linux — e a oficina ganha uma linguagem comum de entrega nos dois sistemas.