ActiveX Shell technology
easy way to enable ActiveX
scripting on Delphi and C++ Builder application
|
Table of contents
What is this
This is a technology for Delphi and C++ Builder.
It allows to create ActiveX object from any Delphi object at design
time and at RUN-TIME by one function call. That allows OLE
automation to access properties and methods of Delphi object.
There is nothing to code with this technology. Just call one function
and use ALL your objects as true ActiveX object now.
The technology can be used, for example, to embed scripting language
such
as VBScript, JScript into the application. With scripting based
on MS ActiveX Scripting or VBA.
In this document you can find all you need for that.
Introduction
You known that Delphi and C++ Builder have their own object model
which is distinct from object model of MS Windows named COM / DCOM / ActiveX /
etc.
Therefore to apply Delphi objects as ActiveX objects it is necessary each
time to create separated ActiveX Library and separated Automation Object object as
wrapper for your code. But will be very problematic to make it for all classes used by
application. Moreover that will not be Delphi application.
The ActiveX Shell technology overcomes this misunderstanding
and makes properties and methods of Delphi objects accessible for OLE
automation that has a huge range of use.
The technology allows to create special ActiveX Shell wrappers around Delphi
objects. ActiveX
Shell wrapper is true ActiveX object.
Delphi object |
+ |
ActiveX Shell |
= |
ActiveX object |
|
Typical example of use is an embedding a scripting language into the
application by using Microsoft ActiveX Scripting or VBA. Where in role
of the scripting language can be used VBScript, JScript, ActivePerl
or any other language maintained MS ActiveX Scripting.
External scripting:
1.Windows applications supporting OLE
2.Windows Scripting Host
3.Office VB
4.Internet Explorer
5.ASP
... |
|
Delphi application internal scripting on:
1.JScript
2.VBScript
3.Perl
...
by using MS Script Control
|
| |
|
| |
OLE automation |
<- |
MS ActiveX Scripting Engine |
| | | |
|
|
ActiveX
Shell wrappers
[ threadsafe ] |
|
|
| |
|
|
Delphi objects |
|
|
|
But MS ActiveX scripting is only one of ways to use application's object
hierarchy created with the ActiveX Shell technology. Now you can use anyone
supporting ActiveX model.
For example, Windows Scripting Host is new MS technology that allows
to use JScript and VBScript programs as Windows batch file. It uses an
ActiveX object model too. Other examples - IIS ASP, Office VB code, VBA.
From side of OLE automation it is enough to create one ActiveX Shell wrapper to receive access to all other linked Delphi objects in application
which is accessible from first as properties, child-components, or methods
results. That means we receive a not only one ActiveX object but access
to all objects in the hierarchy - an OBJECT MODEL OF APPLICATION.
What does it mean ?! For example, if script engine has a reference to
Form1 created with ActiveX Shell then all other components on the form
accessible in script as properties, child-components or as methods results
like this:
Form1.Panel1.Caption
Form1.Panel1.Font.Name
Form1.DBGrid1.Columns.Item(1).Title
Form1.Query1.SQL.Text
Form1.WindowState
...
This is same object hierarchy as you use in Delphi code.
Form1
|____ Panel1
| |-- Caption
| |-- Font
| |-- Size
| |-- Color
| |-- Name
|____ Panel2
| |-- ...
|
|____ Button1
| |-- ...
|
|____ DBGrid1
| |-- Visible
| |-- Columns
| |-- Item(i)
| |-- FieldName
| |-- Title
| |-- Font
| |- ...
|
|____ Query1
| |-- SQL
| | |- Text
| |
| |-- Active
| |-- ...
|
How to obtain a first reference to ActiveX Shell object in your script
?! There are some ways.
For internal scripting you need just to add
first name to the script engine's name space.
And you can use your Delphi objects for external ActiveX scripting. For
example, if application is designed as OCX
library's object then it is possible to execute your application by
calling CreateOLEObject() (or CreateObject() in Visual Basic) and then to use
application objects hierarchy in
Visual Basic program, VBScript, JScript, VBA code of any Windows applications
supporting OLE such as Word, Excel, Outlook, Internet Explorer, IIS ASP
etc. This is a second way to obtain a reference to first ActiveX Shell object.
Possibilities
Technology allows to create ActiveX object from any Delphi
object at design time and at RUN-TIME by one function call. That allows
OLE automation to access properties and methods of corresponding Delphi
object. See below how to create ActiveX wrapper
for your Delphi object.
ActiveX Shell wrapper is TRUE ActiveX object. From the point of view
of OLE, the ActiveX Shell wrapper have same properties and methods as defined
in corresponding native Delphi object. OLE works with native Delphi object
by its ActiveX wrapper.
Now it is possible through this mechanism:
-
to get and set values of published properties
-
for classes inherited from TComponent to receive reference to child-components
by name
-
for classes implementing special Iactivex_shell_executable interface to call methods
with variable number of arguments
-
raise an exception in those methods as
in normal Delphi methods
For object received as result of first two listed actions a new ActiveX
Shell object will be created automatically. To return an object as
result of Iactivex_shell_executable interface methods you have to create new ActiveX Shell
object manually
in the method implementation. You need just to place a call of obj_to_variant
or obj_to_activex function from
our unit.
Now it is possible too:
-
to store and return reference to Delphi object in Variant variable
-
to receive such objects with reference counting and autodestruction features,
see below
ActiveX Shell object is true ActiveX object. Therefore to reference it in Delphi
we should use variable of Variant type. Function var_is_object
described below is used
to check that Variant contains exactly ActiveX Shell object.
When having ActiveX Shell wrapper it is possible anytime to access corresponding
Delphi object by calling function var_to_object described
below. For some Delphi classes
there are extended ActiveX Shell wrappers which are created by the engine when
you call obj_to_variant
and obj_to_activex.
We need extended wrappers to receive access to basic features of some well
known Delphi objects. Especially if the class is frequently used in Delphi but have not
sufficient published properties to manipulate from OLE through our mechanism.
The technology allows to
define such extended ActiveX Shell wrappers for any Delphi classes. See
below
in detail.
Multithread support
You know that Delphi objects have not multithread support. Usually
you have to use Synchronize or other methods to synchronize access to the
objects.
All requests to Delphi object via ActiveX Shell wrappers are always automatically
synchronized. That allow to create multithread application or
multithread accessible application / component without
care about threads synchronization in your code. The technology guarantees that only
one thread in multithread framework will access the Delphi object at the time through
OLE. Even if you create more than one ActiveX Shell wrappers for
one Delphi object. But, of course, any two different Delphi objects are
synchronized independently.
Thread 1 (main)
ActiveX Shell wrapper
for the same Object1 |
|
|
Thread 2
ActiveX Shell wrapper
for the same Object1 |
|
|
Thread 3
ActiveX Shell wrapper
for the same Object1 |
|
|
\
waiting
\
|
|
waiting
| |
/
working
/ |
|
|
|
|
|
|
|
Limitations
Limitations of the technology are based on the features of Run Time Type
Information.
-
The technology works only for classes inherited from TPersistent (most of
classes and all components).
-
It is necessary to have one version of Delphi or C++ Builder (read RTTI) for all separately compiled modules (.exe, .dll, .ocx etc) in application
in the case of use the technology together.
-
ActiveX Shell wrapper can't know if corresponding Delphi object is destroyed. As
everywhere in Delphi a reference to not-existing object can occur. Developer
should control it carefully.
The request on TPersistent is explained by availability the Run Time Type
Information (RTTI) for the object. Though most of Delphi classes are inherited from TPersistent.
And practically absolutely all published
properties of Delphi objects have simple data types or type
inherited from TPersistent.
Available versions,
downloading
Available compiled versions for:
-
C++ Builder 3
-
C++ Builder 4
-
C++ Builder 5
-
Delphi 3.02 (patched)
-
Delphi 4
-
Delphi 5
-
Delphi 6
Source code is compatible with Delphi 3.02, 4, 5, 6 and C++ Builder
3, 4, 5.
Latest version of the component is always available on the components
download page.
How to install
1. |
Unzip archive axshell.zip with subdirectories. |
2. |
Directory CB3\ is for CBuilder 3 users. File activex_shell.obj.
Directory CB4\ is for CBuilder 4 users. File activex_shell.obj.
Directory CB5\ is for CBuilder 5 users. File activex_shell.obj.
Directory D3\ is for Delphi 3 users. File activex_shell.dcu.
Directory D4\ is for Delphi 4 users. File activex_shell.dcu.
Directory D5\ is for Delphi 5 users. File activex_shell.dcu.
Directory D6\ is for Delphi 6 users. File activex_shell.dcu.
Copy file activex_shell.dcu (.obj) from one of this to any Delphi
library path or to your project path.
Or install activex_shell.dcu (.obj) from Menu > Component
> Install Component.
|
3. |
Just add activex_shell to uses statement when need it. |
Examples are located in the corresponding directories too. Also see
examples below.
Hint: For CB3 and CB4 version you can get "Linker error: file not
found dclusr35.lib" (or dclusr40.lib in CB4 case). Just open the
corresponding dclusr??.bpk file in $(BCB)/lib and make it.
Usage
It is very easy to use. Just call one function to create ActiveX
Shell wrapper for your Delphi object
function obj_to_variant(obj : TObject) : Variant;
FYI: The type of returned Variant will be varDispatch because
it will be real ActiveX object.
For example,
unit Unit1;
interface
uses
activex_shell;
type
TForm1 = class (TForm)
Button1: TButton;
procedure Button1Click (Sender:
TObject);
private
end;
implementation
{$R *.DFM}
procedure TForm1. Button1Click (Sender: TObject);
var wrapper: Variant;
begin
// creating an ActiveX Shell wrapper for this
form
wrapper := obj_to_variant(Self);
// using published properties
wrapper.Caption := 'New caption';
wrapper.Font.Size := 22;
// using child-components by name -
// Button1 is not a published property
wrapper.Button1.Caption := 'After click caption';
// using an object type properties
wrapper.ActiveControl := wrapper.Button1;
// String representation is used here to read and
write data of enumeration type
wrapper.WindowState := 'wsMinimized';
ShowMessage(wrapper.WindowState);
wrapper.WindowState := 'wsNormal';
ShowMessage(wrapper.WindowState);
end;
end. |
That is all you need for using published properties and for accessing
child-components by name trowgh ActiveX Shell wrapper.
Note that we are using a Variant reference in this example to show that
we work with the ActiveX objects. Variant in Delphi is used for OLE / ActiveX
objects. All this code can be executed by script engine by VBA, JScript,
VBScript, ActivePerl, etc. See below how to embed
scripting into the application.
Important
declarations in unit activex_shell
Useful functions declared in activex_shell unit:
// checking that Variant is ActiveX
Shell wrapper
function var_is_object(value: Variant): Boolean;
// getting back Delphi object from Variant
containing ActiveX Shell wrapper
function var_to_object(value: Variant) : TObject;
// Getting textual representation of Variant (if
exists) or zero length string
function var_to_string(value: Variant): AnsiString; |
Example: Receiving back Delphi object from Variant containing ActiveX
Shell wrapper. Let variable param is VarArray.
var obj : TObject;
begin
if var_is_object( param[i] ) then
obj := var_to_object( param[i] ); //
making something with the object here
// ...
end; |
How to use
methods
Simple way to access methods without arguments is to use published
property reader.
TMyComponent = class(TComponent)
private
function runMethod1 : String;
published
property Method1 : String read runMethod1;
end; |
As you see, runMethod1 is called every time when accessing published
property Method1.
More flexible way to access the methods is to use special interface
declared in the activex_shell unit as:
Iactivex_shell_executable = interface(IUnknown)
['{B0BA1D30-6F55-11D3-B11C-F9DBB0614516}']
// to return a comma delimited list
of methods supported by your object
function activex_shell_methods : AnsiString;
// to implement methods of your object
function activex_shell_exec(method_name: AnsiString;
var
param: Variant): Variant;
end; |
By implementing Iactivex_shell_executable interface it is possible
to define methods with variable number of arguments. The interface allows
to define what methods of your class will be accessible from OLE automation.
Method activex_shell_methods returns
a comma separated list of methods which you want to publish.
Method activex_shell_exec
is a implementation of those methods.
Methods arguments:
-
method_name is a name of a called method
-
method_name is always on lower case
-
param value is Unassigned or VarArray
(it means array [0.. n] of Variant)
Developer should use standard Delphi functions VarIsArray
and VarArrayHighBound to check that Variant
is an array and for determining size of the array.
Example
of work with methods via Iactivex_shell_executable
You know, Delphi (read OLE engine) needs IUnknown
interface to be implemented to check that the object implements some
other interface (see Delphi manual in detail). Therefore at least two interfaces
are required: Iactivex_shell_executable and IUnknown.
Some Delphi classes are already implements IUnknown. For example, TComponent
class and all its descendants in Delphi 4 and later, C++ Builder 3 and
later.
In other cases you have to implement IUnknown manually in each class
that uses Iactivex_shell_executable interface.
We provide TAXObject class which can be used as base class instead of
TObject in your code to perform automatic IUnknown implementation.
For Delphi 3 we also provide TAXComponent class which can be used
instead of TComponent in your code to perform automatic IUnknown implementation.
Both classes are defined in the activex_shell unit as:
// Useful as base class instead of
TObject
TAXObject = class(TPersistent, IUnknown)
protected
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out
Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
// Useful as base class instead of TComponent
TAXComponent = class(TComponent, IUnknown)
protected
{$ifdef VER100} // only for Delphi 3
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out
Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{$endif}
end; |
Examples, how to provide IUnknown in your class:
Examples |
Description |
// Declaration you have
TMyObject = class
//...
end;
// To provide IUnknown write
TMyObject = class(TAXObject)
// ...
end;
|
TAXObject is used here. Real base class now is not TObject but TPersistent.
That means Delphi will also create RTTI for the instance. |
// Declaration you have
TMyComponent = class(TComponent)
//...
end;
// To provide IUnknown write
TMyComponent = class(TAXComponent)
//...
end; |
TAXComponent is used here. It is not needed in Delphi 4 and above, C++
Builder 3 and above. Do it just for compatibility with Delphi 3. |
// Declaration you have
TMyClass = class(TSomeBaseClass)
// ...
end;
// To provide IUnknown write
TMyClass = class(TSomeBaseClass, IUnknown)
protected
function QueryInterface(const IID: TGUID;
out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
implmentation
uses
Windows;
function TMyClass.QueryInterface(const IID: TGUID;
out Obj): Integer; stdcall;
begin
if GetInterface(IID, Obj)
then Result := 0
else Result := E_NOINTERFACE;
end;
function TMyClass._AddRef: Integer; stdcall;
begin
Result := 0;
end;
function TMyClass._Release: Integer; stdcall;
begin
Result := 0;
end;
|
if TSomeBaseClass doesn't implement IUnknown then you should do it manually
in TMyClass.
Example implementation is presented here too. |
This is example of a component which publishes three its methods as ActiveX
methods by using Iactivex_shell_executable interface:
TMyComponent = class(TAXComponent,Iactivex_shell_executable)
protected
function activex_shell_methods : AnsiString;
function activex_shell_exec(method_name : AnsiString;
var
param: Variant): Variant;
public
procedure Method1();
function Method2(obj : TObject) : String;
function Method3(text : String) : Object;
end;
implementation
// declaration of methods
function TMyComponent.activex_shell_methods : AnsiString;
begin
result := 'method1,method2,method3';
end;
// implementation of methods
function TMyComponent.activex_shell_exec(method_name : AnsiString;
var param: Variant): Variant;
begin
result := Unassigned;
if method_name = 'method1' then begin
Method1();
end
else if method_name = 'method2' then begin
if VarIsArray(param)
then result := Method2(var_to_object(param[0]));
end
else if method_name = 'method3' then begin
if VarIsArray(param)
then result := obj_to_variant(Method3(var_to_string(param[0])));
end;
end; |
Let now MyRef is a ActiveX Shell reference to an instance of TMyComponent in
script engine. Now you can write the following VBScript code:
rem =====================
rem This is VBScript code
rem =====================
rem Receiving a published property value
res = MyObj.Name
rem Assigning a published property value
MyObj.Name = "new_name"
rem Calling a procedure
MyObj.Method1()
rem Receiving a string result
res = MyObj.Method2( MyObj )
rem Receiving a object result
Set obj_res = MyObj.Method3( "test" ) |
This is a working example of Iactivex_shell_executable interface use
for TForm class. You have this as the example application in distribution kit. Additional IUnknown interface implementation here needs only
for Delphi 3.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
activex_shell;
// ^^^^^^^^^^^^^
type
TForm1 = class (TForm, Iactivex_shell_executable)
//
^^^^^^^^^^^^^^^^^^^^^^^^^
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
private
// Iactivex_shell_executable
function activex_shell_methods : AnsiString;
function activex_shell_exec(method_name
: AnsiString; var param: Variant): Variant;
end;
implementation
{$R *.DFM}
procedure TForm1. Button1Click(Sender: TObject);
var wrapper: Variant;
begin
// creating an ActiveX Shell wrapper
wrapper := obj_to_variant(Self);
// using an ActiveX Shell methods
wrapper.show_arguments('only one arg');
wrapper.show_arguments('two', 'args');
wrapper.show_arguments('now', 3 ,'args');
ShowMessage( wrapper.object_classname( wrapper.Button1 ) );
end;
// Iactivex_shell_executable interface
implementation
// declaration of ActiveX Shell methods
function TForm1.activex_shell_methods : AnsiString;
begin
result := 'show_arguments,object_classname';
end;
// implementation of ActiveX Shell methods
function TForm1.activex_shell_exec(method_name : AnsiString;
var param: Variant): Variant;
var i : Integer;
temp_str : String;
begin
result := Unassigned;
//show_arguments
if method_name = 'show_arguments' then begin
if VarIsArray(param) then begin
for i := 0 to VarArrayHighBound(param,
1) do begin
temp_str := temp_str
+ 'arg' + IntToStr(i) + '='
+ var_to_string( param[i] ) + #13;
end;
end;
ShowMessage(temp_str);
end
// object_classname
else if method_name = 'object_classname' then
begin
// How to raise an exception:
if VarIsArray( param ) and (var_to_object(
param[0] ) = nil) then begin
raise Exception.Create( 'Method
parameter is nil !' );
end;
if VarIsArray( param ) and (var_to_object(
param[0] ) <> nil) then begin
result := var_to_object( param[0]
).ClassName;
end;
end;
end;
end. |
Using
TStrings, TCollection, TDataSet
When you are using obj_to_variant
and obj_to_activex, extended ActiveX
Shell wrapper for some Delphi classes is created
automatically by the engine. It helps to receive access to basic features of those Delphi objects via OLE
automation. The technology allows you to
define such extended ActiveX Shell wrappers for any Delphi classes.
For TStrings class and all inherited classes, the following
properties and methods are presented in the extended Active X Shell wrapper:
TStrings properties (see Delphi documentation)
-
Count : Integer;
-
Text : String;
TStrings methods (see Delphi documentation)
-
function Add(value: String) : Integer;
-
procedure Append(value: String) : Integer;
-
procedure Clear();
-
procedure Exchange(index1, index2: Integer);
-
function IndexOf(value: String) : Integer;
-
procedure Insert(index: Integer; value: String);
-
procedure Move(CurIndex, NewIndex: Integer);
-
procedure LoadFromFile(FileName: String);
-
procedure SaveToFile(FileName: String);
Additional methods for getting value of an element
-
function Strings(index: Integer) : String;
-
function Item(index: Integer) : String;
Additional method for setting value of an element
-
procedure SetItem(index: Integer; value: String);
For TCollection class and all inherited classes, the following
properties and methods are presented in the extended Active X Shell wrapper:
TCollection properties (see Delphi documentation)
-
Count : Integer;
-
ItemClass : String;
TCollection methods (see Delphi documentation)
-
function Add : TObject;
-
procedure Clear();
-
function FindItemID(id : Integer) : TObject;
Additional method for getting value of element
-
function Item(index: Integer) : TObject;
For TDataSet class and all inherited classes, the following
properties and methods are presented in the extended Active X Shell wrapper:
TDataSet properties (see Delphi documentation)
-
FieldCount : Integer;
-
BOF : Boolean;
-
EOF : Boolean;
TDataSet methods (see Delphi documentation)
-
procedure First;
-
procedure Last;
-
procedure Next;
-
procedure Prior;
-
function IsEmpty : Boolean;
-
function FieldByName(FieldName: String) : TField;
-
function FindField(FieldName: String) : TField;
Additional methods for getting field and value of field
-
function Fields(index: Integer) : TField;
-
function FieldValues(FieldName: String) : Variant;
-
procedure SetFieldValue(FieldName : String; NewValue: Variant);
Of course those properties and methods always return values as Variant.
Even if result type is TObject here it means result Variant contains ActiveX Shell
wrapper for the instance of that TObject.
Use from
C++ Builder
The use from C++ Builder is same as from Delphi. With only a small
difference. In C++ Builder Variant is class, so we have to use the class syntax.
For example, in Delphi we had the following code:
uses
activex_shell;
....
var myRef : Variant;
begin
// creates OLE object from the form given as self
myRef := obj_to_variant( Self );
// sets new caption to the form
myRef.Caption := 'Welcome !';
end; |
Translated to C++ Builder looks like:
// C++ include directives
#include "activex_shell.hpp"
#pragma link "activex_shell"
...
{
// creates OLE object from the form given as this
// class Variant constructor is used
Variant myRef( obj_to_variant(this) );
// sets new caption to the form
// class Variant method is used
myRef.OlePropertySet("Caption", "Welcome !");
} |
Using
with MS ActiveX Scripting, embedding scripts into the application
MS ActiveX Scripting is just one of ways to use application's
ActiveX object model created with ActiveX Shell technology. You can use any
other scripting engines with your application. If they supports ActiveX /
OLE
object model. See above about it.
For embedding scripts on VBScript, JScript into an application the following
components are required:
-
MS Script Engine
-
MS Script Control
MS Script Engine (Scripting Host) is already on your computer if MS IE 4.0 or above
is installed. It is possible to install separately with the distribution
kit loaded from Microsoft site
URL: http://msdn.microsoft.com/downloads/sample.asp?url=/MSDN-FILES/027/001/733/msdncompositedoc.xml
License: Freeware
GUID: {EE09B103-97E0-11CF-978F-00A02463E06F}
MS Script Control - is necessary for use the
MS Script Engine
by your application. It is possible to install with the distribution kit
loaded from Microsoft site
URL: http://msdn.microsoft.com/downloads/sample.asp?url=/MSDN-FILES/027/001/732/msdncompositedoc.xml
License: Freeware, see site
GUID: {0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC}
Hint: This function allows to do dynamically check by GUID that the necessary
OLE component is installed.
function check_by_guid (component_guid: String):
Boolean;
var v : Variant;
begin
try
v := CreateCOMObject( StringToGUID (component_guid)
);
result := True;
except
result := False;
ShowMessage('Component is not installed: ' +
component_guid);
end;
end; |
This is a example of use of MS Script Control in Run Time where two VBScript
commands are interpreted:
var this_form, scripting, module:
Variant;
begin
// creating an instance of MS Script Control
scripting := CreateOLEObject('ScriptControl');
scripting.AllowUI := True;
scripting.Language := 'VBScript';
// creating ActiveX Shell for the object,
// here for the form given as 'Self'
this_form := obj_to_variant(Self);
// The fist way is to add name to ScriptControl's
namespace
// example of creation of 'this' reference which is global name for
code of all scripts
scripting.AddObject('this', this_form, True);
// example of use of the reference 'this'
scripting.ExecuteStatement(
'this.Caption = "New Caption 1"' + #13#10 +
'MsgBox(this.Caption)'
);
// The second way is to use a special "module"
for the object
// where this. prefix is not need.
module := scripting.Modules.Add('my_form_module', this_form
);
module.ExecuteStatement(
'Caption = "New Caption 2"' + #13#10 +
'MsgBox (Caption)'
);
end; |
In detail about using MS Script Control, its properties, methods and
objects you can read in msscript.hlp from the MS ScriptControl distribution
kit.
Creating
OCX library
Read this only if you need to execute your application as OLE
object.
There is standard way to create an OCX library with "YourAppName.Application" OLE object
by using Delphi ActiveX framework:
-
use Delphi menu > New then choose ActiveX > ActiveX Library
-
save project as "YourAppName"
-
use Delphi menu > New then choose ActiveX > Automation
object
-
write "Application" as Class Name
-
add properties and methods in the Type Library editor and register
library
Now you have OCX library with "YourAppName.Application" object inside.
Now it is possible to execute project and use its objects by call
my_object := CreateOLEObject('YourAppName.Application');
in Delphi or similar function from VBA, VBScript, JScript and all other
languages supporting OLE.
In detail see Delphi documentation.
Now you can use "YourAppName.Application" OLE object as an entry
point to your application object space.
Let the OLE object has property or method returning OleVariant. This
OleVariant can be ActiveX Shell reference to any Delphi object. And all OLE
world can access your Delphi classes by this entry point.
For example, if the Automation object you created has property
DataSet
of type OleVariant which is added by Delphi Type library editor.
An implementation unit will contain empty method which gives the property
value. Use ActiveX Shell technology there:
function TYourAutomationObject.Get_DataSet : OleVariant;
begin
// simply return an object
result := obj_to_variant(FDataSet);
end; |
Now you can access properties and methods of DataSet and all other objects
hierarchically from VBScript. The example:
rem =====================
rem This is VBScript code
rem =====================
my_object = CreateObject('YourAppName.YourAutomationObject')
my_object.DataSet.First()
AmountPaid_sum = 0
do while not my_object.DataSet.EOF
AmountPaid_sum = AmountPaid_sum + my_object.dataset.FieldValues("AmountPaid")
my_object.dataset.Next()
loop
MsgBox(AmountPaid_sum) |
It is a beautiful decision for one more problem.
It is known that only descendants of TWinControl can be automatically
transformed by Delphi to ActiveX. What to do when need to provide functionality
of other classes that are not controls ?
Simply create one Automation object with property that returns the
ActiveX Shell wrapper for Delphi class you need. That allows to receive functionality
of any Delphi classes in the scripts. It was described above
for TDataSet.
Advantage of the Professional
version
I. Multithread
support is in professional version only.
II. In professional version it is possible to create ActiveX
Shell object with reference counting feature and without caring about
destruction of corresponding Delphi object after using it. The Delphi object will be auto destroyed
when reference count is 0.
This feature is very powerful, for example, when returning object value from
a function:
function some_function ... : Variant;
var strings : TStrings;
begin
// creating some object
strings := TStringList.Create();
strings.Add('line 1');
strings.Add('line 2');
strings.Add('line 3');
// creating and returning as result an ActiveX
Shell object
// with feature of reference counting
result := obj_to_activex( strings );
// You have not to care about destruction
of TStringList object.
// It will be auto destroyed when will not be needed.
end; |
Note that
function obj_to_activex( obj : TObject ) : Variant;
is same as considered above obj_to_variant .
But function obj_to_activex create ActiveX Shell wrapper with
feature of reference counting and autodestruction.
This feature is very flexible not only in ActiveX Shell methods
implementation, it can be used freely in Delphi application to return or store
any objects without caring about destruction of them. The object exists while exist
one or more Variant reference to it.
Corresponding Delphi object can be received back from the Variant reference
by using var_to_object
function.
Using with
HTML Template component to create HTML, XML, SGML reports
If you need to create in application HTML, XML, SGML or text
reports then use HTML Template component. It is available for downloading.
In detail see the manual page
of the component.
It works like well known ASP, JSP, PHP templates inside your
application and
allows to produce HTML (XML, SGML, text) page from the page template stored
in the file, database etc. HTML Template works at application side without and Web
server engines and can access application's objects and data to create report.
To design report view it is possible to use your favorite editor. For
example, MS FrontPage, Word, Notepad and so on.
Template page is formatted page with embedded script. The ActiveX Shell
technology can be used as engine for the scripts execution.
How to buy
and download the source code
For commercial purposes or if you are interested in the sources
you have to buy the professional version.
Software will be available immediately after your registration from the secure
web site.
ActiveX
Shell technology
(professional version, source code,
compatible with D3 and above, CB3 and above) |
Personal license,
for one developer |
40 $ |
Buy
it now |
Company license,
for any number of developers within one company |
90 $ |
Buy it
now |
Contact information
Send your questions and comments to support@
Apelseen software website is http://www.
Useful links
|