Main Page IT

LAG ENVIRONMENT

LAG ENVIRONMENT MANUAL EXTERNAL SMART OBJECT


library typicalexternalso;

{

The function getcompatibility is mandatory.

The program checks for the presence of the function with the following syntax in a library and expects an output with the identifier 'LAG ENVIRONMENT'.

If this requirement is not fulfilled then the library will not be treated as if it is compatible with this program.


If the initialize procedure exists then immediately after the library is loaded the initialize procedure is applied.

If the finalize procedure exists then immediately before the library is unloaded the finalize procedure is applied.

If the help function exists then the output lines will be appended to the main help lines. Make sure binary commands are used as text commands may interfere with other parts of help.


In order to be able to use commands the following functions/procedures must be present(all of them): setinputdata, getpointertoidentifier, issanecommand, command, getoutputdata

If all of the above functions/procedures exist then the main program will:

1:

If the main program allows threads then if threadmode exists and returns a value greater than one then that value is the maximum number of threads.

If the returned value is 255 then unlimited number of threads may be used at the same time to call the command procedure.

If the value returned is zero, or the function doesn't exist then threads will be disabled to this library even if the main program allows use of threads.

2:

If getnewidentifier exists then it will be called.

If it doesn't exist then it's the same as if the function returns value zero.

If the value is zero then the main program tries to find an identifier.

3:

If initializeidentifier exists then it is called in order to allow the library to do any needed operations(like allocating space).

4:

Call setinputdata in order to allow the library to assign the command content to the identifier(like copying the data).

5:

If timeout exists then it will be called.

If it doesn't exist or it returns a value smaller than 1 then the main program will use a default timeout value.

The timeout value represents milliseconds and is used when the main program waits for the library command to finish.

6:

Call getpointertoidentifier in order to get an address to the identifier.

This memory address will be used as parameter when calling command.(In the example the pointer points to the identifier longword value);

7:

Call issanecommand in order to know if the command procedure should be used with the identifier(data that was given as parameter when setinputdata was called).

8:

If issanecommand returned a different than zero value, then command procedure is called with the identifier.

If upon execution of the command routine, OUTPUTDATABLOCK contains a new command(chr(39) by default for a silent success), then the command is considered success.

If upon execution of the command routine, OUTPUTDATABLOCK is nil or empty, then the command is considered failure.

9:

If issanecommand returned a different than zero value, then getoutputdata is called with the identifier in order to read the output of the command.

10:

Call finalizeidentifier in order to announce the library that the main program has finished working with the identifier.

This means that any input and output allocated space for that identifier may be freed.


In order to avoid memory leaks and other memory related problems the following rule is used:

The entity that allocates space is in charge with the management of the occupied space.

This means that if memory is allocated by the library, then the library has to free the memory space and also the library will resize(if needed) the allocated memory.

Exceptions from this rule may be allowed, but these should be carefully tested.


Binary commands syntax:

Character 0, Size of the command content in bytes stored as a longword, Command content.

Examples:

Textcommand 'Echo

Binary command byte(0),longword(5),'Echo

Textcommand GETCAMERAINFO

Binary command byte(0),longword(13),GETCAMERAINFO


Calling mechanism is "stdcall" for Windows and "cdecl" for other operating systems.


ATTENTION!!!

Do not try to export functions that return pointers. It will not work.

}



{$mode objfpc}{$H+}


uses sysutils, classes;//Uses example


type tdatastructure=record

Identifier:longword;

OutputDataBlock:pointer;

InputDataBlock:pointer;

end;

ptdatastructure=^tdatastructure;


var DataArray:array of tdatastructure;//Recommended approach to use identifiers with multiple threads.

StaticData:pointer;//Data for functions like help or getcompatibility


procedure command(const pidentifier:pointer);{$ifdef windows}stdcall{$else}cdecl{$endif};

var IndexTmp:longword;

begin

if ((length(DataArray)>0)and(pidentifier<>nil)) then

for IndexTmp:=0 to high(DataArray) do

if DataArray[IndexTmp].Identifier=plongword(pidentifier)^ then

begin

if ((DataArray[IndexTmp].InputDataBlock<>nil)and(plongword(DataArray[IndexTmp].InputDataBlock)^>0)) then

begin//The command input pointer is not nil and the content of the input data is greater than zero



end;

break;

end;

end;


procedure setinputdata(const Identifier:longword;const MemoryBlock:pointer);{$ifdef windows}stdcall{$else}cdecl{$endif};

