[HN Gopher] I built a native Windows Todo app in pure C (278 KB,...
___________________________________________________________________
I built a native Windows Todo app in pure C (278 KB, no frameworks)
Author : toxi360
Score : 234 points
Date : 2025-05-11 15:57 UTC (7 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| vardump wrote:
| I think this Win32 app could be done in C under 20 kB.
| iforgotpassword wrote:
| Iirc mingw links its libc statically, that's probably why. Fwiw
| I still remember that an empty VB6 project with one form
| compiles to 20kb (16 if you select "optimize for size"). It
| still needs its VM, which is a dll that was considerably
| larger. I think about 1mb, but it's been a while.
| sixtram wrote:
| We shipped our VB6 software on a 1.44 MB floppy disk.
| Actually, we had to add some random stuff to the installer to
| make our software fit on two floppies instead of one, so that
| customers would think our application was more complex. Our
| CEO wanted to make sure that the end user had to eject disk 1
| and insert disk 2 during the installation. Sometimes you want
| to go big. So size matters.
| exe34 wrote:
| That's amazing! It reminds me of when a client once asked
| to make the red more red. I asked him to look at it again
| the next day and he said it was much better. I didn't have
| to do anything.
| SoftTalker wrote:
| Similar to programs like TurboTax that add delays and
| "working" animations to make the user think something
| really complicated is being achieved.
| chuckadams wrote:
| I remember TheGun, a Win32 notepad app in 6K, written in MASM.
| Anyone know where to find it?
| formerly_proven wrote:
| If you add a manifest you'll get post-Windows-2000 GUI styling.
| hard_times wrote:
| can you elaborate?
| torstenvl wrote:
| In my experience, the wxWidgets documentation and forums are
| pretty good resources for Windows manifest files. YMMV.
|
| An example from one of my projects:
| https://pastebin.com/Jvjn5C6S
|
| You need to reference it from your resource source like so:
| https://pastebin.com/8FUi4tMz
|
| And then compile that into an object file with windres:
| x86_64-w64-mingw32-windres rsrc/metadata/windows.rc -o
| winbuild/windowsrc.o
|
| And link it with your project like you would any other object
| file.
| trinix912 wrote:
| The entire structure is also documented on MSDN with all
| possible values - https://learn.microsoft.com/en-
| us/windows/win32/sbscs/applic....
|
| While MSDN is a bit impractical to browse (there's simply
| so much stuff in there) it's usually the best place to go
| to for documentation when doing Windows dev.
| torstenvl wrote:
| Strongly disagree. There's way too much mystery and magic
| number usage in the official documentation.
| crimsontech wrote:
| Can you recommend any good alternatives for someone
| looking to learn programming using windows APIs?
| fredoralive wrote:
| As well as information about side by side assemblies (ie:
| library versions), a Windows manifest file has various
| settings and a declaration of compatible versions of Windows
| that affect Windows' handling of the app, such as whether it
| can handle paths over MAX_PATH, if it is hi-dpi aware, or if
| it knows about themed controls.
|
| https://learn.microsoft.com/en-
| us/windows/win32/sbscs/applic...
|
| If an EXE doesn't have a manifest file, Windows assumes that
| it's ancient, so it falls back to conservative defaults like
| ye olde USER controls to try and avoid breaking it.
| MortyWaves wrote:
| I'd be interested in seeing a PR for that. I've always found
| the manifests a bit confusing.
| layer8 wrote:
| But why would you possibly want that? ;)
| Dwedit wrote:
| You can do it without a manifest too, it involves calling
| "CreateActCtxA" and "ActivateActCtx" with the appropriate
| Activation Context object. Manifest file is much easier.
| vparikh wrote:
| Looks like you are linking to static libraries. You should link
| to DLL not to static libraries - this is will cut down on the
| application size dramatically.
| TonyTrapp wrote:
| That seems backwards. If you need to ship the DLLs with the
| program anyway (they are not part of the operating system,
| after all), they will contain their full functionality, each
| one potentially with its own C runtime, etc. If you statically
| compile everything into a single EXE, there will be only a
| single C runtime, all unused functions can be trivially
| removed, etc.
|
| DLLs only reduce size if their code is meant to be shared
| between different programs.
| throwanem wrote:
| > they are not part of the operating system
|
| Yes they are. Exercising the native Windows API is the entire
| point of this project, and the only artifact it builds is an
| executable.
|
| _edit:_ See the thread; I had the wrong end here. I haven 't
| worked with Win32 or C in so long I'd forgotten what balls of
| fishhooks and hair they both tend to be.
| TonyTrapp wrote:
| The CRT is not part of the operating system, unless you
| count the UCRT on Windows 10 onwards (yes there is also a
| MSVCRT copy in the Windows folder that Microsoft strongly
| discourages you from using, so let's ignore that for now).
| So unless you link against the system-provided UCRT, you
| will have to either ship a dynamic or a static copy of the
| C runtime, and linking it statically _will_ be smaller
| because that will only contain the few string and time
| functions used by the program, instead of the whole CRT.
| throwanem wrote:
| The idea that something which ships with the OS, as a
| compatibility shim for legacy but still intentionally
| supported applications, can be called "not part of the
| OS," is religious. Strongly discouraged or otherwise, I
| believe it to be in use here.
|
| Not sure. I haven't really done anything serious with
| MinGW, or Cygwin or even Windows really, in at least a
| decade now. But there's not really a lot going on in the
| build here, so I would imagine with your much more recent
| experience you'd be better able to interpret what's
| there.
|
| _edit:_ Wait, are you even discussing the old (okay,
| ancient) Win32 API? I 'm confused, but as I said, it's
| been a very long time since I attended the space.
| TonyTrapp wrote:
| The important thing in the context of the original
| question is that mingw uses its own C runtime (MSVCRT is
| old and incomplete - you would not be able to use it as a
| drop-in replacement for a modern CRT). You can link the
| mingw CRT statically or dynamically, and OP suggested
| that linking it dynamically would reduce the size. But
| that is only true for the main executable. You would
| still have to ship the mingw CRT alongside, which in
| return would increase the distribution size of the
| program again.
|
| I hope that clears my point up.
| userbinator wrote:
| MSVCRT works perfectly fine for something with this
| feature set.
| TonyTrapp wrote:
| I really didn't want to get into the specifics, because
| the situation is already complex enough without MSVCRT,
| but: Yes, it is. If you wanted to do a size-optimzied
| version of this particular program, it would be a good
| enough choice.
| TonyTrapp wrote:
| Regarding your edit: the CRT is responsible for headers
| such as time.h and string.h, which you can find being
| used in todo.h. Their implementations are not provided by
| the operating system but by the C runtime typically
| supplied by the compiler (mingw in this particular case).
| Other headers such as windows.h belong to the WinAPI, and
| result in functions being imported from OS libraries such
| as user32.dll. They are obviously not linked statically
| into the program.
| throwanem wrote:
| Ugh, thanks. That clears it up.
|
| Say what you like about the modern JS ecosystem, the
| practical requirement of a single exhaustive declaration
| of all external dependencies and their sources is not to
| be sneered at.
| tacker2000 wrote:
| i get you, but this also introduces a whole other set of
| issues, like "dependency hell", where if you update one
| package you need to re-jig everything else. Things were
| just moving much slower back "in the days"
| throwanem wrote:
| Dep version clashes were a problem until iirc some time
| about mid-late last decade, say ~2017.
|
| These days it's perfectly solved at some cost in storage
| and memory, which in entire fairness are lately about as
| cheap as any other resource. There is also lately a
| movement in the space significantly away from "taking
| dependencies," a phrase I quote to highlight its
| pejorative connotation: presumptively undesirable,
| however necessary.
|
| If a large language model is satisfactorily efficient for
| 2025, then to scruple over the disk space and RAM used in
| the current model of exhaustive dependency resolution
| employed by modern JS/TS package managers, seems
| impossible to regard as other than ideologically
| motivated.
|
| In any case, I took some care earlier to avoid talking
| beyond the package.json dependency _declaration_ model,
| in hopes of forestalling precisely this bikeshed. If you
| want to talk further about things that don 't interest me
| in this context, please find someone else with whom to do
| so.
|
| (I don't wish to seem rude in this. Only that I have had
| that discussion too many more times than I can count, and
| I have long since stopped expecting it to vary noticeably
| in a given iteration.)
| jug wrote:
| Why would you not link against the UCRT if you're
| intentionally designing for Win32 though? It's a decade
| old library by now. Time flies...
| TonyTrapp wrote:
| Some people value being able to support older OSes
| without shipping the entire UCRT as an optional
| component. Granted, this will become less and less
| relevant in the future...
| 90s_dev wrote:
| You must not have worked with Win32 or C recently, they
| both tend to be giant balls of fishhooks and hair.
|
| _edit:_ Saw that you just now edited your comment, glad we
| 're on the same page now.
| throwanem wrote:
| Quite literally, it would seem! What an entirely
| remarkable coincidence.
| 90s_dev wrote:
| Call it a coincidence all you want, we both know you just
| copy/pasted my comment into your own edit.
| throwanem wrote:
| Bold, I'll give you that. Did we both get that from the
| UNIX-HATERS Handbook? I believe it originally described
| Perl, and not at all unjustly.
| 90s_dev wrote:
| Don't even have to go that far, it's word for word in
| Perl's own documentation. They've become self aware at
| some point it seems.
| throwanem wrote:
| And who could say it had been too long coming?
| pjmlp wrote:
| Not really, because this is Windows we are talking about.
|
| A traditonal Windows application would be using the Windows
| APIs, and not the C standard library, e.g. FillMemory()
| instead of memset(), thus there is no DLLs to ship with the
| application.
|
| As can be seen on Petzold books examples.
| TonyTrapp wrote:
| This code is not from the Petzold books. It literally
| includes and uses string.h, stdlib.h and time.h. It is
| _not_ using WinAPI equivalents of C functions.
| Dwedit wrote:
| No, linking to a static version of the CRT is a good thing, it
| cuts out the unused code. If you dynamic link to
| MSVCRxx/VCRUNTIME, you force the user to download that exact
| DLL from Microsoft. Dynamic linking to MSVCRT doesn't have that
| problem, but it's very hard to do in Visual Studio.
|
| The only time you really can't static link to the CRT is LGPL
| compliance?
| TonyTrapp wrote:
| Note that the project is using mingw, so it's not using any
| Microsoft DLLs for the CRT anyway. mingw brings its own CRT
| along.
| Dwedit wrote:
| I thought Mingw defaulted to MSVCRT.DLL as the CRT?
| TonyTrapp wrote:
| It looks looks mingw actually has several options to base
| its own CRT on (including MSVCRT, UCRT and various VS
| runtimes). Still, in the context of OP's original post,
| we are talking about the mingw DLLs that may or may not
| redirect most of their duties to Microsoft DLLs,
| depending on how mingw is configured.
| AaronAPU wrote:
| The 6502 programmer in me is dying inside that 278kb now passes
| as lightweight.
| nottorp wrote:
| Maybe we could petition the demo scene competitions to have a
| '64kb TODO app' category.
| Borg3 wrote:
| Hehe :) Okey.. I have sth easier to write.. but smaller:
|
| 15kB quickrun.exe :) C, pure Win32 API.. No hacks to shrink
| binary, Mingw32 compiler.
|
| Its GUI app to quickly launch any application via alias.
| jcelerier wrote:
| A lot of it is due to the platform and executable format.
| Things can be much more lightweight when there's no information
| for stack traces, no dynamic linking infrastructure, no
| exception handling tables (necessary even in C in case
| exceptions traverse a c function,) etc.
| userbinator wrote:
| _no dynamic linking infrastructure_
|
| You get that for free on Windows.
|
| _no exception handling tables (necessary even in C in case
| exceptions traverse a c function,_
|
| Not necessary if you're using pure C. SEH is rarely necessary
| either.
| kgabis wrote:
| 6502? Luxury! In my times you were lucky to have a processor.
| pineaux wrote:
| A processor? Luuuxury! In my time we worked twenty-six hours
| a day, did all the calculations with pen and paper and would
| be thrilled to use an abacus!
| psychoslave wrote:
| Ah, back in my early existence, we didn't have time and all
| these superficial dimensions. Ontological creation out of
| nothing was all one needed, but it looks like it's all lost
| art now.
| p0w3n3d wrote:
| you had paper? We had to use sand and sticks!
| p0w3n3d wrote:
| Btw. I love how you people refer to this sketch so
| seamlessly!
| mhd wrote:
| This reminds me of the days when all of a sudden win32
| programming in assembly became hip enough, probably as a
| response to the increasing size of shareware downloads ('twas
| the dark time of MFC).
|
| Combined with early Palm Pilot 68k programming, those were the
| last hurrahs of non-retrocomputing asm I can remember.
| tonyarkles wrote:
| That barely fits on a 5 1/4" floppy!
| stevekemp wrote:
| I'm spending some time this evening debugging a failure I have
| with an emulator I've written - it emulates a system running a
| Z80 processor with 64k of RAM.
|
| Sometimes I too take a step back and look at the way things
| have changed. But then again we've made a lot of progress for
| the size-changes I guess.
| jackjeff wrote:
| I'm surprised it's that big to be honest. I was expecting it to
| be smaller or half the size to be taken by some app icon. I
| remember writing this kind of stuff back in the days and it was
| smaller.
|
| Is it due to MinGw maybe?
| p0w3n3d wrote:
| it's about ABI, also 8bit << ... << 64bit architecture. Every
| pointer is 8 times longer. Don't complain, just admire. It's an
| art.
| abbeyj wrote:
| I tried to reproduce this binary to see what the 278 KB was
| being taken up by. The first obstacle that I ran into was that
| the build.bat file doesn't work if you have git configured to
| use core.autocrlf=false. Changing that to core.autocrlf=true
| and recloning was sufficient to get me building.
|
| I'm using x86_64-15.1.0-release-win32-seh-msvcrt-rt_v12-rev0.7z
| from https://github.com/niXman/mingw-builds-
| binaries/releases/tag... as the toolchain. This produces a 102
| KB .exe file. Right off the bat we are doing much better than
| the claimed 278 KB. Maybe the author is using a different
| toolchain or different settings? Exact steps to reproduce would
| be welcome.
|
| We can improve this by passing some switches to GCC.
| gcc -Os => 100 KB gcc -Oz => 99 KB gcc -flto =>
| 101 KB gcc -s => 51 KB gcc -s -Oz -flto => 47
| KB
|
| If all you are interested in is a small .exe size, there is
| plenty of room for improvement here.
| jedimastert wrote:
| > Maybe the author is using a different toolchain or
| different settings?
|
| I wonder if they are compiling with debugging symbols? I
| don't know how much this would change things in vanilla C but
| that would be my first guess
| azhenley wrote:
| If you had a blog or YouTube channel where you just went
| around to open source projects optimizing them down, I'd be
| very interested.
| dvdkon wrote:
| If you're going for a small EXE, I'd recommend telling GCC to
| optimise for size with "-Os".
|
| Link-Time Optimisation with "-flto" might also help, depending on
| how the libraries were built.
| RavSS wrote:
| I'd suggest `-Oz` instead, as it optimises for size above all
| else at the cost of performance, unlike `-Os` which is less
| aggressive (but likely produces similar code anyway). `-Oz` is
| somewhat new if I remember correctly, so it depends on the GCC
| version.
| slicktux wrote:
| Simple and elegant!
| Disposal8433 wrote:
| > A modern, native Windows Todo application
|
| What's modern about it? Also you could have used C++ instead to
| remove some potential issues, and those global variables...
|
| Use std::string and std::array or std::list, some anonymous
| namespaces, remove all the malloc, etc. Your code would be half
| the size and still compile to the same assembly language without
| the bugs.
| SoftTalker wrote:
| It's not modern but there's some value to programming close to
| the metal so you understand what's really going on. The problem
| domain is simple and easy to keep in your head. Good learning
| exercise. I wonder if there's an assembly language version of
| something like this.
| trinix912 wrote:
| > Use std::string and std::array or std::list /.../
|
| While nothing is modern about this approach, if we're going the
| WINAPI route, there's very little to be gained by using
| std::string instead of the LPWSTR that WINAPI offers (and plays
| nicely with). I would definitely avoid plain C strings (char[])
| but rather use the wide version (which is what LPWSTR is under
| the hood). But for std::array or std::list, I don't see how the
| codebase would vastly benefit from them.
| pjmlp wrote:
| In that case, make yourself a favour and use WIL, aka Windows
| Implementation Library.
|
| https://github.com/microsoft/wil
| musjleman wrote:
| > those global variables...
|
| What about them? In a 500 loc app there is no practical
| difference and there's only ~20 of them with clear purpose.
|
| > Use std::string <...> or std::list <...> remove all the
| malloc, etc
|
| > still compile to the same assembly language without the bugs.
|
| I see you have no clue what those things actually compile down
| to.
| pjmlp wrote:
| To note that even the latest editions of the famous Petzold
| book, before the C# edition, switched to using the common C
| subset from C++ and compiling with Visual C++ in C++ mode,
| instead of plain old C.
|
| Already by Windows 95 timeframe, only C diehards would be
| writing Windows applications still in C instead of VB, Delphi
| and C++, as the more mainstream languages, there were obviously
| other ones to chose from as well.
| tippytippytango wrote:
| The pedantry in the comments of a todo app is exquisite. HN never
| disappoints.
|
| Very nostalgic OP, warms my heart 10/10
| broken_broken_ wrote:
| I have done something similar for Linux under 2 KiB in assembly
| some time ago: https://gaultier.github.io/blog/x11_x64.html
|
| As others have said, doing so in pure C and linking dynamically,
| you can easily remain under 20 KiB, at least on Linux, but
| Windows should be even simpler since it ships with much more out
| of the box as part of the OS.
|
| In any event, I salute the effort! You can try the linking
| options I mentioned at the end of my article, it should help
| getting the size down.
| toxi360 wrote:
| Hello friends, I made this app just to try it out and have some
| fun, haha, but the comments are right, something like this could
| have been done more sensibly with C++ or other languages, ahaha.
| toxi360 wrote:
| https://github.com/Efeckc17/YoutubeGO By the way, you can also
| review or examine this application, I would be very happy :D
| drooopy wrote:
| Unironically, I would rather use your to-do app over the
| default Windows 11 one.
| toxi360 wrote:
| AHhhahah thanks
| tomtomtom777 wrote:
| This is exactly how I've learned to create my first Windows
| programs about 30 years ago, except that I'd use a C++
| compiler.
|
| I am not sure why but I believe writing C style code with a C++
| compiler was how the windows API was documented to be used. I
| think Microsoft just went with the idea that C++ was an
| improved superset of C so should be used even for C-style code.
| kmangutov wrote:
| This is exactly the sort of project (clean, native UI) that
| motivated me to learn programming, kudos!
| Johanx64 wrote:
| It's just the way it should be.
|
| Other language doesn't fundamentally change anything if you
| want to use win32 API, if anything it would make things more
| confusing.
|
| People often fall prey to C++isms, and they would have made the
| whole thing an even more confusing mess (to people not familiar
| with win32 API).
|
| This is a very cute thing to do and some familiarity with win32
| APIs is a nice basic competency thing, regardless of what other
| people think.
| pcunite wrote:
| Back in the day I used to use UPX to compress my executables to
| achieve impressively small sizes.
| jackjeff wrote:
| I remember doing that for some custom installer I wrote. It
| felt like a good idea for 5mins until it got flagged by a bunch
| of anti virus software... had to sign the installer in the end
| and spent a lot of time reporting false positives.
| dorianmariecom wrote:
| ready for enterprise todo
| eviks wrote:
| > no frameworks
|
| Checks out: blurry fonts in scaled dpi, no Tab support, can't
| Ctrl-A select text in text fields and do all the other stuff that
| pre-modern frameworks offered you, errors on adding a row, ...
|
| > modern
|
| In what way?
| userbinator wrote:
| It's "modern" in that it's much bigger than necessary, while
| missing a lot of functionality.
|
| (A lot of what you mention is missing is trivial to add,
| especially tabbing between controls.)
| card_zero wrote:
| I think font scaling is fixed (i.e. turned on) with
| SetThreadDpiAwarenessContext(-4). Or whatever the constant
| that equates to -4 is called.
| Dwedit wrote:
| Example of setting DPI awareness:
| https://github.com/Dwedit/GameStretcher/blob/master/Stretche...
|
| This code dynamically checks for and calls one of the
| following: user32:SetProcessDpiAwarenessContext,
| shcore:SetProcessDpiAwareness, then user32:SetProcessDPIAware.
| If the Windows version is extremely old and doesn't implement
| any of those (Windows XP or earlier), it won't call anything.
| sargstuff wrote:
| Ah isn't the user32:<windows api functions> a framework not
| related to 'pure' C?
| jchw wrote:
| Arguably, Windows itself is an object oriented UI
| framework.
| ghewgill wrote:
| The colons there don't represent C++. That's just a way of
| referring to a windows API function that exists in a
| specific DLL (in this case "user32"). Because the functions
| used here do not exist in older versions of Windows, the
| linked code dynamically loads user32.dll and tries to get
| the address of those functions so they can be called.
| That's why you need to know which Windows DLL they exist
| in.
| scq wrote:
| You can also set it in the application manifest, which is
| recommended over setting it programmatically:
| https://learn.microsoft.com/en-
| us/windows/win32/hidpi/settin...
| thehias wrote:
| 278kb? you are doing something very wrong, this should be
| possible in 10kb!
| musjleman wrote:
| The actual code in the repo definitely compiles to less than
| 10k. The rest is bloat from linking CRT statically.
| ghewgill wrote:
| I think the hard limit of 100 todos is the best feature of this.
| Why don't other todo apps have this feature?
| jonny_eh wrote:
| Some of us have a lot to do!
| userbinator wrote:
| I think 127 would make more sense.
| nu11ptr wrote:
| This is a blast from the past and it is neat to see some bare
| bones coding projects, but as others have said this is hardly
| "modern".
| userbinator wrote:
| That's more than 10x bigger than I expected, given that all it
| seems to do is manipulate a list view. Something like this should
| be doable in under 10KB.
| electroly wrote:
| Instead of laboriously calling CreateWindow() for every control,
| traditionally we would lay out a dialog resource in a .rc file
| (Visual Studio still has the dialog editor to do it visually) and
| then use CreateDialog() instead of CreateWindow(). This will
| create all the controls for you. Add an application manifest and
| you can get modern UI styling and high-DPI support.
| urbandw311er wrote:
| Great answer, helpful and not judgemental.
| belter wrote:
| Look it up in Petzold they used to say...
| userbinator wrote:
| You also get automatic tabbing between controls, and a few
| other keyboard shortcuts this way. Note that resizing them
| still needs to be done manually if you want that, but that's
| usually easy and not more than a few hundred bytes of code.
| p0w3n3d wrote:
| Great respect! I've tried many times, without final result. I'll
| try to use this for learning purposes!
|
| Btw. I like how Inno Setup used some very old Delphi 2 compiler
| to create exe so small it would fit without breaking the zip
| compliancy. I read it somewhere 10+ years ago, so not sure if
| this is still the case, but still. And the initial dialog was
| done in pure winapi.h (of course it was winapi.pas which made
| everything more difficult for me to learn from)
| hudo wrote:
| Less LOC than React/Redux app... Makes you think, what were we
| doing last 30 years :/
| Kwpolska wrote:
| I'm pretty sure an app as mediocre as this would take up less
| code in React, or even plain JavaScript. The UI is a single
| table and a few inputs and buttons, and its main way of
| communicating with the outside world is message boxes - trivial
| to do in a web browser.
| keepamovin wrote:
| Interesting! I was just looking at raylib for this kind of thing:
| super light weight, cross platform, reliable, ideally C-based
| method to get GUI.
|
| Raylib and raygui is truly incredible from my point of view. I
| succeeded in getting the macOS and Windows builds going on a
| bunch of cute little novel (not stock standard in the repo)
| examples in a matter of hours with AI help. I'm inspired by all I
| can do with this.
|
| For ages I felt "cut off" from the world of Desktop GUI because
| it was so verbose, and had high friction - need a bunch of
| tooling, set up, and so on. And then everything was fragile. I
| like to work quickly, with feedback, and PoCs and results. I
| think in raylib I have found a method that really achieves this.
| For instance, check out this tiny little "text_input.c"
| #define RAYGUI_IMPLEMENTATION #include <raylib.h>
| #include "deps/raygui.h" #define WINDOW_WIDTH 800
| #define WINDOW_HEIGHT 600 #define MAX_INPUT_CHARS 32
| int main(void) { InitWindow(WINDOW_WIDTH,
| WINDOW_HEIGHT, "Text Input Demo"); SetTargetFPS(60);
| // Load a larger font for better text appearance Font
| font = LoadFontEx("resources/fonts/arial.ttf", 32, 0, 0);
| if (font.texture.id == 0) { font =
| GetFontDefault(); // Fallback to default font if loading fails
| } // Set the font for raygui controls
| GuiSetFont(font); // Customize raygui styles
| (using BGR order for hex values) GuiSetStyle(BUTTON,
| TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); GuiSetStyle(BUTTON,
| BASE_COLOR_NORMAL, 0x50AF4CFF); // Green (B=80, G=175, R=76,
| A=255) ,Ui R=76, G=175, B=80 GuiSetStyle(BUTTON,
| TEXT_COLOR_NORMAL, 0xFFFFFFFF); // White text
| GuiSetStyle(BUTTON, BASE_COLOR_PRESSED, 0x6ABB66FF); // Lighter
| green GuiSetStyle(BUTTON, TEXT_COLOR_PRESSED,
| 0xFFFFFFFF); GuiSetStyle(BUTTON, BASE_COLOR_FOCUSED,
| 0x84C781FF); // Hover color GuiSetStyle(BUTTON,
| TEXT_COLOR_FOCUSED, 0xFFFFFFFF); GuiSetStyle(BUTTON,
| BORDER_WIDTH, 2); GuiSetStyle(BUTTON,
| BORDER_COLOR_NORMAL, 0x327D2EFF); // Dark green border
| // Adjust font size for raygui controls (optional, since font is
| already 32pt) GuiSetStyle(DEFAULT, TEXT_SIZE, 20); //
| Slightly smaller for button and text box to fit better
| GuiSetStyle(DEFAULT, TEXT_SPACING, 1); char
| inputText[MAX_INPUT_CHARS + 1] = "\0"; // Buffer for text input
| bool textBoxEditMode = false; // Tracks if the text box is being
| edited bool messageSubmitted = false; // Tracks if a
| message has been submitted float effectTimer = 0.0f; //
| Timer for the flash effect const float effectDuration =
| 0.5f; // Flash duration in seconds while
| (!WindowShouldClose()) { // Update effect timer
| if (effectTimer > 0) { effectTimer -=
| GetFrameTime(); }
| BeginDrawing(); // Set background color based on
| effect if (effectTimer > 0) {
| ClearBackground((Color){ 255, 255, 150, 255 }); // Yellow flash
| (RGB order) } else {
| ClearBackground(RAYWHITE); } //
| Center the text box and button int textBoxWidth =
| 200; int textBoxHeight = 40; int
| buttonWidth = 120; int buttonHeight = 40;
| int textBoxX = (WINDOW_WIDTH - textBoxWidth) / 2;
| int textBoxY = (WINDOW_HEIGHT - textBoxHeight) / 2 - 40;
| int buttonX = (WINDOW_WIDTH - buttonWidth) / 2; int
| buttonY = textBoxY + textBoxHeight + 10; //
| Draw the text box if (GuiTextBox((Rectangle){
| (float)textBoxX, (float)textBoxY, textBoxWidth, textBoxHeight },
| inputText, MAX_INPUT_CHARS, textBoxEditMode)) {
| textBoxEditMode = !textBoxEditMode; // Toggle edit mode on click
| } // Draw the button if
| (GuiButton((Rectangle){ (float)buttonX, (float)buttonY,
| buttonWidth, buttonHeight }, "Submit")) {
| messageSubmitted = true; effectTimer =
| effectDuration; // Start the flash effect
| TraceLog(LOG_INFO, "Message submitted: %s", inputText);
| } // Display the submitted message
| if (messageSubmitted && inputText[0] != '\0') {
| const char *label = "Message: "; char
| displayText[256]; snprintf(displayText,
| sizeof(displayText), "%s%s", label, inputText);
| int textWidth = MeasureTextEx(font, displayText, 32, 1).x;
| int textX = (WINDOW_WIDTH - textWidth) / 2; int
| textY = buttonY + buttonHeight + 20;
| DrawTextEx(font, displayText, (Vector2){ (float)textX,
| (float)textY }, 32, 1, (Color){ 33, 150, 243, 255 }); // Bright
| blue (RGB order) } EndDrawing();
| } UnloadFont(font); CloseWindow();
| return 0; }
|
| I love it! I feel unleashed again to program in graphics and
| games and real GUI! The first real paid programming job I had was
| using a lot of ps5 in Java and JavaScript (Open Processing) and I
| dug it! :)
|
| And the file sizes are sweet (to me):
|
| - macOS: text_input - 123736
|
| - Windows: text_input.exe - 538909
|
| Two dependencies to distribute with on Windows: glfw3.dll and
| libraylib.dll (322K and 2.1MB respectively)
|
| Raylib was built to make game programming fun. And maybe I will
| use it for that! :) But right now I want to use it for GUI. The
| issue with Qt and others, is while I like the idea of standard-
| Andy controls, I don't want to pay a commercial license - when I
| figure "it can't be _that_ hard to get what I want " - as I plan
| to use this stuff for commercial/proprietary control-panes and
| layers on my existing products: BrowserBox, DiskerNet, and more.
|
| At the same time I really respect what Qt have done growing their
| business and might be inspired or even emulate some of their
| model myself in my business.
| bitwize wrote:
| Hell to the yes! int PASCAL WinMain(HINSTANCE
| hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int
| nCmdShow);
|
| If you know, you know.
|
| I'm to understand that entire divisions of Microsoft itself no
| longer know how to code anywhere near this level, which is why
| many of their flagship applications (looking at you, Microsoft
| Teams (work or school)) are Electron monstrosities you can watch
| draw themselves like Windows 1.0 apps -- on modern multicore
| hardware.
|
| EDIT: more correct function sig
| saurik wrote:
| I'm apparently so ancient I am just looking at that line of
| code thinking "isn't that the standard entrypoint for a Windows
| app?", lol; is there something else to know? ;P Oh! I guess,
| staring at it, isn't that wrong?... if you use LPCTSTR, one
| would expect that you are trying to be agnostic to UNICODE, but
| then you also have to use _tWinMain, no? (And, after
| considering that, I went and double-checked, and the C is also
| incorrect in this context.)
| mtlynch wrote:
| Thanks for sharing, OP!
|
| It's probably too late, but this qualifies for "Show HN" if you
| update the title to have the prefix "Show HN: ".[0]
|
| I think the size of the source is actually more impressive than
| the size of the binary. I'm impressed that you can implement the
| whole thing in what looks like about 1 KLOC in just four .c
| files.
|
| [0] https://news.ycombinator.com/showhn.html
| _bin_ wrote:
| Fun project! I think the smallest I ever shrunk a win32
| application was on the order of 2-4kb by writing in ASM. It was a
| great illustration of why 10x binary size is actually a great
| trade-off in terms of productivity.
| pshirshov wrote:
| If only I can do the same across 3 desktop and two phone
| platforms...
| fizlebit wrote:
| Me no like inconsistent use of spaces.
| x += labelW+20; hDescEdit =
| createModernEdit(hwnd, x, y, editW, btnH, ID_DESC_EDIT);
| x += editW + gap;
|
| What no clang-format or equiv in 1990?
| rfl890 wrote:
| There's no application manifest for the common controls so it
| will look outdated
| nsxwolf wrote:
| The Readme emojis tell me this was vibe coded.
| dochtman wrote:
| Curious what this would look like written in Rust, using the
| windows-rs bindings.
| masternight wrote:
| There is something I like about win32 gui programming. It's a
| little idiosyncratic, but if you read Raymond Chen's blog you'll
| see why.
|
| The win32 API has its origins on the 8088 processor and doing
| things a certain way results in saving 40 bytes of code or uses
| one less register or something.
|
| I wrote a lot of toy gui apps using mingw and Petzold's book back
| in the day. Writing custom controls, drawing graphics and text,
| handling scrolling, hit testing etc was all a lot of fun.
|
| I see in your app you're using strcpy, sprintf. Any kind of
| serious programming you should be using the length-checked
| variants. I'm surprised the compiler didn't spew.
|
| You'll also find that the Win32 API has a lot of replacements for
| what's in the C standard library. If you really want to try and
| get the executable size down, see if you can write your app using
| only <Windows.h> and no cstdlib. Instead of memset() you've got
| ZeroMemory(), instead of memcpy() you've got CopyMemory().
|
| At some point writing raw C code becomes painful. Still, I think
| doing your first few attempts in raw C is the best way to learn.
| Managing all the minutiae gives you a great sense of what's going
| on while you're learning.
|
| If you want to play more with win32 gui programming, I'd have a
| look at the WTL (Windows Template Library). It's a C++ wrapper
| around the win32 API and makes it much easier to reason about
| what's going on.
| userbinator wrote:
| _Instead of memset() you 've got ZeroMemory(), instead of
| memcpy() you've got CopyMemory()._
|
| I believe MSVC intrinsics will use the rep stos/movs
| instructions, which are even smaller than calling functions
| (which includes the size of their import table entries too.)
| rcarmo wrote:
| I spent a lot of time doing that and to be honest, I miss the
| ability to develop for native UIs with native code.
| scripturial wrote:
| At minimum, these days, if you dont use strncpy instead of
| strcpy, you'll have to suffer through every man and his dog
| forever telling you to do otherwise. (For me this is one of the
| main arguments of using zig, a lot of these common pitfalls are
| minimized by using zig, but c is fine as well)
| masternight wrote:
| Heh, and if you use strncpy() you'll have to suffer through
| me lecturing you on why strncpy() is the wrong function to
| use as well.
| burnt-resistor wrote:
| Contains numerous memory leaks, doesn't permit arbitrarily long
| lists, and saves and restores uninitialized data. Really sloppy.
| transcriptase wrote:
| Seeing a lot of chirps in here from people who work on software
| or websites that load megabytes of JS or C# or in order to send
| 278kb of telemetry every time the user moves their mouse.
| scripturial wrote:
| The allure of the perfect notes and todo app. Having gone through
| phases of various modern todo and note apps over the years, I've
| finally let it go and decided to embrace just using text files.
| (Neovim for me, not that it matters which text editor one uses)
|
| It's not that there aren't cool apps for this stuff, it's more
| that I have a trail of data across various todo and notes apps
| from years of different tools.
|
| One solution to the problem of making things "feel native" is to
| go all in on letting go of native. Target a different style, be
| it minimalism, Commodore 64, pixel art, etc... it can be fun that
| way, especially if it's mostly just a tool for you.
___________________________________________________________________
(page generated 2025-05-11 23:00 UTC)