@@ -126,6 +126,7 @@ TNamedParamDesc = record
126126
127127{ $IFDEF DELPHIXE2_OR_HIGHER}
128128 { $DEFINE USESYSTEMDISPINVOKE} // Delphi 2010 DispInvoke is buggy
129+ { $DEFINE PATCHEDSYSTEMDISPINVOKE} // To correct memory leaks
129130{ $ENDIF}
130131{ .$IF DEFINED(FPC_FULLVERSION) and (FPC_FULLVERSION >= 20500)}
131132 { .$DEFINE USESYSTEMDISPINVOKE}
@@ -944,17 +945,40 @@ procedure TPythonVariantType.DispInvoke(Dest: PVarData;
944945 var Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
945946{ $ENDIF}
946947{ $IFDEF USESYSTEMDISPINVOKE}
947- { $IFDEF DELPHIXE2_OR_HIGHER}
948- // Modified to correct memory leak QC102387
948+ { $IFDEF PATCHEDSYSTEMDISPINVOKE}
949+ // Modified to correct memory leak QC102387 / RSP-23093
950+ procedure PatchedFinalizeDispatchInvokeArgs (CallDesc: PCallDesc; const Args: TVarDataArray; OrderLTR : Boolean);
951+ const
952+ atByRef = $80 ;
953+ var
954+ I: Integer;
955+ ArgType: Byte;
956+ PVarParm: PVarData;
957+ VType: TVarType;
958+ begin
959+ for I := 0 to CallDesc^.ArgCount-1 do
960+ begin
961+ ArgType := CallDesc^.ArgTypes[I];
962+
963+ if OrderLTR then
964+ PVarParm := @Args[I]
965+ else
966+ PVarParm := @Args[CallDesc^.ArgCount-I-1 ];
967+
968+ VType := PVarParm.VType;
969+
970+ // Only ByVal Variant or Array parameters have been copied and need to be released
971+ // Strings have been released via the use of the TStringRefList parameter to GetDispatchInvokeArgs
972+ // !!Modified to prevent memory leaks!! RSP-23093
973+ if ((ArgType and atByRef) <> atByRef) and ((ArgType = varVariant) or ((VType and varArray) = varArray)) then
974+ VarClear(PVariant(PVarParm)^);
975+ end ;
976+ end ;
977+
949978 procedure PatchedDispInvoke (Dest: PVarData;
950979 const Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
951980 type
952- PParamRec = ^TParamRec;
953- TParamRec = array [0 ..3 ] of LongInt;
954- TStringDesc = record
955- BStr: WideString;
956- PStr: PAnsiString;
957- end ;
981+ PStringRefList = ^TStringRefList;
958982 const
959983 CDoMethod = $01 ;
960984 CPropertyGet = $02 ;
@@ -964,67 +988,75 @@ TStringDesc = record
964988 LIdent: string;
965989 LTemp: TVarData;
966990 VarParams : TVarDataArray;
967- Strings: TStringRefList;
991+ Strings: array of TStringRef;
992+ PIdent: PByte;
968993 begin
969994 // Grab the identifier
970995 LArgCount := CallDesc^.ArgCount;
971- LIdent := FixupIdent(string(AnsiString(PAnsiChar(@CallDesc^.ArgTypes[LArgCount]))));
972-
973- FillChar(Strings, SizeOf(Strings), 0 );
974- VarParams := GetDispatchInvokeArgs(CallDesc, Params, Strings, true);
975-
976- // What type of invoke is this?
977- case CallDesc^.CallType of
978- CDoMethod:
979- // procedure with N arguments
980- if Dest = nil then
981- begin
982- if not DoProcedure(Source, LIdent, VarParams) then
996+ PIdent := @CallDesc^.ArgTypes[LArgCount];
997+ LIdent := FixupIdent( UTF8ToString(MarshaledAString(PIdent)) );
998+ if LArgCount > 0 then begin
999+ SetLength(Strings, LArgCount);
1000+ FillChar(Strings[0 ], SizeOf(TStringRef)*LArgCount, 0 );
1001+ VarParams := GetDispatchInvokeArgs(CallDesc, Params, PStringRefList(Strings)^, true);
1002+ end ;
1003+ try
1004+ // What type of invoke is this?
1005+ case CallDesc^.CallType of
1006+ CDoMethod:
1007+ // procedure with N arguments
1008+ if Dest = nil then
9831009 begin
1010+ if not DoProcedure(Source, LIdent, VarParams) then
1011+ begin
1012+
1013+ // ok maybe its a function but first we must make room for a result
1014+ VarDataInit(LTemp);
1015+ try
1016+
1017+ // notate that the destination shouldn't be bothered with
1018+ // functions can still return stuff, we just do this so they
1019+ // can tell that they don't need to if they don't want to
1020+ SetClearVarToEmptyParam(LTemp);
1021+
1022+ // ok lets try for that function
1023+ if not DoFunction(LTemp, Source, LIdent, VarParams) then
1024+ RaiseDispError;
1025+ finally
1026+ VarDataClear(LTemp);
1027+ end ;
1028+ end
1029+ end
9841030
985- // ok maybe its a function but first we must make room for a result
986- VarDataInit(LTemp);
987- try
988-
989- // notate that the destination shouldn't be bothered with
990- // functions can still return stuff, we just do this so they
991- // can tell that they don't need to if they don't want to
992- SetClearVarToEmptyParam(LTemp);
993-
994- // ok lets try for that function
995- if not DoFunction(LTemp, Source, LIdent, VarParams) then
996- RaiseDispError;
997- finally
998- VarDataClear(LTemp);
999- end ;
1031+ // property get or function with 0 argument
1032+ else if LArgCount = 0 then
1033+ begin
1034+ if not GetProperty(Dest^, Source, LIdent) and
1035+ not DoFunction(Dest^, Source, LIdent, VarParams) then
1036+ RaiseDispError;
10001037 end
1001- end
10021038
1003- // property get or function with 0 argument
1004- else if LArgCount = 0 then
1005- begin
1006- if not GetProperty(Dest^, Source, LIdent) and
1007- not DoFunction(Dest^, Source, LIdent, VarParams) then
1039+ // function with N arguments
1040+ else if not DoFunction(Dest^, Source, LIdent, VarParams) then
10081041 RaiseDispError;
1009- end
10101042
1011- // function with N arguments
1012- else if not DoFunction(Dest^, Source, LIdent, VarParams) then
1013- RaiseDispError;
1043+ CPropertyGet:
1044+ if not ((Dest <> nil ) and // there must be a dest
1045+ (LArgCount = 0 ) and // only no args
1046+ GetProperty(Dest^, Source, LIdent)) then // get op be valid
1047+ RaiseDispError;
10141048
1015- CPropertyGet:
1016- if not ((Dest <> nil ) and // there must be a dest
1017- (LArgCount = 0 ) and // only no args
1018- GetProperty(Dest^, Source, LIdent)) then // get op be valid
1019- RaiseDispError;
1049+ CPropertySet:
1050+ if not ((Dest = nil ) and // there can't be a dest
1051+ (LArgCount = 1 ) and // can only be one arg
1052+ SetProperty(Source, LIdent, VarParams[0 ])) then // set op be valid
1053+ RaiseDispError;
1054+ else
1055+ RaiseDispError;
1056+ end ;
10201057
1021- CPropertySet:
1022- if not ((Dest = nil ) and // there can't be a dest
1023- (LArgCount = 1 ) and // can only be one arg
1024- SetProperty(Source, LIdent, VarParams[0 ])) then // set op be valid
1025- RaiseDispError;
1026- else
1027- RaiseDispError;
1058+ finally
1059+ PatchedFinalizeDispatchInvokeArgs(CallDesc, VarParams, true);
10281060 end ;
10291061
10301062 for I := 0 to Length(Strings) - 1 do
@@ -1033,13 +1065,12 @@ TStringDesc = record
10331065 Break;
10341066 if Strings[I].Ansi <> nil then
10351067 Strings[I].Ansi^ := AnsiString(Strings[I].Wide)
1036- else if Strings[I].Unicode <> nil then
1037- Strings[I].Unicode^ := UnicodeString(Strings[I].Wide)
1068+ else
1069+ if Strings[I].Unicode <> nil then
1070+ Strings[I].Unicode^ := UnicodeString(Strings[I].Wide)
10381071 end ;
1039- for I := Low(VarParams) to High(VarParams) do
1040- VarDataClear(VarParams[I]);
10411072 end ;
1042- { $ENDIF DELPHIXE2_OR_HIGHER }
1073+ { $ENDIF PATCHEDSYSTEMDISPINVOKE }
10431074
10441075 procedure GetNamedParams ;
10451076 var
@@ -1066,17 +1097,17 @@ TStringDesc = record
10661097 if (CallDesc^.CallType = CPropertyGet) and (CallDesc^.ArgCount = 1 ) then begin
10671098 NewCallDesc := CallDesc^;
10681099 NewCallDesc.CallType := CDoMethod;
1069- { $IFDEF DELPHIXE2_OR_HIGHER }
1100+ { $IFDEF PATCHEDSYSTEMDISPINVOKE }
10701101 PatchedDispInvoke(Dest, Source, @NewCallDesc, Params);
1071- { $ELSE DELPHIXE2_OR_HIGHER }
1102+ { $ELSE PATCHEDSYSTEMDISPINVOKE }
10721103 inherited DispInvoke(Dest, Source, @NewCallDesc, Params);
1073- { $ENDIF DELPHIXE2_OR_HIGHER }
1104+ { $ENDIF PATCHEDSYSTEMDISPINVOKE }
10741105 end else
1075- { $IFDEF DELPHIXE2_OR_HIGHER }
1106+ { $IFDEF PATCHEDSYSTEMDISPINVOKE }
10761107 PatchedDispInvoke(Dest, Source, CallDesc, Params);
1077- { $ELSE DELPHIXE2_OR_HIGHER }
1108+ { $ELSE PATCHEDSYSTEMDISPINVOKE }
10781109 inherited ;
1079- { $ENDIF DELPHIXE2_OR_HIGHER }
1110+ { $ENDIF PATCHEDSYSTEMDISPINVOKE }
10801111 finally
10811112 if CallDesc^.NamedArgCount > 0 then SetLength(fNamedParams, 0 );
10821113 end ;
0 commit comments