在您的Delphi应用程序中托管WSH(VBScript、JavaScript)?

4

我希望能够从我的Delphi应用程序中执行用户提供的脚本。

是否可以在我的应用程序中托管Windows脚本宿主引擎,并提供要执行的脚本?还是有更好的方法来解决这个问题?

附言:我不需要第三方组件。


1
请参见http://stackoverflow.com/questions/226135/scripting-library-for-delphi,其中链接了许多可用于Delphi的脚本引擎。 - skamradt
你不能作为主机来托管WSH,因为它是一个托管VBS或JS脚本引擎的程序。你必须自己托管这些引擎,这很容易。由于根wscript对象是一个应用程序对象,在WSH之外运行的脚本中不可用。但是,所有实用程序子对象都可以通过CreateObject获得。 - Noodles
4个回答

1

这些中有免费的吗?带源代码的吗?直接托管引擎而不使用任何第三方组件呢? - James Couvares
在Torry上,任何标有“FWS”的项目都意味着“带源代码的免费软件”。许多这样的软件包都被标记为这种方式。其中一些看起来都是Pascal编写的,因此引擎被编译到您的应用程序中。其他一些似乎使用外部引擎,如Lua。 - Todd

1

几年前,Allen Bauer发表了一篇博客文章,介绍了如何使用Active Scripting。他深入探讨了其背后的理论,并提供了在Code Central上支持VBScript和JavaScript的代码,无需第三方组件。


1

这是我从C++问题转换而来的完整代码示例:

如何从C++中加载并调用VBScript函数?

您需要使用定义如下的IActiveScript等接口:

unit AscrLib;

// PASTLWTR : 1.1
// File generated on 7/27/00 12:13:00 PM from Type Library described below.

// ************************************************************************ //
// Type Lib: E:\tp\internet\temp.tlb (1)
// IID\LCID: {B1376415-E2EF-11D1-A693-00AA00125A98}\0
// Helpfile:
// DepndLst:
//   (1) v2.0 stdole, (C:\WINNT\System32\STDOLE2.TLB)
//   (2) v4.0 StdVCL, (z:\Iliad\Bin\STDVCL40.DLL)
// ************************************************************************ //

