mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 04:11:35 +01:00 
			
		
		
		
	 5bf51c991c
			
		
	
	
		5bf51c991c
		
	
	
	
	
		
			
			- NoInterfaces() not used anymore, removed + Basic test for VariantArray of IInterface git-svn-id: trunk@16527 -
		
			
				
	
	
		
			798 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			798 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| {
 | |
|     This file is part of the Free Pascal run time library.
 | |
|     Copyright (c) 1999-2001 by the Free Pascal development team
 | |
| 
 | |
|     Variant routines for non-windows oses.
 | |
| 
 | |
|     See the file COPYING.FPC, included in this distribution,
 | |
|     for details about the copyright.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | |
| 
 | |
|  **********************************************************************}
 | |
| 
 | |
| { ---------------------------------------------------------------------
 | |
|     Some general stuff: Error handling and so on.
 | |
|   ---------------------------------------------------------------------}
 | |
| 
 | |
| { we do ugly things with tvararray here }
 | |
| {$RANGECHECKS OFF}
 | |
| 
 | |
| Procedure SetUnlockResult (P : PVarArray; Res : HResult);
 | |
| 
 | |
| begin
 | |
|   If Res=VAR_OK then
 | |
|     Res:=SafeArrayUnlock(P)
 | |
|   else
 | |
|     SafeArrayUnlock(P);
 | |
| end;
 | |
| 
 | |
| Procedure MakeWideString (Var P : PWideChar; W : WideString);
 | |
| 
 | |
| begin
 | |
|   P:=PWideChar(W);
 | |
| end;
 | |
| 
 | |
| Procedure CopyAsWideString (Var PDest : PWideChar; PSource : PWideChar);
 | |
| 
 | |
| begin
 | |
|   WideString(Pointer(PDest)):=WideString(Pointer(PSource));
 | |
| end;
 | |
| 
 | |
| { ---------------------------------------------------------------------
 | |
|     Basic variant handling.
 | |
|   ---------------------------------------------------------------------}
 | |
| 
 | |
| procedure VariantInit(var Varg: TVarData); stdcall;
 | |
| begin
 | |
|   With Varg do
 | |
|     begin
 | |
|       FillChar(VBytes, SizeOf(VBytes), 0);
 | |
|       VType:=varEmpty;
 | |
|     end;
 | |
| end;
 | |
| 
 | |
| function VariantClear(var Varg: TVarData): HRESULT;stdcall;
 | |
| begin
 | |
|   With Varg do
 | |
|     if (VType and varArray)=varArray then
 | |
|       begin
 | |
|         Result:=SafeArrayDestroy(VArray);
 | |
|         if Result<>VAR_OK then
 | |
|           exit;
 | |
|       end
 | |
|     else
 | |
|       begin
 | |
|       if (VType and varByRef) = 0 then
 | |
|         case VType of
 | |
|           varEmpty, varNull, varSmallint, varInteger, varWord,
 | |
| {$ifndef FPUNONE}
 | |
|           varSingle, varDouble, varCurrency, varDate,
 | |
| {$endif}
 | |
|           varError, varBoolean, varByte,VarShortInt,
 | |
|           varInt64, VarLongWord,VarQWord:
 | |
|             ;
 | |
|           varOleStr:
 | |
|             WideString(Pointer(VOleStr)):='';
 | |
|           varDispatch,
 | |
|           varUnknown:
 | |
|             iinterface(vunknown):=nil;
 | |
|         else
 | |
|           exit(VAR_BADVARTYPE)
 | |
|         end;
 | |
|     end;
 | |
|   VariantInit(Varg);
 | |
|   Result:=VAR_OK;
 | |
| end;
 | |
| 
 | |
| function VariantCopy(var VargDest: TVarData; const VargSrc: TVarData): HRESULT;stdcall;
 | |
| begin
 | |
|   if @VargSrc = @VargDest then
 | |
|     Exit(VAR_OK);
 | |
|   Result:=VariantClear(VargDest);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   With VargSrc do
 | |
|     begin
 | |
|     if (VType and varArray) <> 0 then
 | |
