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.
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.
> 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.
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.
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.