10 ポイント 投稿者 GN⁺ 2025-05-12 | 3件のコメント | WhatsAppで共有
  • このオープンソースプロジェクトは、CとWin32 APIだけで作られた軽量なネイティブWindows Todoアプリケーション
  • フレームワークに依存せず、最小容量(最大26.5KB)で動作し、高度なWindows GUIとシステム統合を直接実装
  • Todo項目の追加、編集、削除、完了表示といった基本機能に加え、システムトレイ統合や自動起動オプションなど、実用的な生産性機能を提供
  • 保存はバイナリファイルで永続化され、AppDataフォルダに最大100件のToDoリストを保存
  • 大規模フレームワークなしでOSに非常に密着した古典的なプログラミング手法と、軽い実行環境が強み

🌟 Simple Todo (C / WinAPI)

プロジェクト概要

  • このプロジェクトは、CとWin32 APIだけを使ってモダンなネイティブWindows Todoアプリを作成
  • 高度なWindows GUIプログラミングとシステム統合能力を示す
  • プロジェクト容量は非常に小さく(最大26.5KB)、Windows本来の外観をそのまま維持

✨ 主な機能

  • ToDo項目の作成、編集、削除が可能
  • タスクを完了済みにできる
  • AppDataに永続保存され、常にデータが保持される
  • システムトレイと統合され、最小化時にトレイへ移動
  • ネイティブなWindowsスタイルの外観を備える
  • Windows起動時の自動実行オプションを提供

🛠️ 技術的な詳細

  • すべて純粋なCで記述
  • GUI実装にはWin32 APIのみを使用
  • 極小の実行ファイルサイズ(UPX圧縮時26.5KB)
  • システムトレイ統合機能
  • マニフェストによるモダンなビジュアルスタイルの適用

💾 データ保存

  • すべてのToDoは1つのバイナリファイルに保存
  • 保存パス: %APPDATA%\\TodoApp\\todos.dat
  • バイナリ形式で、最大100件の項目を保存可能

📋 必須要件

  • Windows OS環境が必要
  • MinGW-w64 (GCCコンパイラ) および Windows SDK が必要

🎮 使用方法

  • bin/todo.exe を実行後、インターフェースを使って以下の操作が可能
  • "Add" ボタンで新しいToDoを追加
  • 項目を選択後、"Edit" をクリックして修正
  • "Delete" で項目を削除
  • "Complete" で完了処理
  • 各項目の優先度を指定可能

🏗️ プロジェクト構成

  • src/ フォルダにメインエントリポイント(main.c)、ToDo管理ロジック(todo.c)、構造体宣言(todo.h)、GUI実装(gui.c) が存在
  • bin/ にコンパイル済み実行ファイルを配置
  • ビルドスクリプト(build.bat)とプロジェクト文書を含む

🔧 開発要素

  • Win32 API: ウィンドウ管理およびGUI全体の実装
  • Common Controls: モダンなUI要素を使用
  • UXTheme: Windowsビジュアルスタイル適用をサポート
  • File I/O: データの永続保存を実現

📝 ライセンス

  • MITライセンスで自由に使用・修正可能

🤝 コントリビューション案内

  • Pull Request歓迎
  • 誰でもプロジェクトに参加可能

📫 連絡先とリンク

3件のコメント

 
aer0700 2025-05-13

