Programming for Windows

| | Comments (4)

First, let me get some things straight. The toolkits that I write need to work on Windows 98 & ME (called 9x from here on out), as well as NT 4, Windows 2000, XP and up (called NT from here on out). I currently write the toolkits using CodeWarrior on a Macintosh and remote debug onto a native Windows box. I write in C and C++ using the regular Win32 APIs (just say no to MFC!). And for a little extra background: I've been programming for Windows using C since Windows 95 first came out, and Windows is my primary area of expertise when it comes to programming.

Programming for Windows is a lot like shooting fish in a barrel. It's really quite easy once you get used to the nuances. The problem is, you're blindfolded. The good news is, there's a ton of fish to hit.

What I mean is: the Win32 APIs are enormous. There's an API for everything. They're all different from one another in strange and exotic ways, and yet all the APIs seem tantalizingly familiar. It's weird. How about an example?

Everything in Windows programming is a window (or an HWND). A button, an editfield, a menu, a window, the taskbar, everything; if it's a GUI element, it's a window. This makes things really easy since it means that once you know how HWNDs work, you can use just about any GUI element without a problem. Obviously I am skimming over a few facts, but this is generally what I mean by things seem familiar.

On the other hand, the APIs are glaringly different from one another in fundamental ways. Take error handling for example. Some APIs return 0 or false to signify they failed. Others return -1. Still others have ByRef parameters to tell you what's going on. Some set flags that you can retrieve with GetLastError, some don't. Error handling is a royal pain -- you never know what you're going to need. I've seen many bugs creep into people's code due to errors with Windows APIs. A great example is the CreateFile API. You would think that if the file cannot be created, the API would return a nil HFILE reference, right? It doesn't, it actually returns INVALID_HANDLE_VALUE, which is -1. That means you can't do tests like if (!hFile) YouFailed(); since hFile isn't really nil, it's actually 0xFFFFFFFF. Yeeks!

Aside from the error handling being rather obtuse, the APIs tend to have names that you wouldn't really expect. Such as GetParent, which actually gets you the owner of a window (which is different from the parent). If you want to get the real parent, you have to use GetAncestor. Another thing that makes some sense from a very technical point of view, but is very hard for beginners to understand is the fact that lots of things are really just files. For example, you can get a file or a folder on the physical hard drive using CreateFile. But you can also open a serial port using CreateFile. Same with a parallel port. I wouldn't be surprised if I could open a socket using that API as well. If Microsoft wanted to make a cleaner API, they could have easily provided a nicely named function like OpenSerialPort and had it call through to CreateFile under the hood. But they chose to go the easy route and let the programmers figure it out for themselves. Ok fine!

I think my largest pet peeve about programming for Windows is the "Unicode support" they tacked onto the OS. Back in the old days, Microsoft felt that 256 characters was all any written language would ever need. So they designed the entire operating system to handle ASCII characters (also called the ANSI character set) and away they went. A release or so later, they realized that 256 characters is really small (especially for languages like Chinese where there are something like 6000 characters), so they figured they had to do something about this. So, instead of changing the APIs under the hood and doing a bit of C magic to make "everything" work with just a recompile, they came up with the abomination they have today (keep in mind that I understand some people write horrible code that does things like increment their way thru a string, and so code would break. But I don't care. Write good code to start with damnit). Every Win32 API that operates on a string of characters really has an evil twin API to operating on unicode characters (Microsoft chose UTF 16, which is a pretty good choice since it can handle 65, 535 characters instead of 256). So when you see an API like CreateFile, it's really exposed in the underlying libraries as CreateFileA (for ANSI), and CreateFileW (for Wide char). And to decide whether you want the wide char version, you have to use #define UNICODE at the top of every file. And to make matters worse, not every copy of Windows supports Unicode. In NT, Unicode is always supported. But in 9x, it depends on whether the user has installed the proper language packs. So that means to support Windows 9x with Unicode characters, you have to load all APIs dynamically since they may not be there! Yuck!! It's horrible, honestly. So to put it mildly, international support is a royal pain.

Aside from things like unicode support and error reporting, I actually like the Win32 APIs. It could just be that I've been using them for so long that they're just natural to me. But whatever the reason, I quite enjoy programming for Windows. I must admit though that I would prefer to ignore anything before Windows 2000. I find that the APIs for newer NT systems have been thought out better, are more powerful, and tend to be more conformed to the other APIs in the system than many of the older APIs.

4 Comments

What about windows CE?

What about WinCE (what a horrible name... wince)? I've yet to do any coding for WinCE, so I can't really speak about it from a practical point of view.

Currently the 1.0 version of the Compact Framework SUCKS! Once the 2.0 comes out it will be a more viable platform...

i did some proof of concepts using CF.Net .. it wasn't fun

Yeah, but I'm talking about Win32 APIs, not .NET ones.

Leave a comment

Disclaimer

I'm currently an employee of REAL Software. My blog is mine. The opinions represented in this blog are mine as well and may not represent my employer's opinions. All original material is copyrighted and property of the author.

REALbasic® is a registered trademark of REAL Software, Inc. REAL SQL Server™ and Lingua™ are pending trademarks of REAL Software, Inc. All rights reserved.