mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-21 00:23:18 +02:00

------------------------------------------------------------------------ r19294 | paul | 2009-04-10 11:17:35 +0800 (Птн, 10 Апр 2009) | 1 line lcl, win32: start optimizations: imglist (all), controls (all), combtrls (statubar) ------------------------------------------------------------------------ r19305 | martin | 2009-04-10 21:53:27 +0800 (Птн, 10 Апр 2009) | 1 line Moved "DoneRegisterCheck" to global LCL ------------------------------------------------------------------------ r19306 | martin | 2009-04-10 22:14:57 +0800 (Птн, 10 Апр 2009) | 1 line Moved "DoneRegisterCheck" to global LCL (more) ------------------------------------------------------------------------ r19307 | martin | 2009-04-10 22:22:44 +0800 (Птн, 10 Апр 2009) | 1 line changed case true => True ------------------------------------------------------------------------ r19308 | paul | 2009-04-10 22:28:28 +0800 (Птн, 10 Апр 2009) | 1 line fix file case ------------------------------------------------------------------------ r19311 | martin | 2009-04-10 23:09:16 +0800 (Птн, 10 Апр 2009) | 1 line Moved Registration of TCustomCalendar ------------------------------------------------------------------------ r19312 | martin | 2009-04-10 23:28:03 +0800 (Птн, 10 Апр 2009) | 1 line Moved PropertyToSkip for TCalender ------------------------------------------------------------------------ r19314 | paul | 2009-04-10 23:50:30 +0800 (Птн, 10 Апр 2009) | 1 line merge r13913 #999e8b059d ------------------------------------------------------------------------ r19315 | paul | 2009-04-10 23:53:07 +0800 (Птн, 10 Апр 2009) | 1 line cleanup WSCalendar ------------------------------------------------------------------------ r19316 | paul | 2009-04-11 00:37:44 +0800 (Сбт, 11 Апр 2009) | 1 line finish with ComCtrls ------------------------------------------------------------------------ r19318 | martin | 2009-04-11 01:37:40 +0800 (Сбт, 11 Апр 2009) | 1 line Moved dialogs ------------------------------------------------------------------------ r19319 | martin | 2009-04-11 01:47:30 +0800 (Сбт, 11 Апр 2009) | 1 line Moved dialogs ------------------------------------------------------------------------ r19320 | martin | 2009-04-11 02:47:52 +0800 (Сбт, 11 Апр 2009) | 1 line Moved ExtCtrls, ExtDlgs ------------------------------------------------------------------------ r19321 | martin | 2009-04-11 03:23:32 +0800 (Сбт, 11 Апр 2009) | 1 line Moved PropertyToSkip ------------------------------------------------------------------------ r19322 | martin | 2009-04-11 03:37:39 +0800 (Сбт, 11 Апр 2009) | 1 line Moved StdCtrls ------------------------------------------------------------------------ r19323 | martin | 2009-04-11 04:05:50 +0800 (Сбт, 11 Апр 2009) | 1 line Moved Buttons ------------------------------------------------------------------------ r19325 | paul | 2009-04-11 11:02:26 +0800 (Сбт, 11 Апр 2009) | 1 line remove DirSel ------------------------------------------------------------------------ r19326 | paul | 2009-04-11 11:11:37 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterArrow ------------------------------------------------------------------------ r19327 | paul | 2009-04-11 11:32:09 +0800 (Сбт, 11 Апр 2009) | 1 line register WS classes only for TCustomXXX classes if they are available (like TCustomScrollBar instead of TScrollBar) and only for those descendants which really differ (like TRadioButton, TToggleButton) ------------------------------------------------------------------------ r19328 | paul | 2009-04-11 11:40:00 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterCustomCheckBox ------------------------------------------------------------------------ r19329 | paul | 2009-04-11 11:57:22 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterXXX for Forms ------------------------------------------------------------------------ r19330 | paul | 2009-04-11 12:13:05 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterCustomGrid + move of RegisterPropertyToSkip ------------------------------------------------------------------------ r19331 | paul | 2009-04-11 12:24:29 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterXXX for Menus ------------------------------------------------------------------------ r19332 | paul | 2009-04-11 12:35:16 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterXXX for PairSplitter ------------------------------------------------------------------------ r19333 | paul | 2009-04-11 12:47:39 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterXXX for Spin ------------------------------------------------------------------------ r19334 | paul | 2009-04-11 12:58:55 +0800 (Сбт, 11 Апр 2009) | 1 line RegisterCustomRubberBand ------------------------------------------------------------------------ r19335 | paul | 2009-04-11 13:31:43 +0800 (Сбт, 11 Апр 2009) | 1 line remove 2 initialization sections ------------------------------------------------------------------------ r19336 | paul | 2009-04-11 13:46:26 +0800 (Сбт, 11 Апр 2009) | 1 line remove TPopupNotifier.png from LCL ------------------------------------------------------------------------ r19338 | paul | 2009-04-11 13:54:03 +0800 (Сбт, 11 Апр 2009) | 1 line cleanup ------------------------------------------------------------------------ r19341 | paul | 2009-04-11 14:59:27 +0800 (Сбт, 11 Апр 2009) | 1 line cleanup ------------------------------------------------------------------------ r19343 | martin | 2009-04-11 19:59:18 +0800 (Сбт, 11 Апр 2009) | 1 line Reduced Unit-Circles, by moving Register* into WS* units ------------------------------------------------------------------------ r19344 | martin | 2009-04-11 20:22:49 +0800 (Сбт, 11 Апр 2009) | 1 line Dummy file for gtk ------------------------------------------------------------------------ r19345 | martin | 2009-04-11 21:06:55 +0800 (Сбт, 11 Апр 2009) | 1 line Initial move of gtk1 register ------------------------------------------------------------------------ r19346 | martin | 2009-04-11 21:19:48 +0800 (Сбт, 11 Апр 2009) | 1 line Missing dependencies in gtk1 wsfactory ------------------------------------------------------------------------ r19347 | martin | 2009-04-11 22:36:42 +0800 (Сбт, 11 Апр 2009) | 1 line Declare register* in interface, to keep external linker happy ------------------------------------------------------------------------ r19348 | martin | 2009-04-11 23:34:16 +0800 (Сбт, 11 Апр 2009) | 1 line Declare register* in interface, to keep external linker happy ------------------------------------------------------------------------ r19349 | martin | 2009-04-11 23:39:20 +0800 (Сбт, 11 Апр 2009) | 1 line moved uses for factory ------------------------------------------------------------------------ r19350 | martin | 2009-04-11 23:41:57 +0800 (Сбт, 11 Апр 2009) | 1 line corrected a few accidental "Result := False" ------------------------------------------------------------------------ r19351 | paul | 2009-04-12 00:04:15 +0800 (Вск, 12 Апр 2009) | 1 line removed unused units ------------------------------------------------------------------------ r19352 | paul | 2009-04-12 00:05:26 +0800 (Вск, 12 Апр 2009) | 1 line qt: move RegisterWS calls to qtwsfactory ------------------------------------------------------------------------ r19354 | paul | 2009-04-12 01:04:04 +0800 (Вск, 12 Апр 2009) | 1 line wince: move RegisterWS calls to WinCEWSFactory ------------------------------------------------------------------------ r19356 | martin | 2009-04-12 01:39:56 +0800 (Вск, 12 Апр 2009) | 1 line moved GTK2 ------------------------------------------------------------------------ r19357 | martin | 2009-04-12 01:45:31 +0800 (Вск, 12 Апр 2009) | 1 line moved GTK2 / missing units ------------------------------------------------------------------------ r19358 | martin | 2009-04-12 01:57:43 +0800 (Вск, 12 Апр 2009) | 1 line Fixed one return value from register ------------------------------------------------------------------------ r19360 | martin | 2009-04-12 02:47:42 +0800 (Вск, 12 Апр 2009) | 1 line Gtk2 , needs 2 registrations for WinControl ------------------------------------------------------------------------ r19361 | martin | 2009-04-12 02:57:58 +0800 (Вск, 12 Апр 2009) | 1 line Gtk2 , needs 2nd registrations ------------------------------------------------------------------------ r19368 | paul | 2009-04-12 13:09:59 +0800 (Вск, 12 Апр 2009) | 1 line cleanup ------------------------------------------------------------------------ r19373 | paul | 2009-04-12 13:45:17 +0800 (Вск, 12 Апр 2009) | 1 line wince: forgotten file ------------------------------------------------------------------------ r19374 | paul | 2009-04-12 14:04:04 +0800 (Вск, 12 Апр 2009) | 1 line carbon: move RegisterWSComponent to CarbonWSFactory ------------------------------------------------------------------------ r19375 | paul | 2009-04-12 14:27:47 +0800 (Вск, 12 Апр 2009) | 1 line cleanup ------------------------------------------------------------------------ git-svn-id: trunk@19376 -
530 lines
15 KiB
ObjectPascal
530 lines
15 KiB
ObjectPascal
{ $Id$}
|
|
{
|
|
*****************************************************************************
|
|
* wslclclasses.pp *
|
|
* --------------- *
|
|
* *
|
|
* *
|
|
*****************************************************************************
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
unit WSLCLClasses;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
{off$DEFINE VerboseWSRegistration}
|
|
{off$DEFINE VerboseWSRegistration_methods}
|
|
{off$DEFINE VerboseWSRegistration_treedump}
|
|
|
|
interface
|
|
////////////////////////////////////////////////////
|
|
// I M P O R T A N T
|
|
////////////////////////////////////////////////////
|
|
// 1) Only class methods allowed
|
|
// 2) Class methods have to be published and virtual
|
|
// 3) To get as little as possible circles, the uses
|
|
// clause should contain only those LCL units
|
|
// needed for registration. WSxxx units are OK
|
|
// 4) To improve speed, register only classes in the
|
|
// initialization section which actually
|
|
// implement something
|
|
// 5) To enable your XXX widgetset units, look at
|
|
// the uses clause of the XXXintf.pp
|
|
////////////////////////////////////////////////////
|
|
uses
|
|
Classes, LCLProc; //, LCLType; //, InterfaceBase;
|
|
|
|
type
|
|
{ TWSPrivate }
|
|
|
|
{
|
|
Internal WidgetSet specific object tree
|
|
}
|
|
TWSPrivate = class(TObject)
|
|
end;
|
|
TWSPrivateClass = class of TWSPrivate;
|
|
|
|
{ TWSLCLComponent }
|
|
|
|
{$M+}
|
|
TWSLCLComponent = class(TObject)
|
|
public
|
|
class function WSPrivate: TWSPrivateClass; //inline;
|
|
end;
|
|
{$M-}
|
|
TWSLCLComponentClass = class of TWSLCLComponent;
|
|
|
|
{ TWSLCLHandleComponent }
|
|
|
|
TWSLCLReferenceComponent = class(TWSLCLComponent)
|
|
published
|
|
class procedure DestroyReference(AComponent: TComponent); virtual;
|
|
end;
|
|
TWSLCLReferenceComponentClass = class of TWSLCLReferenceComponent;
|
|
|
|
|
|
function FindWSComponentClass(const AComponent: TComponentClass): TWSLCLComponentClass;
|
|
procedure RegisterWSComponent(const AComponent: TComponentClass;
|
|
const AWSComponent: TWSLCLComponentClass;
|
|
const AWSPrivate: TWSPrivateClass = nil);
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils, LCLClasses;
|
|
|
|
procedure DoInitialization; forward;
|
|
|
|
////////////////////////////////////////////////////
|
|
// Registration code
|
|
////////////////////////////////////////////////////
|
|
type
|
|
PClassNode = ^TClassNode;
|
|
TClassNode = record
|
|
LCLClass: TComponentClass;
|
|
WSClass: TWSLCLComponentClass;
|
|
VClass: Pointer;
|
|
VClassName: ShortString;
|
|
Parent: PClassNode;
|
|
Child: PClassNode;
|
|
Sibling: PClassNode;
|
|
end;
|
|
|
|
const
|
|
// To my knowledge there is no way to tell the size of the
|
|
// VMT of a given class.
|
|
// Assume we have no more than 100 virtual entries
|
|
VIRTUAL_VMT_COUNT = 100;
|
|
VIRTUAL_VMT_SIZE = vmtMethodStart + VIRTUAL_VMT_COUNT * SizeOf(Pointer);
|
|
|
|
const
|
|
// vmtAutoTable is something Delphi 2 and not used, we 'borrow' the vmt entry
|
|
vmtWSPrivate = vmtAutoTable;
|
|
|
|
var
|
|
MComponentIndex: TStringList;
|
|
MWSRegisterIndex: TStringList;
|
|
|
|
function FindWSComponentClass(
|
|
const AComponent: TComponentClass): TWSLCLComponentClass;
|
|
var
|
|
idx: Integer;
|
|
cls: TClass;
|
|
Node: PClassNode;
|
|
begin
|
|
if MWSRegisterIndex = nil then
|
|
DoInitialization;
|
|
|
|
Result := nil;
|
|
cls := AComponent;
|
|
while cls <> nil do
|
|
begin
|
|
idx := MWSRegisterIndex.IndexOf(cls.ClassName);
|
|
if idx <> -1
|
|
then begin
|
|
Node := PClassNode(MWSRegisterIndex.Objects[idx]);
|
|
Result := TWSLCLComponentClass(Node^.VClass);
|
|
Exit;
|
|
end;
|
|
cls := cls.ClassParent;
|
|
end;
|
|
end;
|
|
|
|
type
|
|
TMethodNameTableEntry = packed record
|
|
Name: PShortstring;
|
|
Addr: Pointer;
|
|
end;
|
|
|
|
TMethodNameTable = packed record
|
|
Count: DWord;
|
|
Entries: packed array[0..9999999] of TMethodNameTableEntry;
|
|
end;
|
|
PMethodNameTable = ^TMethodNameTable;
|
|
|
|
TPointerArray = packed array[0..9999999] of Pointer;
|
|
PPointerArray = ^TPointerArray;
|
|
|
|
procedure RegisterWSComponent(const AComponent: TComponentClass;
|
|
const AWSComponent: TWSLCLComponentClass;
|
|
const AWSPrivate: TWSPrivateClass = nil);
|
|
|
|
function GetNode(const AClass: TClass): PClassNode;
|
|
var
|
|
idx: Integer;
|
|
Name: String;
|
|
begin
|
|
if (AClass = nil)
|
|
or not (AClass.InheritsFrom(TLCLComponent))
|
|
then begin
|
|
Result := nil;
|
|
Exit;
|
|
end;
|
|
|
|
Name := AClass.ClassName;
|
|
idx := MComponentIndex.IndexOf(Name);
|
|
if idx = -1
|
|
then begin
|
|
New(Result);
|
|
Result^.LCLClass := TComponentClass(AClass);
|
|
Result^.WSClass := nil;
|
|
Result^.VClass := nil;
|
|
Result^.VClassName := '';
|
|
Result^.Child := nil;
|
|
Result^.Parent := GetNode(AClass.ClassParent);
|
|
if Result^.Parent = nil
|
|
then begin
|
|
Result^.Sibling := nil;
|
|
end
|
|
else begin
|
|
Result^.Sibling := Result^.Parent^.Child;
|
|
Result^.Parent^.Child := Result;
|
|
end;
|
|
MComponentIndex.AddObject(Name, TObject(Result));
|
|
end
|
|
else begin
|
|
Result := PClassNode(MComponentIndex.Objects[idx]);
|
|
end;
|
|
end;
|
|
|
|
function FindParentWSClassNode(const ANode: PClassNode): PClassNode;
|
|
begin
|
|
Result := ANode^.Parent;
|
|
while Result <> nil do
|
|
begin
|
|
if Result^.WSClass <> nil then Exit;
|
|
Result := Result^.Parent;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function FindCommonAncestor(const AClass1, AClass2: TClass): TClass;
|
|
begin
|
|
Result := AClass1;
|
|
if AClass2.InheritsFrom(Result)
|
|
then Exit;
|
|
|
|
Result := AClass2;
|
|
while Result <> nil do
|
|
begin
|
|
if AClass1.InheritsFrom(Result)
|
|
then Exit;
|
|
Result := Result.ClassParent;
|
|
end;
|
|
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure CreateVClass(const ANode: PClassNode; AOldPrivate: TClass = nil);
|
|
var
|
|
ParentWSNode: PClassNode;
|
|
CommonClass: TClass;
|
|
Vvmt, Cvmt, Pvmt: PPointerArray;
|
|
Cmnt: PMethodNameTable;
|
|
SearchAddr: Pointer;
|
|
n, idx: Integer;
|
|
WSPrivate, OrgPrivate: TClass;
|
|
Processed: array[0..VIRTUAL_VMT_COUNT-1] of Boolean;
|
|
{$IFDEF VerboseWSRegistration}
|
|
Indent: String;
|
|
{$ENDIF}
|
|
begin
|
|
if AWSPrivate = nil
|
|
then WSPrivate := TWSPrivate
|
|
else WSPrivate := AWSPrivate;
|
|
|
|
if ANode^.VClass = nil
|
|
then begin
|
|
ANode^.VClass := GetMem(VIRTUAL_VMT_SIZE)
|
|
end
|
|
else begin
|
|
// keep original WSPrivate (only when different than default class)
|
|
OrgPrivate := PClass(ANode^.VClass + vmtWSPrivate)^;
|
|
|
|
if (OrgPrivate <> nil) and (OrgPrivate <> AOldPrivate) and OrgPrivate.InheritsFrom(WSPrivate)
|
|
then begin
|
|
{$IFDEF VerboseWSRegistration}
|
|
DebugLn('Keep org private: ', WSPrivate.ClassName, ' -> ', OrgPrivate.Classname);
|
|
{$ENDIF}
|
|
WSPrivate := OrgPrivate;
|
|
end;
|
|
end;
|
|
|
|
// Initially copy the WSClass
|
|
// Tricky part, the source may get beyond read mem limit
|
|
Move(Pointer(ANode^.WSClass)^, ANode^.VClass^, VIRTUAL_VMT_SIZE);
|
|
|
|
// Set WSPrivate class
|
|
ParentWSNode := FindParentWSClassNode(ANode);
|
|
if ParentWSNode = nil
|
|
then begin
|
|
// nothing to do
|
|
PClass(ANode^.VClass + vmtWSPrivate)^ := WSPrivate;
|
|
{$IFDEF VerboseWSRegistration}
|
|
DebugLn('Virtual parent: nil, WSPrivate: ', PClass(ANode^.VClass + vmtWSPrivate)^.ClassName);
|
|
{$ENDIF}
|
|
Exit;
|
|
end;
|
|
|
|
if WSPrivate = TWSPrivate
|
|
then begin
|
|
if ParentWSNode^.VClass = nil
|
|
then begin
|
|
DebugLN('[WARNING] Missing VClass for: ', ParentWSNode^.WSClass.ClassName);
|
|
PClass(ANode^.VClass + vmtWSPrivate)^ := TWSPrivate;
|
|
end
|
|
else PClass(ANode^.VClass + vmtWSPrivate)^ := PClass(ParentWSNode^.VClass + vmtWSPrivate)^;
|
|
end
|
|
else PClass(ANode^.VClass + vmtWSPrivate)^ := WSPrivate;
|
|
|
|
{$IFDEF VerboseWSRegistration}
|
|
DebugLn('Virtual parent: ', ParentWSNode^.WSClass.ClassName, ', WSPrivate: ', PClass(ANode^.VClass + vmtWSPrivate)^.ClassName);
|
|
{$ENDIF}
|
|
|
|
|
|
// Try to find the common ancestor
|
|
CommonClass := FindCommonAncestor(ANode^.WSClass, ParentWSNode^.WSClass);
|
|
{$IFDEF VerboseWSRegistration}
|
|
DebugLn('Common: ', CommonClass.ClassName);
|
|
Indent := '';
|
|
{$ENDIF}
|
|
|
|
Vvmt := ANode^.VClass + vmtMethodStart;
|
|
Pvmt := ParentWSNode^.VClass + vmtMethodStart;
|
|
FillChar(Processed[0], SizeOf(Processed), 0);
|
|
|
|
while CommonClass <> nil do
|
|
begin
|
|
Cmnt := PPointer(Pointer(CommonClass) + vmtMethodTable)^;
|
|
if Cmnt <> nil
|
|
then begin
|
|
{$IFDEF VerboseWSRegistration_methods}
|
|
DebugLn(Indent, '*', CommonClass.Classname, ' method count: ', IntToStr(Cmnt^.Count));
|
|
Indent := Indent + ' ';
|
|
{$ENDIF}
|
|
|
|
Cvmt := Pointer(CommonClass) + vmtMethodStart;
|
|
Assert(Cmnt^.Count < VIRTUAL_VMT_COUNT, 'MethodTable count is larger that assumed VIRTUAL_VMT_COUNT');
|
|
|
|
// Loop though the VMT to see what is overridden
|
|
for n := 0 to Cmnt^.Count - 1 do
|
|
begin
|
|
SearchAddr := Cmnt^.Entries[n].Addr;
|
|
{$IFDEF VerboseWSRegistration_methods}
|
|
DebugLn('%sSearch: %s (%p)', [Indent, Cmnt^.Entries[n].Name^, SearchAddr]);
|
|
{$ENDIF}
|
|
|
|
for idx := 0 to VIRTUAL_VMT_COUNT - 1 do
|
|
begin
|
|
if Cvmt^[idx] = SearchAddr
|
|
then begin
|
|
{$IFDEF VerboseWSRegistration_methods}
|
|
DebugLn('%sFound at index: %d (v=%p p=%p)', [Indent, idx, Vvmt^[idx], Pvmt^[idx]]);
|
|
{$ENDIF}
|
|
|
|
if Processed[idx]
|
|
then begin
|
|
{$IFDEF VerboseWSRegistration_methods}
|
|
DebugLn(Indent, 'Procesed -> skipping');
|
|
{$ENDIF}
|
|
Break;
|
|
end;
|
|
Processed[idx] := True;
|
|
|
|
if (Vvmt^[idx] = SearchAddr) //original
|
|
and (Pvmt^[idx] <> SearchAddr) //overridden by parent
|
|
then begin
|
|
{$IFDEF VerboseWSRegistration_methods}
|
|
DebugLn('%sUpdating %p -> %p', [Indent, Vvmt^[idx], Pvmt^[idx]]);
|
|
{$ENDIF}
|
|
Vvmt^[idx] := Pvmt^[idx];
|
|
end;
|
|
|
|
Break;
|
|
end;
|
|
if idx = VIRTUAL_VMT_COUNT - 1
|
|
then begin
|
|
DebugLn('[WARNING] VMT entry "', Cmnt^.Entries[n].Name^, '" not found in "', CommonClass.ClassName, '"');
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
CommonClass := Commonclass.ClassParent;
|
|
end;
|
|
|
|
// Adjust classname
|
|
ANode^.VClassName := '(V)' + ANode^.WSClass.ClassName;
|
|
PPointer(ANode^.VClass + vmtClassName)^ := @ANode^.VClassName;
|
|
// Adjust classparent
|
|
PPointer(ANode^.VClass + vmtParent)^ := ParentWSNode^.WSClass;
|
|
// Delete methodtable entry
|
|
PPointer(ANode^.VClass + vmtMethodTable)^ := nil;
|
|
end;
|
|
|
|
procedure UpdateChildren(const ANode: PClassNode; AOldPrivate: TClass);
|
|
var
|
|
Node: PClassNode;
|
|
begin
|
|
Node := ANode^.Child;
|
|
while Node <> nil do
|
|
begin
|
|
if Node^.WSClass <> nil
|
|
then begin
|
|
{$IFDEF VerboseWSRegistration}
|
|
DebugLn('Update VClass for: ', Node^.WSClass.ClassName);
|
|
{$ENDIF}
|
|
CreateVClass(Node, AOldPrivate);
|
|
end;
|
|
UpdateChildren(Node, AOldPrivate);
|
|
Node := Node^.Sibling;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Node: PClassNode;
|
|
OldPrivate: TClass;
|
|
begin
|
|
if MWSRegisterIndex = nil then
|
|
DoInitialization;
|
|
Node := GetNode(AComponent);
|
|
if Node = nil then Exit;
|
|
|
|
if Node^.WSClass = nil
|
|
then MWSRegisterIndex.AddObject(AComponent.ClassName, TObject(Node));
|
|
Node^.WSClass := AWSComponent;
|
|
|
|
// childclasses "inherit" the private from their parent
|
|
// the child privates should only be updated when their private is still
|
|
// the same as their parents
|
|
if Node^.VClass = nil
|
|
then OldPrivate := nil
|
|
else OldPrivate := PClass(Node^.VClass + vmtWSPrivate)^;
|
|
|
|
{$IFDEF VerboseWSRegistration}
|
|
DebugLn('Create VClass for: ', AComponent.ClassName, ' -> ', Node^.WSClass.ClassName);
|
|
{$ENDIF}
|
|
CreateVClass(Node);
|
|
|
|
// Since child classes may depend on us, recreate them
|
|
UpdateChildren(Node, OldPrivate);
|
|
end;
|
|
|
|
|
|
{ TWSLCLComponent }
|
|
|
|
class function TWSLCLComponent.WSPrivate: TWSPrivateClass; //inline;
|
|
begin
|
|
Result := TWSPrivateClass(PClass(Pointer(Self) + vmtWSPrivate)^);
|
|
end;
|
|
|
|
{ TWSLCLHandleComponent }
|
|
|
|
class procedure TWSLCLReferenceComponent.DestroyReference(AComponent: TComponent);
|
|
begin
|
|
end;
|
|
|
|
procedure DoInitialization;
|
|
begin
|
|
MComponentIndex := TStringList.Create;
|
|
MComponentIndex.Sorted := True;
|
|
MComponentIndex.Duplicates := dupError;
|
|
|
|
MWSRegisterIndex := TStringList.Create;
|
|
MWSRegisterIndex.Sorted := True;
|
|
MWSRegisterIndex.Duplicates := dupError;
|
|
end;
|
|
|
|
{$ifdef VerboseWSRegistration_treedump}
|
|
procedure DumpVTree;
|
|
procedure DumpNode(ANode: PClassNode; AIndent: String = '');
|
|
begin
|
|
if ANode = nil then Exit;
|
|
|
|
DbgOut(AIndent);
|
|
|
|
DbgOut('LCLClass=');
|
|
if ANode^.LCLClass = nil
|
|
then DbgOut('nil')
|
|
else DbgOut(ANode^.LCLClass.Classname);
|
|
|
|
DbgOut(' WSClass=');
|
|
if ANode^.WSClass = nil
|
|
then DbgOut('nil')
|
|
else DbgOut(ANode^.WSClass.Classname);
|
|
|
|
DbgOut(' VClass=');
|
|
if ANode^.VClass = nil
|
|
then DbgOut('nil')
|
|
else begin
|
|
DbgOut(TClass(ANode^.VClass).Classname);
|
|
DbgOut(' VClass.Parent=');
|
|
if TClass(ANode^.VClass).ClassParent = nil
|
|
then DbgOut('nil')
|
|
else DbgOut(TClass(ANode^.VClass).ClassParent.ClassName);
|
|
|
|
DbgOut(' Private=');
|
|
if PClass(ANode^.VClass + vmtWSPrivate)^ = nil
|
|
then DbgOut('nil')
|
|
else DbgOut(PClass(ANode^.VClass + vmtWSPrivate)^.ClassName);
|
|
end;
|
|
|
|
DbgOut(' VClassName=''', ANode^.VClassName, '''');
|
|
DebugLn;
|
|
|
|
DumpNode(ANode^.Child, AIndent + ' ');
|
|
|
|
DumpNode(ANode^.Sibling, AIndent);
|
|
end;
|
|
|
|
var
|
|
n: Integer;
|
|
Node: PClassNode;
|
|
begin
|
|
for n := 0 to MComponentIndex.Count - 1 do
|
|
begin
|
|
Node := PClassNode(MComponentIndex.Objects[n]);
|
|
if Node^.Parent = nil
|
|
then DumpNode(Node);
|
|
end;
|
|
end;
|
|
{$endif}
|
|
|
|
procedure DoFinalization;
|
|
var
|
|
n: Integer;
|
|
Node: PClassNode;
|
|
begin
|
|
{$ifdef VerboseWSRegistration_treedump}
|
|
DumpVTree;
|
|
{$endif}
|
|
|
|
for n := 0 to MComponentIndex.Count - 1 do
|
|
begin
|
|
Node := PClassNode(MComponentIndex.Objects[n]);
|
|
if Node^.VClass <> nil
|
|
then Freemem(Node^.VClass);
|
|
Dispose(Node);
|
|
end;
|
|
FreeAndNil(MComponentIndex);
|
|
FreeAndNil(MWSRegisterIndex);
|
|
end;
|
|
|
|
|
|
finalization
|
|
DoFinalization;
|
|
|
|
end.
|