AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Windows Scripting Host (WSH)
Thema durchsuchen
Ansicht
Themen-Optionen

Windows Scripting Host (WSH)

Ein Thema von himitsu · begonnen am 5. Nov 2023 · letzter Beitrag vom 7. Nov 2023
Antwort Antwort
Benutzerbild von himitsu
himitsu
Registriert seit: 11. Okt 2003
Windows Scripting Host (WSH)
https://de.wikipedia.org/wiki/Windows_Script_Host

https://learn.microsoft.com/en-us/pr...ectedfrom=MSDN
https://community.embarcadero.com/bl...lication-36013


Da dieses in abgeschlossene Windows-API ist (Entwicklung abgeschlossen und Interfaces als volltändig/ausreichend definiert)
läuft es natürlich nur unter Windows. Schön ist aber, dass sich jeder im Windows registrieren und weitere Engines hinzufügen kann.

Standardmäßig sind JavaScript und VBScript vorhanden.
Vielleicht kennt ihr es vom FinalBuilder, welcher Pyphon und PowerShell zusätzlich drin hat. (sie nutzen aber fertige C#-Komponenten dafür, wie z.B. Bei Google suchenIronPython)

Ich hatte vor 'ner Weile mal geschaut, wie man das nutzt (ein paar wenige "ältere" Delphi-Komponenten inzwischen auch gefunden)
und soooooo schlimm sieht es garnicht aus .... in Minimal kommt man "nativ" mit paar Zeilen Code aus (siehe unten).
Und das dann angefangen in eine TComponent zu packen.


https://de.wikipedia.org/wiki/Windows_Script_Host
https://en.wikipedia.org/wiki/Windows_Script_Host
im Englischen Wiki eine schöne Auflistung, was es z.B. für Sprachen gibt.
* Perl, LUA, PHP, Ruby, Tcl, Huskell, Cobol , Fortan, C++ und C# (als Script) und ja, auch Delphi/Pascal, sowie vieles Mehr.

Wie und wo man die Installationen dafür findent, hab ich "noch" nicht geschaut.

Bezüglich Python hatte ich aber schonmal gesucht und
Es gibt eigentlich das Projekt Bei Google suchenActivePython und die Version 2.7 (mit Python 2.7) gibt es als Community Edition zu finden.
* https://www.heise.de/download/produc...-edition-37561
* die 64 Bit-Version ist auch nur die 32 Bit, also funktioniert es nur für 32 Bit-Delphi-Programme
* die Version 3.x gibt es nirgendwo mehr
* und der Entwickler hat die Community Edition eingestellt https://www.activestate.com/blog/goo...tate-platform/
* die aktuelle kostenlose Version des ActiveState hatte ich getestet und es nicht hinbekommen, dass sie sich im Windows registriert (weder 32 noch 64 Bit)
Achtung, beim Login via GitHub, wollen die lese/schreibzugriffe auf alle eure "privaten" Repos haben ... hab's also via eMail gemacht.

ActivePython ist dieses ominöse "Python.AXScript.2", was man in den Demos findet. (funktioniert auch, wenn es installiert ist)
https://wiki.python.org/moin/ActivePython




Quellcode ... joar, kommt irgendwann.
Aktuell hab ich mir mal 'ne Test-Anwendung wild zusammengeklöppelt, welche alle bisher implementierten Funktionen und ein paar Demo enthält. (PS: siehe Hints überall)

* Achtung, die Ausgabeumleitung fehlt noch. (hoffe auf eine andere Lösung, falls man es in einer ConsolenAnwendung nutzen wöllte)
* Expressions sind nutzbar, da als Funktion-Result aus der Funktion raus kommen
* beim ExecuteScript gibt es eigentlich auch ein Result, aber da steht nichts drin
* da es eine GUIAnwendung ist, hat sie "eigentlich" keine Console, wo die Scriptausgabe vom StdOut landen
* rechts in der TestEcke sind zwei Knöpfe (einmal zum Generieren eines Consolenfensters und das Andere mit einer Umleitung der StdIn/StdOut/StdErr ... was ich aber "noch" nicht in meine Komponente integriert hab)


* paar Varianten eigene Objekte/Variablen/Funktionen aus Delphi reinzugeben existieren schon (in 3 Varianten, siehe ScriptingMain.pas -> TPropTest und Co.)
* wobei die Letzte nicht direkt auf IDispatch aufsetzt, sondern IDispatchEx nutzt und dann via RTTI auf Delphi-Code zufreift, also public Objekt-Felder/Variablen, Property und Methoden

* Ja, SynEdit aus'm GetIt könnte man noch benutzen
* externer Zugriff auf aktuelle Variablen/Objekte/Funktionen, des Scripts, fehlt auch noch
* die Debugging-API hab ich "noch" nicht implementiert
* CodeInsight/CodeCompletion wäre noch interessant, also mit LiveDaten aus der ScriptingEngine
* die PythonScript.dll ist noch ohne Funktion (PythonScript)
* und die ConsoleScript.dll (CMD/CommandScript, PowerShell und WSL, falls installiert)

* CMD/PS/SWL hängt noch etwas, da ich dort noch etwas mit der neuen PseudoConsole (ConPTY) kämpfe.
https://www.delphipraxis.net/214002-...doconsole.html

* innerhalb der Engines die Consolen-Ausgabe umzuleiten, wie es z.B. Python4Delphi macht .... naja
* einmal müsste ich das dann jeweils in der aktuellen Scriptsprache machen, falls es dort überhaupt möglich ist, deren Ausgabefunktionen zu überschreiben
* also wäre schon eine allgemeine Umsetzung angebracht




Ach ja, meine ActiveX-Komponenten ConsoleScript.dll und PythonScript.dll
* sorry, mit dem ActiveX-Experten von Delphi bin ich noch nicht klargekommen (und die Tutorials/Videos ), also hab ich mir's erstmal selbsgemacht
* aktuell rufe ich sie direkt auf (SafeLoadLibrary+DllGetClassObject)
* SideBySide-Loading will ich noch ausprobieren
* registrieren sollten sie sich im Windows lassen, aber ob der Aufruf funktioniert oder noch was fehlt ... hab ich nicht getestet




So, und hier noch ein winziger nativer Ansatz:
https://stackoverflow.com/questions/...-from-within-c
[deleted] Müsste jemand das Script aber nochmal testen ... kann sein, dass SetScriptSite nötig ist und man sich noch ein kleines IActiveScriptSite basteln muß.
Miniaturansicht angehängter Grafiken
activescripting.png  
Angehängte Dateien
Dateityp: 7z ActiveScripting.7z (1,37 MB, 5x aufgerufen)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 5. Nov 2023 um 17:19 Uhr)
 
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#2
  Alt 5. Nov 2023, 17:16
