Files
Michael Schimmel 45ff69fd92 Code-Formatting
2025-07-12 17:10:01 +02:00

315 lines
10 KiB
ObjectPascal

unit MainUnit;
interface
uses
System.SysUtils,
System.Types,
System.UITypes,
System.Classes,
System.Variants,
FMX.Types,
FMX.Controls,
FMX.Forms,
FMX.Graphics,
FMX.Dialogs,
FMX.Controls.Presentation,
FMX.StdCtrls,
FMX.WebBrowser,
Winapi.WebView2,
FMX.Memo.Types,
FMX.ScrollBox,
FMX.Memo,
FMX.Edit,
FMX.StdActns,
// FMX.Edit für TEdit, FMX.StdActns oft für Standardaktionen
// Korrekte und vollständige Units
System.IOUtils,
System.Threading,
System.Diagnostics,
Winapi.Windows,
LLVM.Runner;
const
// Pfad zur HTML-Datei (BITTE HIER ANPASSEN!)
PATH_BLOCKLY = 'T:\Myc\Blockly\index.html'; // <--- PRÜFEN UND ANPASSEN!
// Pfade zu den LLVM-Werkzeugen (BITTE HIER ANPASSEN!)
CLANG_PATH = 'clang.exe'; // <--- PRÜFEN UND ANPASSEN!
LLD_PATH = 'lld-link.exe'; // <--- PRÜFEN UND ANPASSEN!
type
TMainForm = class(TForm)
WebBrowser1: TWebBrowser;
SaveWorkspaceButton: TSpeedButton;
GenerateCodeButton: TSpeedButton;
Memo: TMemo;
InputEdit: TEdit; // <--- Hinzugefügt (Optional für Beschriftung des InputEdit)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure RefreshButtonClick(Sender: TObject);
procedure SaveWorkspaceButtonClick(Sender: TObject);
procedure GenerateCodeButtonClick(Sender: TObject);
procedure WebBrowser1DidFinishLoad(ASender: TObject);
private
{ Private declarations }
FWebView: ICoreWebView2;
FWebMessageReceiver: ICoreWebView2WebMessageReceivedEventHandler;
FWebMessageReceivedToken: EventRegistrationToken;
procedure HandleWebMessage(const AMessage: string);
function ExecuteProcess(const ACommand: string; const AParameters: string): string;
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.fmx}
type
TWebMessageReceiver = class(TInterfacedObject, ICoreWebView2WebMessageReceivedEventHandler)
private
FOwner: TMainForm;
public
constructor Create(AOwner: TMainForm);
function Invoke(const Sender: ICoreWebView2; const args: ICoreWebView2WebMessageReceivedEventArgs): HResult; stdcall;
end;
constructor TWebMessageReceiver.Create(AOwner: TMainForm);
begin
inherited Create;
FOwner := AOwner;
end;
function TWebMessageReceiver.Invoke(const Sender: ICoreWebView2; const args: ICoreWebView2WebMessageReceivedEventArgs): HResult;
var
message: PWideChar;
begin
Result := args.TryGetWebMessageAsString(message);
if Succeeded(Result) then
begin
TThread.Queue(nil, procedure begin FOwner.HandleWebMessage(string(message)); end);
end;
Result := S_OK;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
TLLVMRunner.Log := Memo.Lines;
// Optional: Standardwert für InputEdit
InputEdit.Text := '123';
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
TLLVMRunner.Log := nil;
if (FWebView <> nil) and (FWebMessageReceivedToken.value <> 0) then
begin
FWebView.remove_WebMessageReceived(FWebMessageReceivedToken);
end;
end;
function TMainForm.ExecuteProcess(const ACommand: string; const AParameters: string): string;
var
sa: TSecurityAttributes;
si: TStartupInfo;
pi: TProcessInformation;
stdOutRead, stdOutWrite: THandle;
success: Boolean;
cmdLine: string;
buffer: TBytes;
bytesRead: Cardinal;
output, errors: string;
begin
// Pipe für StdOut und StdErr erstellen
sa.nLength := SizeOf(TSecurityAttributes);
sa.lpSecurityDescriptor := nil;
sa.bInheritHandle := True;
// Für stdout und stderr wird dieselbe Pipe verwendet, da clang Fehler auf stdout ausgibt
if not CreatePipe(stdOutRead, stdOutWrite, @sa, 0) then
Exit('Error creating pipe.');
try
// StartupInfo vorbereiten
FillChar(si, SizeOf(TStartupInfo), 0);
si.cb := SizeOf(TStartupInfo);
si.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
si.wShowWindow := SW_HIDE; // Fenster explizit verstecken
si.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput := stdOutWrite;
si.hStdError := stdOutWrite; // Leite stderr auf dieselbe Pipe wie stdout
cmdLine := Format('"%s" %s', [ACommand, AParameters]);
success := CreateProcess(nil, PChar(cmdLine), nil, nil, True, CREATE_NO_WINDOW, nil, nil, si, pi);
// Schreib-Handle der Pipe sofort schließen
CloseHandle(stdOutWrite);
if not success then
Exit(Format('CreateProcess failed. Code: %d', [GetLastError]));
try
output := '';
// Warten, bis der Prozess fertig ist und alle Daten in die Pipe geschrieben hat
if WaitForSingleObject(pi.hProcess, 5000) = WAIT_TIMEOUT then // 5s Timeout
begin
TerminateProcess(pi.hProcess, 1);
Exit('Process timed out.');
end;
// Bytes aus der Pipe lesen
repeat
SetLength(buffer, 1024);
bytesRead := 0;
if ReadFile(stdOutRead, buffer[0], Length(buffer), bytesRead, nil) and (bytesRead > 0) then
begin
SetLength(buffer, bytesRead);
// Gelesene Bytes mit dem Default-System-Encoding in einen String umwandeln
output := output + TEncoding.Default.GetString(buffer);
end
else
begin
break; // Pipe ist leer oder Fehler
end;
until False;
finally
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
end;
Result := output;
finally
CloseHandle(stdOutRead);
end;
end;
procedure TMainForm.RefreshButtonClick(Sender: TObject);
begin
WebBrowser1.Navigate(PATH_BLOCKLY);
end;
procedure TMainForm.SaveWorkspaceButtonClick(Sender: TObject);
begin
WebBrowser1.EvaluateJavaScript('saveWorkspace()');
end;
procedure TMainForm.GenerateCodeButtonClick(Sender: TObject);
begin
WebBrowser1.EvaluateJavaScript('generateAndPostCode()');
end;
procedure TMainForm.HandleWebMessage(const AMessage: string);
var
llFile, objFile, dllFile: string;
compilerOutput: string;
success: Boolean;
InputInteger: Integer; // <--- Hinzugefügt
begin
Memo.Lines.Clear;
Memo.Lines.Add('LLVM-Code empfangen. Starte Kompilierung...');
Memo.Lines.Add(AMessage);
Memo.Lines.Add('--------------------');
// Wert aus dem InputEdit-Feld holen
try
InputInteger := StrToIntDef(InputEdit.Text, 0); // Standardwert 0, falls ungültig
except
InputInteger := 0;
Memo.Lines.Add('WARNUNG: Ungültige Eingabe im InputEdit-Feld. Verwende 0.');
end;
TTask.Run(
procedure
var
llFileLocal, objFileLocal, dllFileLocal: string; // Lokale Variablen für den Task
compilerOutputLocal: string;
successLocal: Boolean;
begin
llFileLocal := TPath.Combine(TPath.GetTempPath, 'poc.ll');
objFileLocal := TPath.ChangeExtension(llFileLocal, '.obj');
dllFileLocal := TPath.ChangeExtension(llFileLocal, '.dll');
successLocal := False;
try
TFile.WriteAllText(llFileLocal, AMessage);
TThread.Queue(nil, procedure begin Memo.Lines.Add('Kompiliere zu Objektdatei...'); end);
compilerOutputLocal := ExecuteProcess(CLANG_PATH, Format('-c "%s" -o "%s"', [llFileLocal, objFileLocal]));
TThread.Queue(nil, procedure begin Memo.Lines.Add(compilerOutputLocal); end);
if not TFile.Exists(objFileLocal) then
begin
TThread
.Queue(nil, procedure begin Memo.Lines.Add('FEHLER: Kompilierung fehlgeschlagen. .obj-Datei nicht erstellt.'); end);
Exit;
end;
TThread.Queue(nil, procedure begin Memo.Lines.Add('Linke zu DLL...'); end);
compilerOutputLocal := ExecuteProcess(LLD_PATH, Format('/dll /noentry "%s" /out:"%s"', [objFileLocal, dllFileLocal]));
TThread.Queue(nil, procedure begin Memo.Lines.Add(compilerOutputLocal); end);
if TFile.Exists(dllFileLocal) then
begin
successLocal := True;
TThread.Queue(nil, procedure begin Memo.Lines.Add(Format('ERFOLG: DLL wurde erstellt: %s', [dllFileLocal])); end);
end
else
begin
TThread.Queue(nil, procedure begin Memo.Lines.Add('FEHLER: Linken fehlgeschlagen. .dll-Datei nicht erstellt.'); end);
end;
finally
if TFile.Exists(llFileLocal) then
TFile.Delete(llFileLocal);
if TFile.Exists(objFileLocal) then
TFile.Delete(objFileLocal);
if not successLocal and TFile.Exists(dllFileLocal) then
TFile.Delete(dllFileLocal);
end;
TThread.Queue(
nil,
procedure
begin
Memo.Lines.Add('---------------------------------------------------------');
Memo.Lines.Add('DLL wird aufgerufen:');
if TFile.Exists(dllFileLocal) then
begin
var Runner := TLLVMRunner.Create(dllFileLocal);
try
Runner.Execute(InputInteger); // <--- HIER DEN INPUT-PARAMETER ÜBERGEBEN
finally
Runner.Free;
end;
end;
Memo.Lines.Add('DLL beendet.');
Memo.CaretPosition := TCaretPosition.Create(Memo.Lines.Count - 1, 1);
end
);
end
);
end;
procedure TMainForm.WebBrowser1DidFinishLoad(ASender: TObject);
begin
if Assigned(FWebMessageReceiver) then
Exit;
if Supports(WebBrowser1, ICoreWebView2, FWebView) then
begin
FWebMessageReceiver := TWebMessageReceiver.Create(Self);
FWebView.add_WebMessageReceived(FWebMessageReceiver, FWebMessageReceivedToken);
end;
end;
end.