|       Result:=SafeArrayCopy(VArray,VargDest.VArray)
 | |
|     else
 | |
|       begin
 | |
|       if (VType and varByRef) <> 0 then
 | |
|         VArgDest.VPointer:=VPointer
 | |
|       else
 | |
|         case (VType and varTypeMask) of
 | |
|           varEmpty, varNull:;
 | |
|           varSmallint, varInteger, varWord,
 | |
| {$ifndef FPUNONE}
 | |
|           varSingle, varDouble, varCurrency, varDate,
 | |
| {$endif}
 | |
|           varError, varBoolean, varByte,VarShortInt,
 | |
|           varInt64, VarLongWord,VarQWord:
 | |
|             Move(VBytes, VargDest.VBytes, SizeOf(VargDest.VBytes));
 | |
|           varOleStr:
 | |
|             CopyAsWideString(VargDest.VOleStr,VOleStr);
 | |
|           varDispatch:
 | |
|             IUnknown(VargDest.vdispatch):=IUnknown(VargSrc.vdispatch);
 | |
|           varUnknown:
 | |
|             IUnknown(VargDest.vunknown):=IUnknown(VargSrc.vunknown);
 | |
|           else
 | |
|             Exit(VAR_BADVARTYPE);
 | |
|           end;
 | |
|         end;
 | |
|         VargDest.VType:=VType;
 | |
|     end;
 | |
| end;
 | |
| 
 | |
| function VariantCopyInd(var VargDest: TVarData; const VargSrc: TVarData): HRESULT;stdcall;
 | |
| 
 | |
| begin
 | |
|   if (VargSrc.VType and varByRef) = 0 then
 | |
|     Exit(VariantCopy(VargDest, VargSrc));
 | |
|   With VargSrc do
 | |
|     begin
 | |
|     if (VType and varArray) <> 0 then
 | |
|       Exit(VAR_INVALIDARG);
 | |
|     case (VType and varTypeMask) of
 | |
|       varEmpty, varNull:;
 | |
|       varSmallint : VargDest.VSmallInt:=PSmallInt(VPointer)^;
 | |
|       varInteger  : VargDest.VInteger:=PLongint(VPointer)^;
 | |
| {$ifndef FPUNONE}
 | |
|       varSingle   : VargDest.VSingle:=PSingle(VPointer)^;
 | |
|       varDouble   : VargDest.VDouble:=PDouble(VPointer)^;
 | |
|       varCurrency : VargDest.VCurrency:=PCurrency(VPointer)^;
 | |
|       varDate     : VargDest.VDate:=PDate(VPointer)^;
 | |
| {$endif}
 | |
|       varBoolean  : VargDest.VBoolean:=PWordBool(VPointer)^;
 | |
|       varError    : VargDest.VError:=PError(VPointer)^;
 | |
|       varByte     : VargDest.VByte:=PByte(VPointer)^;
 | |
|       varWord     : VargDest.VWord:=PWord(VPointer)^;
 | |
|       VarShortInt : VargDest.VShortInt:=PShortInt(VPointer)^;
 | |
|       VarInt64    : VargDest.VInt64:=PInt64(VPointer)^;
 | |
|       VarLongWord : VargDest.VLongWord:=PCardinal(VPointer)^;
 | |
|       VarQWord    : VargDest.VQWord:=PQWord(VPointer)^;
 | |
|       varVariant  : Variant(VargDest):=Variant(PVarData(VPointer)^);
 | |
|       varOleStr   : CopyAsWideString(VargDest.VOleStr,PVarData(VPointer)^.VoleStr);
 | |
|       varDispatch,
 | |
|       varUnknown  : IInterface(VargDest.vUnknown):=IInterface(PInterface(VargSrc.VPointer)^);
 | |
|       else
 | |
|         Exit(VAR_BADVARTYPE);
 | |
|       end;
 | |
|     VargDest.VType:=VType and VarTypeMask;
 | |
|     end;
 | |
|   Result:=VAR_OK;
 | |
| end;
 | |
| 
 | |
| Function VariantChangeTypeEx(var VargDest: TVarData; const VargSrc: TVarData;
 | |
|   LCID: Integer; Flags: Word; VarType: Word): HRESULT; stdcall;
 | |
