OLE Extensions for Windows NT Perl 5


SYNOPSIS

Perhaps the most prominent new feature of Perl 5 is its object-oriented programming. This, coupled with the powerful capabilities of OLE 2.0 Automation in Windows NT, enables the average Perl hacker to peform complex tasks using a mere few lines of code.

The Perl OLE interface is quite simple, allowing one to interact with OLE Automation objects via Perl objects. Using MkOLEx, a provided utility, one can build Perl module extensions for OLE Automation objects. Once a module for a particular class has been created, one can simply load the module with the "require" (or "use") function, and can then create objects and invoke methods in the usual Perl object-oriented fashion. All supported methods that the OLE object possess are defined within the Perl object, and methods are provided for retrieving/modifying instance variables.

If the interface for the OLE Automation object is not registered, then one must use the OLE interaction routines in order to manipulate the OLE Automation object. These objects are usually obtained from registered objects, for example a chart object within the Excel.Application object.

MkOLEx

OLE Interaction Routines

Low Level OLE Routines

Modules created by MkOLEx


MkOLEx

MkOLEx (Make OLE Extensions) is a Perl script that creates Perl object-oriented extensions from OLE Automation objects. If supplied with the name of an object class, MkOLEx creates the object and enumerates all variables and member functions of that object. If supplied with the name of a type library file, MkOLEx queries the type library and enumerates all variables and functions under the CoClass type description. Note that MkOLEx does not create Perl extensions for OLE Automation objects embedded within other objects. One must manipulate these objects directly using the low-level routines described in the next section.

Usage: MkOLEx -h Get this help message MkOLEx <typelib file> [ <typelib file> ... ] Generate perl OLE objects from type libraries MkOLEx <class name> [ <class name> ... ] Generate perl OLE objects from object classes Examples provided here are based on the DispCalc Display Calculator application, supplied with Visual C++ 2.x Resource Kit. DispCalc is a simple accumulator-based arithmetic calculator.

Using MkOLEx

As an example, to create a Perl module from the application class "DspCalc2.Application.1", type the following: > MkOLEx DspCalc2.Application.1 To create the Perl module from Disp Calc's type library, type the following: > MkOLEx filepath/dspcalc2.tlb where filepath is the path to the type library file.

If the supplied arguments are valid, MkOLEx will query the object/library and enumerate all member functions and variables. Unfortunately, Windows NT Perl 5 does not support all OLE Automation data types. Functions or variables that rely on these unsupported data types will be discarded. Consult the file "NT.ph" in the perl library to determine which data types are supported and which aren't.

MkOLEx allows only word and numeric characters in OLE module names, and will replace all other characters ([^\w\d]) with an underscore. Once an object class has been enumerated, MkOLEx creates a module in the "OLE" subdirectory of the Perl library directory, naming both the module file and the Perl package as the object class name. For example, our Display Calculator module will be named $perldir/lib/OLE/Dspcalc2_Application_1.pm, and the contents of that file will resemble something like this:

# # Auto-generated OLE Automation module # # OLE object type : Dspcalc2_Application_1 # # Edit at your own risk!! # package OLE::Dspcalc2_Application_1; sub CreateObject { my $hObject; main::NTOLECreateObject( 'Dspcalc2.Application.1', $hObject ) || return undef; my $self = {}; $self->{ 'hObject' } = $hObject || return undef; bless $self; } [...et cetera ad infinitum ad nauseam...] In addition, MkOLEx will generate an HTML document that lists all member variables and methods in an klingon-readable form. The file is saved under the same name as the module file is (but with an "htm" extension, naturally) and placed in the directory where the other Perl documentation resides. A hypertext link to that document will automatically be inserted onto this page.

Using extensions created by MkOLEx

The first thing to do when using an OLE object is to load its corresponding module file. For example require OLE::Dspcalc2_Application_1 will load and compile the module file $perldir/lib/OLE/Dspcalc2_Application.pm. We then create the Display Calculator object with the CreateObject method, which is the standard constructor for all OLE objects created by MkOLEx. $expensive_paperweight = CreateObject OLE::Dspcalc2_Application_1 Methods can now be called from the object like any other Perl object. The following code depresses the "1" button on our glorified silicon abacus: $expensive_paperweight->Button( 1 ); Finally, we destroy the object using the standard destructor "DestroyObject". $expensive_paperweight->DestroyObject(); As a side note, Windows NT Perl will automatically clean up all OLE objects it created on exit, one doesn't have to explicitly destroy every single object. However, if Perl chokes midway through execution, OLE objects it has created will not be mopped up and will be left floating around the system, eating up resources like little sharks in a goldfish bowl.

The following sample script will direct Display Calculator to peform the amazing feat of single digit multiplication.

