PerlCtrl - Overview

What is PerlCtrl?

The PerlCtrl utility converts a Perl program into a standalone ActiveX control. PerlCtrl is used to develop controls that can be automated from applications and languages that support ActiveX.

With PerlCtrl, you can:

PerlCtrl combines a Perl component, all of the required Perl modules, and a modified Perl interpreter into one binary unit. When the resulting control is run, it searches for modules within itself before searching the filesystem.

PerlCtrl is not a compiler. The Perl source code in the script and the embedded modules must still be parsed and compiled on the fly when the control is instantiated.

The main benefit of PerlCtrl is that it makes your Perl component available to any language and application that supports ActiveX. It can even be used on remote machines using DCOM.

The control can also be deployed to systems that either do not have Perl or do not have the correct combination of modules installed. Additionally, PerlCtrl ensures that your code is always executed by a specific version of Perl, even if the user has a different Perl version already installed. As a side benefit, it can be used for some degree of source code hiding.

The only argument PerlCtrl requires is the name of the Perl program that you want to convert. In most cases, this produces a working control. Additional options are described in PerlCtrl command-line documentation.

The generated control must also be registered with the operating system. This is accomplished using the regsvr32.exe utility.

How Does PerlCtrl Work?

First, PerlCtrl determines which modules and external files the converted script depends upon. The PerlCtrl program begins by scanning the source code of the script. When it finds occurrences of use, do or require, it attempts to locate the corresponding module and then parse the source of that module. This continues as long as PerlCtrl finds new modules to examine.

PerlCtrl does not attempt to run the script. It does not automatically determine which modules a statement like 'require $module;' might load. In such cases, you can manually specify the additional modules to traverse with the --add option.

The PerlCtrl program has some built-in heuristics for major Perl modules that determine additional modules at runtime, like DBI, LWP, Tk. PerlCtrl predicts the additional required modules so that they will be available in freestanding controls.

PerlCtrl then determines which modules to include in the generated control. Usually, all the located modules are included. This also includes the dynamic object files (.so/.dll) and AutoLoader files (.al) that go with the located modules. If the --dependent option is used, only modules located under the directories given by the --lib option are included.

Finally, the control is built with all the modules compressed (unless the --nocompress option is used) and included. When the control runs, it attempts to load any use, do and require statements that are bundled inside of the application itself.

File Extraction

When the control built with PerlCtrl runs, it extracts its dynamic object files in the /tmp/pdk directory. If the control was built using the --clean option, PerlCtrl also appends the process id to this directory name to avoid race conditions during cleanup. The directory location can be overridden with the TMPDIR environment variable. On Windows, the TEMP environment variable is used to override the location. It is also possible to hardcode the location with the --tmpdir command-line option.

Unless the --clean option is used, extracted files are left behind when the control terminates and reused by later incarnations of the same control (or by other PDK-created executables).

Environment Variables

Build time

PerlCtrl uses the PERLCTRL_OPT environment variable to set default command-line options. PerlCtrl treats these options as if they were specified at the beginning of every PerlCtrl command-line. Note: Perl must be in your PATH if you want to use PERLCTRL_OPT.

All directories specified in the PERL5LIB environment variable are treated as if they had been specified with the --lib command-line option. Therefore, modules located in PERL5LIB directories are included even in dependent executables. If PERL5LIB is not set, PerlCtrl uses the value of PERLLIB instead (just like regular Perl).

PerlCtrl pipes the output of perlctrl --help through the program specified in the PAGER environment variable if stdout is a terminal.

Run time

The following environment variables will not be visible to the control built with PerlCtrl: PERL5LIB, PERLLIB, PERL5OPT, PERL5DB and PERL5SHELL.

The temporary extraction directory is automatically added to the PATH environment variable when a file is bound using the [extract] option.

Getting Started with PerlCtrl

The syntax for generating a control is: perlctrl control-name.ctrl

The name of the control must begin with a letter and can contain only letters, digits, and underscores.

While PerlCtrl makes it easy to start developing your own ActiveX Components, you should be familiar with certain aspects of Perl.