| var
 | |
|   Tmp : TVarData;
 | |
| begin
 | |
|   if ((VarType and varArray) <> 0) or
 | |
|      ((VargSrc.VType and varArray) <> 0) or
 | |
|      ((VarType and varByRef) <> 0) then
 | |
|     Exit(VAR_INVALIDARG);
 | |
|   Result:=VariantCopyInd(Tmp, VargSrc);
 | |
|   if Result = VAR_OK then
 | |
|     try
 | |
|     Result:=VariantClear(VargDest);
 | |
|     {$RANGECHECKS ON}
 | |
|     if Result = VAR_OK then
 | |
|       try
 | |
|         case Vartype of
 | |
|           varSmallInt : VargDest.VSmallInt:=VariantToSmallInt(Tmp);
 | |
|           varInteger  : VargDest.VInteger:=VariantToLongint(Tmp);
 | |
| {$ifndef FPUNONE}
 | |
|           varSingle   : VargDest.VSingle:=VariantToSingle(Tmp);
 | |
|           varDouble   : VargDest.VDouble:=VariantToDouble(Tmp);
 | |
|           varCurrency : VargDest.VCurrency:=VariantToCurrency(Tmp);
 | |
|           varDate     : VargDest.VDate:=VariantToDate(tmp);
 | |
| {$endif}
 | |
|           varOleStr   : MakeWideString(VargDest.VoleStr, VariantToWideString(tmp));
 | |
|           varDispatch : Result:=VAR_TYPEMISMATCH;
 | |
|           varUnknown  : Result:=VAR_TYPEMISMATCH;
 | |
|           varBoolean  : VargDest.VBoolean:=VariantToBoolean(Tmp);
 | |
|           varByte     : VargDest.VByte:=VariantToByte(Tmp);
 | |
|           VarShortInt : VargDest.VShortInt:=VariantToShortInt(Tmp);
 | |
|           VarInt64    : VargDest.Vint64:=VariantToInt64(Tmp);
 | |
|           VarLongWord : VargDest.VLongWord:=VariantToCardinal(Tmp);
 | |
|           VarQWord    : VargDest.VQWord:=VariantToQword(tmp);
 | |
|        else
 | |
|           Result:=VAR_BADVARTYPE;
 | |
|        end;
 | |
|        If Result = VAR_OK then
 | |
|          VargDest.VType:=VarType;
 | |
|       except
 | |
|         On E : EVariantError do
 | |
|           Result:=E.ErrCode;
 | |
|         else
 | |
|           Result:=VAR_INVALIDARG;
 | |
|       end;
 | |
|     finally
 | |
|       VariantClear(Tmp);
 | |
|     end;
 | |
|   {$RANGECHECKS OFF}
 | |
| end;
 | |
| 
 | |
| { ---------------------------------------------------------------------
 | |
|     Variant array support
 | |
|   ---------------------------------------------------------------------}
 | |
| 
 | |
| Function CheckArrayUnlocked (psa : PVarArray) : HResult;
 | |
| 
 | |
| begin
 | |
|   If psa^.LockCount = 0 Then
 | |
|     Result:=VAR_OK
 | |
|   else
 | |
|     Result:=VAR_ARRAYISLOCKED;
 | |
| end;
 | |
| 
 | |
| Function CheckVarArray(psa: PVarArray ): HRESULT;
 | |
| 
 | |
| begin
 | |
|   If psa=nil then
 | |
|     Result:=VAR_INVALIDARG
 | |
|   else
 | |
|     Result:=VAR_OK;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayCalculateElementAddress(psa: PVarArray; aElement: SizeInt): Pointer;
 | |
| 
 | |
| begin
 | |
|   Result:=Pointer(psa^.Data)+(aElement*psa^.ElementSize);
 | |
| end;
 | |
| 
 | |
| Function CheckVarArrayAndCalculateAddress(psa: PVarArray;
 | |
|   Indices: PVarArrayCoorArray; var Address: Pointer; Lockit: Boolean): HRESULT;
 | |
| var
 | |
