Browse Source

--- Merging r42594 into '.':
U packages/winunits-base/src/comobj.pp
U packages/winunits-base/src/comserv.pp
--- Recording mergeinfo for merge of r42594 into '.':
U .
--- Merging r42908 into '.':
U packages/fcl-stl/doc/hashmapexample.pp
U packages/fcl-stl/src/ghashmap.pp
--- Recording mergeinfo for merge of r42908 into '.':
G .
--- Merging r42909 into '.':
G packages/fcl-stl/src/ghashmap.pp
U packages/fcl-stl/src/gvector.pp
--- Recording mergeinfo for merge of r42909 into '.':
G .
--- Merging r42910 into '.':
U packages/fcl-stl/doc/mapexample.pp
U packages/fcl-stl/src/gmap.pp
--- Recording mergeinfo for merge of r42910 into '.':
G .
--- Merging r42914 into '.':
U packages/chm/src/chmreader.pas
--- Recording mergeinfo for merge of r42914 into '.':
G .
--- Merging r42915 into '.':
U packages/fcl-stl/src/ghashset.pp
U packages/fcl-stl/src/gset.pp
--- Recording mergeinfo for merge of r42915 into '.':
G .

# revisions: 42594,42908,42909,42910,42914,42915

git-svn-id: branches/fixes_3_2@42922 -

marco 6 years ago
parent
commit
c07b8a1954

+ 3 - 2
packages/chm/src/chmreader.pas

@@ -115,6 +115,7 @@ type
     procedure ReadCommonData;
     function  ReadStringsEntry(APosition: DWord): String;
     function  ReadStringsEntryFromStream ( strm:TStream ) : String;