{Sets input data content. MemoryBlock points to the input data(the command content) of the Identifier.

This procedure is always used before calling the command procedure. If this procedure is missing then the command procedure will not be called.

The content of the procedure is just as example!!!}

var IndexTmp:longword;

begin

if length(DataArray)>0 then for IndexTmp:=0 to high(DataArray) do

if DataArray[IndexTmp].Identifier=Identifier then

begin//Copy the data from MemoryBlock

if MemoryBlock<>nil then

begin

if DataArray[IndexTmp].InputDataBlock=nil then DataArray[IndexTmp].InputDataBlock:=getmem(sizeof(longword)+plongword(MemoryBlock)^) else ReallocMem(DataArray[IndexTmp].InputDataBlock,sizeof(longword)+plongword(MemoryBlock)^);

move(MemoryBlock^,DataArray[IndexTmp].InputDataBlock^,sizeof(longword)+plongword(MemoryBlock)^);

end else

begin

if DataArray[IndexTmp].InputDataBlock=nil then DataArray[IndexTmp].InputDataBlock:=getmem(sizeof(longword)) else ReallocMem(DataArray[IndexTmp].InputDataBlock,sizeof(longword));

plongword(DataArray[IndexTmp].InputDataBlock)^:=0;

end;

break;

end;

end;


procedure getoutputdata(const Identifier:longword;var MemoryBlock:pointer);{$ifdef windows}stdcall{$else}cdecl{$endif};

{This procedure is always used after calling the command procedure. If this procedure is missing then the command procedure will not be called.

Gets the output data content. MemoryBlock points to the output data(data stored by the command procedure) of the Identifier.

The content of the procedure is just as example!!!}

var IndexTmp:longword;

begin

MemoryBlock:=nil;

if length(DataArray)>0 then for IndexTmp:=0 to high(DataArray) do

if DataArray[IndexTmp].Identifier=Identifier then begin MemoryBlock:=DataArray[IndexTmp].OutputDataBlock;break;end;

end;


procedure help(var MemoryBlock:pointer);{$ifdef windows}stdcall{$else}cdecl{$endif};

begin

//The following lines can be replaced with: MemoryBlock:=nil;

ReallocMem(StaticData,sizeof(longword));plongword(StaticData)^:=0;

MemoryBlock:=StaticData;

end;


procedure getcompatibility(var MemoryBlock:pointer);{$ifdef windows}stdcall{$else}cdecl{$endif};

const CompatibilityIdentifier:shortstring='LAG ENVIRONMENT';//This is the compatibility identifier.

begin

ReallocMem(StaticData,sizeof(longword)+length(CompatibilityIdentifier));//Allocate space(4Bytes as the size of longword+15Bytes as the size of the identifier)

plongword(StaticData)^:=length(CompatibilityIdentifier);//Update the size of the content stored at StaticData

move(pointer(@CompatibilityIdentifier[1])^,pointer(StaticData+sizeof(longword))^,length(CompatibilityIdentifier));//Copy the content of CompatibilityIdentifier

MemoryBlock:=StaticData;//Return a pointer to StaticData which now contains the identifier

end;


procedure initialize;{$ifdef windows}stdcall{$else}cdecl{$endif};

begin

StaticData:=getmem(sizeof(longword));plongword(StaticData)^:=0;//Initialize the memory block that stores output information for standard procedures like getcompatibility or help

setlength(DataArray,0);//Other initializations

end;


procedure finalize;{$ifdef windows}stdcall{$else}cdecl{$endif};

var IndexTmp:longword;

begin

freemem(StaticData,sizeof(longword)+plongword(StaticData)^);//Free the memory block that stores output information for standard procedures like getcompatibility or help

//Free the memory blocks that store identifiers together with inputs and outputs

if length(DataArray)>0 then for IndexTmp:=0 to high(DataArray) do

begin

freemem(DataArray[IndexTmp].InputDataBlock,sizeof(longword)+plongword(DataArray[IndexTmp].InputDataBlock)^);

freemem(DataArray[IndexTmp].OutputDataBlock,sizeof(longword)+plongword(DataArray[IndexTmp].OutputDataBlock)^);

end;

setlength(DataArray,0);

end;


function threadmode:byte;{$ifdef windows}stdcall{$else}cdecl{$endif};

{The function should return:

0 Threads are not allowed;

1..254 No more than this number of threads are allowed;

255 Any number of threads is allowed;

}

begin

Result:=0;//Threads are not allowed

end;