|   I,D,Count,Idx : LongInt;
 | |
| 
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   Address:=nil;
 | |
|   Count:=0;
 | |
|   If Result<>VAR_OK then
 | |
|     exit;
 | |
|   D:=0;
 | |
|   for I:=0 to psa^.DimCount-1 do
 | |
|     begin
 | |
|       Idx:=Indices^[psa^.DimCount-I-1] - psa^.Bounds[I].LowBound;
 | |
|       if (Idx<0) or (Idx>=psa^.Bounds[I].ElementCount) then
 | |
|         Exit(VAR_BADINDEX);
 | |
|       if I=0 then
 | |
|         Count:=Idx
 | |
|       else
 | |
|         Inc(Count,Idx*D);
 | |
|       Inc(D,psa^.Bounds[I].ElementCount);
 | |
|     end;
 | |
|   Address:=SafeArrayCalculateElementAddress(psa, Count);
 | |
|   if LockIt then
 | |
|     Result:=SafeArrayLock(psa);
 | |
| end;
 | |
| 
 | |
| Function SafeArrayElementTotal(psa: PVarArray): Integer;
 | |
| 
 | |
| var
 | |
|   I: Integer;
 | |
| 
 | |
| begin
 | |
|   Result:=1;
 | |
|   With psa^ do
 | |
|    for I:=0 to DimCount - 1 do
 | |
|      Result:=Result*Bounds[I].ElementCount;
 | |
| end;
 | |
| 
 | |
| type
 | |
|   TVariantArrayType = (vatNormal, vatInterface, vatWideString, vatVariant);
 | |
| 
 | |
| Function VariantArrayType(psa: PVarArray): TVariantArrayType;
 | |
| 
 | |
| begin
 | |
|   if ((psa^.Flags and ARR_DISPATCH) <> 0) or
 | |
|      ((psa^.Flags and ARR_UNKNOWN) <> 0) then
 | |
|     Result:=vatInterface
 | |
|   else if (psa^.Flags AND ARR_OLESTR) <> 0 then
 | |
|     Result:=vatWideString
 | |
|   else if (psa^.Flags and ARR_VARIANT) <> 0 then
 | |
|     Result := vatVariant
 | |
|   else
 | |
|     Result:=vatNormal;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayClearDataSpace(psa: PVarArray; WipeBytes: Boolean {= True}): HRESULT;
 | |
| 
 | |
| var
 | |
|   vat: TVariantArrayType;
 | |
|   P : Pointer;
 | |
|   J,Count : Integer;
 | |
| begin
 | |
|   try
 | |
|     count:=SafeArrayElementTotal(psa);
 | |
|     vat:=VariantArrayType(psa);
 | |
|     case vat of
 | |
|       vatNormal : FillChar(psa^.Data^,Count*psa^.ElementSize,0);
 | |
|       vatInterface :
 | |
|          for j := 0 to Count - 1 do
 | |
|            begin
 | |
|            P := SafeArrayCalculateElementAddress(psa,j);
 | |
|            IUnknown(PUnknown(P)^):=Nil
 | |
|            end;
 | |
|       vatWideString :
 | |
|          for j := 0 to Count - 1 do
 | |
|            begin
 | |
|            P := SafeArrayCalculateElementAddress(psa,j);
 | |
|            WideString(PPointer(P)^):='';
 | |
|            end;
 | |
|       vatVariant :
 | |
|          for j := 0 to Count - 1 do
 | |
|            begin
 | |
|            P := SafeArrayCalculateElementAddress(psa,j);
 | |
|            VariantClear(PVarData(P)^);
 | |
|            end;
 | |
|     end;
 | |
|     Result:=VAR_OK;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError (E);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayCopyDataSpace(psa, psaOut: PVarArray): HRESULT;
 | |
| var
 | |
|   vat: TVariantArrayType;
 | |
|   P1,P2 : Pointer;
 | |
|   J,Count : Integer;
 | |
| begin
 | |
|   try
 | |
|     Count:=SafeArrayElementTotal(psa);
 | |
|     vat:=VariantArrayType(psa);
 | |
|     case vat of
 | |