Ach ja, alles natürlich auch für Win64.
Viele Beispiele im Internet funktionieren hier nicht, da zwar die Interfaces "gleich" sind, aber Viele eine andere GUID besitzen.

Auch muß beachtet werden, dass installierte Fremd-Sprachen in der jeweiligen Bittigkeit (oder Beides) installiert sein müssen. (zumindestens bei den In-Process-Servern)



So, und hier noch ein winziger nativer Ansatz:
https://stackoverflow.com/questions/...-from-within-c
Delphi-Quellcode:
uses
  System.SysUtils, System.Win.ComObj, System.Types, System.Variants,
  Winapi.ActiveX, h5u.ActiveScripting.Interfaces;

var
  ClassID: TGUID;
  Engine: IActiveScript;
  ASite: IActiveScriptSite;
  Parser: IActiveScriptParse;
  ErrInfo: EXCEPINFO;
  Flags: DWORD;
  OResult: OleVariant;
  Name: WideString;
  Disp: IDispatch;
  HR: HRESULT;
begin
  // https://stackoverflow.com/questions/7491868/how-to-load-call-a-vbscript-function-from-within-c

  //CoInitializeEx(nil, COINIT_MULTITHREADED);

  OleCheck(CLSIDFromProgID(PWideChar('VBScript'), ClassID));
  Engine := CreateComObject(ClassID) as IActiveScript;

  ASite := TDummyNonInteractiveScriptSite.Create; // ODER: ASite := TDummyActiveScriptSite.Create(Self.Handle)
  OleCheck(Engine.SetScriptSite(ASite));
  OleCheck(Engine.QueryInterface(IActiveScriptParse, Parser));
  OleCheck(Parser.InitNew);

  //OleCheck(Parser.AddScriptlet(nil, PWideChar('...'), nil, nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, Name, ErrInfo));
  {or}
  //OleCheck(Parser.ParseScriptText(PWideChar('...'), nil, nil, nil, 0, 0, ..., nil, ErrInfo));
  {or}
  //if Failed(Parser.ParseScriptText(PWideChar('...'), nil, nil, nil, 0, 0, ..., nil, ErrInfo)) then
  // raise Exception.CreateFmt('Error $%x: %s', [ErrInfo.scode, ErrInfo.bstrDescription]);
  {or}
  //HR := Parser.ParseScriptText(PWideChar('...'), nil, nil, nil, 0, 0, ..., nil, ErrInfo);
  //if Failed(HR) then
  // raise Exception.CreateFmt('Error $%x %s'#10'$%x: %s', [HR, SysErrorMessage(Cardinal(HR)), ErrInfo.scode, ErrInfo.bstrDescription]);

  //HR := Parser.ParseScriptText(PWideChar('WScript.Echo "abc"'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, @OResult, ErrInfo);
  HR := Parser.ParseScriptText(PWideChar('set fso = CreateObject("Scripting.FileSystemObject")'#10'set stream = fso.GetStandardStream(1)'#10
    + 'stream.WriteLine("This will go to standard output.")'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, @OResult, ErrInfo);
  if Failed(HR) then
    raise Exception.CreateFmt('Error $%x %s'#10'$%x: %s', [HR, SysErrorMessage(Cardinal(HR)), ErrInfo.scode, ErrInfo.bstrDescription]);

  HR := Parser.ParseScriptText(PWideChar('a = 123'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, @OResult, ErrInfo);
  if Failed(HR) then
    raise Exception.CreateFmt('Error $%x %s'#10'$%x: %s', [HR, SysErrorMessage(Cardinal(HR)), ErrInfo.scode, ErrInfo.bstrDescription]);
  //
  HR := Parser.ParseScriptText(PWideChar('a * 2 + 3'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISEXPRESSION, @OResult, ErrInfo);
  if Failed(HR) then
    raise Exception.CreateFmt('Error $%x %s'#10'$%x: %s', [HR, SysErrorMessage(Cardinal(HR)), ErrInfo.scode, ErrInfo.bstrDescription]);
  Writeln('Result = ' + VarToStrDef(OResult, '(NULL)'));
  //
  HR := Parser.ParseScriptText(PWideChar('MsgBox "Hello World! The current time is " & Now'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, @OResult, ErrInfo);
  if Failed(HR) then
    raise Exception.CreateFmt('Error $%x %s'#10'$%x: %s', [HR, SysErrorMessage(Cardinal(HR)), ErrInfo.scode, ErrInfo.bstrDescription]);

  // Engine.GetScriptDispatch(nil, Disp);

  //CoUninitialize;
end;
Müsste jemand das Script aber nochmal testen ... kann sein, dass SetScriptSite nötig ist und man sich noch ein kleines IActiveScriptSite basteln muß.
Ja, ein IActiveScriptSite muß bereitgestellt werden, aber die Funktionen können quasi leer sein (einfach nur überall Result jeweils mit S_OK, S_FALSE usw. beglücken)
Hab dafür zwei Dummy-Interfaces in die Interface-Unit gepackt und rechts noch Knöpfe "Native-API" in die Demo-/Testanwendung.

Sollen die Scripte auch Interaktiv sein dürfen, dann muß auch IActiveScriptSiteWindow implementiert sein (und OK sagen), sonst raucht es z.B. bei einem MsgBox "peng" mit einer Exception "Erlaubnis verweigert".

Geändert von himitsu ( 7. Nov 2023 um 07:09 Uhr)
  Mit Zitat antworten Zitat
TiGü

 
Delphi 10.4 Sydney
 
#3
  Alt 6. Nov 2023, 09:08
Bei mir kommt er bis zur Zeile 'a = 123' als Win64 Konsolenprogramm, dann steigt das Programm mit EOleSysError: Ungültiger Zeiger aus.

Delphi-Quellcode:
program ScriptingTest;

{$APPTYPE CONSOLE}

{$R *.res}


uses
    System.SysUtils,
    System.Win.ComObj,
    System.Types,
    System.Variants,
    Winapi.ActiveX,
    h5u.ActiveScripting.Interfaces;

procedure Main;
var
    ClassID: TGUID;
    Engine: IActiveScript;
    ASite: IActiveScriptSite;
    Parser: IActiveScriptParse;
    ErrInfo: EXCEPINFO;
    Flags: DWORD;
    OResult: OleVariant;
    Name: WideString;
    Disp: IDispatch;
    HR: HResult;
begin
    // https://stackoverflow.com/questions/7491868/how-to-load-call-a-vbscript-function-from-within-c

    OleCheck(CLSIDFromProgID(PWideChar('VBScript'), ClassID));
    Engine := CreateComObject(ClassID) as IActiveScript;

    ASite := TDummyNonInteractiveScriptSite.Create; // ODER: ASite := TDummyActiveScriptSite.Create(Self.Handle)
    OleCheck(Engine.SetScriptSite(ASite));
    OleCheck(Engine.QueryInterface(IActiveScriptParse, Parser));
    OleCheck(Parser.InitNew);

    OleCheck(Parser.ParseScriptText(PWideChar('WScript.Echo "abc"'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, nil, ErrInfo));
    //
    HR := Parser.AddScriptlet(nil, PWideChar('a = 123'), nil, nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, Name, ErrInfo);
    OleCheck(HR); // <---- EOleSysError: Ungültiger Zeiger
    OleCheck(Parser.ParseScriptText(PWideChar('a * 2 + 3'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISEXPRESSION, @OResult, ErrInfo));
    Writeln(VarToStrDef(OResult, '(NULL)'));
    //
    OleCheck(Parser.ParseScriptText(PWideChar('MsgBox "Hello World! The current time is " & Now'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE,
      nil, ErrInfo));

    // Engine.GetScriptDispatch(nil, Disp);
end;

begin
    try
        CoInitializeEx(nil, 0);
        try
            Main;
        finally
            CoUninitialize;
        end;
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
    Readln;
end.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#4
  Alt 6. Nov 2023, 20:07
32 Bit knallt auch.

Hmmmm, CoInitialize ist da ... daran liegt es nicht. (macht die VCL ja von selbst)

hier nur nochmal eine erweiterte Fehlerbehandlung.
Delphi-Quellcode:
  HR := Parser.AddScriptlet(nil, PChar('a = 123'), nil, nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, Name, ErrInfo);
  if Failed(HR) then
    raise Exception.CreateFmt('Error $%x %s'#10'$%x: %s', [HR, SysErrorMessage(Cardinal(HR)), ErrInfo.scode, ErrInfo.bstrDescription]);
// Cardinal, weil sonst die Bereichsprüfung knallt Integer<>Cardinal
// und die umgekehrte Variante von HResultFromWin32 auf die Schnelle nicht gefunden
Was mir beim Schreiben grade auffiel, dass ich AddScriptlet garnicht einzeln geteste hatte. (ist dort auskommentiert)

Und was noch komisch ist, dass das erste WScript.Echo ohne Fehler durch läuft.
Das müsste knallen, da WScript hier unbekannt sein sollte. und außerdem macht das Echo nicht -> nichts wird ins Konsolenfenster geschrieben.

Ansonsten ist es quasi fast der selbe Code, wie ich ihn gestern getestet hatte.
Delphi-Quellcode:
procedure TScriptingTestForm.btNativeExecuteClick(Sender: TObject);
var
  ClassID: TGUID;
  Engine: IActiveScript;
  ASite: IActiveScriptSite;
  Parser: IActiveScriptParse;
  ErrInfo: EXCEPINFO;
  Flags: DWORD;
  OResult: OleVariant;
  //Name: WideString;
  //Disp: IDispatch;
begin
  if Trim(edScriptlet.Text) = 'then begin
    cbScriptingEngine.Text := 'VBScript';
    edScriptlet.Text := 'MsgBox "Hello World! The current time is " & Now';
  end;

  // https://stackoverflow.com/questions/7491868/how-to-load-call-a-vbscript-function-from-within-c

  OleCheck(CLSIDFromProgID(PChar(ActiveScripting.ScriptingEngine), ClassID)); // e.q. 'VBScript'
  Engine := CreateComObject(ClassID) as IActiveScript;

  if cbNativeInteractiv.Checked then
    ASite := TDummyActiveScriptSite.Create(Self.Handle)
  else
    ASite := TDummyNonInteractiveScriptSite.Create;
  OleCheck(Engine.SetScriptSite(ASite));
  OleCheck(Engine.QueryInterface(IActiveScriptParse, Parser));
  OleCheck(Parser.InitNew);

  //OleCheck(Parser.ParseScriptText(PChar('WScript.Echo "abc"'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, nil, ErrInfo));
  //
  //OleCheck(Parser.AddScriptlet(nil, PChar('a = 123'), nil, nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, Name, ErrInfo));
  //OleCheck(Parser.ParseScriptText(PChar('a * 2 + 3'), nil, nil, nil, 0, 0, SCRIPTTEXT_ISEXPRESSION, @OResult, ErrInfo));
  //ShowMessage(VarToStrDef(OResult, '(NULL)'));
  OleCheck(Parser.ParseScriptText(PChar(edScriptletInit.Text), nil, nil, nil, 0, 0, SCRIPTTEXT_ISVISIBLE, nil, ErrInfo));
  Flags := IfThen(Sender = btNativeExpression, SCRIPTTEXT_ISEXPRESSION, 0) or SCRIPTTEXT_ISVISIBLE;
  if Failed(Parser.ParseScriptText(PChar(edScriptlet.Text), nil, nil, nil, 0, 0, Flags, @OResult, ErrInfo)) then
    raise Exception.CreateFmt('Error $%x: %s', [ErrInfo.scode, ErrInfo.bstrDescription]);
  edResult.Text := VarToStrDef(OResult, '(NULL)');

  //Engine.GetScriptDispatch(nil, Disp);
end;
Komm grade aus der Sauna und entspanne mich erstmal (viele Grüße von der EKON) ... schau später, ob ich den Fehler finde.

Geändert von himitsu ( 6. Nov 2023 um 20:09 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#5
  Alt 7. Nov 2023, 07:06
Es knallt nicht nur im VBScript, sondern auch beim JScript.

Die Signatur sieht aber OK aus.
https://learn.microsoft.com/en-us/do...4.addscriptlet
https://embedded.vbsedit.com/active/006/001.asp
https://www.jb51.net/shouce/script56...eScriptParse__
https://www.jb51.net/shouce/script56...ml/engines.htm

Obwohl ich denke, dass ItemName und EventName leer sein können, auch gefüllt versucht, aber nee.

Mir fiel auf, dass ich beim ersten Testcode das AddScriptlet drin hatte, es aber dennoch nie benutzt wurde, auch nicht in den wenigen, inzwischen angesammelten, TestCodes war es nicht drin.
Und ich fand im Internet auch praktisch nichts, wo es genutzt wird.



hmmmmmmm ..... booaaaarrrrr .... jaaaaa .....
Aktuell keine Ahnung, aber mit ParseScriptText ist ja erstmal alles so weit nutzbar.
Beispiel in #2 aktualisiert, sowie siehe Anhang.
Angehängte Dateien
Dateityp: dpr ScriptingConsole.dpr (3,3 KB, 2x aufgerufen)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:47 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz