--- 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 -
This commit is contained in:
marco 2019-09-05 12:17:22 +00:00
parent 415c951a87
commit c07b8a1954
10 changed files with 395 additions and 63 deletions

View File

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

View File

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

View File

@ -4,7 +4,7 @@ type lesslli=specialize TLess<longint>;
maplli=specialize TMap<longint, longint, lesslli>; maplli=specialize TMap<longint, longint, lesslli>;
var data:maplli; i:longint; iterator:maplli.TIterator; var data:maplli; i:longint; iterator:maplli.TIterator;
pair : maplli.TPair;
begin begin
data:=maplli.Create; data:=maplli.Create;
@ -14,7 +14,7 @@ begin
writeln(data[7]); writeln(data[7]);
data[7] := 42; data[7] := 42;
{Iteration through elements} {Iteration through elements with write access}
iterator:=data.Min; iterator:=data.Min;
repeat repeat
writeln(iterator.Key, ' ', iterator.Value); writeln(iterator.Key, ' ', iterator.Value);
@ -22,6 +22,10 @@ begin
until not iterator.next; until not iterator.next;
iterator.Destroy; 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); iterator := data.FindLess(7);
writeln(iterator.Value); writeln(iterator.Value);
iterator.Destroy; iterator.Destroy;

View File

