- The VCF's Project Host
   The VCF Website Home   |   Online Discussion Forums   | Project Page   

Chapter 5. Tutorials

Table of Contents

5.1. FoundationKit
5.1.1. Strings and characters Strings Concatenating Strings Finding substrings Extracting substrings Formatting with the Format class Strings and other types Extracting type names Changing case Converting types to a String Trimming a String
5.1.2. Dates and times DatesAndTime
5.1.3. Reflection and RTTI Reflection
5.1.4. Events Event Basics
5.1.5. File System handling Files and Directories
5.1.6. Streams
5.1.7. Enumerators Working With Enumerators
5.1.8. Dictionaries Dictionaries
5.1.9. Dynamic Library Loading SharedLibraries
5.1.10. Threads ThreadBasics ThreadsInGUI Conditions
5.1.11. Processes
5.1.12. Internationalization and Unicode Localization
5.1.13. Resource Loading
5.2. GraphicsKit
5.2.1. GraphicsContext GraphicsBasics
5.2.2. Text and Fonts TextLayout
5.2.3. Images ImageBasics
5.2.4. Advanced Graphics and Anti-Aliased support StrokesAndFills GraphicsAndMouseMoves
5.2.5. Affine Transformations Transformations
5.2.6. Printing Printing
5.3. ApplicationKit
5.3.1. Hello World A Hello World application Hello World Part 2 HelloWorld3
5.3.2. Heavyweight vs. Lightweight Controls HeavyAndLight
5.3.3. Alignment, Anchors, and Layouts Alignment AdvancedAlignment Anchors
5.3.4. MVC Basics MVC Basics
5.3.5. Actions Actions
5.3.6. Clipboard Copy And Paste and the VCF Clipboard
5.3.7. Drag and drop DragAndDrop
5.3.8. Cursor handling
5.3.9. Scrolling Scrolling
5.3.10. Image viewer ImageViewer
5.3.11. Lists and combos
5.3.12. Tree view control
5.3.13. Tree list control
5.3.14. Table control
5.3.15. List view control
5.3.16. Dialog Usage Dialogs
5.3.17. Common dialogs (open, browse dir, select color, select font)
5.3.18. Window handling
5.3.19. Labels Labels
5.3.20. Text fields
5.3.21. Progress bar ProgressBars
5.3.22. Menus
5.3.23. Toolbars Toolbars
5.3.24. Table Control Tables
5.3.25. Splitter controls Splitters
5.3.26. Slider Sliders
5.3.27. Application and Window icons ApplicationIcons
5.3.28. Dates and Times UI DateTimeUI
5.3.29. Visual Form Files VisualFormFiles
5.3.30. Advanced User Interface AdvancedUI
5.3.31. Basic Document/View techniques DocViewBasics
5.3.32. Advanced Document/View DocViewAdvanced
5.3.33. System Tray SysTray
5.4. NetworkKit
5.4.1. Basic TCP server
5.4.2. Basic TCP client
5.4.3. UDP
5.5. RemoteObjectKit

5.1. FoundationKit

5.1.1. Strings and characters Strings

This will provide a brief overview of how to use the String class in the VCF. For more details on this see the String class in the source documentation and the Strings section in the FoundationKit reference manual. Concatenating Strings

You can easily add to a string by using the "+=" operator or "+" operator. The String class has essentially the same interface that the STL's basic_string class uses so any STL experience pays off with regards to the VCF's String class. You can assign strings through the "=" operator or using the String's constructor. For example:

String s1("Hello");
String s2 = "Hello";
String s3;
s3 += s2 + " World";
System::println( s3 );//outputs "Hello World" Finding substrings

You can search a String just like you can an STL string using the String's find() function. It works exactly like the STL basic_string::find() does. For example:

