The Ex32a Example: A Managed C++ DLL Assembly
To give you a feel for how Managed C++ types work, this chapter includes an example with a potpourri of managed types. The example is Ex32a, which is generated using the Managed C++ Class Library project template. In keeping with C++ style, the project wizard generates a header file named


// Ex32a.h
#pragma once
#using <System.DLL>
#using <System.Drawing.DLL>
#using <System.Windows.Forms.DLL>
#using <System.Runtime.Remoting.DLL>
using namespace System;
using namespace System::Collections;
namespace Ex32a
{
// C++ Assembly full of managed types...
public __value enum DaysOfTheWeek {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
public __value struct AManagedValueStruct {
int m_n;
double m_x;
String* m_str;
AManagedValueStruct() {
m_n = 0;
m_x = 1.1;
m_str=new String("Hi there from AManagedValueStruct");
}
void Method1() {
Console::WriteLine("Called AManagedValueStruct::Method1()");
}
};
public __gc struct AManagedGcStruct {
AManagedGcStruct() {
m_str=new String("Hi there from AManagedGcStruct");
}
~AManagedGcStruct() {
System::Console::WriteLine("AManagedStruct Going Away\n");
}
void Method1() {
Console::WriteLine("Called AManagedGcStruct::Method1()");
}
int m_n;
double m_x;
String* m_str;
};
public __gc __interface IPerson {
void Eat();
void Sleep();
void Work();
};
public __gc class SoftwareDeveloper : public IPerson{
~SoftwareDeveloper() {
System::Console::WriteLine
("Finalize called for SoftwareDeveloper");
}
void Eat() {
System::Console::WriteLine("Eat pizza");
}
void Sleep() {
System::Console::WriteLine("Sleep during the day");
}
void Work() {
System::Console::WriteLine("Work during the night");
}
};
public __gc class DotCOMVP : public IPerson {
~DotCOMVP() {
System::Console::WriteLine("Finalize called for DotCOMVP");
}
void Eat() {
System::Console::WriteLine("Eat to Schmooze");
}
void Sleep() {
System::Console::WriteLine("Never sleep");
}
void Work() {
System::Console::WriteLine("Work to get Venture Capital");
}
};
public __gc class Bum : public IPerson {
~Bum() {
System::Console::WriteLine("Finalize called for Bum");
}
void Eat() {
System::Console::WriteLine("Eat sporadically");
}
void Sleep() {
System::Console::WriteLine("Sleep whenever possible");
}
void Work() {
System::Console::WriteLine("Work?");
}
};
public __delegate void AManagedDelegate(String* strMessage);
public __gc __interface IAManagedInterface {
void MethodA();
int MethodB();
};
public __gc class AManagedClass : public IAManagedInterface {
int m_n;
int m_nSize;
double m_f;
String *m_str;
DaysOfTheWeek m_DayOfWeek;
ArrayList *m_rgManagedArray;
public:
AManagedClass() {
m_str = new String("This is AManagedClass\n");
m_DayOfWeek = Friday;
}
~AManagedClass() {
System::Console::WriteLine("AManagedClass Going Away\n");
}
__property int get_Size() {
return m_nSize;
}
__property void set_Size(int value) {
m_nSize = value;
}
void MethodA() {
Console::WriteLine
("Here's some managed C++ code. This is MethodA.");
}
int MethodB() {
Console::WriteLine
("Here's some managed C++ code. This is MethodB.");
return 0;
}
void FillArray() {
m_rgManagedArray = new ArrayList();
Console::WriteLine("Creating a DotCOMVP");
m_rgManagedArray->Add(new DotCOMVP());
Console::WriteLine("Creating a Bum");
m_rgManagedArray->Add(new Bum());
Console::WriteLine("Creating a Software Developer");
m_rgManagedArray->Add(new SoftwareDeveloper());
}
void ShowArray() {
Console::WriteLine();
if(m_rgManagedArray) {
for(int i = 0; i < m_rgManagedArray->Count; i++) {
Console::Write("Type: ");
Console::WriteLine(
(m_rgManagedArray->get_Item(i))->GetType()->ToString());
IPerson* person;
person = __try_cast<IPerson*>
(m_rgManagedArray->get_Item(i));
person->Eat();
person->Work();
person->Sleep();
Console::WriteLine();
}
}
}
void UseDelegate(AManagedDelegate *d) {
d->Invoke("This is called through the delegate...");
}
};
}
The result of building this project is an assembly that contains the managed types. The .NET Framework SDK provides a tool called the Intermediate Language Disassembler (ILDASM). When you open an assembly using ILDASM, ILDASM shows you the contents of the assembly. Figure 32-1 shows the


Figure 32-1: The Ex32a assembly as viewed through ILDASM.
ILDASM shows the internals of an assembly. Remember that all the type information for an assembly is available. The common language runtime library includes classes and methods for iterating through the contents of an assembly, which is actually very straightforward to do. Writing an ILDASM-type browser also isn't that hard to do. (It's much simpler using .NET than using COM's ITypeLibrary and ITypeInfo interfaces, for example.) In the following sections, we'll look at the types available through Ex32a.
DaysOfTheWeek
C and C++ have always provided the enum keyword for naming the types of a collection (such as months of the year or suits in a card deck), but the underlying structure behind the C and C++ enum has simply been an integer. That means you can write source code that mixes enumeration types (Monday, Tuesday, Wednesday, and so on) with raw integers. The managed types of the common language runtime allow you to specify the enumeration as a type, and the compiler enforces that typing, as shown in the following listing:
Void Afunction() {
DaysOfTheWeek dow;
dow = 3; // Would work in C and C++, but not
// under Managed C++
dow = Wednesday; // This is the only syntax
// that works under Managed C++
}
AManagedValueStruct and AManagedGcStruct
AManagedValueStruct is a value struct that lives on the stack and more or less describes formatted memory. AManagedGcStruct is a reference struct that describes a structure living on the garbage-collected heap.
IAManagedInterface and IPerson
IAManagedInterface and IPerson describe two managed interfaces. IAManagedInterface has two methods, MethodA and MethodB. IPerson describes a person type that eats, sleeps, and works. Interfaces are useful for describing basic, abstract functionality. The DotComVP, SoftwareDeveloper, and Bum classes (described shortly) implement the IPerson interfaces. Managed interfaces are different from COM interfaces in that they don't have the IUnknown functions preceding them, and the interfaces are managed by the runtime.
DotCOMVP, SoftwareDeveloper, and Bum
The DotCOMVP, SoftwareDeveloper, and Bum classes all implement the IPerson interface. However, they all do so in different ways. By expressing the functionality of these classes as an interface, you can use them wherever a person can be used. (These classes are type-compatible with IPerson.) You'll see this in the FillArray method of AManagedClass.
AManagedDelegate
AManagedDelegate represents a function signature that can be passed around as a type. You've seen examples of this throughout the C and C++ programming examples in this book. However, in the common language runtime, these function pointers (delegates) are managed types. Because the compiler enforces strict type checking, the possibility of a program error due to passing an incorrect function signature or passing the wrong arguments in the function goes away.
AManagedClass
The last type described in the Ex32a header file is AManagedClass, which implements IAManagedInterface. Notice that AManagedClass has several member variables (a couple of integers, a float type, a String, a DayOfTheWeek type, and an ArrayList). In addition, AManagedClass implements IAManagedInterface and exercises the DotCOMVP, SoftwareDeveloper, and Bum classes. Finally, notice the UseDelegate method, which passes around a delegate (a function signature type).