{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
interface

uses Windows, ActiveX, Classes, StdVCL;

// *********************************************************************//
// GUIDS declared in the TypeLibrary. Following prefixes are used:
//   Type Libraries     : LIBID_xxxx
//   CoClasses          : CLASS_xxxx
//   DISPInterfaces     : DIID_xxxx
//   Non-DISP interfaces: IID_xxxx
// *********************************************************************//
const
  // TypeLibrary Major and minor versions
  ActiveScriptLibMajorVersion = 1;
  ActiveScriptLibMinorVersion = 0;

  LIBID_ActiveScriptLib: TGUID = '{B1376415-E2EF-11D1-A693-00AA00125A98}';

  IID_IActiveScript: TGUID = '{BB1A2AE1-A4F9-11CF-8F20-00805F2CD064}';
  IID_IActiveScriptSite: TGUID = '{DB01A1E3-A42B-11CF-8F20-00805F2CD064}';
  IID_IActiveScriptError: TGUID = '{EAE1BA61-A4ED-11CF-8F20-00805F2CD064}';
  IID_IActiveScriptParse: TGUID = '{BB1A2AE2-A4F9-11CF-8F20-00805F2CD064}';
  IID_IActiveScriptSiteWindow: TGUID = '{D10F6761-83E9-11CF-8F20-00805F2CD064}';

// *********************************************************************//
// Declaration of Enumerations defined in Type Library
// *********************************************************************//
// Constants for enum tagSCRIPTSTATE
type
  tagSCRIPTSTATE = TOleEnum;
const
  SCRIPTSTATE_UNINITIALIZED = $00000000;
  SCRIPTSTATE_INITIALIZED = $00000005;
  SCRIPTSTATE_STARTED = $00000001;
  SCRIPTSTATE_CONNECTED = $00000002;
  SCRIPTSTATE_DISCONNECTED = $00000003;
  SCRIPTSTATE_CLOSED = $00000004;

// Constants for enum tagSCRIPTTHREADSTATE
type
  tagSCRIPTTHREADSTATE = TOleEnum;
const
  SCRIPTTHREADSTATE_NOTINSCRIPT = $00000000;
  SCRIPTTHREADSTATE_RUNNING = $00000001;

// Constants for enum tagSCRIPTINFO
type
  tagSCRIPTINFO = TOleEnum;
const
  SCRIPTINFO_IUNKNOWN = $00000001;
  SCRIPTINFO_ITYPEINFO = $00000002;

// Constants for enum tagSCRIPTITEM
type
  tagSCRIPTITEM = TOleEnum;
const
  SCRIPTITEM_ISVISIBLE = $00000002;
  SCRIPTITEM_ISSOURCE = $00000004;
  SCRIPTITEM_GLOBALMEMBERS = $00000008;
  SCRIPTITEM_ISPERSISTENT = $00000040;
  SCRIPTITEM_CODEONLY = $00000200;
  SCRIPTITEM_NOCODE = $00000400;

type

// *********************************************************************//
// Forward declaration of types defined in TypeLibrary
// *********************************************************************//
  IActiveScript = interface;
  IActiveScriptSite = interface;
  IActiveScriptError = interface;
  IActiveScriptParse = interface;
  IActiveScriptSiteWindow = interface;

// *********************************************************************//
// Declaration of structures, unions and aliases.
// *********************************************************************//
  // wireHWND = ^Integer;
  wireHWND = hWnd;


// *********************************************************************//
// Interface: IActiveScript
// Flags:     (0)
// GUID:      {BB1A2AE1-A4F9-11CF-8F20-00805F2CD064}
// *********************************************************************//
  IActiveScript = interface(IUnknown)
    ['{BB1A2AE1-A4F9-11CF-8F20-00805F2CD064}']
    function  SetScriptSite {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_29:1}const pass: IActiveScriptSite): HResult; stdcall;
    function  GetScriptSite {Flags(1), (2/2) CC:4, INV:1, DBG:6}({VT_29:1}var riid: TGUID;
                                                                 {VT_24:2}out ppvObject: Pointer): HResult; stdcall;
    function  SetScriptState {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_29:0}ss: tagSCRIPTSTATE): HResult; stdcall;
    function  GetScriptState {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_29:1}out pssState: tagSCRIPTSTATE): HResult; stdcall;
    function  Close {Flags(1), (0/0) CC:4, INV:1, DBG:6}: HResult; stdcall;
    function  AddNamedItem {Flags(1), (2/2) CC:4, INV:1, DBG:6}({VT_31:0}pstrName: PWideChar;
                                                                {VT_19:0}dwFlags: LongWord): HResult; stdcall;
    function  AddTypeLib {Flags(1), (4/4) CC:4, INV:1, DBG:6}({VT_29:1}var rguidTypeLib: TGUID;
                                                              {VT_19:0}dwMajor: LongWord;
                                                              {VT_19:0}dwMinor: LongWord;
                                                              {VT_19:0}dwFlags: LongWord): HResult; stdcall;
    function  GetScriptDispatch {Flags(1), (2/2) CC:4, INV:1, DBG:6}({VT_31:0}pstrItemName: PWideChar;
                                                                     {VT_9:1}out ppdisp: IDispatch): HResult; stdcall;
    function  GetCurrentScriptThreadID {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_19:1}out pstidThread: LongWord): HResult; stdcall;
    function  GetScriptThreadID {Flags(1), (2/2) CC:4, INV:1, DBG:6}({VT_19:0}dwWin32ThreadId: LongWord;
                                                                     {VT_19:1}out pstidThread: LongWord): HResult; stdcall;
    function  GetScriptThreadState {Flags(1), (2/2) CC:4, INV:1, DBG:6}({VT_19:0}stidThread: LongWord;
                                                                        {VT_29:1}out pstsState: tagSCRIPTTHREADSTATE): HResult; stdcall;
    function  InterruptScriptThread {Flags(1), (3/3) CC:4, INV:1, DBG:6}({VT_19:0}stidThread: LongWord;
                                                                         {VT_29:1}var pexcepinfo: EXCEPINFO;
                                                                         {VT_19:0}dwFlags: LongWord): HResult; stdcall;
    function  Clone {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_29:2}out ppscript: IActiveScript): HResult; stdcall;
  end;

