?
Solved

ActiveX: Dropped on Form/Create via constructor

Posted on 2005-03-30
9
Medium Priority
?
724 Views
Last Modified: 2010-04-16
This is a really strange problem and is possibly worth at least a thousand points. It is about the differences between controls dropped on forms and created dynamically. At least so I think. Perhaps I'm doing something wrong?

Basically I can't get the MS Script Control to work - unless it's dropped on a form.

To test this you'll need to import the MS Script control to get the unit MSScriptControl_TLB.

The form contains, as ScriptControl1, a dropped MS Script control, a memo for holding the code (Javascript text), and several buttons.

If you start the program and press About you'll see which version of the control you have. I have version 1.0 from Win2K pro. Press the load button to load the Javascript from c:\temp\test.js. If you press Compile you'll get the correct error - namely a missing bracket. If you press Create you'll get the same error. But if you do this the other way round the Create button gives the no error message nor position. It seems that pressing Run causes something to get set or unset so that the behavior changes.

What I need is the ability to create the control in a thread and set the OnError call back.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  OleCtrls, MSScriptControl_TLB, StdCtrls, OleServer, ActiveX;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ScriptControl1: TScriptControl;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Memo1: TMemo;
    edExcept: TEdit;
    Label1: TLabel;
    procedure ScriptControl1Error(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ScriptControl1Error(Sender: TObject);
var
   iError : IScriptError;
begin
   iError:=ScriptControl1.Error;
   ShowMessage(IntToStr(iError.Get_Line)+','+IntToStr(iError.Get_Column)+
               ':' + iError.Get_Description);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ScriptControl1._AboutBox;
end;

procedure TForm1.Button2Click(Sender: TObject);
const
   CRLF:WideString = #$0D#$0A;
begin
   Memo1.Lines.LoadFromFile('c:\temp\test.js');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
   try
      ScriptControl1.AddCode(Memo1.Text);
   except
      edExcept.Text:='exception';
   end;
end;

procedure TForm1.Button4Click(Sender: TObject);
var
  Bounds : array [0..0] of TSafeArrayBound;
  Params : PSafeArray;
begin
  Bounds[0].cElements:=0;
  Bounds[0].lLbound:=0;
  Params:=SafeArrayCreate(varVariant, 1, Bounds);
  ScriptControl1.Run('test',Params);
end;

procedure TForm1.Button5Click(Sender: TObject);
var
   ScriptControl2 : TScriptControl;
begin
  ScriptControl2:=TScriptControl.Create(nil);
//  ScriptControl.ControlData:=ScriptControl1.ControlData;
  try
     ScriptControl2.OnError:=ScriptControl1Error;
     ScriptControl2.Language:='JScript';
     ScriptControl2.AddCode(Memo1.Text);
  except
     edExcept.Text:='exception occured';
  end;
  ScriptControl2.Free;
end;

end.

(* dfm *)
object Form1: TForm1
  Left = 285
  Top = 116
  Width = 696
  Height = 480
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -13
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 120
  TextHeight = 16
  object Label1: TLabel
    Left = 56
    Top = 336
    Width = 59
    Height = 16
    Caption = 'Exception'
  end
  object Button1: TButton
    Left = 64
    Top = 384
    Width = 75
    Height = 25
    Caption = 'About'
    TabOrder = 0
    OnClick = Button1Click
  end
  object ScriptControl1: TScriptControl
    Left = 16
    Top = 8
    Width = 32
    Height = 32
    OnError = ScriptControl1Error
    ControlData = {
      21433412080000002403000024030000D2F1594E010000002200000010270000
      000007004A00530063007200690070007400}
  end
  object Button2: TButton
    Left = 152
    Top = 384
    Width = 75
    Height = 25
    Caption = 'Load'
    TabOrder = 2
    OnClick = Button2Click
  end
  object Button3: TButton
    Left = 248
    Top = 384
    Width = 75
    Height = 25
    Caption = 'Compile'
    TabOrder = 3
    OnClick = Button3Click
  end
  object Button4: TButton
    Left = 344
    Top = 384
    Width = 75
    Height = 25
    Caption = 'Run'
    TabOrder = 4
    OnClick = Button4Click
  end
  object Button5: TButton
    Left = 448
    Top = 384
    Width = 75
    Height = 25
    Caption = 'Create'
    TabOrder = 5
    OnClick = Button5Click
  end
  object Memo1: TMemo
    Left = 56
    Top = 8
    Width = 577
    Height = 305
    Lines.Strings = (
      'Memo1')
    TabOrder = 6
  end
  object edExcept: TEdit
    Left = 120
    Top = 336
    Width = 497
    Height = 24
    TabOrder = 7
  end
end

(* c:\temp\test.js *)
// test piece of Javascript

function test(para)

var x = para;
   if (Para==0) alert('Parameter is zero!');
}
0
Comment
Question by:BigRat
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 3
9 Comments
 
LVL 13

Accepted Solution

by:
BlackTigerX earned 2000 total points
ID: 13663635
a few problems

the test function has two errors

