Membuat aplikasi Todo Windows native murni dengan C (278KB, tanpa framework)
(github.com/Efeckc17)- Simple Todo adalah aplikasi Todo Windows native yang dibuat dengan C dan Win32 API, sebagai proyek yang menunjukkan pemrograman GUI Windows dan fitur integrasi sistem
- Fitur utamanya meliputi membuat, mengedit, dan menghapus Todo, menandai selesai, meminimalkan ke system tray, opsi mulai otomatis saat Windows berjalan, serta pencarian real-time tanpa membedakan huruf besar/kecil
- Data disimpan sebagai file biner di
%APPDATA%\TodoApp\todos.dat, berisi seluruh daftar Todo dan mendukung hingga 100 Todo - Build di Windows memerlukan MinGW-w64 dan Windows SDK, lalu dikompilasi dengan menjalankan
.\build.batsetelah me-clone repositori - Strukturnya dibagi menjadi
main.c,todo.c,gui.c, danutils/search.c, dengan GUI menggunakan Win32 API, Common Controls, dan UXTheme
Karakter proyek
- Simple Todo adalah aplikasi Todo Windows native yang ditulis dengan C dan Win32 API
- Tujuannya adalah executable native yang ringan, dengan tampilan dan nuansa bawaan Windows serta gaya visual Windows modern
- GUI-nya berbasis Win32 API, serta mencakup integrasi system tray dan persistensi data melalui file I/O
Fitur Todo
- Dapat membuat, mengedit, dan menghapus item Todo
- Tugas dapat ditandai sebagai selesai
- Setiap Todo dapat diberi prioritas
- Fitur pencarian bekerja secara real-time dan mendukung pencocokan tanpa membedakan huruf besar/kecil
- Aplikasi dapat diminimalkan ke system tray
- Menyediakan opsi untuk berjalan otomatis saat Windows dimulai
Cara penyimpanan data
- Data Todo disimpan di
%APPDATA%\TodoApp\todos.dat - Format penyimpanannya adalah file biner yang memuat seluruh daftar Todo
- Kapasitas penyimpanan dibatasi hingga 100 Todo
Build dan menjalankan
- Persyaratan
- Windows OS
- Kompiler GCC MinGW-w64
- Windows SDK yang disertakan dalam MinGW
- Langkah build
- Instal MinGW-w64 dan tambahkan direktori
binkePATHsistem - Clone repositori lalu pindah ke direktori
simple-todo-c - Jalankan
.\build.batuntuk melakukan build
- Instal MinGW-w64 dan tambahkan direktori
- Jalankan aplikasi melalui
bin/todo.exe
Susunan implementasi
- Struktur proyek dibagi ke file C berdasarkan fungsi
src/main.c: titik masuk aplikasisrc/todo.c,src/todo.h: logika pengelolaan Todo dan struktur datasrc/gui.c: implementasi GUIsrc/utils/search.c,src/utils/search.h: implementasi dan deklarasi fitur pencariansrc/app.manifest: manifest untuk gaya visual Windows
- Komponen inti mencakup Win32 API, Common Controls, UXTheme, dan File I/O
- Untuk debugging, tersedia panduan
DEBUGGING.mdyang bisa digunakan di Visual Studio, VS Code, dan lainnya
Lisensi dan kontribusi
- Lisensinya adalah MIT License
- Kontribusi diterima melalui Pull Request
3 komentar
Ada nuansa romantisnya.
Pendapat Hacker News
Ada sesuatu yang anehnya menarik dari pemrograman GUI Win32
Memang agak unik, tetapi kalau membaca blog Raymond Chen, alasannya jadi terlihat
Win32 API berakar dari era prosesor 8088, jadi ada latar belakang seperti menghemat 40 byte kode atau memakai satu register lebih sedikit jika dilakukan dengan cara tertentu
Dulu saya banyak membuat aplikasi GUI mainan dengan mingw dan buku Petzold, dan hal-hal seperti menulis custom control, menggambar grafik dan teks, menangani scrolling, serta hit testing semuanya cukup menyenangkan
Terlihat aplikasi ini memakai
strcpydansprintf; untuk pemrograman serius seharusnya memakai varian yang melakukan pemeriksaan panjang. Mengejutkan kompiler tidak mengeluarkan banyak peringatanWin32 API punya banyak fungsi yang menggantikan hal-hal di pustaka standar C. Jika benar-benar ingin mengecilkan ukuran executable, bisa mencoba menulis aplikasi tanpa pustaka standar C. Ada
ZeroMemory()sebagai penggantimemset(), danCopyMemory()sebagai penggantimemcpy()Pada titik tertentu, menulis kode C murni secara langsung memang mulai terasa menyakitkan, tetapi menurut saya untuk beberapa kali pertama, mencoba dengan C murni adalah cara terbaik untuk belajar. Dengan mengelola detail sendiri, selama belajar kita jadi lebih bisa merasakan apa yang terjadi di dalamnya
Jika ingin mencoba lebih jauh pemrograman GUI Win32, saya sarankan melihat WTL(Windows Template Library). Itu adalah wrapper C++ untuk Win32 API, sehingga perilakunya jauh lebih mudah dipahami
Meski fiturnya sangat banyak, ukurannya hanya sekitar 3MB berkat pendekatan itu. Tidak ada framework dan hanya satu executable tunggal, jadi saya berharap semua software masih dibuat seperti ini
strncpysebagai gantistrcpy, harus siap mendengar orang, bahkan alat AI, terus mengatakan bahwa itu tidak boleh dilakukanSecara pribadi, salah satu alasan utama saya memakai Zig adalah karena ia mengurangi banyak jebakan umum seperti ini. Tentu saja C juga baik-baik saja
ZeroMemory()sebagai penggantimemset()danCopyMemory()sebagai penggantimemcpy(), tetapi MSVC intrinsic sepertinya akan memakai instruksirep stos/movsItu bisa lebih kecil daripada pemanggilan fungsi, karena pemanggilan fungsi juga mencakup ukuran entri tabel import
fopen/fread/fclose, tetapi sepertinya tidak memakai Win32 API sepertiCreateFile/ReadFile/WriteFileAlih-alih susah payah memanggil
CreateWindow()untuk setiap kontrol, secara tradisional orang menempatkan resource dialog di file.rc(Visual Studio masih punya editor dialog untuk melakukannya secara visual) lalu memakaiCreateDialog()alih-alihCreateWindow()Dengan begitu semua kontrol dibuat otomatis. Jika menambahkan manifest aplikasi, kita juga bisa mendapatkan gaya UI modern dan dukungan high-DPI
Namun jika ingin mendukung perubahan ukuran, itu tetap harus ditangani manual, tetapi biasanya mudah dan kodenya tidak lebih dari beberapa ratus byte
K&R C memang ada, tetapi setiap sistem operasi di luar UNIX memilih sendiri fungsi apa yang disediakan
Selain itu, di tempat yang bukan keluarga UNIX, ada tradisi bahwa pustaka standar menjadi tanggung jawab kompiler C, bukan platform
Jadi pustaka C disediakan oleh Borland, Watcom, Symantec, Microsoft, Green Hills, Zortech, dan lainnya
Mac OS juga begitu sampai MPW muncul, begitu pula IBM dan Unisys, mikrokomputer dan mainframe, serta VMS sebelum OpenVMS
Sejak Windows 10 juga ada Universal C Runtime
Tidak perlu resource compiler, juga tidak perlu linker untuk membuat resource DLL
File resource dan format binernya bukan API yang bagus
Jika dalam bahasa tingkat cukup tinggi kita punya pemanggilan
CreateWindow, sepertinya kita bisa membuat DSL mirip resource yang menyatu baik dengan bahasa tersebut lewat metaprogrammingDulu saya pernah membuat sesuatu yang mirip di Linux dengan assembly dalam ukuran di bawah 2KiB: https://gaultier.github.io/blog/x11_x64.html
Seperti yang dikatakan orang lain, kalau dibuat dengan C murni dan memakai dynamic linking, setidaknya di Linux ukurannya mudah dijaga di bawah 20KiB. Windows mungkin malah lebih mudah karena jauh lebih banyak hal yang sudah termasuk bawaan sistem operasi
Bagaimanapun, saya mendukung upaya ini. Mencoba opsi linking yang saya tulis di akhir artikel saya akan membantu mengurangi ukurannya
Saya belum berhasil membangun ncurses dengan musl
Karena disebut “look and feel Windows native”, sebelum benar-benar menjalankannya saya berharap list view punya context menu, dan jika mengklik ganda field tertentu akan muncul menu dropdown atau text box yang nyaris inline
Sekarang saya tidak tahu apakah orang-orang sudah tidak tahu cara merancang program sesuai UI/UX Win32, atau saya saja yang sudah terlalu tua
Katanya “tanpa framework”, tapi font tampak buram pada DPI scaling, tidak ada dukungan Tab, Ctrl-A tidak bisa memilih semua di field teks, banyak fitur yang bahkan disediakan framework pra-modern pun hilang, dan saat menambahkan baris masih muncul error
Tidak tahu apa maksudnya “modern”
Kode ini secara dinamis memeriksa mana yang tersedia di antara
user32:SetProcessDpiAwarenessContext,shcore:SetProcessDpiAwareness,user32:SetProcessDPIAware, lalu memanggilnyaJika versi Windows-nya sangat lama sehingga tidak mengimplementasikan satu pun dari itu (sebelum Windows XP), tidak ada yang dipanggil
Sebagian besar fitur yang disebut hilang sangat mudah ditambahkan, terutama navigasi Tab antar-control
Programmer 6502 dalam diri saya perlahan mati melihat 278KB kini dianggap ringan
Hambatan pertama yang saya temui adalah file
build.battidak berfungsi jika git disetel kecore.autocrlf=false. Setelah mengubahnya kecore.autocrlf=truedan melakukan clone lagi, build bisa dilakukanToolchain yang saya gunakan adalah
x86_64-15.1.0-release-win32-seh-msvcrt-rt_v12-rev0.7zdari https://github.com/niXman/mingw-builds-binaries/releases/tag...Dalam kasus ini, yang dihasilkan adalah file
.exe102KB. Dari awal sudah jauh lebih baik daripada klaim 278KB. Bisa saja penulis memakai toolchain atau pengaturan lain, jadi akan bagus kalau ada langkah reproduksi yang persisDengan memberikan beberapa switch ke GCC, ukurannya bisa diperkecil lagi
gcc -Os=> 100KBgcc -Oz=> 99KBgcc -flto=> 101KBgcc -s=> 51KBgcc -s -Oz -flto=> 47KBKalau yang dipedulikan hanya ukuran
.exeyang kecil, masih banyak ruang untuk perbaikanTanpa hal-hal seperti informasi stack trace, infrastruktur dynamic linking, dan tabel exception handling, ukurannya bisa jauh lebih ringan. Tabel exception handling diperlukan bahkan di C karena exception bisa melewati fungsi C
Seingat saya, saat dulu pernah membuat yang seperti ini ukurannya lebih kecil. Mungkinkah karena MinGW?
Mungkin itu reaksi terhadap tren ukuran unduhan shareware yang makin membesar. Itu masa kelam MFC
Bersama pemrograman Palm Pilot 68k awal, saya mengingatnya sebagai sorak terakhir assembly yang bukan retrocomputing
Teman-teman, ini cuma aplikasi yang dibuat untuk dicoba dan bersenang-senang. Komentar-komentarnya benar, hal seperti ini mungkin bisa dibuat dengan lebih masuk akal memakai C++ atau bahasa lain
Entah kenapa, sepertinya dokumentasi Windows API mengarahkan penggunaan kode bergaya C dengan compiler C++. Microsoft tampaknya memandang C++ sebagai superset C yang lebih baik, dan menganggapnya tepat dipakai bahkan untuk kode bergaya C
Kalau memakai Win32 API, bahasa lain pada dasarnya tidak mengubah apa pun, malah bisa membuatnya lebih membingungkan
Orang sering terjebak dalam cara pikir C++, dan bagi orang yang belum akrab dengan Win32 API, itu hanya akan membuat semuanya menjadi gumpalan yang lebih membingungkan
Ini percobaan yang sangat manis, dan apa pun pendapat orang lain, keakraban dengan Win32 API adalah kemampuan dasar yang lumayan baik
Di sini terlihat cukup banyak sindiran dari orang-orang yang membuat software atau situs web yang memuat beberapa MB JS atau C# hanya untuk mengirim 278KB telemetri setiap kali pengguna menggerakkan mouse
Aplikasi ini memakai RAM 1,5MB, dan keduanya langsung terbuka
Saat mengembangkan aplikasi Windows, fakta bahwa semuanya bisa dilakukan dengan C selalu terasa menyenangkan
Cara membangunnya dari elemen dasar di level paling rendah terasa begitu alami
Sebaliknya di macOS, semuanya adalah objek Objective-C, jadi meski bisa menulis aplikasi dengan C murni, itu berarti turun satu lapis di bawah abstraksi yang dimaksudkan Apple, sehingga menjadi hampir 1000 kali lebih bertele-tele. Untuk melakukan sesuatu, pada dasarnya harus mengendalikan hierarki kelas Objective-C seperti boneka, dan itu benar-benar terasa tidak nyaman
Saya tidak mengerti kenapa API berbasis kelas Objective-C tidak bisa ditumpuk kembali di atas API prosedural dasar ala Win32. Secara teknis Win32 juga “berbasis kelas”, tetapi minimal
Karena itu, untuk sementara saya tidak terlalu terpikir untuk mem-porting kode C saya ke macOS
Namun compiler MIDL untuk antarmuka COM menghasilkan header yang memungkinkan antarmuka digunakan dan diimplementasikan dari C: https://www.codeproject.com/KB/com/com_in_c1.aspx
Sepengetahuan saya, ini masih berfungsi di WinRT hingga hari ini. Hanya saja nama struct dan fungsi C yang dihasilkan harus memuat seluruh namespace, sehingga sangat jelek: https://stackoverflow.com/a/7437006/111335
Itu hampir merupakan pengganti drop-in untuk Macintosh Toolbox API yang terang-terangan dijiplak oleh
user32.dllNamun selain rasa hangat yang dirasakan programmer, UI benar-benar menginginkan orientasi objek. Pohon berisi berbagai objek berbeda yang berbagi sebagian perilaku umum menjelaskan hampir 99% kode UI apa adanya
Toolbox dan Carbon cukup dipaksakan karena kurangnya orientasi objek semacam itu. Satu pemikiran orisinal yang benar-benar ditambahkan Windows adalah window class
Secara pribadi, keanehan yang terasa saat menangani kelas Objective-C langsung dari C, saya rasakan setiap kali harus mendefinisikan window class atau window procedure dalam kode
user32.dll[0]Sebagaimana UI menginginkan orientasi objek, orientasi objek menginginkan fitur bahasa khusus. Tanpanya tetap bisa dibuat, tetapi kegunaannya menjadi 2000 kali lebih buruk
[0] Atau apa pun yang berkaitan dengan GTK/GObject
Kelihatannya menautkan ke static library
Seharusnya menautkan ke DLL, bukan static library, dan dengan begitu ukuran aplikasi akan jauh berkurang
Kalau bagaimanapun DLL harus didistribusikan bersama program (karena bukan bagian dari sistem operasi), DLL itu berisi seluruh fungsionalitas, dan setiap DLL bahkan bisa memiliki C runtime-nya sendiri
Jika semuanya dikompilasi secara statis menjadi satu EXE, hanya ada satu C runtime, dan fungsi yang tidak digunakan pun bisa dengan mudah dihapus
DLL hanya mengurangi ukuran ketika kode itu dibagikan di antara beberapa program
Jika menautkan secara dinamis ke
MSVCRxx/VCRUNTIME, pengguna harus mengunduh DLL yang persis itu dari MicrosoftJika menautkan secara dinamis ke
MSVCRT, masalah itu tidak ada, tetapi sangat sulit dilakukan di Visual StudioSatu-satunya kasus di mana menautkan statis ke CRT benar-benar tidak boleh mungkin hanya untuk kepatuhan LGPL
Bro, rasanya seperti embusan napas kalian sampai terasa di sini...