1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420 |
- {
- This include file contains the variants
- support for FPC
- This file is part of the Free Pascal run time library.
- Copyright (c) 2001-2005 by the Free Pascal development team
- 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.
- **********************************************************************}
- {$IFDEF fpc}
- {$mode objfpc}
- {$ENDIF}
- {$h+}
- { Using inlining for small system functions/wrappers }
- {$inline on}
- {$define VARIANTINLINE}
- unit variants;
- interface
- uses
- sysutils,sysconst,rtlconsts,typinfo;
- type
- EVariantParamNotFoundError = class(EVariantError);
- EVariantInvalidOpError = class(EVariantError);
- EVariantTypeCastError = class(EVariantError);
- EVariantOverflowError = class(EVariantError);
- EVariantInvalidArgError = class(EVariantError);
- EVariantBadVarTypeError = class(EVariantError);
- EVariantBadIndexError = class(EVariantError);
- EVariantArrayLockedError = class(EVariantError);
- EVariantNotAnArrayError = class(EVariantError);
- EVariantArrayCreateError = class(EVariantError);
- EVariantNotImplError = class(EVariantError);
- EVariantOutOfMemoryError = class(EVariantError);
- EVariantUnexpectedError = class(EVariantError);
- EVariantDispatchError = class(EVariantError);
- EVariantRangeCheckError = class(EVariantOverflowError);
- EVariantInvalidNullOpError = class(EVariantInvalidOpError);
- TVariantRelationship = (vrEqual, vrLessThan, vrGreaterThan, vrNotEqual);
- TNullCompareRule = (ncrError, ncrStrict, ncrLoose);
- TBooleanToStringRule = (bsrAsIs, bsrLower, bsrUpper);
- Const
- OrdinalVarTypes = [varSmallInt, varInteger, varBoolean, varShortInt,
- varByte, varWord,varLongWord,varInt64];
- FloatVarTypes = [
- {$ifndef FPUNONE}
- varSingle, varDouble,
- {$endif}
- varCurrency];
- { Variant support procedures and functions }
- function VarType(const V: Variant): TVarType; inline;
- function VarTypeDeRef(const V: Variant): TVarType; overload;
- function VarTypeDeRef(const V: TVarData): TVarType; overload; inline;
- function VarAsType(const V: Variant; aVarType: TVarType): Variant;
- function VarIsType(const V: Variant; aVarType: TVarType): Boolean; overload; inline;
- function VarIsType(const V: Variant; const AVarTypes: array of TVarType): Boolean; overload;
- function VarIsByRef(const V: Variant): Boolean; inline;
- function VarIsEmpty(const V: Variant): Boolean; inline;
- procedure VarCheckEmpty(const V: Variant); inline;
- function VarIsNull(const V: Variant): Boolean; inline;
- function VarIsClear(const V: Variant): Boolean; inline;
- function VarIsCustom(const V: Variant): Boolean; inline;
- function VarIsOrdinal(const V: Variant): Boolean; inline;
- function VarIsFloat(const V: Variant): Boolean; inline;
- function VarIsNumeric(const V: Variant): Boolean; inline;
- function VarIsStr(const V: Variant): Boolean;
- function VarToStr(const V: Variant): string;
- function VarToStrDef(const V: Variant; const ADefault: string): string;
- function VarToWideStr(const V: Variant): WideString;
- function VarToWideStrDef(const V: Variant; const ADefault: WideString): WideString;
- function VarToUnicodeStr(const V: Variant): UnicodeString;
- function VarToUnicodeStrDef(const V: Variant; const ADefault: UnicodeString): UnicodeString;
- {$ifndef FPUNONE}
- function VarToDateTime(const V: Variant): TDateTime;
- function VarFromDateTime(const DateTime: TDateTime): Variant;
- {$endif}
- function VarInRange(const AValue, AMin, AMax: Variant): Boolean;
- function VarEnsureRange(const AValue, AMin, AMax: Variant): Variant;
- function VarSameValue(const A, B: Variant): Boolean;
- function VarCompareValue(const A, B: Variant): TVariantRelationship;
- function VarIsEmptyParam(const V: Variant): Boolean; inline;
- procedure VarClear(var V: Variant);{$IFDEF VARIANTINLINE}inline;{$ENDIF VARIANTINLINE}
- procedure VarClear(var V: OleVariant);{$IFDEF VARIANTINLINE}inline;{$ENDIF VARIANTINLINE}
- procedure SetClearVarToEmptyParam(var V: TVarData);
- function VarIsError(const V: Variant; out AResult: HRESULT): Boolean;
- function VarIsError(const V: Variant): Boolean; inline;
- function VarAsError(AResult: HRESULT): Variant;
- function VarSupports(const V: Variant; const IID: TGUID; out Intf): Boolean;
- function VarSupports(const V: Variant; const IID: TGUID): Boolean;
- { Variant copy support }
- procedure VarCopyNoInd(var Dest: Variant; const Source: Variant);
- { Variant array support procedures and functions }
- function VarArrayCreate(const Bounds: array of SizeInt; aVarType: TVarType): Variant;
- function VarArrayCreate(const Bounds: PVarArrayBoundArray; Dims : SizeInt; aVarType: TVarType): Variant;
- function VarArrayOf(const Values: array of Variant): Variant;
- function VarArrayAsPSafeArray(const A: Variant): PVarArray;
- function VarArrayDimCount(const A: Variant) : LongInt;
- function VarArrayLowBound(const A: Variant; Dim : LongInt) : LongInt;
- function VarArrayHighBound(const A: Variant; Dim : LongInt) : LongInt;
- function VarArrayLock(const A: Variant): Pointer;
- procedure VarArrayUnlock(const A: Variant);
- function VarArrayRef(const A: Variant): Variant;
- function VarIsArray(const A: Variant): Boolean; inline;
- function VarIsArray(const A: Variant; AResolveByRef: Boolean): Boolean;
- function VarTypeIsValidArrayType(const aVarType: TVarType): Boolean;
- function VarTypeIsValidElementType(const aVarType: TVarType): Boolean;
- { Variant <--> Dynamic Arrays }
- procedure DynArrayToVariant(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
- procedure DynArrayFromVariant(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);
- { Global constants }
- function Unassigned: Variant; // Unassigned standard constant
- function Null: Variant; // Null standard constant
- var
- EmptyParam: OleVariant;
- { Custom Variant base class }
- type
- TVarCompareResult = (crLessThan, crEqual, crGreaterThan);
- TCustomVariantType = class(TObject, IInterface)
- private
- FVarType: TVarType;
- protected
- function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
- function _AddRef: Integer; stdcall;
- function _Release: Integer; stdcall;
- procedure SimplisticClear(var V: TVarData);
- procedure SimplisticCopy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean = False);
- procedure RaiseInvalidOp;
- procedure RaiseCastError;
- procedure RaiseDispError;
- function LeftPromotion(const V: TVarData; const Operation: TVarOp; out RequiredVarType: TVarType): Boolean; virtual;
- function RightPromotion(const V: TVarData; const Operation: TVarOp; out RequiredVarType: TVarType): Boolean; virtual;
- function OlePromotion(const V: TVarData; out RequiredVarType: TVarType): Boolean; virtual;
- procedure DispInvoke(Dest: PVarData; const Source: TVarData; CallDesc: PCallDesc; Params: Pointer); virtual;
- procedure VarDataInit(var Dest: TVarData);
- procedure VarDataClear(var Dest: TVarData);
- procedure VarDataCopy(var Dest: TVarData; const Source: TVarData);
- procedure VarDataCopyNoInd(var Dest: TVarData; const Source: TVarData);
- procedure VarDataCast(var Dest: TVarData; const Source: TVarData);
- procedure VarDataCastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); overload;
- procedure VarDataCastTo(var Dest: TVarData; const aVarType: TVarType); overload;
- procedure VarDataCastToOleStr(var Dest: TVarData);
- procedure VarDataFromStr(var V: TVarData; const Value: string);
- procedure VarDataFromOleStr(var V: TVarData; const Value: WideString);
- function VarDataToStr(const V: TVarData): string;
- function VarDataIsEmptyParam(const V: TVarData): Boolean;
- function VarDataIsByRef(const V: TVarData): Boolean;
- function VarDataIsArray(const V: TVarData): Boolean;
- function VarDataIsOrdinal(const V: TVarData): Boolean;
- function VarDataIsFloat(const V: TVarData): Boolean;
- function VarDataIsNumeric(const V: TVarData): Boolean;
- function VarDataIsStr(const V: TVarData): Boolean;
- public
- constructor Create; overload;
- constructor Create(RequestedVarType: TVarType); overload;
- destructor Destroy; override;
- function IsClear(const V: TVarData): Boolean; virtual;
- procedure Cast(var Dest: TVarData; const Source: TVarData); virtual;
- procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); virtual;
- procedure CastToOle(var Dest: TVarData; const Source: TVarData); virtual;
- procedure Clear(var V: TVarData); virtual; abstract;
- procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); virtual; abstract;
- procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp); virtual;
- procedure UnaryOp(var Right: TVarData; const Operation: TVarOp); virtual;
- function CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean; virtual;
- procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); virtual;
- property VarType: TVarType read FVarType;
- end;
- TCustomVariantTypeClass = class of TCustomVariantType;
- TVarDataArray = array of TVarData;
- IVarInvokeable = interface
- ['{1CB65C52-BBCB-41A6-9E58-7FB916BEEB2D}']
- function DoFunction(var Dest: TVarData; const V: TVarData;
- const Name: string; const Arguments: TVarDataArray): Boolean;
- function DoProcedure(const V: TVarData; const Name: string;
- const Arguments: TVarDataArray): Boolean;
- function GetProperty(var Dest: TVarData; const V: TVarData;
- const Name: string): Boolean;
- function SetProperty(const V: TVarData; const Name: string;
- const Value: TVarData): Boolean;
- end;
- TInvokeableVariantType = class(TCustomVariantType, IVarInvokeable)
- protected
- procedure DispInvoke(Dest: PVarData; const Source: TVarData;
- CallDesc: PCallDesc; Params: Pointer); override;
- public
- { IVarInvokeable }
- function DoFunction(var Dest: TVarData; const V: TVarData;
- const Name: string; const Arguments: TVarDataArray): Boolean; virtual;
- function DoProcedure(const V: TVarData; const Name: string;
- const Arguments: TVarDataArray): Boolean; virtual;
- function GetProperty(var Dest: TVarData; const V: TVarData;
- const Name: string): Boolean; virtual;
- function SetProperty(const V: TVarData; const Name: string;
- const Value: TVarData): Boolean; virtual;
- end;
- IVarInstanceReference = interface
- ['{5C176802-3F89-428D-850E-9F54F50C2293}']
- function GetInstance(const V: TVarData): TObject;
- end;
- TPublishableVariantType = class(TInvokeableVariantType, IVarInstanceReference)
- protected
- { IVarInstanceReference }
- function GetInstance(const V: TVarData): TObject; virtual; abstract;
- public
- function GetProperty(var Dest: TVarData; const V: TVarData;
- const Name: string): Boolean; override;
- function SetProperty(const V: TVarData; const Name: string;
- const Value: TVarData): Boolean; override;
- end;
- function FindCustomVariantType(const aVarType: TVarType;
- out CustomVariantType: TCustomVariantType): Boolean; overload;
- function FindCustomVariantType(const TypeName: string;
- out CustomVariantType: TCustomVariantType): Boolean; overload;
- type
- TAnyProc = procedure (var V: TVarData);
- TVarDispProc = procedure (Dest: PVariant; const Source: Variant;
- CallDesc: PCallDesc; Params: Pointer); cdecl;
- Const
- CMaxNumberOfCustomVarTypes = $06FF;
- CMinVarType = $0100;
- CMaxVarType = CMinVarType + CMaxNumberOfCustomVarTypes;
- CIncVarType = $000F;
- CFirstUserType = CMinVarType + CIncVarType;
- var
- NullEqualityRule: TNullCompareRule = ncrLoose;
- NullMagnitudeRule: TNullCompareRule = ncrLoose;
- NullStrictConvert: Boolean = true;
- NullAsStringValue: string = '';
- PackVarCreation: Boolean = True;
- {$ifndef FPUNONE}
- OleVariantInt64AsDouble: Boolean = False;
- {$endif}
- VarDispProc: TVarDispProc;
- ClearAnyProc: TAnyProc; { Handler clearing a varAny }
- ChangeAnyProc: TAnyProc; { Handler to change any to Variant }
- RefAnyProc: TAnyProc; { Handler to add a reference to an varAny }
- InvalidCustomVariantType : TCustomVariantType;
- procedure VarCastError;
- procedure VarCastError(const ASourceType, ADestType: TVarType);
- procedure VarCastErrorOle(const ASourceType: TVarType);
- procedure VarInvalidOp;
- procedure VarInvalidOp(const aLeft, aRight: TVarType; aOpCode: TVarOp);
- procedure VarInvalidOp(const aRight: TVarType; aOpCode: TVarOp);
- procedure VarInvalidNullOp;
- procedure VarBadTypeError;
- procedure VarOverflowError;
- procedure VarOverflowError(const ASourceType, ADestType: TVarType);
- procedure VarBadIndexError;
- procedure VarArrayLockedError;
- procedure VarNotImplError;
- procedure VarOutOfMemoryError;
- procedure VarInvalidArgError;
- procedure VarInvalidArgError(AType: TVarType);
- procedure VarUnexpectedError;
- procedure VarRangeCheckError(const AType: TVarType);
- procedure VarRangeCheckError(const ASourceType, ADestType: TVarType);
- procedure VarArrayCreateError;
- procedure VarResultCheck(AResult: HRESULT);{$IFDEF VARIANTINLINE}inline;{$ENDIF VARIANTINLINE}
- procedure VarResultCheck(AResult: HRESULT; ASourceType, ADestType: TVarType);
- procedure HandleConversionException(const ASourceType, ADestType: TVarType);
- function VarTypeAsText(const AType: TVarType): string;
- function FindVarData(const V: Variant): PVarData;
- const
- VarOpAsText : array[TVarOp] of string = (
- '+', {opAdd}
- '-', {opSubtract}
- '*', {opMultiply}
- '/', {opDivide}
- 'div', {opIntDivide}
- 'mod', {opModulus}
- 'shl', {opShiftLeft}
- 'shr', {opShiftRight}
- 'and', {opAnd}
- 'or', {opOr}
- 'xor', {opXor}
- '', {opCompare}
- '-', {opNegate}
- 'not', {opNot}
- '=', {opCmpEq}
- '<>', {opCmpNe}
- '<', {opCmpLt}
- '<=', {opCmpLe}
- '>', {opCmpGt}
- '>=', {opCmpGe}
- '**' {opPower}
- );
- { Typinfo unit Variant routines have been moved here, so as not to make TypInfo dependent on variants }
- Function GetPropValue(Instance: TObject; const PropName: string): Variant;
- Function GetPropValue(Instance: TObject; const PropName: string; PreferStrings: Boolean): Variant;
- Procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant);
- Function GetVariantProp(Instance: TObject; PropInfo : PPropInfo): Variant;
- Function GetVariantProp(Instance: TObject; const PropName: string): Variant;
- Procedure SetVariantProp(Instance: TObject; const PropName: string; const Value: Variant);
- Procedure SetVariantProp(Instance: TObject; PropInfo : PPropInfo; const Value: Variant);
- {$IFDEF DEBUG_VARIANTS}
- var
- __DEBUG_VARIANTS: Boolean = False;
- {$ENDIF}
- implementation
- uses
- Math,
- VarUtils;
- {$IFOPT R-} {$DEFINE RANGECHECKINGOFF} {$ENDIF}
- {$IFOPT Q-} {$DEFINE OVERFLOWCHECKINGOFF} {$ENDIF}
- var
- customvarianttypes : array of TCustomVariantType;
- customvarianttypelock : trtlcriticalsection;
- const
- { all variants for which vType and varComplexType = 0 do not require
- finalization. }
- varComplexType = $BFE8;
- procedure DoVarClearComplex(var v : TVarData); forward;
- procedure DoVarCopy(var Dest : TVarData; const Source : TVarData); forward;
- procedure DoVarCast(var aDest : TVarData; const aSource : TVarData; aVarType : LongInt); forward;
- procedure DoVarClear(var v : TVarData); inline;
- begin
- if v.vType and varComplexType <> 0 then
- DoVarClearComplex(v)
- else
- v.vType := varEmpty;
- end;
- procedure DoVarClearIfComplex(var v : TVarData); inline;
- begin
- if v.vType and varComplexType <> 0 then
- DoVarClearComplex(v);
- end;
- function AlignToPtr(p : Pointer) : Pointer;inline;
- begin
- {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT}
- Result:=align(p,SizeOf(p));
- {$ELSE FPC_REQUIRES_PROPER_ALIGNMENT}
- Result:=p;
- {$ENDIF FPC_REQUIRES_PROPER_ALIGNMENT}
- end;
- { ---------------------------------------------------------------------
- String Messages
- ---------------------------------------------------------------------}
- ResourceString
- SErrVarIsEmpty = 'Variant is empty';
- SErrInvalidIntegerRange = 'Invalid Integer range: %d';
- { ---------------------------------------------------------------------
- Auxiliary routines
- ---------------------------------------------------------------------}
- Procedure VariantError (Const Msg : String); inline;
- begin
- Raise EVariantError.Create(Msg);
- end;
- Procedure NotSupported(Meth: String);
- begin
- Raise EVariantError.CreateFmt('Method %s not yet supported.',[Meth]);
- end;
- type
- TVariantArrayIterator = object
- Bounds : PVarArrayBoundArray;
- Coords : PVarArrayCoorArray;
- Dims : SizeInt;
- constructor Init(aDims: SizeInt; aBounds : PVarArrayBoundArray);
- destructor Done;
- function Next : Boolean;
- { returns true if the iterator reached the end of the variant array }
- function AtEnd: Boolean;
- end;
- {$r-}
- constructor TVariantArrayIterator.Init(aDims: SizeInt; aBounds : PVarArrayBoundArray);
- var
- i : sizeint;
- begin
- Dims := aDims;
- Bounds := aBounds;
- GetMem(Coords, SizeOf(SizeInt) * Dims);
- { initialize coordinate counter }
- for i:= 0 to Pred(Dims) do
- Coords^[i] := Bounds^[i].LowBound;
- end;
- function TVariantArrayIterator.Next: Boolean;
- var
- Finished : Boolean;
- procedure IncDim(Dim : SizeInt);
- begin
- if Finished then
- Exit;
- Inc(Coords^[Dim]);
- if Coords^[Dim] >= Bounds^[Dim].LowBound + Bounds^[Dim].ElementCount then begin
- Coords^[Dim]:=Bounds^[Dim].LowBound;
- if Dim > 0 then
- IncDim(Pred(Dim))
- else
- Finished := True;
- end;
- end;
- begin
- Finished := False;
- IncDim(Pred(Dims));
- Result := not Finished;
- end;
- function TVariantArrayIterator.AtEnd: Boolean;
- var
- i : sizeint;
- begin
- result:=true;
- for i:=0 to Pred(Dims) do
- if Coords^[i] < Bounds^[i].LowBound + Bounds^[i].ElementCount then
- begin
- result:=false;
- exit;
- end;
- end;
- {$ifndef RANGECHECKINGOFF}
- {$r+}
- {$endif}
- destructor TVariantArrayIterator.done;
- begin
- FreeMem(Coords);
- end;
- type
- tdynarraybounds = array of SizeInt;
- tdynarraycoords = tdynarraybounds;
- tdynarrayelesize = tdynarraybounds;
- tdynarraypositions = array of Pointer;
- tdynarrayiter = object
- Bounds : tdynarraybounds;
- Coords : tdynarraycoords;
- elesize : tdynarrayelesize;
- positions : tdynarraypositions;
- Dims : SizeInt;
- data : Pointer;
- constructor init(d : Pointer;p : pdynarraytypeinfo;_dims: SizeInt;b : tdynarraybounds);
- function next : Boolean;
- destructor done;
- end;
- constructor tdynarrayiter.init(d : Pointer;p : pdynarraytypeinfo;_dims: SizeInt;b : tdynarraybounds);
- var
- i : sizeint;
- begin
- Bounds:=b;
- Dims:=_dims;
- SetLength(Coords,Dims);
- SetLength(elesize,Dims);
- SetLength(positions,Dims);
- positions[0]:=d;
- { initialize coordinate counter and elesize }
- for i:=0 to Dims-1 do
- begin
- Coords[i]:=0;
- if i>0 then
- positions[i]:=Pointer(positions[i-1]^);
- { skip kind and name }
- inc(Pointer(p),ord(pdynarraytypeinfo(p)^.namelen)+2);
- p:=AlignToPtr(p);
- elesize[i]:=psizeint(p)^;
- { skip elesize }
- inc(Pointer(p),SizeOf(sizeint));
- p:=pdynarraytypeinfo(ppointer(p)^);
- end;
- data:=positions[Dims-1];
- end;
- function tdynarrayiter.next : Boolean;
- var
- Finished : Boolean;
- procedure incdim(d : SizeInt);
- begin
- if Finished then
- exit;
- inc(Coords[d]);
- inc(Pointer(positions[d]),elesize[d]);
- if Coords[d]>=Bounds[d] then
- begin
- Coords[d]:=0;
- if d>0 then
- begin
- incdim(d-1);
- positions[d]:=Pointer(positions[d-1]^);
- end
- else
- Finished:=true;
- end;
- end;
- begin
- Finished:=False;
- incdim(Dims-1);
- data:=positions[Dims-1];
- Result:=not(Finished);
- end;
- destructor tdynarrayiter.done;
- begin
- Bounds:=nil;
- Coords:=nil;
- elesize:=nil;
- positions:=nil;
- end;
- { ---------------------------------------------------------------------
- VariantManager support
- ---------------------------------------------------------------------}
- procedure sysvarinit(var v : Variant);
- begin
- TVarData(V).vType := varEmpty;
- end;
- procedure sysvarclear(var v : Variant);
- begin
- if TVarData(v).vType and varComplexType <> 0 then
- VarClearProc(TVarData(V))
- else
- TVarData(v).vType := varEmpty;
- end;
- function Sysvartoint (const v : Variant) : Integer;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varInt64)
- else
- Result := 0
- else
- Result := VariantToLongInt(TVarData(V));
- end;
- function Sysvartoint64 (const v : Variant) : Int64;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varInt64)
- else
- Result := 0
- else
- Result := VariantToInt64(TVarData(V));
- end;
- function sysvartoword64 (const v : Variant) : QWord;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varQWord)
- else
- Result := 0
- else
- Result := VariantToQWord (TVarData(V));
- end;
- function sysvartobool (const v : Variant) : Boolean;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varBoolean)
- else
- Result := False
- else
- Result := VariantToBoolean(TVarData(V));
- end;
- {$ifndef FPUNONE}
- function sysvartoreal (const v : Variant) : Extended;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varDouble)
- else
- Result := 0
- else
- Result := VariantToDouble(TVarData(V));
- end;
- {$endif}
- function sysvartocurr (const v : Variant) : Currency;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varCurrency)
- else
- Result := 0
- else
- Result := VariantToCurrency(TVarData(V));
- end;
- procedure sysvartolstr (var s : AnsiString; const v : Variant);
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varString)
- else
- s := NullAsStringValue
- else
- S := VariantToAnsiString(TVarData(V));
- end;
- procedure sysvartopstr (var s; const v : Variant);
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varString)
- else
- ShortString(s) := NullAsStringValue
- else
- ShortString(s) := VariantToShortString(TVarData(V));
- end;
- procedure sysvartowstr (var s : WideString; const v : Variant);
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varOleStr)
- else
- s := NullAsStringValue
- else
- S := VariantToWideString(TVarData(V));
- end;
- procedure sysvartointf (var Intf : IInterface; const v : Variant);
- begin
- case TVarData(v).vType of
- varEmpty:
- Intf := nil;
- varNull:
- if NullStrictConvert then
- VarCastError(varNull, varUnknown)
- else
- Intf := nil;
- varUnknown:
- Intf := IInterface(TVarData(v).vUnknown);
- varUnknown or varByRef:
- Intf := IInterface(TVarData(v).vPointer^);
- varDispatch:
- Intf := IInterface(TVarData(v).vDispatch);
- varDispatch or varByRef:
- Intf := IInterface(TVarData(v).vPointer^);
- varVariant, varVariant or varByRef: begin
- if not Assigned(TVarData(v).vPointer) then
- VarBadTypeError;
- sysvartointf(Intf, Variant(PVarData(TVarData(v).vPointer)^) );
- end;
- else
- VarCastError(TVarData(v).vType, varUnknown);
- end;
- end;
- procedure sysvartodisp (var Disp : IDispatch; const v : Variant);
- begin
- case TVarData(v).vType of
- varEmpty:
- Disp := nil;
- varNull:
- if NullStrictConvert then
- VarCastError(varNull, varDispatch)
- else
- Disp := nil;
- varUnknown:
- if IInterface(TVarData(v).vUnknown).QueryInterface(IDispatch, Disp) <> S_OK then
- VarCastError(varUnknown, varDispatch);
- varUnknown or varByRef:
- if IInterface(TVarData(v).vPointer^).QueryInterface(IDispatch, Disp) <> S_OK then
- VarCastError(varUnknown or varByRef, varDispatch);
- varDispatch:
- Disp := IDispatch(TVarData(v).vDispatch);
- varDispatch or varByRef:
- Disp := IDispatch(TVarData(v).vPointer^);
- varVariant, varVariant or varByRef: begin
- if not Assigned(TVarData(v).vPointer) then
- VarBadTypeError;
- sysvartodisp(Disp, Variant(PVarData(TVarData(v).vPointer)^) );
- end;
- else
- VarCastError(TVarData(v).vType, varDispatch);
- end;
- end;
- {$ifndef FPUNONE}
- function sysvartotdatetime (const v : Variant) : TDateTime;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varDate)
- else
- Result := 0
- else
- Result:=VariantToDate(TVarData(v));
- end;
- {$endif}
- function DynamicArrayIsRectangular(p : Pointer;TypeInfo : Pointer) : Boolean;
- var
- arraysize,i : sizeint;
- begin
- Result := False;
- { get TypeInfo of second level }
- { skip kind and name }
- inc(Pointer(TypeInfo),ord(pdynarraytypeinfo(TypeInfo)^.namelen)+2);
- TypeInfo:=AlignToPtr(TypeInfo);
- TypeInfo:=ppointer(TypeInfo+SizeOf(sizeint))^;
- { check recursively? }
- if assigned(pdynarraytypeinfo(TypeInfo)) and (pdynarraytypeinfo(TypeInfo)^.kind=byte(tkDynArray)) then
- begin
- { set to dimension of first element }
- arraysize:=psizeint(ppointer(p)^-SizeOf(sizeint))^;
- { walk through all elements }
- for i:=1 to psizeint(p-SizeOf(sizeint))^ do
- begin
- { ... and check dimension }
- if psizeint(ppointer(p)^-SizeOf(sizeint))^<>arraysize then
- exit;
- if not(DynamicArrayIsRectangular(ppointer(p)^,TypeInfo)) then
- exit;
- inc(p,SizeOf(Pointer));
- end;
- end;
- Result:=true;
- end;
- procedure sysvartodynarray (var dynarr : Pointer; const v : Variant; TypeInfo : Pointer);
- begin
- DynArrayFromVariant(dynarr, v, TypeInfo);
- end;
- procedure sysvarfrombool (var Dest : Variant; const Source : Boolean);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varBoolean;
- vBoolean := Source;
- end;
- end;
- procedure VariantErrorInvalidIntegerRange(Range: LongInt);
- begin
- VariantError(Format(SErrInvalidIntegerRange,[Range]));
- end;
- procedure sysvarfromint (var Dest : Variant; const Source, Range : LongInt);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do
- if PackVarCreation then
- case Range of
- -4 : begin
- vType := varInteger;
- vInteger := Source;
- end;
- -2 : begin
- vType := varSmallInt;
- vSmallInt := Source;
- end;
- -1 : Begin
- vType := varShortInt;
- vshortint := Source;
- end;
- 1 : begin
- vType := varByte;
- vByte := Source;
- end;
- 2 : begin
- vType := varWord;
- vWord := Source;
- end;
- 4 : Begin
- vType := varLongWord;
- {use vInteger, not vLongWord as the value came passed in as an Integer }
- vInteger := Source;
- end;
- else
- VariantErrorInvalidIntegerRange(Range);
- end
- else begin
- vType := varInteger;
- vInteger := Source;
- end;
- end;
- procedure sysvarfromint64 (var Dest : Variant; const Source : Int64);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varInt64;
- vInt64 := Source;
- end;
- end;
- procedure sysvarfromword64 (var Dest : Variant; const Source : QWord);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varQWord;
- vQWord := Source;
- end;
- end;
- {$ifndef FPUNONE}
- procedure sysvarfromreal (var Dest : Variant; const Source : Extended);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varDouble;
- vDouble := Source;
- end;
- end;
- procedure sysvarfromsingle (var Dest : Variant; const Source : single);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varSingle;
- vSingle := Source;
- end;
- end;
- procedure sysvarfromdouble (var Dest : Variant; const Source : double);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varDouble;
- vDouble := Source;
- end;
- end;
- {$endif}
- procedure sysvarfromcurr (var Dest : Variant; const Source : Currency);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varCurrency;
- vCurrency := Source;
- end;
- end;
- {$ifndef FPUNONE}
- procedure sysvarfromtdatetime (var Dest : Variant; const Source : TDateTime);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varDate;
- vDate := Source;
- end;
- end;
- {$endif}
- procedure sysvarfrompstr (var Dest : Variant; const Source : ShortString);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varString;
- vString := nil;
- AnsiString(vString) := Source;
- end;
- end;
- procedure sysvarfromlstr (var Dest : Variant; const Source : AnsiString);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varString;
- vString := nil;
- AnsiString(vString) := Source;
- end;
- end;
- procedure sysvarfromwstr (var Dest : Variant; const Source : WideString);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vType := varOleStr;
- vOleStr := nil;
- WideString(Pointer(vOleStr)) := Source;
- end;
- end;
- procedure sysvarfromintf(var Dest : Variant; const Source : IInterface);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vUnknown := nil;
- IInterface(vUnknown) := Source;
- vType := varUnknown;
- end;
- end;
- procedure sysvarfromdisp(var Dest : Variant; const Source : IDispatch);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vUnknown := nil;
- IDispatch(vDispatch) := Source;
- vType := varDispatch;
- end;
- end;
- type
- TCommonType = (ctEmpty,ctAny,ctError,ctLongInt,ctBoolean,
- {$ifndef FPUNONE}
- ctFloat,ctDate,ctCurrency,
- {$endif}
- ctInt64,ctNull,ctWideStr,ctString);
- TCommonVarType = varEmpty..varQWord;
- const
- {$ifdef FPUNONE}
- ctFloat = ctError;
- ctDate = ctError;
- ctCurrency = ctError;
- {$endif}
- { get the basic type for a Variant type }
- VarTypeToCommonType : array[TCommonVarType] of TCommonType =
- (ctEmpty, // varEmpty = 0;
- ctNull, // varNull = 1;
- ctLongInt, // varSmallInt = 2;
- ctLongInt, // varInteger = 3;
- ctFloat, // varSingle = 4;
- ctFloat, // varDouble = 5;
- ctCurrency, // varCurrency = 6;
- ctDate, // varDate = 7;
- ctWideStr, // varOleStr = 8;
- ctError, // varDispatch = 9;
- ctError, // varError = 10;
- ctBoolean, // varBoolean = 11;
- ctError, // varVariant = 12;
- ctError, // varUnknown = 13;
- ctError, // ??? 15
- ctError, // varDecimal = 14;
- ctLongInt, // varShortInt = 16;
- ctLongInt, // varByte = 17;
- ctLongInt, // varWord = 18;
- ctInt64, // varLongWord = 19;
- ctInt64, // varInt64 = 20;
- ctInt64 // varQWord = 21;
- );
- { map a basic type back to a Variant type }
- { Not used yet
- CommonTypeToVarType : array[TCommonType] of TVarType =
- (
- varEmpty,
- varany,
- varError,
- varInteger,
- varDouble,
- varBoolean,
- varInt64,
- varNull,
- varOleStr,
- varDate,
- varCurrency,
- varString
- );
- }
- function MapToCommonType(const vType : TVarType) : TCommonType;
- begin
- case vType of
- Low(TCommonVarType)..High(TCommonVarType):
- Result := VarTypeToCommonType[vType];
- varString:
- Result:=ctString;
- varAny:
- Result:=ctAny;
- else
- Result:=ctError;
- end;
- end;
- const
- FindCmpCommonType : array[TCommonType, TCommonType] of TCommonType = (
- { ctEmpty ctAny ctError ctLongInt ctBoolean ctFloat ctDate ctCurrency ctInt64 ctNull ctWideStr ctString }
- ({ ctEmpty } ctEmpty, ctEmpty, ctError, ctEmpty, ctEmpty, {$ifndef FPUNONE}ctEmpty, ctEmpty, ctEmpty, {$endif}ctEmpty, ctEmpty, ctEmpty, ctEmpty ),
- ({ ctAny } ctEmpty, ctAny, ctError, ctAny, ctAny, {$ifndef FPUNONE}ctAny, ctAny, ctAny, {$endif}ctAny, ctAny, ctAny, ctAny ),
- ({ ctError } ctError, ctError, ctError, ctError, ctError, {$ifndef FPUNONE}ctError, ctError, ctError, {$endif}ctError, ctError, ctError, ctError ),
- ({ ctLongInt } ctEmpty, ctAny, ctError, ctLongInt, ctBoolean, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctInt64, ctNull, ctFloat, ctFloat ),
- ({ ctBoolean } ctEmpty, ctAny, ctError, ctLongInt, ctBoolean, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctInt64, ctNull, ctWideStr, ctString ),
- {$ifndef FPUNONE}
- ({ ctFloat } ctEmpty, ctAny, ctError, ctFloat, ctFloat, ctFloat, ctDate, ctCurrency, ctFloat, ctNull, ctFloat, ctFloat ),
- ({ ctDate } ctEmpty, ctAny, ctError, ctDate, ctDate, ctDate, ctDate, ctDate, ctDate, ctNull, ctDate, ctDate ),
- ({ ctCurrency } ctEmpty, ctAny, ctError, ctCurrency, ctCurrency, ctCurrency,ctDate, ctCurrency, ctCurrency, ctNull, ctCurrency, ctCurrency ),
- {$endif}
- ({ ctInt64 } ctEmpty, ctAny, ctError, ctInt64, ctInt64, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctInt64, ctNull, ctFloat, ctFloat ),
- ({ ctNull } ctEmpty, ctAny, ctError, ctNull, ctNull, {$ifndef FPUNONE}ctNull, ctNull, ctNull, {$endif}ctNull, ctNull, ctNull, ctNull ),
- ({ ctWideStr } ctEmpty, ctAny, ctError, ctFloat, ctWideStr, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctFloat, ctNull, ctWideStr, ctWideStr ),
- ({ ctString } ctEmpty, ctAny, ctError, ctFloat, ctString, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctFloat, ctNull, ctWideStr, ctString )
- );
- function DoVarCmpSimple (const Left, Right, Common: TCommonType) : ShortInt; inline;
- begin
- if Left = Common then
- if Right = Common then
- Result := 0
- else
- Result := -1
- else
- Result := 1;
- end;
- function DoVarCmpAny(const Left, Right: TVarData; const OpCode: TVarOp) : ShortInt;
- begin
- VarInvalidOp(Left.vType, Right.vType, OpCode);
- Result:=0;
- end;
- function DoVarCmpLongInt(const Left, Right: LongInt): ShortInt; inline;
- begin
- if Left < Right then
- Result := -1
- else if Left > Right then
- Result := 1
- else
- Result := 0;
- end;
- {$ifndef FPUNONE}
- function DoVarCmpFloat(const Left, Right: Double; const OpCode: TVarOp): ShortInt;
- begin
- if SameValue(Left, Right) then
- Result := 0
- else if (OpCode in [opCmpEq, opCmpNe]) or (Left < Right) then
- Result := -1
- else
- Result := 1;
- end;
- function DoVarCmpDate(const Left, Right: TDateTime; const OpCode: TVarOp): ShortInt;
- begin
- { dates have to match exactly, all bits encode time information }
- if(Left = Right) then
- Result := 0
- else if (OpCode in [opCmpEq, opCmpNe]) or (Left < Right) then
- Result := -1
- else
- Result := 1;
- end;
- {$endif}
- function DoVarCmpInt64(const Left, Right: Int64): ShortInt;
- begin
- if Left < Right then
- Result := -1
- else if Left > Right then
- Result := 1
- else
- Result := 0;
- end;
- function DoVarCmpNull(const Left, Right: TCommonType; const OpCode: TVarOp) : ShortInt;
- const
- ResultMap: array [Boolean, opCmpEq..opCmpGe] of ShortInt =
- ( ( -1, 0, 0, 1, 0, -1 ), ( 0, -1, -1, -1, 1, 1 ) );
- begin
- if OpCode in [opCmpEq, opCmpNe] then
- case NullEqualityRule of
- ncrError: VarInvalidNullOp;
- ncrStrict: Result := ResultMap[False, OpCode];
- ncrLoose: Result := ResultMap[(Left = Right) xor (OpCode = opCmpNe), OpCode];
- end
- else
- case NullMagnitudeRule of
- ncrError: VarInvalidNullOp;
- ncrStrict: Result := ResultMap[False, OpCode];
- ncrLoose: Result := DoVarCmpSimple(Left, Right, ctNull);
- end;
- end;
- function DoVarCmpCurr(const Left, Right: Currency): ShortInt;
- begin
- if Left < Right then
- Result := -1
- else if Left > Right then
- Result := 1
- else
- Result := 0;
- end;
- function DoVarCmpWStrDirect(const Left, Right: Pointer; const OpCode: TVarOp): ShortInt; inline;
- begin
- { we can do this without ever copying the string }
- if OpCode in [opCmpEq, opCmpNe] then
- if Length(WideString(Left)) <> Length(WideString(Right)) then
- Exit(-1);
- Result := WideCompareStr(
- WideString(Left),
- WideString(Right)
- );
- end;
- function DoVarCmpWStr(const Left, Right: TVarData; const OpCode: TVarOp): ShortInt;
- begin
- { keep the temps away from the main proc }
- Result := DoVarCmpWStrDirect(Pointer(VariantToWideString(Left)),
- Pointer(VariantToWideString(Right)), OpCode);
- end;
- function DoVarCmpLStrDirect(const Left, Right: Pointer; const OpCode: TVarOp): ShortInt; inline;
- begin
- { we can do this without ever copying the string }
- if OpCode in [opCmpEq, opCmpNe] then
- if Length(AnsiString(Left)) <> Length(AnsiString(Right)) then
- Exit(-1);
- Result := CompareStr(
- AnsiString(Left),
- AnsiString(Right)
- );
- end;
- function DoVarCmpLStr(const Left, Right: TVarData; const OpCode: TVarOp): ShortInt;
- begin
- { keep the temps away from the main proc }
- Result := DoVarCmpLStrDirect(Pointer(VariantToAnsiString(Left)),
- Pointer(VariantToAnsiString(Right)), OpCode);
- end;
- function DoVarCmpComplex(const Left, Right: TVarData; const OpCode: TVarOp): ShortInt;
- begin
- {!! custom variants? }
- VarInvalidOp(Left.vType, Right.vType, OpCode);
- Result:=0;
- end;
- function DoVarCmp(const vl, vr : TVarData; const OpCode : TVarOp) : ShortInt;
- var
- lct: TCommonType;
- rct: TCommonType;
- begin
- { as the function in cvarutil.inc can handle varByRef correctly we simply
- resolve the final type }
- lct := MapToCommonType(VarTypeDeRef(vl));
- rct := MapToCommonType(VarTypeDeRef(vr));
- {$IFDEF DEBUG_VARIANTS}
- if __DEBUG_VARIANTS then begin
- WriteLn('DoVarCmp $', IntToHex(Cardinal(@vl),8), ' ', GetEnumName(TypeInfo(TVarOp), Ord(OpCode)) ,' $', IntToHex(Cardinal(@vr),8));
- DumpVariant('DoVarCmp/vl', vl);
- WriteLn('lct ', GetEnumName(TypeInfo(TCommonType), Ord(lct)));
- DumpVariant('DoVarCmp/vr', vr);
- WriteLn('rct ', GetEnumName(TypeInfo(TCommonType), Ord(rct)));
- WriteLn('common ', GetEnumName(TypeInfo(TCommonType), Ord(FindCmpCommonType[lct, rct])));
- end;
- {$ENDIF}
- case FindCmpCommonType[lct, rct] of
- ctEmpty: Result := DoVarCmpSimple(lct, rct, ctEmpty);
- ctAny: Result := DoVarCmpAny(vl, vr, OpCode);
- ctLongInt: Result := DoVarCmpLongInt(VariantToLongInt(vl), VariantToLongInt(vr));
- {$ifndef FPUNONE}
- ctFloat: Result := DoVarCmpFloat(VariantToDouble(vl), VariantToDouble(vr), OpCode);
- {$endif}
- ctBoolean: Result := DoVarCmpLongInt(LongInt(VariantToBoolean(vl)), LongInt(VariantToBoolean(vr)));
- ctInt64: Result := DoVarCmpInt64(VariantToInt64(vl), VariantToInt64(vr));
- ctNull: Result := DoVarCmpNull(lct, rct, OpCode);
- ctWideStr:
- if (vl.vType = varOleStr) and (vr.vType = varOleStr) then
- Result := DoVarCmpWStrDirect(Pointer(vl.vOleStr), Pointer(vr.vOleStr), OpCode)
- else
- Result := DoVarCmpWStr(vl, vr, OpCode);
- {$ifndef FPUNONE}
- ctDate: Result := DoVarCmpDate(VariantToDate(vl), VariantToDate(vr), OpCode);
- ctCurrency: Result := DoVarCmpCurr(VariantToCurrency(vl), VariantToCurrency(vr));
- {$endif}
- ctString:
- if (vl.vType = varString) and (vr.vType = varString) then
- Result := DoVarCmpLStrDirect(Pointer(vl.vString), Pointer(vr.vString), OpCode)
- else
- Result := DoVarCmpLStr(vl, vr, OpCode);
- else
- Result := DoVarCmpComplex(vl, vr, OpCode);
- end;
- end;
- function syscmpop (const Left, Right : Variant; const OpCode : TVarOp) : Boolean;
- var
- CmpRes : ShortInt;
- begin
- CmpRes:=DoVarCmp(TVarData(Left),TVarData(Right),OpCode);
- case OpCode of
- opCmpEq:
- Result:=CmpRes=0;
- opCmpNe:
- Result:=CmpRes<>0;
- opCmpLt:
- Result:=CmpRes<0;
- opCmpLe:
- Result:=CmpRes<=0;
- opCmpGt:
- Result:=CmpRes>0;
- opCmpGe:
- Result:=CmpRes>=0;
- else
- VarInvalidOp;
- end;
- end;
- const
- FindOpCommonType : array[TCommonType,TCommonType] of TCommonType = (
- { ctEmpty ctAny ctError ctLongInt ctBoolean ctFloat ctDate ctCurrency ctInt64 ctNull ctWideStr ctString }
- ({ ctEmpty } ctEmpty, ctAny, ctError, ctEmpty, ctEmpty, {$ifndef FPUNONE}ctEmpty, ctEmpty, ctEmpty, {$endif}ctEmpty, ctEmpty, ctEmpty, ctEmpty ),
- ({ ctAny } ctAny, ctAny, ctError, ctAny, ctAny, {$ifndef FPUNONE}ctAny, ctAny, ctAny, {$endif}ctAny, ctAny, ctAny, ctAny ),
- ({ ctError } ctError, ctError, ctError, ctError, ctError, {$ifndef FPUNONE}ctError, ctError, ctError, {$endif}ctError, ctError, ctError, ctError ),
- ({ ctLongInt } ctEmpty, ctAny, ctError, ctLongInt, ctBoolean, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctInt64, ctNull, ctFloat, ctFloat ),
- ({ ctBoolean } ctEmpty, ctAny, ctError, ctLongInt, ctBoolean, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctInt64, ctNull, ctBoolean, ctBoolean ),
- {$ifndef FPUNONE}
- ({ ctFloat } ctEmpty, ctAny, ctError, ctFloat, ctFloat, ctFloat, ctDate, ctCurrency, ctFloat, ctNull, ctFloat, ctFloat ),
- ({ ctDate } ctEmpty, ctAny, ctError, ctDate, ctDate, ctDate, ctDate, ctDate, ctDate, ctNull, ctDate, ctDate ),
- ({ ctCurrency } ctEmpty, ctAny, ctError, ctCurrency, ctCurrency, ctCurrency, ctDate, ctCurrency, ctCurrency, ctNull, ctCurrency, ctCurrency ),
- {$endif}
- ({ ctInt64 } ctEmpty, ctAny, ctError, ctInt64, ctInt64, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctInt64, ctNull, ctFloat, ctFloat ),
- ({ ctNull } ctEmpty, ctAny, ctError, ctNull, ctNull, {$ifndef FPUNONE}ctNull, ctNull, ctNull, {$endif}ctNull, ctNull, ctNull, ctNull ),
- ({ ctWideStr } ctEmpty, ctAny, ctError, ctFloat, ctBoolean, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctFloat, ctNull, ctWideStr, ctWideStr ),
- ({ ctString } ctEmpty, ctAny, ctError, ctFloat, ctBoolean, {$ifndef FPUNONE}ctFloat, ctDate, ctCurrency, {$endif}ctFloat, ctNull, ctWideStr, ctString )
- );
- procedure DoVarOpFloat(var vl :TVarData; const vr : TVarData; const OpCode : TVarOp);
- {$ifndef FPUNONE}
- var
- l, r : Double;
- begin
- l := VariantToDouble(vl);
- r := VariantToDouble(vr);
- case OpCode of
- opAdd : l := l + r;
- opSubtract : l := l - r;
- opMultiply : l := l * r;
- opDivide : l := l / r;
- opPower : l := l ** r;
- else
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- DoVarClearIfComplex(vl);
- vl.vType := varDouble;
- vl.vDouble := l;
- {$else}
- begin
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- {$endif}
- end;
- procedure DoVarOpAny(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- begin
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- procedure DoVarOpLongInt(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- var
- l, r: LongInt;
- begin
- l := VariantToLongint(vl);
- r := VariantToLongint(vr);
- case OpCode of
- opIntDivide : l := l div r;
- opModulus : l := l mod r;
- opShiftLeft : l := l shl r;
- opShiftRight : l := l shr r;
- opAnd : l := l and r;
- opOr : l := l or r;
- opXor : l := l xor r;
- else
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- DoVarClearIfComplex(vl);
- vl.vType := varInteger;
- vl.vInteger := l;
- end;
- procedure DoVarOpInt64(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- var
- l, r : Int64;
- Overflow : Boolean;
- begin
- l := VariantToInt64(vl);
- r := VariantToInt64(vr);
- Overflow := False;
- case OpCode of
- {$R+}{$Q+}
- opAdd..opMultiply,opPower: try
- case OpCode of
- opAdd : l := l + r;
- opSubtract : l := l - r;
- opMultiply : l := l * r;
- {$ifndef FPUNONE}
- opPower : l := l ** r;
- {$endif}
- end;
- except
- on E: SysUtils.ERangeError do
- Overflow := True;
- on E: SysUtils.EIntOverflow do
- Overflow := True;
- end;
- {$IFDEF RANGECHECKINGOFF} {$R-} {$ENDIF} {$IFDEF OVERFLOWCHECKINGOFF} {$Q+} {$ENDIF}
- opIntDivide : l := l div r;
- opModulus : l := l mod r;
- opShiftLeft : l := l shl r;
- opShiftRight : l := l shr r;
- opAnd : l := l and r;
- opOr : l := l or r;
- opXor : l := l xor r;
- else
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- if Overflow then
- DoVarOpFloat(vl,vr,OpCode)
- else begin
- DoVarClearIfComplex(vl);
- vl.vType := varInt64;
- vl.vInt64 := l;
- end;
- end;
- procedure DoVarOpInt64to32(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- begin
- { can't do this well without an efficent way to check for overflows,
- let the Int64 version handle it and check the Result if we can downgrade it
- to integer }
- DoVarOpInt64(vl, vr, OpCode);
- with vl do
- if (vType = varInt64) and (vInt64 >= Low(LongInt)) and (vInt64 <= High(LongInt)) then begin
- vInteger := vInt64;
- vType := varInteger;
- end;
- end;
- procedure DoVarOpBool(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- var
- l,r: Boolean;
- begin
- l := VariantToBoolean(vl);
- r := VariantToBoolean(vr);
- case OpCode of
- opAnd : l := l and r;
- opOr : l := l or r;
- opXor : l := l xor r;
- else
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- DoVarClearIfComplex(vl);
- vl.vType := varBoolean;
- vl.vBoolean := l;
- end;
- procedure DoVarOpNull(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- begin
- if (OpCode = opAnd) or (OpCode = opOr) then
- if vl.vType = varNull then begin
- if vr.vType = varNull then begin
- {both null, do nothing }
- end else begin
- {Left null, Right not}
- if OpCode = opAnd then begin
- if not VariantToBoolean(vr) then
- VarCopyProc(vl, vr);
- end else {OpCode = opOr} begin
- if VariantToBoolean(vr) then
- VarCopyProc(vl, vr);
- end;
- end;
- end else begin
- if vr.vType = varNull then begin
- {Right null, Left not}
- if OpCode = opAnd then begin
- if VariantToBoolean(vl) then begin
- DoVarClearIfComplex(vl);
- vl.vType := varNull;
- end;
- end else {OpCode = opOr} begin
- if not VariantToBoolean(vl) then begin
- DoVarClearIfComplex(vl);
- vl.vType := varNull;
- end;
- end;
- end else begin
- { both not null, shouldn't happen }
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- end
- else begin
- DoVarClearIfComplex(vl);
- vl.vType := varNull;
- end;
- end;
- procedure DoVarOpWStrCat(var vl : TVarData; const vr : TVarData);
- var
- ws: WideString;
- begin
- ws := VariantToWideString(vl) + VariantToWideString(vr);
- DoVarClearIfComplex(vl);
- vl.vType := varOleStr;
- { transfer the WideString without making a copy }
- Pointer(vl.vOleStr) := Pointer(ws);
- { prevent the WideString from being freed, the reference has been transfered
- from the local to the variant and will be correctly finalized when the
- variant is finalized. }
- Pointer(ws) := nil;
- end;
- procedure DoVarOpLStrCat(var vl: TVarData; const vr : TVarData);
- var
- s: AnsiString;
- begin
- s := VariantToAnsiString(vl) + VariantToAnsiString(vr);
- DoVarClearIfComplex(vl);
- vl.vType := varString;
- { transfer the AnsiString without making a copy }
- Pointer(vl.vString) := Pointer(s);
- { prevent the AnsiString from being freed, the reference has been transfered
- from the local to the variant and will be correctly finalized when the
- variant is finalized. }
- Pointer(s) := nil;
- end;
- procedure DoVarOpDate(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- {$ifndef FPUNONE}
- var
- l, r : TDateTime;
- begin
- l := VariantToDate(vl);
- r := VariantToDate(vr);
- case OpCode of
- opAdd : l := l + r;
- opSubtract : l := l - r;
- else
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- DoVarClearIfComplex(vl);
- vl.vType := varDate;
- vl.vDate := l;
- {$else}
- begin
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- {$endif}
- end;
- procedure DoVarOpCurr(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp; const lct, rct : TCommonType);
- {$ifndef FPUNONE}
- var
- c : Currency;
- d : Double;
- begin
- case OpCode of
- opAdd:
- c := VariantToCurrency(vl) + VariantToCurrency(vr);
- opSubtract:
- c := VariantToCurrency(vl) - VariantToCurrency(vr);
- opMultiply:
- if lct = ctCurrency then
- if rct = ctCurrency then {both Currency}
- c := VariantToCurrency(vl) * VariantToCurrency(vr)
- else {Left Currency}
- c := VariantToCurrency(vl) * VariantToDouble(vr)
- else
- if rct = ctCurrency then {rigth Currency}
- c := VariantToDouble(vl) * VariantToCurrency(vr)
- else {non Currency, error}
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- opDivide:
- if lct = ctCurrency then
- if rct = ctCurrency then {both Currency}
- c := VariantToCurrency(vl) / VariantToCurrency(vr)
- else {Left Currency}
- c := VariantToCurrency(vl) / VariantToDouble(vr)
- else
- if rct = ctCurrency then begin {rigth Currency}
- d := VariantToCurrency(vl) / VariantToCurrency(vr);
- DoVarClearIfComplex(vl);
- vl.vType := varDouble;
- vl.vDouble := d;
- Exit;
- end else {non Currency, error}
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- opPower:
- if lct = ctCurrency then
- if rct = ctCurrency then {both Currency}
- c := VariantToCurrency(vl) ** VariantToCurrency(vr)
- else {Left Currency}
- c := VariantToCurrency(vl) ** VariantToDouble(vr)
- else
- if rct = ctCurrency then {rigth Currency}
- c := VariantToDouble(vl) ** VariantToCurrency(vr)
- else {non Currency, error}
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- else
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- DoVarClearIfComplex(vl);
- vl.vType := varCurrency;
- vl.vCurrency := c;
- {$else}
- begin
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- {$endif}
- end;
- procedure DoVarOpComplex(var vl : TVarData; const vr : TVarData; const OpCode : TVarOp);
- begin
- {custom Variant support? }
- VarInvalidOp(vl.vType, vr.vType, OpCode);
- end;
- procedure SysVarOp(var Left : Variant; const Right : Variant; OpCode : TVarOp);
- var
- lct: TCommonType;
- rct: TCommonType;
- {$IFDEF DEBUG_VARIANTS}
- i: Integer;
- {$ENDIF}
- begin
- { as the function in cvarutil.inc can handle varByRef correctly we simply
- resolve the final type }
- lct := MapToCommonType(VarTypeDeRef(Left));
- rct := MapToCommonType(VarTypeDeRef(Right));
- {$IFDEF DEBUG_VARIANTS}
- if __DEBUG_VARIANTS then begin
- WriteLn('SysVarOp $', IntToHex(Cardinal(@TVarData(Left)),8), ' ', GetEnumName(TypeInfo(TVarOp), Ord(OpCode)) ,' $', IntToHex(Cardinal(@TVarData(Right)),8));
- DumpVariant('SysVarOp/TVarData(Left)', TVarData(Left));
- WriteLn('lct ', GetEnumName(TypeInfo(TCommonType), Ord(lct)));
- DumpVariant('SysVarOp/TVarData(Right)', TVarData(Right));
- WriteLn('rct ', GetEnumName(TypeInfo(TCommonType), Ord(rct)));
- WriteLn('common ', GetEnumName(TypeInfo(TCommonType), Ord(FindOpCommonType[lct, rct])));
- end;
- {$ENDIF}
- case FindOpCommonType[lct, rct] of
- ctEmpty:
- case OpCode of
- opDivide:
- Error(reZeroDivide);
- opIntDivide, opModulus:
- Error(reDivByZero);
- else
- DoVarClear(TVarData(Left));
- end;
- ctAny:
- DoVarOpAny(TVarData(Left),TVarData(Right),OpCode);
- ctLongInt:
- case OpCode of
- opAdd..opMultiply,opPower:
- DoVarOpInt64to32(TVarData(Left),TVarData(Right),OpCode);
- opDivide:
- DoVarOpFloat(TVarData(Left),TVarData(Right),OpCode);
- else
- DoVarOpLongInt(TVarData(Left),TVarData(Right),OpCode);
- end;
- {$ifndef FPUNONE}
- ctFloat:
- if OpCode in [opAdd,opSubtract,opMultiply,opDivide] then
- DoVarOpFloat(TVarData(Left),TVarData(Right),OpCode)
- else
- DoVarOpInt64to32(TVarData(Left),TVarData(Right),OpCode);
- {$endif}
- ctBoolean:
- case OpCode of
- opAdd..opMultiply, opPower:
- DoVarOpFloat(TVarData(Left),TVarData(Right),OpCode);
- opIntDivide..opShiftRight:
- DoVarOpLongInt(TVarData(Left),TVarData(Right),OpCode);
- opAnd..opXor:
- DoVarOpBool(TVarData(Left),TVarData(Right),OpCode);
- else
- VarInvalidOp(TVarData(Left).vType, TVarData(Right).vType, OpCode);
- end;
- ctInt64:
- if OpCode <> opDivide then
- DoVarOpInt64(TVarData(Left),TVarData(Right),OpCode)
- else
- DoVarOpFloat(TVarData(Left),TVarData(Right),OpCode);
- ctNull:
- DoVarOpNull(TVarData(Left),TVarData(Right),OpCode);
- ctWideStr:
- case OpCode of
- opAdd:
- DoVarOpWStrCat(TVarData(Left),TVarData(Right));
- opSubtract..opDivide,opPower:
- DoVarOpFloat(TVarData(Left),TVarData(Right),OpCode);
- opIntDivide..opXor:
- DoVarOpInt64to32(TVarData(Left),TVarData(Right),OpCode);
- else
- VarInvalidOp(TVarData(Left).vType, TVarData(Right).vType, OpCode);
- end;
- {$ifndef FPUNONE}
- ctDate:
- case OpCode of
- opAdd:
- DoVarOpDate(TVarData(Left),TVarData(Right),OpCode);
- opSubtract: begin
- DoVarOpDate(TVarData(Left),TVarData(Right),OpCode);
- if lct = rct then {both are date}
- TVarData(Left).vType := varDouble;
- end;
- opMultiply, opDivide:
- DoVarOpFloat(TVarData(Left),TVarData(Right),OpCode);
- else
- DoVarOpInt64to32(TVarData(Left),TVarData(Right),OpCode);
- end;
- ctCurrency:
- if OpCode in [opAdd..opDivide, opPower] then
- DoVarOpCurr(TVarData(Left),TVarData(Right),OpCode, lct, rct)
- else
- DoVarOpInt64to32(TVarData(Left),TVarData(Right),OpCode);
- {$endif}
- ctString:
- case OpCode of
- opAdd:
- DoVarOpLStrCat(TVarData(Left),TVarData(Right));
- opSubtract..opDivide,opPower:
- DoVarOpFloat(TVarData(Left),TVarData(Right),OpCode);
- opIntDivide..opXor:
- DoVarOpInt64to32(TVarData(Left),TVarData(Right),OpCode);
- else
- VarInvalidOp(TVarData(Left).vType, TVarData(Right).vType, OpCode);
- end;
- else
- { more complex case }
- DoVarOpComplex(TVarData(Left),TVarData(Right),OpCode);
- end;
- end;
- procedure DoVarNegAny(var v: TVarData);
- begin
- VarInvalidOp(v.vType, opNegate);
- end;
- procedure DoVarNegComplex(var v: TVarData);
- begin
- { custom variants? }
- VarInvalidOp(v.vType, opNegate);
- end;
- procedure sysvarneg(var v: Variant);
- const
- BoolMap: array [Boolean] of SmallInt = (0, -1);
- begin
- with TVarData(v) do case vType of
- varEmpty: begin
- vSmallInt := 0;
- vType := varSmallInt;
- end;
- varNull:;
- varSmallint: vSmallInt := -vSmallInt;
- varInteger: vInteger := -vInteger;
- {$ifndef FPUNONE}
- varSingle: vSingle := -vSingle;
- varDouble: vDouble := -vDouble;
- varCurrency: vCurrency := -vCurrency;
- varDate: vDate := -vDate;
- varOleStr: sysvarfromreal(v, -VariantToDouble(TVarData(v)));
- {$else}
- varOleStr: sysvarfromint64(v, -VariantToInt64(TVarData(v)));
- {$endif}
- varBoolean: begin
- vSmallInt := BoolMap[vBoolean];
- vType := varSmallInt;
- end;
- varShortInt: vShortInt := -vShortInt;
- varByte: begin
- vSmallInt := -vByte;
- vType := varSmallInt;
- end;
- varWord: begin
- vInteger := -vWord;
- vType := varInteger;
- end;
- varLongWord:
- if vLongWord and $80000000 <> 0 then begin
- vInt64 := -vLongWord;
- vType := varInt64;
- end else begin
- vInteger := -vLongWord;
- vType := varInteger;
- end;
- varInt64: vInt64 := -vInt64;
- varQWord: begin
- if vQWord and $8000000000000000 <> 0 then
- VarRangeCheckError(varQWord, varInt64);
- vInt64 := -vQWord;
- vType := varInt64;
- end;
- varVariant: v := -Variant(PVarData(vPointer)^);
- else {with TVarData(v) do case vType of}
- case vType of
- {$ifndef FPUNONE}
- varString: sysvarfromreal(v, -VariantToDouble(TVarData(v)));
- {$else}
- varString: sysvarfromint64(v, -VariantToInt64(TVarData(v)));
- {$endif}
- varAny: DoVarNegAny(TVarData(v));
- else {case vType of}
- if (vType and not varTypeMask) = varByRef then
- case vType and varTypeMask of
- varSmallInt: begin
- vSmallInt := -PSmallInt(vPointer)^;
- vType := varSmallInt;
- end;
- varInteger: begin
- vInteger := -PInteger(vPointer)^;
- vType := varInteger;
- end;
- {$ifndef FPUNONE}
- varSingle: begin
- vSingle := -PSingle(vPointer)^;
- vType := varSingle;
- end;
- varDouble: begin
- vDouble := -PDouble(vPointer)^;
- vType := varDouble;
- end;
- varCurrency: begin
- vCurrency := -PCurrency(vPointer)^;
- vType := varCurrency;
- end;
- varDate: begin
- vDate := -PDate(vPointer)^;
- vType := varDate;
- end;
- varOleStr: sysvarfromreal(v, -VariantToDouble(TVarData(v)));
- {$else}
- varOleStr: sysvarfromint64(v, -VariantToInt64(TVarData(v)));
- {$endif}
- varBoolean: begin
- vSmallInt := BoolMap[PWordBool(vPointer)^];
- vType := varSmallInt;
- end;
- varShortInt: begin
- vShortInt := -PShortInt(vPointer)^;
- vType := varShortInt;
- end;
- varByte: begin
- vSmallInt := -PByte(vPointer)^;
- vType := varSmallInt;
- end;
- varWord: begin
- vInteger := -PWord(vPointer)^;
- vType := varInteger;
- end;
- varLongWord:
- if PLongWord(vPointer)^ and $80000000 <> 0 then begin
- vInt64 := -PLongWord(vPointer)^;
- vType := varInt64;
- end else begin
- vInteger := -PLongWord(vPointer)^;
- vType := varInteger;
- end;
- varInt64: begin
- vInt64 := -PInt64(vPointer)^;
- vType := varInt64;
- end;
- varQWord: begin
- if PQWord(vPointer)^ and $8000000000000000 <> 0 then
- VarRangeCheckError(varQWord, varInt64);
- vInt64 := -PQWord(vPointer)^;
- vType := varInt64;
- end;
- varVariant:
- v := -Variant(PVarData(vPointer)^);
- else {case vType and varTypeMask of}
- DoVarNegComplex(TVarData(v));
- end {case vType and varTypeMask of}
- else {if (vType and not varTypeMask) = varByRef}
- DoVarNegComplex(TVarData(v));
- end; {case vType of}
- end; {with TVarData(v) do case vType of}
- end;
- procedure DoVarNotAny(var v: TVarData);
- begin
- VarInvalidOp(v.vType, opNot);
- end;
- procedure DoVarNotOrdinal(var v: TVarData);
- var
- i: Int64;
- begin
- { only called for types that do no require finalization }
- i := VariantToInt64(v);
- with v do
- if (i < Low(Integer)) or (i > High(Integer)) then begin
- vInt64 := not i;
- vType := varInt64;
- end else begin
- vInteger := not Integer(i);
- vType := varInteger;
- end
- end;
- procedure DoVarNotWStr(var v: TVarData; const p: Pointer);
- var
- i: Int64;
- e: Word;
- b: Boolean;
- begin
- Val(WideString(p), i, e);
- with v do
- if e = 0 then begin
- DoVarClearIfComplex(v);
- if (i < Low(Integer)) or (i > High(Integer)) then begin
- vInt64 := not i;
- vType := varInt64;
- end else begin
- vInteger := not Integer(i);
- vType := varInteger;
- end
- end else begin
- if not TryStrToBool(WideString(p), b) then
- VarInvalidOp(vType, opNot);
- DoVarClearIfComplex(v);
- vBoolean := not b;
- vType := varBoolean;
- end;
- end;
- procedure DoVarNotLStr(var v: TVarData; const p: Pointer);
- var
- i: Int64;
- e: Word;
- b: Boolean;
- begin
- Val(AnsiString(p), i, e);
- with v do
- if e = 0 then begin
- DoVarClearIfComplex(v);
- if (i < Low(Integer)) or (i > High(Integer)) then begin
- vInt64 := not i;
- vType := varInt64;
- end else begin
- vInteger := not Integer(i);
- vType := varInteger;
- end
- end else begin
- if not TryStrToBool(AnsiString(p), b) then
- VarInvalidOp(v.vType, opNot);
- DoVarClearIfComplex(v);
- vBoolean := not b;
- vType := varBoolean;
- end;
- end;
- procedure DoVarNotComplex(var v: TVarData);
- begin
- { custom variant support ?}
- VarInvalidOp(v.vType, opNot);
- end;
- procedure sysvarnot(var v: Variant);
- begin
- with TVarData(v) do case vType of
- varEmpty: v := -1;
- varNull:;
- varSmallint: vSmallInt := not vSmallInt;
- varInteger: vInteger := not vInteger;
- {$ifndef FPUNONE}
- varSingle,
- varDouble,
- varCurrency,
- varDate: DoVarNotOrdinal(TVarData(v));
- {$endif}
- varOleStr: DoVarNotWStr(TVarData(v), Pointer(vOleStr));
- varBoolean: vBoolean := not vBoolean;
- varShortInt: vShortInt := not vShortInt;
- varByte: vByte := not vByte;
- varWord: vWord := not vWord;
- varLongWord: vLongWord := not vLongWord;
- varInt64: vInt64 := not vInt64;
- varQWord: vQWord := not vQWord;
- varVariant: v := not Variant(PVarData(vPointer)^);
- else {with TVarData(v) do case vType of}
- case vType of
- varString: DoVarNotLStr(TVarData(v), Pointer(vString));
- varAny: DoVarNotAny(TVarData(v));
- else {case vType of}
- if (vType and not varTypeMask) = varByRef then
- case vType and varTypeMask of
- varSmallInt: begin
- vSmallInt := not PSmallInt(vPointer)^;
- vType := varSmallInt;
- end;
- varInteger: begin
- vInteger := not PInteger(vPointer)^;
- vType := varInteger;
- end;
- {$ifndef FPUNONE}
- varSingle,
- varDouble,
- varCurrency,
- varDate: DoVarNotOrdinal(TVarData(v));
- {$endif}
- varOleStr: DoVarNotWStr(TVarData(v), PPointer(vPointer)^);
- varBoolean: begin
- vBoolean := not PWordBool(vPointer)^;
- vType := varBoolean;
- end;
- varShortInt: begin
- vShortInt := not PShortInt(vPointer)^;
- vType := varShortInt;
- end;
- varByte: begin
- vByte := not PByte(vPointer)^;
- vType := varByte;
- end;
- varWord: begin
- vWord := not PWord(vPointer)^;
- vType := varWord;
- end;
- varLongWord: begin
- vLongWord := not PLongWord(vPointer)^;
- vType := varLongWord;
- end;
- varInt64: begin
- vInt64 := not PInt64(vPointer)^;
- vType := varInt64;
- end;
- varQWord: begin
- vQWord := not PQWord(vPointer)^;
- vType := varQWord;
- end;
- varVariant:
- v := not Variant(PVarData(vPointer)^);
- else {case vType and varTypeMask of}
- DoVarNotComplex(TVarData(v));
- end {case vType and varTypeMask of}
- else {if (vType and not varTypeMask) = varByRef}
- DoVarNotComplex(TVarData(v));
- end; {case vType of}
- end; {with TVarData(v) do case vType of}
- end;
- {
- This procedure is needed to destroy and clear non-standard variant type array elements,
- which can not be handled by SafeArrayDestroy.
- If array element type is varVariant, then clear each element individually before
- calling VariantClear for array. VariantClear just calls SafeArrayDestroy.
- }
- procedure DoVarClearArray(var VArray: TVarData);
- var
- arr: pvararray;
- i, cnt: cardinal;
- data: pvardata;
- begin
- if VArray.vtype and varTypeMask = varVariant then begin
- if WordBool(VArray.vType and varByRef) then
- arr:=PVarArray(VArray.vPointer^)
- else
- arr:=VArray.vArray;
- VarResultCheck(SafeArrayAccessData(arr, data));
- try
- { Calculation total number of elements in the array }
- cnt:=1;
- {$ifopt r+}
- { arr^.bounds[] is an array[0..0] }
- {$define rangeon}
- {$r-}
- {$endif}
- for i:=0 to arr^.dimcount - 1 do
- cnt:=cnt*cardinal(arr^.Bounds[i].ElementCount);
- {$ifdef rangeon}
- {$undef rangeon}
- {$r+}
- {$endif}
- { Clearing each element }
- for i:=1 to cnt do begin
- DoVarClear(data^);
- Inc(pointer(data), arr^.ElementSize);
- end;
- finally
- VarResultCheck(SafeArrayUnaccessData(arr));
- end;
- end;
- VariantClear(VArray);
- end;
- procedure DoVarClearComplex(var v : TVarData);
- var
- Handler : TCustomVariantType;
- begin
- with v do
- if vType < varInt64 then
- VarResultCheck(VariantClear(v))
- else if vType = varString then begin
- AnsiString(vString) := '';
- vType := varEmpty
- end else if vType = varAny then
- ClearAnyProc(v)
- else if vType and varArray <> 0 then
- DoVarClearArray(v)
- else if FindCustomVariantType(vType, Handler) then
- Handler.Clear(v)
- else begin
- { ignore errors, if the OS doesn't know how to free it, we don't either }
- VariantClear(v);
- vType := varEmpty;
- end;
- end;
- type
- TVarArrayCopyCallback = procedure(var aDest: TVarData; const aSource: TVarData);
- procedure DoVarCopyArray(var aDest: TVarData; const aSource: TVarData; aCallback: TVarArrayCopyCallback);
- var
- SourceArray : PVarArray;
- SourcePtr : Pointer;
- DestArray : PVarArray;
- DestPtr : Pointer;
- Bounds : array[0..63] of TVarArrayBound;
- Iterator : TVariantArrayIterator;
- Dims : Integer;
- HighBound : Integer;
- i : Integer;
- begin
- with aSource do begin
- if vType and varArray = 0 then
- VarResultCheck(VAR_INVALIDARG);
- if (vType and varTypeMask) = varVariant then begin
- if (vType and varByRef) <> 0 then
- SourceArray := PVarArray(vPointer^)
- else
- SourceArray := vArray;
- Dims := SourceArray^.DimCount;
- for i := 0 to Pred(Dims) do
- with Bounds[i] do begin
- VarResultCheck(SafeArrayGetLBound(SourceArray, Succ(i), LowBound));
- VarResultCheck(SafeArrayGetUBound(SourceArray, Succ(i), HighBound));
- ElementCount := HighBound - LowBound + 1;
- end;
- DestArray := SafeArrayCreate(varVariant, Dims, PVarArrayBoundArray(@Bounds)^);
- if not Assigned(DestArray) then
- VarArrayCreateError;
- DoVarClearIfComplex(aDest);
- with aDest do begin
- vType := varVariant or varArray;
- vArray := DestArray;
- end;
- Iterator.Init(Dims, @Bounds);
- try
- if not(Iterator.AtEnd) then
- repeat
- VarResultCheck(SafeArrayPtrOfIndex(SourceArray, Iterator.Coords, SourcePtr));
- VarResultCheck(SafeArrayPtrOfIndex(DestArray, Iterator.Coords, DestPtr));
- aCallback(PVarData(DestPtr)^, PVarData(SourcePtr)^);
- until not Iterator.Next;
- finally
- Iterator.Done;
- end;
- end else
- VarResultCheck(VariantCopy(aDest, aSource));
- end;
- end;
- procedure DoVarCopyComplex(var Dest: TVarData; const Source: TVarData);
- var
- Handler: TCustomVariantType;
- begin
- DoVarClearIfComplex(Dest);
- with Source do
- if vType < varInt64 then
- VarResultCheck(VariantCopy(Dest, Source))
- else if vType = varString then begin
- Dest.vType := varString;
- Dest.vString := nil;
- AnsiString(Dest.vString) := AnsiString(vString);
- end else if vType = varAny then begin
- Dest := Source;
- RefAnyProc(Dest);
- end else if vType and varArray <> 0 then
- DoVarCopyArray(Dest, Source, @DoVarCopy)
- else if FindCustomVariantType(vType, Handler) then
- Handler.Copy(Dest, Source, False)
- else
- VarResultCheck(VariantCopy(Dest, Source));
- end;
- procedure DoVarCopy(var Dest : TVarData; const Source : TVarData);
- begin
- if @Dest <> @Source then
- if (Source.vType and varComplexType) = 0 then begin
- DoVarClearIfComplex(Dest);
- Dest := Source;
- end else
- DoVarCopyComplex(Dest, Source);
- end;
- procedure sysvarcopy (var Dest : Variant; const Source : Variant);
- begin
- DoVarCopy(TVarData(Dest),TVarData(Source));
- end;
- procedure DoVarAddRef(var v : TVarData); inline;
- var
- Dummy : TVarData;
- begin
- Dummy := v;
- v.vType := varEmpty;
- DoVarCopy(v, Dummy);
- end;
- procedure sysvaraddref(var v : Variant);
- begin
- DoVarAddRef(TVarData(v));
- end;
- procedure DoVarCastWStr(var aDest : TVarData; const aSource : TVarData);
- begin
- SysVarFromWStr(Variant(aDest), VariantToWideString(aSource));
- end;
- procedure DoVarCastLStr(var aDest : TVarData; const aSource : TVarData);
- begin
- SysVarFromLStr(Variant(aDest), VariantToAnsiString(aSource));
- end;
- procedure DoVarCastDispatch(var aDest : TVarData; const aSource : TVarData);
- var
- Disp: IDispatch;
- begin
- SysVarToDisp(Disp, Variant(aSource));
- SysVarFromDisp(Variant(aDest), Disp);
- end;
- procedure DoVarCastInterface(var aDest : TVarData; const aSource : TVarData);
- var
- Intf: IInterface;
- begin
- SysVarToIntf(Intf, Variant(aSource));
- SysVarFromIntf(Variant(aDest), Intf);
- end;
- procedure DoVarCastAny(var aDest : TVarData; const aSource : TVarData; aVarType : LongInt);
- begin
- VarCastError(aSource.vType, aVarType)
- end;
- procedure DoVarCastFallback(var aDest : TVarData; const aSource : TVarData; aVarType : LongInt);
- begin
- if aSource.vType and varTypeMask >= varInt64 then begin
- DoVarCast(aDest, aSource, varOleStr);
- VarResultCheck(VariantChangeTypeEx(aDest, aDest, VAR_LOCALE_USER_DEFAULT,
- 0, aVarType), aSource.vType, aVarType);
- end else if aVarType and varTypeMask < varInt64 then
- VarResultCheck(VariantChangeTypeEx(aDest, aSource, VAR_LOCALE_USER_DEFAULT,
- 0, aVarType), aSource.vType, aVarType)
- else
- VarCastError(aSource.vType, aVarType);
- end;
- procedure DoVarCastComplex(var aDest : TVarData; const aSource : TVarData; aVarType : LongInt);
- var
- Handler: TCustomVariantType;
- begin
- if aSource.vType = varAny then
- DoVarCastAny(aDest, aSource, aVarType)
- else if FindCustomVariantType(aSource.vType, Handler) then
- Handler.CastTo(aDest, aSource, aVarType)
- else if FindCustomVariantType(aVarType, Handler) then
- Handler.Cast(aDest, aSource)
- else
- DoVarCastFallback(aDest, aSource, aVarType);
- end;
- procedure DoVarCast(var aDest : TVarData; const aSource : TVarData; aVarType : LongInt);
- begin
- with aSource do
- if vType = aVarType then
- DoVarCopy(aDest, aSource)
- else begin
- if (vType = varNull) and NullStrictConvert then
- VarCastError(varNull, aVarType);
- case aVarType of
- varEmpty, varNull: begin
- DoVarClearIfComplex(aDest);
- aDest.vType := aVarType;
- end;
- varSmallInt: SysVarFromInt(Variant(aDest), VariantToSmallInt(aSource), -2);
- varInteger: SysVarFromInt(Variant(aDest), VariantToLongInt(aSource), -4);
- {$ifndef FPUNONE}
- varSingle: SysVarFromSingle(Variant(aDest), VariantToSingle(aSource));
- varDouble: SysVarFromDouble(Variant(aDest), VariantToDouble(aSource));
- varCurrency: SysVarFromCurr(Variant(aDest), VariantToCurrency(aSource));
- varDate: SysVarFromTDateTime(Variant(aDest), VariantToDate(aSource));
- {$endif}
- varOleStr: DoVarCastWStr(aDest, aSource);
- varBoolean: SysVarFromBool(Variant(aDest), VariantToBoolean(aSource));
- varShortInt: SysVarFromInt(Variant(aDest), VariantToShortInt(aSource), -1);
- varByte: SysVarFromInt(Variant(aDest), VariantToByte(aSource), 1);
- varWord: SysVarFromInt(Variant(aDest), VariantToLongInt(aSource), 2);
- varLongWord: SysVarFromInt(Variant(aDest), Integer(VariantToCardinal(aSource)), 4);
- varInt64: SysVarFromInt64(Variant(aDest), VariantToInt64(aSource));
- varQWord: SysVarFromWord64(Variant(aDest), VariantToQWord(aSource));
- varDispatch: DoVarCastDispatch(aDest, aSource);
- varUnknown: DoVarCastInterface(aDest, aSource);
- else
- case aVarType of
- varString: DoVarCastLStr(aDest, aSource);
- varAny: VarCastError(vType, varAny);
- else
- DoVarCastComplex(aDest, aSource, aVarType);
- end;
- end;
- end;
- end;
- procedure sysvarcast (var aDest : Variant; const aSource : Variant; aVarType : LongInt);
- begin
- DoVarCast(TVarData(aDest), TVarData(aSource), aVarType);
- end;
- procedure sysvarfromdynarray(var Dest : Variant; const Source : Pointer; TypeInfo: Pointer);
- begin
- DynArrayToVariant(Dest,Source,TypeInfo);
- if VarIsEmpty(Dest) then
- VarCastError;
- end;
- procedure sysolevarfrompstr(var Dest : olevariant; const Source : ShortString);
- begin
- sysvarfromwstr(Variant(TVarData(Dest)), Source);
- end;
- procedure sysolevarfromlstr(var Dest : olevariant; const Source : AnsiString);
- begin
- sysvarfromwstr(Variant(TVarData(Dest)), Source);
- end;
- procedure DoOleVarFromAny(var aDest : TVarData; const aSource : TVarData);
- begin
- VarCastErrorOle(aSource.vType);
- end;
- procedure DoOleVarFromVar(var aDest : TVarData; const aSource : TVarData);
- var
- Handler: TCustomVariantType;
- begin
- with aSource do
- if vType = varByRef or varVariant then
- DoOleVarFromVar(aDest, PVarData(vPointer)^)
- else begin
- case vType of
- varShortInt, varByte, varWord:
- DoVarCast(aDest, aSource, varInteger);
- varLongWord:
- if vLongWord and $80000000 = 0 then
- DoVarCast(aDest, aSource, varInteger)
- else
- {$ifndef FPUNONE}
- if OleVariantInt64AsDouble then
- DoVarCast(aDest, aSource, varDouble)
- else
- {$endif}
- DoVarCast(aDest, aSource, varInt64);
- varInt64:
- if (vInt64 < Low(Integer)) or (vInt64 > High(Integer)) then
- {$ifndef FPUNONE}
- if OleVariantInt64AsDouble then
- DoVarCast(aDest, aSource, varDouble)
- else
- {$endif}
- DoVarCast(aDest, aSource, varInt64)
- else
- DoVarCast(aDest, aSource, varInteger);
- varQWord:
- if vQWord > High(Integer) then
- {$ifndef FPUNONE}
- if OleVariantInt64AsDouble or (vQWord and $8000000000000000 <> 0) then
- DoVarCast(aDest, aSource, varDouble)
- else
- {$endif}
- DoVarCast(aDest, aSource, varInt64)
- else
- DoVarCast(aDest, aSource, varInteger);
- varString:
- DoVarCast(aDest, aSource, varOleStr);
- varAny:
- DoOleVarFromAny(aDest, aSource);
- else
- if (vType and varArray) <> 0 then
- DoVarCopyArray(aDest, aSource, @DoOleVarFromVar)
- else if (vType and varTypeMask) < CFirstUserType then
- DoVarCopy(aDest, aSource)
- else if FindCustomVariantType(vType, Handler) then
- Handler.CastToOle(aDest, aSource)
- else
- VarCastErrorOle(vType);
- end;
- end;
- end;
- procedure sysolevarfromvar(var aDest : OleVariant; const aSource : Variant);
- begin
- DoOleVarFromVar(TVarData(aDest), TVarData(aSource));
- end;
- procedure sysolevarfromint(var Dest : olevariant; const Source : LongInt; const range : ShortInt);
- begin
- DoVarClearIfComplex(TVarData(Dest));
- with TVarData(Dest) do begin
- vInteger := Source;
- vType := varInteger;
- end;
- end;
- procedure DoVarCastOle(var aDest: TVarData; const aSource: TVarData; aVarType: LongInt);
- var
- Handler: TCustomVariantType;
- begin
- with aSource do
- if vType = varByRef or varVariant then
- DoVarCastOle(aDest, PVarData(VPointer)^, aVarType)
- else
- if (aVarType = varString) or (aVarType = varAny) then
- VarCastError(vType, aVarType)
- else if FindCustomVariantType(vType, Handler) then
- Handler.CastTo(aDest, aSource, aVarType)
- else
- DoVarCast(aDest, aSource, aVarType);
- end;
- procedure sysvarcastole(var Dest : Variant; const Source : Variant; aVarType : LongInt);
- begin
- DoVarCastOle(TVarData(Dest), TVarData(Source), aVarType);
- end;
- procedure sysdispinvoke(Dest : PVarData; const Source : TVarData;calldesc : pcalldesc;params : Pointer);cdecl;
- var
- temp : TVarData;
- tempp : ^TVarData;
- customvarianttype : TCustomVariantType;
- begin
- if Source.vType=(varByRef or varVariant) then
- sysdispinvoke(Dest,PVarData(Source.vPointer)^,calldesc,params)
- else
- begin
- try
- { get a defined Result }
- if not(assigned(Dest)) then
- tempp:=nil
- else
- begin
- fillchar(temp,SizeOf(temp),0);
- tempp:=@temp;
- end;
- case Source.vType of
- varDispatch,
- varAny,
- varUnknown,
- varDispatch or varByRef,
- varAny or varByRef,
- varUnknown or varByRef:
- VarDispProc(pvariant(tempp),Variant(Source),calldesc,params);
- else
- begin
- if FindCustomVariantType(Source.vType,customvarianttype) then
- customvarianttype.DispInvoke(tempp,Source,calldesc,params)
- else
- VarInvalidOp;
- end;
- end;
- finally
- if assigned(tempp) then
- begin
- DoVarCopy(Dest^,tempp^);
- DoVarClear(temp);
- end;
- end;
- end;
- end;
- procedure sysvararrayredim(var a : Variant;highbound : SizeInt);
- var
- src : TVarData;
- p : pvararray;
- newbounds : tvararraybound;
- begin
- src:=TVarData(a);
- { get final Variant }
- while src.vType=varByRef or varVariant do
- src:=TVarData(src.vPointer^);
- if (src.vType and varArray)<>0 then
- begin
- { get Pointer to the array }
- if (src.vType and varByRef)<>0 then
- p:=pvararray(src.vPointer^)
- else
- p:=src.vArray;
- {$ifopt r+}
- {$define rangeon}
- {$r-}
- {$endif}
- if highbound<p^.Bounds[p^.dimcount-1].LowBound-1 then
- VarInvalidArgError;
- newbounds.LowBound:=p^.Bounds[p^.dimcount-1].LowBound;
- {$ifdef rangon}
- {$undef rangeon}
- {$r+}
- {$endif}
- newbounds.ElementCount:=highbound-newbounds.LowBound+1;
- VarResultCheck(SafeArrayRedim(p,newbounds));
- end
- else
- VarInvalidArgError(src.vType);
- end;
- function getfinalvartype(const v : TVarData) : TVarType;{$IFDEF VARIANTINLINE}inline;{$ENDIF VARIANTINLINE}
- var
- p: PVarData;
- begin
- p := @v;
- while p^.vType = varByRef or varVariant do
- p := PVarData(p^.vPointer);
- Result := p^.vType;
- end;
- function sysvararrayget(const a : Variant;indexcount : SizeInt;indices : plongint) : Variant;cdecl;
- var
- src : TVarData;
- p : pvararray;
- arraysrc : pvariant;
- arrayelementtype : TVarType;
- begin
- src:=TVarData(a);
- { get final Variant }
- while src.vType=varByRef or varVariant do
- src:=TVarData(src.vPointer^);
- if (src.vType and varArray)<>0 then
- begin
- { get Pointer to the array }
- if (src.vType and varByRef)<>0 then
- p:=pvararray(src.vPointer^)
- else
- p:=src.vArray;
- { number of indices ok? }
- if p^.DimCount<>indexcount then
- VarInvalidArgError;
- arrayelementtype:=src.vType and varTypeMask;
- if arrayelementtype=varVariant then
- begin
- VarResultCheck(SafeArrayPtrOfIndex(p,PVarArrayCoorArray(indices),arraysrc));
- Result:=arraysrc^;
- end
- else
- begin
- TVarData(Result).vType:=arrayelementtype;
- VarResultCheck(SafeArrayGetElement(p,PVarArrayCoorArray(indices),@TVarData(Result).vPointer));
- end;
- end
- else
- VarInvalidArgError(src.vType);
- end;
- procedure sysvararrayput(var a : Variant; const value : Variant;indexcount : SizeInt;indices : plongint);cdecl;
- var
- Dest : TVarData;
- p : pvararray;
- arraydest : pvariant;
- valuevtype,
- arrayelementtype : TVarType;
- tempvar : Variant;
- variantmanager : tvariantmanager;
- begin
- Dest:=TVarData(a);
- { get final Variant }
- while Dest.vType=varByRef or varVariant do
- Dest:=TVarData(Dest.vPointer^);
- valuevtype:=getfinalvartype(TVarData(value));
- if not(VarTypeIsValidElementType(valuevtype)) and
- { varString isn't a valid varArray type but it is converted
- later }
- (valuevtype<>varString) then
- VarCastError(valuevtype,Dest.vType);
- if (Dest.vType and varArray)<>0 then
- begin
- { get Pointer to the array }
- if (Dest.vType and varByRef)<>0 then
- p:=pvararray(Dest.vPointer^)
- else
- p:=Dest.vArray;
- { number of indices ok? }
- if p^.DimCount<>indexcount then
- VarInvalidArgError;
- arrayelementtype:=Dest.vType and varTypeMask;
- if arrayelementtype=varVariant then
- begin
- VarResultCheck(SafeArrayPtrOfIndex(p,PVarArrayCoorArray(indices),arraydest));
- { we can't store ansistrings in Variant arrays so we convert the string to
- an olestring }
- if valuevtype=varString then
- begin
- tempvar:=VarToWideStr(value);
- arraydest^:=tempvar;
- end
- else
- arraydest^:=value;
- end
- else
- begin
- GetVariantManager(variantmanager);
- variantmanager.varcast(tempvar,value,arrayelementtype);
- if arrayelementtype in [varOleStr,varDispatch,varUnknown] then
- VarResultCheck(SafeArrayPutElement(p,PVarArrayCoorArray(indices),TVarData(tempvar).vPointer))
- else
- VarResultCheck(SafeArrayPutElement(p,PVarArrayCoorArray(indices),@TVarData(tempvar).vPointer));
- end;
- end
- else
- VarInvalidArgError(Dest.vType);
- end;
- { import from system unit }
- Procedure fpc_Write_Text_AnsiStr (Len : LongInt; Var f : Text; S : AnsiString); external name 'FPC_WRITE_TEXT_ANSISTR';
- function syswritevariant(var t : text; const v : Variant;width : LongInt) : Pointer;
- var
- s : AnsiString;
- variantmanager : tvariantmanager;
- begin
- GetVariantManager(variantmanager);
- variantmanager.vartolstr(s,v);
- fpc_write_text_ansistr(width,t,s);
- Result:=nil; // Pointer to what should be returned?
- end;
- function syswrite0Variant(var t : text; const v : Variant) : Pointer;
- var
- s : AnsiString;
- variantmanager : tvariantmanager;
- begin
- getVariantManager(variantmanager);
- variantmanager.vartolstr(s,v);
- fpc_write_text_ansistr(-1,t,s);
- Result:=nil; // Pointer to what should be returned?
- end;
- Const
- SysVariantManager : TVariantManager = (
- vartoint : @sysvartoint;
- vartoint64 : @sysvartoint64;
- vartoword64 : @sysvartoword64;
- vartobool : @sysvartobool;
- {$ifndef FPUNONE}
- vartoreal : @sysvartoreal;
- vartotdatetime: @sysvartotdatetime;
- {$endif}
- vartocurr : @sysvartocurr;
- vartopstr : @sysvartopstr;
- vartolstr : @sysvartolstr;
- vartowstr : @sysvartowstr;
- vartointf : @sysvartointf;
- vartodisp : @sysvartodisp;
- vartodynarray : @sysvartodynarray;
- varfrombool : @sysvarfromBool;
- varfromint : @sysvarfromint;
- varfromint64 : @sysvarfromint64;
- varfromword64 : @sysvarfromword64;
- {$ifndef FPUNONE}
- varfromreal : @sysvarfromreal;
- varfromtdatetime: @sysvarfromtdatetime;
- {$endif}
- varfromcurr : @sysvarfromcurr;
- varfrompstr : @sysvarfrompstr;
- varfromlstr : @sysvarfromlstr;
- varfromwstr : @sysvarfromwstr;
- varfromintf : @sysvarfromintf;
- varfromdisp : @sysvarfromdisp;
- varfromdynarray: @sysvarfromdynarray;
- olevarfrompstr: @sysolevarfrompstr;
- olevarfromlstr: @sysolevarfromlstr;
- olevarfromvar : @sysolevarfromvar;
- olevarfromint : @sysolevarfromint;
- varop : @SysVarOp;
- cmpop : @syscmpop;
- varneg : @sysvarneg;
- varnot : @sysvarnot;
- varinit : @sysvarinit;
- varclear : @sysvarclear;
- varaddref : @sysvaraddref;
- varcopy : @sysvarcopy;
- varcast : @sysvarcast;
- varcastole : @sysvarcastole;
- dispinvoke : @sysdispinvoke;
- vararrayredim : @sysvararrayredim;
- vararrayget : @sysvararrayget;
- vararrayput : @sysvararrayput;
- writevariant : @syswritevariant;
- write0Variant : @syswrite0variant;
- );
- Var
- PrevVariantManager : TVariantManager;
- Procedure SetSysVariantManager;
- begin
- GetVariantManager(PrevVariantManager);
- SetVariantManager(SysVariantManager);
- end;
- Procedure UnsetSysVariantManager;
- begin
- SetVariantManager(PrevVariantManager);
- end;
- { ---------------------------------------------------------------------
- Variant support procedures and functions
- ---------------------------------------------------------------------}
- function VarType(const V: Variant): TVarType;
- begin
- Result:=TVarData(V).vType;
- end;
- function VarTypeDeRef(const V: Variant): TVarType;
- var
- p: PVarData;
- begin
- p := @TVarData(V);
- Result := p^.vType and not varByRef;
- while Result = varVariant do begin
- p := p^.vPointer;
- if not Assigned(p) then
- VarBadTypeError;
- Result := p^.vType and not varByRef;
- end;
- end;
- function VarTypeDeRef(const V: TVarData): TVarType;
- begin
- Result := VarTypeDeRef(Variant(v));
- end;
- function VarAsType(const V: Variant; aVarType: TVarType): Variant;
- begin
- sysvarcast(Result,V,aVarType);
- end;
- function VarIsType(const V: Variant; aVarType: TVarType): Boolean; overload;
- begin
- Result:=((TVarData(V).vType and varTypeMask)=aVarType);
- end;
- function VarIsType(const V: Variant; const AVarTypes: array of TVarType): Boolean; overload;
- Var
- I : Integer;
- begin
- I:=Low(AVarTypes);
- Result:=False;
- While Not Result and (I<=High(AVarTypes)) do
- Result:=((TVarData(V).vType and varTypeMask)=AVarTypes[I]);
- end;
- function VarIsByRef(const V: Variant): Boolean;
- begin
- Result:=(TVarData(V).vType and varByRef)<>0;
- end;
- function VarIsEmpty(const V: Variant): Boolean;
- begin
- Result:=TVarData(V).vType=varEmpty;
- end;
- procedure VarCheckEmpty(const V: Variant);
- begin
- If VarIsEmpty(V) Then
- VariantError(SErrVarIsEmpty);
- end;
- procedure VarClear(var V: Variant);{$IFDEF VARIANTINLINE}inline;{$ENDIF VARIANTINLINE}
- begin
- sysvarclear(v);
- end;
- procedure VarClear(var V: OleVariant);{$IFDEF VARIANTINLINE}inline;{$ENDIF VARIANTINLINE}
- begin
- { strange casting using TVarData to avoid call of helper olevariant->Variant }
- sysvarclear(Variant(TVarData(v)));
- end;
- function VarIsNull(const V: Variant): Boolean;
- begin
- Result:=TVarData(V).vType=varNull;
- end;
- function VarIsClear(const V: Variant): Boolean;
- Var
- VT : TVarType;
- begin
- VT:=TVarData(V).vType and varTypeMask;
- Result:=(VT=varEmpty) or
- (((VT=varDispatch) or (VT=varUnknown))
- and (TVarData(V).vDispatch=Nil));
- end;
- function VarIsCustom(const V: Variant): Boolean;
- begin
- Result:=TVarData(V).vType>=CFirstUserType;
- end;
- function VarIsOrdinal(const V: Variant): Boolean;
- begin
- Result:=(TVarData(V).vType and varTypeMask) in OrdinalVarTypes;
- end;
- function VarIsFloat(const V: Variant): Boolean;
- begin
- Result:=(TVarData(V).vType and varTypeMask) in FloatVarTypes;
- end;
- function VarIsNumeric(const V: Variant): Boolean;
- begin
- Result:=(TVarData(V).vType and varTypeMask) in (OrdinalVarTypes + FloatVarTypes);
- end;
- function VarIsStr(const V: Variant): Boolean;
- begin
- case (TVarData(V).vType and varTypeMask) of
- varOleStr,
- varString :
- Result:=True;
- else
- Result:=False;
- end;
- end;
- function VarToStr(const V: Variant): string;
- begin
- Result:=VarToStrDef(V,'');
- end;
- function VarToStrDef(const V: Variant; const ADefault: string): string;
- begin
- If TVarData(V).vType<>varNull then
- Result:=V
- else
- Result:=ADefault;
- end;
- function VarToWideStr(const V: Variant): WideString;
- begin
- Result:=VarToWideStrDef(V,'');
- end;
- function VarToWideStrDef(const V: Variant; const ADefault: WideString): WideString;
- begin
- If TVarData(V).vType<>varNull then
- Result:=V
- else
- Result:=ADefault;
- end;
- function VarToUnicodeStr(const V: Variant): UnicodeString;
- begin
- Result:=VarToUnicodeStrDef(V,'');
- end;
- function VarToUnicodeStrDef(const V: Variant; const ADefault: UnicodeString): UnicodeString;
- begin
- If TVarData(V).vType<>varNull then
- Result:=V
- else
- Result:=ADefault;
- end;
- {$ifndef FPUNONE}
- function VarToDateTime(const V: Variant): TDateTime;
- begin
- Result:=VariantToDate(TVarData(V));
- end;
- function VarFromDateTime(const DateTime: TDateTime): Variant;
- begin
- SysVarClear(Result);
- with TVarData(Result) do
- begin
- vType:=varDate;
- vdate:=DateTime;
- end;
- end;
- {$endif}
- function VarInRange(const AValue, AMin, AMax: Variant): Boolean;
- begin
- Result:=(AValue>=AMin) and (AValue<=AMax);
- end;
- function VarEnsureRange(const AValue, AMin, AMax: Variant): Variant;
- begin
- If Result>AMAx then
- Result:=AMax
- else If Result<AMin Then
- Result:=AMin
- else
- Result:=AValue;
- end;
- function VarSameValue(const A, B: Variant): Boolean;
- var
- v1,v2 : TVarData;
- begin
- v1:=FindVarData(a)^;
- v2:=FindVarData(b)^;
- if v1.vType in [varEmpty,varNull] then
- Result:=v1.vType=v2.vType
- else if v2.vType in [varEmpty,varNull] then
- Result:=False
- else
- Result:=A=B;
- end;
- function VarCompareValue(const A, B: Variant): TVariantRelationship;
- var
- v1,v2 : TVarData;
- begin
- Result:=vrNotEqual;
- v1:=FindVarData(a)^;
- v2:=FindVarData(b)^;
- if (v1.vType in [varEmpty,varNull]) and (v1.vType=v2.vType) then
- Result:=vrEqual
- else if not(v2.vType in [varEmpty,varNull]) and
- not(v1.vType in [varEmpty,varNull]) then
- begin
- if a=b then
- Result:=vrEqual
- else if a>b then
- Result:=vrGreaterThan
- else
- Result:=vrLessThan;
- end;
- end;
- function VarIsEmptyParam(const V: Variant): Boolean;
- begin
- Result:=(TVarData(V).vType = varError) and
- (TVarData(V).vError=VAR_PARAMNOTFOUND);
- end;
- procedure SetClearVarToEmptyParam(var V: TVarData);
- begin
- VariantClear(V);
- V.vType := varError;
- V.vError := VAR_PARAMNOTFOUND;
- end;
- function VarIsError(const V: Variant; out aResult: HRESULT): Boolean;
- begin
- Result := TVarData(V).vType = varError;
- if Result then
- aResult := TVarData(v).vError;
- end;
- function VarIsError(const V: Variant): Boolean;
- begin
- Result := TVarData(V).vType = varError;
- end;
- function VarAsError(AResult: HRESULT): Variant;
- begin
- TVarData(Result).vType:=varError;
- TVarData(Result).vError:=AResult;
- end;
- function VarSupports(const V: Variant; const IID: TGUID; out Intf): Boolean;
- begin
- case TVarData(v).vType of
- varUnknown:
- Result := Assigned(TVarData(v).vUnknown) and (IInterface(TVarData(v).vUnknown).QueryInterface(IID, Intf) = S_OK);
- varUnknown or varByRef:
- Result := Assigned(TVarData(v).vPointer) and Assigned(pointer(TVarData(v).vPointer^)) and (IInterface(TVarData(v).vPointer^).QueryInterface(IID, Intf) = S_OK);
- varDispatch:
- Result := Assigned(TVarData(v).vDispatch) and (IInterface(TVarData(v).vDispatch).QueryInterface(IID, Intf) = S_OK);
- varDispatch or varByRef:
- Result := Assigned(TVarData(v).vPointer) and Assigned(pointer(TVarData(v).vPointer^)) and (IInterface(TVarData(v).vPointer^).QueryInterface(IID, Intf) = S_OK);
- varVariant, varVariant or varByRef:
- Result := Assigned(TVarData(v).vPointer) and VarSupports(Variant(PVarData(TVarData(v).vPointer)^), IID, Intf);
- else
- Result := False;
- end;
- end;
- function VarSupports(const V: Variant; const IID: TGUID): Boolean;
- var
- Dummy: IInterface;
- begin
- Result := VarSupports(V, IID, Dummy);
- end;
- { Variant copy support }
- {$warnings off}
- procedure VarCopyNoInd(var Dest: Variant; const Source: Variant);
- begin
- NotSupported('VarCopyNoInd');
- end;
- {$warnings on}
- {****************************************************************************
- Variant array support procedures and functions
- ****************************************************************************}
- {$r-}
- function VarArrayCreate(const Bounds: array of SizeInt; aVarType: TVarType): Variant;
- var
- hp : PVarArrayBoundArray;
- p : pvararray;
- i,lengthb : SizeInt;
- begin
- if not(VarTypeIsValidArrayType(aVarType)) or odd(length(Bounds)) then
- VarArrayCreateError;
- lengthb:=length(Bounds) div 2;
- try
- GetMem(hp,lengthb*SizeOf(TVarArrayBound));
- for i:=0 to lengthb-1 do
- begin
- hp^[i].LowBound:=Bounds[i*2];
- hp^[i].ElementCount:=Bounds[i*2+1]-Bounds[i*2]+1;
- end;
- SysVarClear(Result);
- p:=SafeArrayCreate(aVarType,lengthb,hp^);
- if not(assigned(p)) then
- VarArrayCreateError;
- TVarData(Result).vType:=aVarType or varArray;
- TVarData(Result).vArray:=p;
- finally
- FreeMem(hp);
- end;
- end;
- {$ifndef RANGECHECKINGOFF}
- {$r+}
- {$endif}
- function VarArrayCreate(const Bounds: PVarArrayBoundArray; Dims : SizeInt; aVarType: TVarType): Variant;
- var
- p : pvararray;
- begin
- if not(VarTypeIsValidArrayType(aVarType)) then
- VarArrayCreateError;
- SysVarClear(Result);
- p:=SafeArrayCreate(aVarType,Dims,Bounds^);
- if not(assigned(p)) then
- VarArrayCreateError;
- TVarData(Result).vType:=aVarType or varArray;
- TVarData(Result).vArray:=p;
- end;
- function VarArrayOf(const Values: array of Variant): Variant;
- var
- i : SizeInt;
- begin
- Result:=VarArrayCreate([0,high(Values)],varVariant);
- for i:=0 to high(Values) do
- Result[i]:=Values[i];
- end;
- function VarArrayAsPSafeArray(const A: Variant): PVarArray;
- var
- v : TVarData;
- begin
- v:=TVarData(a);
- while v.vType=varByRef or varVariant do
- v:=TVarData(v.vPointer^);
- if (v.vType and varArray)=varArray then
- begin
- if (v.vType and varByRef)<>0 then
- Result:=pvararray(v.vPointer^)
- else
- Result:=v.vArray;
- end
- else
- VarResultCheck(VAR_INVALIDARG);
- end;
- function VarArrayDimCount(const A: Variant) : LongInt;
- var
- hv : TVarData;
- begin
- hv:=TVarData(a);
- { get final Variant }
- while hv.vType=varByRef or varVariant do
- hv:=TVarData(hv.vPointer^);
- if (hv.vType and varArray)<>0 then
- Result:=hv.vArray^.DimCount
- else
- Result:=0;
- end;
- function VarArrayLowBound(const A: Variant; Dim: LongInt) : LongInt;
- begin
- VarResultCheck(SafeArrayGetLBound(VarArrayAsPSafeArray(A),Dim,Result));
- end;
- function VarArrayHighBound(const A: Variant; Dim: LongInt) : LongInt;
- begin
- VarResultCheck(SafeArrayGetUBound(VarArrayAsPSafeArray(A),Dim,Result));
- end;
- function VarArrayLock(const A: Variant): Pointer;
- begin
- VarResultCheck(SafeArrayAccessData(VarArrayAsPSafeArray(A),Result));
- end;
- procedure VarArrayUnlock(const A: Variant);
- begin
- VarResultCheck(SafeArrayUnaccessData(VarArrayAsPSafeArray(A)));
- end;
- function VarArrayRef(const A: Variant): Variant;
- begin
- if (TVarData(a).vType and varArray)=0 then
- VarInvalidArgError(TVarData(a).vType);
- TVarData(Result).vType:=TVarData(a).vType or varByRef;
- if (TVarData(a).vType and varByRef)=0 then
- TVarData(Result).vPointer:=@TVarData(a).vArray
- else
- TVarData(Result).vPointer:=@TVarData(a).vPointer;
- end;
- function VarIsArray(const A: Variant; AResolveByRef: Boolean): Boolean;
- var
- v : TVarData;
- begin
- v:=TVarData(a);
- if AResolveByRef then
- while v.vType=varByRef or varVariant do
- v:=TVarData(v.vPointer^);
- Result:=(v.vType and varArray)=varArray;
- end;
- function VarIsArray(const A: Variant): Boolean;
- begin
- VarIsArray:=VarIsArray(A,true);
- end;
- function VarTypeIsValidArrayType(const aVarType: TVarType): Boolean;
- begin
- Result:=aVarType in [varSmallInt,varInteger,
- {$ifndef FPUNONE}
- varSingle,varDouble,varDate,
- {$endif}
- varCurrency,varOleStr,varDispatch,varError,varBoolean,
- varVariant,varUnknown,varShortInt,varByte,varWord,varLongWord];
- end;
- function VarTypeIsValidElementType(const aVarType: TVarType): Boolean;
- var
- customvarianttype : TCustomVariantType;
- begin
- if FindCustomVariantType(aVarType,customvarianttype) then
- Result:=true
- else
- begin
- Result:=(aVarType and not(varByRef) and not(varArray)) in [varEmpty,varNull,varSmallInt,varInteger,
- {$ifndef FPUNONE}
- varSingle,varDouble,varDate,
- {$endif}
- varCurrency,varOleStr,varDispatch,varError,varBoolean,
- varVariant,varUnknown,varShortInt,varByte,varWord,varLongWord,varInt64];
- end;
- end;
- { ---------------------------------------------------------------------
- Variant <-> Dynamic arrays support
- ---------------------------------------------------------------------}
- function DynArrayGetVariantInfo(p : Pointer; var Dims : sizeint) : sizeint;
- begin
- Result:=varNull;
- { skip kind and name }
- inc(Pointer(p),ord(pdynarraytypeinfo(p)^.namelen)+2);
- p:=AlignToPtr(p);
- { skip elesize }
- inc(p,SizeOf(sizeint));
- { search recursive? }
- if pdynarraytypeinfo(ppointer(p)^)^.kind=21{tkDynArr} then
- Result:=DynArrayGetVariantInfo(ppointer(p)^,Dims)
- else
- begin
- { skip dynarraytypeinfo }
- inc(p,SizeOf(pdynarraytypeinfo));
- Result:=plongint(p)^;
- end;
- inc(Dims);
- end;
- {$r-}
- procedure DynArrayToVariant(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
- var
- i,
- Dims : sizeint;
- vararrtype,
- dynarrvartype : LongInt;
- vararraybounds : PVarArrayBoundArray;
- iter : TVariantArrayIterator;
- dynarriter : tdynarrayiter;
- p : Pointer;
- temp : Variant;
- variantmanager : tvariantmanager;
- dynarraybounds : tdynarraybounds;
- type
- TDynArray = array of Pointer;
- begin
- DoVarClear(TVarData(v));
- Dims:=0;
- dynarrvartype:=DynArrayGetVariantInfo(TypeInfo,Dims);
- vararrtype:=dynarrvartype;
- if (Dims>1) and not(DynamicArrayIsRectangular(DynArray,TypeInfo)) then
- exit;
- GetVariantManager(variantmanager);
- { retrieve Bounds array }
- Setlength(dynarraybounds,Dims);
- GetMem(vararraybounds,Dims*SizeOf(TVarArrayBound));
- try
- p:=DynArray;
- for i:=0 to Dims-1 do
- begin
- vararraybounds^[i].LowBound:=0;
- vararraybounds^[i].ElementCount:=length(TDynArray(p));
- dynarraybounds[i]:=length(TDynArray(p));
- if dynarraybounds[i]>0 then
- { we checked that the array is rectangular }
- p:=TDynArray(p)[0];
- end;
- { .. create Variant array }
- V:=VarArrayCreate(vararraybounds,Dims,vararrtype);
- VarArrayLock(V);
- try
- iter.init(Dims,PVarArrayBoundArray(vararraybounds));
- dynarriter.init(DynArray,TypeInfo,Dims,dynarraybounds);
- if not iter.AtEnd then
- repeat
- case vararrtype of
- varSmallInt:
- temp:=PSmallInt(dynarriter.data)^;
- varInteger:
- temp:=PInteger(dynarriter.data)^;
- {$ifndef FPUNONE}
- varSingle:
- temp:=PSingle(dynarriter.data)^;
- varDouble:
- temp:=PDouble(dynarriter.data)^;
- varDate:
- temp:=PDouble(dynarriter.data)^;
- {$endif}
- varCurrency:
- temp:=PCurrency(dynarriter.data)^;
- varOleStr:
- temp:=PWideString(dynarriter.data)^;
- varDispatch:
- temp:=PDispatch(dynarriter.data)^;
- varError:
- temp:=PError(dynarriter.data)^;
- varBoolean:
- temp:=PBoolean(dynarriter.data)^;
- varVariant:
- temp:=PVariant(dynarriter.data)^;
- varUnknown:
- temp:=PUnknown(dynarriter.data)^;
- varShortInt:
- temp:=PShortInt(dynarriter.data)^;
- varByte:
- temp:=PByte(dynarriter.data)^;
- varWord:
- temp:=PWord(dynarriter.data)^;
- varLongWord:
- temp:=PLongWord(dynarriter.data)^;
- varInt64:
- temp:=PInt64(dynarriter.data)^;
- varQWord:
- temp:=PQWord(dynarriter.data)^;
- else
- VarClear(temp);
- end;
- dynarriter.next;
- variantmanager.VarArrayPut(V,temp,Dims,PLongint(iter.Coords));
- until not(iter.next);
- finally
- iter.done;
- dynarriter.done;
- VarArrayUnlock(V);
- end;
- finally
- FreeMem(vararraybounds);
- end;
- end;
- procedure DynArrayFromVariant(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);
- var
- DynArrayDims,
- VarArrayDims : SizeInt;
- iter : TVariantArrayIterator;
- dynarriter : tdynarrayiter;
- temp : Variant;
- dynarrvartype : LongInt;
- variantmanager : tvariantmanager;
- vararraybounds : PVarArrayBoundArray;
- dynarraybounds : tdynarraybounds;
- i : SizeInt;
- type
- TDynArray = array of Pointer;
- begin
- VarArrayDims:=VarArrayDimCount(V);
- DynArrayDims:=0;
- dynarrvartype:=DynArrayGetVariantInfo(TypeInfo,DynArrayDims);
- if (VarArrayDims=0) or (VarArrayDims<>DynArrayDims) then
- VarResultCheck(VAR_INVALIDARG);
- { retrieve Bounds array }
- Setlength(dynarraybounds,VarArrayDims);
- GetMem(vararraybounds,VarArrayDims*SizeOf(TVarArrayBound));
- try
- for i:=0 to VarArrayDims-1 do
- begin
- vararraybounds^[i].LowBound:=VarArrayLowBound(V,i+1);
- vararraybounds^[i].ElementCount:=VarArrayHighBound(V,i+1)-vararraybounds^[i].LowBound+1;
- dynarraybounds[i]:=vararraybounds^[i].ElementCount;
- end;
- DynArraySetLength(DynArray,TypeInfo,VarArrayDims,PSizeInt(dynarraybounds));
- GetVariantManager(variantmanager);
- VarArrayLock(V);
- try
- iter.init(VarArrayDims,PVarArrayBoundArray(vararraybounds));
- dynarriter.init(DynArray,TypeInfo,VarArrayDims,dynarraybounds);
- if not iter.AtEnd then
- repeat
- temp:=variantmanager.VarArrayGet(V,VarArrayDims,PLongint(iter.Coords));
- case dynarrvartype of
- varSmallInt:
- PSmallInt(dynarriter.data)^:=temp;
- varInteger:
- PInteger(dynarriter.data)^:=temp;
- {$ifndef FPUNONE}
- varSingle:
- PSingle(dynarriter.data)^:=temp;
- varDouble:
- PDouble(dynarriter.data)^:=temp;
- varDate:
- PDouble(dynarriter.data)^:=temp;
- {$endif}
- varCurrency:
- PCurrency(dynarriter.data)^:=temp;
- varOleStr:
- PWideString(dynarriter.data)^:=temp;
- varDispatch:
- PDispatch(dynarriter.data)^:=temp;
- varError:
- PError(dynarriter.data)^:=temp;
- varBoolean:
- PBoolean(dynarriter.data)^:=temp;
- varVariant:
- PVariant(dynarriter.data)^:=temp;
- varUnknown:
- PUnknown(dynarriter.data)^:=temp;
- varShortInt:
- PShortInt(dynarriter.data)^:=temp;
- varByte:
- PByte(dynarriter.data)^:=temp;
- varWord:
- PWord(dynarriter.data)^:=temp;
- varLongWord:
- PLongWord(dynarriter.data)^:=temp;
- varInt64:
- PInt64(dynarriter.data)^:=temp;
- varQWord:
- PQWord(dynarriter.data)^:=temp;
- else
- VarCastError;
- end;
- dynarriter.next;
- until not(iter.next);
- finally
- iter.done;
- dynarriter.done;
- VarArrayUnlock(V);
- end;
- finally
- FreeMem(vararraybounds);
- end;
- end;
- {$ifndef RANGECHECKINGOFF}
- {$r+}
- {$endif}
- function FindCustomVariantType(const aVarType: TVarType; out CustomVariantType: TCustomVariantType): Boolean; overload;
- begin
- Result:=(aVarType>=CMinVarType);
- if Result then
- begin
- EnterCriticalSection(customvarianttypelock);
- try
- Result:=(aVarType-CMinVarType)<=high(customvarianttypes);
- if Result then
- begin
- CustomVariantType:=customvarianttypes[aVarType-CMinVarType];
- Result:=assigned(CustomVariantType) and
- (CustomVariantType<>InvalidCustomVariantType);
- end;
- finally
- LeaveCriticalSection(customvarianttypelock);
- end;
- end;
- end;
- {$warnings off}
- function FindCustomVariantType(const TypeName: string; out CustomVariantType: TCustomVariantType): Boolean; overload;
- begin
- NotSupported('FindCustomVariantType');
- end;
- {$warnings on}
- function Unassigned: Variant; // Unassigned standard constant
- begin
- SysVarClear(Result);
- TVarData(Result).vType := varEmpty;
- end;
- function Null: Variant; // Null standard constant
- begin
- SysVarClear(Result);
- TVarData(Result).vType := varNull;
- end;
- { ---------------------------------------------------------------------
- TCustomVariantType Class.
- ---------------------------------------------------------------------}
- {$warnings off}
- function TCustomVariantType.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
- begin
- NotSupported('TCustomVariantType.QueryInterface');
- end;
- function TCustomVariantType._AddRef: Integer; stdcall;
- begin
- NotSupported('TCustomVariantType._AddRef');
- end;
- function TCustomVariantType._Release: Integer; stdcall;
- begin
- NotSupported('TCustomVariantType._Release');
- end;
- procedure TCustomVariantType.SimplisticClear(var V: TVarData);
- begin
- NotSupported('TCustomVariantType.SimplisticClear');
- end;
- procedure TCustomVariantType.SimplisticCopy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean = False);
- begin
- NotSupported('TCustomVariantType.SimplisticCopy');
- end;
- procedure TCustomVariantType.RaiseInvalidOp;
- begin
- NotSupported('TCustomVariantType.RaiseInvalidOp');
- end;
- procedure TCustomVariantType.RaiseCastError;
- begin
- NotSupported('TCustomVariantType.RaiseCastError');
- end;
- procedure TCustomVariantType.RaiseDispError;
- begin
- NotSupported('TCustomVariantType.RaiseDispError');
- end;
- function TCustomVariantType.LeftPromotion(const V: TVarData; const Operation: TVarOp; out RequiredVarType: TVarType): Boolean;
- begin
- NotSupported('TCustomVariantType.LeftPromotion');
- end;
- function TCustomVariantType.RightPromotion(const V: TVarData; const Operation: TVarOp; out RequiredVarType: TVarType): Boolean;
- begin
- NotSupported('TCustomVariantType.RightPromotion');
- end;
- function TCustomVariantType.OlePromotion(const V: TVarData; out RequiredVarType: TVarType): Boolean;
- begin
- NotSupported('TCustomVariantType.OlePromotion');
- end;
- procedure TCustomVariantType.DispInvoke(Dest: PVarData; const Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
- begin
- NotSupported('TCustomVariantType.DispInvoke');
- end;
- procedure TCustomVariantType.VarDataInit(var Dest: TVarData);
- begin
- FillChar(Dest,SizeOf(Dest),0);
- end;
- procedure TCustomVariantType.VarDataClear(var Dest: TVarData);
- begin
- VarClearProc(Dest);
- end;
- procedure TCustomVariantType.VarDataCopy(var Dest: TVarData; const Source: TVarData);
- begin
- DoVarCopy(Dest,Source)
- end;
- procedure TCustomVariantType.VarDataCopyNoInd(var Dest: TVarData; const Source: TVarData);
- begin
- // This is probably not correct, but there is no DoVarCopyInd
- DoVarCopy(Dest,Source);
- end;
- procedure TCustomVariantType.VarDataCast(var Dest: TVarData; const Source: TVarData);
- begin
- DoVarCast(Dest, Source, VarType);
- end;
- procedure TCustomVariantType.VarDataCastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
- begin
- DoVarCast(Dest, Source, AVarType);
- end;
- procedure TCustomVariantType.VarDataCastTo(var Dest: TVarData; const aVarType: TVarType);
- begin
- DoVarCast(Dest,Dest,AVarType);
- end;
- procedure TCustomVariantType.VarDataCastToOleStr(var Dest: TVarData);
- begin
- VarDataCastTo(Dest, Dest, varOleStr);
- end;
- procedure TCustomVariantType.VarDataFromStr(var V: TVarData; const Value: string);
- begin
- sysvarfromlstr(Variant(V),Value);
- end;
- procedure TCustomVariantType.VarDataFromOleStr(var V: TVarData; const Value: WideString);
- begin
- sysvarfromwstr(variant(V),Value);
- end;
- function TCustomVariantType.VarDataToStr(const V: TVarData): string;
- begin
- sysvartolstr(Result,Variant(V));
- end;
- function TCustomVariantType.VarDataIsEmptyParam(const V: TVarData): Boolean;
- begin
- VarIsEmptyParam(Variant(V));
- end;
- function TCustomVariantType.VarDataIsByRef(const V: TVarData): Boolean;
- begin
- Result:=(V.vType and varByRef)=varByRef;
- end;
- function TCustomVariantType.VarDataIsArray(const V: TVarData): Boolean;
- begin
- Result:=(V.vType and varArray)=varArray;
- end;
- function TCustomVariantType.VarDataIsOrdinal(const V: TVarData): Boolean;
- begin
- Result:=(V.vType and varTypeMask) in OrdinalVarTypes;
- end;
- function TCustomVariantType.VarDataIsFloat(const V: TVarData): Boolean;
- begin
- Result:=(V.vType and varTypeMask) in FloatVarTypes;
- end;
- function TCustomVariantType.VarDataIsNumeric(const V: TVarData): Boolean;
- begin
- Result:=(V.vType and varTypeMask) in (OrdinalVarTypes + FloatVarTypes);
- end;
- function TCustomVariantType.VarDataIsStr(const V: TVarData): Boolean;
- begin
- Result:=
- ((V.vType and varTypeMask) = varOleStr) or
- ((V.vType and varTypeMask) = varString);
- end;
- constructor TCustomVariantType.Create;
- begin
- inherited Create;
- EnterCriticalSection(customvarianttypelock);
- try
- SetLength(customvarianttypes,Length(customvarianttypes)+1);
- customvarianttypes[High(customvarianttypes)]:=self;
- FVarType:=CMinVarType+High(customvarianttypes);
- finally
- LeaveCriticalSection(customvarianttypelock);
- end;
- end;
- constructor TCustomVariantType.Create(RequestedVarType: TVarType);
- begin
- FVarType:=RequestedVarType;
- end;
- destructor TCustomVariantType.Destroy;
- begin
- EnterCriticalSection(customvarianttypelock);
- try
- if FVarType<>0 then
- customvarianttypes[FVarType-CMinVarType]:=InvalidCustomVariantType;
- finally
- LeaveCriticalSection(customvarianttypelock);
- end;
- inherited Destroy;
- end;
- function TCustomVariantType.IsClear(const V: TVarData): Boolean;
- Var
- VT : TVarType;
-
- begin
- VT:=V.vType and varTypeMask;
- Result:=(VT=varEmpty) or (((VT=varDispatch) or (VT=varUnknown))
- and (TVarData(V).vDispatch=Nil));
- end;
- procedure TCustomVariantType.Cast(var Dest: TVarData; const Source: TVarData);
- begin
- DoVarCast(Dest,Source,VarType);
- end;
- procedure TCustomVariantType.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
- begin
- DoVarCast(Dest,Source,AVarType);
- end;
- procedure TCustomVariantType.CastToOle(var Dest: TVarData; const Source: TVarData);
- begin
- NotSupported('TCustomVariantType.CastToOle');
- end;
- procedure TCustomVariantType.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
- begin
- NotSupported('TCustomVariantType.BinaryOp');
- end;
- procedure TCustomVariantType.UnaryOp(var Right: TVarData; const Operation: TVarOp);
- begin
- NotSupported('TCustomVariantType.UnaryOp');
- end;
- function TCustomVariantType.CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean;
- begin
- NotSupported('TCustomVariantType.CompareOp');
- end;
- procedure TCustomVariantType.Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult);
- begin
- NotSupported('TCustomVariantType.Compare');
- end;
- {$warnings on}
- { ---------------------------------------------------------------------
- TInvokeableVariantType implementation
- ---------------------------------------------------------------------}
- {$warnings off}
- procedure TInvokeableVariantType.DispInvoke(Dest: PVarData; const Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
- begin
- NotSupported('TInvokeableVariantType.DispInvoke');
- end;
- function TInvokeableVariantType.DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
- begin
- NotSupported('TInvokeableVariantType.DoFunction');
- end;
- function TInvokeableVariantType.DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
- begin
- NotSupported('TInvokeableVariantType.DoProcedure');
- end;
- function TInvokeableVariantType.GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean;
- begin
- NotSupported('TInvokeableVariantType.GetProperty');
- end;
- function TInvokeableVariantType.SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean;
- begin
- NotSupported('TInvokeableVariantType.SetProperty');
- end;
- {$warnings on}
- function TPublishableVariantType.GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean;
- begin
- Result:=true;
- Variant(Dest):=GetPropValue(getinstance(v),name);
- end;
- function TPublishableVariantType.SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean;
- begin
- Result:=true;
- SetPropValue(getinstance(v),name,Variant(value));
- end;
- procedure VarCastError;
- begin
- raise EVariantTypeCastError.Create(SInvalidVarCast);
- end;
- procedure VarCastError(const ASourceType, ADestType: TVarType);
- begin
- raise EVariantTypeCastError.CreateFmt(SVarTypeCouldNotConvert,
- [VarTypeAsText(ASourceType),VarTypeAsText(ADestType)]);
- end;
- procedure VarCastErrorOle(const ASourceType: TVarType);
- begin
- raise EVariantTypeCastError.CreateFmt(SVarTypeCouldNotConvert,
- [VarTypeAsText(ASourceType),'(OleVariant)']);
- end;
- procedure VarInvalidOp;
- begin
- raise EVariantInvalidOpError.Create(SInvalidVarOp);
- end;
- procedure VarInvalidOp(const aLeft, aRight: TVarType; aOpCode: TVarOp);
- begin
- raise EVariantInvalidOpError.CreateFmt(SInvalidBinaryVarOp,
- [VarTypeAsText(aLeft),VarOpAsText[aOpCode],VarTypeAsText(aRight)]);
- end;
- procedure VarInvalidOp(const aRight: TVarType; aOpCode: TVarOp);
- begin
- raise EVariantInvalidOpError.CreateFmt(SInvalidUnaryVarOp,
- [VarOpAsText[aOpCode],VarTypeAsText(aRight)]);
- end;
- procedure VarInvalidNullOp;
- begin
- raise EVariantInvalidOpError.Create(SInvalidvarNullOp);
- end;
- procedure VarParamNotFoundError;
- begin
- raise EVariantParamNotFoundError.Create(SVarParamNotFound);
- end;
- procedure VarBadTypeError;
- begin
- raise EVariantBadVarTypeError.Create(SVarBadType);
- end;
- procedure VarOverflowError;
- begin
- raise EVariantOverflowError.Create(SVarOverflow);
- end;
- procedure VarOverflowError(const ASourceType, ADestType: TVarType);
- begin
- raise EVariantOverflowError.CreateFmt(SVarTypeConvertOverflow,
- [VarTypeAsText(ASourceType),VarTypeAsText(ADestType)]);
- end;
- procedure VarRangeCheckError(const AType: TVarType);
- begin
- raise EVariantOverflowError.CreateFmt(SVarTypeRangeCheck1,
- [VarTypeAsText(AType)])
- end;
- procedure VarRangeCheckError(const ASourceType, ADestType: TVarType);
- begin
- if ASourceType<>ADestType then
- raise EVariantOverflowError.CreateFmt(SVarTypeRangeCheck2,
- [VarTypeAsText(ASourceType),VarTypeAsText(ADestType)])
- else
- VarRangeCheckError(ASourceType);
- end;
- procedure VarBadIndexError;
- begin
- raise EVariantBadIndexError.Create(SVarArrayBounds);
- end;
- procedure VarArrayLockedError;
- begin
- raise EVariantArrayLockedError.Create(SVarArrayLocked);
- end;
- procedure VarNotImplError;
- begin
- raise EVariantNotImplError.Create(SVarNotImplemented);
- end;
- procedure VarOutOfMemoryError;
- begin
- raise EVariantOutOfMemoryError.Create(SOutOfMemory);
- end;
- procedure VarInvalidArgError;
- begin
- raise EVariantInvalidArgError.Create(SVarInvalid);
- end;
- procedure VarInvalidArgError(AType: TVarType);
- begin
- raise EVariantInvalidArgError.CreateFmt(SVarInvalid1,
- [VarTypeAsText(AType)])
- end;
- procedure VarUnexpectedError;
- begin
- raise EVariantUnexpectedError.Create(SVarUnexpected);
- end;
- procedure VarArrayCreateError;
- begin
- raise EVariantArrayCreateError.Create(SVarArrayCreate);
- end;
- procedure RaiseVarException(res : HRESULT);
- begin
- case res of
- VAR_PARAMNOTFOUND:
- VarParamNotFoundError;
- VAR_TYPEMISMATCH:
- VarCastError;
- VAR_BADVARTYPE:
- VarBadTypeError;
- VAR_EXCEPTION:
- VarInvalidOp;
- VAR_OVERFLOW:
- VarOverflowError;
- VAR_BADINDEX:
- VarBadIndexError;
- VAR_ARRAYISLOCKED:
- VarArrayLockedError;
- VAR_NOTIMPL:
- VarNotImplError;
- VAR_OUTOFMEMORY:
- VarOutOfMemoryError;
- VAR_INVALIDARG:
- VarInvalidArgError;
- VAR_UNEXPECTED:
- VarUnexpectedError;
- else
- raise EVariantError.CreateFmt(SInvalidVarOpWithHResultWithPrefix,
- ['$',res,'']);
- end;
- end;
- procedure VarResultCheck(AResult: HRESULT);{$IFDEF VARIANTINLINE}inline;{$ENDIF VARIANTINLINE}
- begin
- if AResult<>VAR_OK then
- RaiseVarException(AResult);
- end;
- procedure VarResultCheck(AResult: HRESULT; ASourceType, ADestType: TVarType);
- begin
- case AResult of
- VAR_OK:
- ;
- VAR_OVERFLOW:
- VarOverflowError(ASourceType,ADestType);
- VAR_TYPEMISMATCH:
- VarCastError(ASourceType,ADestType);
- else
- RaiseVarException(AResult);
- end;
- end;
- procedure HandleConversionException(const ASourceType, ADestType: TVarType);
- begin
- if exceptobject is econverterror then
- VarCastError(asourcetype,adesttype)
- else if (exceptobject is eoverflow) or
- (exceptobject is erangeerror) then
- varoverflowerror(asourcetype,adesttype)
- else
- raise exception(acquireexceptionobject);
- end;
- function VarTypeAsText(const AType: TVarType): string;
- var
- customvarianttype : TCustomVariantType;
- const
- names : array[varEmpty..varQWord] of string[8] = (
- 'Empty','Null','Smallint','Integer','Single','Double','Currency','Date','OleStr','Dispatch','Error','Boolean','Variant',
- 'Unknown','Decimal','???','ShortInt','Byte','Word','DWord','Int64','QWord');
- begin
- if ((AType and varTypeMask)>=low(names)) and ((AType and varTypeMask)<=high(names)) then
- Result:=names[AType and varTypeMask]
- else
- case AType and varTypeMask of
- varString:
- Result:='String';
- varAny:
- Result:='Any';
- else
- begin
- if FindCustomVariantType(AType and varTypeMask,customvarianttype) then
- Result:=customvarianttype.classname
- else
- Result:='$'+IntToHex(AType and varTypeMask,4)
- end;
- end;
- if (AType and vararray)<>0 then
- Result:='Array of '+Result;
- if (AType and varByRef)<>0 then
- Result:='Ref to '+Result;
- end;
- function FindVarData(const V: Variant): PVarData;
- begin
- Result:=PVarData(@V);
- while Result^.vType=varVariant or varByRef do
- Result:=PVarData(Result^.vPointer);
- end;
- { ---------------------------------------------------------------------
- Variant properties from typinfo
- ---------------------------------------------------------------------}
- function GetVariantProp(Instance : TObject;PropInfo : PPropInfo) : Variant;
- type
- TGetVariantProc = function:Variant of object;
- TGetVariantProcIndex = function(Index: integer): Variant of object;
- var
- AMethod : TMethod;
- begin
- Result:=Null;
- case PropInfo^.PropProcs and 3 of
- ptField:
- Result:=PVariant(Pointer(Instance)+PtrUInt(PropInfo^.GetProc))^;
- ptStatic,
- ptVirtual:
- begin
- if (PropInfo^.PropProcs and 3)=ptStatic then
- AMethod.Code:=PropInfo^.GetProc
- else
- AMethod.Code:=PPointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.GetProc))^;
- AMethod.Data:=Instance;
- if ((PropInfo^.PropProcs shr 6) and 1)=0 then
- Result:=TGetVariantProc(AMethod)()
- else
- Result:=TGetVariantProcIndex(AMethod)(PropInfo^.Index);
- end;
- end;
- end;
- Procedure SetVariantProp(Instance : TObject;PropInfo : PPropInfo; const Value : Variant);
- type
- TSetVariantProc = procedure(const AValue: Variant) of object;
- TSetVariantProcIndex = procedure(Index: integer; AValue: Variant) of object;
- Var
- AMethod : TMethod;
- begin
- case (PropInfo^.PropProcs shr 2) and 3 of
- ptfield:
- PVariant(Pointer(Instance)+PtrUInt(PropInfo^.SetProc))^:=Value;
- ptVirtual,ptStatic:
- begin
- if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then
- AMethod.Code:=PropInfo^.SetProc
- else
- AMethod.Code:=PPointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.SetProc))^;
- AMethod.Data:=Instance;
- if ((PropInfo^.PropProcs shr 6) and 1)=0 then
- TSetVariantProc(AMethod)(Value)
- else
- TSetVariantProcIndex(AMethod)(PropInfo^.Index,Value);
- end;
- end;
- end;
- Function GetVariantProp(Instance: TObject; const PropName: string): Variant;
- begin
- Result:=GetVariantProp(Instance,FindPropInfo(Instance,PropName));
- end;
- Procedure SetVariantProp(Instance: TObject; const PropName: string; const Value: Variant);
- begin
- SetVariantprop(instance,FindpropInfo(Instance,PropName),Value);
- end;
- { ---------------------------------------------------------------------
- All properties through Variant.
- ---------------------------------------------------------------------}
- Function GetPropValue(Instance: TObject; const PropName: string): Variant;
- begin
- Result:=GetPropValue(Instance,PropName,True);
- end;
- Function GetPropValue(Instance: TObject; const PropName: string; PreferStrings: Boolean): Variant;
- var
- PropInfo: PPropInfo;
- begin
- // find the property
- PropInfo := GetPropInfo(Instance, PropName);
- if PropInfo = nil then
- raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName])
- else
- begin
- Result := Null; //at worst
- // call the Right GetxxxProp
- case PropInfo^.PropType^.Kind of
- tkInteger, tkChar, tkWChar, tkClass, tkBool:
- Result := GetOrdProp(Instance, PropInfo);
- tkEnumeration:
- if PreferStrings then
- Result := GetEnumProp(Instance, PropInfo)
- else
- Result := GetOrdProp(Instance, PropInfo);
- tkSet:
- if PreferStrings then
- Result := GetSetProp(Instance, PropInfo, False)
- else
- Result := GetOrdProp(Instance, PropInfo);
- {$ifndef FPUNONE}
- tkFloat:
- Result := GetFloatProp(Instance, PropInfo);
- {$endif}
- tkMethod:
- Result := PropInfo^.PropType^.Name;
- tkString, tkLString, tkAString:
- Result := GetStrProp(Instance, PropInfo);
- tkWString:
- Result := GetWideStrProp(Instance, PropInfo);
- tkUString:
- Result := GetUnicodeStrProp(Instance, PropInfo);
- tkVariant:
- Result := GetVariantProp(Instance, PropInfo);
- tkInt64:
- Result := GetInt64Prop(Instance, PropInfo);
- else
- raise EPropertyConvertError.CreateFmt('Invalid Property Type: %s',[PropInfo^.PropType^.Name]);
- end;
- end;
- end;
- Procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant);
- var
- PropInfo: PPropInfo;
- // TypeData: PTypeData;
- O : Integer;
- S : String;
- B : Boolean;
- begin
- // find the property
- PropInfo := GetPropInfo(Instance, PropName);
- if PropInfo = nil then
- raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName])
- else
- begin
- // TypeData := GetTypeData(PropInfo^.PropType);
- // call Right SetxxxProp
- case PropInfo^.PropType^.Kind of
- tkBool:
- begin
- { to support the strings 'true' and 'false' }
- B:=Value;
- SetOrdProp(Instance, PropInfo, ord(B));
- end;
- tkInteger, tkChar, tkWChar:
- begin
- O:=Value;
- SetOrdProp(Instance, PropInfo, O);
- end;
- tkEnumeration :
- begin
- if (VarType(Value)=varOleStr) or (VarType(Value)=varString) then
- begin
- S:=Value;
- SetEnumProp(Instance,PropInfo,S);
- end
- else
- begin
- O:=Value;
- SetOrdProp(Instance, PropInfo, O);
- end;
- end;
- tkSet :
- begin
- if (VarType(Value)=varOleStr) or (VarType(Value)=varString) then
- begin
- S:=Value;
- SetSetProp(Instance,PropInfo,S);
- end
- else
- begin
- O:=Value;
- SetOrdProp(Instance, PropInfo, O);
- end;
- end;
- {$ifndef FPUNONE}
- tkFloat:
- SetFloatProp(Instance, PropInfo, Value);
- {$endif}
- tkString, tkLString, tkAString:
- SetStrProp(Instance, PropInfo, VarToStr(Value));
- tkWString:
- SetWideStrProp(Instance, PropInfo, VarToWideStr(Value));
- tkUString:
- SetUnicodeStrProp(Instance, PropInfo, VarToUnicodeStr(Value));
- tkVariant:
- SetVariantProp(Instance, PropInfo, Value);
- tkInt64:
- SetInt64Prop(Instance, PropInfo, Value);
- else
- raise EPropertyConvertError.CreateFmt('SetPropValue: Invalid Property Type %s',
- [PropInfo^.PropType^.Name]);
- end;
- end;
- end;
- var
- i : LongInt;
- Initialization
- InitCriticalSection(customvarianttypelock);
- SetSysVariantManager;
- SetClearVarToEmptyParam(TVarData(EmptyParam));
- VarClearProc:=@DoVarClear;
- VarAddRefProc:=@DoVarAddRef;
- VarCopyProc:=@DoVarCopy;
- // Typinfo Variant support
- OnGetVariantProp:=@GetVariantprop;
- OnSetVariantProp:=@SetVariantprop;
- OnSetPropValue:=@SetPropValue;
- OnGetPropValue:=@GetPropValue;
- InvalidCustomVariantType:=TCustomVariantType(-1);
- SetLength(customvarianttypes,CFirstUserType);
- Finalization
- EnterCriticalSection(customvarianttypelock);
- try
- for i:=0 to high(customvarianttypes) do
- if customvarianttypes[i]<>InvalidCustomVariantType then
- customvarianttypes[i].Free;
- finally
- LeaveCriticalSection(customvarianttypelock);
- end;
- UnSetSysVariantManager;
- DoneCriticalSection(customvarianttypelock);
- end.
|