Freddy1990
2011-08-04 09:57:24
I've finished the base for the SCAR 4 plugin system, it's already pretty functional. I've completely changed the design in comparison to the Divi plugin system to hopefully result in a far more flexible system. Also I've tried to make it more compatible with C++ by trying not to use any Delphi specific stuff.
Here's an example for a Delphi plugin:
I've also created a c++ example with Visual Studio:
I know the naming conventions in the c++ example are horrible, but I wanted to keep the plugin as similar to the delphi one as possible for the example. Feel free to rename stuff to your liking :) As long as you don't rename LoadPlugin, UnloadPlugin and DoExport of course :p
Both of these plugins can be ran with this sample script:
You can find all of the files for the delphi and c++ projects on here:
http://svn.scar-divi.com/titan_plugin/
The latest copy of SCAR 4 can be downloaded here:
http://svn.scar-divi.com/titan/
As for c++ support, there's some stuff that just might not be compatible with Delphi, so you may not be able to do everything in c++ you can with the Delphi plugin, but I'm trying to keep as much compatible as possible. I haven't succeeded in for example passing structs by value to a script from a function, maybe that's just because my c++ skills aren't as good as my Delphi ones, so if anyone can figure that out, let me know. In the example I've used a pointer to the struct to achieve the same thing. Note that this method is unsafe, the local struct var will be destroyed, that's why i'm copying the contents by value to a variable in the script, it prevents an error, using the pointer will probably not be an option.
EDIT: SCAR 4 will also feature a separated GUI plugin system btw, but I have more important things to focus on first.
Here's an example for a Delphi plugin:
library SamplePlugin;
uses
TitanPlugin in 'TitanPlugin.pas';
{$R *.res}
type
PTest = ^TTest;
TTest = record
a, b: Integer;
end;
function TestStdCall(i: Integer): Integer; stdcall;
begin
Result := i;
end;
function TestCDecl(i: Integer): Integer; cdecl;
begin
Result := i;
end;
function MakeTest(a, b: Integer): TTest;
begin
Result.a := a;
Result.b := b;
end;
// --
function LoadPlugin(VMajor, VMinor: Integer): Boolean; stdcall;
begin
Result := (VMajor = 4) and (VMinor >= 0);
end;
function UnloadPlugin: Boolean; stdcall;
begin
Result := True;
end;
procedure DoExport(Engine: Integer; EExport: PEExport; ELib: PELib); stdcall;
var
n, t: Integer;
begin
EExport^.RegisterDirectiveA(Engine, 'TEST_DELPHI');
n := EExport^.RegisterNamespaceW(Engine, 'Test');
EExport^.RegisterHeaderW(Engine, n, 'function TestStdCall(i: Integer): Integer; stdcall;', @TestStdCall);
EExport^.RegisterHeaderW(Engine, n, 'function TestCDecl(i: Integer): Integer; cdecl;', @TestCDecl);
t := EExport^.RegisterTypeA(Engine, n, 'TTest = record a, b: Integer; end;');
EExport^.RegisterPointerTypeA(Engine, n, 'PTest', t);
EExport^.RegisterDynArrTypeA(Engine, n, 'TTestArray', t);
EExport^.RegisterDynArrTypeA(Engine, n, 'TMyIntArray', T_Integer);
EExport^.RegisterHeaderA(Engine, n, 'function MakeTest(a, b: Integer): TTest;', @MakeTest);
end;
exports LoadPlugin;
exports UnloadPlugin;
exports DoExport;
end.I've also created a c++ example with Visual Studio:
#include "Main.h"
#include "TitanPlugin.h"
typedef struct {
int a, b;
} TTest, *PTest;
int __stdcall TestStdCall(int i) {
return i;
}
int TestCDecl(int i) {
return i;
}
PTest __stdcall MakeTest(int a, int b) {
TTest t;
t.a = a;
t.b = b;
return &t;
}
// --
bool DLL_EXPORT LoadPlugin(int VMajor, int VMinor) {
return (VMajor == 4) && (VMinor >= 0);
}
bool DLL_EXPORT UnloadPlugin() {
return true;
}
void DLL_EXPORT DoExport(int Engine, PEExport EExport, PELib ELib) {
EExport->RegisterDirectiveA(Engine, "TEST_CPP");
int n = EExport->RegisterNamespaceA(Engine, "Test");
EExport->RegisterHeaderA(Engine, n, "function TestStdCall(i: Integer): Integer; stdcall;", &TestStdCall);
EExport->RegisterHeaderA(Engine, n, "function TestCDecl(i: Integer): Integer; cdecl;", &TestCDecl);
int t = EExport->RegisterTypeA(Engine, n, "TTest = record a, b: Integer; end;");
EExport->RegisterPointerTypeA(Engine, n, "PTest", t);
EExport->RegisterDynArrTypeA(Engine, n, "TTestArray", t);
EExport->RegisterDynArrTypeA(Engine, n, "TMyIntArray", T_Integer);
EExport->RegisterHeaderA(Engine, n, "function MakeTest(a, b: Integer): PTest; stdcall;", &MakeTest);
}I know the naming conventions in the c++ example are horrible, but I wanted to keep the plugin as similar to the delphi one as possible for the example. Feel free to rename stuff to your liking :) As long as you don't rename LoadPlugin, UnloadPlugin and DoExport of course :p
Both of these plugins can be ran with this sample script:
{$PLUGIN SamplePlugin}
uses
Test, Types;
var
tmpTest: TTest;
begin
{$IFDEF TEST_CPP}
tmpTest := MakeTest(7, 8)^;
PrintLn('Using C++ SamplePlugin');
{$ELSE}
tmpTest := MakeTest(7, 8);
PrintLn('Using Delphi SamplePlugin');
{$ENDIF}
PrintLn(TestStdCall(5));
PrintLn(TestCDecl(6));
PrintLn(ToStr(tmpTest.a) + ' ' + ToStr(tmpTest.b));
end.You can find all of the files for the delphi and c++ projects on here:
http://svn.scar-divi.com/titan_plugin/
The latest copy of SCAR 4 can be downloaded here:
http://svn.scar-divi.com/titan/
As for c++ support, there's some stuff that just might not be compatible with Delphi, so you may not be able to do everything in c++ you can with the Delphi plugin, but I'm trying to keep as much compatible as possible. I haven't succeeded in for example passing structs by value to a script from a function, maybe that's just because my c++ skills aren't as good as my Delphi ones, so if anyone can figure that out, let me know. In the example I've used a pointer to the struct to achieve the same thing. Note that this method is unsafe, the local struct var will be destroyed, that's why i'm copying the contents by value to a variable in the script, it prevents an error, using the pointer will probably not be an option.
EDIT: SCAR 4 will also feature a separated GUI plugin system btw, but I have more important things to focus on first.