String s = "here's some text.";
size_t pos = s.find("here");
if ( pos != String::npos ) {
	System::println( "Found the string!" );

pos = s.find("Huck Finn");
if ( pos == String::npos ) {
	System::println( "Didn't find the string!" );
} Extracting substrings

You can extract a a substring from a String just like you can an STL string using the String's substr() function. It works exactly like the STL basic_string::substr() does. For example:

String s = "here's some text.";
System::println( s.substr( s.find("some"), 4 ) ); //prints out "some" Formatting with the Format class

In the VCF we've gone out of our way to get rid of the usage of variable argument functions for string formatting. Typically you might use printf or sprintf to do this. In the VCF we use the Format class to do this. The Format constructor takes a formatting string, and the Format class provides an overload of the "%" operator to add variable arguments. For example:

String s = Format("Say hello %d times.") % 100; //s will equal "Say hello 100 times."	

You can format strings easily - you can pass in the whole string object, as opposed to just passing in a pointer to the character data.

String myName = "Bobby Fillagutty";
String s = Format("My name is %s.") % myName; //s will equal "My name is Bobby Fillagutty."	

You can format multiple arguments by simply following the previous argument with another "%" operator. Since the Format's "%" operator overload returns a reference to the Format object, you can easily use it for a variable number of arguments. For example:

System::println( Format("The planet %s orbits at a distance of %u AU from the Sun.") % "Krypton" % 100000 );

This will output "The planet Krypton orbits at a distance of 100000 AU from the Sun.".

The formatting codes for the Format class are identical to those used for printf or sprintf. Strings and other types

There are concatenation operators provided for various primitive types to make it easy to form more complex strings. For example, you can concatenate integer values or even bool values to a string:

String bigString = String("Some info is ")  + true + " but some is worth " + 100.342 + " times it's weight in gold." ;

The value of the string will be "Some info is true but some is worth 100.342 times it's weight in gold.".

You can concatenate complex objects as well, so long as the class derives in some way from VCF::Object. For example:

class Foo : public VCF::Object {
	virtual VCF::String toString() {
		return VCF::String("Foo here!\n\t") + Object::toString();

Foo f;
System::println( String("f is: ") + f + "\n" + 99.5643231 + " bottles of " + &f + " on the wall!" );

The Foo's toString() function will be called to convert the foo instance to a string. Extracting type names

You can extract the type name of a primitive type by using the typeid() operator, in conjunction with a string. This is not the same as calling the type_info::name() function. The difference is that the VCF makes certain guarantees about what is returned. For example, if you call typeid(int).name() using Microsoft Visual C++, you get "int" returned, however the same code when compiled with GCC's G++ will output "i" (or maybe something different, it may depend on the version). The VCF string extraction routines will always output "int". For example:

int i = 0;
bool j = false;
const double* k = NULL;
float l = 0;	
System::println( "i is a " + typeid(i) + " type" );
System::println( "j is a " + typeid(j) + " type" );
System::println( "k is a " + typeid(k) + " type" );
System::println( "l is a " + typeid(l) + " type" );

This will output

i is a int type
j is a bool type
k is a double const * type
l is a float type Changing case

You can change the case of a string by using the StringUtils::lowerCase() and StringUtils::upperCase(). Both functions take a string reference and modify this string. So if we had:

String s = "Some text to chAngE.";

The variable "s" is now uppercased to "SOME TEXT TO CHANGE.", as opposed to returning a new string. If you don't want to have the original string modified then you need to make a copy of it. For example:

String s = "Some text to chAngE.";
String s2 = s;

The uppercase/lowercase conversion is not locale or culture sensitive. If you want an accurate case conversion that takes the locale into consideration, then use the Locale class's Locale::toLowerCase() and Locale::toUpperCase(). Converting types to a String

You can convert an int, long, double, and so on, to a string by using the StringUtils::toString() functions. For example:

String val = StringUtils::toString( 12 );
System::println( Format("value: %s") % val );

val = StringUtils::toString( 1234.009459034 );
System::println( Format("value: %s") % val );

val = StringUtils::toString( 53433.000034f );
System::println( Format("value: %s") % val );

val = StringUtils::toString( true );
System::println( Format("value: %s") % val );

val = StringUtils::toString( false );
System::println( Format("value: %s") % val );

This will output:

value: 12
value: 1234.00946
value: 53433.00000
value: true
value: false Trimming a String
Strings can be trimmed using the StringUtils::trim(), StringUtils::trimLeft(), and StringUtils::trimRight() functions. These all take a string source reference to operate on, and a string of characters to trim from the source.

5.1.2. Dates and times DatesAndTime

Your content here, explaining the usage/functioning of your example.

5.1.3. Reflection and RTTI Reflection

Your content here, explaining the usage/functioning of your example.

5.1.4. Events Event Basics

This example will explain how to work with events in the VCF, and how to add event support to your own custom classes.

Event's are quite easy to use. You can receive notification of an event by registering an instance of an event handler with any valid Delegate instance on the object that will be firing the event you're interested in. Event handlers wrap a function call, which may be a class method, or a static function, and when the event is fired your event handler (and in turn your callback) will get called. Delegate classes are used to both store a collection of 0 or more event handlers, and to send the event to all registered event handlers. For each event the object fires, there should generally be a distinct Delegate instance. For example the Control classes fires off mouse down, mouse move, and mose up events (among others), and has a Delegate member variable for each (named MouseDown, MouseMove, and MouseUp). While most member variables in the VCF use camel casing for theirr naming standard, delegates do not to make them stand out more.

So lets look our first example. Let's create a very simple class that fires a single event when the class "talks".

class Simple : public Object {
	Delegate Talking;
	void talk() {
		Event e(this);
		Talking.fireEvent( &e );


Notice that we do have to derive the class from either VCF::Object or some other class that directly or indirectly inherits from VCF::Object. We have a single member variable, a Delegate called Talking, and we have a single method called talk() that fires off a talking event. It does this in two steps:

  • First it creates an event (and you can create the event on the stack), and passes in itself as the event's source.

  • Then it calls the Talking delegate's fireEvent() method, and passes in a pointer to the event (e).

Once the Talking delegate's fireEvent() method is called, it will pass the event to all the registered event handlers that have registered with the Talking delegate.

Next we'll examine some simple examples that make use of this, one with static functions, and then two different ways to with member functions. First we'll look at how to connect a static function to the Talking delegate as a callback.

void StaticTalkingCallBack( Event* e ) 
  //call back code here


When you declare the function it does have to follow certain rules, namely:

  • It must return "void".

  • It must take a single parameter, a pointer to a VCF::Event or some other class that derives (directly or indirectly) from VCF::Event.

Once you have declared the function, you can use that function as a callback by creating the appropriate EventHandler class, for example:

EventHandler* handler = new StaticEventHandlerInstance<Event>( StaticTalkingCallBack );
Simple simple;
simple.Talking.addHandler( handler );

The first linbe creates a StaticEventHandlerInstance, which is a template class that take a single template argument: the event type. In our case it's just a VCF::Event, so that's what use. Had the event that our static callback taken, been a NotifyEvent then we would have written:

EventHandler* handler = new StaticEventHandlerInstance<NotifyEvent>( StaticTalkingCallBack );

The next line creates an instance of the Simple class. The last line adds our event handler to the simple.Talking delegate.

One thing to note - the above code creates an event handler, but does not delete it. As is, we would have to write some code to take care of this. We'll see in the following examples how to use some of extra parameters in the event handler constructor to take care of this automatically for us.

Our next example will use the member function of a class. We'll define the as follows:

class SimpleCallBackClass : public Object {
	void onTalking( Event* e ) {
		//call back code here

As before we must observe the rules for a callback function. Now we can see how we register it with the Talking delegate.

Simple simple;
SimpleCallBackClass callback;
EventHandler* handler = new GenericEventHandler<SimpleCallBackClass>( callback, &SimpleCallBackClass::onTalking );	

simple.Talking += handler;

The first two lines create a Simple instance, and a SimpleCallBackClass instance. The next line creates and event handler for the SimpleCallBackClass's onTalking method. We create an instnce of the GenericEventHandler class, which is used to member functions that take a VCF::Event, and has a single template argument, the source class type. The source class is the class that the callback method is part of, os for our purposes this is the SimpleCallBackClass. Next we pass in two arguments to the GenericEventHandler constructor: a pointer to an instance of the source class (the callback variable) and the function pointer for the call back function (SimpleCallBackClass::onTalking). Now when the is called our event handler will get invoked and in turn call the SimpleCallBackClass::onTalking() method. As before, we have an event handler instance that needs to be cleaned up. Lets move to the next example to see how we handle that.

In our third and final example, we introduce a way to associate event handlers with a source and to clean up any event handlers automatically when the source is destroyed.

We'll create another class, but this time, instead of deriving from VCF::Object, we'll derive from VCF::ObjectWithEvents. By doing this we gain some extra functionality. First, we can name the event handlers and refer back to them at any given time during the life cyle of the object instance. Secondly, we no longer have to manuallly manage the lifetimes of the event handlers. When we create the event handler, if the source object derives from ObjectWithEvents, then the event handler's will be added to a list of event handlers maintained by the source, and when the source is destroyed, it will destroy any event handlers in it's list.

To see this in action, let's declare a new class like so:

class SimpleCallBackClass2 : public ObjectWithEvents {
	SimpleCallBackClass2() {
		//lets add an event handler to our collection
		EventHandler* handler = 
			new GenericEventHandler<SimpleCallBackClass2>( this, &SimpleCallBackClass2::onTalking, "SimpleCallBackClass2::onTalking" );		
	void onTalking( Event* e ) {
		//callback code here


To use the class we can write the following:

Simple simple;
SimpleCallBackClass2 callback2;

//we can get at the event handler by name
simple.Talking += callback2.getEventHandler( "SimpleCallBackClass2::onTalking" );;


This will now fire the event, and the SimpleCallBackClass2's onTalking() method will get called. As mentioned earlier, a Delegate can have more than one event handler, for example:

Simple simple;
SimpleCallBackClass callback;
SimpleCallBackClass2 callback2;

EventHandler* handler = new GenericEventHandler<SimpleCallBackClass>( &callback, &SimpleCallBackClass::onTalking );

simple.Talking += handler;

simple.Talking += callback2.getEventHandler( "SimpleCallBackClass2::onTalking" );;


Now when the Simple talk() method is called and fires the event, both event handlers are called, and SimpleCallBackClass::onTalking and SimpleCallBackClass2::onTalking methods get invoked.

This pretty much sums up the basics of event handlers. As we can see the event and the event handlers do not have to have any dependency on UI code and can be used in console applications as well as GUI's.

5.1.5. File System handling Files and Directories

This example will demonstrate using the various file and directory classes for working with the underlying filesystem.

File names and the FilePath class.  The first part we'll look at is dealing with file names. To make this easier to work with, the VCF uses a special class called the FilePath class. This class allows you to deal with the various parts of a file name string, such as extracting the directory, or just the file extension.

Using a FilePath object is easy - just assign a string to it.

FilePath fileName = "tmp-output.txt";

Now we can check to see if the file name is a relative file name or a fully qualified file name.

if ( fileName.isRelativePath() ) {		
	fileName = fileName.expandRelativePathName( System::getCurrentWorkingDirectory() );

Calling the fileName.isRelativePath() method will return true if it's a relative path, or false otherwise. If the file name is relative, then we can expand the file name by calling expandRelativePathName(). Note that this returns a string that represents the fully qualified file name, but the original data for the FilePath object is unmodified.

We can examine the various parts of the file name quite easily, like so:

String drive = fileName.getDriveName();
String directoryPath = fileName.getPathName();
String name = fileName.getName();
String extension = fileName.getExtension();
String nativeOSFilePath = fileName.transformToOSSpecific();

Each of these functions, getDriveName(), getPathName(), getName(), and getExtension(), extracts the various data from the original FilePath object, again, it makes no modifications to do so. This is roughly analagous to Microsoft's _splitpath() C Runtime function.

In addition to extracting the various path components, you can also get an vector of strings for the directory components. For example, a directory such as "C:\Program Files\A Program\User Settings\Stuff.txt" would have 3 strings, "Program Files", "A Program", and "User Settings". You can enumerate these like so:

std::vector<String> pathComponents = fileName.getPathComponents();
std::vector<String>::iterator it = pathComponents.begin();
while ( it != pathComponents.end() ) {
	System::println( *it );
	it ++;

Creating a file.  You can create files (as well as read and write to them) using the FileOutputStream class. To create a file, just create an isntance of FileOutputStream, and pass in the file name to the constructor. Then use the various write() methods of the FileOutputStream class. For example, lets create a file, write some text to it, and then display the file size:

FileOutputStream fs(fileName);
String text = "here's some text to put in the file";
fs << text;
System::println( "FileOutputStream current size: %d", fs.getSize() );

Now lets look at accessing the same file that we just created with the File object. With the VCF::File object we can get information about the file attributes, such as size. To do this all we need to do is create a File object and pass in a file name to the File's constructor.

File file( fileName ); 
System::println( "The file %s's size: %d", fileName.getFileName().c_str(), file.getSize() );

As we can see this is extremely easy to do. Now lets copy the file somewhere else:

file.copyTo( fileName.getPathName(true) + 
			FilePath::getDirectorySeparator() + 
			fileName.getName() + "-copy" + fileName.getExtension() );

To accomplish this, we just call the File's copyTo() method, and pass in the file name that we are copying to. If this fails, an exception will be thrown, so we may want to wrap this in a try/catch block like so:

try {
	file.copyTo( fileName.getPathName(true) + 
				FilePath::getDirectorySeparator() + 
				fileName.getName() + "-copy" + fileName.getExtension() );
catch ( BasicException& e ) {
	System::println( "Oops, couldn't copy the file, error: " + e.getMessage() );

File searches.  The last things we'll look at is search for files. To do this we will use a directory object, and a Directory::Finder object. A directory is somewhat similar to a File object, but obviously is specific to just directories. To actually search for files, you call the Directory::findFiles() method.

5.1.6. Streams

5.1.7. Enumerators Working With Enumerators

This example will exaplain how to use the VCF::Enumerator class. An Enumerator is simply a virtual class that wraps around a collection and provides a standard interface for iterating through the collection, without worrying about the specifics of the collection type.

For example you might have a collection class based on a std::vector. If you exposed the collection type directly, then any changes you made to would have to be reflected in all cases where you iterate through the collection. However, if you use an Enumerator, this wraps the collection type, and you can then transparently change the collection type, say from a std::vector, to a std::list, and any code using the Enumerator will remain unaffected.

An Enumerator has 3 main methods. The first method, Enumerator::hasMoreElements() returns true or false, indicating whether there are any more elements left to enumerate. The next method, Enumerator::nextElement() allows you to move to the element of the Enumerator. If the Enumerator wraps something like a std::vector, then this is equivalent to calling the ++ operator on the std::vector::iterator. Finally, the Enumerator can be rewound, or set back to the beginning by calling Enumerator::reset().

To actually enumerate items it's quite easy. To demonstrate this, lets get an enumerator of Class objects from the ClassRegistry, like so:

Enumerator<Class*>* classes = ClassRegistry::getClasses();

The enumerator takes only a single template argument: the type of element in the enumeration. Note that the enumerator is returned as a pointer - this is always the case in the VCF, as the Enumerator class is itself abstract. Now to enumerator, you simply use the hasMoreElements() and nextElement() methods in a while loop:

while ( classes->hasMoreElements() ) {
	Class* clazz = classes->nextElement();

That's it. You can now iterate through the collection of classes without caring what the actual collection implementation is.

You can reset the enumerator when you need to loop through it again. For example, lets say you looped through a collection, looking for something, and then needed to loop through it again. To do this on the same enumerator pointer, you would just call the reset() method, like so:

while ( classes->hasMoreElements() ) {
	Class* clazz = classes->nextElement();
	//do something 

//reset the enumerator back to the beginnin

while ( classes->hasMoreElements() ) {
	Class* clazz = classes->nextElement();
	//do something else

You may find that you want to use enumerators with your own classes or code. Doing so is quite easy. For example, if you wanted to wrap a std::vector<String> instance you can use the EnumeratorContainer<> template class. This takes two template arguments, the first is the type of container or collection class, and the second is the element type.

std::vector<String> strings;

//string container
EnumeratorContainer<std::vector<String>,String> stringContainer;

The EnumeratorContainer class needs to be initialized once. To do so, you need to call the initContainer() method, and pass in a reference to the actual collection instance.

stringContainer.initContainer( strings );

At this, point you can now add or remove elements to the collection:

strings.push_back( "1" );
strings.push_back( "2" );
strings.push_back( "3" );
strings.push_back( "4" );

Now to enumerate the collection, we simply call the getEnumerator() method of the EnumeratorContainer instance.

Enumerator<String>* stringEnum = stringContainer.getEnumerator();

We now have a pointer to an Enumerator, which we can use just the same as demonstrated earlier.

Note that an Enumerator that is a wrapper to one of the STL's collection classes has the same limits as the underlying collection class. For example, if you have an Enumerator that wraps a vector<String>, and during the course of enumerating through it, you remove an element from the vector, then the enumeration will become invalid, just like an iterator to the vector would be invalid. In addition, there is no threading support built in beyond what the STL provides, so anything else needs to added by the application developer, at least at this point in time.

5.1.8. Dictionaries Dictionaries

Introduction.  The Dictionary class is a simple class intended to be used when you have a collection of name value pairs. It is based on the STL std::map class, and you can use it just as you would a std::map<String,VariantData> instance. Because the class uses the VariantData type for it's value type, you can easily store just about anything in it. One use might be for passing a collection of named arguments to a plugin, where you may not know the arguments at compile time. Another usage might be for storing and/or accessing application preferences.

You can add elements to a dictionary quite easily, for example:

Dictionary dict;
dict["size"] = 200;
dict["Name"] = "Bob";

This adds two elements, one named "size", with a value of 200, and another named "Name" with a string value of "Bob".

Removing individual elements or clearing the dictionary is also easy, for example, to remove the element named "Name":

dict.remove( "Name" );

To remove all the elements of the dictionary use the Dictionary::clear() method:


To access an element, use the [] operator, just like for a std::map class. Since the value type is a VariantData class, you can either retrieve the value as a VarianData instance, or into one of the primitive types.

VariantData name = dict["Name"];
int size = dict["size"];

You can easily save or load a dictionary to (or from) a stream. Since the Dictionary class implements the Persistable interface, you can simply pass a pointer of the dictionary intance to a stream, and you're done! For example, lets save the dictionary to a file stream:

FileOutputStream fs( "dict.file.txt" );
fs << dict;

Loading the dictionary from a file is just as easy:

FileInputStream fs( "dict.file.txt" );
fs >> dict;

Iterating the elements is identical to doing so with an std::map. Lets print out all the elements in a dictionary.

Dictionary::iterator it = dict.begin();		
while ( it != dict.end() ) {
	Dictionary::pair& element = *it;

	System::println( "dict[\"%s\"] = %s", element.first.c_str(), element.second.toString().c_str() );
	it ++;

5.1.9. Dynamic Library Loading SharedLibraries

Your content here, explaining the usage/functioning of your example.

5.1.10. Threads ThreadBasics

Your content here, explaining the usage/functioning of your example. ThreadsInGUI

Your content here, explaining the usage/functioning of your example. Conditions

Your content here, explaining the usage/functioning of your example.

5.1.11. Processes

Not complete at this time

5.1.12. Internationalization and Unicode Localization

Your content here, explaining the usage/functioning of your example.

5.1.13. Resource Loading


1. Resources

Your content here, explaining the usage/functioning of your example.

Example 5.1. Resources Example Code


#include "vcf/FoundationKit/FoundationKit.h"

using namespace VCF;

This simple program will demonstrate how to load up resources.
We will use bundle based resources for this test, and .rc based 
resources for the Win32 version.

#define IDS_STRING1	"1"

int main( int argc, char** argv ){

	FoundationKit::init( argc, argv );

	//retrieves the System's resource bundle for this application
	ResourceBundle* resBundle = System::getResourceBundle();

	//retreive a string resource
	String val = resBundle->getString( IDS_STRING1 );

	System::println( "IDS_STRING1: " + val );
	val = resBundle->getString( "HELLO_STR" );

	System::println( "HELLO_STR: " + val );

	val = resBundle->getString( "TEST" );

	System::println( "TEST: " + val );

	val = resBundle->getString( "goodbye_str" );

	System::println( "goodbye_str: " + val );

	This retreives a resource in the form of a raw data buffer.
	The caller is responsible for freeing the resources
	instance if one is returned

	Resource* res = resBundle->getResource( "MyData.dat" );
	if ( NULL == res ) {
		System::println( "Failed to find resource!" );
	else {
		System::println( "Found resource " + res->getName() + 
							" size in bytes: " + StringUtils::toString(res->getDataSize()) +
							" buffer: " + Format( "%p") % res->getData() );


	This will extract a resource from the exe
	res = resBundle->getResource( "logo_png" );
	if ( NULL == res ) {
		System::println( "Failed to find resource!" );
	else {
		System::println( "Found resource " + res->getName() + 
							" size in bytes: " + StringUtils::toString(res->getDataSize()) +
							" buffer: " + Format( "%p" ) % res->getData() );


	Get program information about the program from either the 
	Win32 RT_VERSION res type, or, if the file exists, the Info.xml (or Info.plist)
	meta-data files.
	The caller is responsible for releasing the ProgramInfo instance
	ProgramInfo* info = resBundle->getProgramInfo();
	if ( NULL == info ) {
		System::println( "Sorry, no program information was found." );
	else {
		System::println( "Program information:" );

		System::println( info->getProgramName() );
		System::println( info->getProgramVersion() );
		System::println( info->getAuthor() );
		System::println( info->getCompany() );
		System::println( info->getDescription() );		


	return 0;

   Comments or Suggestions?    License Information