|  | There are some basic concepts and ideologies behind the way this library was created that you should learn before moving on to the actual nuts and bolts of it. #### File Structure The following is a view of all the header files in the library and how they are logically grouped from the bottom up. As you can see, your application need simply include <gs_lib.h> to access the functionality of the library.
                                      gs_common
                                          |
                                      gs_debug
                            ______________|___________________________________________
                           |              |               |                |          |
                gs_directdraw      gs_directinput  gs_directmusic  gs_winstandard  gs_timer
                gs_surface         gs_keyboard     gs_directsound          |          |
                gs_font                   |               |                |          |
                gs_deviceenumerator       |               |                |          |
                           |______________|_______________|________________|__________|
                                          |
                                      gs_helper
                                          |
                                        gs_lib
                                          |
                                   your application
#### Singletons The way the library is designed is based for the most part on the idea of "singletons". As the name implies, there can only be one instance of a singleton object in an entire application. Typical examples of singletons are the keyboard or mouse on a system, or a file manager in an operating system. In this library, the singleton objects are the following: DirectDrawObject PrimarySurfaceObject DirectInputObject KeyboardObject DirectSoundObject DirectMusicObject MouseObject So what does this all mean? How does this change the way I use these objects? Simple: the constructors for these objects are not public, so you cannot do this:
    DirectDrawObject DDrawObject;
The compiler will not allow this because it cannot construct this object. So how do you get access to this object? Simple, you use a special member function called "Instance()" to retrieve the single instance of this object as follows:
    DirectDrawObject *pDDrawObject = DirectDrawObject::Instance();
This may seem more complicated, but there are many advantages to using singletons:
| There is no way you can have more than one instance of a singleton object.
| You don't need to keep global variables nor pass a singleton to functions because you can always use the "Instance()" function anywhere to retrieve it.
The only disadvantage to using singletons is that their destructors are not automatically called, so to properly destroy them, you should call the "DestroyInstance()" member function. Of course, even if you don't, the OS will clean up the unallocated memory, so this isn't a huge problem. So now you know what singletons are and how to use them. The sample code shows how to use them in more detail. After a while, you will become very comfortable with singletons so don't worry about it if it seems complicated. #### Object Creation Nearly all objects in the library must be created through their "Create()" member function. Some may argue that such creation should be accomplished by the constructors of the objects; however, I opted for this method because it allows you to have objects in the library exist as data members of a class. If constructor parameters were required, then you could not do this because C++ does not allow you to initialize data members directly (they must be initialized in the constructor). #### Debugging A special debugging mechanism exists in the library in order to catch any errors produced by the program or common mistakes that are made by programmers using the library. This debugging mechanism is only available when the project is compiled in Debug mode; in Release mode, I have made every effort to make the program run as fast as possible by removing extra error-checking and debugging. Thus, it is highly recommended that you compile in Debug mode during development and only compile the release version in Release mode (naturally). The debugging mechanism provides the following:
| Every object created is given a unique identifier (ID) starting with '1', unless the object is a singleton, in which case it's ID is simply "--".
| When an error occurs, the application is killed and a message box appears explaining the error and providing the object ID as well as the member function in which the error occured.
| Certain events as well as generated errors are logged in a file called "debug.txt" which can be found in the root directory of the application. Although you can view this file with any text editor, it is often easier to read it using the "GS Debug Viewer" available in the \bin directory of the library.
To log your own special events, you should place the following in your code:
    #ifdef GS_DEBUG
    	DebugMsg(0, "Function", "Message");
    #endif