ロマンがありますね

 
GN⁺ 2025-05-12
Hacker Newsの意見
  • Win32 GUIプログラミングには好きなところがある。少し変わってはいるが、Raymond Chenのブログを読むとその理由が分かる。Win32 APIは8088プロセッサ時代に始まっていて、やり方次第でコードを40バイト節約できたり、レジスタを1つ少なく使えたりする。昔、mingwとPetzoldの本を見ながら、たくさんの簡単なGUIアプリを自分で書いたことがある。カスタムコントロール、グラフィック/テキスト描画、スクロール処理、ヒットテストなど、すべてを自分でやるのが本当に楽しかった。あなたのアプリでは strcpysprintf を使っているのが見えたが、真面目にプログラミングするなら長さをチェックする派生版を必ず使うべきだ。コンパイラがすぐ警告を出さなかったのが不思議なくらいだ。Win32 APIには標準Cライブラリ関数を置き換える関数が多い。実行ファイルサイズをもっと減らしたいなら、<Windows.h> だけを使って cstdlib なしで書いてみることを勧める。memset の代わりに ZeroMemorymemcpy の代わりに CopyMemory が使える。もちろん生のCコーディングはある時点で非常につらくなるが、最初の何回かは純粋なCで自分でやってみるのが学習にはいちばん役立つ。こういう細かい部分を扱う感覚が身につく。Win32 GUIプログラミングをもっとやってみたいなら、WTL (Windows Template Library) も勧めたい。Win32 APIをC++でラップしてくれるので、動作原理をずっと把握しやすくなる
    • 今どきは少なくとも strcpy の代わりに strncpy くらいは使うべきだ。そうしないと誰からも延々と指摘される。Zigを使う大きな理由の1つは、こういうありがちなミスが減ることだ。もちろんCでも問題ない
    • memset の代わりに ZeroMemorymemcpy の代わりに CopyMemory という話について、MSVCの組み込み関数は rep stos/movs 命令を使うので、関数呼び出しよりコードも小さくなり、importテーブルのサイズも減る
    • 自分も昔はこれをよくやっていたが、正直、ネイティブコードでネイティブUIを開発する能力が恋しい
    • memsetmemcpy の代わりに ZeroMemoryCopyMemory が提供されている理由についての質問。なぜわざわざ既存の標準Cライブラリの代わりにこういうものを作ったのか気になる
  • 昔は CreateWindow を毎回苦労して呼ぶより、.rc ファイルでダイアログリソースを書いて(Visual Studioにはダイアログエディタもある)、CreateDialog を使っていた。そうするとすべてのコントロールが一度に生成される。アプリケーションmanifestを追加するだけで、モダンなUIスタイルと高解像度DPIにも対応できる
    • この方式を使うと、コントロール間のTab移動のようなキーボードショートカット対応も自動で有効になる。ただし、サイズ変更のようなものは依然として自分でやる必要があるが、コードもすぐに書き足せるし難しくない
    • Petzoldの本にも出てくる方法なので、一度調べてみることを勧める
  • 自分も昔、似たようなものをLinux向けに2KiB以下のアセンブリで実装したことがある。Cで書いて動的リンクすれば、Linuxなら20KiB以内には簡単にできる。Windowsは内蔵機能が多いので、むしろもっと簡単だと思う。だからこういう試みは応援したい。記事の最後にあるリンカオプションを参考にすれば、サイズをさらに減らしやすいはずだ
  • フレームワークなしで作ると、DPIスケーリング時のフォントのにじみ、Tab対応なし、テキストフィールドでの Ctrl-A 選択のようなプレモダンなフレームワークでも当たり前の機能の大半が欠けるし、行追加時のエラーなどもある。それなのに、どの点でこれが「モダン」なのか気になる
    • DPI認識設定の例を添付する。コードはバージョンに応じてさまざまなWindows関数(user32:SetProcessDpiAwarenessContextshcore:SetProcessDpiAwarenessuser32:SetProcessDPIAware)でDPI認識設定を試み、かなり古いバージョンなら何も呼ばない
    • 「モダン」という言葉はふさわしくない。サイズばかり大きくて機能は不足している(コントロール間のTab移動は自前で簡単に実装できるが)
  • 6502でプログラミングしていた身としては、今や278KBですら軽量と見なされる現実がつらい
    • 自分がバイナリサイズを分析してみたところ、最初の障害は build.batcore.autocrlf=false の設定では正しく動かないことだった。これを core.autocrlf=true に変えてクローンし直したらビルドに成功した。mingwのあるツールチェインだと102KBの .exe が出る。つまり278KBよりずっと効率的だ。さらに減らしたければGCCに追加フラグを渡せばよい。gcc -s -Oz -flto で47KBまでいける。バイナリサイズだけに関心があるなら、改善の余地はかなりある
    • これくらいのサイズになるのはプラットフォームと実行ファイル形式のせいだ。スタックトレース情報、動的リンク基盤、例外処理テーブルなど、いろいろなものが容量を食う
    • デモシーンの大会に「64KB TODOアプリ」カテゴリを新設してほしい
    • 正直、こんなにサイズが大きいのは驚きだ。昔はアイコン容量を除けばもっと小さかった記憶がある。MinGWのせいなのだろうか
    • 6502? それはぜいたくだ。自分の時代はCPUすらないことも多かった
    • Win32アセンブリプログラミングが急に流行した時代を思い出す。特にシェアウェアのダウンロードサイズが大きくなっていた頃に注目されていた。初期Palm Pilotの68kプログラミングも思い出す。ノンレトロなアセンブリの最後の輝きのようだった
    • 15KBの quickrun.exe を作った人もいた。CとPure Win32 APIだけを使用。バイナリサイズ削減のための裏技はなし。Mingw32コンパイラを使用した、エイリアスで素早くアプリを起動するGUIアプリだ
    • 今夜はZ80、64KB RAMシステムをエミュレートする自分のエミュレータをデバッグしているところだ。こうして時代と環境がずいぶん変わったことを改めて感じることがある。それでも、サイズ増加に見合うだけのすさまじい進歩も実現してきたのではないかと思う
    • 8ビットから64ビットアーキテクチャまで、アドレスポインタ1つ取っても8倍大きくなった。文句を言うのではなく、こういう変化そのものが芸術であることを味わってみてほしい
    • 278KBなら5 1/4インチフロッピーディスクにぎりぎり入る容量だ
  • このアプリは楽しみでただ自分で作ってみたものだ。コメントで指摘されているように、もっと合理的にはC++や別の言語でやることもできただろうが、自分としてはとにかくやってみるのが楽しかった
    • 30年ほど前、自分もほとんど同じようにWindows最初のプログラムをこうやって作ったことがある。違うのは自分がC++コンパイラを使った点だ。当時はCスタイルのコードをC++コンパイラで書くのが公式ドキュメントでも案内される方法だった。C++はCの上位互換だったので、Microsoftもそうする傾向があった
    • 心から、Windows 11標準のTo-doアプリよりあなたのアプリのほうをずっと使いたい
    • Win32 APIを使うときは、どの言語を使っても本質はそれほど変わらない。むしろ言語を変えると余計に混乱することすらある。C++スタイルにこだわると、Win32 APIを初めて学ぶ人にはかえって混乱が増すかもしれない。こういうシンプルでかわいい個人プロジェクトでWin32 APIに慣れるのは、開発者としての基礎力だと思う
    • 別に YoutubeGO という自分の別アプリもあるので、よければ見てほしい
    • こういうきれいなネイティブUIプロジェクトこそ、自分がプログラミングを学び始めた動機だったので、共感するし褒めたい
  • Webやソフトウェアで278KBのテレメトリを送るためにメガバイト級のJSやC#をロードする文化が多い中で、こういう試みは新鮮だ
    • C# + WinFormsで作った似たアプリはディスク上で10KB未満、RAMは6MBしか使わない。このアプリはRAM使用量が1.5MBだ。どちらも起動すると即座に表示される
  • 今見ると静的ライブラリをリンクしたように見える。DLLでリンクすればアプリサイズは劇的に減るはずだ
    • それは少し逆だ。プログラムにDLLを必ず同梱しなければならないなら(そのDLLがOSに含まれていないなら)、各DLLが独自のCランタイムを含むので、かえって大きくなる。EXE1本に静的に全部入れれば、Cランタイムは1セットだけで済み、未使用関数も簡単に削除できる。DLLでサイズが減るのは、複数のプログラムが同じDLLを共有するときだけだ
    • CRT(ランタイムライブラリ)を静的リンクするほうが、むしろ不要なコードを減らすのに有利だ。DLLを動的リンクすると、VCRUNTIME DLLをMicrosoftから別途インストールしなければならないこともある。Visual StudioではMSVCRTへの動的リンクが難しいこともある。ただし、LGPL準拠が必要な場合は例外だ
  • 最近リリースされた高速ファイルエクスプローラのFile Pilotを思い出す。Cで作られていて、たった1.8MBしかない
  • 「モダン」「ネイティブ」なWindows Todoアプリだと言っているが、何が現代的なのか本当に疑問だし、C++で書けば多くの問題も防げてグローバル変数もなくせる。std::stringstd::arraystd::list、無名名前空間を使い、malloc もなくせば、コード量は半分になりバグも減るはずだ
    • グローバル変数は500行程度のアプリでは大して影響しないし、用途も明確だ。std::stringstd::list に置き換えたところで、実際のアセンブリ出力が同じになるわけではない。内部動作を本当に分かっていないのが見える
    • Petzoldの本でさえ最新版ではC++モードでVisual C++を使ってビルドし、C/C++共通構文を推奨している。Windows 95時代には、ほぼCだけで書く人はすでに少なく、VB、Delphi、C++へと主流言語は移っていた
    • 標準のstringやarray/listを使おうという意見について、WinAPIを直接使うくらいなら std::string より LPWSTR(ワイド文字列)を使うほうがAPIとの相性がよく、お勧めだ。char[] のような古い方法よりは LPWSTR を勧める。std::arraylist でコードが良くなるとも思えない
    • 現代的ではないが、こういう基礎寄りのプログラミングは根本の動作をきちんと理解する助けになる。問題も単純で理解しやすい。良い学習用プロジェクトだと思う。アセンブリ版でこの手のアプリを実装した例も気になる
 
roxie 2025-05-16

兄貴たちの鼻息がここまで伝わってくるような感じ…