+    { Return LocalUrl string from #URLSTR }
     function  ReadURLSTR(APosition: DWord): String;
     function  CheckCommonStreams: Boolean;
     procedure ReadWindows(mem:TMemoryStream);
@@ -489,8 +490,8 @@ begin
   fURLTBLStream.ReadDWord; // unknown
   fURLTBLStream.ReadDWord; // TOPIC index #
   fURLSTRStream.Position := LEtoN(fURLTBLStream.ReadDWord);
-  fURLSTRStream.ReadDWord;
-  fURLSTRStream.ReadDWord;
+  fURLSTRStream.ReadDWord; // URL
+  fURLSTRStream.ReadDWord; // FrameName
   if fURLSTRStream.Position < fURLSTRStream.Size-1 then
     Result := PChar(fURLSTRStream.Memory+fURLSTRStream.Position);
 end;

+ 7 - 7
packages/fcl-stl/doc/hashmapexample.pp

@@ -1,5 +1,7 @@
 {$mode objfpc}
 
+{define oldstyleiterator}
+
 uses ghashmap;
 
 type hashlli=class
@@ -13,7 +15,8 @@ begin
   hash:= a mod b;
 end;
 
-var data:maplli; i:longint; iterator:maplli.TIterator;
+var data:maplli; i:longint;
+    pair : maplli.TPair;
 
 begin
   data:=maplli.Create;
@@ -24,12 +27,9 @@ begin
   data.delete(5);
 
   {Iteration through elements}
-  iterator:=data.Iterator;
-  repeat
-    writeln(iterator.Key, ' ', iterator.Value);
-  until not iterator.Next;
-  {Don't forget to destroy iterator}
-  iterator.Destroy;
+  // destroying class iterators is afaik a FPC extension.
+  for pair in data do
+    writeln(pair.Key, ' ', pair.Value);
 
   data.Destroy;
 end.

+ 6 - 2
packages/fcl-stl/doc/mapexample.pp

@@ -4,7 +4,7 @@ type lesslli=specialize TLess<longint>;
      maplli=specialize TMap<longint, longint, lesslli>;
 
 var data:maplli; i:longint; iterator:maplli.TIterator;
-
+    pair : maplli.TPair;
 begin
   data:=maplli.Create;
 
@@ -14,7 +14,7 @@ begin
   writeln(data[7]);
   data[7] := 42;
 
-  {Iteration through elements}
+  {Iteration through elements with write access}
   iterator:=data.Min;
   repeat
     writeln(iterator.Key, ' ', iterator.Value);
@@ -22,6 +22,10 @@ begin
   until not iterator.next;
   iterator.Destroy;
 
+  // using for..in to check everything changed to 47. For in is shorter and autoallocated, but can't write to cells via iterator.
+  for pair in data.min do
+    writeln('Min: ',pair.Key, ' ', pair.Value);         
+
   iterator := data.FindLess(7);
   writeln(iterator.Value);
   iterator.Destroy;

+ 59 - 26
packages/fcl-stl/src/ghashmap.pp

@@ -38,25 +38,33 @@
   }
 
   type
-    generic THashmapIterator<TKey, TValue, T, TTable>=class
-      public
-      type PValue=^TValue;
-      var
-        Fh,Fp:SizeUInt;
-        FData:TTable;
-        function Next:boolean;inline;
-        function Prev:boolean;inline;
-        function GetData:T;inline;
-        function GetKey:TKey;inline;
-        function GetValue:TValue;inline;
-        function GetMutable:PValue;inline;
-        procedure SetValue(value:TValue);inline;
-        property Data:T read GetData;
-        property Key:TKey read GetKey;
-        property Value:TValue read GetValue write SetValue;
-        property MutableValue:PValue read GetMutable;
-    end;
 
+    { THashmapIterator }
+
+    generic THashmapIterator<TKey, TValue, T, TTable>=class
+         public
+         type PValue=^TValue;
+              TIntIterator = specialize THashmapIterator<TKey, TValue, T, TTable>;
+         var
+           Fh,Fp:SizeUInt;
+           FData:TTable;
+           function Next:boolean;inline;
+           function MoveNext:boolean;inline;
+           function Prev:boolean;inline;
+           function GetData:T;inline;
+           function GetKey:TKey;inline;
+           function GetValue:TValue;inline;
+           function GetMutable:PValue;inline;
+           procedure SetValue(value:TValue);inline;
+           function GetEnumerator : TIntIterator; inline;
+           property Data:T read GetData;
+           property Key:TKey read GetKey;
+           property Value:TValue read GetValue write SetValue;
+           property MutableValue:PValue read GetMutable;
+           property Current : T read GetData;
+       end;
+
+    { THashmap }
     generic THashmap<TKey, TValue, Thash>=class
       public
       type
@@ -76,20 +84,19 @@
       public 
       type
         TIterator = specialize THashmapIterator<TKey, TValue, TPair, TTable>;
-        constructor create;
-        destructor destroy;override;
+        constructor Create;
+        destructor Destroy;override;
         procedure insert(key:TKey;value:TValue);inline;
         function contains(key:TKey):boolean;inline;
-        function size:SizeUInt;inline;
+        function Size:SizeUInt;inline;
         procedure delete(key:TKey);inline;
         procedure erase(iter:TIterator);inline;
         function IsEmpty:boolean;inline;
         function GetData(key:TKey):TValue;inline;
         function GetValue(key:TKey;out value:TValue):boolean;inline;
-
-        property Items[i : TKey]: TValue read GetData write Insert; default;
-
         function Iterator:TIterator;
+        function getenumerator :TIterator;
+        property Items[i : TKey]: TValue read GetData write Insert; default;
   end;
 
 implementation
@@ -111,7 +118,7 @@ begin
   FData.Destroy;
 end;
 
-function THashmap.IsEmpty(): boolean;
+function THashmap.IsEmpty: boolean;
 begin
   IsEmpty := Size()=0;
 end;
@@ -145,7 +152,7 @@ begin
   end;
 end;
 
-constructor THashmap.create;
+constructor THashmap.Create;
 var i: SizeUInt;
 begin
   FDataSize:=0;
@@ -290,6 +297,22 @@ begin
   exit(false);
 end;
 
+function THashmapIterator.MoveNext: boolean;
+begin
+  Assert(Fh < FData.size);      // assumes FData.size>0 (i.e. buckets don't shrink) and cannot call Next again after reaching end
+  inc(Fp);
+  if (Fp < (FData[Fh]).size) then
+    exit(true);
+  Fp:=0; Inc(Fh);
+  while Fh < FData.size do begin
+    if ((FData[Fh]).size > 0) then
+      exit(true);
+    Inc(Fh);
+  end;
+  //Assert((Fp = 0) and (Fh = FData.size));
+  exit(false);
+end;
+
 function THashmapIterator.Prev: boolean;
 var bs:SizeUInt;
 begin
@@ -330,6 +353,11 @@ begin
   Iterator.FData := FData;
 end;
 
+function THashmap.getenumerator: TIterator;
+begin
+  result:=iterator;
+end;
+
 function THashmapIterator.GetKey: TKey;
 begin
   GetKey:=((FData[Fh])[Fp]).Key;
@@ -350,4 +378,9 @@ begin
   ((FData[Fh]).mutable[Fp])^.Value := value;
 end;
 
+function THashmapIterator.getenumerator: TIntIterator;
+begin
+  result:=self;
+end;
+
 end.

+ 47 - 4
packages/fcl-stl/src/ghashset.pp

@@ -23,14 +23,22 @@ const baseFDataSize = 8;
 value in range <0,n-1> base only on arguments, n will be always power of 2}
 
 type