@ -38,25 +38,33 @@
} }
type 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 generic THashmap<TKey, TValue, Thash>=class
public public
type type
@ -76,20 +84,19 @@
public public
type type
TIterator = specialize THashmapIterator<TKey, TValue, TPair, TTable>; TIterator = specialize THashmapIterator<TKey, TValue, TPair, TTable>;
constructor create; constructor Create;
destructor destroy;override; destructor Destroy;override;
procedure insert(key:TKey;value:TValue);inline; procedure insert(key:TKey;value:TValue);inline;
function contains(key:TKey):boolean;inline; function contains(key:TKey):boolean;inline;
function size:SizeUInt;inline; function Size:SizeUInt;inline;
procedure delete(key:TKey);inline; procedure delete(key:TKey);inline;
procedure erase(iter:TIterator);inline; procedure erase(iter:TIterator);inline;
function IsEmpty:boolean;inline; function IsEmpty:boolean;inline;
function GetData(key:TKey):TValue;inline; function GetData(key:TKey):TValue;inline;
function GetValue(key:TKey;out value:TValue):boolean;inline; function GetValue(key:TKey;out value:TValue):boolean;inline;
property Items[i : TKey]: TValue read GetData write Insert; default;
function Iterator:TIterator; function Iterator:TIterator;
function getenumerator :TIterator;
property Items[i : TKey]: TValue read GetData write Insert; default;
end; end;
implementation implementation
@ -111,7 +118,7 @@ begin
FData.Destroy; FData.Destroy;
end; end;
function THashmap.IsEmpty(): boolean; function THashmap.IsEmpty: boolean;
begin begin
IsEmpty := Size()=0; IsEmpty := Size()=0;
end; end;
@ -145,7 +152,7 @@ begin
end; end;
end; end;
constructor THashmap.create; constructor THashmap.Create;
var i: SizeUInt; var i: SizeUInt;
begin begin
FDataSize:=0; FDataSize:=0;
@ -290,6 +297,22 @@ begin
exit(false); exit(false);
end; 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; function THashmapIterator.Prev: boolean;
var bs:SizeUInt; var bs:SizeUInt;
begin begin
@ -330,6 +353,11 @@ begin
Iterator.FData := FData; Iterator.FData := FData;
end; end;
function THashmap.getenumerator: TIterator;
begin
result:=iterator;
end;
function THashmapIterator.GetKey: TKey; function THashmapIterator.GetKey: TKey;
begin begin
GetKey:=((FData[Fh])[Fp]).Key; GetKey:=((FData[Fh])[Fp]).Key;
@ -350,4 +378,9 @@ begin
((FData[Fh]).mutable[Fp])^.Value := value; ((FData[Fh]).mutable[Fp])^.Value := value;
end; end;
function THashmapIterator.getenumerator: TIntIterator;
begin
result:=self;
end;
end. end.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,10 +37,13 @@ const
SELFREG_E_CLASS = -2; SELFREG_E_CLASS = -2;
type type
TStartMode = (smStandalone, smAutomation,smRegserver,smUnregserver);
TLastReleaseEvent = procedure(var shutdown: Boolean) of object;
{ TComServer } { TComServer }
TComServer = class(TComServerObject) TComServer = class(TComServerObject)
class var orgInitProc: codepointer;
private private
fCountObject: Integer; fCountObject: Integer;
fCountFactory: Integer; fCountFactory: Integer;
@ -48,7 +51,23 @@ type
fServerName, fServerName,
fServerFileName: String; fServerFileName: String;
fHelpFileName : String; fHelpFileName : String;
fRegister: Boolean;
fStartSuspended : 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 protected
function CountObject(Created: Boolean): Integer; override; function CountObject(Created: Boolean): Integer; override;
function CountFactory(Created: Boolean): Integer; override; function CountFactory(Created: Boolean): Integer; override;
@ -69,10 +88,16 @@ type
function CanUnloadNow: Boolean; function CanUnloadNow: Boolean;
procedure RegisterServer; procedure RegisterServer;
procedure UnRegisterServer; 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; end;
var var
ComServer: TComServer = nil; ComServer: TComServer = nil;
haut :TLibHandle;
//http://msdn.microsoft.com/en-us/library/ms690368%28VS.85%29.aspx //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. //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; function TComServer.CountObject(Created: Boolean): Integer;
begin begin
if Created then 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 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; end;
function TComServer.CountFactory(Created: Boolean): Integer; function TComServer.CountFactory(Created: Boolean): Integer;
@ -232,6 +272,22 @@ begin
Result:=InterLockedDecrement(fCountFactory); Result:=InterLockedDecrement(fCountFactory);
end; 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; function TComServer.GetHelpFileName: string;
begin begin
result:=fhelpfilename; result:=fhelpfilename;
@ -244,14 +300,29 @@ end;
function TComServer.GetServerKey: string; function TComServer.GetServerKey: string;
begin begin
result:='LocalServer32'; if FIsInproc then
Result := 'InprocServer32'
else
Result := 'LocalServer32';
end; end;
function TComServer.GetServerName: string; function TComServer.GetServerName: string;
begin begin
Result := fServerName; if FServerName <> '' then
Result := FServerName
else
if FTypeLib <> nil then
Result := GetTypeLibName
else
Result := GetModuleName;
end; end;
function TComServer.GetTypeLibName: widestring;
begin
OleCheck(TypeLib.GetDocumentation(-1, @Result, nil, nil, nil));
end;
function TComServer.GetStartSuspended: Boolean; function TComServer.GetStartSuspended: Boolean;
begin begin
result:=fStartSuspended; result:=fStartSuspended;
@ -262,6 +333,30 @@ begin
Result := fTypeLib; Result := fTypeLib;
end; 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); procedure TComServer.SetHelpFileName(const Value: string);
begin begin
FHelpFileName:=value; FHelpFileName:=value;
@ -277,10 +372,25 @@ begin
Factory.UpdateRegistry(False); Factory.UpdateRegistry(False);
end; 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; constructor TComServer.Create;
var var
name: WideString; name: WideString;
begin begin
haut := SafeLoadLibrary('oleaut32.DLL');
CheckCmdLine;
inherited Create; inherited Create;
{$ifdef DEBUG_COM} {$ifdef DEBUG_COM}
WriteLn('TComServer.Create'); WriteLn('TComServer.Create');
@ -288,6 +398,9 @@ begin
fCountFactory := 0; fCountFactory := 0;
fCountObject := 0; fCountObject := 0;
FTypeLib := nil;
FIsInproc := ModuleIsLib;
fServerFileName := GetModuleFileName(); fServerFileName := GetModuleFileName();
name := fServerFileName; name := fServerFileName;
@ -301,11 +414,61 @@ begin
end end
else else
fServerName := GetModuleName; fServerName := GetModuleName;
if not ModuleIsLib then
begin
orgInitProc := InitProc;
InitProc := @TComServer.AutomationStart;
// AddTerminateProc(TTerminateProc(@TComServer.AutomationDone));
end;
Self.FIsInteractive := True;
end; 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; destructor TComServer.Destroy;
begin begin
ComClassManager.ForEachFactory(Self, @FactoryFree,true);
Self.fTypeLib:=nil;
inherited Destroy; inherited Destroy;
FreeLibrary(haut);
{$ifdef DEBUG_COM} {$ifdef DEBUG_COM}
WriteLn('TComServer.Destroy'); WriteLn('TComServer.Destroy');
{$endif} {$endif}
@ -332,15 +495,17 @@ begin
ComClassManager.ForEachFactory(self, @UnregisterServerFactory); ComClassManager.ForEachFactory(self, @UnregisterServerFactory);
end; end;
initialization initialization
{$ifdef DEBUG_COM} {$ifdef DEBUG_COM}
WriteLn('comserv initialization begin'); WriteLn('comserv initialization begin');
{$endif} {$endif}
ComServer := TComServer.Create; ComServer := TComServer.Create;
{$ifdef DEBUG_COM} {$ifdef DEBUG_COM}
WriteLn('comserv initialization end'); WriteLn('comserv initialization end');
{$endif} {$endif}
finalization finalization
ComServer.Free; ComServer.AutomationDone;
FreeAndNil(ComServer);
end. end.