// *********************************************************************//
// Interface: IActiveScriptSite
// Flags:     (0)
// GUID:      {DB01A1E3-A42B-11CF-8F20-00805F2CD064}
// *********************************************************************//
  IActiveScriptSite = interface(IUnknown)
    ['{DB01A1E3-A42B-11CF-8F20-00805F2CD064}']
    function  GetLCID {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_19:1}out plcid: LongWord): HResult; stdcall;
    function  GetItemInfo {Flags(1), (4/4) CC:4, INV:1, DBG:6}({VT_31:0}pstrName: PWideChar;
                                                               {VT_19:0}dwReturnMask: LongWord;
                                                               {VT_13:1}out ppiunkItem: IUnknown;
                                                               {VT_29:2}out ppti: IUnknown): HResult; stdcall;
    function  GetDocVersionString {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_8:1}out pbstrVersion: WideString): HResult; stdcall;
    function  OnScriptTerminate {Flags(1), (2/2) CC:4, INV:1, DBG:6}({VT_12:1}var pvarResult: OleVariant;
                                                                     {VT_3:1}var pexcepinfo: EXCEPINFO): HResult; stdcall;
    function  OnStateChange {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_29:0}ssScriptState: tagSCRIPTSTATE): HResult; stdcall;
    function  OnScriptError {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_29:1}const pscripterror: IActiveScriptError): HResult; stdcall;
    function  OnEnterScript {Flags(1), (0/0) CC:4, INV:1, DBG:6}: HResult; stdcall;
    function  OnLeaveScript {Flags(1), (0/0) CC:4, INV:1, DBG:6}: HResult; stdcall;
  end;

// *********************************************************************//
// Interface: IActiveScriptError
// Flags:     (0)
// GUID:      {EAE1BA61-A4ED-11CF-8F20-00805F2CD064}
// *********************************************************************//
  IActiveScriptError = interface(IUnknown)
    ['{EAE1BA61-A4ED-11CF-8F20-00805F2CD064}']
    function  GetExceptionInfo {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_24:1}out pexcepinfo: EXCEPINFO): HResult; stdcall;
    function  GetSourcePosition {Flags(1), (3/3) CC:4, INV:1, DBG:6}({VT_19:1}out pdwSourceContext: LongWord;
                                                                     {VT_19:1}out pulLineNumber: LongWord;
                                                                     {VT_3:1}out plCharacterPosition: Integer): HResult; stdcall;
    function  GetSourceLineText {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_8:1}out pbstrSourceLine: WideString): HResult; stdcall;
  end;