require OLE::Dspcalc2_Application_1; $expensive_paperweight = CreateObject OLE::Dspcalc2_Application_1; $expensive_paperweight->Button( 'c' ); $expensive_paperweight->Button( '8' ); $expensive_paperweight->Button( '*' ); $expensive_paperweight->Button( '5' ); $expensive_paperweight->Button( '=' ); $expensive_paperweight->Quit; $expensive_paperweight->DestroyObject; If all goes well, the final result displayed should be "40".

CAUTION!

Windows NT isn't case sensitive, whereas Perl is (rightly so!). This becomes a problem when the user supplies an object class as an argument to MkOLEx. For example, the proper classname for the Display Calculator application is "Dspcalc2.Application.1", but typing > MkOLEx dspcalc2.application.1 generates the module OLE::dspcalc2_application_1, not OLE::Dspcalc2_Application_1. When the time comes for a user to actually "require" the modules, the differences in case will undoubtedly become a major source of irritation and confusion. The following Perl code require OLE::Dspcalc2_Application_1 will fail. One need not worry about this when a module is generated from a type library, since the object class name is automagically extracted from the type library.

OLE Interact routines

The following routines interact directly with OLE objects. If an interface to an OLE Automation object is not registered in the Windows Registry (e.g. for embedded objects), then one will have to use these low-level routines to manipulate the object. One should have a solid understanding of OLE programming concepts before attempting to use these routines.

Assuming the user knows what methods and variables exist, it is still possible to invoke these methods and retrieve/modify these variables. Having retrieved an object from a registered object using one of its methods or properties, it is good practise to ensure it has an IDispatch interface by using the NTOLEIsDispatch function. Then one retrieves the function DISPID / variable member ID using NTOLEGetIDofName, and generates a magic string using NTOLECreateMagicString if necessary. One can then use NTOLEPropertyGet / NTOLEPropertySet or NTOLEMethod in order to manipulate the object.

All functions return true on success and false on failure.

NTOLEIsDispatch HOBJECT

Given the handle HOBJECT of an ITypeLib object, returns true if in fact this object has an IDispatch interface attached to it.

NTOLEGetIDofName HOBJECT, MEMBERNAME, MEMBERID

Given the handle HOBJECT of an object created by NTOLECreateObject or returned by an OLE Automation object, returns the DISPID of the function or the MEMBERID of the variable named by MEMBERNAME.

NTOLECreateMagicString STRING, TYPE1, TYPE2, ... , TYPEN

Creates a magic string returned in STRING, given valid OLE Automation variable types TYPE1 to TYPEN, as listed in NT.ph. This is supplied as the FUNCMAGIC for NTOLEMethod.

NTOLEPropertyGet HOBJECT, VARMEMBERID, VARTYPE, VARRETURN

Given the handle HOBJECT, retrieves the variable identified by VARMEMBERID, returning its type in VARTYPE and its value in VARRETURN.

NTOLEPropertyPut HOBJECT, VARMEMBERID, VARTYPE, VARVALUE

Given the handle HOBJECT, sets the value of the variable identified by VARMEMBERID to be VARVALUE. VARTYPE must match the type of the variable for a call to this function to succeed.

NTOLEMethod HOBJECT, FUNCMAGIC, FUNCDISPID, FUNCRETURN, @PARAMS

Given the handle HOBJECT, invokes the method identified by FUNCDISPID. The supplied FUNCMAGIC parameter must correctly identify the types of parameters that the method accepts, and parameters are supplied in the @PARAMS array. The return value of the function is placed in FUNCRETURN.


Low-Level OLE Routines

Using the following routines, one can query type libraries for objects, create objects, enumerate methods and variables, and of course invoke any methods an object posseses. These routines are used by MkOLEx to build the Perl object interfaces to the OLE objects. Warning: the routines are not for the faint of heart, you should have a solid understanding of OLE programming before attempting to use these functions.

NTOLECreateTypeLib FILENAME, HOBJECT, COUNT

Given the FILENAME of a type library, creates an ITypeLib object and stores its handle in HOBJECT, and retrieves the number of type descriptions and stores that in COUNT.

NTOLETypeLibTypeKind HOBJECT, TYPEINDEX, TYPEKIND

Queries the ITypeLib interface of the given object, and returns the TYPEKIND for the type description indexed by TYPEINDEX.

NTOLETypeLibGetTypeInfo HOBJECT, TYPEINDEX, FUNCCOUNT, VARCOUNT

Returns the function count FUNCCOUNT and variable count VARCOUNT for the TYPEINDEX of the ITypeLib object.

NTOLETypeLibGetDispatchIndex HOBJECT, INDEX, DISPSTRING, FUNCCOUNT, VARCOUNT