+
+    { THashSetIterator }
+
     generic THashSetIterator<T, TTable>=class
     public
+    Type
+      TLHashSetIterator = specialize THashSetIterator<T, TTable>;
     var
       Fh,Fp:SizeUInt;
       FData:TTable;
       function Next:boolean;
+      function MoveNext:boolean; inline;
       function GetData:T;
+      function GetEnumerator: TLHashSetIterator; inline;
       property Data:T read GetData;
+      property Current:T read GetData;
  end;
 
   generic THashSet<T, Thash>=class
@@ -52,18 +60,18 @@ type
       function size:SizeUInt;inline;
       procedure delete(value:T);inline;
       function IsEmpty:boolean;inline;
-
+      function GetEnumerator: TIterator; inline;
       function Iterator:TIterator;
   end;
 
 implementation
 
-function THashSet.Size:SizeUInt;inline;
+function THashSet.size: SizeUInt;
 begin
   Size:=FDataSize;
 end;
 
-destructor THashSet.Destroy;
+destructor THashSet.destroy;
 var i:SizeUInt;
 begin
   for i:=0 to FData.size-1 do
@@ -71,7 +79,7 @@ begin
   FData.Destroy;
 end;
 
-function THashSet.IsEmpty():boolean;inline;
+function THashSet.IsEmpty: boolean;
 begin
   if Size()=0 then 
     IsEmpty:=true
@@ -79,6 +87,22 @@ begin
     IsEmpty:=false;
 end;
 
+function THashSet.GetEnumerator: TIterator;
+  var h,p:SizeUInt;
+begin
+  h:=0;
+  p:=0;
+  while h < FData.size do begin
+    if ((FData[h]).size > 0) then break;
+    inc(h);
+  end;
+  if (h = FData.size) then exit(nil);
+  result := TIterator.create;
+  result.Fh := h;
+  result.Fp := p;
+  result.FData := FData;
+end;
+
 procedure THashSet.EnlargeTable;
 var i,j,h,oldDataSize:SizeUInt; 
     value:T;
@@ -163,11 +187,30 @@ begin
   Next := true;
 end;
 
+function THashSetIterator.MoveNext: boolean;
+begin
+  inc(Fp);
+  if (Fp = (FData[Fh]).size) then begin
+    Fp:=0; inc(Fh);
+    while Fh < FData.size do begin
+      if ((FData[Fh]).size > 0) then break;
+      inc(Fh);
+    end;
+    if (Fh = FData.size) then exit(false);
+  end;
+  MoveNext := true;
+end;
+
 function THashSetIterator.GetData:T;
 begin
   GetData:=(FData[Fh])[Fp];
 end;
 
+function THashSetIterator.GetEnumerator: TLHashSetIterator;
+begin
+  result:=self;
+end;
+
 function THashSet.Iterator:TIterator;
 var h,p:SizeUInt;
 begin

+ 38 - 0
packages/fcl-stl/src/gmap.pp

@@ -23,9 +23,12 @@ type
     class function c(a,b :TPair):boolean;
   end;
 
+  { TMapIterator }
+
   generic TMapIterator<TKey, TValue, TPair, TNode>=class
     public
     type PNode=^TNode;
+         TLMapIterator = specialize TMapIterator<TKey, TValue, TPair, TNode>;
     var FNode:PNode;
     type PValue=^TValue;
     function GetData:TPair;inline;
@@ -33,12 +36,15 @@ type
     function GetValue:TValue;inline;
     function GetMutable:PValue;inline;
     procedure SetValue(value:TValue);inline;
+    function MoveNext:boolean;inline;
     function Next:boolean;inline;
     function Prev:boolean;inline;
+    function GetEnumerator: TLMapIterator; inline;
     property Data:TPair read GetData;
     property Key:TKey read GetKey;
     property Value:TValue read GetValue write SetValue;
     property MutableValue:PValue read GetMutable;
+    property Current : TPair read GetData;
   end;
 
   generic TMap<TKey, TValue, TCompare>=class
@@ -71,6 +77,7 @@ type
     procedure Delete(key:TKey);inline;
     function Size:SizeUInt;inline;
     function IsEmpty:boolean;inline;
+    function GetEnumerator: TIterator; inline;
     constructor Create;
     destructor Destroy;override;
     property Items[i : TKey]: TValue read GetValue write Insert; default;
@@ -227,6 +234,11 @@ begin
   IsEmpty:=FSet.IsEmpty;
 end;
 
+function TMap.GetEnumerator: TIterator;
+begin
+  result:=titerator.create;
+end;
+
 function TMapIterator.GetData:TPair;inline;
 begin
   GetData:=FNode^.Data;
@@ -252,6 +264,27 @@ begin
   FNode^.Data.Value := value;
 end;
 
+function TMapIterator.MoveNext: boolean;
+var temp:PNode;
+begin
+  if(FNode=nil) then exit(false);
+  if(FNode^.Right<>nil) then begin
+    temp:=FNode^.Right;
+    while(temp^.Left<>nil) do temp:=temp^.Left;
+  end
+  else begin
+    temp:=FNode;
+    while(true) do begin
+      if(temp^.Parent=nil) then begin temp:=temp^.Parent; break; end;
+      if(temp^.Parent^.Left=temp) then begin temp:=temp^.Parent; break; end;
+      temp:=temp^.Parent;
+    end;
+  end;
+  if (temp = nil) then exit(false);
+  FNode:=temp;
+  MoveNext:=true;
+end;
+
 function TMapIterator.Next:boolean;inline;
 var temp:PNode;
 begin
@@ -294,4 +327,9 @@ begin
   Prev:=true;
 end;
 
+function TMapIterator.GetEnumerator: TLMapIterator;
+begin
+  result:=Self;
+end;
+
 end.

+ 20 - 2
packages/fcl-stl/src/gset.pp

@@ -20,14 +20,22 @@ const RED=true;
 const BLACK=false;
 
 type
+
+  { TSetIterator }
+
   generic TSetIterator<T, TNode>=class
     public
     type PNode=^TNode;
+         TLSetIterator = specialize TSetIterator<T, TNode>;
+
     var FNode:PNode;
-    function GetData:T;
+    function GetData:T; Inline;
     function Next:boolean;
+    function MoveNext:boolean; Inline;
+    function GetEnumerator : TLSetIterator; Inline;
     function Prev:boolean;
     property Data:T read GetData;
+    property Current:T read GetData;
   end;
 
   generic TSet<T, TCompare>=class
@@ -502,6 +510,11 @@ begin
 end;
 
 function TSetIterator.Next:boolean;
+begin
+  Result:=MoveNext;
+end;
+
+function TSetIterator.MoveNext: boolean;
 var temp:PNode;
 begin
   if(FNode=nil) then exit(false);
@@ -519,7 +532,12 @@ begin
   end;
   if (temp = nil) then exit(false);
   FNode:=temp;
