Use the cfobject tag or the CreateObject function to create an instance of the COM object (component) in ColdFusion before your application pages can invoke any methods or assign any properties in the component. 
For example, the following code uses the cfobject tag to create the Windows CDO (Collaborative Data Objects) for NTS NewMail object to send mail:

action="Create"
name="Mailer"
class="CDONTS.NewMail">

The following line shows how to use the corresponding CreateObject function in CFScript:

Mailer = CreateObject("COM", "CDONTS.NewMail");

Several examples in this documentation use this object.

Note: CDO is installed by default on all Windows NT and 2000 operating systems that have installed the Microsoft SMTP server. In Windows NT Server environments, the SMTP server is part of the Option Pack 4 setup. In Windows 2000 Server and Workstation environments, it is bundled with the operating system.

note. >>>The CDO for NTS NewMail component includes methods and properties to perform a wide range of mail-handling tasks. (In the OLE/COM Object Viewer, methods and properties can be grouped, so you could find it difficult to distinguish between them at first.)
The CDO for NTS NewMail object includes the following properties:

Cc[ String ]
From[ String ]
Importance[ Long ]
Subject[ String ]
To[ String ]

You use these properties to define elements of your mail message. The CDO for NTS NewMail object also includes a send method which has optional arguments to send messages.

Connecting to COM objects

The action attribute of the cfobject tag provides the following two ways to connect to COM objects:

  • Create method (cfobject action="Create") Takes a COM object, typically a DLL, and instantiates it before executing methods and assigning properties.
  • Connect method (cfobject action="Connect") Links to an object, typically an executable, that is already running on the server.You can use the optional cfobject context attribute to specify the object context. If you do not specify a context, ColdFusion uses the setting in the Registry. The following table describes the context attribute values:

Attribute value

Description

InProc

An in-process server object (typically a DLL) that is running in the same process space as the calling process, such as ColdFusion.

local

An out-of-process server object (typically an EXE file) that is running outside the ColdFusion process space but running locally on the same server.

remote

An out-of-process server object (typically an EXE file) that is running remotely on the network. If you specify remote, Also use the server attribute to identify where the object resides.

Setting properties and executing methods

The following example, which uses the sample Mailer COM object, shows how to assign properties to your mail message and how to execute component methods to handle mail messages.
In the example, form variables contain the method parameters and properties, such as the name of the recipient, the desired e-mail address, and so on:

<cfobject type="COM"
action="Create"
name="Mailer"
class="CDONTS.NewMail">

<!--- Second, use the form variables from the user entry form to populate a number
of properties necessary to create and send the message. --->
<cfset Mailer.From = "#Form.fromName#">
<cfset Mailer.To = "#Form.to#">
<cfset Mailer.Subject = "#Form.subject#">
<cfset Mailer.Importance = 2>
<cfset Mailer.Body = "#Form.body#">
<cfset Mailer.Cc = "#Form.cc#">

<!--- Last, use the Send() method to send the message.
Invoking the Send() method destroys the object.--->
<cfset Mailer.Send()>

 

Note: Use the cftry and cfcatch tags to handle exceptions thrown by COM objects. For more information on exception handling, see Handling runtime exceptions with ColdFusion tags.

Releasing COM objects

By default, COM object resources are released when the Java garbage collector cleans them. You can use the ReleaseCOMObject function to immediately release resources if an object is no longer needed. 
Use the ReleaseCOMObject function to release COM objects that are launched as an external process, such as Microsoft Excel. The garbage collector does not always clean these processes in a short time, resulting in multiple external processes running, which drains system resources.
If the COM object has an end method, such as a quit method that terminates the program, call this method before you call the ReleaseComObject function. If you use the ReleaseComObject function on an object that is in use, the object is prematurely released and your application gets exceptions.

Example

The following example creates a Microsoft Excel application object, uses it, then releases the object when it is no longer needed:

<h3>ReleaseComObject Example</h3>
<cfscript>
obj = CreateObject("Com", "excel.application.9");
//code that uses the object goes here
obj.quit();
ReleaseComObject(obj);
</cfscript>

General COM object considerations

When you use COM objects, consider the following to prevent and resolve errors:

  • Ensuring correct threading
  • Using input and output arguments
  • Understanding common COM-related error messages
Ensuring correct threading

Improper threading can cause serious problems when using a COM object in ColdFusion. Make sure that the object is thread-safe. 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 threading model of the object to the Apartment model. 
If you are planning to store a reference to the COM object in the Application, Session, or Server scope, do not use the Apartment threading 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 threading model, and lock all code that accesses the object, as described in Locking code with cflock.

