The "ActiveX shell" technology


easy way to enable ActiveX scripting on your Delphi and C++ Builder application

Table of contents

What is this
This technology is for Delphi and C++ Builder.

It allows to create special OLE object (named "ActiveX shell") for any Delphi (VCL) object as at design time so at RUN-TIME. That allows OLE mechanism to access properties and methods of the VCL objects.

The technology can be used, for example, to embed scripting language such as VBScript, JScript into the application. In this document you can find all what you need for that.
 

Introduction
It is known that Delphi and C++ Builder have own object model which is distinct from object model of MS Windows named COM / DCOM / OLE / ActiveX. Therefore to apply Delphi objects as ActiveX objects it is necessary each time to create ActiveX Library and separated ActiveX object as wrapper. But will be very problematic to make it for all objects used by Delphi application. Moreover that will not be Delphi application.

The "ActiveX shell" technology overcomes this misunderstanding and makes properties and methods of VCL objects accessible for OLE / ActiveX model that has a HUGE range of use.

Typical example of use is an embedding a scripting language into the application by using Microsoft ActiveX Scripting. Where in role of  the scripting language can be used VBScript, JScript or any other maintained MS ActiveX Scripting.
 
I. Windows applications
supporting OLE, VBA

II. Windows Scripting Host

|
OLE mechanism
<- ActiveX Scripting <- JScript, VBScript, Perl etc
| |
"ActiveX shell" object Delphi application's internal scripts
|
Delphi (VCL) objects

MS ActiveX scripting is only one of ways to using application's object model created by "ActiveX shell" technology. You can use with your application any other scripting engine that use AciveX object model.

If you create OCX library with "YourAppName.Application" object then  is possible to execute your application and to use its object model from Visual Basic or VBA of other Windows application supporting OLE such as Word, Excel, Outlook, Internet Explorer etc.

For example, Windows Scripting Host is new technology that allows to create JScript and VBScript program as Windows batch file. It can use your application's object model created by "ActiveX shell" technology too.
 

Possibilities
It allows to create special OLE object (named "ActiveX shell") for any Delphi (VCL) object as at design time so at RUN-TIME. That allows OLE mechanism to access properties and methods of the VCL objects.

See below how to create "ActiveX shell" object for your Delphi object.

The "ActiveX shell" object is true OLE object.

From the point of view of OLE a "ActiveX shell" object have same properties and methods as defined in corresponding native Delphi object. OLE works with native Delphi object by its "ActiveX shell" object.

Now is possible through this mechanism:

It is enough to create one "ActiveX shell" object to receive access to all other Delphi objects in application as to OLE objects.

For object received as a result of first two listed actions a new "ActiveX shell" object exists automatically.

However to return some Delphi object as result of  "ActiveX shell" methods you have to create new "ActiveX shell" object  manually.

The "ActiveX shell" object is true OLE object. Therefore to reference such object in Delphi is used Variant type. To determine that some Variant variable is "ActiveX shell" object is used function var_is_object described below.

When having object as "Activex shell" object you can access corresponding Delphi object by calling function var_to_object described below.

For TStrings it creates automatically extended "ActiveX shell" object for receiving access to the basic features of the class TStrings. Because TStrings is frequently used in Delphi but have not sufficient published properties to manipulate. See below in detail.


Limitations

Limitations of the technology is based on the Run Time Type Information's features. The request on TPersistent is explained by availability the Run Time Type Information (RTTI) for the object. Though classes inherited from TPersistent is the majority of Delphi classes. And practically absolutely all published properties of Delphi objects are simple data types or reference to classes inherited from TPersistent. For example, TComponent, TPicture, TGraphic, TFont and TStrings are inherited from TPersistent.
Available versions, downloading
Compiled versions: Compiled versions for other Delphi and C++ Builder releases is not available now.
But you can use the source code with those releases of course.

Download now latest version of axshell.zip (~50 Kb).

