|
Antwort |
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. IronPython) 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 ActivePython 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ß.
$2B or not $2B
Geändert von himitsu ( 5. Nov 2023 um 18:19 Uhr) |
Delphi 12 Athens |
#2
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:
Müsste jemand das Script aber nochmal testen ... kann sein, dass SetScriptSite nötig ist und man sich noch ein kleines IActiveScriptSite basteln muß.
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; 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 08:09 Uhr) |
Zitat |
Delphi 10.4 Sydney |
#3
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. |
Zitat |
Delphi 12 Athens |
#4
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:
Was mir beim Schreiben grade auffiel, dass ich AddScriptlet garnicht einzeln geteste hatte. (ist dort auskommentiert)
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 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:
Komm grade aus der Sauna und entspanne mich erstmal (viele Grüße von der EKON) ... schau später, ob ich den Fehler finde.
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; Geändert von himitsu ( 6. Nov 2023 um 21:09 Uhr) |
Zitat |
Delphi 12 Athens |
#5
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. |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |