CFOBJECT and COM
As we have already seen, ColdFusion enables us to work with a variety of Java objects and components, but that's not all we are limited to. ColdFusion gives you access to COM/DCOM components and to Common Object Request Broker Architecture (CORBA) objects. In this section, we cover how you can use COM objects in your ColdFusion applications with CFOBJECT.
A Little About COM and DCOM
COM is Microsoft's attempt at building robust, portable, and reusable components with their Distributed Component Object Model distributable components, much like JavaBeans or Enterprise JavaBeans.
COM and DCOM are powerful methods that enable Windows programmers to "componentize" functionality. You can find COM objects that do everything from providing access to specific programs, such as Microsoft Office programs, to providing access to COM-based cryptography libraries.
To find out more about COM, go to www.microsoft.com/com. In addition, look at www.cfcomet.com, which is a web site totally devoted to working with COM objects from ColdFusion. It's a great resource!
Working with COM Objects and ColdFusion
You can call a COM object that resides either on your local machine or anywhere on your network; but before you can do so, you need to make sure the component you are trying to call is registered. To do this, you use the regsvr32 command from a Windows command prompt, like this:
C:\> regsvr32 someobject.dll
If a COM object has been registered on your machine, you can access it from CFOBJECT using this syntax:
<cfobject type="com" name="name" action="action" context="context" server="your server name"
When you connect to a COM component, you need to set the CFOBJECT type attribute to COM. The name attribute is a reference variable and is also required. It is needed, as are other CFOBJECT calls, to provide a pointer to an object's attributes and methods.
class is a required attribute and points to the COM component's program ID for the object you want to invoke. You might have trouble finding the program ID, and if so, you should check the documentation for that component, which provides you with a list of its methods as well as the ProgramID. You can also use the OLE/COM Object Viewer that comes with Visual Studio or you can download it from www.microsoft.com/com/resources/oleview.asp.
The next attribute we have to deal with is the action attribute. This is a required attribute with two possible values: Create or Connect. Create takes a COM object and instantiates it prior to invoking methods and assigning properties, while Connect enables you to link/connect to a COM object (typically an executable) that is already running on the server. An example of the use of this type of object is a background service such as Net Stat.
The context attribute is an optional attribute that enables you to specify the context under which your object is running. Table 16.1 provides the various contexts.
The final attribute needed to call COM objects from CFOBJECT is server, which is required if the context attribute is set to remote. server simply specifics a valid server.
Properties and Methods
Any object has a series of methods and properties that you need to set and use. To set a property of a COM object, you only need to use the CFSET tag:
<cfset someobject.someproperty = "somevalue">
You can also access or get a property's value by doing this:
<cfset getProperty = someobject.someproperty>
To invoke a method with no arguments is just as simple:
<cfset variablename = someobject.somemethod()>
Methods that require arguments need to have those arguments passed by value:
<cfset somevar = 4> <cfset anothervar = someobject.somemethod (somevar, someOutput)
You can also pass arguments by reference. Arguments passed by reference have their values modified by the COM object variable on the calling page, so the calling page can use the resulting value. To pass a variable by reference, surround the name of an existing ColdFusion variable with quotation marks. If the argument is a numeric type, assign the variable a valid number before you make the call. For example:
<cfset somestring="Print PI"> <cfset somenumeric=0> <cfset result=myCOMObject.calculate(somestring, " somenumeric ")>
The string "Print PI" is passed to the object's calculate method as an input argument. The value of somenumeric is set by the method to a numeric value.
Let's look at a real example. Let's pretend that we want to send out bulk mailings of special offers and other mail to our customers. To do this, we automate Microsoft Office to print a form letter with each of our customers, names and pertinent information. You can look at Microsoft's COM reference for Word on MSDN at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbawd10/html/wotocObjectModelApplication.asp.
Listing 16.9 mailmerge.cfm
<cfquery name="getCustomers" datasource="ICF" dbtype="ODBC"> SELECT Customer.CustomerID, Customer.CustomerFirstName, Customer.CustomerLastName, Customer.CustomerAddress, Customer.CustomerCity, Customer.CustomerStateID, Customer.CustomerZip, Customer.CustomerPhone, Customer.CustomerEmail, Customer.CustomerPassword, Customer.CustomerNotification FROM Customer, State </cfquery> <cftry> <!--- If it exists, connect to it ---> <cfobject action="Connect" name="objWord" type="COM"> <cfcatch> <!--- The object doesn't exist, so create it ---> <cftry> <cfobject action="create" name="objWord" type="COM"> <cfcatch type="ANY"> <cfabort showerror="<FONT COLOR='RED'>Cannot create Word Object<BR>Make sure Word is installed and that ColdFusion has permissions to use the Word COM objects</FONT><BR><B>Error Details:</B> #CFCATCH.MESSAGE#"> </cfcatch> </cftry> </cfcatch> </cftry> <cfscript> /* This will open Word if running locally */ objWord.Visible = true; /* This returns the 'Documents' collection the Word Object */ objDoc = objWord.Documents; /* Create a new document */ newDoc = objDoc.Add(); </cfscript> <cfset strLoc = Application.DrivePath & "\temp\worddata.doc"> <!--- Delete file ---> <cfif FileExists('#Application.DrivePath#temp\worddata.doc')> <cftry> <cffile action="DELETE" FILE='#Application.DrivePath#temp\Worddata.doc'> <cfcatch TYPE="Any"> </cfcatch> </cftry> </cfif> <cfscript> /* Save the document to a location */ newDoc.SaveAs(strLoc); /* We specify the range of '0' -- start at the beginning of the document */ docRange = newDoc.Range(0); </cfscript> <cfset strtemp = ""> <!--- Loop through the query ---> <cfloop query="getCustomers"> <cfset i = getCustomers.CurrentRow> <cfset strtemp = strtemp & "#CustomerID#" & ","> <cfset strtemp = strtemp & "#CustomerFirstName#" & ","> <cfset strtemp = strtemp & "#CustomerLastName#" & Chr(13) & Chr(10)> </cfloop> <cfscript> /* Add text to the range */ docRange.Text = strtemp; /* Save the changes */ newDoc.Save(); /* Print document objWord.ActivePrinter = "HP LaserJet 6L on NE01:"; objWord.PrintOut();*/ /* Close the document */ newDoc.Close(); /* Quit Word */ objWord.Quit(); </cfscript>
Although this looks like a complicated template, it's really not. We connect to the Word object by specifying the class name "Word.Application". Then we use a try-catch statement to see whether an instance of the object already exists and, if so, to connect to it. If not, we create an instance of it.
We then simply use the Word document's COM objects to add text to the created Word document.
Before you get excited about automating your Office applications through ColdFusion and CFOBJECT, make sure to go to http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257757. There you can read about some pitfalls and Microsoft's official view of automating Office applications.
Best Practices When Using COM Objects
Although using CFOBJECT and COM to create rich ColdFusion applications is easy, it is also easy to get yourself in trouble if you do not consider what you are doing. One of the main issues with calling COM objects from ColdFusion is improper threading. You must make sure that your COM object is thread-safe. If you do not, you might experience major issues under load and bring your server to its knees. An object is thread-safe if it can be called from many programming threads simultaneously without causing errors.
Visual Basic ActiveX DLLs are typically not thread-safe. If you use such a DLL in ColdFusion, you can make it thread-safe by using the OLE/COM Object Viewer to change the object's threading model to the Apartment model.
If you are planning on storing a reference to the COM object in the application, session, or server scope, do not use the Apartment model. This threading model is intended to service only a single request. If your application requires you to store the object in any of these scopes, keep the object in the Both model, and lock all code that accesses the object.
In this section, you have learned how to work with COM objects through CFOBJECT. You are provided with an invaluable tool to extend or rapidly add rich functionality to your ColdFusion applications. You can also use COM and CFOBJECT to provide a level of application integration between your ColdFusion web applications and sophisticated applications such as PeopleSoft and SAP, which provide extensive COM support.
It's important to note that although it is very simple and easy to work with COM from ColdFusion, there are risks and you need to read all the documentation on your COM object. You need to make sure it is thread-safe, or you must force it to be thread-safe through the OLE Object View application. Then you must rigorously test it before you use it in production.