Change the threading model of a COM Object
  1. Open the OLE/COM Object Viewer.
  2. Select All Objects under Object Classes in the left pane.
  3. Locate your COM object. The left pane lists the objects by name.
  4. Select your object.
  5. Select the Implementation tab in the right pane.
  6. Select the Inproc Server tab, below the App ID field.
  7. Select the Threading Model drop-down list and select Apartment or Both, as appropriate.
Using input and output arguments

COM object methods in arguments are passed by value. The COM object gets a copy of the variable value, so you can specify a ColdFusion variable without surrounding it with quotation marks. 
COM object out method arguments are passed by reference. The COM object modifies the contents of the 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 outNumericArg=0>
<cfset result=myCOMObject.calculate(inStringArg, "outNumericArg")>

The string "Hello Object" is passed to the object's calculate method as an input argument. The method sets the value of outNumericArg to a numeric value.

Understanding common COM-related error messages

The following table described some error messages you could encounter when using COM objects:

Error

Cause

Error Diagnostic InformationError trying to create object specified in the tag. COM error 0x800401F3. Invalid class string.

The COM object is not registered or does not exist.

Error Diagnostic InformationError trying to create object specified in the tag. COM error 0x80040154. Class not registered.

The COM object is not registered or does not exist. This error usually occurs when an object existed previously, but was removed.

Error Diagnostic InformationFailed attempting to find "SOMEMETHOD" property/method on the object COM error 0x80020006.Unknown name.

The COM object was instantiated correctly, but the method you specified does not exist.

Accessing Complex COM Objects using Java proxies

ColdFusion supports Java proxies to access COM objects. If you do not create Java proxies in advance, ColdFusion must dynamically discover the COM interface. This technique can have two disadvantages:

  • Dynamic discovery takes time and can reduce server performance with frequently used complex COM objects.
  • Dynamic discovery uses the IDispatcher interface to determine the COM object features, and does not always handle some complex COM interfaces.
    To overcome these problems, ColdFusion includes a utility, com2java.exe, that creates static Java stub proxy classes for COM objects. ColdFusion can use these Java stubs to access COM objects more efficiently than when it creates the proxies dynamically. Additionally, the com2java.exe utility can create stubs for features that the dynamic proxy generator could miss.
    ColdFusion ships with pregenerated stubs for the Windows XP, Windows 2000, and Windows 97 editions of Microsoft Excel, Microsoft Word, and Microsoft Access. ColdFusion is configured to automatically use these stubs.
    If you create Java stub files for a COM object, you continue to use the cfobject tag with a type attribute value of COM, or the CreateObject function with a first argument of COM, and you access the object properties and methods as you normally do for COM objects in ColdFusion.
    Use the following steps to use the com2java.exe utility. This procedure uses Microsoft Outlook as an example.