-  Next:=true;
+  Result:=true;
+end;
+
+function TSetIterator.GetEnumerator: TLSetIterator;
+begin
+  result:=self;
 end;
 
 function TSetIterator.Prev:boolean;

+ 6 - 0
packages/fcl-stl/src/gvector.pp

@@ -50,6 +50,7 @@ type
       function GetCurrent: T; inline;
     public
       constructor Create(AVector: TVector);
+      function GetEnumerator: TVectorEnumerator; inline;
       function MoveNext: Boolean; inline;
       property Current: T read GetCurrent;
     end;
@@ -83,6 +84,11 @@ begin
   FVector := AVector;
 end;
 
+function TVector.TVectorEnumerator.GetEnumerator: TVectorEnumerator;
+begin
+  result:=self;
+end;
+
 function TVector.TVectorEnumerator.GetCurrent: T;
 begin
   Result := FVector[FPosition];

+ 38 - 14
packages/winunits-base/src/comobj.pp

@@ -92,7 +92,7 @@ unit ComObj;
         destructor Destroy; override;
         procedure AddObjectFactory(factory: TComObjectFactory);
         procedure RemoveObjectFactory(factory: TComObjectFactory);
-        procedure ForEachFactory(ComServer: TComServerObject; FactoryProc: TFactoryProc);
+        procedure ForEachFactory(ComServer: TComServerObject; FactoryProc: TFactoryProc;const bBackward:boolean=false);
         function GetFactoryFromClass(ComClass: TClass): TComObjectFactory;
         function GetFactoryFromClassID(const ClassID: TGUID): TComObjectFactory;
       end;
@@ -159,11 +159,12 @@ unit ComObj;
         FErrorIID: TGUID;
         FInstancing: TClassInstancing;
         FLicString: WideString;
-        //FRegister: Longint;
+        FIsRegistered: dword;
         FShowErrors: Boolean;
         FSupportsLicensing: Boolean;
         FThreadingModel: TThreadingModel;
         function GetProgID: string;
+        function reg_flags(): integer;
       protected
         { IUnknown }
         function QueryInterface(constref IID: TGUID; out Obj): HResult; stdcall;
@@ -694,7 +695,7 @@ implementation
       end;
 
     procedure TComClassManager.ForEachFactory(ComServer: TComServerObject;
-      FactoryProc: TFactoryProc);
+      FactoryProc: TFactoryProc;const bBackward:boolean=false);
       var
         i: Integer;
         obj: TComObjectFactory;
@@ -703,12 +704,20 @@ implementation
          if printcom then 
         WriteLn('ForEachFactory');
 {$endif}
+        if not bBackward then
         for i := 0 to fClassFactoryList.Count - 1 do
         begin
           obj := TComObjectFactory(fClassFactoryList[i]);
           if obj.ComServer = ComServer then
             FactoryProc(obj);
-        end;
+        end
+        else
+        for i := fClassFactoryList.Count - 1 downto 0 do
+        begin
+          obj := TComObjectFactory(fClassFactoryList[i]);
+          if obj.ComServer = ComServer then
+            FactoryProc(obj);
+        end
       end;
 
 
@@ -937,8 +946,8 @@ implementation
          if printcom then 
         WriteLn('LockServer: ', fLock);
 {$endif}
-        RunError(217);
-        Result:=0;
+          Result := CoLockObjectExternal(Self, fLock, True);
+          ComServer.CountObject(fLock);
       end;
 
 
@@ -1003,13 +1012,14 @@ implementation
         FComClass := ComClass;
         FInstancing := Instancing;;
         ComClassManager.AddObjectFactory(Self);
+        fIsRegistered := dword(-1);
       end;
 
 
     destructor TComObjectFactory.Destroy;
       begin
+        if fIsRegistered <> dword(-1) then CoRevokeClassObject(fIsRegistered);
         ComClassManager.RemoveObjectFactory(Self);
-        //RunError(217);
       end;
 
 
@@ -1023,15 +1033,27 @@ implementation
         Result := TComClass(FComClass).Create();
       end;
 
