शुद्ध C में बना नेटिव Windows Todo ऐप (278KB, बिना framework)
(github.com/Efeckc17)- Simple Todo एक नेटिव Windows Todo ऐप है जिसे C और Win32 API से बनाया गया है; यह Windows GUI programming और system integration क्षमताओं को दिखाने वाला project है
- मुख्य features में Todo बनाना·edit करना·delete करना, completed mark करना, system tray में minimize करना, Windows auto-start option, और case-insensitive real-time search शामिल हैं
- डेटा
%APPDATA%\TodoApp\todos.datमें binary file के रूप में save होता है, जिसमें पूरी Todo list रहती है और अधिकतम 100 Todo support होते हैं - build के लिए Windows पर MinGW-w64 और Windows SDK चाहिए; repository clone करने के बाद
.\build.batसे compile किया जाता है - structure
main.c,todo.c,gui.c,utils/search.cमें बँटा है, और GUI Win32 API·Common Controls·UXTheme का उपयोग करता है
Project की प्रकृति
- Simple Todo C और Win32 API में लिखा गया एक नेटिव Windows Todo application है
- इसका लक्ष्य हल्की native executable file है, और यह Windows का default look-and-feel और modern Windows visual styles इस्तेमाल करता है
- GUI Win32 API आधारित है, और इसमें system tray integration तथा file I/O के जरिए data persistence शामिल है
Todo features
- Todo items को बनाया, edit किया और delete किया जा सकता है
- tasks को completed status में mark किया जा सकता है
- हर Todo के लिए priority set की जा सकती है
- search feature real-time में काम करता है और case-insensitive matching support करता है
- app को system tray में minimize किया जा सकता है
- Windows startup पर auto-run करने का option देता है
Data storage तरीका
- Todo data
%APPDATA%\TodoApp\todos.datमें store होता है - storage format पूरी Todo list रखने वाली binary file है
- storage capacity अधिकतम 100 Todo तक सीमित है
Build और run
- Requirements
- Windows OS
- MinGW-w64 GCC compiler
- MinGW में शामिल Windows SDK
- Build process
- MinGW-w64 install करें और
bindirectory को systemPATHमें add करें - repository clone करने के बाद
simple-todo-cdirectory में जाएँ - build करने के लिए
.\build.batचलाएँ
- MinGW-w64 install करें और
- execution
bin/todo.exeसे शुरू होता है
Implementation structure
- project structure functionality के अनुसार C files में बँटा है
src/main.c: application entry pointsrc/todo.c,src/todo.h: Todo management logic और data structuressrc/gui.c: GUI implementationsrc/utils/search.c,src/utils/search.h: search feature implementation और declarationssrc/app.manifest: Windows visual styles के लिए manifest
- core components Win32 API, Common Controls, UXTheme, File I/O हैं
- debugging के लिए Visual Studio, VS Code आदि में इस्तेमाल हो सकने वाली
DEBUGGING.mdguide दी गई है
License और contribution
- license MIT License है
- Pull Request के रूप में contributions स्वीकार किए जाते हैं
3 टिप्पणियां
इसमें एक अलग ही रोमांस है।
Hacker News की राय
Win32 GUI प्रोग्रामिंग में कुछ अजीब-सा आकर्षक है
यह थोड़ा अनोखा ज़रूर है, लेकिन Raymond Chen का ब्लॉग पढ़ें तो वजह समझ आती है
Win32 API की जड़ें 8088 प्रोसेसर के दौर में हैं, इसलिए इसके पीछे ऐसे संदर्भ हैं कि किसी खास तरीके से करने पर code के 40 bytes बच जाते थे या एक register कम इस्तेमाल होता था
पहले मैंने mingw और Petzold की किताब से बहुत सारे toy GUI apps बनाए थे, और custom controls लिखना, graphics और text draw करना, scrolling handle करना, hit testing वगैरह सब काफी मज़ेदार था
app में
strcpy,sprintfका इस्तेमाल दिख रहा है, लेकिन serious programming के लिए length check करने वाले variants इस्तेमाल करने चाहिए। हैरानी है कि compiler ने warnings की बौछार नहीं कीWin32 API में C standard library की चीज़ों के विकल्प के तौर पर कई functions हैं। अगर executable size सच में घटाना हो, तो C standard library के बिना app लिखकर देख सकते हैं।
memset()की जगहZeroMemory(),memcpy()की जगहCopyMemory()हैएक समय के बाद pure C code सीधे लिखना दर्दनाक हो जाता है, लेकिन शुरुआती कुछ बार pure C में करना सीखने के लिए सबसे अच्छा लगता है। details खुद manage करने पर सीखते समय अंदर क्या हो रहा है, इसकी अच्छी समझ बनती है
अगर Win32 GUI programming और आज़माना चाहते हैं, तो WTL(Windows Template Library) देखने की सलाह दूंगा। यह Win32 API के ऊपर C++ wrapper है, जिससे behavior समझना काफी आसान हो जाता है
इसमें बहुत सारे features हैं, फिर भी इसी वजह से इसका size सिर्फ करीब 3MB है। कोई framework नहीं, सिर्फ एक single executable file है, इसलिए काश सारा software आज भी इसी तरह होता
strcpyकी जगहstrncpyनहीं इस्तेमाल करते, तो इंसानों के साथ-साथ AI tools भी लगातार कहेंगे कि ऐसा नहीं करना चाहिएनिजी तौर पर Zig इस्तेमाल करने की मेरी बड़ी वजहों में से एक यह है कि यह ऐसे common pitfalls को काफी कम कर देता है। हालांकि C भी ठीक है
memset()की जगहZeroMemory(),memcpy()की जगहCopyMemory()है, लेकिन MSVC intrinsic शायदrep stos/movsinstruction इस्तेमाल करेगायह function call से छोटा हो सकता है। क्योंकि function call में import table entry का size भी शामिल होता है
fopen/fread/fcloseभी इस्तेमाल हो रहे हैं, लेकिन लगता हैCreateFile/ReadFile/WriteFileजैसे Win32 API नहीं इस्तेमाल किए जा रहेहर control के लिए मेहनत से
CreateWindow()call करने के बजाय, परंपरागत रूप से.rcfile में dialog resources layout किए जाते थे(Visual Studio में अभी भी इसे visually करने वाला dialog editor है) औरCreateWindow()की जगहCreateDialog()इस्तेमाल होता थाइससे सारे controls अपने आप बन जाते हैं। application manifest जोड़ने पर modern UI style और high-DPI support भी मिल जाता है
हालांकि अगर resizing चाहिए, तो उसे अभी भी manually handle करना पड़ता है, लेकिन आम तौर पर यह आसान होता है और code भी कुछ सौ bytes से ज्यादा नहीं होता
K&R C था, लेकिन UNIX के बाहर हर operating system अपनी-अपनी मर्जी से features देता था
ऊपर से non-UNIX systems में standard library की जिम्मेदारी platform की नहीं, बल्कि C compiler की होने की परंपरा थी
इसलिए C library Borland, Watcom, Symantec, Microsoft, Green Hills, Zortech आदि देते थे
Mac OS में भी MPW आने तक ऐसा ही था, और IBM व Unisys, microcomputers और mainframes, OpenVMS से पहले VMS में भी यही था
Windows 10 से Universal C Runtime भी है
न resource compiler चाहिए, न resource DLL बनाने वाला linker
resource files और उनका binary format अच्छा API नहीं हैं
अगर किसी ठीक-ठाक high-level language में
CreateWindowcalls उपलब्ध हों, तो metaprogramming से language में अच्छी तरह घुल-मिल जाने वाला resource जैसा DSL बनाया जा सकता हैपहले Linux पर assembly में ऐसा ही कुछ 2KiB से कम में बनाया था: https://gaultier.github.io/blog/x11_x64.html
जैसा दूसरों ने कहा, pure C में बनाकर dynamic linking इस्तेमाल करें, तो कम-से-कम Linux पर इसे 20KiB से नीचे रखना आसान है। Windows में OS के साथ default में बहुत ज्यादा चीजें शामिल हैं, इसलिए शायद और आसान हो
खैर, कोशिश की सराहना करता हूं। मेरे लेख के अंत में दिए link options आज़माकर देखें, size घटाने में मदद मिलेगी
अभी तक musl के साथ ncurses build करके नहीं देख पाया
“native Windows look-and-feel” सुनकर, असल में चलाने से पहले मुझे उम्मीद थी कि list view में context menu होगा और किसी खास field पर double-click करने से लगभग inline dropdown menu या text box खुल जाएगा
अब समझ नहीं आता कि लोग Win32 UI/UX के हिसाब से program design करना नहीं जानते, या मैं ही बहुत बूढ़ा हो गया हूं
“Framework नहीं” कहा गया था, लेकिन DPI scaling में font धुंधला है, Tab support भी नहीं है, text field में Ctrl-A से पूरा select भी नहीं होता, और pre-modern frameworks तक जो कई features देते थे वे गायब हैं; row जोड़ने पर error भी आती है
“Modern” से मतलब क्या है, समझ नहीं आता
यह code
user32:SetProcessDpiAwarenessContext,shcore:SetProcessDpiAwareness,user32:SetProcessDPIAwareमें से जो उपलब्ध हो, उसे dynamically check करके call करता हैअगर Windows version इतना पुराना हो कि इनमें से कोई भी implement न हो (Windows XP से पहले), तो कुछ भी call नहीं करता
जिन missing features का जिक्र किया गया है, उनमें से ज्यादातर—खासकर controls के बीच Tab से जाना—जोड़ना बहुत आसान है
मेरे अंदर का 6502 programmer यह देखकर अंदर ही अंदर मर रहा है कि 278KB को अब lightweight माना जा रहा है
पहली बाधा यह मिली कि अगर git में
core.autocrlf=falseset हो, तोbuild.batfile काम नहीं करती।core.autocrlf=trueमें बदलकर फिर से clone किया, तो build हो गयाToolchain के लिए https://github.com/niXman/mingw-builds-binaries/releases/tag... का
x86_64-15.1.0-release-win32-seh-msvcrt-rt_v12-rev0.7zइस्तेमाल कियाइस case में 102KB की
.exefile बनी। बताए गए 278KB से शुरुआत ही काफी बेहतर है। हो सकता है author कोई और toolchain या settings इस्तेमाल कर रहा हो, इसलिए exact reproduction steps मिलें तो अच्छा होगाGCC को कुछ switches देने पर size और घटाई जा सकती है
gcc -Os=> 100KBgcc -Oz=> 99KBgcc -flto=> 101KBgcc -s=> 51KBgcc -s -Oz -flto=> 47KBअगर चिंता सिर्फ छोटी
.exesize की है, तो अभी काफी सुधार की गुंजाइश हैStack trace जानकारी, dynamic linking infrastructure, exception handling tables जैसी चीजें न हों तो यह बहुत हल्का हो सकता है। Exception handling tables C में भी जरूरी हैं, क्योंकि exceptions C functions को cross करके गुजर सकते हैं
पहले जब मैंने ऐसी चीज लिखी थी, तो याद है कि वह छोटी थी। कहीं MinGW की वजह से तो नहीं?
शायद यह shareware download sizes के बढ़ने के trend की प्रतिक्रिया थी। MFC का अंधकार युग था
शुरुआती Palm Pilot 68k programming के साथ, इसे मैं retrocomputing नहीं बल्कि assembly की आखिरी जयकार के रूप में याद करता हूँ
दोस्तों, यह बस एक बार try करके मजे के लिए बनाई गई app है। Comments सही हैं, ऐसी चीज C++ या किसी और language में ज्यादा rational तरीके से बनाई जा सकती थी
वजह ठीक से नहीं पता, लेकिन Windows API docs शायद C-style code को C++ compiler के साथ इस्तेमाल करने के तरीके से guide करते थे। लगता है Microsoft C++ को C का improved superset मानता था, और C-style code के लिए भी उसे इस्तेमाल करना सही समझता था
Win32 API इस्तेमाल करनी हो तो दूसरी language fundamentally कुछ नहीं बदलती, बल्कि चीजों को और उलझा सकती है
लोग अक्सर C++ वाली सोच में फँस जाते हैं, और जो लोग Win32 API से familiar नहीं हैं उनके लिए पूरा मामला और ज्यादा confusing mess बन जाता
यह बहुत cute attempt है, और दूसरे लोग कुछ भी सोचें, Win32 API से familiarity एक अच्छी basic skill है
यहाँ मुझे काफी लोग तंज कसते दिख रहे हैं, जो ऐसा software या websites बनाते हैं जो user के mouse हिलाते ही 278KB telemetry भेजने के लिए कई MB का JS या C# load करते हैं
यह app 1.5MB RAM इस्तेमाल करती है, और दोनों तुरंत start हो जाती हैं
Windows ऐप डेवलप करते समय यह बात कि सब कुछ C में किया जा सकता है, हमेशा अच्छा महसूस कराती है
सबसे निचले स्तर के बुनियादी हिस्सों से ऊपर की ओर बनाना बस स्वाभाविक लगता है
इसके उलट macOS में सब कुछ Objective-C object है, इसलिए शुद्ध C में ऐप लिखा तो जा सकता है, लेकिन यह Apple की intended abstraction से एक स्तर नीचे जाने जैसा है, और लगभग 1000 गुना ज़्यादा verbose हो जाता है। कुछ भी करने के लिए असल में Objective-C class hierarchy को कठपुतली की तरह चलाना पड़ता है, जो सच में असहज लगता है
समझ नहीं आता कि Objective-C के class-based API को बेसिक Win32-स्टाइल procedural API के ऊपर फिर से क्यों नहीं रखा जा सकता। तकनीकी रूप से Win32 भी “class-based” है, लेकिन बहुत minimal है
इसलिए फिलहाल अपने C code को macOS पर port करने का मन नहीं करता
लेकिन COM interface के लिए MIDL compiler ऐसे headers बनाता है जिनसे C में interface को use और implement किया जा सकता है: https://www.codeproject.com/KB/com/com_in_c1.aspx
मेरी जानकारी में यह WinRT में भी आज तक काम करता है। हालांकि generated C structs और function names में पूरा namespace शामिल करना पड़ता है, इसलिए वे बेहद बदसूरत हो जाते हैं: https://stackoverflow.com/a/7437006/111335
यह Macintosh Toolbox API का लगभग drop-in replacement था, जिसे
user32.dllने साफ़ तौर पर कॉपी किया थाहालांकि programmer को मिलने वाली गर्माहट को छोड़ दें, तो UI सच में object-oriented होना चाहता है। अलग-अलग objects का tree, जो कुछ common behavior share करते हैं, UI code के 99% को लगभग ज्यों का त्यों समझा देता है
Toolbox और Carbon में ऐसी object orientation की कमी थी, इसलिए उन्हें काफी खींचतान करनी पड़ी। Windows ने सच में जो एक ज़्यादा मौलिक विचार जोड़ा, वह window class था
निजी तौर पर C में Objective-C classes को सीधे handle करते समय जो अजीबपन महसूस होता है, वही मुझे
user32.dllcode में हर बार window class या window procedure define करते समय महसूस होता है[0]जैसे UI object orientation चाहता है, वैसे ही object orientation dedicated language features चाहता है। इनके बिना भी बनाया जा सकता है, लेकिन usability 2000 गुना खराब हो जाती है
[0] या GTK/GObject से जुड़ी हर चीज़
ऐसा लग रहा है जैसे static library से link कर रहे हों
static library नहीं, DLL से link करना चाहिए, तब application का size काफी कम हो जाएगा
अगर वैसे भी DLL को program के साथ ship करना है (क्योंकि वह operating system का हिस्सा नहीं है), तो DLL में पूरा feature set होता है और हर DLL का अपना C runtime भी हो सकता है
सब कुछ single EXE में statically compile करने पर C runtime सिर्फ एक होता है, और unused functions को आसानी से हटाया जा सकता है
DLL size सिर्फ तभी घटाता है जब वह code कई programs के बीच share होता है
MSVCRxx/VCRUNTIMEसे dynamic link करने पर user को Microsoft से ठीक वही DLL download करना पड़ेगाMSVCRTसे dynamic link करने पर यह समस्या नहीं होती, लेकिन Visual Studio में यह करना बहुत कठिन हैCRT से static link सच में गलत शायद सिर्फ LGPL compliance जैसे मामलों में होगा
लगता है बड़े भैया की साँस की गर्मी यहाँ तक पहुँच रही है...