Given the handle HOBJECT of an ITypeLib object, searches for the CoClass indexed by INDEX, and returns the object classname in DISPSTRING, with the function count in FUNCCOUNT and the variable count in VARCOUNT. One can now use HOBJECT for typelib queries using NTOLETypeInfoVar, NTOLETypeInfoFunc and NTOLETypeInfoFuncInfo. This functions does more or less what NTOLETypeInfo does.

NTOLETypeLibGetDispatchCount HOBJECT, INFOCOUNT

Given the handle HOBJECT of an ITypeLib object, places the number of items in that object in INFOCOUNT.

NTOLECreateObject CLASS, HOBJECT

Given an object CLASS string, creates the object and returns its handle in HOBJECT. The object may now be queried using NTOLETypeInfo, NTOLETypeInfoVar, NTOLETypeInfoFunc, NTOLETypeInfoFuncInfo. Methods may now be invoked using NTOLEMethod, and variables can be retrieved/modified using NTOLEPropertyGet/NTOLEPropertyPut.

NTOLEDestryObject HOBJECT

Destroys the object whose handle is HOBJECT. Once the object is destroyed, the handle HOBJECT should not be used again.

NTOLETypeInfo HOBJECT, FUNCCOUNT, VARCOUNT

Given the handle HOBJECT of an object created by NTOLECreateObject, returns FUNCCOUNT, the number of functions; and VARCOUNT, the number of variables; that the object possesses.

NTOLETypeInfoVar HOBJECT, VARINDEX, VARNAME, VARMEMBERID, VARTYPE, DUMMY, DUMMY, DUMMY

Given the handle HOBJECT of an object created by NTOLECreateObject, returns information regarding the variable indexed by VARINDEX including VARNAME, the variable name, VARMEMBERID, a magical identifier, and VARTYPE, the variable type.

In order to enumerate the variables of an object, one usually starts with VARINDEX being 0, and incremementing VARINDEX with each subsequent call to NTOLETypeInfoVar until VARINDEX exceeds VARCOUNT. Alternately, one could start at VARCOUNT and decrement until VARINDEX is 0.

VARMEMBERID uniquely identifies each variable that an object has, and must be supplied for calls to NTOLEPropertyGet and NTOLEPropertyPut.

OLE Automation data types are defined in the file "NT.ph", this file must be "required" for contained definitions to be loaded. Not all data types are supported by Windows NT Perl 5, consult "NT.ph" to determine which types are supported and which aren't.

DUMMY variables must be supplied, their use will be documented in the next source. If you're brave enough, browsing through the source code will give you an idea what extra functionality is provided. Be warned: these features are completely untested!

NTOLETypeInfoFunc HOBJECT, FUNCINDEX, FUNCNAME, FUNCDISPID, FUNCRETURNTYPE, PARACOUNT, FUNCMAGIC, DUMMY, DUMMY, DUMMY

Given the handle HOBJECT of an object created by NTOLECreateObject, returns information regarding the function indexed by FUNCINDEX including FUNCNAME, the name of the function; FUNCDISPID, a magical identifier; FUNCRETURNTYPE, the function return type; PARACOUNT, the number of parameters the function requires; and FUNCMAGIC, a coded string that identifies the parameter types.

In order to enumerate the functions of an object, one usually starts with FUNCINDEX being 0, and incremementing FUNCINDEX with each subsequent call to NTOLETypeInfoVar until FUNCINDEX exceeds FUNCCOUNT. Alternately, one could start at FUNCCOUNT and decrement until FUNCINDEX is 0.

FUNCDISPID and FUNCMAGIC uniquely identify the function and its parameters respectively, and both must be supplied for calls to NTOLEMethod. OLE Automation data types are defined in the file "NT.ph", this file must be "required" for contained definitions to be loaded. Not all data types are supported by Windows NT Perl 5, consult "NT.ph" to determine which types are supported and which aren't.

DUMMY variables must be supplied, their use will be documented in the next source. If you're brave enough, browsing through the source code will give you an idea what extra functionality is provided. Be warned: these features are completely untested!

NTOLETypeInfoFuncInfo HOBJECT, FUNCINDEX, PARAINDEX, PARANAME, PARATYPE

Given the handle HOBJECT of an object created by NTOLECreateObject, the index of a function FUNCINDEX and the index of a parameter of that function PARAINDEX, returns the parameter name PARANAME and parameter type PARATYPE. OLE Automation data types are defined in the file "NT.ph", this file must be "required" for contained definitions to be loaded. Not all data types are supported by Windows NT Perl 5, consult "NT.ph" to determine which types are supported and which aren't.


MkOLEx generated modules

Netscape_Network_1

Netscape_Registry_1

Excel_Application_5

Word_Basic