// *********************************************************************//
// Interface: IActiveScriptParse
// Flags:     (0)
// GUID:      {BB1A2AE2-A4F9-11CF-8F20-00805F2CD064}
// *********************************************************************//
  IActiveScriptParse = interface(IUnknown)
    ['{BB1A2AE2-A4F9-11CF-8F20-00805F2CD064}']
    function  InitNew {Flags(1), (0/0) CC:4, INV:1, DBG:6}: HResult; stdcall;
    function  AddScriptlet {Flags(1), (11/11) CC:4, INV:1, DBG:6}({VT_31:0}pstrDefaultName: PWideChar;
                                                                  {VT_31:0}pstrCode: PWideChar;
                                                                  {VT_31:0}pstrItemName: PWideChar;
                                                                  {VT_31:0}pstrSubItemName: PWideChar;
                                                                  {VT_31:0}pstrEventName: PWideChar;
                                                                  {VT_31:0}pstrDelimiter: PWideChar;
                                                                  {VT_19:0}dwSourceContextCookie: LongWord;
                                                                  {VT_19:0}ulStartingLineNumber: LongWord;
                                                                  {VT_19:0}dwFlags: LongWord;
                                                                  {VT_8:1}out pBstrName: WideString;
                                                                  {VT_29:1}out pexcepinfo: TGUID): HResult; stdcall;
    function  ParseScriptText {Flags(1), (9/9) CC:4, INV:1, DBG:6}({VT_31:0}pstrCode: PWideChar;
                                                                   {VT_31:0}pstrItemName: PWideChar;
                                                                   {VT_13:0}const punkContext: IUnknown;
                                                                   {VT_31:0}pstrDelimiter: PWideChar;
                                                                   {VT_19:0}dwSourceContextCookie: LongWord;
                                                                   {VT_19:0}ulStartingLineNumber: LongWord;
                                                                   {VT_19:0}dwFlags: LongWord;
                                                                   {VT_12:1}pvarResult: Pointer;
                                                                   {VT_29:1}out pexcepinfo: EXCEPINFO): HResult; stdcall;
  end;

// *********************************************************************//
// Interface: IActiveScriptSiteWindow
// Flags:     (0)
// GUID:      {D10F6761-83E9-11CF-8F20-00805F2CD064}
// *********************************************************************//
  IActiveScriptSiteWindow = interface(IUnknown)
    ['{D10F6761-83E9-11CF-8F20-00805F2CD064}']
    function  GetWindow {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_3:2}out phwnd: wireHWND): HResult; stdcall;
    function  EnableModeless {Flags(1), (1/1) CC:4, INV:1, DBG:6}({VT_3:0}fEnable: Integer): HResult; stdcall;
  end;

implementation

uses ComObj;

end.

这是转换后的示例代码:

unit Unit2;

interface

uses
  Winapi.ActiveX,
  Winapi.Windows,
  System.ObjAuto,
  AscrLib;

const
  CLSID_VBScript: TGUID = '{b54f3741-5b07-11cf-a4b0-00aa004a55e8}';
  CLSID_JScript: TGUID = '{f414c260-6ac0-11cf-b6d1-00aa00bbbb58}';
  SCRIPT_E_REPORTED = HRESULT($80020101);

type
  TSimpleScriptSite = class(TInterfacedObject, IActiveScriptSite,
    IActiveScriptSiteWindow)
  private
    FHwnd: wireHWND;
  public
    // IActiveScriptSite
    function GetLCID(out plcid: LongWord): HResult; stdcall;
    function GetItemInfo(pstrName: PWideChar; dwReturnMask: LongWord;
      out ppiunkItem: IUnknown; out ppti: IUnknown): HResult; stdcall;
    function GetDocVersionString(out pbstrVersion: WideString)
      : HResult; stdcall;
    function OnScriptTerminate(var pvarResult: OleVariant;
      var pexcepinfo: EXCEPINFO): HResult; stdcall;
    function OnStateChange(ssScriptState: tagSCRIPTSTATE): HResult; stdcall;
    function OnScriptError(const pscripterror: IActiveScriptError)
      : HResult; stdcall;
    function OnEnterScript: HResult; stdcall;
    function OnLeaveScript: HResult; stdcall;
    // IActiveScriptSiteWindow
    function GetWindow(out phwnd: wireHWND): HResult; stdcall;
    function EnableModeless(fEnable: Integer): HResult; stdcall;
  end;

procedure TestActiveScriptingOuter;
procedure TestActiveScripting;

implementation

{ TSimpleScriptSite }

function TSimpleScriptSite.EnableModeless(fEnable: Integer): HResult;
begin
  Result := S_OK;
end;

function TSimpleScriptSite.GetDocVersionString(out pbstrVersion
  : WideString): HResult;
