SRL Archive - OSR Advanced Scripting Tutorials

How to make plugins for SCAR (Delphi)


Cazax

2009-01-30 08:01:17

First of all, you need delphi 7(If you don't have it look at EvilChicken's sig) and basic delphi knowledge.

Open Delphi.

Now we start creating the plugin:

Select Dll Wizard:

You will see this:

In uses, add:
  FastShareMem,
SysUtils,
Classes,
Windows,
Graphics;

Now, add your functions.
Function example:
Function MiddleBox(X1, Y1, X2, Y2 : Integer): TPoint; stdcall;
Begin
Result.X := (X1 + X2) Shr 1;
Result.Y := (Y1 + Y2) Shr 1;
End;

procedure example:
Procedure MiddleBox(X1, Y1, X2, Y2 : Integer; var TP : TPoint) stdcall;
Begin
TP.X := (X1 + X2) Shr 1;
TP.Y := (Y1 + Y2) Shr 1;
End;

If you need to call functions from SCAR(like Writeln), declare a variable:
Type
TSCARPlugFunc = record
Name: string;
Ptr: Pointer;
end;

TWriteln = procedure(s : string);
var
Writeln : TWriteln;


and how to fill in Writeln:
procedure SetFunctions(Funcs: array of TSCARPlugFunc); stdcall;
var
i: Integer;
begin
for i := 0 to Length(Funcs) - 1 do
if Funcs[i].Name = 'Writeln' then
Writeln := Funcs[i].Ptr;
end;
Then in your functions you can call Writeln. Remember there are only few function you can call from SCAR. You can check them at Plugins/Accessable SCAR Functions.
So, if you need color finding related functions, you will have to use the handle of the client and search each pixel. Example:
Function BlackPixelsInMS(DC : Cardinal): Integer; Stdcall;
Var
Canvas : TCanvas;
I, J : Integer;
Begin
Result := 0;
Canvas := TCanvas.Create;
Canvas.Handle := DC;
For I := 4 to 516 Do
For J := 4 to 338 Do
If Canvas.Pixels[I, J] = ClBlack Then
Inc(Result);
Canvas.Free;
End;

Using types from the plugin:
Type
TExample = Record
ExampleName : String;
ExampleID : Integer;
End;


Function GetExample: TExample; Stdcall;
Begin
Result.ExampleName := 'Tutorial';
Result.ExampleID := 1;
End;


Now, that you have your functions, we have to export them.

First function:
function GetFunctionCount(): Integer; stdcall; export;
begin
Result := 2;
end;
Change this to the number of functions you are exporting. In this case, 2;(Function MiddleBox and blackPixelsInMS).

Second function:
function GetFunctionInfo(x: Integer; var ProcAddr: Pointer; var ProcDef: PChar): Integer; stdcall;
begin
case x of
0:
begin
ProcAddr := @MiddleBox;
StrPCopy(ProcDef, 'function MiddleBox(X1, Y1, X2, Y2 : Integer): TPoint;');
end;
1:
begin
ProcAddr := @blackPixelsInMS;
StrPCopy(ProcDef, 'function blackPixelsInMS(DC : Cardinal): Integer;');
end;
else
x := -1;
end;
Result := x;
end;
x cases are the number of functions you are exporting starting from 0. ProcAddr is your function. Change the string in StrPCopy to your function's name (example function blackPixelsInMS(DC : Cardinal): Integer;).

third function:
function GetTypeCount(): Integer; stdcall; export;
begin
Result := 1;
end;
Change this to number of types you are exporting. In this case 1(TExample).

fourth function:
function GetTypeInfo(x: Integer; var sType, sTypeDef: string): Integer; stdcall;
begin
case x of
0:
begin
sType := 'TExample';
sTypeDef := 'record ExampleName : string; ExampleID : Integer; End;';
end;
else
x := -1;
end;
Result := x;
end;
x cases = number of types
sType = type's name
sTypeDef = what does the type have (example : record ExampleName : string; ExampleID : Integer; End;).


These are all the functions. How would your plugin will look like?:
library CazaxPlugin;


uses
FastShareMem,
SysUtils,
Classes,
Windows,
Graphics;

{$R *.res}


Function MiddleBox(X1, Y1, X2, Y2 : Integer): TPoint; stdcall;
Begin
Result.X := (X1 + X2) Shr 1;
Result.Y := (Y1 + Y2) Shr 1;
End;

Function BlackPixelsInMS(DC : Cardinal): Integer; Stdcall;
Var
Canvas : TCanvas;
I, J : Integer;
Begin
Result := 0;
Canvas := TCanvas.Create;
Canvas.Handle := DC;
For I := 4 to 516 Do
For J := 4 to 338 Do
If Canvas.Pixels[I, J] = ClBlack Then
Inc(Result);
Canvas.Free;
End;

function GetFunctionCount(): Integer; stdcall; export;
begin
Result := 2;
end;