function getnewidentifier:longword;{$ifdef windows}stdcall{$else}cdecl{$endif};

{If the function returns 0, it's the same as if the function doesn't exist.This means that the main program has to find a unique command identifier.

Developing code within this function might be useful if this library is used within unlimited threads or

when optimizations based on space allocated for obsolete identifiers is reused.}

begin

Result:=0;//Set default output

end;


procedure initializeidentifier(const Identifier:longword);{$ifdef windows}stdcall{$else}cdecl{$endif};

{After getting a new identifier the main program calls this procedure.}

var IndexTmp:longword;

IdentifierExists:boolean;

begin

IdentifierExists:=False;

if length(DataArray)>0 then for IndexTmp:=0 to high(DataArray) do

if DataArray[IndexTmp].Identifier=Identifier then

begin

IdentifierExists:=True;

if DataArray[IndexTmp].InputDataBlock<>nil then

begin

ReallocMem(DataArray[IndexTmp].InputDataBlock,sizeof(longword));plongword(DataArray[IndexTmp].InputDataBlock)^:=0;

end;

if DataArray[IndexTmp].OutputDataBlock<>nil then

begin

ReallocMem(DataArray[IndexTmp].OutputDataBlock,sizeof(longword));plongword(DataArray[IndexTmp].OutputDataBlock)^:=0;

end;

break;

end;

if IdentifierExists=False then

begin

setlength(DataArray,succ(length(DataArray)));

DataArray[high(DataArray)].Identifier:=Identifier;

DataArray[high(DataArray)].InputDataBlock:=getmem(sizeof(longword));plongword(DataArray[high(DataArray)].InputDataBlock)^:=0;

DataArray[high(DataArray)].OutputDataBlock:=getmem(sizeof(longword));plongword(DataArray[high(DataArray)].OutputDataBlock)^:=0;

end;

end;


procedure finalizeidentifier(const Identifier:longword);{$ifdef windows}stdcall{$else}cdecl{$endif};

{After the command procedure has ended the main program calls this procedure.}

var IndexTmp:longword;

ShiftData:bytebool;

begin

ShiftData:=False;

if length(DataArray)>0 then for IndexTmp:=0 to high(DataArray) do

begin

if DataArray[IndexTmp].Identifier=Identifier then

begin//The Identifier has been found

freemem(DataArray[IndexTmp].InputDataBlock,sizeof(longword)+plongword(DataArray[IndexTmp].InputDataBlock)^);

freemem(DataArray[IndexTmp].OutputDataBlock,sizeof(longword)+plongword(DataArray[IndexTmp].OutputDataBlock)^);

//Shift data is needed

ShiftData:=True;

end;

if ((ShiftData=True)and(IndexTmp<high(DataArray))) then DataArray[IndexTmp]:=DataArray[succ(IndexTmp)];

end;

if ShiftData=True then setlength(DataArray,pred(length(DataArray)));//If the Identifier has been found then remove the last entry

end;


procedure getpointertoidentifier(const Identifier:longword;var MemoryBlock:pointer);{$ifdef windows}stdcall{$else}cdecl{$endif};

var IndexTmp:longword;

begin

MemoryBlock:=nil;

if length(DataArray)>0 then

for IndexTmp:=0 to high(DataArray) do

begin

if DataArray[IndexTmp].Identifier=Identifier then

begin

MemoryBlock:=pointer(@DataArray[IndexTmp].Identifier);break;

end;

end;

end;


function timeout(const Identifier:longword):longword;{$ifdef windows}stdcall{$else}cdecl{$endif};

{The function returns the number of milliseconds given for the command procedure to end.

The main program will replace any value smaller than 1 with a default value.

If this function is missing from a library then the main program will use a default value.}

begin

Result:=10000;//Give 10 seconds to any command

end;


function issanecommand(const Command:pointer):byte;{$ifdef windows}stdcall{$else}cdecl{$endif};

{The function returns 1 if the command can be used by the library and returns 0 if it can't be used.

The function is called before the command procedure.}

begin

Result:=0;

if ((Command<>nil)and(plongword(Command)^>0)) then

begin//Assume any non-empty Command to be a valid one.{Not recommended to be left in this state.}

Result:=1;



end;

end;


exports getcompatibility, setinputdata, command, getoutputdata, initialize, finalize, help, threadmode,

getpointertoidentifier, getnewidentifier, initializeidentifier, finalizeidentifier, issanecommand, timeout;


begin


end.

Free Web Hosting