Skip to content

Developer Guide

KaiUR edited this page May 13, 2026 · 13 revisions

Developer Guide

Prerequisites

  • LLVM/Clang 17+ — C compiler (clang-cl.exe, the MSVC-compatible Clang driver)
  • Visual Studio 2019+ (or Build Tools for Visual Studio) — provides Windows SDK, rc.exe, and link.exe
  • CMake 3.16+
  • Ninja build system
  • Git
  • Qt Creator (optional, as IDE)

Building

Open a Developer Command Prompt for VS, then:

git clone https://github.com/KaiUR/CatiaMenuWin32
cd CatiaMenuWin32
cmake -S . -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang-cl
cmake --build build

The executable is output to build/CatiaMenuWin32.exe.

Qt Creator

  1. Open CMakeLists.txt in Qt Creator
  2. Select a Clang kit configured with the MSVC toolchain
  3. Add -DCMAKE_C_COMPILER=clang-cl to the CMake arguments
  4. Build → Build All

Tip: Launch Qt Creator from a Developer Command Prompt for VS so that rc.exe and the Windows SDK are on the PATH.

CI/CD

The workflow (.github/workflows/release.yml) runs on windows-latest using:

  • ilammy/msvc-dev-cmd — sets up the MSVC environment (Windows SDK, rc.exe, link.exe)
  • LLVM/Clang (pre-installed on windows-latest) as the C compiler
  • Ninja as the build backend

On a tagged release (v*) the workflow additionally:

  1. Builds with -DCMAKE_C_COMPILER=clang-cl -DVERSION_OVERRIDE=<version>
  2. Authenticode-signs CatiaMenuWin32.exe via PowerShell + signtool.exe (x64)
  3. Commits the incremented build_number.txt back to main as a verified bot commit
  4. Creates a lightweight tag on the verified commit and publishes the GitHub Release

Code signing secrets

The following secrets must be set in Settings → Secrets → Actions:

Secret Description
CERTIFICATE Base64-encoded PFX file
PASSWORD PFX password
CERTHASH SHA1 thumbprint of the certificate
CERTNAME Common name of the certificate

Project Structure

src/         C source and header files
res/         Resource files (icons, manifest, resource.rc.in, version.h.in)
docs/        GitHub Pages documentation
.github/     GitHub Actions workflows and issue templates

Key Source Files

File Purpose
main.c / main.h Entry point, WndProc, AppState struct
window.c Window creation, menu, toolbar, layout
tabs.c Custom tab bar, script buttons, filter
paint.c GDI painting, script button rendering, tooltips
sync.c GitHub sync thread, manifest, offline cache
github.c HTTPS requests, JSON parsing, SHA verification
runner.c Script execution, Python detection
meta.c Script header metadata parsing
settings.c Settings load/save, Settings dialog
sources.c Script Sources dialog
prefs.c Favourites, hidden scripts, notes, run counts
help.c In-app help window
updater.c Update checker and auto-update
quickbar.c Floating Quick Launch Bar

Versioning

  • Version is determined from the latest Git tag at CMake configure time
  • build_number.txt increments by 1 on every CMake configure (local and CI)
  • Local builds show a (local) suffix and skip the update check
  • CI workflow: tag push → build → sign → release → commit build_number.txt back to main

Releasing

  1. Develop on develop branch
  2. Open a pull request to main
  3. Merge the PR
  4. Tag from main: git tag v1.x.x && git push origin v1.x.x
  5. GitHub Actions builds, signs, and creates the release automatically

Code Style

  • C11, Win32 API only — no external libraries

  • Unicode throughout — WCHAR, L"" literals, _snwprintf_s

  • Memory-safe functions only — always use _s (C11 Annex K) or bounded variants; never use functions flagged by clang-analyzer-security.insecureAPI:

    Never use Use instead Notes
    strcpy, wcscpy strcpy_s, wcscpy_s always pass _countof(dest)
    strcat, wcscat strcat_s, wcscat_s always pass _countof(dest)
    strncpy, wcsncpy strncpy_s, wcsncpy_s _s variant guarantees NUL termination
    sprintf, swprintf sprintf_s, swprintf_s pass _countof(buf)
    snprintf, _snwprintf _snprintf_s, _snwprintf_s use _TRUNCATE as the count argument
    fprintf fprintf_s
    vsprintf, vswprintf vsprintf_s, vswprintf_s
    gets fgets
    memcpy memcpy_s pass destSize then count
    memmove memmove_s pass destSize then count
    memset (zeroing secrets) SecureZeroMemory prevents compiler from eliding the zero
  • All GDI painting double-buffered

  • All state in global AppState g struct

  • Heap memory for scripts — use Folder_Alloc / Folder_Free / Folder_Push helpers; always free on every exit path

  • Use COL_BG(), COL_TEXT() etc. — never hardcode RGB values

  • Cross-thread communication via PostMessage only

Clone this wiki locally