Difference between revisions of "Creating LCL Control From Libraries"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting)
 
(11 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
== About ==
 
== About ==
 +
 
Due to several problems, LCL components and ansistrings cannot be passed between a library (dll/so/dynlib) and an application (exe/app).
 
Due to several problems, LCL components and ansistrings cannot be passed between a library (dll/so/dynlib) and an application (exe/app).
  
 
This interface provides a simple API between the library and the application to create LCL UI controls application-side, however controlled by dummies library-side.
 
This interface provides a simple API between the library and the application to create LCL UI controls application-side, however controlled by dummies library-side.
  
 +
== Examples ==
  
== Examples ==
 
 
=== Usage example 1 (library) ===
 
=== Usage example 1 (library) ===
<pre>procedure init; stdcall;
+
 
 +
<syntaxhighlight lang="pascal">
 +
procedure init; stdcall;
 
var myBtn:TRHandle;
 
var myBtn:TRHandle;
 
begin
 
begin
Line 14: Line 17:
 
end;
 
end;
  
exports init;</pre>
+
exports init;
 +
</syntaxhighlight>
  
 
=== Usage example 2 (library) ===
 
=== Usage example 2 (library) ===
<pre>procedure init(RApplication,RParent:TRHandle); stdcall;
+
 
 +
<syntaxhighlight lang="pascal">
 +
procedure init(RApplication,RParent:TRHandle); stdcall;
 
var winCtrl:TRWinControl;
 
var winCtrl:TRWinControl;
 
begin
 
begin
Line 28: Line 34:
 
end;
 
end;
  
exports init;</pre>
+
exports init;
 +
</syntaxhighlight>
  
 
=== Usage example 3 (application) ===
 
=== Usage example 3 (application) ===
<pre>type
+
 
 +
<syntaxhighlight lang="pascal">
 +
type
 
   TDllInit1=procedure(intr:TRWinControlInterface); stdcall;
 
   TDllInit1=procedure(intr:TRWinControlInterface); stdcall;
 
   TDllInit2=procedure(intr:TRWinControlInterface; Appl,Parnt:TRHandle); stdcall;
 
   TDllInit2=procedure(intr:TRWinControlInterface; Appl,Parnt:TRHandle); stdcall;
Line 55: Line 64:
 
   FreeLibrary(lib);
 
   FreeLibrary(lib);
 
end.
 
end.
</pre>
+
</syntaxhighlight>
  
 +
== Technical details ==
  
== Technical details ==
 
 
=== Passing strings ===
 
=== Passing strings ===
 +
 
Strings cannot be usually passed between a library and an application. Since this system requires passing strings, a solution has been included:
 
Strings cannot be usually passed between a library and an application. Since this system requires passing strings, a solution has been included:
 
* You can either use simple PChars
 
* You can either use simple PChars
Line 65: Line 75:
 
* Or use the binary string system
 
* Or use the binary string system
 
** This probably is slower then just using PChars but it allows passing any type of data up to 2Gb.
 
** This probably is slower then just using PChars but it allows passing any type of data up to 2Gb.
To make it easy to switch, just type this switch "{$DEFINE USE_BIN_STR}" (without quotes) on the very top of your "rwincontrol" unit.
+
To make it easy to switch, just type this switch  
If this switch is set, binary strings support is enabled. If not, the more conventional PChars are used.
+
<syntaxhighlight lang="pascal">{$DEFINE USE_BIN_STR}</syntaxhighlight>
 +
on the very top of your "rwincontrol" unit.
 +
If this switch is set, binary strings support is enabled.
 +
If not, the more conventional PChars are used.
  
 
=== How does it work? ===
 
=== How does it work? ===
 +
 
A set of functions in the application are passed to the library as pointers in a record (TRWinControlInterface).
 
A set of functions in the application are passed to the library as pointers in a record (TRWinControlInterface).
 
Each time a library needs to change or create a control these functions are called. They basically make use of RTTI to provide this functionality.
 
Each time a library needs to change or create a control these functions are called. They basically make use of RTTI to provide this functionality.
  
 
=== What type of LCL controls? ===
 
=== What type of LCL controls? ===
 +
 
Actually, it's not just LCL but any other class you want. You just have to register your class application-side and provide a suitable wrapper library-side (though it is not required).
 
Actually, it's not just LCL but any other class you want. You just have to register your class application-side and provide a suitable wrapper library-side (though it is not required).
 
To register a class, put something like the following code in the initialization section of your program:
 
To register a class, put something like the following code in the initialization section of your program:
<pre>RegisterClass(TMyClass);</pre>
+
<syntaxhighlight lang="pascal">RegisterClass(TMyClass);</syntaxhighlight>
  
 +
== FAQ/Troubleshoot ==
  
== FAQ/Troubleshoot ==
 
 
====I get "class not found" errors====
 
====I get "class not found" errors====
 +
 
You have to register that class application-side. See [[#What type of LCL controls?]]
 
You have to register that class application-side. See [[#What type of LCL controls?]]
  
 +
====Where do I download the sources?====
 +
 +
[https://www.dropbox.com/sh/fanban54tb31p5e/AACSIXObpVfAIsinz0Sbbzkma?dl=0 View Source Code] or [https://www.dropbox.com/sh/fanban54tb31p5e/AACSIXObpVfAIsinz0Sbbzkma?dl=1 Download Zip]
  
 
== Copyright ==
 
== Copyright ==
 +
 
Devised and created by Christian Sciberras, with the help of the following people from #lazarus-ide IRC (alphabetical):
 
Devised and created by Christian Sciberras, with the help of the following people from #lazarus-ide IRC (alphabetical):
 
* Andreas <nowiki>'\pub\bash0r'</nowiki> Schneider
 
* Andreas <nowiki>'\pub\bash0r'</nowiki> Schneider
Line 90: Line 110:
 
* Vincent <nowiki>'fpcfan'</nowiki> Snijders
 
* Vincent <nowiki>'fpcfan'</nowiki> Snijders
  
 +
== License ==
  
== License ==
 
 
&copy; 2009 Covac Software. You may copy, store, modify and sell this software/source as long as you keep copyright comments in the source code intact.
 
&copy; 2009 Covac Software. You may copy, store, modify and sell this software/source as long as you keep copyright comments in the source code intact.
  
 
<!-- Still a learner, need this link for the future: http://www.mediawiki.org/wiki/Help:Formatting -->
 
<!-- Still a learner, need this link for the future: http://www.mediawiki.org/wiki/Help:Formatting -->
 +
 +
[[Category:LCL]]

Latest revision as of 05:22, 8 February 2020

About

Due to several problems, LCL components and ansistrings cannot be passed between a library (dll/so/dynlib) and an application (exe/app).

This interface provides a simple API between the library and the application to create LCL UI controls application-side, however controlled by dummies library-side.

Examples

Usage example 1 (library)

procedure init; stdcall;
var myBtn:TRHandle;
begin
  myBtn:=RCreate(StrToRstr('TButton'));
  RSetStrProp(myBtn,StrToRstr('Caption'),StrToRstr('Hello world!'));
end;

exports init;

Usage example 2 (library)

procedure init(RApplication,RParent:TRHandle); stdcall;
var winCtrl:TRWinControl;
begin
  winCtrl:=TRWinControl.Create(RApplication);
  winCtrl.Left:=20;
  winCtrl.Top:=10;
  winCtrl.Width:=100;
  winCtrl.Height:=24;
  winCtrl.Parent:=RParent;
end;

exports init;

Usage example 3 (application)

type
  TDllInit1=procedure(intr:TRWinControlInterface); stdcall;
  TDllInit2=procedure(intr:TRWinControlInterface; Appl,Parnt:TRHandle); stdcall;

var
  lib:TLibHandle;
  init1:TDllInit1;
  init2:TDllInit2;
begin
  RegisterClass(TButton);
  RegisterClass(TWinControl);

  // library example 1
  lib:=LoadLibrary('library1.'+SharedSuffix);
  init1:=TDllInit(GetProcAddress(lib,'init'));
  init1(FillRWinControlInterface);
  FreeLibrary(lib);

  // library example 2
  lib:=LoadLibrary('library2.'+SharedSuffix);
  init2:=TDllInit(GetProcAddress(lib,'init'));
  init2(FillRWinControlInterface,TRHandle(Application),TRHandle(Panel1));
  FreeLibrary(lib);
end.

Technical details

Passing strings

Strings cannot be usually passed between a library and an application. Since this system requires passing strings, a solution has been included:

  • You can either use simple PChars
    • Fast but not suitable for binary data (especially containing null characters)
  • Or use the binary string system
    • This probably is slower then just using PChars but it allows passing any type of data up to 2Gb.

To make it easy to switch, just type this switch

{$DEFINE USE_BIN_STR}

on the very top of your "rwincontrol" unit. If this switch is set, binary strings support is enabled. If not, the more conventional PChars are used.

How does it work?

A set of functions in the application are passed to the library as pointers in a record (TRWinControlInterface). Each time a library needs to change or create a control these functions are called. They basically make use of RTTI to provide this functionality.

What type of LCL controls?

Actually, it's not just LCL but any other class you want. You just have to register your class application-side and provide a suitable wrapper library-side (though it is not required). To register a class, put something like the following code in the initialization section of your program:

RegisterClass(TMyClass);

FAQ/Troubleshoot

I get "class not found" errors

You have to register that class application-side. See #What type of LCL controls?

Where do I download the sources?

View Source Code or Download Zip

Copyright

Devised and created by Christian Sciberras, with the help of the following people from #lazarus-ide IRC (alphabetical):

  • Andreas '\pub\bash0r' Schneider
  • Dmitry 'skalogryz' Boyarintsev
  • Marc 'giantm' Weustink
  • Vincent 'fpcfan' Snijders

License

© 2009 Covac Software. You may copy, store, modify and sell this software/source as long as you keep copyright comments in the source code intact.