Let's write a managed C++ executable to exercise the library. As you'll see from this example, writing C++ client code that uses managed types is fairly straightforward and nearly seamless. The following listing, Ex32b, shows a simple console application that exercises the types found in Ex32a:
// This is the main project file for a Visual C++ application // generated using an application wizard. #include "stdafx.h" #using <mscorlib.dll> #using <..\Ex32a\debug\ex32a.dll> #include <tchar.h> using namespace System; using namespace Ex32a; __gc class CDelegateHolder { public: static void DelegateFn(String* str) { Console::WriteLine(str); } }; void UseValueStruct() { Console::WriteLine("Working with AManagedValueStruct"); AManagedValueStruct amvs; Console::WriteLine(amvs.m_str); amvs.Method1(); } void UseGcStruct() { Console::WriteLine("Working with AManagedGcStruct"); AManagedGcStruct *amgcs; amgcs = new AManagedGcStruct(); Console::WriteLine(amgcs->m_str); amgcs->Method1(); } // This is the entry point for this application int _tmain(void) { Console::WriteLine( "Creating and exercising an instance of AManagedClass"); AManagedClass *amc = new AManagedClass(); Console::WriteLine("Filling array"); amc->FillArray(); amc->ShowArray(); Console::WriteLine(); Console::WriteLine("Creating and using a Delegate"); CDelegateHolder *dh; dh = new CDelegateHolder(); AManagedDelegate *amd; amd = new AManagedDelegate(dh, dh->DelegateFn); amc->UseDelegate(amd); Console::WriteLine(); Console::WriteLine( "Talking to the object through IAManagedInterface"); IAManagedInterface *ami; ami = amc; ami->MethodA(); ami->MethodB(); Console::WriteLine(); UseGcStruct(); Console::WriteLine(); UseValueStruct(); GC::Collect(); return 0; }
Before getting into the details of the code, take a look at the top of the previous listing. There's an include statement for
The structure of all console applications within the common language runtime is similar. The assembly needs to include a single class. (You can call it anything you want.) The class needs to include a single static method named Main. This is the entry point to the application.
The main thread to the application then instantiates various types living within
Notice the UseDelegate class near the top of the file. This class holds a function of the same signature type declared by AManagedDelegate. The Ex32b application passes an instance of this method to the AManagedClass UseDelegate method to illustrate using delegates.
Ex32b then casts the AManagedClass object to IAManagedInterface and talks to the object through the interface. This shows how you can pare an object instance down to one of its interfaces and use the class through the interface type.
Finally, the main thread creates instances of AManagedGcStruct and AManagedValueStruct to show how managed versus reference types work. Notice that the value structure simply sits on the stack, while the reference types live on the garbage-collected heap. (They're instantiated using the new operator.)
The final act of Ex32b is to execute the garbage collector by calling GC::Collect. Notice how finalizers are called on the objects as they're garbage collected.
Figure 32-2 shows the results of executing the Ex32b application.
Figure 32-2: Running the Ex32b console application.