Any kind of non-trivial programming task in Perl requires an understanding of Perl's reference mechanism. This feature makes it easy to develop nested data structures, such as scalar variables that contain references to arrays, arrays whose elements are references to hashes, etc. Any scalar value can be a reference to data or code. Perl's Reference feature is a cornerstone of Perl's object-oriented functionality and is also used to construct the 'type' library that is a key part of your Perl Control.

When you pass a reference to an array, scalar, or hash from a client script to a PerlCtrl, a copy of your data is passed, not a true reference to your data. Thus, when you manipulate the data from within the PerlCtrl, you are not manipulating the client's data. The ability to use references in a traditional manner from within PerlCtrl will be addressed in a future version of the Perl Dev Kit.

For complete information on Perl References, see the perlref document in the Perl documentation suite.


Perl controls rely on Perl's package mechanism to create the code that makes up your component. See the perlmod document in the Perl documentation suite for information about how packages are handled in Perl; see the perlfunc document in the Perl documentation suite for information regarding the package statement. See the perlsub document for additional information.

Modules and Classes

You can use Perl modules to create class definitions. This feature can be used with PerlCtrl to create Perl Controls that are object factories. Instead of exposing the functionality of your objects, object factories return instances of the objects. For example, you could create a Perl control that exposes a single method and returns instances of HTTP connection objects. You could then invoke methods on each connection object, rather than on the Perl control itself. Information about Perl's object-oriented features can be found in the perltoot, perlobj, and perlbot pages of the Perl documentation.

Using PerlCtrl with Visual J++

To use a Perl control with Visual J++, you can use Microsoft's x package, which lets you build Java applications that host ActiveX components. To create and use an instance of a Perl Control, you must:

J++ and DCOM

You can use a control over DCOM with J++ to launch instances of controls across the network, but it is more complicated than launching a local copy of the control. The example provided with the Perl Dev Kit relies on some utility classes that are included with the Microsoft SDK for Java 3.1. These utility classes are wrappers around JDirect calls that directly invoke Win32 API functions.

Freestanding Controls

PerlCtrl creates freestanding controls by default. The DLL that is generated contains everything needed to run the control on any Windows machine. This DLL is much larger than a DLL generated with the --dependent switch because it contains the compiled script, the Perl runtime components, and any extensions or modules.

What PerlCtrl includes for a freestanding control

PerlCtrl includes any modules mentioned in a require or use statement. For example, if you have file that requires, which requires, PerlCtrl loads all of these packages. However, PerlCtrl will not load a module mentioned in a variable. For example, if a script has the following line:

  require $module;

PerlCtrl does not include the module identified by $module. To explicitly include this module, rebuild the PerlCtrl using the --add <list> command-line switch, where <list> is a semicolon-delimited list of the modules you wish to explicitly include. PerlCtrl detects which DLLs have been loaded by the *.pm files. However, if a DLL loaded by a .pm file depends upon a second DLL, the second DLL is not bound into the executable. Otherwise, PerlCtrl includes numerous system DLLs.

Installing a Freestanding Control

To install a freestanding control on another computer, copy the DLL you generated with PerlCtrl to the computer, and register it with regsvr32. For example:

  regsvr32 mycontrol.dll

When the control is registered, a message indicates that the control was installed successfully. The control can then be launched from programs running on that machine, or even by programs running on other machines that connect with it using DCOM.

Variant Types

Most examples in this document only show how to declare methods and properties with VT_BSTR (binary strings). PerlCtrl translates Perl values to these types. You need only supply the data types.

 Type Name                Type Symbol
 Unspecified              VT_EMPTY
 Null                     VT_NULL
 2-byte Signed Integer    VT_I2
 4-byte Signed Integer    VT_I4
 4-byte Real Value        VT_R4
 8-byte Real Value        VT_R8
 Currency                 VT_CY
 Date                     VT_DATE
 Binary String            VT_BSTR
 IDispatch FAR*           VT_DISPATCH
 Scodes                   VT_ERROR
 Boolean                  VT_BOOL
 Variant FAR*             VT_VARIANT
 IUnknown FAR*            VT_UNKNOWN
 Unsigned char            VT_UI1

When you pass a reference to an array, scalar, or hash from a client script to a PerlCtrl, a copy of your data is passed, not a true reference to your data. So, when you manipulate the data from within the PerlCtrl, you are not manipulating the client's data. The ability to use references from within PerlCtrl will be addressed in a future version of the Perl Dev Kit.

