Creating dynamic PPL libraries.

PPL comes with some very powerful functions that looks very plain simple at first but when you start using them, only then can you understand their real power.

The Run() function does exactly what it is suppose to, it runs a PPL program. However you can run a program but keep it in memory to access its internal functions. To keep a program from being freed from memory after it is ran, you need to use the following as your main code.

func WinMain
// Initialization code
return (true); // keep the program in memory
end;


You must also note, that since PPL comes with a built-in linker, all unused functions will be removed from the compiled code in memory. You must then force the functions not to be removed by the linker using the forcelink statement.

forcelink func MyFunction (a$, b$)
// My function code
end;


Once all your functions, procedures and main code are all setup it is time to load the library in memory.

MyLib$ = Run(AppPath$ + "MyLibrary");

MyLib$ will contain the handle pointing to the compiled library. Notice that we didn't specify an extension to our file "MyLibrary". It is because PPL will detect if a .ppl or .ppc exists and use the right one. While developing your project leave the .ppl file there so that the code is recompiled as needed. When you distribute your program, just use the .ppc (compiled) file.

Now it is time to call one of the library's function.

result$ = Call(MyLib$, "MyFunction", 10, 20);

The Call() function is very powerful, it can accept as many parameters as are needed by the called function or procedure and can return a value. In our case here, we call the function named "MyFunction" inside the program pointed to by MyLib$, passing the values 10 and 20.

Once we are finished with the library, we can free it from memory using the KillApp() function. This will unload the program from memory.

KillApp(MyLib$);

Here is our library file MyLibrary.ppl:

forcelink func MyFunction(a$, b$)
return (a$ + b$);
end;

func WinMain
return (true);
end;


Here is our main program file Main.ppl:

proc main
MyLib$ = Run(AppPath$ + "MyLibrary");
ShowMessage(Call(MyLib$, "MyFunction", 10, 20)); // Should show 30
KillApp(MyLib$);
end;



How do we use variables between libraries?

The first and easiest way would be to use global variables with the % sign.

MyLibrary.ppl:

forcelink func MyFunction
return (GlobalVar1% + GlobalVar2%);
end;

func WinMain
return (true);
end;

Main.ppl:

proc main
GlobalVar1% = 10;
GlobalVar2% = 20;
MyLib$ = Run(AppPath$ + "MyLibrary");
ShowMessage(Call(MyLib$, "MyFunction")); // Should show 30
KillApp(MyLib$);
end;


The second way to do this would be to have a DownloadVars and UploadVars procedures to transfer variables from and to a library.

MyLibrary.ppl:

forcelink proc DownloadVars(v1$, v2$);
LibVar1$ = v1$;
LibVar2$ = v2$;
end;

forcelink proc UploadVars$(v$)
v$ = result$;
end;

forcelink proc MyFunction
result$ = LibVar1$ + LibVar2$;
end;

func WinMain
Global(Result$);
return (true);
end;


Main.ppl:

proc main
MyLib$ = Run(AppPath$ + "MyLibrary");
Call(MyLib$, "DownloadVars", 10, 20);
Call(MyLib$, "MyFunction");
Call(MyLib$, "UploadVars", &result$);
ShowMessage(result$); // Should show 30.
KillApp(MyLib$);
end;


We hope this tutorial will give you a good idea on how to split your program into dynamic modules that you can load and unload when needed.