+    function TComObjectFactory.reg_flags():integer;inline;
+    begin
+       Result:=0;
+       case Self.FInstancing of
+       ciSingleInstance: Result:=Result or REGCLS_SINGLEUSE;
+       ciMultiInstance: Result:=Result or REGCLS_MULTIPLEUSE;
+       end;
+       if FComServer.StartSuspended then
+         Result:=Result or REGCLS_SUSPENDED;
+    end;
 
     procedure TComObjectFactory.RegisterClassObject;
-      begin
+    begin
       {$ifdef DEBUG_COM}
          if printcom then 
         WriteLn('TComObjectFactory.RegisterClassObject');
       {$endif}
-        RunError(217);
-      end;
+      if FInstancing <> ciInternal then
+      OleCheck(CoRegisterClassObject(FClassID, Self, CLSCTX_LOCAL_SERVER,
+         reg_flags(), @FIsRegistered));
+    end;
 
 
 (* Copy from Sample.RGS (http://www.codeproject.com/KB/atl/RegistryMap.aspx)
@@ -1066,6 +1088,7 @@ HKCR
     procedure TComObjectFactory.UpdateRegistry(Register: Boolean);
       var
         classidguid: String;
+        srv_type: string;
 
         function ThreadModelToString(model: TThreadingModel): String;
         begin
@@ -1086,12 +1109,14 @@ HKCR
 {$endif}
         if Instancing = ciInternal then Exit;
 
+        if System.ModuleIsLib then srv_type:='InprocServer32' else srv_type:='LocalServer32';
+
         if Register then
         begin
           classidguid := GUIDToString(ClassID);
-          CreateRegKey('CLSID\' + classidguid + '\InprocServer32', '', FComServer.ServerFileName);
+          CreateRegKey('CLSID\' + classidguid + '\'+srv_type, '', FComServer.ServerFileName);
           //tmSingle, tmApartment, tmFree, tmBoth, tmNeutral
-          CreateRegKey('CLSID\' + classidguid + '\InprocServer32', 'ThreadingModel', ThreadModelToString(ThreadingModel));
+          CreateRegKey('CLSID\' + classidguid + '\'+srv_type, 'ThreadingModel', ThreadModelToString(ThreadingModel));
           CreateRegKey('CLSID\' + classidguid, '', Description);
           if ClassName <> '' then
           begin
@@ -1115,7 +1140,7 @@ HKCR
         end else
         begin
           classidguid := GUIDToString(ClassID);
-          DeleteRegKey('CLSID\' + classidguid + '\InprocServer32');
+          DeleteRegKey('CLSID\' + classidguid + '\'+srv_type);
           DeleteRegKey('CLSID\' + classidguid + '\VersionIndependentProgID');
           if ClassName <> '' then
           begin
@@ -1875,4 +1900,3 @@ finalization
   if Initialized then
     CoUninitialize;
 end.
-

+ 171 - 6
packages/winunits-base/src/comserv.pp

@@ -37,10 +37,13 @@ const
   SELFREG_E_CLASS = -2;
 
 type
+  TStartMode = (smStandalone, smAutomation,smRegserver,smUnregserver);
+  TLastReleaseEvent = procedure(var shutdown: Boolean) of object;
 
   { TComServer }
 
   TComServer = class(TComServerObject)
+  class var orgInitProc: codepointer;
   private
     fCountObject: Integer;
     fCountFactory: Integer;
@@ -48,7 +51,23 @@ type
     fServerName,
     fServerFileName: String;
     fHelpFileName : String;
+    fRegister: Boolean;
     fStartSuspended : Boolean;
+    FIsInproc: Boolean;
+    FIsInteractive: Boolean;
+    FStartMode: TStartMode;
+    FOnLastRelease: TLastReleaseEvent;
+
+    class function AutomationDone: Boolean;
+    class procedure AutomationStart;
+    procedure CheckCmdLine;
+    procedure FactoryFree(Factory: TComObjectFactory);
+    procedure FactoryRegisterClassObject(Factory: TComObjectFactory);
+    procedure FactoryUpdateRegistry(Factory: TComObjectFactory);
+    procedure CheckReleased;
+    function GetTypeLibName: widestring;
+    procedure RegisterObjectWith(Factory: TComObjectFactory);
+    procedure Start;
   protected
     function CountObject(Created: Boolean): Integer; override;
     function CountFactory(Created: Boolean): Integer; override;
@@ -69,10 +88,16 @@ type
     function CanUnloadNow: Boolean;
     procedure RegisterServer;
     procedure UnRegisterServer;
+    property IsInprocServer: Boolean read FIsInproc write FIsInproc;
+    property IsInteractive: Boolean read fIsInteractive;
+    property StartMode: TStartMode read FStartMode;
+    property ServerObjects:integer read fCountObject;
   end;
 
 var
   ComServer: TComServer = nil;
+  haut :TLibHandle;
+
 
 //http://msdn.microsoft.com/en-us/library/ms690368%28VS.85%29.aspx
 //If the function succeeds, the return value is S_OK. Otherwise, it is S_FALSE.
@@ -219,9 +244,24 @@ end;
 function TComServer.CountObject(Created: Boolean): Integer;
 begin
   if Created then
-    Result:=InterLockedIncrement(fCountObject)
+  begin
+    Result := InterlockedIncrement(FCountObject);
+    if (not IsInProcServer) and (StartMode = smAutomation)
+      and Assigned(ComObj.CoAddRefServerProcess) then
+      ComObj.CoAddRefServerProcess;
+  end
   else
-    Result:=InterLockedDecrement(fCountObject);
+  begin
+    Result := InterlockedDecrement(FCountObject);
+    if (not IsInProcServer) and (StartMode = smAutomation)
+      and Assigned(ComObj.CoReleaseServerProcess) then
+    begin
+      if ComObj.CoReleaseServerProcess() = 0 then
+        CheckReleased;
+    end
+    else if Result = 0 then
+      CheckReleased;
+  end;
 end;
 
 function TComServer.CountFactory(Created: Boolean): Integer;
@@ -232,6 +272,22 @@ begin
     Result:=InterLockedDecrement(fCountFactory);
 end;
 
+procedure TComServer.FactoryFree(Factory: TComObjectFactory);
+begin
+  Factory.Free;
+end;
+
+procedure TComServer.FactoryRegisterClassObject(Factory: TComObjectFactory);
+begin
+  Factory.RegisterClassObject;
+end;
+
+procedure TComServer.FactoryUpdateRegistry(Factory: TComObjectFactory);
+begin
+  if Factory.Instancing <> ciInternal then
+    Factory.UpdateRegistry(FRegister);
+end;
+
 function TComServer.GetHelpFileName: string;
 begin
   result:=fhelpfilename;
@@ -244,14 +300,29 @@ end;
 
 function TComServer.GetServerKey: string;
 begin
-  result:='LocalServer32';
+  if FIsInproc then
+    Result := 'InprocServer32'
+  else
+    Result := 'LocalServer32';
 end;
 
 function TComServer.GetServerName: string;
 begin
-  Result := fServerName;
+  if FServerName <> '' then
+    Result := FServerName
+  else
+    if FTypeLib <> nil then
+      Result := GetTypeLibName
+    else
+      Result := GetModuleName;
 end;
 
+function TComServer.GetTypeLibName: widestring;
+begin
+  OleCheck(TypeLib.GetDocumentation(-1, @Result, nil, nil, nil));
+end;
+
+
 function TComServer.GetStartSuspended: Boolean;
 begin
   result:=fStartSuspended;
@@ -262,6 +333,30 @@ begin
   Result := fTypeLib;
 end;
 
+procedure TComServer.RegisterObjectWith(Factory: TComObjectFactory);
+begin
+  Factory.RegisterClassObject;
+end;
+
+
+procedure TComServer.Start;
+begin
+  case fStartMode of
+  smRegServer:
+    begin
+      Self.RegisterServer;
+      Halt;
+    end;
+  smUnregServer:
+    begin
+      Self.UnRegisterServer;
+      Halt;
+    end;
+  end;
+  ComClassManager.ForEachFactory(Self, @RegisterObjectWith);
+end;
+
+
 procedure TComServer.SetHelpFileName(const Value: string);
 begin
   FHelpFileName:=value;
@@ -277,10 +372,25 @@ begin
   Factory.UpdateRegistry(False);
 end;
 
+procedure TComServer.CheckCmdLine;
+const
+  sw_set:TSysCharSet = ['/','-'];
+begin
+  if FindCmdLineSwitch('automation',sw_set,true) or
+     FindCmdLineSwitch('embedding',sw_set,true) then
+    fStartMode := smAutomation
+  else if FindCmdlIneSwitch('regserver',sw_set,true) then
+    fStartMode := smRegServer
+  else if FindCmdLineSwitch('unregserver',sw_set,true) then
+    fStartMode := smUnregServer;
+end;
+
 constructor TComServer.Create;
 var
   name: WideString;
 begin
+  haut := SafeLoadLibrary('oleaut32.DLL');
+  CheckCmdLine;
   inherited Create;
 {$ifdef DEBUG_COM}
   WriteLn('TComServer.Create');
@@ -288,6 +398,9 @@ begin
   fCountFactory := 0;
   fCountObject := 0;
 
+  FTypeLib := nil;
+  FIsInproc := ModuleIsLib;
+
   fServerFileName := GetModuleFileName();
 
   name := fServerFileName;
@@ -301,11 +414,61 @@ begin
   end
   else
     fServerName := GetModuleName;
+
+  if not ModuleIsLib then
+  begin
+    orgInitProc := InitProc;
+    InitProc := @TComServer.AutomationStart;
+  //  AddTerminateProc(TTerminateProc(@TComServer.AutomationDone));
+  end;
+
+  Self.FIsInteractive := True;
 end;
 
+class procedure TComServer.AutomationStart;
+begin
+  if orgInitProc <> nil then TProcedure(orgInitProc)();
+  ComServer.FStartSuspended := (CoInitFlags <> -1) and
+    Assigned(ComObj.CoInitializeEx) and Assigned(ComObj.CoResumeClassObjects);
+  ComServer.Start;
+  if ComServer.FStartSuspended then
+    ComObj.CoResumeClassObjects;
+end;
+
+class function TComServer.AutomationDone: Boolean;
+begin
+  Result := True;
+  if (ComServer <> nil) and (ComServer.ServerObjects > 0) and ComServer.IsInteractive then
+  begin
+    Result := MessageBox(0, PChar('COM server is in use'),
+      PChar('OLE Automation'), MB_YESNO or MB_TASKMODAL or
+      MB_ICONWARNING or MB_DEFBUTTON2) = IDYES;
+  end;
+end;
+
+
+procedure TComServer.CheckReleased;
+var
+  Shutdown: Boolean;
+begin
+  if not FIsInproc then
+  begin
+    Shutdown := FStartMode = smAutomation;
+    try
+      if Assigned(FOnLastRelease) then FOnLastRelease(Shutdown);
+    finally
+      if Shutdown then PostThreadMessage(MainThreadID, WM_QUIT, 0, 0);
+    end;
+  end;
+end;
+
+
 destructor TComServer.Destroy;
 begin
+  ComClassManager.ForEachFactory(Self, @FactoryFree,true);
+  Self.fTypeLib:=nil;
   inherited Destroy;
+  FreeLibrary(haut);
 {$ifdef DEBUG_COM}
   WriteLn('TComServer.Destroy');
 {$endif}
@@ -332,15 +495,17 @@ begin
   ComClassManager.ForEachFactory(self, @UnregisterServerFactory);
 end;
 
+
 initialization
 {$ifdef DEBUG_COM}
   WriteLn('comserv initialization begin');
 {$endif}
   ComServer := TComServer.Create;
+
 {$ifdef DEBUG_COM}
   WriteLn('comserv initialization end');
 {$endif}
 finalization
-  ComServer.Free;
+  ComServer.AutomationDone;
+  FreeAndNil(ComServer);
 end.
-