DLL FMXInno: Hidden Features Revealed

BLACKFIRE69

Новичок
1) Today, I unlock the feature 'Runtime Scripts' for FMXInno for general use.

So, what are 'Runtime Scripts'? They are scripts that run at runtime without needing to be compiled at compile-time. This means that once you compile your Setup, you don't need to recompile it to apply changes made in 'Runtime Scripts'.

Enough explanations, let's dive into a simple example:

Here, I use the file extension '.fxs' for Runtime Scripts, but you can use whatever you want: '.pas', '.iss', '.txt', etc.

Форматирование (BB-код):
   Test_1.fxs
-------------------------------------------
program Test1CreateRect;   // This line is optional, so you can get rid of it.

var ARect: FRectangle;

procedure CleanUpRect;
begin
  ARect := nil;
end; 

begin
  ARect := InitRectangleHandle;
  ARect.FCreate(FMXFormHandle);
  ARect.SetBounds(200, 90, 250, 250);
  ARect.FillColor(ALRed);

  AExternalObj := ARect.Handle;
end.
Форматирование (BB-код):
   Example.iss
-------------------------------------------
var
  ARuntimeScript: FRuntimeScript;
  FirstRun: Boolean;
  AExternalObj: TFMXObject;
 
procedure ABtnOnClick(Sender: TObject);
begin
  if not FirstRun then    
  begin
      // Get the handle of the external object that was created with the external script.
    AExternalObj := ARuntimeScript.GetRegisteredLongIntVar('AExternalObj');
      // Call for cleanup.
    ARuntimeScript.CallProcFromScriptNoVar('CleanUpRect');
      // Remove the external object from FMXForm as well.
    FMXForm.RemoveObject(AExternalObj);
  end;

  ARuntimeScript.CompileAndRun;
  FirstRun := False;
end;
Форматирование (BB-код):
procedure InitializeWizard();
begin
  {FMX Form}
  FMXForm.FCreateFluent(WizardForm.Handle, False, False, 0.96, 0);

  {ABtn}
  ABtn.FCreate(FMXForm.Handle);
  ABtn.Text('&Run');
  ABtn.OnClick(@ABtnOnClick);

  {ARuntimeScript}
  ARuntimeScript.FCreate(ExpandConstant('{src}\_Scripts\Test_1.fxs'));
  ARuntimeScript.RegisterLongIntConst('FMXFormHandle', FMXForm.Handle);
  ARuntimeScript.RegisterLongIntVar('AExternalObj', 0); 
end;
1. This example will create a Rectangle (ARect1: FRectangle) at runtime, while the Setup is running.
2. While the Setup is running, make some changes to the Runtime Script and smash the 'Run' button to see the changes.
Форматирование (BB-код):
ARect.FillColor(ALGreen);  // ARect.FillColor(ALRed);
3. Try creating a similar object (ARect2) by following the 'ARect1' code. Once you save the file, click the 'Run' button.
Форматирование (BB-код):
var ARect, ARect2: FRectangle; 
 
begin
  ARect := InitRectangleHandle;
  ARect.FCreate(FMXFormHandle);
  ARect.SetBounds(80, 90, 200, 200);
  ARect.FillColor(ALRed);
 
  ARect2 := InitRectangleHandle;
  ARect2.FCreate(FMXFormHandle);
  ARect2.SetBounds(360, 90, 200, 200);
  ARect2.FillColor(ALBlue);
  ...
end .


* FMXInno has supported runtime scripts for quite a while with 'Lua'. Some may not be familiar with 'Lua', so i didn't promote it. On the other hand, 'FRuntimeScript' is Pascal, so everyone who uses InnoSetup can use this without any doubt.


[*] Built-In Features / Functions / Constants / Variables:

1. 'Runtime Scripts' has built-in support for FMXInno classes, so you can use them inside 'Runtime Scripts'.​
-- Currently, it only supports the 'FMX_Standard', 'FMX_Shapes', 'FMX_Additional', 'FMX_Layouts', and 'FMX_Effects' classes. because i'm too lazy to add all the classes at the moment. but in the future.​

2. 'Runtime Scripts' are not literally InnoSetup, so functions like "ExpandConstant" and "ExtractTemporaryFile" used in InnoSetup can't be used in runtime scripts.​
-- However, I've added some extra useful functions by default from 'System.SysUtils', 'System.Math', 'Winapi.Windows', etc., and you'll find them in the 'BuiltIn Features.txt' file.​

3. Added default variable 'Application: TApplication', so you can now use 'Application.ProcessMessages;' inside the runtime scripts.​


[*] Register Custom Types:

Форматирование (BB-код):
 Example.iss
-------------------------------------------
  ARuntimeScript.RegisterType('TDummyRec', 'record' +#13#10+
                                            ' PosX: Integer;' +#13#10+
                                            ' PosY: Integer;' +#13#10+
                                            'end;');

  ARuntimeScript.RegisterType('TsNum', 'Single');
 
 Test_1.fxs
------------------------------------------- 
var
  Shipping Fees: TsNum;
  ADummyRec: TDummyRec;

[*] Load External Libraries (DLLs):

You can call external DLLs inside runtime scripts in three different ways,

