MMObjLst.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:31k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Tel.: +0351-8012255                   =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 20.01.1998 - 18:00:00 $                                      =}
  24. {========================================================================}
  25. unit MMObjLst;
  26. {$I COMPILER.INC}
  27. {*********  Parts from  ****************************}
  28. {                                                   }
  29. {  Delphi Visual Component Library                  }
  30. {                                                   }
  31. {  Copyright (c) 1995 Borland International         }
  32. {                                                   }
  33. {***************************************************}
  34. (* Send bug reports (with reproducable source)     *)
  35. (*    LPL Soft : Robert Daignault                  *)
  36. (*    Compuserve: 70302,1653                       *)
  37. (*                                                 *)
  38. (***************************************************)
  39. interface
  40. uses
  41. {$IFDEF WIN32}
  42.     Windows,
  43. {$ELSE}
  44.     WinTypes,
  45.     WinProcs,
  46. {$ENDIF}
  47.     Classes,
  48.     SysUtils,
  49.     MMObj;
  50. const
  51. { Remmove the following comment if you don't need 16/32 bit stream       }
  52. { compatability In that case, the default list size is 64K objects.      }
  53. { To change, simply edit the cMaxList constant for 32 bit only operation }
  54. {$DEFINE Comp16_32Streams}
  55. {$IFDEF WIN32}
  56.  {$IFDEF Comp16_32Streams}
  57.    cMaxList = MaxListSize;
  58.  {$ELSE}
  59.    cMaxList = $FFFE;   { 32 bit only operation : 64K objects }
  60.  {$ENDIF}
  61. {$ELSE}
  62.    cMaxList = MaxListSize;
  63. {$ENDIF}
  64.    STREAMKENNUNG : Longint = $004A424F; { 'OBJ ' }
  65. type
  66. {$IFDEF WIN32}
  67.  {$IFDEF Comp16_32Streams}
  68.    TOLSize = SmallInt;
  69.  {$ELSE}
  70.    TOLSize = integer;   { 32 bit only operation : 64K objects }
  71.  {$ENDIF}
  72. {$ELSE}
  73.    TOLSize = integer;
  74. {$ENDIF}
  75.  PObjects    = ^TObjects;
  76.  TObjects    = array[0..cMaxList-1] of Pointer;
  77.  {-- TObjectList --------------------------------------------------------}
  78.  TObjectList = class(TMMObject)
  79.  private
  80.     FDestroy    : Boolean;
  81.     FList       : PObjects;
  82.     FCount      : TOLSize;
  83.     FCapacity   : TOLSize;
  84.  protected
  85.     procedure Error; virtual;
  86.     procedure Grow; virtual;
  87.     procedure Put(Index: TOLSize; Item: TObject);virtual;
  88.     function  Get(Index: TOLSize): TObject; virtual;
  89.     procedure SetCapacity(NewCapacity: TOLSize);
  90.     procedure SetCount(NewCount: TOLSize);
  91.     Function  Allocate(Size: LongInt): Pointer;
  92.     Procedure FreeItem(AnItem: Pointer); virtual;
  93.     procedure ReadData(S: TStream); virtual;
  94.     procedure WriteData(S: TStream); virtual;
  95.     procedure DefineProperties(Filer: TFiler); override;
  96.  public
  97.     constructor Create; virtual;
  98.     constructor CreateWithOptions(DestroyObjects: Boolean; InitialCapacity: TOLSize);
  99.     destructor  Destroy; override;
  100.     function    AddObject(Item: TObject): TOLSize; virtual;
  101.     procedure   AddObjects(Objects: TObjectList); virtual;
  102.     { Clear and Delete are identical. They do not Free each object }
  103.     procedure   Clear; virtual;
  104.     procedure   Delete(Index: TOLSize);
  105.     procedure   DeleteAll;
  106.     function    Remove(Item: TObject): TOLSize;
  107.     { Free procedures first destroy tObjects and then call Delete procedures }
  108.     procedure   FreeAll; virtual;
  109.     procedure   FreeAt(Index: TOLSize);
  110.     procedure   FreeObject(Item: TObject);
  111.     function    First: TObject;
  112.     function    Last: TObject;
  113.     function    IndexOf(Item: TObject): TOLSize; virtual;
  114.     procedure   Insert(Index: TOLSize; Item: TObject); virtual;
  115.     procedure   Move(CurIndex, NewIndex: TOLSize);
  116.     procedure   Exchange(Index1, Index2: TOLSize);
  117.     procedure   Pack;
  118.     constructor CreateFromFile(const FileName: string);
  119.     procedure   SaveToFile(const FileName:String);
  120.     procedure   LoadFromFile(const FileName: string);
  121.     property OnChange;
  122.     property OnChanging;
  123.     property DestroyObjects: Boolean read FDestroy write FDestroy;
  124.     property Capacity: TOLSize read FCapacity write SetCapacity;
  125.     property Count: TOLSize read FCount;
  126.     property Items[Index: TOLSize]: TObject read Get write Put; {$IFDEF WIN32}default;{$ENDIF}
  127.   end;
  128.   {-- TSortedObjectList -------------------------------------------------}
  129.   TSortedObjectList = class(TObjectList)
  130.   private
  131.     FDuplicates: TDuplicates;
  132.   protected
  133.     function  KeyOf(Item: TObject): Pointer; virtual;
  134.     procedure Put(Index: TOLSize; Item: TObject); override;
  135.   public
  136.     constructor CreateEx(WithDuplicates: TDuplicates);
  137.     procedure ReadData(S: TStream); override;
  138.     procedure WriteData(S: TStream); override;
  139.     function  Compare(Key1, Key2: Pointer): integer; virtual; abstract;
  140.     function  AddObject(Item: TObject): TOLSize; override;
  141.     function  Search(Key: Pointer; var Index: TOLSize): Boolean;virtual;
  142.     procedure Insert(Index: tOLSize; Item: TObject); override;
  143.     function  IndexOf(Item: TObject): TOLSize; override;
  144.     property  Items[Index: TOLSize]: TObject read Get;
  145.     property  Duplicates: TDuplicates read FDuplicates;
  146.   end;
  147.   { Specialized memory Stream. Will Stream to a fixed memory buffer }
  148.   { Mainly used when storing objects into a Object database record  }
  149.   { NOTE: the memory is not freed. That is your job!                }
  150.   { An exception will be raised if an operation causes the stream   }
  151.   { position to go behond it's max size                             }
  152.   TAbsMemStream = class(TStream)
  153.   private
  154.     FMemory: Pointer;
  155.     FSize,
  156.     FPosition: Longint;
  157.   public
  158.     Constructor Create(UseBuf: Pointer; MaxSize: LongInt);
  159.     function Read(var Buffer; Count: Longint): Longint; override;
  160.     function Write(const Buffer; Count: Longint): Longint; override;
  161.     function Seek(Offset: Longint; Origin: Word): Longint; override;
  162.     property Position: LongInt read FPosition;
  163.     property Memory: Pointer read FMemory;
  164.     property Size: Longint read FSize;
  165.   end;
  166. { Streaming registration support }
  167. Procedure  DoRegisterClass(const LoadProc,StoreProc:Pointer;Sender:tClass);
  168. Function   IsRegistered(AClass:tClass):Boolean;
  169. (******************************************************)
  170. (* Misc. Usefull tools enabled by registering classes *)
  171. (******************************************************)
  172. Procedure  WriteObjectToStream(Source: TObject; S: TStream);
  173. Function   ReadObjectFromStream(S: TStream): TObject;
  174. (* CopyOf creates and returns a new instance of Source *)
  175. Function   CopyOf(Source: TObject): TObject;
  176. (*******************************************************)
  177. (* Clipboard related functions. Cut & paste tObjects!  *)
  178. (*******************************************************)
  179. Function RegisterClipBoardType(const TypeName:String):Word;
  180.   (* Use the result of RegisterClipBoardType as the ClipType
  181.     Parameter to the 2 following procedures   *)
  182. Function CopyObjectToClipboard(ClipType: Word; Source: TObject): Boolean;
  183. Function PasteObjectFromClipboard(ClipType: Word): TObject;
  184. {========================================================================}
  185. implementation
  186. {========================================================================}
  187. Uses
  188.     Consts
  189.     {$IFDEF DELPHI6}
  190.     ,RTLConsts
  191.     {$ENDIF}
  192.     ;
  193. type
  194.     TClassName = String[63];
  195.     TRegisterRec = class(TObject)
  196.       Obj: TClass; { Class type }
  197.       { This is a pointer because otherwise a
  198.          class instance would be required to register }
  199.       DoLoad,
  200.       DoStore : Pointer;
  201.       Constructor Create(aClass: TClass; Loader, Storer: Pointer);
  202.  end;
  203. var
  204.    ClassRegistry: TStringList;
  205. {========================================================================}
  206. constructor TRegisterRec.Create(aClass: TClass; Loader, Storer:Pointer);
  207. begin
  208.    inherited Create;
  209.    Obj := aClass;
  210.    DoLoad := Loader;
  211.    DoStore := Storer;
  212. end;
  213. {========================================================================}
  214. procedure DoRegisterClass(const LoadProc,StoreProc:Pointer;Sender:TClass);
  215. begin
  216.    ClassRegistry.AddObject(Sender.ClassName,
  217.                  TRegisterRec.Create(Sender,LoadProc,StoreProc));
  218. end;
  219. {========================================================================}
  220. function IsRegistered(aClass: TClass): Boolean;
  221. Var
  222.    Index: Integer;
  223. begin
  224.    Result := ClassRegistry.Find(aClass.ClassName,Index);
  225. end;
  226. {========================================================================}
  227. function GetRegistration(aName: TClassName): TRegisterRec;
  228. Var
  229.    Index: Integer;
  230. begin
  231.    with ClassRegistry do
  232.    if Find(aName,Index) then
  233.       Result := TRegisterRec(Objects[Index])
  234.    else
  235.       Result := nil;
  236. end;
  237. {========================================================================}
  238. function CreateInstanceByName(const Name: TClassName; var Loader: Pointer): TObject;
  239. var
  240.    R: TRegisterRec;
  241. begin
  242.    R := GetRegistration(Name);
  243.    If R <> nil then
  244.    begin
  245.       Result := R.Obj.Create;
  246.       Loader := R.DoLoad;
  247.    end
  248.    else raise EClassNotFound.CreateFmt('Class <%s> not registered',[Name]);
  249. end;
  250. {========================================================================}
  251. procedure CallStreamProc(Obj: TObject; S: TStream; SProc: Pointer);
  252. begin
  253.    asm
  254.       {$IFNDEF WIN32}
  255.       les    di,S
  256.       push   es
  257.       push   di
  258.       les    di,Obj
  259.       push   es
  260.       push   di
  261.       call   DWord ptr SProc; { Call Obj's Load or Store proc }
  262.       {$ELSE}
  263.       {  In delphi32 : using registers calling
  264.       EAX = pointer to Obj
  265.       EDX = pointer to S
  266.       ECX = SProc }
  267.       call   ecx
  268.       {$ENDIF}
  269.    end;
  270. end;
  271. {========================================================================}
  272. function CopyOf(Source: TObject): TObject;
  273. Var
  274.    S: TMemoryStream;
  275. begin
  276.    if Source <> nil then 
  277.    begin
  278.       S := TMemoryStream.Create;
  279.       try
  280.          WriteObjectToStream(Source,S);
  281.          S.Seek(0,0);    { Rewind to beginning }
  282.          Result := ReadObjectFromStream(S);
  283.       finally
  284.         S.Free;
  285.       end;
  286.    end
  287.    else raise EClassNotFound.Create('Nil Source Class!');
  288. end;
  289. {========================================================================}
  290. function ReadObjectFromStream(S: TStream): TObject;
  291. var
  292.    Name: TClassName;
  293.    LoadProc: Pointer;
  294. begin
  295.    { Read the object name }
  296.    S.ReadBuffer(Name[0],1);
  297.    S.ReadBuffer(Name[1],Ord(Name[0]));
  298.    { If Name is valid (registered)... }
  299.    Result:=CreateInstanceByName(Name,LoadProc);
  300.    { Then ask it to load itself }
  301.    CallStreamProc(Result,S,LoadProc);
  302. end;
  303. {========================================================================}
  304. procedure WriteObjectToStream(Source: TObject; S: TStream);
  305. Var
  306.    R: TRegisterRec;
  307.    Name: TClassName;
  308. begin
  309.    If Source <> nil then
  310.    begin
  311.       Name := Source.ClassName;
  312.       R := GetRegistration(Name);
  313.       if R = nil then
  314.          raise EClassNotFound.CreateFmt('Source Class <%s> not registered',[Name]);
  315.       { First write out the object name }
  316.       S.WriteBuffer(Name,Length(Name)+1);
  317.       { And ask the object to write itself to S }
  318.       CallStreamProc(Source,S,R.DoStore); { S now contains Source }
  319.    end
  320.    else raise EClassNotFound.Create('Nil Source Class!');
  321. end;
  322. {== TObjectList =========================================================}
  323. constructor TObjectList.Create;
  324. begin
  325.    inherited Create;
  326.    FCount := 0;
  327.    FCapacity := 0;
  328.    FDestroy := True;
  329. end;
  330. {-- TObjectList ---------------------------------------------------------}
  331. constructor TObjectList.CreateWithOptions(DestroyObjects: Boolean;
  332.                                           InitialCapacity: TOLSize);
  333. begin
  334.    Create;
  335.    FDestroy := DestroyObjects;
  336.    SetCapacity(InitialCapacity);
  337. end;
  338. {-- TObjectList ---------------------------------------------------------}
  339. constructor TObjectList.CreateFromFile(const FileName: string);
  340. begin
  341.    Create;
  342.    LoadFromFile(FileName);
  343. end;
  344. {-- TObjectList ---------------------------------------------------------}
  345. destructor TObjectList.Destroy;
  346. begin
  347.    OnChange := nil;
  348.    OnChanging := nil;
  349.    FreeAll;
  350.    Clear;
  351.    inherited Destroy;
  352. end;
  353. {-- TObjectList ---------------------------------------------------------}
  354. function TObjectList.AddObject(Item: TObject): TOLSize;
  355. begin
  356.    Result := FCount;
  357.    Insert(Result, Item);
  358. end;
  359. {-- TObjectList ---------------------------------------------------------}
  360. procedure TObjectList.AddObjects(Objects: TObjectList);
  361. var
  362.    i: integer;
  363. begin
  364.    BeginUpdate;
  365.    try
  366.       for i := 0 to Objects.Count-1 do
  367.           AddObject(Objects.Items[i]);
  368.    finally
  369.       EndUpdate;
  370.    end;
  371. end;
  372. {-- TObjectList ---------------------------------------------------------}
  373. procedure TObjectList.Clear;
  374. begin
  375.    { Clear does not free it's objects. It's the same as calling DeleteAll }
  376.    if FCount <> 0 then
  377.    begin
  378.       Changing;
  379.       SetCount(0);
  380.       SetCapacity(0);
  381.       Changed;
  382.    end;
  383. end;
  384. {-- TObjectList ---------------------------------------------------------}
  385. Procedure TObjectList.FreeItem(AnItem: Pointer);
  386. begin
  387.    { Overwrite if Items are not objects }
  388.    if FDestroy then TObject(AnItem).Free;
  389. end;
  390. {-- TObjectList ---------------------------------------------------------}
  391. function TObjectList.Remove(Item: TObject): TOLSize;
  392. begin
  393.    Result := IndexOf(Item);
  394.    if Result <> -1 then Delete(Result);
  395. end;
  396. {-- TObjectList ---------------------------------------------------------}
  397. procedure TObjectList.Delete(Index: TOLSize);
  398. begin
  399.    if (Index < 0) or (Index >= FCount) then Error;
  400.    Changing;
  401.    dec(FCount);
  402.    if Index < FCount then
  403.       System.Move(FList^[Index+1], FList^[Index],
  404.                  (FCount-Index)*SizeOf(TObject));
  405.    Changed;
  406. end;
  407. {-- TObjectList ---------------------------------------------------------}
  408. procedure TObjectList.DeleteAll;
  409. begin
  410.    Clear;
  411. end;
  412. {-- TObjectList ---------------------------------------------------------}
  413. procedure TObjectList.FreeAt(Index: TOLSize);
  414. begin
  415.    if (Index < 0) or (Index >= FCount) then Error;
  416.    FreeItem(FList^[Index]);
  417.    Delete(Index);
  418. end;
  419. {-- TObjectList ---------------------------------------------------------}
  420. procedure TObjectList.FreeAll;
  421. var
  422.    Index: TOLSize;
  423. begin
  424.    for Index := 0 to FCount-1 do
  425.        FreeItem(FList^[Index]);
  426.    Clear;
  427. end;
  428. {-- TObjectList ---------------------------------------------------------}
  429. procedure TObjectList.FreeObject(Item: TObject);
  430. begin
  431.    try
  432.       FreeAt(IndexOf(Item));
  433.    except
  434.       on EListError do
  435.          raise EListError.CreateFmt('TObject %s not in item list',[Item.ClassName]);
  436.    end;
  437. end;
  438. {-- TObjectList ---------------------------------------------------------}
  439. procedure TObjectList.Error;
  440. begin
  441.    raise EListError.Create({$IFDEF DELPHI3}SListIndexError{$ELSE}LoadStr(SListIndexError){$ENDIF});
  442. end;
  443. {-- TObjectList ---------------------------------------------------------}
  444. function TObjectList.First: TObject;
  445. begin
  446.    Result := Get(0);
  447. end;
  448. {-- TObjectList ---------------------------------------------------------}
  449. function TObjectList.Last: TObject;
  450. begin
  451.    Result := Get(FCount - 1);
  452. end;
  453. {-- TObjectList ---------------------------------------------------------}
  454. function TObjectList.Get(Index: TOLSize): TObject;
  455. begin
  456.    if (Index < 0) or (Index >= FCount) then Error;
  457.    Result := FList^[Index];
  458. end;
  459. {-- TObjectList ---------------------------------------------------------}
  460. procedure TObjectList.Grow;
  461. Var
  462.    Delta: TOLSize;
  463. begin
  464.    if FCapacity > 8 then Delta := 16
  465.    else if FCapacity > 4 then Delta := 8
  466.    else Delta := 4;
  467.    SetCapacity(FCapacity+Delta);
  468. end;
  469. {-- TObjectList ---------------------------------------------------------}
  470. function TObjectList.IndexOf(Item: TObject): TOLSize;
  471. begin
  472.    Result := 0;
  473.    while (Result < FCount) and (FList^[Result] <> Item) do Inc(Result);
  474.    if Result = FCount then Result := -1;
  475. end;
  476. {-- TObjectList ---------------------------------------------------------}
  477. procedure TObjectList.Insert(Index: TOLSize; Item: TObject);
  478. begin
  479.    if (Index < 0) or (Index > FCount) then Error;
  480.    Changing;
  481.    if FCount = FCapacity then Grow;
  482.    if Index < FCount then
  483.    begin
  484.       System.Move(FList^[Index], FList^[Index+1],
  485.                   (FCount-Index)*SizeOf(TObject));
  486.    end;
  487.    FList^[Index] := Item;
  488.    inc(FCount);
  489.    Changed;
  490. end;
  491. {-- TObjectList ---------------------------------------------------------}
  492. procedure TObjectList.Exchange(Index1, Index2: TOLSize);
  493. var
  494.   Item: TObject;
  495. begin
  496.    if (Index1 <> Index2) then
  497.    begin
  498.       if (Index1 < 0) or (Index1 >= FCount) or
  499.          (Index2 < 0) or (Index2 >= FCount) then Error;
  500.       Changing;
  501.       Item := FList^[Index1];
  502.       FList^[Index1] := FList^[Index2];
  503.       FList^[Index2] := Item;
  504.       Changed;
  505.    end;
  506. end;
  507. {-- TObjectList ---------------------------------------------------------}
  508. procedure TObjectList.Move(CurIndex, NewIndex: TOLSize);
  509. var
  510.    Item: TObject;
  511. begin
  512.    if CurIndex <> NewIndex then
  513.    begin
  514.       if (NewIndex < 0) or (NewIndex >= FCount) then Error;
  515.       Item := Get(CurIndex);
  516.       Delete(CurIndex);
  517.       Insert(NewIndex, Item);
  518.    end;
  519. end;
  520. {-- TObjectList ---------------------------------------------------------}
  521. procedure TObjectList.Put(Index: TOLSize; Item: TObject);
  522. begin
  523.    if (Index < 0) or (Index >= FCount) then Error;
  524.    FList^[Index] := Item;
  525. end;
  526. {-- TObjectList ---------------------------------------------------------}
  527. procedure TObjectList.Pack;
  528. var
  529.    i: Integer;
  530. begin
  531.    for i := FCount-1 downto 0 do if Items[i] = nil then Delete(i);
  532. end;
  533. {-- TObjectList ---------------------------------------------------------}
  534. procedure TObjectList.SetCapacity(NewCapacity: TOLSize);
  535. var
  536.    NewList: PObjects;
  537. begin
  538.    if (NewCapacity <> FCapacity) then
  539.    begin
  540.       if (NewCapacity < FCount) or (integer(NewCapacity)>=cMaxList) then Error;
  541.       if NewCapacity = 0 then NewList := nil
  542.       else
  543.       begin
  544.          NewList := Allocate(NewCapacity * SizeOf(tObject));
  545.          if FCount <> 0 then System.Move(FList^, NewList^, FCount * SizeOf(tObject));
  546.       end;
  547.       if FCapacity <> 0 then FreeMem(FList, FCapacity * SizeOf(tObject));
  548.       FList := NewList;
  549.       FCapacity := NewCapacity;
  550.    end;
  551. end;
  552. {-- TObjectList ---------------------------------------------------------}
  553. procedure TObjectList.SetCount(NewCount: TOLSize);
  554. begin
  555.    if (NewCount < 0) or (integer(NewCount) >= cMaxList) then Error;
  556.    if NewCount > FCapacity then SetCapacity(NewCount);
  557.    if NewCount > FCount then
  558.       FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(TObject), 0);
  559.    FCount := NewCount;
  560. end;
  561. {-- TObjectList ---------------------------------------------------------}
  562. procedure TObjectList.DefineProperties(Filer: TFiler);
  563. begin
  564.    Filer.DefineBinaryProperty('ObjectContainer', ReadData, WriteData, FCount>0);
  565. end;
  566. {-- TObjectList ---------------------------------------------------------}
  567. procedure TObjectList.ReadData(S: TStream);
  568. Var
  569.    ObjCount,
  570.    Index: TOLSize;
  571.    Kennung: Longint;
  572. begin
  573.    BeginUpdate;
  574.    try
  575.       S.ReadBuffer(Kennung,sizeOf(STREAMKENNUNG));
  576.       if (Kennung <> STREAMKENNUNG) then
  577.          raise EStreamError.Create('Invalid Object stream');
  578.       FreeAll;
  579.       { load stream items }
  580.       S.ReadBuffer(FDestroy,SizeOf(FDestroy));
  581.       S.ReadBuffer(ObjCount,SizeOf(Objcount));  { Read in Object count }
  582.       if FCapacity-FCount < ObjCount then SetCapacity(FCount+ObjCount);
  583.       { Read in Object Count }
  584.       for Index := 0 to ObjCount-1 do
  585.           AddObject(ReadObjectFromStream(S));
  586.    finally
  587.       EndUpdate;
  588.    end;
  589. end;
  590. {-- TObjectList ---------------------------------------------------------}
  591. procedure TObjectList.WriteData(S: TStream);
  592. var
  593.    Index,
  594.    ObjCount: TOlSize;
  595. begin
  596.    { Write list to Stream }
  597.    S.WriteBuffer(STREAMKENNUNG,SizeOf(STREAMKENNUNG));
  598.    S.WriteBuffer(FDestroy,SizeOf(FDestroy));
  599.    ObjCount := FCount;
  600.    S.WriteBuffer(ObjCount,SizeOf(ObjCount));
  601.    for Index := 0 to FCount-1 do
  602.        WriteObjectToStream(Items[Index],S);
  603. end;
  604. {-- TObjectList ---------------------------------------------------------}
  605. procedure TObjectList.SaveToFile(const FileName: String);
  606. Var
  607.    S: TFileStream;
  608. begin
  609.    { Will create Filename and overwrite any existing file
  610.      of the same name                                     }
  611.    S := TFileStream.Create(FileName,fmCreate);
  612.    try
  613.       WriteData(S);
  614.    finally
  615.       S.Free;
  616.    end;
  617. end;
  618. {-- TObjectList ---------------------------------------------------------}
  619. procedure TObjectList.LoadFromFile(const FileName: string);
  620. Var
  621.    S: TFileStream;
  622. begin
  623.    { LoadFromStream will add the Stream's content to it's current items }
  624.    S := TFileStream.Create(FileName,fmOpenRead);
  625.    try
  626.       try
  627.          ReadData(S)
  628.       except
  629.          raise EStreamError.Create('Unable to load Object stream');
  630.       end;
  631.    finally
  632.       S.Free;
  633.    end;
  634. end;
  635. {-- TObjectList ---------------------------------------------------------}
  636. function TObjectList.Allocate(Size: LongInt): Pointer;
  637. begin
  638.    GetMem(Result,Size);
  639. end;
  640. {== TSortedList =========================================================}
  641. constructor TSortedObjectList.CreateEx(WithDuplicates: TDuplicates);
  642. begin
  643.   inherited Create;
  644.   FDuplicates:=WithDuplicates;
  645. end;
  646. {-- TSortedObjectList ---------------------------------------------------}
  647. procedure TSortedObjectList.ReadData(S: TStream);
  648. Var
  649.    ObjCount,
  650.    Index: TOLSize;
  651.    Kennung: Longint;
  652. begin
  653.    BeginUpdate;
  654.    try
  655.       S.ReadBuffer(Kennung,sizeOf(STREAMKENNUNG));
  656.       if (Kennung <> STREAMKENNUNG) then
  657.          raise EStreamError.Create('Invalid Object stream');
  658.       FreeAll;
  659.       { load stream items }
  660.       S.ReadBuffer(FDuplicates,sizeof(FDuplicates));
  661.       S.ReadBuffer(FDestroy,SizeOf(FDestroy));
  662.       S.ReadBuffer(ObjCount,SizeOf(Objcount));  { Read in Object count }
  663.       if FCapacity-FCount < ObjCount then SetCapacity(FCount+ObjCount);
  664.       { Read in Object Count }
  665.       for Index := 0 to ObjCount-1 do
  666.           AddObject(ReadObjectFromStream(S));
  667.    finally
  668.       EndUpdate;
  669.    end;
  670. end;
  671. {-- TSortedObjectList ---------------------------------------------------}
  672. procedure TSortedObjectList.WriteData(S: TStream);
  673. var
  674.    Index,
  675.    ObjCount: TOlSize;
  676. begin
  677.    { Write list to Stream }
  678.    S.WriteBuffer(STREAMKENNUNG,SizeOf(STREAMKENNUNG));
  679.    S.WriteBuffer(FDuplicates,sizeof(FDuplicates));
  680.    S.WriteBuffer(FDestroy,SizeOf(FDestroy));
  681.    ObjCount := FCount;
  682.    S.WriteBuffer(ObjCount,SizeOf(ObjCount));
  683.    for Index := 0 to FCount-1 do
  684.        WriteObjectToStream(Items[Index],S);
  685. end;
  686. {-- TSortedObjectList ---------------------------------------------------}
  687. function TSortedObjectList.AddObject(Item: TObject): TOLSize;
  688. begin
  689.    Insert(-1, Item);
  690.    Result := IndexOf(Item);
  691. end;
  692. {-- TSortedObjectList ---------------------------------------------------}
  693. procedure TSortedObjectList.Insert(Index: TOLSize; Item: TObject);
  694. begin
  695.    { ignores the Index-Value! }
  696.    if Search(KeyOf(Item),Index) then
  697.    case FDuplicates of
  698.       DupIgnore: Exit;
  699.       DupError : raise EListError.Create('Duplicate Object index');
  700.    end;
  701.    inherited Insert(Index,Item);
  702. end;
  703. {-- TSortedObjectList ---------------------------------------------------}
  704. function TSortedObjectList.KeyOf(Item: TObject): Pointer;
  705. begin
  706.    Result := Item;
  707. end;
  708. {-- TSortedObjectList ---------------------------------------------------}
  709. function TSortedObjectList.IndexOf(Item: TObject): TOLSize;
  710. begin
  711.    if not Search(KeyOf(Item),Result) then Result := -1;
  712. end;
  713. {-- TSortedObjectList ---------------------------------------------------}
  714. function TSortedObjectList.Search(Key: Pointer; var Index: TOLSize): Boolean;
  715. var
  716.   L, H, I, C: TOLSize;
  717. begin
  718.    Result := False;
  719.    L := 0;
  720.    H := Count - 1;
  721.    while L <= H do
  722.    begin
  723.       I := (L + H) shr 1;
  724.       C := Compare(KeyOf(Items[I]), Key);
  725.       if C < 0 then L := I + 1
  726.       else
  727.       begin
  728.          H := I - 1;
  729.          if C = 0 then
  730.          begin
  731.             Result := True;
  732.             if Duplicates <> dupAccept then L := I;
  733.          end;
  734.       end;
  735.    end;
  736.    Index := L;
  737. end;
  738. {-- TSortedObjectList ---------------------------------------------------}
  739. procedure TSortedObjectList.Put(Index: TOLSize; Item: TObject);
  740. begin
  741.    raise EListError.Create('Cannot <Put> an Object in a sorted list!');
  742. end;
  743. {$IFNDEF WIN32}
  744. procedure __AHSHIFT; far; external 'KERNEL' index 113;
  745. function OffsetPointer(P: Pointer; Ofs: Longint): Pointer; assembler;
  746. asm
  747.         MOV     AX,Ofs.Word[0]
  748.         MOV     DX,Ofs.Word[2]
  749.         ADD     AX,P.Word[0]
  750.         ADC     DX,0
  751.         MOV     CX,OFFSET __AHSHIFT
  752.         SHL     DX,CL
  753.         ADD     DX,P.Word[2]
  754. end;
  755. {$ENDIF}
  756. {== TAbsMemStream =======================================================}
  757. constructor TAbsMemStream.Create(UseBuf: Pointer; MaxSize: LongInt);
  758. begin
  759.    inherited Create;
  760.    FMemory := UseBuf;
  761.    FSize := MaxSize;
  762.    FPosition := 0;
  763. end;
  764. {-- TAbsMemStream -------------------------------------------------------}
  765. function TAbsMemStream.Read(var Buffer; Count: Longint): Longint;
  766. begin
  767.    if (FPosition >= 0) and (Count >= 0) then
  768.    begin
  769.       Result := FSize - FPosition; { Remaining buffer }
  770.       if Result >= Count then
  771.          Result := Count
  772.       else
  773.          raise EStreamError.Create('MemStream reading behond limits');
  774.       {$IFNDEF WIN32}
  775.       hmemcpy(@Buffer, OffsetPointer(FMemory, FPosition), Result);
  776.       {$ELSE}
  777.       Move(Pointer(Longint(FMemory) + FPosition)^, Buffer, Result);
  778.       {$ENDIF}
  779.       inc(FPosition, Result);
  780.    end
  781.    else Result := 0;
  782. end;
  783. {-- TAbsMemStream -------------------------------------------------------}
  784. function TAbsMemStream.Write(const Buffer; Count: Longint): Longint;
  785. var
  786.    Pos: Longint;
  787. begin
  788.    if (FPosition >= 0) and (Count >= 0) then
  789.    begin
  790.       Pos := FPosition + Count; { Ending FPosition }
  791.       if (Pos>=FSize) then
  792.          raise EStreamError.Create('MemStream writing behond limits');
  793.       {$IFNDEF WIN32}
  794.       hmemcpy(OffsetPointer(FMemory, FPosition), @Buffer, Count);
  795.       {$ELSE}
  796.       Move(Buffer, Pointer(Longint(FMemory) + FPosition)^, Count);
  797.       {$ENDIF}
  798.       FPosition := Pos;
  799.       Result := Count;
  800.    end
  801.    else Result := 0;
  802. end;
  803. {-- TAbsMemStream -------------------------------------------------------}
  804. function TAbsMemStream.Seek(Offset: Longint; Origin: Word): Longint;
  805. begin
  806.    case Origin of
  807.       0: FPosition := Offset;
  808.       1: Inc(FPosition, Offset);
  809.       2: FPosition := FSize - Offset;
  810.    end;
  811.    if (FPosition>FSize) Or (FPosition<0) then
  812.       raise EStreamError.Create('MemStream seeking behond limits');
  813.    Result := FPosition;
  814. end;
  815. {========================================================================}
  816. (* Clipboard related *)
  817. Function RegisterClipBoardType(const TypeName: String): Word;
  818. Var
  819.    Name: PChar;
  820. begin
  821.    GetMem(Name,Length(TypeName)+1);
  822.    StrpCopy(Name,TypeName);
  823.    Result := RegisterClipBoardFormat(Name);
  824.    FreeMem(Name,Length(TypeName)+1);
  825. end;
  826. {========================================================================}
  827. function CopyObjectToClipboard(ClipType: word; Source:TObject): Boolean;
  828. var
  829.    S: TMemoryStream;
  830.    MemHandle: THandle;
  831.    MemPtr: Pointer;
  832. begin
  833.    if Source<>nil then
  834.    begin
  835.       Result:=False;
  836.       S := TMemoryStream.Create;
  837.       try
  838.          WriteObjectToStream(Source,S);
  839.          S.Seek(0,0);                         { Rewind to beginning }
  840.          MemHandle := GlobalAlloc(GHND,S.Size); { allocate memory }
  841.          if MemHandle = 0 then
  842.             raise EOutOfMemory.Create('Not enough memory to copy object to clipboard');
  843.             MemPtr:=GlobalLock(MemHandle);
  844.          S.Read(MemPtr^,S.Size);{ read in the stream contents into MemPtr}
  845.          GlobalUnlock(MemHandle);
  846.          if SetClipboardData(ClipType, MemHandle) = 0 then
  847.             GlobalFree(MemHandle)
  848.          else
  849.             Result := True;
  850.             
  851.       finally
  852.          S.Free;
  853.       end;
  854.    end
  855.    else raise EClassNotFound.Create('Nil Source Class!');
  856. end;
  857. {========================================================================}
  858. function PasteObjectFromClipboard(ClipType: word): TObject;
  859. var
  860.    MemHandle:THandle;
  861.    clipData:Pointer;
  862.    ClipSize:longint;
  863.    S: TAbsMemStream;
  864. begin
  865.    Result := nil;
  866.    MemHandle := GetClipBoardData(ClipType);
  867.    if MemHandle <> 0 then
  868.    begin
  869.       ClipSize := GlobalSize(MemHandle);
  870.       ClipData := GlobalLock(MemHandle);
  871.       S := TAbsMemStream.Create(ClipData,ClipSize);
  872.       try
  873.          Result := ReadObjectFromStream(S);
  874.       finally
  875.          GlobalUnlock(MemHandle);
  876.          S.Free;
  877.       end;
  878.    end;
  879. end;
  880. {========================================================================}
  881. Procedure TContainExitProc; far;
  882. Var
  883.    Idx:Integer;
  884. begin
  885.    for Idx := 0 to ClassRegistry.Count-1 do
  886.        (ClassRegistry.Objects[Idx] as TRegisterRec).Free;
  887.    ClassRegistry.Free;
  888. end;
  889. {========================================================================}
  890. Initialization
  891.    ClassRegistry := TStringList.Create;
  892.    ClassRegistry.Sorted := True;
  893.    ClassRegistry.Duplicates := dupIgnore;
  894.    {$IFNDEF WIN32}
  895.    AddExitProc(TContainExitProc);
  896.    {$ENDIF}
  897. {$IFDEF WIN32}
  898. Finalization
  899.   TContainExitProc;
  900. {$ENDIF}
  901. end.