Going in the lines of Yoda, you have learned much so far in your long journey through the swamps of code, which is fine and well, but now you must unlearn much of your dirty habits to survive.
The classic democoding attitude is to get as much speed out of everything not caring about possible problems of ditching some safety overboard. If it works on my machine, it'll work everywhere.. right?
Every democoder on PC at least should know by now that this isn't true.
Now, in windows world, you're not alone. While you might get in direct contact with hardware somehow, this is not advisable, and most probably wouldn't work everywhere. Also, you must build your programs so that it'll keep its hands to itself, without messing around in memory it shouldn't access. And if it reads somewhere to check something before use, or not to rely on some data on some occasions, you should, really, do as asked (or told) to.
First reason is to make your code work in the first place. The second is to make it work 10 years from now, on a possible win32 platform, or a win32 platform emulator, of that time. While it is already true that you can't find too many similar PCs around - even if they had the exactly same hardware, the software will differ somehow, if even by user preference settings. Under win32, you have an interface you should rely on, and not the hardware (or software) beyond. Let's take the trusty old VGA into consideration. Is it, at register level compatibility, required to run current win32 programs? What about in 10 years?
Another thing to consider is that by using the API to do something instead of rebuilding it yourself may be a very good idea indeed. For one thing, the API may have hardware acceleration behind it, and for the other, it may have code for a new processor that doesn't exist yet.
This is the way a democoder thinks: Speed, speed speed. Who cares about the rules. Right. So, let's stop all that stuff, and start thinking in different way. Rules above speed. If a part of API is not documented (like the infamous killgdi or some of the screensaver API), it is generally better to leave it alone, and use the documented way instead.
Now, win95 isn't as bad as you might first think. Really! Internally, it's a horrible pile of stuff built on top of an empty match box, and I can't understand how they succeeded in it, but it's far more stable than you might expect looking at its specs. In fact I think that if you run only well-behaving programs in win95, you shouldn't get any crashes at all.
(The fact that microsoft themselves break their own rules and sometimes build badly-behaving programs is not to be taken as a good example).
But enough of that. Let's look at windows.
Windows is a message-based system. This is true from win3 world as well. In addition to the message passing, win32 has this pre-emptive multitasking thing which means that if a task takes more than its allocated time (which varies by priority levels), it will be put on hold and other code is run in the meanwhile. And when it gets its turn again, it continues from where it was left off.
So, most of the time your program will just wait for a message. Actually, your program will not even be called if it doesn't get a message, so it will take absolutely no time at all.
In addition to this, you have processes and threads. One program is one process, which contains one or more threads. A process can spawn new processes and new threads. One process' threads can use the same memory space.
Let's say your program has a "print" button, and you want the user to continue working right away without waiting the program to render whatever it does into picture form to feed to the printing facilities, you'll start a new thread to do this, and continue on in the message polling system. Your thread will do its work in the background and kills itself when the task is finished. Handy. Or you could set up a chess program that has one of those AI:s that think while player is working. Or put your module player as different thread. etc.
Now, what are these messages? Your program is called every time an event happens that your program is thought to know about. These include keyboard presses, mouse movements over your window, window closing/opening, termination of your program, and other much less used things like screen saver starts or PNP configuration has changed. There are possibly thousands of messages in use, and your programs may make up new ones.
Coding for windows is different from coding for DOS. For one thing, if you, let's say, want to ask the user a question, you don't start building your own user interface code (even if it's one printf and one getch), but you first try to find what function to use, which is in this case MessageBox.
Now we'll meet our 20-meg friend win32.hlp, which you should get in the win32 SDK; mine was on Watcom CD. You'll use this file a lot so if you can, configure your favorite editor to spawn it with as little trouble as possible. Also be sure to build the search index for this file, although it takes 10 to 40 megs as well (depending on what mode you use).
Win32 sdk help says on the topic of MessageBox: (reprinted without permission, but as far as I can see, this will help microsoft's world domination, so I don't think they'll be pissed off..)
int MessageBox(
HWND hWnd, // handle of owner window
LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);
Now, please let me read your mind. "What the heck is that all about?". Thank you. Windows API uses what is called Hungarian way of writing variable names or something. Generally speaking each variable type and name is prefixed with one to many letters meaning what this variable type is.
HWND means Handle to WiNDow. Handles are like pointers (actually it's index to a pointer table), and all you need to know about them is that when you allocate something, you get a handle, and then you'll interact with this thing using the aforementioned handle.
LPCTSTR means Long Pointer to STRing (CT might mean C-Type or asciiz string, but I'm not sure. That's what it is anyway). Now, long pointers are not used in the win32 world; all pointers are 32 bit flat memory area pointers. There is some mechanism to access 64 bits of memory but I'm not familiar with it.
UINT is, yes, you guessed it, unsigned integer. The uType parameter in this case is full of flags; for full list of them, refer the Win32 API. We'll just use MB_YESNO here.
I'm not going to explain every single command and what you can do with them in this tutorial. It is a very good idea to look up every new keyword you find here from the win32 SDK help file. After all, you're going to look up stuff from this file all the time when coding for windows. Truly.
Let's say our window's handle is stored in hWnd variable. Let's ask the user whether we wish to quit or not:
i=MessageBox(hWnd,"Leaving already?",
"Do you wish to quit?",MB_YESNO);
if (i==IDYES) terminate_this_silly_program();
Every single windows program has a window, even if it's not visible. Actually, everything you see in windows is a window as well, including push buttons and every single menu option. You'll be passing your window's handle to all kinds of API calls, so that they know what window they are acting with. Other often used handle is the window instance handle, but more of that in the next chapter, where we build our very first windows program! yippee!