PerlCtrl Threading

Every top-level object created by PerlCtrl has its own interpreter. Each interpreter is capable of simultaneous and independent execution; that is, a thread in one interpreter does not interfere with a thread in another.

Threading Models

Given that each interpreter is isolated from other interpreters, PerlCtrl objects are "thread safe". This means that they can operate safely in both a single-threaded and a multi-threaded apartment. Synchronization of multiple threads in the same interpreter is handled by the PerlCtrl runtime on a per call basis.


Regardless of the threading model used, all method calls into an interpreter are synchronized internally by the PerlCtrl runtime. In PerlCtrl, this would mean only IDispatch::Invoke. Therefore it is only possible for one thread to execute code in an interpreter at any given time. If two threads attempt to invoke a PerlCtrl method at the same time, one thread is blocked. Once the first thread completes its operation, the second thread is allowed to run.

Interpreter Synchronization

In addition to synchronizing per method calls, the PerlCtrl runtime also synchronizes per interpreter. This applies to two important scenarios:

When there are instantiated multiple PerlCtrl objects, each with its own interpreter, a method call to one PerlCtrl object would not block a method call to another. This means multiple PerlCtrl objects can coexist without conflicts.

Synchronization Issues

While the PerlCtrl runtime synchronizes on a per call basis, it is still possible for an application to encounter problems. For example, if two threads attempt to invoke a PerlCtrl method at the same time, on the same object, or on objects that share an interpreter space. This would cause one thread to be blocked. When the first thread completes its operation, the second thread is allowed to run. Therefore, it is possible for the second thread to change in the object without the first thread recognizing this. Application developers should be aware of this situation and handle it accordingly.

Performance Concerns

Applications may incur a performance penalty based on the threading model used, but this performance hit would be due to the poor design of the host application and not PerlCtrl. For example, if a host application instantiates a PerlCtrl object in a single-threaded apartment and wants to share the interface pointer to another thread, the interface pointer must be marshaled across the apartment boundary. After this, all cross-apartment calls will have to go through the proxy/stub mechanism.

This is enforced via COM and not by PerlCtrl. In the above situation, it would be better if the object were instantiated in a multi-threaded apartment, allowing multiple threads to share the interface pointer directly.

Linking to Compiled HTML Help

PerlCtrl provides the ability to embed context-sensitive references to a compiled HTML Help (.chm) file within a control. When users press 'F1' from within the control, the specified help file and page are opened automatically.

About Microsoft HTML Help

Microsoft HTML Help is a technology used to create compiled help files from groups of HTML files. Compiled help files have the extension ".chm" and can only be viewed on the Windows platform. Within the compiled help, individual pages can be associated with numerical markers, which in turn can be associated with type libraries, and methods and properties contained within type libraries.

For more information about Microsoft's HTML Help, and to download HTML Help components, see . While Microsoft provides a graphical tool called the HTML Help Workshop for creating and compiling help projects, help projects can also be compiled from the command line. The HTML Help Workshop does not provide support for adding [MAP] references to project files (as described in the next section). Therefore, you must use an external editor and add these sections manually to the project file.

Configuring the Help Project File

HTML Help project files contain the definition for the help project and are used by the help compiler to generate the compiled output file. Project files have the extension ".hhp".

To associate a page in the compiled help file with a control, you must first assign an ID number to the page. This ID number corresponds to the value specified in the HelpContext setting in the type library definition. These IDs must be configured under [MAP] sections in the help project file. For example:

  #define MyControl  1
  #define Greet     10
  #define name      20

Compiling the Help File

The command-line compiler for generating HTML Help is called hhc.exe. Note that in order to compile the project, the HTML files must be located in the same directory as the .hhp project file. To compile a help file, enter:

  hhc myhelp.hhp

This assumes that hhc.exe is in your system PATH; modify as necessary.

The compiled help file must be located in the same directory as the DLL generated by PerlCtrl.

Configuring the Control

Adding Type Library References to the Control

There are three %TypeLib configuration items:

For example:

  %TypeLib = (
    PackageName     => 'MyControl',
    DocString       => 'My very own control',
    HelpFileName    => 'MyControl.chm',
    HelpContext     => 1,

This example shows how to associate a help page with a method:

  'Greet' => {
    DocString           => "The Greet() method",
    HelpContext         => 10,

Testing the Control

Testing with the ActivePerl Win32::OLE - Type Library Browser

ActivePerl includes a OLE Type Library Browser that can be used to view the methods and properties within a control and their associated help files. To open the Type Library Browser, select OLE-Browser from the ActivePerl program group on the Windows Start menu.

In the middle pane, scroll down to the library generated with PerlCtrl. (The library is named according to the value of the DocString type library.) Click the library name to display the components; click a component name to view the methods and properties associated with the component. To view the help page associated with the method or property, select the method or property and click 'F1'.

Testing with the Microsoft VBA Editor

Microsoft Office applications include a Visual Basic Editor that can be used to view the methods and properties within a control and their associated help files. To open the Visual Basic editor, first open an Office application (such as Word or Excel), then select Tools|Macro|Visual Basic Editor ('Alt'+'F11').

Within the Visual Basic Editor, use the Tools|References dialog to select the library generated with PerlCtrl. The reference is named according value of the DocString type library; select the check box beside the name to select it.

Use the Object Browser (View|Object Browser or 'F2') to view methods and properties within the library. Select the desired library from the drop-down list in the top left corner of the Object Browser, and then select the control name to display its members. Click on the desired method or property, then click 'F1' to view the associated page in the help file.

Configuring a PerlCtrl for DCOM

Configuring a component developed with PerlCtrl is a simple matter of configuring its DCOM security, since components developed with PerlCtrl are fully DCOM compatible. To configure a control' s DCOM security, use the dcomcnfg.exe utility:

You must configure both Access and Launch properties for the control.


Access Permissions

Make sure Use custom access permissions is selected, and click Edit. Be conservative - only provide access to users who need it. The following graphic shows a control configured on a server named OSCORB for local administrators, domain administrators, interactive users, and the system account.


Launch Permissions

Set the same permissions for Launch: select Use custom launch permissions, and then click Edit. Next, configure the permissions as you did for Access Permissions.

Configuration Permissions

To give another user permission to configure this control, use the Configuration Permissions section of the Security tab to add the user. In most cases, you should not need to modify Configuration Permissions.


Select the Identity tab on the control's Properties dialog. By default, "The launching user" is selected.


"The launching user" is an acceptable setting, if you know that the users who launch the control remotely have sufficient permissions for the control's function. For example, if the control executes shell commands or reads the filesystem, the remote user must have permissions to perform these operations, or the control will not work correctly. Alternatively, you can create a new user account with the correct permissions, and then run the control under that user account (choose "This user" and select a user by clicking Browse or typing the username). You must supply the user account name as well as the password. Use this with caution, since you are allowing remote users to impersonate another user on your machine. If you choose "The interactive user" your control will run with the permissions of whoever is currently logged in to the server (it is possible that no one will be logged in). The "The interactive user" setting should only be used for testing in a secure environment.

Using a PerlCtrl with DCOM

Once you have configured your control for DCOM, using it is simple. If you are programming with Perl on the remote machines, you can use Win32::OLE to launch the control remotely.

You must have two networked machines. The machine with your PerlCtrl for DCOM is the server; the machine you launch the control from is the remote client. To use this example, either of two cases must be true:


This is because the example launches the component using its ProgId (for example, in the case of the sample control, Hello.World). The client machine needs to resolve the ProgID into the CLSID before it can launch the control. If the control is installed on the client machine, the CLSID of the control is the same on each machine, so the client machine can look up the CLSID in its own registry using its ProgID. If the client machine does not have the component installed, Win32::OLE will try to connect to the server's registry and look up the CLSID. If your network configuration does not permit this, you can launch the control using its CLSID in place of its ProgID. The following example launches Hello.World on a remote machine using the ProgID and invokes its Hello method. This example can be found in the DCOMHello subdirectory of the Samples directory. Here is the source for

  #! perl -w
  use Win32::OLE;
  use strict;
  # The user must supply the name of the server on which to launch the
  # control.
  unless (@ARGV >= 1) {
    die "usage: $0 <SERVER>\n";
  my $server = shift;
  my $obj_hello = Win32::OLE->new( [$server, "Hello.World"] );
  print $obj_hello-&gt;Hello();