views:

485

answers:

2

Is there a better way to create objects in IScriptControl than this?

Result := SC.Eval('new Date()');

I need something like this:

function CreateJSObject(JSClassName: string; Params: PDispParams): OleVariant;

a naive implementation would be

var 
    S: string;
begin 
    S := '';
    for I := P.cArgs - 1 downto 0 do
    begin
        if S <> '' then
            S := S + ', ';
        S := S + ConvertParamToJSSyntax(OleVariant(P.rgvarg[I]));
    end;
    Result := ScriptControl.Eval('new ' + JSClassName + '(' + S + ');'); 
end;
A: 

To call a subroutine, you need to use the Run method, instead of Eval. See this doc for more info.

You are correct in saying that "constructors are different sort of methods", but in this case you are actually just returning the newly-constructed value, aren't you? And so I would expect to still be able to use Eval().

The following code works for me:

procedure TForm1.Button1Click(Sender: TObject);
var
  ScriptControl: Variant;
  Value: Variant;
begin
  ScriptControl := CreateOleObject('ScriptControl');
  ScriptControl.SitehWnd := Handle;
  ScriptControl.Language := 'JScript';

  Value := ScriptControl.Eval('new Date();');
  ShowMessage(VarToStr(Value));
end;

When I click the button, my ShowMessage shows up with "Wed Sep 16 23:37:14 TC+0200 2009".

And so for returning a value from a constructor, you can actually use Eval().

Cobus Kruger
Thank you for the answer, but I know about Run (see my previous comment) and I know about Eval (see the post). I am searching for a *better* way of calling constructors: faster, without converting parameters to JavaScript syntax.
kaboom
Totally confused now, sorry. What do you mean "without converting parameters to JavaScript syntax?" In your reply to roosteronacid you asked "How can I call a constructor?" but now you are saying you'd like to construct the object without using JavaScript parameters? Perhaps it will clear things up for me if you showed some pseudo code of what you're trying to do.
Cobus Kruger
I edited the question. I hope it is more clear now.
kaboom
+1  A: 

Query the IDispachEx interface on the CodeObject property of the MSScriptControl. It is a pointer on the global state of the JScript and it contains all objects added to it. Then do an InvokeEx with a DISPATCH_CONSTRUCT parameter on the object name you want to create. This would be equivalent to calling "new".

This would create an object of the correct type and you would not have to convert them to javascript types. You'll be able to pass native objects to the constructor as well.

I know that this works for constructors defined in script. I'm not sure about Date which is a native property.

This works on JScript and VBScript activescripting host, but some others scripting host does not return anything on CodeObject, so this is not very portable.

Emmanuel Caradec