' C ' Windows Programming ' C ' Windows Programming ? Programming under Windows ? Do you really wish to learn ' C ' Programming under Windows ? Well, you have come to the right place. Now that you have finished learning ' C ' programming under DOS, it is high time you learnt something better. We will try to make it easier for you but we hope that the batch of " anti-frustration " tablets - which you most probably had used while learning ' C ' under DOS - is not exhausted . If it is, we advise you to get a fresh batch now, and we assure you that you will need it now, more than ever before. Learning ' C ' programming under DOS, is not easy, as you undoubtedly know. But then, you should know that if you want to learn something better, it is bound to be more difficult, and you would have to work harder to understand it. So here we are, trying to help you understand ' C ' programming under Windows. These programs are written and explained with some assumptions, one of them being that you have thoroughly understood the concept of ' C ' programming under DOS and are well versed with it's functionality. With this assumption, we shall go ahead and try to understand what ' C ' programming under Windows is all about. Creating your workspace... Before starting with the programming part, you have to know where to type out the program. For this you have to follow the steps given below. Click on Start and select Programs. Next, select Microsoft Visual C++ 5.0 From here, select Microsoft Visual C++ 5.0 once again Now click on File and select New. You will now see a tabbed Dialog Box with Project already being selected From here, choose Win32 Application, type in the name of your project in the first edit box on the right hand side of this dialog box, and click on O.K. Again, select File and select New. You will now see the same tabbed Dialog Box but with File being selected. Here, choose the Text File option, and put in the name of the file in the second edit box on the right. You have to end the file name with ' .c ' You have now entered the world of ' C ' Windows Programming. There is no turning back. You have to go through this ordeal if you wish to learn at least something about ' C ' programming under Windows. Getting started... Let us start with a small program in ' C ' under Windows WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { } In a ' C ' program under DOS, you know that the first function to be called is ' main()', and may start to wonder where is ' main() ' in our program. Before you confuse yourself - trying to make some sense out of our program - please continue reading. In ' C ' Windows programming, the first function to be called is ' WinMain '. We already have this function in our program (It should not take too much time to dawn upon you, that it is a function. This is because we all know that a function begins and ends with an open brace '{ ' and a close braces ' }' ) . Now some genius amongst you will undoubtedly ask as to why the function should be called ' WinMain ' and not ' xyz ' or any other name ? This being a very intelligent question, we feel that the answer should also be equally intelligent. Many different answers come to our mind. But the best explanation we choose to give is as follows. The person who had designed Windows programming , visited a very well known astrologer, who after searching for some signs and reading scriptures, advised him to give the function a name of seven characters in length and with two of the characters in capital letters. This person promptly thought of naming it ' WindowMain ' - Windows, because it is a Windows program and Main because it is the first function that is called in a ' C ' program . But then, he realised that the number of characters were more than seven, so he simply shortened it to WinMain. Now if you believe this explanation, we can safely assume that you will belive anything we say, and we can also safely assume that you can be fooled easily ( this being a blessing in disguise, as there are some instances where we are forced to ask you to trust us, so that we can explain the concept better). Here, all we can say as to why it is called WinMain is, we do not know. The only person who can answer this supposedly ' intelligent ' question, is the person who designed Windows programming. But then, as we do not know who he is - though we tried our level best to find out who the person is - we cannot come up with the actual reason. If you know who the person is, you can get back to us with his name and address, so that we can ask him the reason why he named it ' WinMain ' and not xyz or whatever. Getting back to the program, we are saying that we have created a function called WinMain and it is passed four parameters viz. HINSTANCE i,, HINSTANCE j, char * k and int l. Now, why we took i,j,k,and l as the variables is also an interesting question. This is mainly because we had decided to use these variables some years ago - due to some good reasons - and since then, we have faced no problem while using these variables. The reason, as to why we had decided on these particular variables, and not any other, has been forgotten. But, if by any chance, we happen to remember, and you are still interested, we'll let you know. Until then, we shall continue using the above variables, but you are free to use any variable you like. Now, whoever calls the function ' WinMain() ', puts the parameters of the function on the stack, and they take up a certain amount of space on stack We shall explain what these parameters stand for. The first parameter HINSTANCE, is an unsigned int. If you search through the header file you will find this parameter as a #define HINSTANCE = unsigned int. This parameter is written in uppercase, we have not used the lower case, so you should also write it in the uppercase only. This is because of the fact that anything written in upper case in ' C ' is assumed to be a ' Macro ' and by convention all Macros are written in the uppercase. Before venturing into any field, it is always better to invoke the blessings of God. So after offering prayers to God, and deciding on the auspicious time to start with your programming, type this program down. To compile a program under ‘ C ‘ Windows, click on the menu option ‘Build’. In the box which drops down, select ‘Build .exe ’. This will compile as well as link your program. After compiling this short program in ' C ' under Windows, what do you see? You see some errors on your screen. This is not an auspicious start. But please do not panic and start praying all over again. The Gods are not displeased with you. There is a saying in English " To err is Human ". These errors are human errors. We have erred in the sense that we have not included the required header file - where the macros are defined - into our program. Inclusion of header files... So now we include that header file in our program #include WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { } Now on compiling the program, you still get an error. But to your relief, you see that there is only one error. This goes to prove that the Gods have at least partially heard your prayers. Before you start wondering what went wrong , you have to understand what ' C ' Windows programming is all about. In ' C ' programming, there is something known as a ' calling convertion '. This calling convention is something like Diplomacy. Diplomacy means, that whenever you come into the presence of a Queen, you should go down on your knees. There is also a protocol in Diplomacy which specifies that when a President of a country comes to India, then it is the President of our country and not the Prime Minister who receives him. The President of India does not have any power, but as he is the first citizen of our country, it is proper that it is he who should meet the President of that country. Similarly, there is a rule in ' C ' which says that when you push parameters on the stack, you push it in the reverse order. These rules which define how the parameters are to be pushed on stack, are known as ' calling conventions '. So now, we also have to specify which calling convention, our function should use. In our program unfortunately, the WinMain follows the Standard Calling Convention, which is different from the ' C ' Calling Convention. Since our program is a ' C ' program, all functions are assumed to be called in the ' C ' Calling Convention. But if we are to call a function in the Standard Calling Convention we have to put ' _stdcall ' before it. So here in our program we call the function in the Standard Calling Convention method. #include _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { } As soon as you put in ' _stdcall ' in front of the function you'll see that the colour of the word ' _stdcall ' changes, this shows that it is a reserved word in Windows ' C ' program and it has a special meaning to it .' C ' understands what ' _stdcall ' is. Now when you compile the program you will not get any errors. You can now go ahead and build the program. To your relief there is still no errors. Now execute this program by choosing ‘ Build ‘ from the menubar and select ‘ Execute .exe ‘. On execution, you will see that the program does not do anything. This is because there are no lines of code within ‘ WinMain() ’. Now to make our program do something useful, we add a MessageBox into our program which appears as shown below. #include _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { MessageBox(0,"Hi","Bye",0); } Let us understand what is the code we have put inside our ' WinMain() '. We have put in a MessageBox which is a function that is understood by ' C '. This function has to be passed four parameters as part of it's syntax. Here we give you a bit of advise that we learnt very early in life. " Never argue with syntax ". The first and last parameters, which are both ' 0 ', need not be understood by us at this stage. So, forgetting these parameters - though we have to pass them in our function as part of the precious syntax - we can go to the second and third parameters and insert two strings ( you can pass any values you wish, but they should be such that they could be passed as strings). If you want to know why we used "Hi" and "Bye" as the parameters we can also provide you with an explanation. We have passed these parameters as they were the first thing to come to our mind and they looked very friendly. You can pass any string you want, we are not stopping you in any way. Now continuing with our program, why don't you build and execute it ? Ah! What do you see ? What you now see, is a cute little MessageBox with "Hi" and "Bye" in it .The MessageBox disappears as soon as you click on the O.K. button in it. So finally, we have managed to get our program to do something for us. If you are in a mood of doing some R & D, we suggest that you try changing the last parameter from 0 to 1 or 2 or 3 and so on till you get exhausted.We have tried our best to reach the last limit of this parameter,but we got exasperated after we reached 1000000, and decided not to go any further. Do us a favour by not asking us as to how far you can go with these numbers. Do not, however, change the first parameter at present. When you change the last parameter to 1, you do not get any errors after the compilation and linking process. On executing the program, you see that there is a change in the number of buttons displayed in the MessageBox. Similarly, as you keep changing this last parameter, you will see that the appearence of the MessageBox keeps changing with only the messages remaining unchanged. Now let us change the code in the function as under; #include _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { char aa[100]; sprintf (aa,"%d", i); MessageBox(0,aa,aa,0); } In this program we have defined an array ' aa ' of 100 characters. Let us see how we can store some value into it. So in our next line of code, the function ' sprintf ' is used to store the value of ' i ' - which is the first parameter of our function ' WinMain() ' - in the array ' aa '. Now to give you an explanation of what the functions ' fprintf() ' and ' sprintf() ' do, would be an insult to your intelligence. Hence, they are not explained here (you already know what they do, as it is assumed that you know ' C ' under DOS). Now when you build this program and execute it, you see a number displayed in the MessageBox. This number, is a number assigned to ' i ' by Microsoft Windows, and of no importance to us, but to Windows it is an identifier. It tells Windows who we are, and the first parameter we have passed to ' WinMain ' is this identifier. This identifier had to be given a name. It is called a handle in programming parlance, and so we shall also call it a handle . When we say that ' i ' is a handle in Windows, you have to realise that you should not touch that variable. When we say ' not ', it means that you should not touch this variable, do not try to reassign a value to it or try to increment it’s value or do any other thing to this variable. It is to your advantage that you leave this handle alone. Creating a window... Let us now proceed to somthing big - like creating our own window. Whenever we write "Windows" with the "W" in capitals, we are referring to the Microsoft Windows System. But when we write "window", we refer to our window application. In ‘ C ’ under DOS we know that you faced many problems while creating the window. In Windows programming you will see that the creation is a bit easier. We already have two lines of code as our base. Let us go ahead with it and include some lines, one step at a time till we create our window. #include WNDCLASS a; _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { } You have the right to wonder what ' WNDCLASS ' means. Please bear with us for the moment and build this program. What do you find? You get no errors. This proves that ' WNDCLASS ' is something which is understood by ' C ' Windows. Let’s also understand what it is that ' C ' understood. ' WNDCLASS ' is written in capitals and so we can say that it is a Macro. Where can a Macro be found? It is needless to say that it is found in the header file < windows.h >. Now since it is present in the header file, you may want to know what it could be? It could be a long, or an unsigned int or anything. ‘ WNDCLASS ‘ is none of the above, it is a structure tag and has it's own set of pre-defined variables ( If you want to know what a structure tag is, we advise you to get your fundamentals of ' C ' under DOS cleared ). Now by passing the above line we have created a structure ' a ' which looks like ' WNDCLASS '. We have chosen ' a ' as the name of our structure, because ' a ' is the first alphabet in English and we felt that it should be accorded some respect. Now when you run this program you do not see any output. You may wonder, why even after creating a structure, ' C ' under Windows is stupid and does not give you an output? But then you have merely created a structure, you have not initialised any of it’s member variables and so you can't expect ' C ' to create a window merely because you created a structure. Initialisation process... Let’s move ahead and put a line of code in our function and try to initialise some of the members of our structure. #include WNDCLASS a; _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { a.hInstance = i ; } Now fold your hands, and pray that you don't get any errors. Finish your prayers and compile the program. Great! your prayers have been answered. You get no errors. Is this a miracle? Well let us try to explain this great phenomenon. You get no errors because if you look at the structure ' WNDCLASS ', in the header file, you will see that ' hInstance ' is a member of this structure. Now since our structure ' a ' looks just like ‘ WNDCLASS’, ‘ a ’ also inherit’s these variables and can now call them as if they were it's own. Now what is the data type of this member of ' a '. It is obvious that it has to be an ' int ', otherwise we would have had a type mismatch error. We add one more line of code to our program. #include WNDCLASS a; _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { a.hInstance = i ; a. lpszClassName = "Hi" ; } When you build the program, you still do not get any errors. Do not get exited. There are no errors because 'a.lpszClassName' is also a member of ' WNDCLASS '. So now you know a second members of our structure ' a '. This member of our structure is a string and we have initialised it to "Hi". Now why did we pass this string as " Hi "? Well it's like this, whenever you meet a good friend on the road, how do you greet him? Obviously you say "Hi". Similarly, we thought that when we walk down the streets of Windows programming, and happen to see our window, it should greet us in a polite manner . You may not want your window to greet you politely, but we always like our windows to be polite. Even if this is the only virtue of our window that we may be able to boast about. Hence we have named this member as " Hi ". Putting an additional line of code, we get the following program. #include WNDCLASS a; _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { a.hInstance = i ; a. lpszClassName = "Hi" ; a.lpfnWndProc = zzz ; } Now you are in for a disappointment .On building the program you'll encounter an error. It is a compilation error which says " 'zzz' : undeclared identifier ". This is because ' zzz ' has not been defined by us. The error is not due to ' a.lpfnWndProc ' - otherwise it would have told you "' a.lpfnWndProc ' : undeclared identifier ". In our program we have initialised the third member of our structure ' a ' viz. ' a.lpfnWndProc '. It has to point to the starting position of the function we shall define in the next program. Now let us define the function zzz in our program #include WNDCLASS a; long _stdcall zzz(); _stdcall WinMain(HINSTANCE i,HINSTANCE j,char * k, int l) { a.hInstance = i ; a. lpszClassName = "Hi" ; a.lpfnWndProc = zzz ; } long _stdcall zzz(UINT w,UINT x, UINT y, long z) { } We now have a function prototype ' zzz ' in our program. This function follows the ' Standard Calling Convention ' and returns a ' long '. Now, whenever ' C ' encounters ' zzz ' it knows that it is the name of a function . But what does the name of a function tell us? It only tells us where the function starts in memory . If you had not defined the function, where would ' C ' search for it ? So we have to write the code of the function in our program. Hence we have added another function ' zzz ' to our program. This function is passed four parameters. The first three parameters are Macros which are of the type ' unsigned ints ', while the fourth parameter is a ' long '. Now when you build this program you should not get any error. Even after writing so many lines of code in your program, on execution you see that it does nothing. This, to you, may seem very strange. But in actuality, what have we done? We have merely initialised some variables and declared a function. We have not asked our program to do anything. So why should it do anything for us? We shall add some lines of code - which we had earlier learnt in ' C ' under DOS - to our program. #include #include WNDCLASS a; long _stdcall zzz(); FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; fp = fopen("c:\\z.txt","w"); fprintf(fp,"start\n"); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } In this program we have used ' FILE '. This you have already learnt in ' C ' under DOS. Unfortunately, when we use ' FILE ', we also have to include it's header file . It is like the case when you bring home a pet dog. Well, bringing the pet is O.K. but then you also bring home additional problems like feeding the pet, etc. You can't have a pet without also having the problems that it brings. Similarly, when you use ' FILE ', you have to include it's header file in our program, without which, it will give us an error. We have also added ' fprintf() ' statements in both our functions viz. ' WinMain() ' and ' zzz() '. We have put an ' fprintf() ' statement in ' zzz() ' to store the values of the four parameters we have passed to the function in the ‘ z.txt ’ file. What the last three lines of code of our function ' zzz() ' does, is not to be understood by you at this stage. It will be explained later. In the mean time, please take our word for it and write it as a part of syntax. When you build the program you do not get any errors. Before execution however you have to take care that there is no file by the name ' z.txt ' in your root directory, because, on execution of this program your existing file will be completely overwritten. Now on execution of the program you still do not see any output on screen. This is because the output is stored in ' z.txt ' in the root directory. You can see for yourself, the output present in ' z.txt '. The output in z.txt is as follows: start But what is this ? You have only ' start 'as your output. Where are the values of the parameters of our function ' zzz '. Go back to your program and see whether you have forgotten to put the ' fprintf ' statement in your function. You have it there. So what went wrong? Let us try to understand why this has happened. In the function ‘ zzz() ’ we have used the ' fprintf() ' statement to print it’s parameters. But we have not called the function. This function gets called only after we use a function called CreateWindow. We shall incorporate this function in our next program. Creation process... So let us try to create a window in our program. #include #include WNDCLASS a; long _stdcall zzz(); FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; fp = fopen("c:\\z.txt","w"); fprintf(fp,"start\n"); CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0) ; } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Phew! Just look at the number of parameters we have had to pass to our ' CreateWindow() ' function. Now why do we need to have so many parameters in our function, and what does each parameter signify? As to the question of why we need so many parameters, we do not know. You will have to ask the person who designed Windows programming for the reason. But as to what each of the parameters signify, we shall try to explain them. The first parameter you pass is a string. This is the same string which we had given earlier to ' a.lpszClassName ' in our program. The second parameter is also a string, which we have initialised as "Bye". You can give any value you choose, to this string . This string will appear as the title of your window. We would prefer to get rid of you as soon as possible and hence we have used "Bye" as our string. The third parameter is in capitals, hence it can be safely said to be a Macro. This Macro WS_OVERLAPPEDWINDOW, is defined as an ' unsigned int ' in the header file . It is passed a number, which makes no sense to us. Whenever the user wants to minimize or maximize his window, in fact, do anything with it, he should be allowed to do so. This parameter provides Windows System with the required information, to allow the user to do whatever he/she wants with the window. Now, where do we want this window to appear ? i.e. At which position on the screen? This is specified by the next four parameters of our function ‘ CreateWindow() ‘. The fourth and fifth parameters constitute the' x ' & ' y ' co-ordinates of where our window is to be displayed on the screen. The sixth and seventh parameters specify it’s ' width ' and ' height '. The next two parameters i.e. the eighth and ninth, are ' 0 ' and so it should not be any concern to you. When we close the window, we are asking Microsoft Windows to do something for us. So it is now necessary to tell Microsoft Windows who we are. The tenth parameter is the handle of our window and this gives Microsoft Windows the information it requires. The last parameter is again ' 0 ', so we shall not explain it. Now when you compile and run the program you'll see that there is no change in the output even though we have added the ‘ CreateWindow() ’ function. Let us try to understand what the problem is? When we are saying ' CreateWindow ', the poor function, as it is, is already loaded down with so many parameters. And until now you haven't even said what the background colour should be or how you mouse should look like, the moment it enters the window. Now if you include these description as parameters to the 'CreateWindow()', then just imagine how large your function would become. Now you may keep creating windows. Microsoft wanted to make this creation process more effecient. They saw to it that this function did not land up with fifty parameters. Here, we want to create a window that looks like the class "Hi", which is the first parameter of our function ' CreateWindow()'. But before this can be done, you have to first register the class i.e. "Hi". We register a class by giving it the address of a structure which looks like ' WNDCLASS '. When you register a class, it means that the ' CreateWindow() ' function can access the members which we had initialised earlier. So far you have seen us speaking of " Hi " as a class, but may be wondering as to why it is called so? Well we have initialised a member ' lpszClassName ' to "Hi" and hence it is called as a class. A class is actually a hypothetical entity and it can't be physically shown. We have also initialised ' lpfnWndProc ' to ‘ zzz ’, so now whenever Windows wants to talk to us, he does not need to speak to ' WinMain() ' he will only talk to our ' zzz() ' function. That is why the function gets called four times. Now whenever Microfoft Windows wants to do something for us it would first need to know who we are and this is shown by the variable ' i '. Registering a class... Let us now learn how to register a class. #include #include WNDCLASS a; long _stdcall zzz(); FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; fp = fopen("c:\\z.txt","w"); fprintf(fp,"start\n"); RegisterClass(&a); CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } The ' RegisterClass ' should have R and C in capitals. Why this is so, is not known to us. We have so far never argued with syntax. They want the syntax of a function to be in a particular manner, so be it. We have always obliged them. If you want it to be worded differently, you can create your own version of ' C ' Windows programming language. Once you have created your programming language, please let us know, so that we can use your syntax. Until then, we shall use the function as it is. The ' RegisterClass() ' should be passed the address of our structure i.e.' a ' so that the compiler now knows whose variables are to be registered in memory. After you compile and execute this program what do you see? Although we have executed the program only once, the ' zzz ' function is called four times. Now if you do not have the same output as us ( with regards to the numbers in our output) , please do not worry. These numbers tend to be different at different times. The output that we get in ' z.txt ' is as follows: start 1056..36..0..6618072 1056..129..0..6618108 1056..131..0..6618140 1056..1..0..6618108 Now let us put an ' fprintf ' statement after the RegisterClass and see what happens. #include #include WNDCLASS a; long _stdcall zzz(); FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; fp = fopen("c:\\z.txt","w"); fprintf(fp,"start\n"); RegisterClass(&a); fprintf(fp,"start1\n"); CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } What happens now? Looking at the output, there are two things you notice at once. The first being, that both the ' fprintf() ' functions of WinMain are executed first. This shows that the function ' zzz ' gets called only after the ' CreateWindow () ' function. The second thing you may have noticed is that the values of the parameters have also changed. Now did we not ask you to ignore the value of these parameters, but you would not listen, you will still notice that the values of the parameters are different, ignore them in future. Our output however now looks as under: start start1 1592..36..0..6618072 1592..129..0..6618108 1592..131..0..6618140 1592..1..0..6618108 You have still not been able to see a window as your output. For this however, you will have to first create a variable and store the return value of the function ‘CreateWindow()’ in it. Your program now looks as below #include #include WNDCLASS a; long _stdcall zzz(); HWND b; FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; fp = fopen("c:\\z.txt","w"); fprintf(fp,"start\n"); RegisterClass(&a); fprintf(fp,"start1\n"); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } In this program,the variable ‘ b ’ is of the type ' HWND '. HWND is a macro which is an ' unsigned int '. We have initialised ‘ b ‘ to the return value of the ‘ CreateWindow() ’ function. Now ' b ' stands for the number of the window which we have just created. It is possible to create multiple windows in one application - each having it's own unique identification number, and now whenever Windows sees ' b ', it knows that our window is to be called. When you compile the program and run it, you will still not be able to see your window. Don't feel frustrated, just hold on to your patience a little while more, we are nearly home. We agree that you do not see the window. This is because when you say ' CreateWindow ' a window is created, but in memory. To see it on the screen you will have to use the function ' ShowWindow() ' . A glimpse of the window... Let us put in the line of code in our program to display the window. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; fp = fopen("c:\\z.txt","w"); fprintf(fp,"start\n"); RegisterClass(&a); fprintf(fp,"start1\n"); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Go ahead, you can build and run this program. Bingo! You can now see a window even if it is only for a nano second. Well you should be happy that you have now created your window, even if it is alive only for a nano second. But now and when you look at the output at DOS prompt in ' z.txt ' you will see that the function ' zzz ' has now been called more often. Your output will be something like below. start start1 1992..36..0..6618072 1992..129..0..6618108 1992..131..0..6618140 :: :: :: :: :: :: :: :: :: :: :: :: We are forced into not displaying the entire output due to lack of space. Now if you are satisfied with this achievement, we can assume that you are easily satisfied with very little. Now, now, don't get frustrated. Take a dose of the " anti - frustration " tablet we had recommended and get back to work. Now that we have got the hang of creating a window, let’s proceed further and try to keep our window alive until it closes, only when we want it to. Capturing the window... Let us put some more code in our program.and see what it does. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; fp = fopen("c:\\a.txt","w"); fprintf(fp,"start\n"); RegisterClass(&a); fprintf(fp,"start1\n"); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } The new lines of code which we have passed i.e. ‘ GetMessage() ’ and ‘ DispatchMessage() ’ shall be explained later. For the time being, just compile and run the program, keeping your faith in us. Executing the program, what do you see? Your faith in us is justified. We did not lead you astray. You can now view your window properly. But what is this? You have a window, but it is without clothes, you can see right through it. Are you not ashamed that your window is standing without any clothes in front of so many people ? Close it quickly. You now have a problem of providing your window with clothes. We shall learn, how to provide it with clothes, a little later. In the mean time, check your ' z.txt '. You'll see that the function ' zzz ' is now called more often that ever before. The ' z.txt ' file now looks as under start start1 3816..36..0..6618072 3816..129..0..6618108 3816..131..0..6618140 3816..1..0..6618108 :: :: :: :: :: :: :: :: :: :: :: :: Clothing the window... Let us proceed with the clothing of our window. Let’s see what we can achieve by adding some more lines of code in our program. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; FILE *fp; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(BLACK_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); fp = fopen("c:\\a.txt","w"); fprintf(fp,"start\n"); RegisterClass(&a); fprintf(fp,"start1\n"); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { fprintf(fp,"%u..%u..%u..%ld\n",w,x,y,z); if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } After you build and run the program, what do you see? You will see two things. One, that you now have a window which is completely clothed - though it appears to be in mourning as it is wearing dark black clothes - and the other, that the moment you bring the cursor inside the window, it changes to a cross ' + '. These changes are not appearing due to some black magic on our part. They are appearing because of the additional lines of code. Let us understand what these lines of codes mean. When you compiled this program you did not get any errors. This is because ' hbrBackground ' and ' hCursor ' are also members of our structure ' a '. The first member ' hbrBackground ' is used to store the background colour of the window. To get the background colour, you have to use a function ' GetStockObject() '. This function is passed a parameter, which is a Macro. This Macro - has already been assigned the number of a colour in the header file - knows which colour is to be displayed, which in our case is black. Now you can make some changes to this parameter using ' WHITE_BRUSH ' or ' GRAY_BRUSH '. You will see a nice white coloured window if you use ' WHITE_BRUSH ' and an old grayish looking window if you use the ' GRAY_BRUSH '. Similarly you are free to find out any other different colour in the header file as part of your R & D. Likewise in ' hCursor ' you are storing the value of the cursor which you get using the function ' LoadCursor() ' . This Macro is also pre-defined with the number in the header file . You have now seen the window on your screen, but have you bothered to look at your output in the ' z.txt ' file? If you have taken the pain to do so, you will see that the output there looks more or less as below. start start1 604..36..0..6618072 604..129..0..6618108 604..131..0..6618140 604..1..0..6618108 :: :: :: :: :: :: :: :: :: :: :: :: We know that you are too bored to keep going to the DOS prompt and seeing the output in the ' z.txt ' file. So let us now remove the ' FILE ' macro, and all the ' fprintf() ' functions from our program and execute it, retaining only the following codes. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Bet you did not notice it while writing the program. The colour of the background has been changed by us in this program to a peace loving white. This has been done by changing the value of ' a.hbrBackground ' from 'BLACK_BRUSH ' to 'WHITE_BRUSH'. Now when you execute this program, you’ll see that we still get our window - albeit one with a white background. If you get any errors, it means that either the Gods are angry with you or that you have not followed our coding correctly. Please recheck the code carefully and execute the program. It should not give you any errors and on execution should display the window to you. Changing the size of our window during runtime... Let us now change our program a little. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,SW_SHOWMAXIMIZED); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } The only change we made to our program is that we have changed the second parameter of ‘ ShowWindow() ’ from ' 1 ' to ' SW_SHOWMAXIMIZED '. What does this do ? If you execute this program you will see that our window now occupies the full screen. When you pass ' SW_SHOWMAXIMIZED ' as the second parameter to the ‘ ShowWindow() ’ function, the fourth, fifth, sixth and seventh parameter of the ‘ CreateWindow() ’ will lose their meaning. Even if we change them all to ' 0 ' the window will still be displayed over the whole screen. Similarly you can try with ' SW_SHOWMINIMIZED ' wherein your window will be in the minimised form when you execute the program no matter what you pass as the fourth, fifth, sixth and seventh parameters to ShowWindow. Then change this parameter to ' SW_SHOWNORMAL' . You will see that it works the same way as it did when you used ' 1 '. You can even try to change the second parameter of ‘ ShowWindow() ’ to 2 and 3. You will see that when you use ' 2 ', it works in a manner similar to ' SW_SHOWMINIMIZED ', and when you use ' 3 ' it works similar to ' SW_SHOWMAXIMIZED '. You can change to only these three numbers to have any meaning to your program, you try to change the parameter to any other positive number you will see that it works as if it takes ' 1 ' as the parameter. Trapping the mouse click in our window... Now let us tinker around with one of the parameter of the function ' zzz ' and see what happens. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { MessageBox(0,"Hi","Hi",0); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Whenever we say ' CreateWindow() ' or ' ShowWindow() ', the function ' zzz() ' gets called. Likewise, whenever Microsoft Windows wants to tell us something important, it calls the ' zzz ' function and conveys any information through it. It is high time that you learnt that ' x ', which is the second parameter of the function ' zzz ', is used to tell us as to why Windows is calling the ' zzz() ' function. You don't have to wonder what WM_LBUTTONDOWN is. It is nothing but a Macro. So now whenever you click with the mouse on the window, Microsoft puts four parameters on the stack. The second parameter is the number WM_LBUTTONDOWN. It is always easier to remember WM_LBUTTONDOWN than to remember it’s number. So in our case, what the window has been told, is that the left mouse button has been clicked and held down. The moment you click on the window, the function ' zzz ' is called and it puts the four parameters of this function on the stack. The second parameter i.e. ' x ' is now passed the number of ' WM_LBUTTONDOWN '. This is easily understood because we have trapped the mousebutton’s message, and the moment we click on our window, the MessageBox gets called. So now whenever you click with the left mouse button, you will see a MessageBox displayed on the window with the message "Hi" in it. Now for your R & D you can change WM_LBUTTONDOWN to WM_LBUTTONUP or use WM_RBUTTONDOWN or change it to WM_RBUTTONUP. With the first change you will see that the MessageBox is seen only after you release the mousebutton. With the second change you would see that now there is no MessageBox if you click with your left mouse button but you can see the MessageBox if you click with the right button. With the last change you will see the MessageBox being displayed only after you release the right mousebutton. Now let’s mess around with the parameters some more. We add the following lines of code to our program which now looks as follows. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,SW_SHOWMAXIMIZED); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { char aa[100]; int x1,y1; x1 = LOWORD(z); y1 = HIWORD(z); sprintf(aa,"%d..%d..",x1,y1); MessageBox(0,aa,aa,0); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Here, we have created a character array ' aa ' of size 100. We have also defined two ints x1 and y1. Now let us remember that a long is four bytes in length. Can't we treat a long as if it were made up of two ints, of two bytes each. Well that is exactly what we have done (remember that the last parameter of our function ' zzz ' is a long with a variable 'z'). The first two bytes of the variable ' z ' are read into x1, while the second two bytes are read into y1. Let us now understand what is stored in ' z '. The moment we click with our mousebutton in our window, the function ' zzz ' is called, and as usual, it puts the four parameters on the stack. The last parameter ' z ' stores the value of the ' x ' and ' y ' co-ordinates of our window in it. Thus when we store the first two bytes of ' z ' in ' x1 ' we get the ' x ' co-ordinates of our window. The next two bytes store the y co-ordinate of our window. That is the job of LOWORD(z) and HIWORD(z). Now whenever you click with the mousebutton on the window the ' x ' and ' y ' co-ordinates of that position is displayed in the MessageBox. Printing text on screen... Don't you feel bored looking at MessageBoxes all the time? You do! Well now that we have got the hang of how the ' C ' programming under Windows works, we shall try to do something in our window. In our next program we shall try to learn how to display some text on our window. So let’s roll ahead and learn how it is done. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { TextOut( LOWORD(z),HIWORD(z), "Hello",4); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Now in this program, we have used another function of ' C ' Windows programming, viz. ' TextOut() '. We ask this function to print ' hello ' at the position the mouse is clicked on the window. For this we have passed the parameters LOWORD(z) and HIWORD(z) to show the ' x ' and ' y ' co-ordinates of the window, as the first two parameters to our ‘ TextOut() ’ function.We have also passed to this function, the string which we want to display on the screen, as the third parameter. The last parameter however is explained in the next program. But when you compile this program the compiler is not satisfied with the number of parameters you have passed. It gives you an error ,which states, " 'TextOutA' : too few actual parameters ". This shows that we have passed the function a parameter too less. Now let us understand that, whenever we want to display text on the screen of our window, we have to specify the font size, the colour, etc. Now how do we do this? Well whenever you want to specify these things, you have to use a Device Context called ' GetDC '. You have to pass this Device Context a parameter, which should be the number of our window. Where should we search for this window number? Don't worry, this window number is stored in the first parameter of our ' zzz ' function. This variable has to be passed as the parameter to the ' GetDC() ' function. You can check and see that both ' w ' and ' b ' - the variable which we used to create our window - will have the same value. Simply writing 'GetDC(w)' will not solve your problem. This function returns an int which is stored in a variable and passed as the first parameter to the function ' TextOut '. For this purpose in our next program we have created a variable ' h ' which looks like a Macro ' HDC '. This Macro has been predefined as an unsigned int in our header file . We don't know how it is with you, but with us, we have a rule that, whenever we borrow something from others, we should always return it back. This rule of ours applies in this program also. It is always good programming sense to return the variable, which we use, back to our function ‘ zzz() ’. We have used the variables ' w ' and ' h ' in our ' GetDC ' Device Context, so it is only proper that we return this Device Context back. To return the variables, on exiting from ‘ GetDC() ’ back to the function ’ zzz() ’, we have to use the function ' ReleaseDC() '. This function takes the window handle and Device Context - which we return - as it’s parameters. So now we have changed our program which looks as under. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; HDC h; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { h = GetDC(w); TextOut(h,LOWORD(z),HIWORD(z), "Hello",4); ReleaseDC(w,h); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Now on building this program, you get no errors. Now, when you click on the window you now see a "Hello" at the position where you have clicked on the window. What ? You are not getting a "Hello"? What do you get? You get " Hell ". Well you may have put " Hell " as your string. No? You have put " Hello ". Well it may be because of one of the two reasons. One being that you have really been going through "Hell" in trying to understand ' C ' Windows programming. Or, it may be because you have passed ' 4 ' as the fourth parameter of our TextOut function which specifies the number of characters of the string which has to be displayed on the screen. Try putting ' 5 ' as the parameter and run it. You will now see " Hello " on your window. Changing the text colour... Let us make one small change to our program #include #include WNDCLASS a; long _stdcall zzz(); HWND b; HDC h; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { h = GetDC(w); SetTextColor(h,RGB(255,0,0)); TextOut(h,LOWORD(z),HIWORD(z), "Hello",4); ReleaseDC(w,h); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } We were not satisfied with getting the text on our screen in black. So with the ' SetTextColor() ' function, we are passing the colour we want the text to be printed in. Please do not try to correct our incorrect spelling of the word colour in the program (We know the spelling of colour but the ' C ' program was designed by an American and all Americans spell colour as ' c.o.l.o.r ', so that is how you have to spell it if you want your program to work). This function asks for two parameters. The first parameter is a Device Context, so we pass it ' h ' which is assigned the value of our 'GetDC' Device Context. The second parameter is a function which specifies the colour we want. Now we shall explain what 'RGB()' function means. Windows knows only the three basic colours red, green and blue. So when you use 'RGB()' you have to specify as to how much of each colour you want. You can choose from a minimum of ' 0 ' to a maximum of ' 255 '. These requirements of yours are specified as the three parameters to this ' RGB() ' function. They are then mixed together, to form the colour which you want, and displays the text in that colour as your output. In our case we have chosen the maximum value we can assign to ' red ', so do not be surprised and scream for help if you see "Hell" in blood red. You can choose some other value to specify the colour you want and check out the result - This can be a part of your R&D. Learning to write with the mouse... Have you ever had the urge to write on your window with a mouse. If you have the urge, then the next program will help you to write on screen with your mouse. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; HDC h; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while (GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { h = GetDC(w); SetPixel(h,LOWORD(z),HIWORD(z),RGB(255,0,0)); ReleaseDC(w,h); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Whenever we want to see something on the screen we have to call the ' GetDC ' Device Context. Now we are wanting to write with the mouse, hence the first thing is to call this Device Context. Here we are putting ' Pixels ' or dots on the screen when we say ' SetPixel () '. This function has to be passed four parameters. The first should be the variable in which the return value of the ' GetDC() ' Device Context is stored. The second and third parameters are the 'x ' and ' y ' co-ordinates of the position where you click with the mouse on your screen. The last parameter specifies the colour, the pixel should appear on the screen. When you build and execute this program, you’ll see a dot appearing on the screen at the position where you have clicked with the mouse. You should be happy that you can now, not only write but also draw with your mouse on your window. We can however bet that you are unhappy, as you have to keep clicking with the mouse again and again umpteen number of times, to write a simple word on the screen. Well try making a change to your program i.e. change WM_LBUTTONDOWN to WM_MOUSEMOVE. Now you will see that when you move the mouse - without pressing the mousebutton - on your window screen, pixels start appearing at each of the mouse position. Now position your mouse at one corner of your window and move it across the screen in a fast motion you see that five or six pixels appear on screen but when you move the mouse slowly more number of pixels appear on your window. When you move your mouse fast, the ' zzz ' function is called a fewer number of times whereas, if you move it slowly the function is called more number of times. Hence you see more pixels appearing on the screen. You may still not be satisfied as you have to move your mouse slowly across the screen when you want to write something on the screen, well then use the keyboard. Why do you think all the companies keep providing you with keyboards if all the writing could be done with a mouse. Drawing a line... If you have finished with you artistic skills we can proceed further in a newer direction. Let us now draw a straight line in our window. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; HDC h; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { h = GetDC(w); LineTo(h,LOWORD(z),HIWORD(z)); ReleaseDC(w,h); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } You can see how easy it is to draw a line in the above program. You just have to call the function ' LineTo() ', pass it three parameters - the first being the value of our ' GetDC ' Device Context. The other two parameters are the ' x ' and ' y ' co-ordinates of your mouse position - and you see the line. Well, the job is done, we have drawn the line in our window. But don't you find it odd, that whenever you click on the window, it draws a line, from the position of the mouse on the screen to the top left hand corner of our window. Let us understand what happens. When we call the ' GetDC ' function it makes the position ' 0,0 ' of your window as the active pixel. Hence whenever you click on the window the line will be drawn from that active pixel to the position where your mouse is. Adding one more line of code to your program you get #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; HDC h; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { h = GetDC(w); LineTo(h,LOWORD(z),HIWORD(z)); LineTo(h,LOWORD(z),HIWORD(z)); ReleaseDC(w,h); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } What did this additional code avail us? If you think nothing, think again. Don't you now see a line drawn from the top left hand corner of your screen to the position where the mouse has been clicked and again another line drawn which goes straight down from that position. This shows that, when the mouse is clicked and the ' LineTo ' function is called, the active pixel which was at ' 0,0 ' in the beginning, is now passed on to that position where the mouse is clicked. Hence when the second ' LineTo ' function is called, it is from this position that the line is drawn on our window. You can try increasing the LOWORD(z) by some value and seeing the output. You can follow the trail of the active pixel, and see how it keeps changing as the next ' LineTo ' function gets called. Let's try another program and see how we can draw a line form our mouse position to another active pixel which we defined. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; HDC h; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { h = GetDC(w); MoveToEx(h,1,100,0); LineTo(h,LOWORD(z),HIWORD(z)); ReleaseDC(w,h); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } In this program, you see that when you click on the window, a line is drawn from the position of your window screen, where the 'x ' co-ordinate is '1' and the ' y ' co-ordinate is ' 100 ' to the position where the mouse has been clicked. If you don't believe us, you can count the number of pixels and see for yourself whether we are bluffing. Now whenever we want to move the active pixel from the ' 0,0 ' position to a new position, we have to use the ' MoveToEx() ' function. This function has to be passed four parameters. The first parameter is to be the ' GetDC() ' number, the second and third parameter are the ' x ' and 'y' co-ordinates respectively. The last parameter is ' 0 ' and hence we will not explain it. Whenever you want to change the active pixel from the ' 0,0 ' position to a new position you can use the ' MoveToEx ' function. Using this function in our next program, we now try to draw a line between any two position in our window. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; HDC h; int ii = 0; int x1,y1; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { if (ii = = 0) { ii = 1; x1 = LOWORD(z); y1 = HIWORD(z); } else { ii = 0; h = GetDC(w); MoveToEx(h,x1,y1,0); LineTo(h,LOWORD(z),HIWORD(z)); ReleaseDC(w,h); } } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Let us understand what we have done in this program. We have declared three global variables of the data type ' int ' viz. ii , x1 and y1. Now when you click with the mouse on your window the value of ii, which is ' 0 ', changes to ' 1 ' and the 'x ' and ' y ' co-ordinates of this position get stored in ' x1 ' and ' y1 ' respectively. Now when you again click with the mouse, the value of ii changes back to ' 1 '. The ' MoveTo() ' functions then makes x1 and y1 the active pixel, so now when the ' LineTo ' function gets called the line is drawn from the present mouse position to this active pixel. Now you can keep drawing as many lines as you want as the value of ' ii ' keeps alternating between ' 1 ' and ' 0 '. Designing with the mouse... Previously, we had written a program where you were able to write with the mouse on your window. But there you had got bored with it as you had to move the mouse very slowly across the screen. You also had to keep in mind that you had move the mouse fast when you had finished and wanted to move out of the screen. It still showed a trail of pixels across the screen and thus ruined your design. When you wanted to go back to the same position you came back to that position leaving a trail of pixels behind your mouse. Seeing your hurt expression we decided to show you another program where all these difficulties come to an end. So let’s write the same type of program, but in a different manner. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; HDC h; int ii = 0; int x1,y1; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_LBUTTONDOWN) { ii = 1; h = GetDC(w); MoveToEx(h,LOWORD(z),HIWORD(z),0); } if (x = = WM_LBUTTONUP) { ii = 0; ReleaseDC(w,h); } if (x = = WM_MOUSEMOVE) { if( ii = = 1) LineTo(h,LOWORD(z),HIWORD(z)); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } In this program we are using three of the mouse functions viz. the WM_LBUTTONDOWN, WM_LBUTTONUP and the WM_MOUSEMOVE. By now you should be familiar with these three mouse button functions. Now when you click with the left mouse button and keep it pressed the first ' if ' statement will get called. In this ' if ' statement we are merely initialising the active mouse pixel to that position where we have clicked with the mouse button. When you move the mouse - keeping the left mouse button held down - you will now see that it keeps drawing a line to the previous pixel i.e. the active pixel keeps changing. Now with moving the mouse on your window you’ll see that even if you move it fast there will be no blank trails in the mouse move. The code for this happening is passed in the WM_MOUSEMOVE's ' if ' statement. The mouse will stop drawing on the screen the moment you release the mouse button. This is because of the code you have passed in the WM_LBUTTONUP's ' if ' statement that the moment you release the mouse button the value of ' ii ' changes back to ' 0 ' and hence ' WM_MOUSEMOVE ' does not get called. Isn't this program superior to the previous program - in the sense that you can now draw faster with your mouse? Callback function... Now let us learn something which is different to these mouse moves. Let us learn what a callback function is ? In a program, there is a function that is used ( by the Microsoft Windows in our case ) to let us know of any events that are taking place in our window. This function keeps getting called repeatedly and hence it is called as the callback function. In our program the function ' zzz ' gets called every time the windows wants to tell us whatever is happening in it. Hence, this is our callback function. Let us put some different code in our program and see what happens. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,2); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_QUERYOPEN) { MessageBox(0,"Hi","Hi",0); return 0; } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } In our previous programs, after execution, whenever we had minimized and maximized the window it used to get maximized without giving us any problems. We had never understood then - nor cared - which function was getting called, when our window was being maximized. On executing our program, the window is displayed in the minimized state. Now click on it to maximize it. You’ll now see that it does not get maximized, in fact try clicking on it as many number of times as you want, it will stubbornly refuse to get maximized. Now Windows whenever it is asked to maximizes a window it asks a question. He asks whether we want him to maximize the window for us, yes or no? At this point in time, it asks us the question by sending us a WM_QUERYOPEN Message. If you return a ' 0 ' in response to this question, it means that you are telling Windows not to maximize our window. Previously in all our other programs, we had never tried to trap this message anywhere. So it turned to ‘ DefWindowProc() ‘. Now ‘ DefWindowProc() ‘ by default always returns 1 and hence the window used to get maximized. But in this program we have trapped this message and returned ' 0 ' to it , which means that we are now telling Windows not to maximize our application. Hence now find yourself unable to maximize your application. To now remove this program from memory you have to either press ' Alt-F4 ', or go to the status bar - to the position where our window has been minimized - and click with the right mouse button and close the window. There is also another way to remove this window from memory which will be explained later. Creating a MenuBar... Enough of these commands, now let us try to create a MenuBar. By now you should be able to write the shortest program in ' C ' under Windows without any problem. So let’s create a new project workspace and open a text file. We have created a project ' aa ' in our root directory along with a File of the type ' TextFile ' called as ' aa.c ' . We advise you to do the same as it will be easier to understand. Let’s write that program we have learnt and insert one more line to the code and see what happens. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Compile and execute this program to see what happens. On execution there is nothing additional to our window. Now the question is, what new thing have we learnt in this program? Well, at a glance, we have at least shown you one more member of the structure ' a ' i.e. our structure which looks like ' WNDCLASS '. It is this member of the structure, which stores the menu name. Now we have to understand that a menu has nothing to do with your program. All that we can now do is, in a separate file i.e. a rc file, we can writing code which will display a menu for us. This file should be saved as an ' .rc ' file. For accomplishing this task we can go to the DOS prompt and create a new file in our directory ‘ aa ’ having the name ' aa.rc '. In this file we type in the following details AAA MENU BEGIN MENUITEM "A1",100 MENUITEM "A2",101 END What do these lines of code mean? Here we are passing the codes which specify as to what we want to do with the MenuBar. These codes will be explained, but before that why don't we go back to our program and insert this file into our project? To insert this file into our project follow the following steps: Select Project from your menu bar Choose Add to projects Choose files Here you will see a dialog box, where you should click on aa.rc and select " insert ". Now that your insertion is complete you can build the program once again. On execution of the program you can see a MenuBar with " A1 " and " A2 " on your window. Let us explain what has happened. Whenever you have to pass some codes of our MenuBar - which are not part of the actual creation of the window - you have to pass them in a separate file. This file is called a resource file and it is to be saved as a ' .rc ' file. By the insertion of this resource file in our project, the compiler on compilation reads it’s contents. Now seeing that the first line of the resource file is the name of our MenuBar it promptly displays the MenuBar on our window screen. While we are in the topic of resource files let us also understand as to what code we have passed to our MenuBar. The first line shows the name as "AAA" and that it is our Menu name. Now any code we have to pass in the resource file has to start with a " begin " statement. The compiler now knows that we have started with our coding part and reads it accordingly. In the third line we have a "menuitem" which is "A1", this has been given a number viz. ' 100 ' - in future whenever we call our command button and specify ' 100 ' it knows which menu item is to be called - we can understand the use of ' 100 ' better in another program. In the meantime let’s continue with our understanding of the other lines of the file. The fourth line is similar to the third line with the exception that the menuitem's name and number is different. Don't you think that it is always good to end whatever you have begun? Well the last line ends the code you had started when you said begin. The statements in the resource files are not case sensitive, except for the numbers which should be in the lower case. Creating a popup... Let us now learn how to create a popup. To create a popup you just have to change the resousce file in the following manner. AAA MENU BEGIN POPUP "ABC" BEGIN MENUITEM "A1",100 MENUITEM "A2",101 END END When you say " popup " the compiler knows that you want to create a popup menubar. Now inside a " begin " statement we have another " begin " statement in which you display the menu items you want to see in your popup. Since we have two " begin " statements in our resource file we also should also have two " end " statement in it. Individual selection of menuitems... Let us learn how to select a menuitem from our MenuBar. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x = = WM_COMMAND) { MessageBox(0,"Hi","Hello",0); } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } The ' WM_COMMAND ' which is used here, captures the selection of the menuitems. But here we have not specified, as to which menuitem when clicked, is to display the MessageBox. So, on clicking any of the two menuitems, you see the same MessageBox being displayed. Importance of the numbers passed to our menuitems... So far in our previous programs, you have learnt what three, of the four parameters, of our callback function mean viz. ' w ' which is our window number, ' x ' which tells us as to why our window is being called and ' z ' which tells us what is the position of the mouse on our screen. Let us now learn what the other parameter ' y ' does. The parameter ' y ' is number which tells us the selection made in our window. Let us now use this parameter to capture the menuitem we want to select from our MenuBar. Here we shall also learn the importance of the number which we had passed as a value in our resource file. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x = = WM_COMMAND) { if(y = =100) { MessageBox(0,"Hi","Hi",0); } else if(y = =101) { MessageBox(0,"Bye","Bye",0); } } if (x = = WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } In this program the additional code which you have passed in ' WM_COMMAND ' specifies the menuitem you have selected. Remember, we had given ' 100 ' as the number to ' A1 ' and ' 101 ' to ' A2 ', hence on selection of ' A1 ' we get a different MessageBox as compared to the MessageBox we get when we select 'A2 '. Now that you have learnt about MenuBars, menuitems and popups why don't you try to create a MenuBar with two or more popups and different menuitems as part of your R & D. Capturing the System's Menuitem... Now that you have learnt of how to capture the menuitems selected from your popup, we shall learn how to capture the menuitems of the System popup. To do this you have to first learn where the System menu exists. Now if you were an observant person, you would have seen that when your window is created, on the topmost left hand corner of your window there is a picture. This picture is provided by Microsoft Windows, to our window - the one which we create in our program - free of charge. When you click with the mouse on this picture, that you will see your System popup menu displayed. So let’s learn how to trap these command. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x == WM_SYSCOMMAND) { MessageBox(0,"Hi","Hi",0); } if (x == WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } Now on execution of our program, whenever you click on any of the System’s menu item you will see the MessageBox being displayed. You will also see that when you click anywhere on the System MenuBar - it being in someway or the other effecting your System popup - your MessageBox being displayed. Let’s make a small change in our program and see what it does. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x == WM_SYSCOMMAND && y == SC_CLOSE) { MessageBox(0,"Hi","Hi",0); return 1; } if (x == WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } There are two changes in our program. We have extended the ' if ' statement by anding it with the ' y ' parameter to trap the close button of the System menu popup. We have also returned a value to our ' if ' condition. Execute the program and try to close it. What do you see? Don't you see your MessageBox ? Well, go ahead and close your window. Go ahead, we dare you to close the window using any of the limited commands at your disposal. Well you can't ? Now, now don't get upset. Just like in our normal menu we had given the numbers ' 100 ' , ' 101 ' to our menuitems, similarly the Windows menu has also given our application’s menuitems the numbers ' SC_CLOSE ', 'SC_MOVE ', ' SC_SIZE', etc. In our program we have trapped the ' SC_CLOSE ' number in our ' if ' statement, so now you will see the MessageBox being displayed only when you click on close or you click on the ‘ x ‘ on your menu bar or you use "Alt+F4". You click on any other menuitem, you will not see the MessageBox. Keep in mind that your parameter ' x ' i.e. which tells us when the callback function is called, is ' WM_SYSCOMMAND '. To get out of your window you have to press " Ctrl + Alt + Del " only once. You will get a dialog box. select " Bye " from it and say " End Task " to come out of the program. If you press " Ctrl + Alt + Del " twice you will be rebooting your machine. Let us learn why you could not close the window. Normally when you close the window, your 'if ' condition does not return a value. So whenever you click on ' x ' on the Menubar or you press 'Alt + F4 ' or say close on the System Menu, you return the values used - in the callback function - in the ' DefWindowProc() ', and after it receives all the values, ‘ DefWindowProc() ‘ start it's shutdown process and closes your window. Now when you return a value in the ' if ' statement, you say that the ‘ DefWindowProc() ‘ is not to be called and since it does not get called, the values of ' x ' and ' y ' - which in our case is "WM_SYSCOMMAND' and 'SC_CLOSE' respectively - does not reach it. And since the values of ' x ' and ' y ' do not reach it, the ‘ DefWindowProc() ‘ does not start the shutdown procedure of our window and it can't close. You now have to call the anytime troubleshooter " Ctrl + Alt + Del " button to shutdown our window. Now let’s remove the return statement, and put in some other code. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x == WM_SYSCOMMAND && y == SC_CLOSE) { MessageBox(0,"Hi","Hi",0); } if(x == WM_CLOSE) { MessageBox(0,"Close","Close",0); } if (x == WM_DESTROY) PostQuitMessage(0); return DefWindowProc(w,x,y,z); } After you compile and run this program you now see two MessageBoxes. The first with the message "Hi" in it and the second with the message "close" in it. This shows that when you close the window i.e. when you click on " close " in the System menu or you press " Alt + F4 " or when you click on th 'x' on the System's MenuBar, ‘ DefWindowProc() ‘ receives the values of ' x ' and ' y ' and sends your window a WM_CLOSE message.You will however encounter the same problem you had in the previous program if you return a value to it i.e. you will be unable to close your window. Now let’s add just two more lines of code to our program. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x == WM_SYSCOMMAND && y == SC_CLOSE) { MessageBox(0,"Hi","Hi",0); } if(x == WM_CLOSE) { MessageBox(0,"Close","Close",0); } if (x == WM_DESTROY) { MessageBox(0,"in Wm_Destroy", "in Wm_Destroy",0); PostQuitMessage(0); } return DefWindowProc(w,x,y,z); Run the program, and close the window. What do you find ? You find that, you are now getting three MessageBoxes. This shows that when you close the window even the WM_DESTROY gets called as part of the shutdown process. But this WM_DESTROY gets called after WM_CLOSE. So we now know that, whenever you want to close your window ‘ DefWindowProc() ‘ first calls SC_CLOSE which calls WM_CLOSE which in turn calls WM_DESTROY. Give the WM_CLOSE a return value and you will see that again the value of ' x ' and ' y ' does not reach the ‘ DefWindowProc() ‘, and hence you cannot close your window. The MessageBox which we have put inside the WM_DESTROY will also not be seen. Now let’s also pass the ' if ' statement of WM_CLOSE a ' DestroyWindow() ' and see what happens. Our program now looks as under. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); a.lpszMenuName = "AAA"; RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x == WM_SYSCOMMAND && y == SC_CLOSE) { MessageBox(0,"Hi","Hi",0); } if(x == WM_CLOSE) { MessageBox(0,"Close","Bye",0); DestroyWindow(w); return 1; } if (x == WM_DESTROY) { MessageBox(0,"in wm_destroy", "in wm_destroy", 0); PostQuitMessage(0); } return DefWindowProc(w,x,y,z); } You now see that all three MessageBoxes are called. But now, inspite of giving a return value in WM_CLOSE, you notice that the window closes. Well, let us understand why this is happening. When ever you close the window using any of the three methods to close the window i.e. when you click on " close " in the System menu or you press " Alt + F4 " or when you click on th 'x' on your window’s MenuBar, your window receives a ' WM_SYSCOMMAND ' and a ' SC_CLOSE ' which is given to ‘ DefWindowProc() ‘. Now ‘ DefWindowProc() ‘ has an ' if ' statement in it by which it sends our window a ' WM_CLOSE ' message. So now if you do not do anything with the ' WM_CLOSE ' message and give it back untampered to ‘ DefWindowProc() ‘ it invokes a function called ' DestroyWindow() '. The job of ' DestroyWindow() ' is to remove your window from the screen and send your callback function a WM_DESTROY message. Now as we were doing the same shutdown process which ‘ DefWindowProc() ‘ uses - when he receives the WM_CLOSE message - we were able to close down our window without any problems. So far the only function that we have not learnt about is the ‘ PostQuitMessage() ’ function. Let us remove this function in our next program and see what changes take place to our window and why. #include #include WNDCLASS a; long _stdcall zzz(); HWND b; MSG c; HDC h; int ii = 0; int x1,y1; _stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l) { a.hInstance = i; a.lpszClassName = "Hi" ; a.lpfnWndProc = zzz; a.hbrBackground = GetStockObject(WHITE_BRUSH); a.hCursor = LoadCursor(0,IDC_CROSS); RegisterClass(&a); b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0); ShowWindow(b,1); while(GetMessage(&c,0,0,0)) DispatchMessage(&c); } long _stdcall zzz(UINT w, UINT x, UINT y, long z) { if(x == WM_SYSCOMMAND && y == SC_CLOSE) { MessageBox(0,"Hi","Hi",0); } if(x == WM_CLOSE) { MessageBox(0,"Close","Close",0); DestroyWindow(w); return 1; } if (x == WM_DESTROY) { MessageBox(0,"in wm_destroy", "in wm_destroy", 0); } return DefWindowProc(w,x,y,z); } Here, as explained in the previous program, the ‘ DestroyWindow() ’ function removes the window from the screen and sends a WM_DESTROY to ‘ DefWindowProc() ’. But now when ‘ DefWindowProc() ’ receives a WM_DESTROY he does nothing because there is no line of code passed in WM_DESTROY other than the MessageBox. This is bad programming. You’ll realise that because ‘ DestroyWindow() ’ function was called, the window is removed from the screen. But in your ‘ WinMain() ‘, you are still waiting in a ‘ while ’ loop with a ‘ GetMessage() ’ function. Now ‘ GetMessage() ’ is a blocking function. When we say blocking it means that the function wait’s. This is what gives Microsoft Windows the ability to multitask i.e. because it has blocking functions. Let's understand that, the moment you click on the window or press a key on the keyboard, the ‘ GetMessage() ’ function gets called. Windows knows, that the first parameter of this function, is a pointer to a structure that looks like MSG. This structure takes the same four parameters as the callback function ‘ zzz ’. So ‘ GetMessage() ’ fills up this structure and it returns a ‘ non 0 ’ value. It is the job of ‘ DispatchMessage() ’, who is given the address of this same structure, to now call your callback function. So we are always waiting at the ‘ GetMessage() ’ function. The only way this ‘ GetMessage() ’ function will return a ‘ 0 ‘ value, is when it receives a ‘ WM_QUIT ‘ message. The job of ‘ PostQuitMessage()’ function is to send a ‘ WM_QUIT ’ Message to the ‘ GetMessage() ’ function. Now because we have not put in the ‘ PostQuitMessage(0) ’ function in ‘ WM_DESTROY ’ the WM_QUIT message is not passed to the ‘ GetMessage() ’ and hence it is still waiting and because of this you window is not deleted from memory. All that if Microsoft had done was, if in their ‘ DefWindowProc() ’ function, they had an ‘ if ’ statement that said, ‘ x = = WM_DESTROY ’ PostQuitMessage(0) we would have had no problems and would not have had to learn this function. Wrapping it up... Well friends you can breathe a sigh of relief. That was the last program under ‘ C ‘ Windows Programming. We sincerly hope that you have learnt something out of this session, and if worse comes to worst, you should at least be able to say that you are a ‘ C ‘ Windows programer. We have tried to be meticulious with each program, and tried to explain each of them in a manner which may be easy to follow and understand.