Yello! I have been busy searching through the archives of my yahoo group which I started way back in 2003. And guess what? It has a wealth of information. It is quite amazing to see how I have evolved in my art of writing and thinking. Feels a little bit nostalgic to start talking about MS DOS, Windows, etc. Now that I have been almost exclusively working with Linux on the system level and have kept myself confined to application layer on Windows, it really is fun to go back and look at my article on Windows System Programming from 2003. I talk about a lot of stuff including message queues, context switching, semaphores and mutexes, BHOs, TSRs, etc. I doubt if people use them application layer programming anymore (atleast I don’t). It is long and quite interesting. The unedited article follows.
I remember the days of my graduation when I had seen a computer and came to know about what all it can do. Simultaneously, I was introduced to the different programming languages namely QBasic, C
and 8085 Assembly. I was doing fairly well in 8085 assembly when one of my electronics professor told me about how interesting writing programs in C can be. You can have sound and graphics and stuff. The fun part was you don't need to write the ADD, LHLD, etc. in C. Its a high level language. And believe me, I was so excited that I bought an old 386 and started with C. I did a lot of coding in C, right from general C progs (ofcourse the escalator simulator :)) to TSRs (my new programming friends might have forgotten about it... anyway, will talk about it later) to games to viruses (yeah... interesting....
still one of my favourite codes) to MBR programming. One day I came across a book "Windows Programming in C" By Vijay Mukhi (One of the best coders in INDIA, currently the head of IT Dept. in Mumbai, Maharastra, India). I was just dumbfounded by what I saw on the first page of the book. A simple Hello World program consisting of 2 pages. Oh my... I thought, my old C was much better. How can I type in 300/400 lines for doing the job that a simple 1 line can do. Was I back in the 8085 world???
As far as I have observed, Windows programming is always daunting for newbies who migrate themselves from DOS C to Windows C. Many new concepts in Windows Programming hits a DOS programmer right through his basics, especially students. I am not talking about guys who directly jump to Windows Programming using Visual Basic (... ...), then come out with their own fundas and jump on to VC++ (thinking its the same as C++... man...) and then comes softwares full of Access Violations... Anyway, I always advise people to first clear the concepts about windows programming and then go ahead with coding. So thats how I will start. In this and coming issues, I will write about
the windows programming concepts, message queues, call back functions, differences between DOS and Windows, memory management, the different layers of windows model, the HAL (Hardware Abstraction Layer), the Executive Layer, Multi-tasking/Multi-processing, context switching, mutexes, semaphores, kernel mode and application mode programming, socket programming, etc. (Hey, if I miss out something just refresh me about it.. ). I will write about all this with code snippets in places I find useful else links will be provided. In short, the guide to Windows programming would start out with beginner basics and would eventually reach advanced levels such as device driver development and BHOs (Browser Helper Objects... what the hell is that... read on and I will tell ya...) and COM/DCOM and stuff.
Anyway, lets start with the first basic.
DIFFERENCES IN DOS AND WINDOWS:
-- DOS (Disk Operating System) has a monolithic architecture whereas Windows follows the Distributed Layered architecture model.
The monolithic architecture of the DOS Kernel is best described in the Book "DOS Internals" by Ray Duncan (I really appreciate him because of the abundance and depth of knowledge. He is really a must read for someone who really needs to know about programming. By programming I mean real programming and not just producing a chunk of code...). DOS mainly needs 3 files.
1) MSDOS.sys - The loader called after the POST-BIOS routines.
2) IO.sys - The file initializing and mainting the io subsytem for DOS.
3) COMMAND.com - The file acting as the service provider (kernel) for DOS.
If any one of the files is missing then the DOS won't work. COMMAND.com is further divided into the Resident portion and the Transient portion. The resident portion of the command.com loads itself into memory during DOS initialization/loading. Commands such as dir, cd, etc. reside in the resident portion of the command.com. The Transient portion is the one which is dynamically loaded and unloaded by the resident portion of command.com. External commands such as tree, any .bat file, etc. are loaded dynamically by the resident portion alongwith the transient portion. All the services needed by applications are either in the resident or the transient portion of DOS Kernel.
The Windows is altogether a different scenario. The Windows Kernel namely krnl386.exe has a layered architecture broadly divided into the following components listed from bottom to top layers.
1) IO Layer
2) File Manager
3) Service Provider
4) GUI Manager
The Windows Kernel also interacts with other subsidiary exes and dlls namely Kernel32.dll, user32.dll, gdi32.dll, gdi32.exe, advapi32.dll, ole32.dll, comdlg32.dll, shell32.dll, winmm.dll, etc. The Windows Kernel provides different services to the applications. In turn it also accesses services of various other dlls. Thus the Windows Kernel architecture is based on components/services which provides for better flexibility. Plug-in a component for extra functionality and take out one for reducing the kernel service and dependency.
-- DOS was not multi-tasking/multi-processing whereas Windows is multi-tasking and multi-processing.
Before elaborating on this point, we need to understand about multi-tasking and multi-processing. Are they the same or different? Well, multi-tasking stands for the ability to execute different tasks simultaneously. Context-switching/process-switching is an important fundamental requirement for multi-tasking. Multi-processing on the other hand stands for the ability to utilize different processors.
Multiple processors in case of multi-processing may be used to execute the same process/application or different applications. Multi-tasking is the fundamental requirement for multi-processing. Context-
switching is the ability of an operating system to switch between different contexts (after saving the current state of the context being switched and after retrieving the previous state of the context
being switched to), be it processes or threads in the same process or different process.
DOS as we all know was never able to run 2 tasks/processes simultaneously. Some of you may argue about TSRs. But TSRs were again simply loaded into memory and were only executed on occurence of some certain event. Infact, the addresses of the event ISRs (Interrupt Service Routines) in the IST (Interrupt Service Table) were replaced by the addresses of the TSRs (Terminate and Stay Resident Programs). So whenever an event occured, the TSR was executed. Still it was not multi-tasking because no contexts was saved or retrieved. DOS was not even able to satisfy the minimum requirement of multi-tasking so multi-processing was an ofcourse no-no.
Windows on the other hand supports both multi-tasking and multi-processing. You can run many applications simultaneously. Windows 2000 supports upto 8 processors. Even Win9x supports 2 processors. So multi-tasking and multi-processing makes a huge difference in windows especially synchronization, mutexes, semaphores, critical sections, resource acquiring/releasing, etc. needs to be taken care of by the Windows Programmer (though VC++/MFC provides a high support for coding Windows Programs, still a better coded program using the best tools, without understanding the concept behind it, is equivalent to a lousily coded program). Many of the errors received by released
products are the results of synchronization troubles. Recently our team members had a perfectly working server. We did rigorous load testing with a single thread and it was able to meet our expectatins. But the moment second client thread was invoked, the server behaved erratically. It took nearly a day to find out the synchronization trouble. The server code was not thread-safe. This proves the importance of synchronization.
-- DOS does not have any support GUI(Graphical User Inteface) whereas Windows is a full-fleged OS with a high level support for GUI.
I don't need to elaborate on this point. 😉
-- DOS doesn't recognize any callback functions whereas callback functions are the building blocks of a Windows program.
Though replacing the ISR address with our function routine would provide a kind of call back functionality in DOS, still the real callback functions are different. The OS calling the user defined functions to carry out specific tasks. This kind of functions are know as callback functions.
-- Windows has a message-driven architecture.
DOS knew nothing about messages or IPC(Inter-process communication). Windows on the other hand is purely message driven. The message queues in Windows are divided into the System message queue and application message queue. Both of them are maintained by the OS. The windows programs operates by posting/getting messages from the message queue. If the program needs to do something, then it has to request the OS to allow it to do it by posting a message in its application queue. The OS regularly keeps on checking the message queue and grants/denies the permission. In windows the program/thread is always in one of the 3 states, ready state, wait state and running
state (Yes.. Tanenbaum explains the 3 states in detail... ;))
-- DOS knew nothing about virtual memory but windows has the concept of Demand Paged Virtual Memory.
Ofcourse, if the programs in DOS were bigger then the amount of RAM in the machine, then it was the programmers responsibility to define boundary points / sections in his program, so that DOS can
load/unload them as needed. But it never had a true concept of demand paged virtual memory wherein the RAM is divided into pages. Again, windows also maintains some amount of the HDD free space as virtual RAM which it manages like RAM pages. If a program is bigger then the total amount of RAM on the system, then Windows will load only the modules needed for execution of the current context. If a module other then the ones loaded are referenced, then a page fault will occur which will tell the OS to load the referenced module. For this, the OS will unload the least used page from memory and load the
referenced page from virtual memory to the RAM and execute the instructions in there. (Yep.. guessed right... Tanenbaum and Malkovich have given a lot of algorithms for page management... But,
I don't know which one Windows implements. Anyway, the one implemented by window is a pretty good one.. ).
-- Windows has one more feature different from DOS and that is the different application space for different applications so that if one application behaves erratically and tries to over-write some other
app’s. memory then windows inherently will prevent this from happening. DOS didn't have any such restrictions. You can easily view/edit the memory occupied by other applications.
Well, with that told, I think I have written enough for this issue. In the next issue, we will have a code walkthrough for a true windows based program (yeah.. the great 400 liner...). If I have missed out
something, then you guys can add in it.
Another thing is that I promised 2 articles in this issue. The other one was related to Software development with UP/UML. But, I have dropped that idea cause I already got a great article by the
innovator of UP/UML himself... Yes none other then Grady Booch. So, I am copying and pasting his article in this issue.
Waiting eagerly for your comments.