How to install
  1. Unzip archive axshell.zip with subdirectories.
  2. Directory D3\ is for Delphi 3 users. Directory D4\ is for Delphi 4 users.

  3. Copy file activex_shell.dcu from one of this to any Delphi library path or to your project path.
    Or install activex_shell.dcu from Delphi menu > Component > Install Component.
  4. Simply add activex_shell to uses statement when need it.
Examples source code is located at corresponding directories ( D3\, D4\ ) too.
Also see examples below.
Usage
It is easy to use.
Simply call one function to create "ActiveX shell" object for your Delphi object

function obj_to_variant(obj : TObject) : Variant;

This is same as

function Tactivex_shell . CreateShell (obj : TObject) : Variant;

Returned Variant datatype will be varDispatch because it is OLE / 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 v: Variant; 
begin

// Creation "ActiveX shell" object for the form
  v := Tactivex_shell . CreateShell ( Self ); 

// Using published properties
  v. Caption := ' New caption '; 
  v. Font. Size := 22; 

// Using child-components by name -
// Button1 is not a published property
  v. Button1. Caption := ' After click caption '; 
 

// Using the object type properties
 v. ActiveControl := v. Button1;

end

end.




The important definitions from the unit activeX_shell.
 
// Definition of the interface

type
  Iactivex_shell_executable = interface (IUnknown) 
      ['{B0BA1D30-6F55-11D3-B11C-F9DBB0614516}']

// to return a comma delimited list of methods supported by object
      function  activex_shell_methods : AnsiString;

// to execute objects methods with variable number of arguments
      function  activex_shell_exec (method_name: AnsiString; var param: Variant): Variant; 
  end

// Where method_name is name of a called method. 
// Note that method_name always on lower case.
// Param is Unassigned or VarArray - array [0.. n] of Variant

// Use standard Delphi functions for determining that it is an array and size of the array:
// VarIsArray( param) 
// VarArrayHighBound( param, n ) 
 


// The following functions are defined:

// Determining that Variant is "ActiveX shell" object
function var_is_object(value: Variant): Boolean; 

// Getting back Delphi object from Variant containing "ActiveX shell" object
function var_to_object(value: Variant) : TObject; 

// For example, where variable obj is of type TObject and param is VarArray
// if var_is_object( param [i] ) then obj := var_to_object( param [i] );

// Additional function of transformation
// it returns textual representation of Variant value or zero length string
function var_to_string (value: Variant): AnsiString;
 

For all classes implementing Iactivex_shell_executable interface and IUnknown interface it is possible to use methods with variable number of arguments.

This is example of using Iactivex_shell_executable interface in Delphi 3.
Note that Delphi 4 TCustomForm class is already implements IUnknown and you should not implement it.
 
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
    { Private declarations }

      // IUnknown
    function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

    // 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 v: Variant; 
begin

// Creation "ActiveX shell" object
  v := Tactivex_shell . CreateShell (Self); 

// Using "ActiveX shell" methods
  v.show_arguments('only one arg');
  v.show_arguments('two', 'args');
  v.show_arguments('now', 3 ,'args');

  ShowMessage( v.object_classname( v.Button1 ) );

end;

// Iactivex_shell_executable

// definition 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

    if VarIsArray( param ) and var_is_object( param[0] ) and (var_to_object( param[0] ) <> nil) then begin
      result  := var_to_object( param[0] ).ClassName;
    end;

  end;

end;
 

// IUnknown
function TForm1.QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
begin
  if GetInterface(IID, Obj) then result := 0 else result := E_NOINTERFACE;
end;

function TForm1._AddRef: Integer; stdcall;
begin
  result := 0;
end;

function TForm1._Release: Integer; stdcall;
begin
  result := 0;
end;

end.

For TStrings it creates automatically extended "ActiveX shell" object for receiving access to the basic features of the class TStrings, because TStrings is frequently used in Delphi but have not sufficient published properties to manipulate.

For TStrings class and all inherited classes it is possible to use in appropriate extended "Active X shell" object already defined properties and methods:

Standard TStrings properties, see Delphi documentation

Standard TStrings methods, see Delphi documentation Special methods for getting value of element Special method for setting value of element


Using with MS ActiveX Scripting, embedding scripts into the application