-- Supported flags: 'stdcall' , 'cdecl' , and 'delayload' .


1. System Libs:​
Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
function KillTimer(handle: HWND; TimerId: LongWord): boolean;
  external 'KillTimer@user32.dll stdcall';

2. Libs from custom path:​
Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
procedure MyDllFunc(hWnd: Integer);
  external 'MyDllFunc@"C:\Test\Libs\MyDll.dll" stdcall';

3. I've added three special constants to runtime scripts, but you need to define them manually first.​

a. 'Src':​
Форматирование (BB-код):
 Example.iss
-------------------------------------------
ARuntimeScript.RegisterSpecialSrcConst(ExpandConstant('{src}'));


 Test_1.fxs
-------------------------------------------
procedure MyDllFunc(hWnd: Integer);
  external 'MyDllFunc@"{src}\MyDll.dll" stdcall';

b. 'App':​
Форматирование (BB-код):
 Example.iss
-------------------------------------------
ARuntimeScript.RegisterSpecialAppConst(ExpandConstant('{src}\_ExtrnlDll'));


 Test_1.fxs
-------------------------------------------
procedure MyDllFunc(hWnd: Integer);
  external 'MyDllFunc@"{app}\MyDll.dll" stdcall';

c. 'Tmp':​
Форматирование (BB-код):
 Example.iss
-------------------------------------------
ARuntimeScript.RegisterSpecialAppConst(ExpandConstant('{src}\_ExtrnlDll'));


 Test_1.fxs
-------------------------------------------
procedure MyDllFunc(hWnd: Integer);
  external 'MyDllFunc@"{tmp}\MyDll.dll" stdcall';

d. You can also use 'files:' to define the path.​
Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
procedure MyDllFunc(hWnd: Integer);
  external 'MyDllFunc@"files:MyDll.dll" stdcall';
  • In runtime scripts, 'files:' is equal to 'Tmp'.
  • It doesn't extract the Lib to the 'Tmp' directory as InnoSetup does.

e. Added built-in support for 'CreateCallback' function.​
Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
  SetTimer(0, 0, 250, CreateCallback(@TimerProc1));


[*] Call a function/procedure declared in Runtime Scripts through InnoSetup:

There are two ways to call a function/procedure declared in Runtime Scripts via InnoSetup.

1. Without Parameters:​
Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
procedure SayHi;
begin
  ShowMessage('Hi, I am from the Runtime Script!');
end; 

 Example.iss
-------------------------------------------
  ARuntimeScript.CallProcFromScriptNoVar('SayHi');

2. With Parameters:​
-- Here you have to use FNewArray for Parameters.​
Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
procedure CalAddition(const x, y: Integer);
begin
  MyMathResult := x + y; 
end;

 Example.iss
-------------------------------------------
var
  AParams: FNewArray;
 
  {AParams}
  AParams.FCreate;
  AParams.AddInteger(32);
  AParams.AddInteger(37);
  ARuntimeScript.CallProcFromScript('CalAddition', AParams);

[*] Register InnoSetup's function/procedure and use them in Runtime Script:

You can register functions/procedures for Runtime Scripts that have been declared in the InnoSetup (.iss).
1. At the moment, it doesn't accept any parameters.
2. You have to use the Callback function.

Форматирование (BB-код):
 Example.iss
-------------------------------------------
type
  TDummyFunc2 = function: Integer;

function XWrapNoVarFuncNew(Callback: TDummyFunc2): Longword;
  external 'XWrapNoVar@files:FMXInno.dll stdcall delayload';

function GetValueFromInnoSetup: Integer;
begin
  Result := 69;
end;

procedure InnoMsgProc;
var
  LNum: Longint;
begin
  MsgBox('Hi', mbInformation, MB_OK);
end;

ARuntimeScript.RegisterProcNoVar(XWrapNoVarProc(@InnoMsgProc), 'procedure InnoMsgProc;');
ARuntimeScript.RegisterProcNoVar(XWrapNoVarFuncNew(@GetValueFromInnoSetup), 'function GetValueFromInnoSetup: Integer;');
Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
program Test7RegisterProc;

var
  LuckyNum: Integer;

procedure DoIt;
begin
  InnoMsgProc();
end; 

begin
  LuckyNum := GetValueFromInnoSetup();
  DoIt;
end.


[*] PreProcessor and Include Files:

Runtime scripts support preprocessors and include files.

Форматирование (BB-код):
 Test_1.fxs
-------------------------------------------
program Test10aIncludeFiles; // This line is optional, so you can get rid of it.

{$DEFINE WHO_ARE_YOU}

{$I ".\_Scripts\Test_10b.fxs"}

var
  S: String;

begin
{$IFDEF WHO_ARE_YOU}
  S := 'Mr. BLACKFIRE';
{$ELSE}
  S := 'Mr/Ms/Mrs. Nobody';
{$ENDIF}

  SayHi(S);
end.


[*] Syntax Highlighting in the Text Editor:

Open the '.fxs' file in your favorite text editor or IDE and select the file syntax as 'Pascal'. Now you're good to go.





00.gif





01.gif




02.gif




03.gif




x.png




y.png




z.png
 

Вложения

Сверху