The other main use of the code model is to generate source code programmatically. This aspect of the code model reveals most clearly the promise of a universal programming language: the same AddClass method that generates a Visual C# class when run against a .cs file will generate a Visual C++ class when run against a .cpp file, and will generate a Visual J# class when run against a .jsl file. In this section, we'll show how to generate the source file in Listing 12-1 by using the code model. Note that the following example provides only the briefest of introductions to this subjectfor details about the objects and methods used in this section, please refer to the Appendix.
All of the code model methods that generate code begin with Add, as in AddNamespace, AddClass, AddVariable, and so on. By calling an Add method on a CodeElement, you create a new code construct within the CodeElement. Note that CodeElement objects can't adopt other existing CodeElement objectsthey can have children only by bearing their own; a consequence of this is that you have to create your code hierarchy from the top down. The top-most element in Listing 12-1 is CMNamespace, so you begin by creating a new namespace, as shown in the following code:
Sub CreateListing_12_1() Dim fcm As FileCodeModel = GetFileCodeModel() If Not fcm Is Nothing Then Dim cdeNamespace As CodeNamespace ' Try to create a new namespace Try cdeNamespace = fcm.AddNamespace("CMNamespace") Catch e As Exception End Try ' If successful, create the rest of the code elements If Not cdeNamespace Is Nothing ThenEnd If End If End Sub
The FileCodeModel.AddNamespace method generates the source code for a new top-level namespace and returns a reference to its corresponding CodeNamespace object. The call to AddNamespace takes place within a Try/Catch block because Add methods throw an exception if they're unable to create the requested code element. Assuming all goes well, you'll have a reference with which to create the namespace's child elements.
The first child element to create is CMDelegate. CMDelegate defines an integer parameter, and you can create both the delegate and the parameter in the same Try/Catch block:
Try Dim cdeDelegate As CodeDelegate ' Try to create a new delegate cdeDelegate = cdeNamespace.AddDelegate("CMDelegate", _ vsCMTypeRef.vsCMTypeRefVoid) ' Try to add a new parameter to the delegate cdeDelegate.AddParameter("delParam", vsCMTypeRef.vsCMTypeRefInt) Catch e As Exception End Try
AddDelegate and AddParameter both take a parameter that specifies the code element's type; the vsCMTypeRef.vsCMTypeRefVoid value represents a void type, and the vsCMTypeRef.vsCMTypeRefInt value represents an integer type. The previous code doesn't declare a variable to store AddParameter's return value because nothing further needs to be done with the delegate's parameter.
Next you create the structure and its field:
Try Dim cdeStruct As CodeStruct ' Try to create a new structure cdeStruct = cdeNamespace.AddStruct("CMStruct", -1) ' Try to add a new field to the structure cdeStruct.AddVariable("field", vsCMTypeRef.vsCMTypeRefInt) Catch e As Exception End Try
By now the rhythm should be familiar: define a variable for the new code element, assign the return value of the Add method to the variable, and call methods on the variable to alter the new code element. The -1 parameter to AddStruct tells the method to insert the source code for the new structure after every other sibling code element; all the Add methods accept this optional parameter. Here's the code for creating the enumeration and the interface:
Try Dim cdeEnum As CodeEnum ' Try to create a new enumeration cdeEnum = cdeNamespace.AddEnum("CMEnum", -1) ' Try to add a new member to the enumeration cdeEnum.AddMember("Member") Catch e As Exception End Try Try Dim cdeInterface As CodeInterface ' Try to create a new interface cdeInterface = cdeNamespace.AddInterface("CMInterface", -1) ' Try to add a new method to the interface cdeInterface.AddFunction("CMInterfaceMethod", _ vsCMFunction.vsCMFunctionFunction, vsCMTypeRef.vsCMTypeRefInt) Catch e As Exception End Try
The second parameter to AddFunction lets you specify what kind of function to create, such as a constructor, a destructor, a pure virtual function, and so on; the value of vsCMFunction.vsCMFunctionFunction for CMInterfaceMethod creates a vanilla function. Finally, here's the code that creates the class, its attribute, and all its members:
Try Dim cdeClass As CodeClass ' Try to create a new class cdeClass = cdeNamespace.AddClass("CMClass", -1) Try ' Try to add a new attribute to the class cdeClass.AddAttribute("CMAttribute", "CMVal") Catch e As Exception End Try Try ' Try to add a new member variable to the class cdeClass.AddVariable("memberVar", vsCMTypeRef.vsCMTypeRefObject, -1) Catch e As Exception End Try Try Dim cdeFunction As CodeFunction ' Try to add a new member function to the class cdeFunction = cdeClass.AddFunction("CMCallbackFunction", _ vsCMFunction.vsCMFunctionFunction, _ vsCMTypeRef.vsCMTypeRefVoid, -1) ' Try to add a new parameter to the member function cdeFunction.AddParameter("param", vsCMTypeRef.vsCMTypeRefInt) Catch e As Exception End Try Try ' Try to add a new property to the class cdeClass.AddProperty("CMProperty", "CMProperty", _ vsCMTypeRef.vsCMTypeRefInt, -1) Catch e As Exception End Try Catch e As Exception End Try
Now that you're done writing the code that writes the code, it's time for some bad news: none of the language implementations will generate a complete simulacrum of Listing 12-1 from this code, either because the language doesn't support a particular code construct or because the language hasn't yet implemented a particular Add method. You can verify this for yourself by running the CreateListing_12_1 macro on different language source filesif you do, you'll find that Visual C# generates everything but the attribute; Visual C++ generates everything but the delegate and the property; Visual J# generates everything but the delegate, structure, enumeration, attribute, and property; and Visual Basic doesn't generate anything. Again, that's the bad newsthe good news is that the code model is a young branch of the automation object model, so you can expect major improvements in its next version.