Хостинг WSH (VBScript, JavaScript) в вашем приложении Delphi? - PullRequest
4 голосов
/ 06 августа 2009

Я ищу выполнение пользовательских сценариев из моего приложения Delphi.

Можно ли разместить движок Windows Script Host в моем приложении и предоставить ему скрипты для выполнения? Или есть лучший способ решить эту проблему?

P.S Я не ищу сторонние компоненты.

Ответы [ 4 ]

1 голос
/ 14 марта 2019

Вот полный пример кода, который я преобразовал из этого вопроса C ++:

Как загрузить и вызвать функцию VBScript из C ++?

Вам нужны интерфейсы 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. Вы должны получить MsgBox из VBScript, и в отладчике вы можете увидеть, как выражения оцениваются и передаются в Res вариант.

В этом примере не показано, как передать COM-объекты, с которыми скрипт может взаимодействовать. Это должно быть возможно через IActiveScript.AddNamedItem и IActiveScriptSite.GetItemInfo.

Также нет проверки ошибок в коде, который вы должны добавить перед использованием в работе!

1 голос
/ 08 августа 2009

Аллен Бауэр написал в блоге об использовании Active Scripting несколько лет назад. Это входит в теорию, лежащую в основе, и ссылается на код в Code Central, который поддерживает VBScript и JavaScript, сторонние компоненты не нужны.

1 голос
/ 06 августа 2009

Это вполне возможно, и есть много кода, который показывает, как это сделать. Проверить: http://www.torry.net/pages.php?id=280

0 голосов
/ 07 августа 2009

Вам не нужны никакие сторонние компоненты для использования Windows Script Host. Мы используем его в течение десяти лет и создали вокруг него огромную ERP-систему с более чем 1 млн строк исходного кода в VBScript.

Вы должны использовать Windows Script Control, чтобы сообщить Windows Script Host или просто подключиться напрямую через известные интерфейсы.

...