|
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:
-
develop components that can be used in a variety of Win32 applications and
development environments
-
create ActiveX components for system administration that can be accessed
remotely using DCOM
-
develop ActiveX components that expose a subset of Perl functionality, such
as Perl's regular expression engine
-
develop ActiveX components that expose the functionality of a Perl module,
such as a module from the libwww-perl (LWP) library
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.
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.
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).
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.
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.
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.
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.
To use a Perl control with Visual J++, you can use Microsoft's com.ms.Active
x package, which lets you build Java applications that host ActiveX
components. To create and use an instance of a Perl Control, you must:
-
import the import com.ms.activeX.* package
-
create a new instance of the control with new ActiveXComponent ("COMPONENTNAME")
-
invoke the component's methods using the
invoke() method
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.
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.
PerlCtrl includes any modules mentioned in a require or
use statement. For example, if you have file A.pm that requires
B.pm, which requires C.pm, 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.
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.
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.
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.
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.
In addition to synchronizing per method calls, the PerlCtrl runtime also
synchronizes per interpreter. This applies to two important scenarios:
-
multiple objects that each have their own interpreter
-
multiple objects that each share a common interpreter
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.
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.
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.
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.
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 http://msdn.microsoft.com/library/default.asp .
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.
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:
[FILES]
MyControl.htm
Greet.htm
name.htm
[MAP]
#define MyControl 1
#define Greet 10
#define name 20
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.
There are three %TypeLib configuration items:
-
DocString: the name of the type library displayed in type library
browsers, such as the ActivePerl Win32::OLE - Type Library
Browser or the Microsoft VBA Editor.
-
HelpFileName: the name of the compiled help file. The HelpFileName can
only be specified for the entire type library; it cannot be specified for
individual methods or properties. The HelpFileName cannot contain path
references, only the name of the compiled help file.
-
HelpContext: the page in the help file that should be displayed when help
is invoked from the application, or from a method or property within the
application. This is a numerical value that corresponds to the numbers
assigned to pages in the
[MAP] section of the Help Project File.
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,
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'.
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 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:
-
Choose Run from the Start menu, enter
dcomcnfg.exe , and click OK.
The Distributed COM Configuration Properties tool appears, and displays a
list of configurable applications.
-
Find and select your control in the list of applications. Your control
should be listed with the
ProgID value from the %TypeLib hash.
-
Click Properties. The properties dialog for your control appears. Click on
the Security tab (shown below).
You must configure both Access and Launch properties for the control.

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.

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.
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.
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:
-
the remote client must have Perl and the component you developed with
PerlCtrl installed
OR
-
the user on the remote client must be able to read the server's registry
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 dcomhello.pl:
#! 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->Hello();
|