|       vatNormal: Move(psa^.Data^,psaOut^.Data^,Count*psa^.ElementSize);
 | |
|       vatInterface :
 | |
|          for j := 0 to Count - 1 do
 | |
|            begin
 | |
|            P1 := SafeArrayCalculateElementAddress(psa,j);
 | |
|            P2 := SafeArrayCalculateElementAddress(psaout,j);
 | |
|            IUnknown(PUnknown(P2)^):=IUnknown(PUnknown(P1)^);
 | |
|            end;
 | |
|       vatWideString :
 | |
|          for j := 0 to Count - 1 do
 | |
|            begin
 | |
|            P1 := SafeArrayCalculateElementAddress(psa,j);
 | |
|            P2 := SafeArrayCalculateElementAddress(psaOut,j);
 | |
|            WideString(PPointer(P2)^):=WideString(PPointer(P1)^);
 | |
|            end;
 | |
|       vatVariant :
 | |
|          for j := 0 to Count - 1 do
 | |
|            begin
 | |
|            P1 := SafeArrayCalculateElementAddress(psa,j);
 | |
|            P2 := SafeArrayCalculateElementAddress(psaOut,j);
 | |
|            VariantCopy(PVarData(P2)^,PVarData(P2)^);
 | |
|            end;
 | |
|     end;
 | |
|     Result:=VAR_OK;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| Const
 | |
|   Supportedpsas = [varSmallint,varInteger,
 | |
| {$ifndef FPUNONE}
 | |
|      varSingle,varDouble,varCurrency,varDate,
 | |
| {$endif}
 | |
|      varOleStr,varDispatch,varError,varBoolean,varVariant,varUnknown,varShortInt,varByte,
 | |
|      varWord,varLongWord,varInt64,varQWord];
 | |
|   psaElementFlags : Array [varEmpty..varQWord] of Longint =
 | |
|     (ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,
 | |
|      ARR_OLESTR,ARR_DISPATCH,ARR_NONE,ARR_NONE,ARR_VARIANT,ARR_UNKNOWN,
 | |
|      ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE);
 | |
|   psaElementSizes : Array [varEmpty..varQWord] of Byte =
 | |
|     (0,0,                  // varempty, varnull
 | |
|      SizeOf(SmallInt),     // varsmallint
 | |
|      SizeOf(Integer),      // varinteger
 | |
|      SizeOf(Single),       // varsingle
 | |
|      SizeOf(Double),       // vardouble
 | |
|      SizeOf(Currency),     // varcurrency
 | |
|      SizeOf(TDateTime),    // vardate
 | |
|      SizeOf(PWideString),  // varolestr
 | |
|      SizeOf(IInterface),   // vardispatch
 | |
|      SizeOf(TError),       // varerror
 | |
|      SizeOf(Boolean),      // varboolean
 | |
|      SizeOf(TVarData),     // varvariant
 | |
|      SizeOf(IUnknown),     // varunknown
 | |
|      0, // Decimal         // vardecimal
 | |
|      0, // Unused
 | |
|      SizeOf(ShortInt),     // varshortint
 | |
|      SizeOf(Byte),         // varbyte
 | |
|      SizeOf(Word),         // varword
 | |
|      SizeOf(LongWord),     // varlongword
 | |
|      SizeOf(Int64),        // varint64
 | |
|      SizeOf(QWord));       // varqword
 | |
| 
 | |
| Function SafeArrayCreate(VarType, Dim: DWord; const Bounds: TVarArrayBoundArray): PVarArray;stdcall;
 | |
|   var
 | |
|     res : HRESULT;
 | |
|     I   : DWord;
 | |
|   begin
 | |
|     Result:=nil;
 | |
|     if Not (VarType in Supportedpsas) Then
 | |
|       exit;
 | |
|     Res:=SafeArrayAllocDescriptor(Dim, Result);
 | |
|     if Res<>VAR_OK then
 | |
|       exit;
 | |
|     Result^.DimCount:=Dim;
 | |
|     Result^.Flags:=psaElementFlags[VarType];
 | |
|     Result^.ElementSize:=psaElementSizes[VarType];
 | |
