9 ms·
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 o
by masternight 1y ago
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 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...
- rcarmo 1y agoI spent a lot of time doing that and to be honest, I miss the ability to develop for native UIs with native code.
- scripturial 1y agoAt minimum, these days, if you dont use strncpy instead of strcpy, you’ll have to suffer through every man and his dog (or AI tool) 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 1y agoHeh, 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.
- nly 1y agostrncpy is more or less perfect in my line of work where a lot of binary protocols have fixed size string fields (char x[32]) etc. The padding is needed to make packets hashable and not leak uninitialized bytes. You just never assume a string is null terminated when reading, using strnlen or strncpy when reading as well.
- masternight 1y agoYep, that's intended use case for strncpy(). It's not really suitable for general purpose programming like the OP is doing. It won't null terminate the string if the buffer is filled, which will cause you all sorts of problems. If the buffer is not filled, it will write extra null bytes to fill the buffer (not a problem, but unnecessary). On freebsd you have strlcpy(), Windows has strcpy_s() which will do what the OP needs. I remember someone trying to import strlcpy() into Linux, but Ulrich Drepper had a fit and said no. You just never assume a string is null terminated when reading, using strnlen or strncpy when reading as well. Not really possible when dealing with operating system level APIs that expect and require null-terminated strings. It's safer and less error-prone to keep everything null terminated at all times. Or just write in C++ and use std::string, or literally any other language. C is terrible when it comes to text strings.
- 1y ago
- MortyWaves 1y ago> Instead of memset() you've got ZeroMemory(), instead of memcpy() you've got CopyMemory(). What is or was the purpose of providing these instead of the existing Windows C std?
- masternight 1y agoThose functions explicitly? I can't find any definitive explanation on why they exist. It looks like nowdays ZeroMemory() and RtlZeroMemory() are just macros for memset(). Here's an article on some of the RECT helper functions. Relevant for the 8088 CPU but probably not so much today: https://devblogs.microsoft.com/oldnewthing/20200224-00/?p=103472 https://devblogs.microsoft.com/oldnewthing/20200224-00/?p=10...
- lmz 1y agoYou could write code without using libc / the C runtime. You still can.
- userbinator 1y agoIt's worth remembering that Windows 1.x and 2.x predates the C89 standard. This also explains why WINAPI calling convention was inherited from Pascal instead of C. The C standard library was "just another competitor" at the time.
- int_19h 1y agoThe WINAPI calling convention is a cross between C and Pascal - C-style order of arguments on the stack, but Pascal-style callee cleaning the stack before return. The reason for its use in Windows is that it makes generated code slightly smaller and more efficient, at the cost of not supporting varags easily (which you don't need for most functions anyway). Back when you had 640 Kb of RAM, saving a few bytes here and there adds up quickly.
- mike_hearn 1y agoWindows didn't standardize on C. It was mostly assembly and some Pascal in the beginning with C and C++ later. Microsoft have always viewed C as just another language, it's not privileged in the way UNIX privileges C. By implication, the C standard library was provided by your compiler and shipped with your app as a dependency on Windows, it wasn't provided by the operating system. These days that's been changing, partly because lots of installers dumped the MSVC runtime into c:\windows\system and so whether it was a part of the OS or not became blurred and partly because Microsoft got more willing to privilege languages at the OS level. Even so, the Windows group retains a commitment to language independence that other operating systems just don't have. WinRT comes with lots of metadata for binding it into other languages, for example.
- rlkf 1y agoI second this, and just want to add that strsafe.h contains replacements for the runtime string routines.
- codebolt 1y ago> 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(). I see he's also using fopen/fread/fclose rather than CreateFile/ReadFile/WriteFile/etc.
- deleted 1y ago[deleted]
- donnachangstein 1y ago> I see he's also using fopen/fread/fclose rather than CreateFile/ReadFile/WriteFile/etc. It's a todo list, not a network service. So what if it's using unbounded strcpy's all over the place? It has basically no attack surface. He wrote it for himself, not for criticism from the HN hoi polloi. For once maybe take someone's work at face value instead of critiquing every mundane detail in order to feel like the smartest person in the room. Computers are tools to get stuff done. Sometimes those tools are not pretty. I place much of the criticism being levied here in the same category as the "we must rewrite 'ls' in Rust for security" nonsense that is regularly praised here.
- masternight 1y agoSo what if it's using unbounded strcpy's all over the place? It has basically no attack surface. He wrote it for himself, not for criticism from the HN hoi polloi I didn't point that out so I could be the smartest person in the room and I certainly don't subscribe to the whole rewrite-the-world in rust. The sheer amount of time I spent debugging problems caused by buffer overruns and other daft problems is immense. It's literal days of my life that could have been saved had safer APIs been created in the first place. It's a cool toy program and I encourage the learning but maybe let's try and avoid unnecessary problems.
- Suppafly 1y ago>I certainly don't subscribe to the whole rewrite-the-world in rust. Good because those Rust people get really upset when you point out that Rust mostly seems to exist for people to "Rewrite X in Rust".
- BarryGuff 1y ago> There is something I like about win32 gui programming Totally agree with you. I use an excellent PC app called AlomWare Toolbox, and it's the epitome of Win32 design (https://www.alomware.com/images/tab-automation.png https://www.alomware.com/images/tab-automation.png), and despite it doing so much it's only about 3 MB in size because of it. No frameworks with it either, just a single executable file. I wish all software were still like this.
- raverbashing 1y agoI agree with most of this, but let's be honest, win32 gui programming (like this) is/was a pain Even MFC barely took the edge out. It's amazing how much better Borland built their "Delphi like" C++ library. > Instead of memset() you've got ZeroMemory(), instead of memcpy() you've got CopyMemory(). Yes. And your best API for opening (anything but files but maybe files as well) is... CreateFile Aah the memories :)
- int_19h 1y ago> It's amazing how much better Borland built their "Delphi like" C++ library. As I recall, it wasn't "Delphi like", but rather literally the same VCL that Delphi used. That's why C++Builder had all those language extensions - they mapped 1:1 to the corresponding Delphi language features so that you could take any random Delphi unit (like VCL) and just use it from C++. In fact, C++Builder could even compile Delphi source code.
- pjmlp 1y agoYes, and it grew out of Object Windows Library, which also add extensions, and was definitly much more pleasant to use than MFC has ever managed to. No need for the past tense, both products are still on the market with frequent releases and developer conferences, even if no longer at the same adoption level.
- int_19h 1y agoI remember OWL being somewhat weird in that it rendered quite a few stock controls itself, in ways that made OWL apps really stick out on Win 3.11. MFC gets a lot of flak, but I think that a large chunk of it is undeserved because it's a fundamentally different kind of framework - a wrapper that tries to streamline the use of underlying APIs without concealing their fundamental nature, whereas OWL and VCL (and VB6, and WinForms) are higher-level wrappers that do quite a lot for you even when they use native widgets under the hood. From that perspective, if anything, the more appropriate criticism of MFC is that it tries to do too much - e.g. that whole document/view thing is clearly a high-level abstraction that always felt out of place to me given the overall design of the framework. WTL is basically what MFC tried to be but failed.