MS ActiveX Scripting is only one of ways to using application's object model created by "ActiveX shell" technology. You can use with your application any other scripting engine that use AciveX object model. See above about it.

For embedding scripts on VBScript or JScript into an application in addition is required

MS Script Engine - already is on your computer if MSIE 4.0 or above is installed. It is possible to install separately with the distribution kit loaded from Microsoft site

http://www.microsoft.com/msdownload/vbscript/scripting.asp

Size: ~ 650 Kb
License: Freeware
GUID: {EE09B103-97E0-11CF-978F-00A02463E06F}
 

MS Script Control - is necessary for use in the application the MS Script Engine . It is possible to install separately with the distribution kit loaded from Microsoft site

http://msdn.microsoft.com/scripting/scriptcontrol/default.htm

Size: ~ 250 Kb
License: Freeware, see site
GUID: {0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC}
 
// Hint:
// You can use this function for checking availability of component by its GUID

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;

For using MS Script Control it is possible to import it ActiveX class to Delphi ( Delphi IDE Menu > Component > Import ActiveX Control ) and to use it in application as Delphi control, having placed on the necessary form at designer.

Other method is to create OLE object manually in Run Time. This is a small example of use MS Script Control. Where in Run Time two commands on VBScript are interpreted:
 
    var this_form, scripting, module: Variant; 
begin

// Creation of instance of MS Script Control
  scripting := CreateOLEObject ('ScriptControl'); 
  scripting. AllowUI  := True; 
  scripting. Language := 'VBScript'; 
 

// Creation of  "ActiveX shell" for object
  this_form := Tactivex_shell .CreateShell (Self); 
 

// Example of creation of reference 'this' that is global name for all scripts code
  scripting. AddObject ('this', this_form, True); 

// Example of using of the reference 'this'
  scripting. ExecuteStatement (' this.Caption = "New Caption 1"  '   + #13#10 + ' MsgBox (this.Caption) '); 

// Example of creation and using of module for the object 
  module := scripting. Modules. Add ( '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 see msscript.hlp from the MS Script Control distribution kit.


Creating OCX library

This is only if you need to execute your application as OLE object.

For creating OCX library with "YourAppName.Application" OLE object:

  1. use Delphi menu > New  then choose ActiveX > ActiveX Library
  2. save project as "YourAppName"
  3. use Delphi menu > New  then choose ActiveX > Automation object
  4. write "Application" as Class Name
  5. add properties and methods to that object and register library
Now you have OCX library with "YourAppName.Application" object.

Now it is possible to execute project and use its object model by calling

CreateOLEObject( 'YourAppName.Application' )

from Delphi or similar function from VBA and other languages.

In detail see Delphi documentation.

The "YourAppName.Application" object can have properties and methods of type Variant that is object reference. They can be implemented easy by using the "ActiveX shell" technology.
 

Professional version's advantages
In professional version.

It is possible to create "ActiveX shell" object with reference counting and without caring about clearing corresponding Delphi object. The Delphi object will be auto destroyed when reference count is 0.

This feature is very powerful, for example, when returning value from function:
 
function ...
  var strings : TStrings;
begin

// Creating object 
  strings := TStringList.Create();

  strings.Add('line 1');
  strings.Add('line 2');
  strings.Add('line 3');

// Creating and returning from function "ActiveX shell" object 
// with feature of reference counting
  result := obj_to_activex( strings );

// You have not to destroy here the TStringList object.
// It will be auto destroyed when will be not 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" object with feature of reference counting and auto destruction.

This feature is very flexible not only in "ActiveX shell" methods implementation, it can be used freely in your application to return or store any objects without caring about clearing it. Real Delphi object can be received by using  var_to_object  function anytime.


Source code buy online

Professional version with source code costs only 40 $.
Click the image and buy it online.


 

After receiving the payment, maximum per two days we send you technology source texts with comments by e-mail or you can download it from our secure web site.

Thank you for support !

Contact information
Contact person: Karim Yusupov

Send your questions and comments to  apelseen@mail.com

Take a look of  http://apelseen.da.ru