the missing braket and the "P"ara, instead of "p"ara

then, in your error handler, you have hardcoded the one in your form, not the one created dinamically:

var
   iError : IScriptError;
begin
   iError:=ScriptControl1.Error; //always calls the one on the form

I'll show you the code I have... is working as expected so far...
0
 
LVL 13

Expert Comment

by:BlackTigerX
ID: 13664366
ah... found something else...

you can't call "alert", that's not part of JScript, that's why I was getting a "object expected" error in that specific line
0
 
LVL 13

Expert Comment

by:BlackTigerX
ID: 13664504
here are some comments I gathered from some people that know more about JScript:

"JScript doesn't have anything native (like VBScript's MsgBox).  When WSH is the host, the WScript
object has the echo method.  But the Script Control as a host for the script engines doesn't provide
any built-in objects with properties/methods.

It up to your application (as the host of the script control) to create/add it's own object to the
script control to expose a comparable alert method.

Or you can just use the WshShell object's PopUp method from JScript. "
----------------------
"You *could* use WshShell.Popup from JScript...  Otherwise, you application as the ultimate host
needs to create an object with an "alert-like" method (a simple wrapper around MsgBox) that you then
add with AddObject...  (see the AddObject documentation for optional arguments) "
----------
and this from a Microsoft guy:
"Sure, the "object expected" is coming from the JScript engine when it
attempts to execute the line of code

alert("Hi there");

"alert" is a method of the Internet Explorer document object model.  If
you're not running your script under IE DOM, the script engine has no idea
what "alert" means -- it is expecting that alert will resolve to a function
object, hence "object expected".

FYI, JScript has no built-in message box routine like VBScript's "MsgBox". "
-------------

so basically your code is good, let me put what I have, is almost the same as yours
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 13

Expert Comment

by:BlackTigerX
ID: 13664552
//code:
unit Unit1;

interface

