12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664 |
- {
- 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 VarIsBool(const V: Variant): Boolean; inline;
- 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({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; virtual; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
- function _AddRef: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
- function _Release: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
- 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 = $0EFF;
- 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;
- var
- customvarianttypes : array of TCustomVariantType;
- customvarianttypelock : trtlcriticalsection;
- customvariantcurrtype : LongInt;
- 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;
- {$push}
- {$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;
- {$pop}// {$r-} for TVariantArrayIterator
- 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;typeInfo : Pointer;_dims: SizeInt;b : tdynarraybounds);
- function next : Boolean;
- destructor done;
- end;
- constructor tdynarrayiter.init(d : Pointer;typeInfo : Pointer;_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 }
- typeInfo:=aligntoptr(typeInfo+2+Length(PTypeInfo(typeInfo)^.Name));
- elesize[i]:=PTypeData(typeInfo)^.elSize;
- typeInfo:=PTypeData(typeInfo)^.elType2;
- 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) : Longint;
- 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;
- var Handler: TCustomVariantType;
- dest: TVarData;
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varDouble)
- else
- Result := 0
- { TODO: performance: custom variants must be handled after standard ones }
- else if FindCustomVariantType(TVarData(v).vType, Handler) then
- begin
- VariantInit(dest);
- Handler.CastTo(dest, TVarData(v), varDouble);
- Result := dest.vDouble;
- end
- 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;
- function CustomVarToLStr(const v: TVarData; out s: AnsiString): Boolean;
- var
- handler: TCustomVariantType;
- temp: TVarData;
- begin
- result := FindCustomVariantType(v.vType, handler);
- if result then
- begin
- VariantInit(temp);
- handler.CastTo(temp, v, varString);
- { out-semantic ensures that s is finalized,
- so just copy the pointer and don't finalize the temp }
- Pointer(s) := temp.vString;
- end;
- end;
- procedure sysvartolstr (var s : AnsiString; const v : Variant);
- begin
- if VarType(v) = varNull then
- if NullStrictConvert then
- VarCastError(varNull, varString)
- else
- s := NullAsStringValue
- { TODO: performance: custom variants must be handled after standard ones }
- else if not CustomVarToLStr(TVarData(v), s) then
- S := VariantToAnsiString(TVarData(V));
- end;
- procedure sysvartopstr (var s; const v : Variant);
- var
- tmp: AnsiString;
- begin
- sysvartolstr(tmp, v);
- ShortString(s) := tmp;
- 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 }
- TypeInfo:=aligntoptr(TypeInfo+2+Length(PTypeInfo(TypeInfo)^.Name));
- TypeInfo:=PTypeData(TypeInfo)^.elType2;
- { check recursively? }
- if assigned(TypeInfo) and (PTypeInfo(TypeInfo)^.kind=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 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;
- var Handler: TCustomVariantType;
- CmpRes: boolean;
- begin
- if (Left.vType=varnull) or (Right.vType=varnull) then
- // don't bother custom variant handlers with conversion to NULL
- begin
- if OpCode in [opCmpEq,opCmpNe] then
- begin
- if (Left.vType=Right.vType) xor (OpCode=opCmpNe) then
- result:=0
- else
- result:=-1;
- end
- else
- if Left.vType=varnull then
- begin
- if Right.vType=varnull then
- Result := 0
- else
- Result := -1;
- end
- else
- Result := 1;
- end
- else
- begin
- if FindCustomVariantType(Left.vType, Handler) then
- CmpRes := Handler.CompareOp(Left, Right, OpCode)
- else if FindCustomVariantType(Right.vType, Handler) then
- CmpRes := Handler.CompareOp(Left, Right, OpCode)
- else
- VarInvalidOp(Left.vType, Right.vType, OpCode);
- case OpCode of
- opCmpEq:
- if CmpRes then
- Result:=0
- else
- Result:=1;
- opCmpNe:
- if CmpRes then
- Result:=1
- else
- Result:=0;
- opCmpLt,
- opCmpLe:
- if CmpRes then
- Result:=-1
- else
- Result:=1;
- opCmpGt,
- opCmpGe:
- if CmpRes then
- Result:=1
- else
- Result:=-1;
- end;
- end;
- 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 := DoVarCmpFloat(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
- {$push}
- {$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;
- {$pop}
- 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);
- var Handler: TCustomVariantType;
- begin
- if FindCustomVariantType(vl.vType, Handler) then
- Handler.BinaryOp(vl, vr, OpCode)
- else if FindCustomVariantType(vr.vType, Handler) then
- Handler.BinaryOp(vl, vr, OpCode)
- else
- 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;
- {$push}
- { arr^.bounds[] is an array[0..0] }
- {$r-}
- for i:=0 to arr^.dimcount - 1 do
- cnt:=cnt*cardinal(arr^.Bounds[i].ElementCount);
- {$pop}
- { 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 = varUString then
- begin
- UnicodeString(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 : Longint;
- 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 (vType and varByRef <> 0) and (vType xor varByRef = varString) then
- Dest := Source
- 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;
- {$push}
- {$r-}
- if highbound<p^.Bounds[p^.dimcount-1].LowBound-1 then
- VarInvalidArgError;
- newbounds.LowBound:=p^.Bounds[p^.dimcount-1].LowBound;
- {$pop}
- 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;
- 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
- 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 : RawByteString); 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
- begin
- Result:=((TVarData(V).vType and varTypeMask)=AVarTypes[I]);
- inc(i);
- end;
- 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;
- CustomType: TCustomVariantType;
- begin
- VT:=TVarData(V).vType and varTypeMask;
- if VT<CFirstUserType then
- Result:=(VT=varEmpty) or
- (((VT=varDispatch) or (VT=varUnknown))
- and (TVarData(V).vDispatch=Nil))
- else
- Result:=FindCustomVariantType(VT,CustomType) and CustomType.IsClear(TVarData(V));
- 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,
- varUString,
- varString :
- Result:=True;
- else
- Result:=False;
- end;
- end;
- function VarIsBool(const V: Variant): Boolean;
- begin
- Result := (TVarData(V).vType and varTypeMask) = varboolean;
- 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 AValue>AMAx then
- Result:=AMax
- else If AValue<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 }
- {$push}
- {$warnings off}
- procedure VarCopyNoInd(var Dest: Variant; const Source: Variant);
- begin
- NotSupported('VarCopyNoInd');
- end;
- {$pop}
- {****************************************************************************
- Variant array support procedures and functions
- ****************************************************************************}
- {$push}
- {$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;
- {$pop}
- 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
- 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]) or
- FindCustomVariantType(aVarType,customvarianttype);
- end;
- { ---------------------------------------------------------------------
- Variant <-> Dynamic arrays support
- ---------------------------------------------------------------------}
- function DynArrayGetVariantInfo(p : Pointer; var Dims : sizeint) : sizeint;
- begin
- Result:=varNull;
- { skip kind and name }
- p:=aligntoptr(p+2+Length(PTypeInfo(p)^.Name));
- { search recursive? }
- if PTypeInfo(PTypeData(p)^.elType2)^.kind=tkDynArray then
- Result:=DynArrayGetVariantInfo(PTypeData(p)^.elType2,Dims)
- else
- Result:=PTypeData(p)^.varType;
- inc(Dims);
- end;
- {$push}
- {$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;
- 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;
- { 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;
- VarArrayPut(V,temp,Slice(iter.Coords^,Dims));
- 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;
- 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));
- VarArrayLock(V);
- try
- iter.init(VarArrayDims,PVarArrayBoundArray(vararraybounds));
- dynarriter.init(DynArray,TypeInfo,VarArrayDims,dynarraybounds);
- if not iter.AtEnd then
- repeat
- temp:=VarArrayGet(V,Slice(iter.Coords^,VarArrayDims));
- 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;
- {$pop}//{$r-} for DynArray[From|To]Variant
- 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;
- function FindCustomVariantType(const TypeName: string; out CustomVariantType: TCustomVariantType): Boolean; overload;
- var
- i: Integer;
- tmp: TCustomVariantType;
- ShortTypeName: shortstring;
- begin
- ShortTypeName:=TypeName; // avoid conversion in the loop
- result:=False;
- EnterCriticalSection(customvarianttypelock);
- try
- for i:=low(customvarianttypes) to high(customvarianttypes) do
- begin
- tmp:=customvarianttypes[i];
- result:=Assigned(tmp) and (tmp<>InvalidCustomVariantType) and
- tmp.ClassNameIs(ShortTypeName);
- if result then
- begin
- CustomVariantType:=tmp;
- Exit;
- end;
- end;
- finally
- LeaveCriticalSection(customvarianttypelock);
- end;
- end;
- 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;
- procedure VarDispInvokeError;
- begin
- raise EVariantDispatchError.Create(SDispatchError);
- end;
- { ---------------------------------------------------------------------
- TCustomVariantType Class.
- ---------------------------------------------------------------------}
- { All TCustomVariantType descendants are singletons, they ignore automatic refcounting. }
- function TCustomVariantType.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
- begin
- if GetInterface(IID, obj) then
- result := S_OK
- else
- result := E_NOINTERFACE;
- end;
- function TCustomVariantType._AddRef: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
- begin
- result := -1;
- end;
- function TCustomVariantType._Release: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
- begin
- result := -1;
- end;
- {$warnings off}
- procedure TCustomVariantType.SimplisticClear(var V: TVarData);
- begin
- VarDataInit(V);
- end;
- procedure TCustomVariantType.SimplisticCopy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean = False);
- begin
- NotSupported('TCustomVariantType.SimplisticCopy');
- end;
- procedure TCustomVariantType.RaiseInvalidOp;
- begin
- VarInvalidOp;
- end;
- procedure TCustomVariantType.RaiseCastError;
- begin
- VarCastError;
- end;
- procedure TCustomVariantType.RaiseDispError;
- begin
- VarDispInvokeError;
- 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
- RaiseDispError;
- 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
- Result:=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;
- procedure RegisterCustomVariantType(obj: TCustomVariantType; RequestedVarType: TVarType;
- UseFirstAvailable: Boolean);
- var
- index,L: Integer;
- begin
- EnterCriticalSection(customvarianttypelock);
- try
- L:=Length(customvarianttypes);
- if UseFirstAvailable then
- begin
- repeat
- inc(customvariantcurrtype);
- if customvariantcurrtype>=CMaxVarType then
- raise EVariantError.Create(SVarTypeTooManyCustom);
- until ((customvariantcurrtype-CMinVarType)>=L) or
- (customvarianttypes[customvariantcurrtype-CMinVarType]=nil);
- RequestedVarType:=customvariantcurrtype;
- end
- else if (RequestedVarType<CFirstUserType) or (RequestedVarType>CMaxVarType) then
- raise EVariantError.CreateFmt(SVarTypeOutOfRangeWithPrefix, ['$', RequestedVarType]);
- index:=RequestedVarType-CMinVarType;
- if index>=L then
- SetLength(customvarianttypes,L+1);
- if Assigned(customvarianttypes[index]) then
- begin
- if customvarianttypes[index]=InvalidCustomVariantType then
- raise EVariantError.CreateFmt(SVarTypeNotUsableWithPrefix, ['$', RequestedVarType])
- else
- raise EVariantError.CreateFmt(SVarTypeAlreadyUsedWithPrefix,
- ['$', RequestedVarType, customvarianttypes[index].ClassName]);
- end;
- customvarianttypes[index]:=obj;
- obj.FVarType:=RequestedVarType;
- finally
- LeaveCriticalSection(customvarianttypelock);
- end;
- end;
- constructor TCustomVariantType.Create;
- begin
- RegisterCustomVariantType(Self,0,True);
- end;
- constructor TCustomVariantType.Create(RequestedVarType: TVarType);
- begin
- RegisterCustomVariantType(Self,RequestedVarType,False);
- 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;
- begin
- result:=False;
- 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
- RaiseInvalidOp;
- end;
- procedure TCustomVariantType.UnaryOp(var Right: TVarData; const Operation: TVarOp);
- begin
- RaiseInvalidOp;
- 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
- ---------------------------------------------------------------------}
- procedure TInvokeableVariantType.DispInvoke(Dest: PVarData; const Source: TVarData;
- CallDesc: PCallDesc; Params: Pointer);
- var
- method_name: ansistring;
- arg_count: byte;
- args: TVarDataArray;
- arg_idx: byte;
- arg_type: byte;
- arg_byref, has_result: boolean;
- arg_ptr: pointer;
- arg_data: PVarData;
- dummy_data: TVarData;
- const
- argtype_mask = $7F;
- argref_mask = $80;
- begin
- arg_count := CallDesc^.ArgCount;
- method_name := ansistring(pchar(@CallDesc^.ArgTypes[arg_count]));
- setLength(args, arg_count);
- if arg_count > 0 then
- begin
- arg_ptr := Params;
- for arg_idx := 0 to arg_count - 1 do
- begin
- arg_type := CallDesc^.ArgTypes[arg_idx] and argtype_mask;
- arg_byref := (CallDesc^.ArgTypes[arg_idx] and argref_mask) <> 0;
- arg_data := @args[arg_count - arg_idx - 1];
- case arg_type of
- varUStrArg: arg_data^.vType := varUString;
- varStrArg: arg_data^.vType := varString;
- else
- arg_data^.vType := arg_type
- end;
- if arg_byref then
- begin
- arg_data^.vType := arg_data^.vType or varByRef;
- arg_data^.vPointer := PPointer(arg_ptr)^;
- Inc(arg_ptr,sizeof(Pointer));
- end
- else
- case arg_type of
- varError:
- arg_data^.vError:=VAR_PARAMNOTFOUND;
- varVariant:
- begin
- arg_data^ := PVarData(PPointer(arg_ptr)^)^;
- Inc(arg_ptr,sizeof(Pointer));
- end;
- varDouble, varCurrency, varInt64, varQWord:
- begin
- arg_data^.vQWord := PQWord(arg_ptr)^; // 64bit on all platforms
- inc(arg_ptr,sizeof(qword))
- end
- else
- arg_data^.vAny := PPointer(arg_ptr)^; // 32 or 64bit
- inc(arg_ptr,sizeof(pointer))
- end;
- end;
- end;
- has_result := (Dest <> nil);
- if has_result then
- variant(Dest^) := Unassigned;
- case CallDesc^.CallType of
- 1: { DISPATCH_METHOD }
- if has_result then
- begin
- if arg_count = 0 then
- begin
- // no args -- try GetProperty first, then DoFunction
- if not (GetProperty(Dest^,Source,method_name) or
- DoFunction(Dest^,Source,method_name,args)) then
- RaiseDispError
- end
- else
- if not DoFunction(Dest^,Source,method_name,args) then
- RaiseDispError;
- end
- else
- begin
- // may be procedure?
- if not DoProcedure(Source,method_name,args) then
- // may be function?
- try
- variant(dummy_data) := Unassigned;
- if not DoFunction(dummy_data,Source,method_name,args) then
- RaiseDispError;
- finally
- VarDataClear(dummy_data)
- end;
- end;
- 2: { DISPATCH_PROPERTYGET -- currently never generated by compiler for Variant Dispatch }
- if has_result then
- begin
- // must be property...
- if not GetProperty(Dest^,Source,method_name) then
- // may be function?
- if not DoFunction(Dest^,Source,method_name,args) then
- RaiseDispError
- end
- else
- RaiseDispError;
- 4: { DISPATCH_PROPERTYPUT }
- if has_result or (arg_count<>1) or // must be no result and a single arg
- (not SetProperty(Source,method_name,args[0])) then
- RaiseDispError;
- else
- RaiseDispError;
- end;
- end;
- function TInvokeableVariantType.DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
- begin
- result := False;
- end;
- function TInvokeableVariantType.DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
- begin
- result := False
- end;
- function TInvokeableVariantType.GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean;
- begin
- result := False;
- end;
- function TInvokeableVariantType.SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean;
- begin
- result := False;
- end;
- { ---------------------------------------------------------------------
- TPublishableVariantType implementation
- ---------------------------------------------------------------------}
- 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:=PCodePointer(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:=PCodePointer(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);
- tkQWord:
- Result := QWord(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;
- I64: Int64;
- Qw: QWord;
- 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' }
- if (VarType(Value)=varOleStr) or
- (VarType(Value)=varString) or
- (VarType(Value)=varBoolean) then
- begin
- B:=Value;
- SetOrdProp(Instance, PropInfo, ord(B));
- end
- else
- begin
- I64:=Value;
- if (I64<TypeData^.MinValue) or (I64>TypeData^.MaxValue) then
- raise ERangeError.Create(SRangeError);
- SetOrdProp(Instance, PropInfo, I64);
- end;
- end;
- tkInteger, tkChar, tkWChar:
- begin
- I64:=Value;
- if (TypeData^.OrdType=otULong) then
- if (I64<LongWord(TypeData^.MinValue)) or (I64>LongWord(TypeData^.MaxValue)) then
- raise ERangeError.Create(SRangeError)
- else
- else
- if (I64<TypeData^.MinValue) or (I64>TypeData^.MaxValue) then
- raise ERangeError.Create(SRangeError);
- SetOrdProp(Instance, PropInfo, I64);
- end;
- tkEnumeration :
- begin
- if (VarType(Value)=varOleStr) or (VarType(Value)=varString) then
- begin
- S:=Value;
- SetEnumProp(Instance,PropInfo,S);
- end
- else
- begin
- I64:=Value;
- if (I64<TypeData^.MinValue) or (I64>TypeData^.MaxValue) then
- raise ERangeError.Create(SRangeError);
- SetOrdProp(Instance, PropInfo, I64);
- 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:
- begin
- I64:=Value;
- if (I64<TypeData^.MinInt64Value) or (I64>TypeData^.MaxInt64Value) then
- raise ERangeError.Create(SRangeError);
- SetInt64Prop(Instance, PropInfo, I64);
- end;
- tkQWord:
- begin
- Qw:=Value;
- if (Qw<TypeData^.MinQWordValue) or (Qw>TypeData^.MaxQWordValue) then
- raise ERangeError.Create(SRangeError);
- SetInt64Prop(Instance, PropInfo,Qw);
- end
- else
- raise EPropertyConvertError.CreateFmt('SetPropValue: Invalid Property Type %s',
- [PropInfo^.PropType^.Name]);
- end;
- end;
- end;
- var
- i : LongInt;
- Initialization
- InitCriticalSection(customvarianttypelock);
- // start with one-less value, so first increment yields CFirstUserType
- customvariantcurrtype:=CFirstUserType-1;
- 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.
|