Now that we know how to make a DLL, we should be able to understand more of C, so let's come back again to the syntax and take a closer look.
We have extensively used the switch statement above. This statement allows you to select several cases from the possible ones and act accordingly. It is composed from a switch expression that should evaluate to an integer result, and several pieces of code, associated to an integer value. The compiler generates code to evaluate the switch expression, and jump accordingly to the corresponding case.
In C, a case will continue with the next one, unless you finish it with a break expression, the same expression that is used to break from a loop.
switch (expr)
In this example, if expr is equal to 123, the expression a = p*6; will be executed, then the expression a = p*9; Yes, I know this is not evident, but it's like that, and zillion lines of code are already written that use this feature. Cases can be easily merged:
switch (expr)
Note that here a default case is missing. This is not a good practice, even if you do not want to do anything in the default case. More readable is:
switch (expr)
Here we see that you do NOT intend to do anything in the default case.
Another problem area is function pointer casting, what leads straight into gibberish-looking code.
int (APIENTRY *pfn)(char *,char *,int);
Better is to typedef such constructs with:
typedef int (APIENTRY *pfn)(char *,char *,int);
Now we declare our function pointer just with
pfn pfnGetString;
and we can cast the result of GetProcAddress easily with:
pfnGetString = (pfn)GetProcAddress( . );
Hiding the gibberish in a typedef is quite useful in this situations, and much more readable later.
In another level, what those programs show us is how to do event-oriented programs, i.e. programs designed to react to a series of events furnished by the event stream.
Under windows, each program should make this event-stream pump turn, by writing somewhere:
while (GetMessage())
we will describe the exact syntax later. This message-pump is hidden now from view under the DefDlgProc procedure, but it is the source of all the messages passed to the dialog procedure that we defined.
A windows program is designed to react to those messages, or events. It will process them in sequence, until it decides to stop the message pump ending the program.
The general structure is then:
Initialize the application, register the window classes, etc.
Start the message pump
Process events until a predefined event (generally the closing of the main window) provokes the stop of the message pump.
Cleanup
This was the standard way of windows programming until the C++ "wizards" decided that this message pump was too ugly to be shown to programmers and hid it behind an "application object". Later, several years later, things changed again and the ATL environment made the famous "message pump" visible again.
Texts started appearing explaining the surprised programmers what was WinMain and that "message pump" that was again the non-plus-ultra of modernity. Luckily for people programming in C, all those fads were invisible. Since C programming emphasizes low-level knowledge of what is going on, the "message pump" has always been there and we knew about it.
Messages are sent to window objects that are members of a class of similar objects or window class. The procedure SendMessage can also send messages to a window object, as if they would have been sent by the system itself. We send, for instance, the message EM_SETLIMITTEXT to an entry field to set the maximum number of characters that the entry field will process.
The system relies on the window procedure passing all messages that it doesn't handle to the default message procedure for that class of objects, to maintain a coherent view of the desktop and to avoid unnecessary code duplication at each window.
We are now ready to start our next project: building a real window, not just a simple dialog.
Application frameworks like MFC introduce an additional simplifying layer between you and the operating system. Much has been said and written about them, and here I will not discuss this in much more detail. Suffice to note that the purpose of lcc-win32 is to let you be always in control of what is going on. You can do here anything, contrary to a framework, where you can only do what the framework provides for, and nothing else.
True, an application framework can simplify the coding, and many people use them. It would be feasible to build such a framework with lcc-win32, but . I will leave this problem "as an exercise to the reader".
In the data processing field, we have been always recycling very old ideas as "new, just improved". Object oriented programming was an idea that came from the old days of Simula in the beginning of the seventies but was "rediscovered" or rather "reinvented" in the late 80s. Garbage collection was standard in lisp systems in the seventies, and now has been discovered again by Mr. Bill Gates, in the next century, with his proposal for the C# language.
|