mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 13:59:37 +01:00 
			
		
		
		
	* variants.pp, patch from Ivan Shikhalev implementing TInvokeableVariant.DispInvoke (with some changes), resolves #17919.
git-svn-id: trunk@16458 -
This commit is contained in:
		
							parent
							
								
									3b910d9eb2
								
							
						
					
					
						commit
						099df04a5e
					
				@ -3940,10 +3940,115 @@ end;
 | 
			
		||||
    TInvokeableVariantType implementation
 | 
			
		||||
  ---------------------------------------------------------------------}
 | 
			
		||||
 | 
			
		||||
procedure TInvokeableVariantType.DispInvoke(Dest: PVarData; const Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
 | 
			
		||||
 | 
			
		||||
procedure TInvokeableVariantType.DispInvoke(Dest: PVarData; const Source: TVarData;
 | 
			
		||||
  CallDesc: PCallDesc; Params: Pointer);
 | 
			
		||||
var
 | 
			
		||||
  method_name: ansistring;
 | 
			
		||||
  arg_count: byte;
 | 
			
		||||
  args: TVarDataArray;
 | 
			
		||||
  arg_idx: byte;
 | 
			
		||||
  arg_type: byte;
 | 
			
		||||
  arg_byref, has_result: boolean;
 | 
			
		||||
  arg_ptr: pointer;
 | 
			
		||||
  arg_data: PVarData;
 | 
			
		||||
  dummy_data: TVarData;
 | 
			
		||||
const
 | 
			
		||||
  argtype_mask = $7F;
 | 
			
		||||
  argref_mask = $80;
 | 
			
		||||
begin
 | 
			
		||||
  NotSupported('TInvokeableVariantType.DispInvoke');
 | 
			
		||||
  arg_count := CallDesc^.ArgCount;
 | 
			
		||||
  method_name := ansistring(pchar(@CallDesc^.ArgTypes[arg_count]));
 | 
			
		||||
  setLength(args, arg_count);
 | 
			
		||||
  if arg_count > 0 then
 | 
			
		||||
  begin
 | 
			
		||||
    arg_ptr := Params;
 | 
			
		||||
    for arg_idx := 0 to arg_count - 1 do
 | 
			
		||||
    begin
 | 
			
		||||
      arg_type := CallDesc^.ArgTypes[arg_idx] and argtype_mask;
 | 
			
		||||
      arg_byref := (CallDesc^.ArgTypes[arg_idx] and argref_mask) <> 0;
 | 
			
		||||
      arg_data := @args[arg_count - arg_idx - 1];
 | 
			
		||||
      case arg_type of
 | 
			
		||||
        varUStrArg: arg_data^.vType := varUString;
 | 
			
		||||
        varStrArg: arg_data^.vType := varString;
 | 
			
		||||
      else
 | 
			
		||||
        arg_data^.vType := arg_type
 | 
			
		||||
      end;
 | 
			
		||||
      if arg_byref then
 | 
			
		||||
      begin
 | 
			
		||||
        arg_data^.vType := arg_data^.vType or varByRef;
 | 
			
		||||
        arg_data^.vPointer := PPointer(arg_ptr)^;
 | 
			
		||||
        Inc(arg_ptr,sizeof(Pointer));
 | 
			
		||||
      end
 | 
			
		||||
      else
 | 
			
		||||
        case arg_type of
 | 
			
		||||
          varVariant:
 | 
			
		||||
            begin
 | 
			
		||||
              arg_data^ := PVarData(PPointer(arg_ptr)^)^;
 | 
			
		||||
              Inc(arg_ptr,sizeof(Pointer));
 | 
			
		||||
            end;
 | 
			
		||||
          varDouble, varCurrency, varInt64, varQWord:
 | 
			
		||||
            begin
 | 
			
		||||
              arg_data^.vQWord := PQWord(arg_ptr)^; // 64bit on all platforms
 | 
			
		||||
              inc(arg_ptr,sizeof(qword))
 | 
			
		||||
            end
 | 
			
		||||
        else
 | 
			
		||||
          arg_data^.vAny := PPointer(arg_ptr)^; // 32 or 64bit
 | 
			
		||||
          inc(arg_ptr,sizeof(pointer))
 | 
			
		||||
        end;
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
  has_result := (Dest <> nil);
 | 
			
		||||
  if has_result then
 | 
			
		||||
    variant(Dest^) := Unassigned;
 | 
			
		||||
  case CallDesc^.CallType of
 | 
			
		||||
 | 
			
		||||
    1:     { DISPATCH_METHOD }
 | 
			
		||||
      if has_result then
 | 
			
		||||
      begin
 | 
			
		||||
        if arg_count = 0 then
 | 
			
		||||
        begin
 | 
			
		||||
          // no args -- try GetProperty first, then DoFunction
 | 
			
		||||
          if not (GetProperty(Dest^,Source,method_name) or
 | 
			
		||||
            DoFunction(Dest^,Source,method_name,args)) then
 | 
			
		||||
            RaiseDispError
 | 
			
		||||
        end
 | 
			
		||||
        else
 | 
			
		||||
          if not DoFunction(Dest^,Source,method_name,args) then
 | 
			
		||||
            RaiseDispError;
 | 
			
		||||
      end
 | 
			
		||||
      else
 | 
			
		||||
      begin
 | 
			
		||||
        // may be procedure?
 | 
			
		||||
        if not DoProcedure(Source,method_name,args) then
 | 
			
		||||
        // may be function?
 | 
			
		||||
        try
 | 
			
		||||
          variant(dummy_data) := Unassigned;
 | 
			
		||||
          if not DoFunction(dummy_data,Source,method_name,args) then
 | 
			
		||||
            RaiseDispError;
 | 
			
		||||
        finally
 | 
			
		||||
          VarDataClear(dummy_data)
 | 
			
		||||
        end;
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
    2:     { DISPATCH_PROPERTYGET -- currently never generated by compiler for Variant Dispatch }
 | 
			
		||||
      if has_result then
 | 
			
		||||
      begin
 | 
			
		||||
        // must be property...
 | 
			
		||||
        if not GetProperty(Dest^,Source,method_name) then
 | 
			
		||||
          // may be function?
 | 
			
		||||
          if not DoFunction(Dest^,Source,method_name,args) then
 | 
			
		||||
            RaiseDispError
 | 
			
		||||
      end
 | 
			
		||||
      else
 | 
			
		||||
        RaiseDispError;
 | 
			
		||||
 | 
			
		||||
    4:    { DISPATCH_PROPERTYPUT }
 | 
			
		||||
      if has_result or (arg_count<>1) or  // must be no result and a single arg
 | 
			
		||||
        (not SetProperty(Source,method_name,args[0])) then
 | 
			
		||||
        RaiseDispError;
 | 
			
		||||
  else
 | 
			
		||||
    RaiseDispError;
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TInvokeableVariantType.DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user