13 ms·
I built a native Windows Todo app in pure C (278 KB, no frameworks)
- userbinator 1y agoThat'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.
- dorianmariecom 1y agoready for enterprise todo
- vardump 1y agoI think this Win32 app could be done in C under 20 kB.
- iforgotpassword 1y agoIirc 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 1y agoWe 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 1y agoThat'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 1y agoSimilar to programs like TurboTax that add delays and “working” animations to make the user think something really complicated is being achieved.
- chuckadams 1y agoI remember TheGun, a Win32 notepad app in 6K, written in MASM. Anyone know where to find it?
- mananaysiempre 1y agohttps://web.archive.org/web/20051230021217/http://www.movsd.com/thegun.htm https://web.archive.org/web/20051230021217/http://www.movsd....
- DarmokJalad1701 1y agohutch was a legend. RIP. https://forum.exetools.com/showthread.php?p=127834 https://forum.exetools.com/showthread.php?p=127834
- tom_ 1y agoI built it with VC++ and it's 23,552 bytes. Close enough. Command line: cl /Zi /MD /Os /Fetest.exe gui.c main.c todo.c comctl32.lib user32.lib gdi32.lib shell32.lib advapi32.lib /link /opt:ref /opt:icf
- mananaysiempre 1y agoSo, this uses the DLL version of the Microsoft CRT. Don’t know if that counts as cheating :) Why is a CRT needed here anyway, beyond very basic stuff like startup code and memcpy?.. Is MiniCRT[1] an option? [1] http://www.malsmith.net/minicrt/ http://www.malsmith.net/minicrt/
- tom_ 1y agoIt possibly isn't, and you can typically do without by telling VC++ to build without linking to it - though the compiler has a bad habit of generating calls to memcpy, so you may have to provide your own implementation of that (and hope the compiler doesn't spot what you're doing and helpfully replace it with a call to memcpy). But aside from that, it's easy enough. You don't need the CRT startup code; you can use WriteConsole to print to stdout/stderr; you can use LocalAlloc/LocalFree to allocate memory; there's a few string routines in the Win32 DLLs that are a bit like the C equivalents, if nothing in the ordinary Win32 API does what you want. I used to be into this stuff and created a number of useful <10 KB EXEs this way. I'm not sure it's really worth it though! I started out writing code for computers where you'd have like 16 KB free RAM, and this wasn't much, but for most purposes you didn't actually have to sweat every single last byte. So on the same basis, now that even my laptop (which is over 10 years old) has 16 GB RAM, I am not massively inclined to worry about anything less than 1 MB.
- ziml77 1y agoThe downside to me knowing how small programs can be if I don't link the CRT is that I can't help but feel like what I've written is terribly bloated if I don't make an effort to avoid the CRT. I blame people who constantly comment about how bloated software is now for making overly conscious of program size even when its down at a point where it doesn't matter :')
- formerly_proven 1y agoIf you add a manifest you’ll get post-Windows-2000 GUI styling.
- hard_times 1y agocan you elaborate?
- torstenvl 1y agoIn 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 https://pastebin.com/Jvjn5C6S You need to reference it from your resource source like so: https://pastebin.com/8FUi4tMz 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 1y agoThe entire structure is also documented on MSDN with all possible values - https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests 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 1y agoStrongly disagree. There's way too much mystery and magic number usage in the official documentation.
- crimsontech 1y agoCan you recommend any good alternatives for someone looking to learn programming using windows APIs?
- vparikh 1y agoLooks 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 1y agoThat 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 1y ago> 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.
- deleted 1y ago[deleted]
- TonyTrapp 1y agoThe 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 1y ago
- AaronAPU 1y agoThe 6502 programmer in me is dying inside that 278kb now passes as lightweight.
- nottorp 1y agoMaybe we could petition the demo scene competitions to have a '64kb TODO app' category.
- Borg3 1y agoHehe :) 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 1y agoA 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 1y agono 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 1y ago6502? Luxury! In my times you were lucky to have a processor.
- pineaux 1y agoA 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!
- dvdkon 1y agoIf 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 1y agoI'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.
- jcalvinowens 1y ago-Oz and -Os are basically identical with GCC in my experience. LLVM -Os is much less aggressive. Random example: https://news.ycombinator.com/item?id=39547329 https://news.ycombinator.com/item?id=39547329
- slicktux 1y agoSimple and elegant!
- Disposal8433 1y ago> 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 1y agoIt’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 1y ago> 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 1y agoIn that case, make yourself a favour and use WIL, aka Windows Implementation Library. https://github.com/microsoft/wil https://github.com/microsoft/wil
- musjleman 1y ago> 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 1y ago
- waltercool 1y ago[dead]
- tippytippytango 1y agoThe pedantry in the comments of a todo app is exquisite. HN never disappoints. Very nostalgic OP, warms my heart 10/10
- broken_broken_ 1y agoI have done something similar for Linux under 2 KiB in assembly some time ago: https://gaultier.github.io/blog/x11_x64.html 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.
- johnisgood 1y agoWell, my somewhat extended TUI (ncurses) TODO program is 15K. Linux. Not statically linked though. I did not get around to build ncurses yet with musl.
- toxi360 1y agoHello 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 1y agohttps://github.com/Efeckc17/YoutubeGO https://github.com/Efeckc17/YoutubeGO By the way, you can also review or examine this application, I would be very happy :D
- drooopy 1y agoUnironically, I would rather use your to-do app over the default Windows 11 one.
- toxi360 1y agoAHhhahah thanks
- tomtomtom777 1y agoThis 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.
- cesarb 1y ago> 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. And as a consequence, for a long time their official C compiler was stuck on C89, while other platforms already had full C99 support and beyond. I believe their support for newer C standards has gotten better since then, but AFAIK they still don't have full C99 support.
- kmangutov 1y ago
- pcunite 1y agoBack in the day I used to use UPX to compress my executables to achieve impressively small sizes.
- jackjeff 1y agoI 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.
- pjmlp 1y agoStill common today when dealing with Go executables.
- eviks 1y ago> 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 1y agoIt'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 1y agoI think font scaling is fixed (i.e. turned on) with SetThreadDpiAwarenessContext(-4). Or whatever the constant that equates to -4 is called.
- Dwedit 1y agoExample of setting DPI awareness: https://github.com/Dwedit/GameStretcher/blob/master/Stretcher/Main.cpp#L51 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.
- thehias 1y ago278kb? you are doing something very wrong, this should be possible in 10kb!
- musjleman 1y agoThe actual code in the repo definitely compiles to less than 10k. The rest is bloat from linking CRT statically.
- throwaway2037 1y agoAbove, someone shared this tip to compile down to 23,552 bytes. Ref: https://news.ycombinator.com/item?id=43957984 https://news.ycombinator.com/item?id=43957984 Can you share how you can compile to only 10kb?
- musjleman 1y agoBy "actual code" I meant the assembly that the application logic compiles down to, not the entire executable. But as far as the entire package goes, compiling it using clang with some flags I can get down to 19.5k without any effort. If I wanted to waste time on this, ripping out the CRT entirely and getting it to 16k would probably take less than an hour.
- ghewgill 1y agoI think the hard limit of 100 todos is the best feature of this. Why don't other todo apps have this feature?
- jonny_eh 1y agoSome of us have a lot to do!
- userbinator 1y agoI think 127 would make more sense.
- nu11ptr 1y agoThis 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".
- electroly 1y agoInstead 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 1y agoGreat answer, helpful and not judgemental.
- belter 1y agoLook it up in Petzold they used to say...
- userbinator 1y agoYou 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.
- kazinator 1y agoHowever, this approach is easily translatable to a language that has decent FFI, and requires nothing else: no resource compiler and linker to make a resource DLL. Resource files and their binary format are not a good API. If you have those CreateWindow calls in a decently high level language, you can probably meta-program some resource-like DSL that fits right in the language.
- int_19h 1y agoYou don't need a "resource DLL"; the compiled .rc file gets linked directly into the binary, and any Win32 C toolchain is capable of doing that, including MinGW. As API goes, I don't see what's wrong with it (anymore so than Win32 in general). And you do get quite a lot for free, as GP mentioned. Hi-DPI, for example - .rc files use "dialog units" to measure all widgets, which, unlike raw pixel values you pass to CreateWindow, are DPI-independent.
- p0w3n3d 1y agoGreat 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 1y agoLess LOC than React/Redux app... Makes you think, what were we doing last 30 years :/
- Kwpolska 1y agoI’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 1y agoInteresting! 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) ‚Üí 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 1y agoHell 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 1y agoI'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.)
- int_19h 1y agoFunnily enough, the "ANSI" versions of Win32 functions are no longer considered a legacy thing, now that the OS offers UTF-8 as the supported encoding, and apps can explicitly request it (regardless of non-Unicode codepage setting) via manifest: https://learn.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page https://learn.microsoft.com/en-us/windows/apps/design/global...
- mtlynch 1y agoThanks 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 https://news.ycombinator.com/showhn.html
- _bin_ 1y agoFun 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 1y agoIf only I can do the same across 3 desktop and two phone platforms...
- fizlebit 1y agoMe 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 1y agoThere's no application manifest for the common controls so it will look outdated
- nsxwolf 1y agoThe Readme emojis tell me this was vibe coded.
- dochtman 1y agoCurious what this would look like written in Rust, using the windows-rs bindings.
- masternight 1y agoThere 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 1y agoInstead 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.)
- kevin_thibedeau 1y agoThe standard allows memset/memcpy to be replaced by inline code. There is no need to use non-standard extensions to get a performance boost.
- userbinator 1y agoThat's how the MSVC intrinsics work. Turn on the option and memset/memcpy, among others, gets replaced automatically: https://learn.microsoft.com/en-us/cpp/preprocessor/intrinsic?view=msvc-170 https://learn.microsoft.com/en-us/cpp/preprocessor/intrinsic...
- burnt-resistor 1y agoContains numerous memory leaks, doesn't permit arbitrarily long lists, and saves and restores uninitialized data. Really sloppy.
- transcriptase 1y agoSeeing 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.
- lostmsu 1y agoA similar app in C# + WinForms is under 10KB on disk and 6MB RAM. This app takes 1.5MB RAM. Both start instantly.
- throwaway2037 1y agoImpressive. Can you share a link to the source code?
- int_19h 1y agoA 10 Kb .exe shouldn't be surprising given that it's fairly high-level (Java-like) bytecode rather than native code, and that WinForms incorporates a lot of the scaffolding that you have to handwrite for a Win32 app, like message dispatch.
- scripturial 1y agoThe 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.
- ghewgill 1y agoIf text files are your world, then http://todotxt.org/ http://todotxt.org/ might be for you. I'm currently using "pter".
- jftuga 1y agoHere is one of few Windows apps that I have written, albeit in C#. compinfo is a single, 431 KB windows executable. It displays basic computer info including user name, computer name, OS, model, serial number (service tag), CPU model, memory, IPv4 address and uptime. https://github.com/jftuga/compinfo https://github.com/jftuga/compinfo
- dataflow 1y agoYou'll definitely want to allow theming on your controls, if for no other reason than to let them feel native like the rest of the OS. I'd also suggest at ATL, to make your life a bit easier without making it much heavier.
- smusamashah 1y agoThe title reminds of recently released really fast file explorer called File Pilot. Made in C and weighs 1.8MB only https://filepilot.tech/ https://filepilot.tech/
- thecaio 1y agoNever easy to pull these off, so congrats! App might be modern in the sense that you coded it in 2025, but looks straight out of Windows 98
- toxi360 1y agoRight now it's only 27 kb and I've added the manifest file :)
- lucasoshiro 1y agoEvery time I see something in C for Windows I see people using MinGW, gcc and friends just like they would do in a Unix-like system. But I wouldn't expect that they are tools that Microsoft recommends for developing on Windows. So, a honest question from a Linux/Mac guy: what is the Windows-y way to do that?
- int_19h 1y agoThe most Windows-y way to do that is to get Visual Studio (Community Edition is free for non-commercial use). It still has project templates for pure Win32 apps even, although they are C++ rather than C.
- dwattttt 1y agoA cursory browse says there's no Linux-isms in the code base, so the Windows-y way to build that (without going into licensing) would be to use the Visual Studio Build Tools. They're the CLI toolchain you get for Visual Studio, but free when compiling open source projects (as of recently: https://devblogs.microsoft.com/cppblog/updates-to-visual-studio-build-tools-license-for-c-and-cpp-open-source-projects/ https://devblogs.microsoft.com/cppblog/updates-to-visual-stu...) They still notionally need to run on a Windows machine, although I recall people have managed to run them under wine before. EDIT: It took me a few reads to parse what the link is saying, so: using the toolchain to compile open source dependencies is fine, even if your codebase is closed source, so long as the closed source part isn't being built with the Build Tools.
- lucasoshiro 1y agoThanks!
- thefilmore 1y agoI wrote a guide [1] that collects this information in one place. [1] https://akr.am/blog/posts/a-guide-to-compiling-programs-on-windows https://akr.am/blog/posts/a-guide-to-compiling-programs-on-w...
- card_zero 1y ago
- webprofusion 1y agoNostalgia: My first job in 1997 was a windows apps in C++, it was weather software used on ships and oil rigs, we used to ship updates on floppy disk via helicopter.
- phendrenad2 1y agoThe fact that you can do everything in C when developing a Windows app always makes me feel all warm and fuzzy. Building up from the lowest-level primitives just makes sense. Meanwhile, on MacOS, everything is an ObjectiveC Object, so if you want to write an app in pure C you can but it's about 1000x more verbose because you've gone an abstraction level deeper than Apple intended, and you essentially have to puppeteer the Objective C class hierarchy to make anything happen. It's incredibly icky. I don't know why they can't rebase the ObjectiveC class-based API onto a basic win32-style procedural API (technically win32 is also "class-based" but it's minimal). It's part of why I don't see myself porting any of my C code to MacOS any time soon.
- kmeisthax 1y agoThey did have a procedural API, it was called Carbon; which was a nearly drop-in replacement for the Macintosh Toolbox API that user32.dll blatantly copied. The thing is, outside of programmer fuzzies, UIs really, really want to be object-oriented. A tree of unrelated objects sharing some common behaviors describes basically 99% of all UI code. And Toolbox / Carbon really strained for lack of having one. That's actually the one original thought Windows added - window classes. Personally, the weirdness you feel manipulating Obj-C classes directly from C is how I feel any time I have to define a window class or procedure in user32.dll code[0]. OOP wants dedicated language features, just like how UI wants OOP. You can make do without but it's 2000x less ergonomic. [0] Or anything to do with GTK/GObject.
- int_19h 1y agoInterestingly, Windows has its own object-oriented API/ABI with COM (and later WinRT, which builds on COM). However, the MIDL compiler for COM interfaces produces headers that are consumable from C, both to use interfaces and to implement them: https://www.codeproject.com/KB/com/com_in_c1.aspx https://www.codeproject.com/KB/com/com_in_c1.aspx As far as I know, this still works today even for WinRT, although the generated C struct and function names get very ugly because they have to include the entire namespace: https://stackoverflow.com/a/7437006/111335 https://stackoverflow.com/a/7437006/111335
- re-lre-l 1y agoIt should be written UPPER CASE, in Pascal, maybe...
- yapyap 1y agoTitle says 278 KB, github says 27 KB. I assume this is a typo in the title, OP if you ask dang nicely I’m sure he would be willing to remove the typo.
- pinoy420 1y ago[dead]
- leecommamichael 1y agoOdd that there’s so much conversation about this. Why is that? Genuine question.
- Plasmoid2000ad 1y agoI find frequently the smaller and simpler the subject, the more people can easily confidently grasp it and generate quick to share opinions. Noticed this with Code Reviews. To a point, the smaller the code change, the more comments and input. Beyond a certain size, comments and reviews (without nagging or external incentives) trends towards zero.
- Koshkin 1y agoIncidentally, NASM makes Win32 programming in assembler a breeze.
- Jamesits 1y ago"Native Windows look and feel". Before actually launching it, I hoped it's listview had context menu, and double clicking certain fields would lead to (in-line-ish) dropdown menus or textboxes. Maybe people don't know how to design programs for the Win32 UI/UX anymore, or maybe I'm too old for this.