begin
  pbstrVersion := '1.0';
  Result := S_OK;
end;

function TSimpleScriptSite.GetItemInfo(pstrName: PWideChar;
  dwReturnMask: LongWord; out ppiunkItem, ppti: IInterface): HResult;
begin
  Result := TYPE_E_ELEMENTNOTFOUND;
end;

function TSimpleScriptSite.GetLCID(out plcid: LongWord): HResult;
begin
  plcid := 0;
  Result := S_OK;
end;

function TSimpleScriptSite.GetWindow(out phwnd: wireHWND): HResult;
begin
  phwnd := FHwnd;
  Result := S_OK;
end;

function TSimpleScriptSite.OnEnterScript: HResult;
begin
  Result := S_OK;
end;

function TSimpleScriptSite.OnLeaveScript: HResult;
begin
  Result := S_OK;
end;

function TSimpleScriptSite.OnScriptError(const pscripterror
  : IActiveScriptError): HResult;
begin
  Result := S_OK;
end;

function TSimpleScriptSite.OnScriptTerminate(var pvarResult: OleVariant;
  var pexcepinfo: EXCEPINFO): HResult;
begin
  Result := S_OK;
end;

function TSimpleScriptSite.OnStateChange(ssScriptState: tagSCRIPTSTATE)
  : HResult;
begin
  Result := S_OK;
end;

procedure TestActiveScriptingOuter;
var
  hr: HResult;
begin
  hr := CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  TestActiveScripting;
  CoUninitialize();
end;

procedure TestActiveScripting;
const
  SCRIPTTEXT_ISEXPRESSION = $00000020;
var
  hr: HResult;
  ScriptSite: IActiveScriptSite;
  JScript: IActiveScript;
  JScriptParse: IActiveScriptParse;
  VBScript: IActiveScript;
  VBScriptParse: IActiveScriptParse;
  res: Variant;
  ei: TExcepInfo;
begin
  // Initialize
  ScriptSite := TSimpleScriptSite.Create as IActiveScriptSite;
  hr := CoCreateInstance(CLSID_JScript, nil, CLSCTX_INPROC_SERVER, IID_IActiveScript, JScript);
  hr := JScript.SetScriptSite(ScriptSite);
  JScriptParse := JScript as IActiveScriptParse;
  hr := JScriptParse.InitNew;

  hr := CoCreateInstance(CLSID_VBScript, nil, CLSCTX_INPROC_SERVER, IID_IActiveScript, VBScript);
  hr := VBScript.SetScriptSite(ScriptSite);
  VBScriptParse := VBScript as IActiveScriptParse;
  hr := VBScriptParse.InitNew;

  // Run some scripts
  hr := JScriptParse.ParseScriptText('(new Date()).getTime()', nil, nil, nil, 0, 0, SCRIPTTEXT_ISEXPRESSION, @res, ei);
  hr := VBScriptParse.ParseScriptText('Now', nil, nil, nil, 0, 0, SCRIPTTEXT_ISEXPRESSION, @res, ei);
  hr := VBScriptParse.ParseScriptText('MsgBox "Hello World! The current time is: " & Now', nil, nil, nil, 0, 0, 0, @res, ei);;
end;

end.

只需运行TestActiveScriptingOuter方法。您应该会收到来自VBScript的MsgBox,并且在调试器中,您可以看到表达式如何被评估并传递给Res变量。
此示例未显示如何传递脚本可以与之交互的COM对象。这应该通过IActiveScript.AddNamedItemIActiveScriptSite.GetItemInfo实现。
此外,在代码中没有错误检查,您应该在使用它进行生产之前添加错误检查!

0

使用Windows脚本宿主不需要任何第三方组件。我们已经使用它十年,并围绕它构建了一个庞大的ERP系统,其中VBScript源代码行数超过100万。

您应该使用Windows脚本控件来告诉Windows脚本宿主,或者直接通过已知接口连接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接