To create Java stub files for COM objects:
  1. Configure your system as follows:
    1. Ensure that a JDK (Java Development Kit) is correctly installed, including proper configuration of the CLASSPATH and the command prompt PATH variable.
    2. Add _CF_root_lib\jintegra.jar to your CLASSPATH.
  2. Make a new directory for the Java stub files; for example:

    mkdir C:\src\outlookXP

    This directory can be temporary. You add files from the directory to a ColdFusion JAR file.

  3. Run the CF_root\Jintegra\bin\com2java.exe program from a command line or the Windows Start Menu. A window appears.
    1. If a COM class implements multiple interfaces that define methods with the same names, click the Options button and clear the Implement interfaces that may conflict option. The generated Java stub classes do not implement the additional, conflicting, interfaces. You can still access the interfaces using the getAs_XXX_ method that is generated. See the generated comments in the Java files.
    2. Click the Select button.
    3. Select your COM object's Type Library or DLL. For Microsoft Outlook in Windows XP, it is normally Program Files\Microsoft Office\Office10\MSOUTL.OLB.
    4. Enter a package name (for example, outlookXP) in the Java package field in the com2java dialog box. This package will contain all the classes for the Java stubs for the COM object.

      Note: Adobe uses a package name that starts with coldfusion.runtime.com.com2java_ for the packages that contain the preinstalled Java stubs for Microsoft Excel, Microsoft Word, and Microsoft Access. For example, the name for the package containing the Microsoft Word XP Java stub classes is_ coldfusion.runtime.com.com2java.wordXP_. This package name hierarchy results in the wordXP classes having a path inside the msapps.jar file of coldfusion\runtime\com\com2java\wordXP\className.class. Although this naming convention is not necessary, consider using a similar package naming convention for clarity, if you use many COM objects._

       

    1. Click the Generate Proxies button to display the File browser. Select the directory you created in step 2., and click the file browser OK button to generate the stub files.
    2. Click Close to close the com2java.exe utility.The files generated in your directory include the following:
    • A Java interface and proxy class for each COM interface
    • A Java class for each COM class
    • A Java interface for each ENUM (a set of constant definitions)
  1. Compile your Java code. In a command prompt, do the following:
    1. Make the directory that contains the Java stubs (in this example, C:\src\outlookXP) your working directory.
    2. Enter the following line:

      javac -J-mx100m -J-ms100m *.java

      The compiler switches ensure that you have enough memory to compile all the necessary files.

      Note: If you did not place jintegra.jar on your CLASSPATH in step 1b, add the switch -classpath:/cf_root/lib/jintegra.jar, where cf_root is the directory where ColdFusion is installed, to the command.

       

  1. Ensure that the ColdFusion server is not running. To stop the ColdFusion server, open the Services control panel, select ColdFusion application server, and click Stop.
  2. Add your .class files to the ColdFusion Microsoft application Java stubs file by doing the following:
    1. In the Windows Command prompt, make the parent directory of the directory that contains your class files your working directory. In this example, make c:\src your working director by entering cd .. in the Command prompt from step 4.
    2. Enter the following command:

      jar -uvf cf_root\lib\msapps.jar directoryName\*.class

      Where cf_root is the directory where ColdFusion is installed and directoryNameis the name of the directory that contains the class files. For the OutlookXP example, enter the following line:

      jar -uvf C:\CFusion\lib\msapps.jar outlookXP\*.class

       

  3. Update the cf_root/lib/neo-comobjmap.xml file by appending your object definition to the list. The object definition consists of the following lines:

    <string>PackageName.mainClass</string>
    </var>

    Use the following values in these lines:

  • ProgID The COM object ProgID, as displayed in the OLE/COM object viewer.
  • PackageName The package name you specified in step 3c.
  • mainClass The main class of the COM object. The main class contains the methods you invoke. For many Microsoft applications, this class is Application. In general, the largest class file created in step 4 is the main class. For example, to add outlookXP to neo-comobjmap.xml, add the lines in bold text above the </struct>end tag:

    <string>coldfusion.runtime.com.com2java.access2k.Application</string>
    </var>
    <var name="outlook.application.10">
    <string>outlookXP.Application</string>
    </var>
    </struct>

    In this example, outlook.application.10 is the ProgID of the Outlook COM object, outlookXP is the package name you specified in step 3c, and Application is the main class of the COM object.

  1. Restart the ColdFusion server: Open the Services control panel, select ColdFusion application server, and click Start.
  2. After you have installed the stubs, you can delete the directory you created in step 2., including all its contents.

Using the Application Scope to improve COM performance

The Java call to create a COM object instance can take substantial time. As a result, creating COM objects in ColdFusion can be substantially slower than in ColdFusion 5. For example, on some systems, creating a Microsoft Word application object could take over one second using ColdFusion, while on the same system, the overhead of creating the Word object could be about 200 milliseconds. 
Therefore, in ColdFusion, you can improve COM performance substantially if you can share a single COM object in the Application scope among all pages. 
Use this technique only if the following are true:

  • The COM object need not be created for every request or session. (For session-specific objects, consider using the technique described here with the Session scope in place of the Application scope.)
  • The COM object is designed for sharing.
    Because the object can be accessed from multiple pages and sessions simultaneously, also consider the following threading and locking issues:
  • For best performance, make the object multi-threaded. Otherwise, only one request can access the object at a time.
  • Lock the code that accesses and modifies common data. In general, you do not have to lock code that modifies a shared object's data, including writable properties or file contents, if multiple requests do not share the data (as opposed to the object) . However, specific locking needs depend on the COM object's semantics, interface, and implementation.
  • All cflock tags in the application that use an Application scope lock share one lock. Therefore, code that accesses a frequently used COM object inside an Application scope lock can become a bottleneck and reduce throughput if many users request pages that use the object. In some cases, you can avoid some contention by placing code that uses the COM object in named locks. Place the code that creates the object in an Application scope lock.

Note: You can also improve the performance of some COM objects by creating Java stubs, as described in Accessing Complex COM Objects using Java proxies above. Using a Java stub does not improve performance as much as sharing the COM object, but the technique works with all COM objects. Also, generate Java stubs to correctly access complex COM objects that do not properly make all their features available through the COM IDispatcher interface. Therefore, to get the greatest performance increase and prevent possible problems, use both techniques.

Example 1: Using the FileSystem object

The following example uses the Microsoft FileSystem Scripting object in the Application scope. This code creates a user-defined function that returns a structure that consists of the drive letters and free disk space for all hard drives on the system.