function GetFunctionInfo(x: Integer; var ProcAddr: Pointer; var ProcDef: PChar): Integer; stdcall;
begin
case x of
0:
begin
ProcAddr := @MiddleBox;
StrPCopy(ProcDef, 'function MiddleBox(X1, Y1, X2, Y2 : Integer): TPoint;');
end;
1:
begin
ProcAddr := @blackPixelsInMS;
StrPCopy(ProcDef, 'function blackPixelsInMS(DC : Cardinal): Integer;');
end;
else
x := -1;
end;
Result := x;
end;

exports GetFunctionCount;
exports GetFunctionInfo;

end.


Finally, compiling it to a .Dll:

Save the project in plugins folder.

Press run.

You will get this:


But look at the plugins folder, there it is!:

Iroki

2009-01-30 08:22:18

Why you are exporting your functions?? Functions should works without exporting :)

btw, very good toturial :)

EvilChicken!

2009-01-30 08:25:49

I like this tutorial way more than the other one.
Well explained!

5 stars, rep+! :)

Baked0420

2009-01-30 08:31:41

wow nice, I been wondering how to make plugins, I was going to try to do it in C++ though, but I'll try this out also for now. Thanks for the tut. Rep+

Cazax

2009-01-30 09:12:24

From: manfromczech
Why you are exporting your functions?? Functions should works without exporting :)

btw, very good toturial :)

You are right, I removed that.



Thanks to everyone :)

Gu3st...

2009-01-30 10:05:25

Woah, cool! I am sure "almost" will find use for this!!
Thank you ;P

Dervish

2009-01-30 11:05:15

1 question : Why is it better to have DLL's than SCAR Includes ? :)

Cazax

2009-01-30 11:30:14

From: Dr D. Dervish
1 question : Why is it better to have DLL's than SCAR Includes ? :)

Functions and procedure will load when SCAR is initialized, not when you run the script. That makes them faster. And Dlls are closed source.

Naum

2009-01-30 12:29:33

Also you can do many things in delphi which you cannot do in SCAR :)

Baked0420

2009-02-02 06:44:50

and those things that you cannot do in scar can still be transfered over through a dll to be possible to do in scar? that's pretty cool, could you give an example of what Delphi can do that Scar cannot, something useful. I might learn Delphi and try to make some plugins if there's good enough Procedures/Functions to make that Scar can't.

Bad Processor

2009-02-03 12:04:00

Hey, looking good and working! My plugin was made, just won't load into SCAR. Nevermind. :(

Anyway, would this work with any API-like \ stdcall .dll file, for eg. C++? Because that means I could create Plugins using VB*.

Thanks.

*Yes, I know by default you can't create a standard DLL in VB, but I downloaded a thing of the net where you can make them.

– BP

Cazax

2009-02-03 12:08:37

From: Baked0420
and those things that you cannot do in scar can still be transfered over through a dll to be possible to do in scar? that's pretty cool, could you give an example of what Delphi can do that Scar cannot, something useful. I might learn Delphi and try to make some plugins if there's good enough Procedures/Functions to make that Scar can't.

Delphi is full of functions that aren't in SCAR. For example, CMYK functions. Also I think you can edit Read-only properties with Dlls. Not sure.

@BadProcessor: I don't know about that.

mormonman

2009-02-03 16:06:40

so stuff like this would help autocoloring?
http://delphi.about.com/od/delphitips2007/qt/rgb_cmyk.htm

Cazax

2009-02-03 16:11:12

You could also make them in SCAR, but from dlls would be faster. So yes :)

bullzeye95

2009-02-03 17:57:19

From: Baked0420
could you give an example of what Delphi can do that Scar cannot, something useful.


Delphi has access to the whole WinAPI, so it can pretty much do anything you want to do. Also, it allows for custom ASM code, if you are making something that needs to be as fast as possible (even though coding something in Delphi gives a huge speed boost over SCAR anyway).

SCAR actually has access to the whole WinAPI too, but it's kinda a pain in the ass to use.

The_Shermanator

2009-02-03 21:24:50

Goodjob I've been wanting to know how to do this for a while.

-The_Shermanator :garfield:

NiCbaZ

2009-02-04 01:03:41

From: Cazax
Functions and procedure will load when SCAR is initialized, not when you run the script. That makes them faster. And Dlls are closed source.


Not only that, you can use the full Delphi features in your DLL.

Also say if i was making a form ( plugin) and loaded all the textBoxes into a record like


TPluginPlayers = Record
Name: String;
// etc

T2DPluginPlayer = Array of TPluginPlayers



and then load TPluginPlayers through scar to get the names for declare players etc….

i tryed them but i get runtime errors when trying to acsess thoose TextBoxes through scar…

Helps, i know this can work because it is done in the SMM

ZaSz

2009-02-04 01:16:42

So with a plugin the function StrToDateTime (delphi) would work when i call it in SCAR?

edit: meant scar

NiCbaZ

2009-02-04 02:45:51

From: zasz
So with a plugin the function StrToDateTime (delphi) would work when i call it in smart?


What has SMART got to do with calling a function from a plugin?

ZaSz

2009-02-04 02:46:40

oops meant to say scar, smart was on my mind lol