uses
  Variants, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  OleCtrls, MSScriptControl_TLB, StdCtrls, OleServer, ActiveX;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Memo1: TMemo;
    edExcept: TEdit;
    Label1: TLabel;
    procedure ScriptControl1Error(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FScriptControl:TScriptControl;
  public
    { Public declarations }
    aScriptControl:TScriptControl;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ScriptControl1Error(Sender: TObject);
var
   iError : IScriptError;
begin
   iError:=FScriptControl.Error;
   ShowMessage(Format('Control Error: %d,%d:%s', [iError.Get_Line, iError.Get_Column, iError.Get_Description]));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  aScriptControl._AboutBox;
end;

procedure TForm1.Button2Click(Sender: TObject);
const
   CRLF:WideString = #$0D#$0A;
begin
   Memo1.Lines.LoadFromFile('c:\temp\test.js');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
   try
     aScriptControl.AddCode(Memo1.Text);
   except
     on E:Exception do
       edExcept.Text:='exception:'+E.Message;
   end;
end;

procedure TForm1.Button4Click(Sender: TObject);
var
  V: Variant;
begin
  V:=VarArrayOf([1]); //if you pass a zero, it will fail at run time, because "alert" doesn't exist
  aScriptControl.Run('test', PSafeArray(TVarData(V).VArray));
end;

procedure TForm1.Button5Click(Sender: TObject);
var
   ScriptControl2 : TScriptControl;

  Bounds : array [0..0] of TSafeArrayBound;
  Params : PSafeArray;
begin
  ScriptControl2:=TScriptControl.Create(nil);
//  ScriptControl.ControlData:=ScriptControl1.ControlData;
  try
    FScriptControl:=ScriptControl2;
    ScriptControl2.OnError:=ScriptControl1Error;
    ScriptControl2.Language:='JScript';
    ScriptControl2.AllowUI:=False;
    ScriptControl2.AddCode(Memo1.Text);

    Bounds[0].cElements:=0;
    Bounds[0].lLbound:=0;
    Params:=SafeArrayCreate(varVariant, 1, Bounds);

    ScriptControl2.Run('test', Params)
  except
    on E:Exception do
      edExcept.Text:='exception occured:'+E.Message;
  end;
  ScriptControl2.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  aScriptControl:=TScriptControl.Create(nil);
  aScriptControl.Language:='JScript';
  aScriptControl.AllowUI:=True;
  aScriptControl.OnError:=ScriptControl1Error;
  aScriptControl.State:=0;
  aScriptControl.SitehWnd:=Handle;
  FScriptControl:=aScriptControl
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  aScriptControl.Free
end;

end.
//***************************
//form
object Form1: TForm1
  Left = 285
  Top = 116
  Width = 532
  Height = 367
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -10
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 46
    Top = 273
    Width = 47
    Height = 13
    Caption = 'Exception'
  end
  object Button1: TButton
    Left = 52
    Top = 312
    Width = 61
    Height = 20
    Caption = 'About'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 124
    Top = 312
    Width = 60
    Height = 20
    Caption = 'Load'
    TabOrder = 1
    OnClick = Button2Click
  end
  object Button3: TButton
    Left = 202
    Top = 312
    Width = 60
    Height = 20
    Caption = 'Compile'
    TabOrder = 2
    OnClick = Button3Click
  end
  object Button4: TButton
    Left = 280
    Top = 312
    Width = 60
    Height = 20
    Caption = 'Run'
    TabOrder = 3
    OnClick = Button4Click
  end
  object Button5: TButton
    Left = 364
    Top = 312
    Width = 61
    Height = 20
    Caption = 'Create'
    TabOrder = 4
    OnClick = Button5Click
  end
  object Memo1: TMemo
    Left = 46
    Top = 7
    Width = 468
    Height = 247
    Lines.Strings = (
      'Memo1')
    TabOrder = 5
  end
  object edExcept: TEdit
    Left = 98
    Top = 273
    Width = 403
    Height = 24
    TabOrder = 6
  end
end
0
 
LVL 13

Expert Comment

by:BlackTigerX
ID: 13665036
also, this is relevant and good to know:

//***This calls a function or sub with parameters:

procedure TForm1.Button2Click(Sender: TObject);
var  V: Variant;
begin
  V := VarArrayOf(['test1', 'test2', 'test2']);
  ScriptControl1.Run('Test', PSafeArray(TVarData(V).VArray)­);
end;

//***This calls a function or sub without params:
procedure TForm1.Button2Click(Sender: TObject);
var
    psa: PSafeArray; (* Used to allocate a safe array *)
    sab: TSafeArrayBound; (* Array bound descriptor *)
begin
    sab.lLbound := 0;
    sab.cElements := 0;
    psa := SafeArrayCreate(VT_VARIANT, 1, sab);
    scriptControl1.run ('Test', psa);
    SafeArrayDestroy (psa);
end;

//***One other way to archive the same if the name is known at design time is:
procedure TForm1.Button2Click(Sender: TObject);
var  V: Variant;
begin
  v := scriptControl1.CodeObject;
  v.Test ('test1, 'test2', 'test3');
end;
0
 
LVL 27

Author Comment

by:BigRat
ID: 13670037
>>the test function has two errors

It is irrelevant how many errors the test function has, the point is getting the control to report the error messages. The real code is part of an IDE, which handles RatScript, Javascript, HTML, CSS and XML/XSLT. The "Compile" function performs RatScript compile, Javascript syntax check, HTML/CSS check with w3c.org's Tidy lib, and well-formedness of XML and XSLT with Delphi components.
0
 
LVL 27

Author Comment

by:BigRat
ID: 13670068
>>then, in your error handler, you have hardcoded the one in your form, not the one created dinamically.

Ooops. That certainly is the error here. I have changed the code to read :-

procedure TForm1.ScriptControl1Error(Sender: TObject);
var
   iError : IScriptError;
begin
   iError:=(Sender as TScriptControl).Error;  //  <==== Changed HERE!!!
   ShowMessage(IntToStr(iError.Get_Line)+','+IntToStr(iError.Get_Column)+
               ':' + iError.Get_Description);
end;

and it works perfectly of course  :(. Now I'll just go back to the IDE and see what is different. Back in an hour or so.....
0
 
LVL 27

Author Comment

by:BigRat
ID: 13670785
Here is no the working JScript compiler code :-

procedure TJScriptCompiler.OnError(Sender : TObject);
var
   ErrorObj : IScriptError;
  begin (* gets called when an error occurs *)
   ErrorObj:=(Sender as TScriptControl).Error;
   if Assigned(OnCompMessage) then
      OnCompMessage(ErrorObj.Get_Description,ErrorObj.Get_Line);
  end;

function TJScriptCompiler.Compile : Boolean;
var
   Reply    : HResult;
   ErrorObj : IScriptError;
  begin
   Reply:=CoInitialize(nil);
   if Reply<>S_OK then
      begin
      if Assigned(OnCompMessage) then
         OnCompMessage('Cannot init COM '+ IntToStr(Reply),1);
      Result:=false;
      end
   else
      begin
      try
         ScriptControl:=TScriptControl.Create(nil);
         ScriptControl.AllowUI:=false;
         ScriptControl.OnError:=OnError;
         ScriptControl.Language:=WideString('JScript');
         ScriptControl.AddCode(Text);
         Result:=true;
      except
         begin
//         ErrorObj:=ScriptControl.Error;
//         if Assigned(OnCompMessage) and Assigned(ErrorObj) then
//            OnCompMessage(ErrorObj.Get_Description,ErrorObj.Get_Line);
//         ShowMessage(ErrorObj.Get_Text + ' ' + IntToStr(ErrorObj.Get_Line));
         Result:=false;
         end;
      end;
      ScriptControl.Free;
      CoUninitialize;
      end;
  end;

I had made the same mistake of using an uninitialized script control variable to get the error message. Furthermore I had turned off the CoInitialize() to test outside the thread and the result was an uninitialized IScriptError object (the methods seem to go via Fintf variable which was nil).
0
 
LVL 13

Expert Comment

by:BlackTigerX
ID: 13671344
you certainly know more about using the script control... looks good =o)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses

801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question