|     Result^.LockCount := 0;
 | |
|     for i:=0 to Dim-1 do
 | |
|       begin
 | |
|         Result^.Bounds[i].LowBound:=Bounds[Dim-I-1].LowBound;
 | |
|         Result^.Bounds[I].ElementCount:=Bounds[Dim-I-1].ElementCount;
 | |
|       end;
 | |
|     res:=SafeArrayAllocData(Result);
 | |
|     if res<>VAR_OK then
 | |
|       begin
 | |
|       SafeArrayDestroyDescriptor(Result);
 | |
|       Result:=nil;
 | |
|       end;
 | |
|   end;
 | |
| 
 | |
| 
 | |
| Function SafeArrayAllocDescriptor(DimCount: Dword; var psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   try
 | |
|     { one bound item is included in TVarArray }
 | |
|     psa:=GetMem(SizeOf(TVarArray) + SizeOf(TVarArrayBound)*(DimCount-1));
 | |
|     Result:=VAR_OK;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayAllocData(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   try
 | |
|     With psa^ do
 | |
|       begin
 | |
|         Data:=GetMem(SafeArrayElementTotal(psa)*ElementSize);
 | |
|         fillchar(Data^,SafeArrayElementTotal(psa)*ElementSize,0);
 | |
|       end;
 | |
|     Result:=VAR_OK;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayDestroy(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<> VAR_OK then
 | |
|     exit;
 | |
|   Result:=CheckArrayUnlocked(psa);
 | |
|   if Result<> VAR_OK then
 | |
|     exit;
 | |
|   Result:=SafeArrayDestroyData(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   Result:=SafeArrayDestroyDescriptor(psa);
 | |
| end;
 | |
| 
 | |
| Function SafeArrayDestroyDescriptor(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   Result:=CheckArrayUnlocked(psa);
 | |
|   if Result<> VAR_OK then
 | |
|     exit;
 | |
|   try
 | |
|     FreeMem(psa);
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayDestroyData(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   Result:=CheckArrayUnlocked(psa);
 | |
|   if Result<> VAR_OK then
 | |
|     exit;
 | |
|   try
 | |
|     Result:=SafeArrayClearDataSpace(psa, False);
 | |
|     if (Result=VAR_OK) and ((psa^.Flags and ARR_FIXEDSIZE)=0) then
 | |
|       begin
 | |
|       FreeMem(psa^.Data);
 | |
|       psa^.Data:=nil;
 | |
|       end;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayRedim(psa: PVarArray; const NewBound: TVarArrayBound): HRESULT;stdcall;
 | |
| 
 | |
| var
 | |
|   vat: TVariantArrayType;
 | |
|   i, D,j,count : Integer;
 | |
|   P : Pointer;
 | |
| 
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result <> VAR_OK then
 | |
|     exit;
 | |
|   if (psa^.Flags and ARR_FIXEDSIZE) <> 0 then
 | |
|     Exit(VAR_INVALIDARG);
 | |
|   Result:=SafeArrayLock(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   try
 | |
|     D:=NewBound.ElementCount - psa^.Bounds[0].ElementCount;
 | |
|     for i:=1 to psa^.DimCount - 1 do
 | |
|       D:=D*psa^.Bounds[i].ElementCount;
 | |
|     if D<>0 then
 | |
|       begin
 | |
|       Count:=SafeArrayElementTotal(psa);
 | |
|       if D<0 then
 | |
|         begin
 | |
|         vat:=VariantArrayType(psa);
 | |
|         for j:=Count-1 downto Count+D do
 | |
|           begin
 | |
|           P:=SafeArrayCalculateElementAddress(psa,j);
 | |
|           if vat = vatInterface then
 | |
|             IUnknown(PPointer(P)^):=Nil
 | |
|           else if vat=vatWideString then
 | |
|             WideString(PPointer(P)^):=''
 | |
|           else if vat=vatVariant then
 | |
|             VariantClear(PVarData(P)^);
 | |
|           end;
 | |
|         end;
 | |
|       ReAllocMem(psa^.Data,(Count+D)*psa^.ElementSize);
 | |
|       if D>0 then
 | |
|         fillchar((PChar(psa^.Data)+Count*psa^.ElementSize)^,D*psa^.ElementSize,0);
 | |
|       end;
 | |
|     psa^.Bounds[0].ElementCount:=NewBound.ElementCount;
 | |
|     psa^.Bounds[0].LowBound:=NewBound.LowBound;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
|   SetUnlockResult(psa,Result);
 | |
| end;
 | |
| 
 | |
| Function SafeArrayCopy(psa: PVarArray; var psaOut: PVarArray): HRESULT;stdcall;
 | |
| 
 | |
| var
 | |
|   i : Integer;
 | |
| 
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   Result:=SafeArrayLock(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   try
 | |
|     Result:=SafeArrayAllocDescriptor(psa^.DimCount,psaOut);
 | |
|     if Result<>VAR_OK then
 | |
|       Exit;
 | |
|     try
 | |
|       With psaOut^ do
 | |
|         begin
 | |
|         Flags:=psa^.Flags;
 | |
|         ElementSize:=psa^.ElementSize;
 | |
|         LockCount := 0;
 | |
|         DimCount:=psa^.DimCount;
 | |
|         for i:=0 to DimCount-1 do
 | |
|           begin
 | |
|           Bounds[i].ElementCount:=psa^.Bounds[i].ElementCount;
 | |
|           Bounds[i].LowBound:=psa^.Bounds[i].LowBound;
 | |
|           end;
 | |
|         end;
 | |
|       Result:=SafeArrayAllocData(psaOut);
 | |
|       if Result<>VAR_OK then
 | |
|         exit;
 | |
|       Result:=SafeArrayCopyDataSpace(psa, psaOut);
 | |
|     finally
 | |
|       if Result<>VAR_OK then
 | |
|         begin
 | |
|         SafeArrayDestroyDescriptor(psaOut);
 | |
|         psaOut:=nil;
 | |
|         end;
 | |
|     end;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E)
 | |
|   end;
 | |
|   SetUnlockResult(psa,Result);
 | |
| end;
 | |
| 
 | |
| Function SafeArrayCopyData(psa, psaOut: PVarArray): HRESULT;stdcall;
 | |
| var
 | |
|   i : Integer;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   Result:=CheckVarArray(psaOut);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   Result:=SafeArrayLock(psaOut);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   try
 | |
|     Result:=SafeArrayLock(psa);
 | |
|     if Result<>VAR_OK then
 | |
|      exit;
 | |
|     try
 | |
|       With psaOut^ do
 | |
|         begin
 | |
|         if (psa^.Flags<>Flags) or
 | |
|            (psa^.ElementSize<>ElementSize) or
 | |
|            (psa^.DimCount<>DimCount) then
 | |
|           Exit(VAR_INVALIDARG);
 | |
|         for i:=0 to psa^.DimCount - 1 do
 | |
|           if (psa^.Bounds[i].LowBound<>Bounds[i].LowBound) or
 | |
|              (psa^.Bounds[i].ElementCount<>Bounds[i].ElementCount) then
 | |
|             exit(VAR_INVALIDARG);
 | |
|         end;
 | |
|       Result:=SafeArrayClearDataSpace(psaOut,True);
 | |
|       if Result<> VAR_OK then
 | |
|         exit;
 | |
|       Result:=SafeArrayCopyDataSpace(psa, psaOut);
 | |
|     finally
 | |
|       SetUnlockResult(psa,Result);
 | |
|     end;
 | |
|   finally
 | |
|     SetUnlockResult(psaOut,Result);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayGetLBound(psa: PVarArray; Dim: DWord; var LBound: LongInt): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   if (Dim>0) and (Dim<=psa^.DimCount) then
 | |
|     LBound:=psa^.Bounds[psa^.dimcount-Dim].LowBound
 | |
|   else
 | |
|     Result:=VAR_BADINDEX;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayGetUBound(psa: PVarArray; Dim : DWord; var UBound: LongInt): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   if (Dim>0) and (Dim<=psa^.DimCount) then
 | |
|     UBound:=psa^.Bounds[psa^.dimcount-Dim].LowBound +
 | |
|             psa^.Bounds[psa^.dimcount-Dim].ElementCount-1
 | |
|   else
 | |
|     Result:=VAR_BADINDEX
 | |
| end;
 | |
| 
 | |
| Function SafeArrayGetDim(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   if CheckVarArray(psa)<>VAR_OK then
 | |
|     Result:=0
 | |
|   else
 | |
|     Result:=psa^.DimCount;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayAccessData(psa: PVarArray; var ppvData: Pointer): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=SafeArrayLock(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     ppvData:=nil
 | |
|   else
 | |
|     ppvData:=psa^.Data;
 | |
| end;
 | |
| 
 | |
| Function SafeArrayUnaccessData(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=SafeArrayUnlock(psa);
 | |
| end;
 | |
| 
 | |
| Function SafeArrayLock(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   InterlockedIncrement(psa^.LockCount);
 | |
| end;
 | |
| 
 | |
| Function SafeArrayUnlock(psa: PVarArray): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArray(psa);
 | |
|   if (Result<>VAR_OK) then
 | |
|     exit;
 | |
|   if InterlockedDecrement(psa^.LockCount)<0 then
 | |
|     begin
 | |
|       InterlockedIncrement(psa^.LockCount);
 | |
|       result:=VAR_UNEXPECTED;
 | |
|     end;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function SafeArrayGetElement(psa: PVarArray; Indices: PVarArrayCoorArray;
 | |
|   Data: Pointer): HRESULT;stdcall;
 | |
| var
 | |
|   P: Pointer;
 | |
| begin
 | |
|   Result:=CheckVarArrayAndCalculateAddress(psa, Indices, P, True);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   try
 | |
|     case VariantArrayType(psa) of
 | |
|       vatNormal:
 | |
|         Move(P^, Data^, psa^.ElementSize);
 | |
|       vatInterface:
 | |
|         IInterface(PInterface(Data)^) := IInterface(PInterface(P)^);
 | |
|       vatWideString:
 | |
|         CopyAsWideString(PWideChar(Data^), PWideChar(P^));
 | |
|       vatVariant:
 | |
|         VariantCopy(PVarData(Data)^, PVarData(P)^);
 | |
|     end;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
|   SetUnlockResult(psa,Result);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function SafeArrayPutElement(psa: PVarArray; Indices: PVarArrayCoorArray;
 | |
|   const Data: Pointer): HRESULT;stdcall;
 | |
| var
 | |
|   P: Pointer;
 | |
| begin
 | |
|   Result:=CheckVarArrayAndCalculateAddress(psa,Indices,P,True);
 | |
|   if Result<>VAR_OK then
 | |
|     exit;
 | |
|   try
 | |
|     case VariantArrayType(psa) of
 | |
|       vatNormal:
 | |
|         Move(Data^,P^,psa^.ElementSize);
 | |
|       vatInterface:
 | |
|         IInterface(PInterface(P)^):=IInterface(Data);
 | |
|       vatWideString:
 | |
|         CopyAsWideString(PWideChar(P^), PWideChar(Data));
 | |
|       vatVariant:
 | |
|         VariantCopy(PVarData(P)^, PVarData(Data)^);    // !! Untested
 | |
|     end;
 | |
|   except
 | |
|     On E : Exception do
 | |
|       Result:=ExceptionToVariantError(E);
 | |
|   end;
 | |
|   SetUnlockResult(psa,Result);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function SafeArrayPtrOfIndex(psa: PVarArray; Indices: PVarArrayCoorArray;
 | |
|   var Address: Pointer): HRESULT;stdcall;
 | |
| begin
 | |
|   Result:=CheckVarArrayAndCalculateAddress(psa,Indices,Address,False);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function SafeArrayGetElemSize(psa: PVarArray): LongWord;stdcall;
 | |
| begin
 | |
|   if CheckVarArray(psa)<>VAR_OK then
 | |
|     Result:=0
 | |
|   else
 | |
|     Result:=psa^.ElementSize;
 | |
| end;
 | |
| 
 | |
| 
 | |
| 
 |