lazarus/lcl/widgetset/wslclclasses.pp
paul f02c53c71c merge lcl-smartlink branch:
------------------------------------------------------------------------
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 -
2009-04-12 08:46:31 +00:00

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.