<!--- Uncomment the following line if you must delete the object from the
Application scope during debugging. Then restore the comments.
This technique is faster than stopping and starting the ColdFusion server. --->
<!--- <cfset structdelete(Application, "fso")> --->

<!--- The getFixedDriveSpace user-defined function returns a structure with
the drive letters as keys and the drive's free space as data for all fixed
drives on a system. The function does not take any arguments --->

<cffunction name="getFixedDriveSpace" returnType="struct" output=True>
<!--- If the FileSystemObject does not exist in the Application scope,
create it. --->
<!--- For information on the use of initialization variables and locking in
this code, see "Locking application variables efficiently" in Chapter 15,
"Using Persistent Data and Locking" --->
<cfset fso_is_initialized = False>
<cflock scope="application" type="readonly" timeout="120">
<cfset fso_is_initialized = StructKeyExists(Application, "fso")>
</cflock>
<cfif not fso_is_initialized >
<cflock scope="Application" type="EXCLUSIVE" timeout="120">
<cfif NOT StructKeyExists(Application, "fso")>
<cfobject type="COM" action="create" class="Scripting.FileSystemObject"
name="Application.fso" server="\\localhost">
</cfif>
</cflock>
</cfif>

<!--- Get the drives collection and loop through it to populate the
structure. --->
<cfset drives=Application.fso.drives()>
<cfset driveSpace=StructNew()>
<cfloop collection="#drives#" item="curDrive">
<!--- A DriveType of 2 indicates a fixed disk --->
<cfif curDrive.DriveType IS 2>
<!--- Use dynamic array notation with the drive letter for the struct key
--->
<cfset driveSpace["#curDrive.DriveLetter#"]=curDrive.availablespace>
</cfif>
</cfloop>
<cfreturn driveSpace>
</cffunction>

<!--- Test the function. Get the execution time for running the function --->
<cfset start = getTickCount()>
<cfset DriveInfo=getFixedDriveSpace()>
<h3>Getting fixed drive available space</h3>
<cfoutput>Execution Time: #int(getTickCount()-start)# milliseconds</cfoutput><br><br>
<cfdump label="Drive Free Space" var="#driveInfo#">

Example 2: Using the Microsoft Word application object

The following example uses the Microsoft Word application COM object in the Application scope to convert a Word document to HTML. This example works with Word 2000 as written. To work with Word 97, change "Val(8)" to "Val(10)". 
This example uses an Application scope lock to ensure that no other page interrupts creating the object. Once the Word object exists, the example uses a named lock to prevent simultaneous access to the file that is being converted.

<!--- Uncomment the following line if you must delete the object from the
Application scope --->
<!--- <cfset structdelete(Application, "MyWordObj")> --->

<!--- use the GetTickCount function to get a current time indicator, used for
displaying the total processing time. --->
<cfset start = GetTickCount()>
<!--- If necessary, create the Word.application object and place it in the
Application scope --->
<cfset WordObj_is_initialized = False>
<cflock scope="application" type="readonly" timeout=120>
<cfset WordObj_is_initialized = StructKeyExists(application, "MyWordObj")>
</cflock>
<cfif not WordObj_is_initialized >
<cflock scope="Application" type="exclusive" timeout="120">
<cfif not StructKeyExists(application, "MyWordObj")>

<!--- First try to connect to an existing Word object --->
<cftry>
<cfobject type="com"
action="connect"
class="Word.application"
name="Application.MyWordobj"
context="local">
<cfcatch>
<!--- No object exists, create one --->
<cfobject type="com"
action="Create"
class="Word.application"
name="Application.MyWordobj"
context="local">
</cfcatch>
</cftry>

<cfset Application.mywordobj.visible = False>
</cfif>
</cflock>
</cfif>

<!--- Convert a Word document in temp.doc to an HTML file in temp.htm. --->
<!--- Because this example uses a fixed filename, multiple pages could try
to use the file simultaneously. The lock ensures that all actions from
reading the input file through closing the output file are a single "atomic"
operation, and the next page cannot access the file until the current page
completes all processing.
Use a named lock instead of the Application scope lock to reduce lock contention. --->
<cflock name="WordObjLock" type="exclusive" timeout="120">
<cfset docs = application.mywordobj.documents()>
<cfset docs.open("c:\CFusion\wwwroot\temp.doc")>
<cfset converteddoc = application.mywordobj.activedocument>
<!--- Val(8) works with Word 2000. Use Val(10) for Word 97 --->
<cfset converteddoc.saveas("c:\CFusion\wwwroot\temp.htm",val(8))>
<cfset converteddoc.close()>
</cflock>

<cfoutput>
Conversion of temp.htm Complete<br>
Execution Time: #int(getTickCount()-start)# milliseconds<br>
</cfoutput>

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy