Main.pas 167 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504
  1. unit Main;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2024 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Background form
  8. }
  9. interface
  10. {$I VERSION.INC}
  11. uses
  12. Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
  13. SetupForm, StdCtrls, Struct, DebugStruct, Int64Em, CmnFunc, CmnFunc2,
  14. SetupTypes, ScriptRunner, BidiUtils, RestartManager;
  15. type
  16. TMainForm = class(TSetupForm)
  17. procedure FormResize(Sender: TObject);
  18. procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  19. procedure FormPaint(Sender: TObject);
  20. procedure FormKeyDown(Sender: TObject; var Key: Word;
  21. Shift: TShiftState);
  22. private
  23. { Private declarations }
  24. IsMinimized, HideWizard: Boolean;
  25. function MainWindowHook(var Message: TMessage): Boolean;
  26. procedure UpdateWizardFormVisibility;
  27. procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
  28. procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  29. procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  30. procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
  31. public
  32. { Public declarations }
  33. CurStep: TSetupStep;
  34. constructor Create(AOwner: TComponent); override;
  35. destructor Destroy; override;
  36. procedure Finish(const FromPreparingPage: Boolean);
  37. procedure InitializeWizard;
  38. function Install: Boolean;
  39. procedure SetStep(const AStep: TSetupStep; const HandleExceptions: Boolean);
  40. class procedure ShowException(Sender: TObject; E: Exception);
  41. class procedure ShowExceptionMsg(const S: String);
  42. procedure ShowAboutBox;
  43. end;
  44. TEntryType = (seLanguage, seCustomMessage, sePermission, seType, seComponent,
  45. seTask, seDir, seFile, seFileLocation, seIcon, seIni, seRegistry,
  46. seInstallDelete, seUninstallDelete, seRun, seUninstallRun);
  47. TShellFolderID = (sfDesktop, sfStartMenu, sfPrograms, sfStartup, sfSendTo, //these have common and user versions
  48. sfFonts, sfAppData, sfDocs, sfTemplates, //
  49. sfFavorites, sfLocalAppData, sfUserProgramFiles, sfUserCommonFiles, sfUserSavedGames); //these only have user versions
  50. const
  51. EntryStrings: array[TEntryType] of Integer = (SetupLanguageEntryStrings,
  52. SetupCustomMessageEntryStrings, SetupPermissionEntryStrings,
  53. SetupTypeEntryStrings, SetupComponentEntryStrings, SetupTaskEntryStrings,
  54. SetupDirEntryStrings, SetupFileEntryStrings, SetupFileLocationEntryStrings,
  55. SetupIconEntryStrings, SetupIniEntryStrings, SetupRegistryEntryStrings,
  56. SetupDeleteEntryStrings, SetupDeleteEntryStrings, SetupRunEntryStrings,
  57. SetupRunEntryStrings);
  58. EntryAnsiStrings: array[TEntryType] of Integer = (SetupLanguageEntryAnsiStrings,
  59. SetupCustomMessageEntryAnsiStrings, SetupPermissionEntryAnsiStrings,
  60. SetupTypeEntryAnsiStrings, SetupComponentEntryAnsiStrings, SetupTaskEntryAnsiStrings,
  61. SetupDirEntryAnsiStrings, SetupFileEntryAnsiStrings, SetupFileLocationEntryAnsiStrings,
  62. SetupIconEntryAnsiStrings, SetupIniEntryAnsiStrings, SetupRegistryEntryAnsiStrings,
  63. SetupDeleteEntryAnsiStrings, SetupDeleteEntryAnsiStrings, SetupRunEntryAnsiStrings,
  64. SetupRunEntryAnsiStrings);
  65. { Exit codes that are assigned to the SetupExitCode variable.
  66. Note: SetupLdr also returns exit codes with the same numbers. }
  67. ecInitializationError = 1; { Setup failed to initialize. }
  68. ecCancelledBeforeInstall = 2; { User clicked Cancel before the actual
  69. installation started. }
  70. ecNextStepError = 3; { A fatal exception occurred while moving to
  71. the next step. }
  72. ecInstallationError = 4; { A fatal exception occurred during
  73. installation. }
  74. ecInstallationCancelled = 5; { User clicked Cancel during installation,
  75. or clicked Abort at an Abort-Retry-Ignore
  76. dialog. }
  77. ecKilledByDebugger = 6; { User killed the Setup process from within
  78. the debugger. }
  79. ecPrepareToInstallFailed = 7; { Stopped on Preparing to Install page;
  80. restart not needed. }
  81. ecPrepareToInstallFailedRestartNeeded = 8;
  82. { Stopped on Preparing to Install page;
  83. restart needed. }
  84. CodeRunnerNamingAttribute = 'Event';
  85. var
  86. MainForm: TMainForm;
  87. { Variables for command line parameters }
  88. SetupLdrMode: Boolean;
  89. SetupLdrOriginalFilename: String;
  90. SetupLdrOffset0, SetupLdrOffset1: Longint;
  91. SetupNotifyWndPresent: Boolean;
  92. SetupNotifyWnd: HWND;
  93. InitLang: String;
  94. InitDir, InitProgramGroup: String;
  95. InitLoadInf, InitSaveInf: String;
  96. InitNoIcons, InitSilent, InitVerySilent, InitNoRestart, InitCloseApplications,
  97. InitNoCloseApplications, InitForceCloseApplications, InitNoForceCloseApplications,
  98. InitLogCloseApplications, InitRestartApplications, InitNoRestartApplications,
  99. InitNoCancel: Boolean;
  100. InitSetupType: String;
  101. InitComponents, InitTasks: TStringList;
  102. InitComponentsSpecified: Boolean;
  103. InitDeselectAllTasks: Boolean;
  104. InitPassword: String;
  105. InitRestartExitCode: Integer;
  106. InitPrivilegesRequired: TSetupPrivilegesRequired;
  107. HasInitPrivilegesRequired: Boolean;
  108. InitSuppressMsgBoxes: Boolean;
  109. DetachedUninstMsgFile: Boolean;
  110. NewParamsForCode: TStringList;
  111. { Debugger }
  112. OriginalEntryIndexes: array[TEntryType] of TList;
  113. { 'Constants' }
  114. SourceDir, TempInstallDir, WinDir, WinSystemDir, WinSysWow64Dir, WinSysNativeDir, SystemDrive,
  115. ProgramFiles32Dir, CommonFiles32Dir, ProgramFiles64Dir, CommonFiles64Dir,
  116. CmdFilename, SysUserInfoName,
  117. SysUserInfoOrg, UninstallExeFilename: String;
  118. { Uninstall 'constants' }
  119. UninstallExpandedAppId, UninstallExpandedApp, UninstallExpandedGroup,
  120. UninstallExpandedGroupName, UninstallExpandedLanguage: String;
  121. UninstallSilent: Boolean;
  122. { Variables read in from the SETUP.0 file }
  123. SetupHeader: TSetupHeader;
  124. LangOptions: TSetupLanguageEntry;
  125. Entries: array[TEntryType] of TList;
  126. WizardImages: TList;
  127. WizardSmallImages: TList;
  128. CloseApplicationsFilterList: TStringList;
  129. { User options }
  130. ActiveLanguage: Integer = -1;
  131. ActiveLicenseText, ActiveInfoBeforeText, ActiveInfoAfterText: AnsiString;
  132. WizardUserInfoName, WizardUserInfoOrg, WizardUserInfoSerial, WizardDirValue, WizardGroupValue: String;
  133. WizardNoIcons, WizardPreparingYesRadio: Boolean;
  134. WizardSetupType: PSetupTypeEntry;
  135. WizardComponents, WizardDeselectedComponents, WizardTasks, WizardDeselectedTasks: TStringList;
  136. NeedToAbortInstall: Boolean;
  137. { Check/BeforeInstall/AfterInstall 'constants' }
  138. CheckOrInstallCurrentFilename, CheckOrInstallCurrentSourceFilename: String;
  139. { RestartManager API state.
  140. Note: the handle and key might change while running, see TWizardForm.QueryRestartManager. }
  141. RmSessionStarted, RmFoundApplications, RmDoRestart: Boolean;
  142. RmSessionHandle: DWORD;
  143. RmSessionKey: array[0..CCH_RM_SESSION_KEY] of WideChar;
  144. RmRegisteredFilesCount: Integer;
  145. { Other }
  146. ShowLanguageDialog, MatchedLangParameter: Boolean;
  147. InstallMode: (imNormal, imSilent, imVerySilent);
  148. HasIcons, IsWin64, Is64BitInstallMode, IsAdmin, IsPowerUserOrAdmin, IsAdminInstallMode,
  149. NeedPassword, NeedSerial, NeedsRestart, RestartSystem,
  150. IsUninstaller, AllowUninstallerShutdown, AcceptedQueryEndSessionInProgress: Boolean;
  151. InstallDefaultDisableFsRedir, ScriptFuncDisableFsRedir: Boolean;
  152. InstallDefaultRegView: TRegView = rvDefault;
  153. HasCustomType, HasComponents, HasTasks: Boolean;
  154. ProcessorArchitecture: TSetupProcessorArchitecture = paUnknown;
  155. WindowsVersion: Cardinal;
  156. NTServicePackLevel: Word;
  157. WindowsProductType: Byte;
  158. WindowsSuiteMask: Word;
  159. MinimumSpace: Integer64;
  160. DeleteFilesAfterInstallList, DeleteDirsAfterInstallList: TStringList;
  161. ExpandedAppName, ExpandedAppVerName, ExpandedAppCopyright, ExpandedAppMutex: String;
  162. DisableCodeConsts: Integer;
  163. SetupExitCode: Integer;
  164. CreatedIcon: Boolean;
  165. RestartInitiatedByThisProcess, DownloadTemporaryFileProcessMessages: Boolean;
  166. TaskbarButtonHidden: Boolean;
  167. InstallModeRootKey: HKEY;
  168. CodeRunner: TScriptRunner;
  169. procedure CodeRunnerOnLog(const S: String);
  170. procedure CodeRunnerOnLogFmt(const S: String; const Args: array of const);
  171. function CodeRunnerOnDebug(const Position: LongInt;
  172. var ContinueStepOver: Boolean): Boolean;
  173. function CodeRunnerOnDebugIntermediate(const Position: LongInt;
  174. var ContinueStepOver: Boolean): Boolean;
  175. procedure CodeRunnerOnDllImport(var DllName: String; var ForceDelayLoad: Boolean);
  176. procedure CodeRunnerOnException(const Exception: AnsiString; const Position: LongInt);
  177. procedure CreateTempInstallDir;
  178. procedure DebugNotifyEntry(EntryType: TEntryType; Number: Integer);
  179. procedure DeinitSetup(const AllowCustomSetupExitCode: Boolean);
  180. function ExitSetupMsgBox: Boolean;
  181. function ExpandConst(const S: String): String;
  182. function ExpandConstEx(const S: String; const CustomConsts: array of String): String;
  183. function ExpandConstEx2(const S: String; const CustomConsts: array of String;
  184. const DoExpandIndividualConst: Boolean): String;
  185. function ExpandConstIfPrefixed(const S: String): String;
  186. function GetCustomMessageValue(const AName: String; var AValue: String): Boolean;
  187. function GetShellFolder(const Common: Boolean; const ID: TShellFolderID): String;
  188. function GetShellFolderByCSIDL(Folder: Integer; const Create: Boolean): String;
  189. function GetUninstallRegKeyBaseName(const ExpandedAppId: String): String;
  190. function GetUninstallRegSubkeyName(const UninstallRegKeyBaseName: String): String;
  191. function GetPreviousData(const ExpandedAppID, ValueName, DefaultValueData: String): String;
  192. function GetPreviousLanguage(const ExpandedAppID: String): Integer;
  193. procedure InitializeAdminInstallMode(const AAdminInstallMode: Boolean);
  194. procedure Initialize64BitInstallMode(const A64BitInstallMode: Boolean);
  195. procedure Log64BitInstallMode;
  196. procedure InitializeCommonVars;
  197. procedure InitializeSetup;
  198. procedure InitMainNonSHFolderConsts;
  199. function InstallOnThisVersion(const MinVersion: TSetupVersionData;
  200. const OnlyBelowVersion: TSetupVersionData): TInstallOnThisVersionResult;
  201. function IsRecurseableDirectory(const FindData: TWin32FindData): Boolean;
  202. procedure LoadSHFolderDLL;
  203. function LoggedAppMessageBox(const Text, Caption: PChar; const Flags: Longint;
  204. const Suppressible: Boolean; const Default: Integer): Integer;
  205. function LoggedMsgBox(const Text, Caption: String; const Typ: TMsgBoxType;
  206. const Buttons: Cardinal; const Suppressible: Boolean; const Default: Integer): Integer;
  207. function LoggedTaskDialogMsgBox(const Icon, Instruction, Text, Caption: String;
  208. const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String;
  209. const ShieldButton: Integer; const Suppressible: Boolean; const Default: Integer;
  210. const VerificationText: String = ''; const pfVerificationFlagChecked: PBOOL = nil): Integer;
  211. procedure LogWindowsVersion;
  212. procedure NotifyAfterInstallEntry(const AfterInstall: String);
  213. procedure NotifyAfterInstallFileEntry(const FileEntry: PSetupFileEntry);
  214. procedure NotifyBeforeInstallEntry(const BeforeInstall: String);
  215. procedure NotifyBeforeInstallFileEntry(const FileEntry: PSetupFileEntry);
  216. function PreviousInstallCompleted(const WizardComponents, WizardTasks: TStringList): Boolean;
  217. function CodeRegisterExtraCloseApplicationsResource(const DisableFsRedir: Boolean; const AFilename: String): Boolean;
  218. procedure RegisterResourcesWithRestartManager(const WizardComponents, WizardTasks: TStringList);
  219. procedure RemoveTempInstallDir;
  220. procedure SaveResourceToTempFile(const ResName, Filename: String);
  221. procedure SetActiveLanguage(const I: Integer);
  222. procedure SetTaskbarButtonVisibility(const AVisible: Boolean);
  223. procedure ShellExecuteAsOriginalUser(hWnd: HWND; Operation, FileName, Parameters, Directory: LPWSTR; ShowCmd: Integer); stdcall;
  224. function ShouldDisableFsRedirForFileEntry(const FileEntry: PSetupFileEntry): Boolean;
  225. function ShouldDisableFsRedirForRunEntry(const RunEntry: PSetupRunEntry): Boolean;
  226. function EvalDirectiveCheck(const Expression: String): Boolean;
  227. function ShouldProcessEntry(const WizardComponents, WizardTasks: TStringList;
  228. const Components, Tasks, Languages, Check: String): Boolean;
  229. function ShouldProcessFileEntry(const WizardComponents, WizardTasks: TStringList;
  230. const FileEntry: PSetupFileEntry; const IgnoreCheck: Boolean): Boolean;
  231. function ShouldProcessIconEntry(const WizardComponents, WizardTasks: TStringList;
  232. const WizardNoIcons: Boolean; const IconEntry: PSetupIconEntry): Boolean;
  233. function ShouldProcessRunEntry(const WizardComponents, WizardTasks: TStringList;
  234. const RunEntry: PSetupRunEntry): Boolean;
  235. function TestPassword(const Password: String): Boolean;
  236. procedure UnloadSHFolderDLL;
  237. function WindowsVersionAtLeast(const AMajor, AMinor: Byte): Boolean;
  238. implementation
  239. uses
  240. ShellAPI, ShlObj,
  241. Msgs, MsgIDs, Install, InstFunc, InstFnc2, RedirFunc, PathFunc,
  242. Compress, CompressZlib, bzlib, LZMADecomp, ArcFour, SetupEnt, SelLangForm,
  243. Wizard, DebugClient, VerInfo, Extract, FileClass, Logging, MD5, SHA1, ActiveX,
  244. SimpleExpression, Helper, SpawnClient, SpawnServer, DotNet, BitmapImage,
  245. TaskDialog, RegStr;
  246. {$R *.DFM}
  247. var
  248. ShellFolders: array[Boolean, TShellFolderID] of String;
  249. ShellFoldersRead: array[Boolean, TShellFolderID] of Boolean;
  250. SHFolderDLLHandle: HMODULE;
  251. SHGetFolderPathFunc: function(hwndOwner: HWND; nFolder: Integer;
  252. hToken: THandle; dwFlags: DWORD; pszPath: PChar): HRESULT; stdcall;
  253. SHGetKnownFolderPathFunc: function(const rfid: TGUID; dwFlags: DWORD; hToken: THandle;
  254. var ppszPath: PWideChar): HRESULT; stdcall;
  255. DecompressorDLLHandle: HMODULE;
  256. DecryptDLLHandle: HMODULE;
  257. type
  258. TDummyClass = class
  259. public
  260. class function ExpandCheckOrInstallConstant(Sender: TSimpleExpression;
  261. const Constant: String): String;
  262. class function EvalInstallIdentifier(Sender: TSimpleExpression;
  263. const Name: String; const Parameters: array of const): Boolean;
  264. class function EvalComponentOrTaskIdentifier(Sender: TSimpleExpression;
  265. const Name: String; const Parameters: array of const): Boolean;
  266. class function EvalLanguageIdentifier(Sender: TSimpleExpression;
  267. const Name: String; const Parameters: array of const): Boolean;
  268. class function EvalCheckIdentifier(Sender: TSimpleExpression;
  269. const Name: String; const Parameters: array of const): Boolean;
  270. end;
  271. { Misc. functions }
  272. function WindowsVersionAtLeast(const AMajor, AMinor: Byte): Boolean;
  273. begin
  274. Result := (WindowsVersion >= Cardinal((AMajor shl 24) or (AMinor shl 16)));
  275. end;
  276. function GetUninstallRegKeyBaseName(const ExpandedAppId: String): String;
  277. var
  278. UseAnsiCRC32: Boolean;
  279. S: AnsiString;
  280. I: Integer;
  281. begin
  282. { Set uninstall registry key base name }
  283. Result := ExpandedAppId;
  284. { Uninstall registry keys can only be up to 63 characters, otherwise Win95
  285. ignores them. Limit to 57 since Setup will add _isXXX to the end later. }
  286. if Length(Result) > 57 then begin
  287. { Only keep the first 48 characters, then add an tilde and the CRC
  288. of the original string (to make the trimmed string unique). The
  289. resulting string is 57 characters long. On Unicode, only do this if we
  290. can get a CRC32 compatible with ANSI versions, else there's no point
  291. in shortening since Unicode doesn't run on Win95. }
  292. UseAnsiCRC32 := True;
  293. for I := 1 to Length(Result) do begin
  294. if Ord(Result[I]) > 126 then begin
  295. UseAnsiCRC32 := False;
  296. Break;
  297. end;
  298. end;
  299. if UseAnsiCRC32 then begin
  300. S := AnsiString(Result);
  301. FmtStr(Result, '%.48s~%.8x', [Result, GetCRC32(S[1], Length(S)*SizeOf(S[1]))]);
  302. end;
  303. end;
  304. end;
  305. function GetUninstallRegSubkeyName(const UninstallRegKeyBaseName: String): String;
  306. begin
  307. Result := Format('%s\%s_is1', [REGSTR_PATH_UNINSTALL, UninstallRegKeyBaseName]);
  308. end;
  309. { Based on FindPreviousData in Wizard.pas }
  310. function GetPreviousData(const ExpandedAppID, ValueName, DefaultValueData: String): String;
  311. var
  312. H: HKEY;
  313. begin
  314. Result := DefaultValueData;
  315. if ExpandedAppId <> '' then begin
  316. if RegOpenKeyExView(InstallDefaultRegView, InstallModeRootKey,
  317. PChar(GetUninstallRegSubkeyName(GetUninstallRegKeyBaseName(ExpandedAppId))),
  318. 0, KEY_QUERY_VALUE, H) = ERROR_SUCCESS then begin
  319. try
  320. RegQueryStringValue (H, PChar(ValueName), Result);
  321. finally
  322. RegCloseKey (H);
  323. end;
  324. end;
  325. end;
  326. end;
  327. function GetPreviousLanguage(const ExpandedAppID: String): Integer;
  328. var
  329. PrevLang: String;
  330. I: Integer;
  331. begin
  332. { do not localize or change the following string }
  333. PrevLang := GetPreviousData(ExpandConst(SetupHeader.AppId), 'Inno Setup: Language', '');
  334. if PrevLang <> '' then begin
  335. for I := 0 to Entries[seLanguage].Count-1 do begin
  336. if CompareText(PrevLang, PSetupLanguageEntry(Entries[seLanguage][I]).Name) = 0 then begin
  337. Result := I;
  338. Exit;
  339. end;
  340. end;
  341. end;
  342. Result := -1;
  343. end;
  344. function TestPassword(const Password: String): Boolean;
  345. var
  346. Context: TSHA1Context;
  347. Hash: TSHA1Digest;
  348. begin
  349. SHA1Init(Context);
  350. SHA1Update(Context, PAnsiChar('PasswordCheckHash')^, Length('PasswordCheckHash'));
  351. SHA1Update(Context, SetupHeader.PasswordSalt, SizeOf(SetupHeader.PasswordSalt));
  352. SHA1Update(Context, Pointer(Password)^, Length(Password)*SizeOf(Password[1]));
  353. Hash := SHA1Final(Context);
  354. Result := SHA1DigestsEqual(Hash, SetupHeader.PasswordHash);
  355. end;
  356. class function TDummyClass.ExpandCheckOrInstallConstant(Sender: TSimpleExpression;
  357. const Constant: String): String;
  358. begin
  359. Result := ExpandConst(Constant);
  360. end;
  361. class function TDummyClass.EvalInstallIdentifier(Sender: TSimpleExpression;
  362. const Name: String; const Parameters: array of const): Boolean;
  363. begin
  364. CodeRunner.RunProcedure(AnsiString(Name), Parameters, True);
  365. Result := True; { Result doesn't matter }
  366. end;
  367. procedure NotifyInstallEntry(const Install: String);
  368. procedure EvalInstall(const Expression: String);
  369. var
  370. SimpleExpression: TSimpleExpression;
  371. begin
  372. try
  373. SimpleExpression := TSimpleExpression.Create;
  374. try
  375. SimpleExpression.Expression := Expression;
  376. SimpleExpression.OnEvalIdentifier := TDummyClass.EvalInstallIdentifier;
  377. SimpleExpression.OnExpandConstant := TDummyClass.ExpandCheckOrInstallConstant;
  378. SimpleExpression.ParametersAllowed := True;
  379. SimpleExpression.SingleIdentifierMode := True;
  380. SimpleExpression.Eval;
  381. finally
  382. SimpleExpression.Free;
  383. end;
  384. except
  385. InternalError(Format('Expression error ''%s''', [GetExceptMessage]));
  386. end;
  387. end;
  388. begin
  389. if Install <> '' then begin
  390. try
  391. if CodeRunner = nil then
  392. InternalError('"BeforeInstall" or "AfterInstall" parameter with no CodeRunner');
  393. EvalInstall(Install);
  394. except
  395. { Don't allow exceptions raised by Before/AfterInstall functions to be propagated out }
  396. Application.HandleException(nil);
  397. end;
  398. end;
  399. end;
  400. procedure NotifyBeforeInstallEntry(const BeforeInstall: String);
  401. begin
  402. NotifyInstallEntry(BeforeInstall);
  403. end;
  404. procedure NotifyBeforeInstallFileEntry(const FileEntry: PSetupFileEntry);
  405. begin
  406. CheckOrInstallCurrentFilename := FileEntry.DestName;
  407. CheckOrInstallCurrentSourceFilename := FileEntry.SourceFilename;
  408. NotifyInstallEntry(FileEntry.BeforeInstall);
  409. CheckOrInstallCurrentFilename := '';
  410. CheckOrInstallCurrentSourceFilename := '';
  411. end;
  412. procedure NotifyAfterInstallEntry(const AfterInstall: String);
  413. begin
  414. NotifyInstallEntry(AfterInstall);
  415. end;
  416. procedure NotifyAfterInstallFileEntry(const FileEntry: PSetupFileEntry);
  417. begin
  418. CheckOrInstallCurrentFilename := FileEntry.DestName;
  419. CheckOrInstallCurrentSourceFilename := FileEntry.SourceFilename;
  420. NotifyInstallEntry(FileEntry.AfterInstall);
  421. CheckOrInstallCurrentFilename := '';
  422. CheckOrInstallCurrentSourceFilename := '';
  423. end;
  424. class function TDummyClass.EvalComponentOrTaskIdentifier(Sender: TSimpleExpression;
  425. const Name: String; const Parameters: array of const): Boolean;
  426. var
  427. WizardItems: TStringList;
  428. begin
  429. WizardItems := TStringList(Sender.Tag);
  430. Result := ListContains(WizardItems, Name);
  431. end;
  432. class function TDummyClass.EvalLanguageIdentifier(Sender: TSimpleExpression;
  433. const Name: String; const Parameters: array of const): Boolean;
  434. begin
  435. Result := CompareText(PSetupLanguageEntry(Entries[seLanguage][ActiveLanguage]).Name, Name) = 0;
  436. end;
  437. class function TDummyClass.EvalCheckIdentifier(Sender: TSimpleExpression;
  438. const Name: String; const Parameters: array of const): Boolean;
  439. begin
  440. Result := CodeRunner.RunBooleanFunction(AnsiString(Name), Parameters, True, False);
  441. end;
  442. function EvalCheck(const Expression: String): Boolean;
  443. var
  444. SimpleExpression: TSimpleExpression;
  445. begin
  446. try
  447. SimpleExpression := TSimpleExpression.Create;
  448. try
  449. SimpleExpression.Lazy := True;
  450. SimpleExpression.Expression := Expression;
  451. SimpleExpression.OnEvalIdentifier := TDummyClass.EvalCheckIdentifier;
  452. SimpleExpression.OnExpandConstant := TDummyClass.ExpandCheckOrInstallConstant;
  453. SimpleExpression.ParametersAllowed := True;
  454. SimpleExpression.SilentOrAllowed := False;
  455. SimpleExpression.SingleIdentifierMode := False;
  456. Result := SimpleExpression.Eval;
  457. finally
  458. SimpleExpression.Free;
  459. end;
  460. except
  461. InternalError(Format('Expression error ''%s''', [GetExceptMessage]));
  462. Result := False;
  463. end;
  464. end;
  465. function EvalDirectiveCheck(const Expression: String): Boolean;
  466. begin
  467. if not TryStrToBoolean(Expression, Result) then
  468. Result := EvalCheck(Expression);
  469. end;
  470. function ShouldProcessEntry(const WizardComponents, WizardTasks: TStringList;
  471. const Components, Tasks, Languages, Check: String): Boolean;
  472. function EvalExpression(const Expression: String;
  473. OnEvalIdentifier: TSimpleExpressionOnEvalIdentifier; Tag: LongInt): Boolean;
  474. var
  475. SimpleExpression: TSimpleExpression;
  476. begin
  477. try
  478. SimpleExpression := TSimpleExpression.Create;
  479. try
  480. SimpleExpression.Lazy := True;
  481. SimpleExpression.Expression := Expression;
  482. SimpleExpression.OnEvalIdentifier := OnEvalIdentifier;
  483. SimpleExpression.ParametersAllowed := False;
  484. SimpleExpression.SilentOrAllowed := True;
  485. SimpleExpression.SingleIdentifierMode := False;
  486. SimpleExpression.Tag := Tag;
  487. Result := SimpleExpression.Eval;
  488. finally
  489. SimpleExpression.Free;
  490. end;
  491. except
  492. InternalError(Format('Expression error ''%s''', [GetExceptMessage]));
  493. Result := False;
  494. end;
  495. end;
  496. var
  497. ProcessComponent, ProcessTask, ProcessLanguage: Boolean;
  498. begin
  499. if (Components <> '') or (Tasks <> '') or (Languages <> '') or (Check <> '') then begin
  500. if (Components <> '') and (WizardComponents <> nil) then
  501. ProcessComponent := EvalExpression(Components, TDummyClass.EvalComponentOrTaskIdentifier, LongInt(WizardComponents))
  502. else
  503. ProcessComponent := True;
  504. if (Tasks <> '') and (WizardTasks <> nil) then
  505. ProcessTask := EvalExpression(Tasks, TDummyClass.EvalComponentOrTaskIdentifier, LongInt(WizardTasks))
  506. else
  507. ProcessTask := True;
  508. if Languages <> '' then
  509. ProcessLanguage := EvalExpression(Languages, TDummyClass.EvalLanguageIdentifier, 0)
  510. else
  511. ProcessLanguage := True;
  512. Result := ProcessComponent and ProcessTask and ProcessLanguage;
  513. if Result and (Check <> '') then begin
  514. try
  515. if CodeRunner = nil then
  516. InternalError('"Check" parameter with no CodeRunner');
  517. Result := EvalCheck(Check);
  518. except
  519. { Don't allow exceptions raised by Check functions to be propagated out }
  520. Application.HandleException(nil);
  521. Result := False;
  522. end;
  523. end;
  524. end else
  525. Result := True;
  526. end;
  527. function ShouldProcessFileEntry(const WizardComponents, WizardTasks: TStringList;
  528. const FileEntry: PSetupFileEntry; const IgnoreCheck: Boolean): Boolean;
  529. begin
  530. if foDontCopy in FileEntry.Options then begin
  531. Result := False;
  532. Exit;
  533. end;
  534. CheckOrInstallCurrentFilename := FileEntry.DestName;
  535. CheckOrInstallCurrentSourceFilename := FileEntry.SourceFilename;
  536. if IgnoreCheck then
  537. Result := ShouldProcessEntry(WizardComponents, WizardTasks, FileEntry.Components, FileEntry.Tasks, FileEntry.Languages, '')
  538. else
  539. Result := ShouldProcessEntry(WizardComponents, WizardTasks, FileEntry.Components, FileEntry.Tasks, FileEntry.Languages, FileEntry.Check);
  540. CheckOrInstallCurrentFilename := '';
  541. CheckOrInstallCurrentSourceFilename := '';
  542. end;
  543. function ShouldProcessRunEntry(const WizardComponents, WizardTasks: TStringList;
  544. const RunEntry: PSetupRunEntry): Boolean;
  545. begin
  546. if (InstallMode <> imNormal) and (roSkipIfSilent in RunEntry.Options) then
  547. Result := False
  548. else if (InstallMode = imNormal) and (roSkipIfNotSilent in RunEntry.Options) then
  549. Result := False
  550. else
  551. Result := ShouldProcessEntry(WizardComponents, WizardTasks, RunEntry.Components, RunEntry.Tasks, RunEntry.Languages, RunEntry.Check);
  552. end;
  553. function ShouldProcessIconEntry(const WizardComponents, WizardTasks: TStringList;
  554. const WizardNoIcons: Boolean; const IconEntry: PSetupIconEntry): Boolean;
  555. begin
  556. if WizardNoIcons and (IconEntry.Tasks = '') and
  557. (Copy(IconEntry.IconName, 1, 8) = '{group}\') then
  558. Result := False
  559. else
  560. Result := ShouldProcessEntry(WizardComponents, WizardTasks, IconEntry.Components, IconEntry.Tasks, IconEntry.Languages, IconEntry.Check);
  561. end;
  562. function ShouldDisableFsRedirForFileEntry(const FileEntry: PSetupFileEntry): Boolean;
  563. begin
  564. Result := InstallDefaultDisableFsRedir;
  565. if fo32Bit in FileEntry.Options then
  566. Result := False;
  567. if fo64Bit in FileEntry.Options then begin
  568. if not IsWin64 then
  569. InternalError('Cannot install files to 64-bit locations on this version of Windows');
  570. Result := True;
  571. end;
  572. end;
  573. function SlashesToBackslashes(const S: String): String;
  574. var
  575. I: Integer;
  576. begin
  577. Result := S;
  578. for I := 1 to Length(Result) do
  579. if Result[I] = '/' then
  580. Result[I] := '\';
  581. end;
  582. procedure LoadInf(const FileName: String; var WantToSuppressMsgBoxes: Boolean);
  583. const
  584. Section = 'Setup';
  585. var
  586. S: String;
  587. begin
  588. //saved infs
  589. InitLang := GetIniString(Section, 'Lang', InitLang, FileName);
  590. InitDir := GetIniString(Section, 'Dir', InitDir, FileName);
  591. InitProgramGroup := GetIniString(Section, 'Group', InitProgramGroup, FileName);
  592. InitNoIcons := GetIniBool(Section, 'NoIcons', InitNoIcons, FileName);
  593. InitSetupType := GetIniString(Section, 'SetupType', InitSetupType, FileName);
  594. S := GetIniString(Section, 'Components', '$', FileName);
  595. if S <> '$' then begin
  596. InitComponentsSpecified := True;
  597. SetStringsFromCommaString(InitComponents, SlashesToBackslashes(S));
  598. end;
  599. S := GetIniString(Section, 'Tasks', '$', FileName);
  600. if S <> '$' then begin
  601. InitDeselectAllTasks := True;
  602. SetStringsFromCommaString(InitTasks, SlashesToBackslashes(S));
  603. end;
  604. //non saved infs (=non user settable)
  605. InitSilent := GetIniBool(Section, 'Silent', InitSilent, FileName);
  606. InitVerySilent := GetIniBool(Section, 'VerySilent', InitVerySilent, FileName);
  607. InitNoRestart := GetIniBool(Section, 'NoRestart', InitNoRestart, FileName);
  608. InitCloseApplications := GetIniBool(Section, 'CloseApplications', InitCloseApplications, FileName);
  609. InitNoCloseApplications := GetIniBool(Section, 'NoCloseApplications', InitNoCloseApplications, FileName);
  610. InitForceCloseApplications := GetIniBool(Section, 'ForceCloseApplications', InitForceCloseApplications, FileName);
  611. InitNoForceCloseApplications := GetIniBool(Section, 'NoForceCloseApplications', InitNoForceCloseApplications, FileName);
  612. InitLogCloseApplications := GetIniBool(Section, 'LogCloseApplications', InitLogCloseApplications, FileName);
  613. InitRestartApplications := GetIniBool(Section, 'RestartApplications', InitRestartApplications, FileName);
  614. InitNoRestartApplications := GetIniBool(Section, 'NoRestartApplications', InitNoRestartApplications, FileName);
  615. InitNoCancel := GetIniBool(Section, 'NoCancel', InitNoCancel, FileName);
  616. InitPassword := GetIniString(Section, 'Password', InitPassword, FileName);
  617. InitRestartExitCode := GetIniInt(Section, 'RestartExitCode', InitRestartExitCode, 0, 0, FileName);
  618. WantToSuppressMsgBoxes := GetIniBool(Section, 'SuppressMsgBoxes', WantToSuppressMsgBoxes, FileName);
  619. InitSaveInf := GetIniString(Section, 'SaveInf', InitSaveInf, FileName);
  620. end;
  621. procedure SaveInf(const FileName: String);
  622. const
  623. Section = 'Setup';
  624. begin
  625. SetIniString(Section, 'Lang',
  626. PSetupLanguageEntry(Entries[seLanguage][ActiveLanguage]).Name, FileName);
  627. SetIniString(Section, 'Dir', WizardDirValue, FileName);
  628. SetIniString(Section, 'Group', WizardGroupValue, FileName);
  629. SetIniBool(Section, 'NoIcons', WizardNoIcons, FileName);
  630. if WizardSetupType <> nil then begin
  631. SetIniString(Section, 'SetupType', WizardSetupType.Name, FileName);
  632. SetIniString(Section, 'Components', StringsToCommaString(WizardComponents), FileName);
  633. end
  634. else begin
  635. DeleteIniEntry(Section, 'SetupType', FileName);
  636. DeleteIniEntry(Section, 'Components', FileName);
  637. end;
  638. SetIniString(Section, 'Tasks', StringsToCommaString(WizardTasks), FileName);
  639. end;
  640. function GetCustomMessageValue(const AName: String; var AValue: String): Boolean;
  641. var
  642. I: Integer;
  643. begin
  644. Result := False;
  645. for I := 0 to Entries[seCustomMessage].Count-1 do begin
  646. with PSetupCustomMessageEntry(Entries[seCustomMessage][I])^ do begin
  647. if (CompareText(Name, AName) = 0) and
  648. ((LangIndex = -1) or (LangIndex = ActiveLanguage)) then begin
  649. Result := True;
  650. AValue := Value;
  651. { don't stop looping, last item counts }
  652. end;
  653. end;
  654. end;
  655. end;
  656. function ExpandIndividualConst(Cnst: String;
  657. const CustomConsts: array of String): String;
  658. { Cnst must be the name of a single constant, without the braces.
  659. For example: app
  660. IsPath is set to True if the result is a path which needs special trailing-
  661. backslash handling. }
  662. procedure HandleAutoConstants(var Cnst: String);
  663. const
  664. Actual: array [Boolean] of String = ('user', 'common');
  665. begin
  666. if Copy(Cnst, 1, 4) = 'auto' then begin
  667. StringChange(Cnst, 'auto', Actual[IsAdminInstallMode]);
  668. if (Cnst = 'userpf32') or (Cnst = 'userpf64') or
  669. (Cnst = 'usercf32') or (Cnst = 'usercf64') then
  670. Delete(Cnst, Length(Cnst)-1, 2);
  671. end;
  672. end;
  673. procedure NoUninstallConstError(const C: String);
  674. begin
  675. InternalError(Format('Cannot evaluate "%s" constant during Uninstall', [C]));
  676. end;
  677. function ExpandEnvConst(C: String): String;
  678. var
  679. I: Integer;
  680. VarName, Default: String;
  681. begin
  682. Delete(C, 1, 1);
  683. I := ConstPos('|', C); { check for 'default' value }
  684. if I = 0 then
  685. I := Length(C)+1;
  686. VarName := Copy(C, 1, I-1);
  687. Default := Copy(C, I+1, Maxint);
  688. Result := '';
  689. if ConvertConstPercentStr(VarName) and ConvertConstPercentStr(Default) then begin
  690. Result := GetEnv(ExpandConstEx(VarName, CustomConsts));
  691. if Result = '' then
  692. Result := ExpandConstEx(Default, CustomConsts);
  693. end;
  694. end;
  695. function ExpandRegConst(C: String): String;
  696. { Expands a registry-value constant in the form:
  697. reg:HKxx\SubkeyName,ValueName|DefaultValue }
  698. type
  699. TKeyNameConst = packed record
  700. KeyName: String;
  701. KeyConst: HKEY;
  702. end;
  703. const
  704. KeyNameConsts: array[0..5] of TKeyNameConst = (
  705. (KeyName: 'HKA'; KeyConst: HKEY_AUTO),
  706. (KeyName: 'HKCR'; KeyConst: HKEY_CLASSES_ROOT),
  707. (KeyName: 'HKCU'; KeyConst: HKEY_CURRENT_USER),
  708. (KeyName: 'HKLM'; KeyConst: HKEY_LOCAL_MACHINE),
  709. (KeyName: 'HKU'; KeyConst: HKEY_USERS),
  710. (KeyName: 'HKCC'; KeyConst: HKEY_CURRENT_CONFIG));
  711. var
  712. Z, Subkey, Value, Default: String;
  713. I, J, L: Integer;
  714. RegView: TRegView;
  715. RootKey: HKEY;
  716. K: HKEY;
  717. begin
  718. Delete(C, 1, 4); { skip past 'reg:' }
  719. I := ConstPos('\', C);
  720. if I <> 0 then begin
  721. Z := Copy(C, 1, I-1);
  722. if Z <> '' then begin
  723. RegView := InstallDefaultRegView;
  724. L := Length(Z);
  725. if L >= 2 then begin
  726. { Check for '32' or '64' suffix }
  727. if (Z[L-1] = '3') and (Z[L] = '2') then begin
  728. RegView := rv32Bit;
  729. SetLength(Z, L-2);
  730. end
  731. else if (Z[L-1] = '6') and (Z[L] = '4') then begin
  732. if not IsWin64 then
  733. InternalError('Cannot access a 64-bit key in a "reg" constant on this version of Windows');
  734. RegView := rv64Bit;
  735. SetLength(Z, L-2);
  736. end;
  737. end;
  738. RootKey := 0;
  739. for J := Low(KeyNameConsts) to High(KeyNameConsts) do
  740. if CompareText(KeyNameConsts[J].KeyName, Z) = 0 then begin
  741. RootKey := KeyNameConsts[J].KeyConst;
  742. if RootKey = HKEY_AUTO then
  743. RootKey := InstallModeRootKey;
  744. Break;
  745. end;
  746. if RootKey <> 0 then begin
  747. Z := Copy(C, I+1, Maxint);
  748. I := ConstPos('|', Z); { check for a 'default' data }
  749. if I = 0 then
  750. I := Length(Z)+1;
  751. Default := Copy(Z, I+1, Maxint);
  752. SetLength(Z, I-1);
  753. I := ConstPos(',', Z); { comma separates subkey and value }
  754. if I <> 0 then begin
  755. Subkey := Copy(Z, 1, I-1);
  756. Value := Copy(Z, I+1, Maxint);
  757. if ConvertConstPercentStr(Subkey) and ConvertConstPercentStr(Value) and
  758. ConvertConstPercentStr(Default) then begin
  759. Result := ExpandConstEx(Default, CustomConsts);
  760. if RegOpenKeyExView(RegView, RootKey,
  761. PChar(ExpandConstEx(Subkey, CustomConsts)),
  762. 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  763. RegQueryStringValue(K, PChar(ExpandConstEx(Value, CustomConsts)),
  764. Result);
  765. RegCloseKey(K);
  766. end;
  767. Exit;
  768. end;
  769. end;
  770. end;
  771. end;
  772. end;
  773. { it will only reach here if there was a parsing error }
  774. InternalError('Failed to parse "reg" constant');
  775. end;
  776. function ExpandIniConst(C: String): String;
  777. { Expands an INI-value constant in the form:
  778. filename,section,key|defaultvalue }
  779. var
  780. Z, Filename, Section, Key, Default: String;
  781. I: Integer;
  782. begin
  783. Delete(C, 1, 4); { skip past 'ini:' }
  784. I := ConstPos(',', C);
  785. if I <> 0 then begin
  786. Z := Copy(C, 1, I-1);
  787. if Z <> '' then begin
  788. Filename := Z;
  789. Z := Copy(C, I+1, Maxint);
  790. I := ConstPos('|', Z); { check for a 'default' data }
  791. if I = 0 then
  792. I := Length(Z)+1;
  793. Default := Copy(Z, I+1, Maxint);
  794. SetLength(Z, I-1);
  795. I := ConstPos(',', Z); { comma separates section and key }
  796. if I <> 0 then begin
  797. Section := Copy(Z, 1, I-1);
  798. Key := Copy(Z, I+1, Maxint);
  799. if ConvertConstPercentStr(Filename) and ConvertConstPercentStr(Section) and ConvertConstPercentStr(Key) and
  800. ConvertConstPercentStr(Default) then begin
  801. Filename := ExpandConstEx(Filename, CustomConsts);
  802. Section := ExpandConstEx(Section, CustomConsts);
  803. Key := ExpandConstEx(Key, CustomConsts);
  804. Default := ExpandConstEx(Default, CustomConsts);
  805. Result := GetIniString(Section, Key, Default, Filename);
  806. Exit;
  807. end;
  808. end;
  809. end;
  810. end;
  811. { it will only reach here if there was a parsing error }
  812. InternalError('Failed to parse "ini" constant');
  813. end;
  814. function ExpandParamConst(C: String): String;
  815. { Expands an commandline-parameter-value constant in the form:
  816. parametername|defaultvalue }
  817. function GetParamString(const Param, Default: String): String;
  818. var
  819. I, PCount: Integer;
  820. Z: String;
  821. begin
  822. PCount := NewParamCount();
  823. for I := 1 to PCount do begin
  824. Z := NewParamStr(I);
  825. if StrLIComp(PChar(Z), PChar('/'+Param+'='), Length(Param)+2) = 0 then begin
  826. Delete(Z, 1, Length(Param)+2);
  827. Result := Z;
  828. Exit;
  829. end;
  830. end;
  831. Result := Default;
  832. end;
  833. var
  834. Z, Param, Default: String;
  835. I: Integer;
  836. begin
  837. Delete(C, 1, 6); { skip past 'param:' }
  838. Z := C;
  839. I := ConstPos('|', Z); { check for a 'default' data }
  840. if I = 0 then
  841. I := Length(Z)+1;
  842. Default := Copy(Z, I+1, Maxint);
  843. SetLength(Z, I-1);
  844. Param := Z;
  845. if ConvertConstPercentStr(Param) and ConvertConstPercentStr(Default) then begin
  846. Param := ExpandConstEx(Param, CustomConsts);
  847. Default := ExpandConstEx(Default, CustomConsts);
  848. Result := GetParamString(Param, Default);
  849. Exit;
  850. end;
  851. { it will only reach here if there was a parsing error }
  852. InternalError('Failed to parse "param" constant');
  853. end;
  854. function ExpandCodeConst(C: String): String;
  855. { Expands an Pascal-script-value constant in the form:
  856. parametername|defaultvalue }
  857. function GetCodeString(const ScriptFunc, Default: String): String;
  858. begin
  859. if (CodeRunner <> nil) then
  860. Result := CodeRunner.RunStringFunction(AnsiString(ScriptFunc), [Default], True, Default)
  861. else begin
  862. InternalError('"code" constant with no CodeRunner');
  863. Result := '';
  864. end;
  865. end;
  866. var
  867. Z, ScriptFunc, Default: String;
  868. I: Integer;
  869. begin
  870. if DisableCodeConsts <> 0 then
  871. raise Exception.Create('Cannot evaluate "code" constant because of possible side effects');
  872. Delete(C, 1, 5); { skip past 'code:' }
  873. Z := C;
  874. I := ConstPos('|', Z); { check for a 'default' data }
  875. if I = 0 then
  876. I := Length(Z)+1;
  877. Default := Copy(Z, I+1, Maxint);
  878. SetLength(Z, I-1);
  879. ScriptFunc := Z;
  880. if ConvertConstPercentStr(ScriptFunc) and ConvertConstPercentStr(Default) then begin
  881. Default := ExpandConstEx(Default, CustomConsts);
  882. Result := GetCodeString(ScriptFunc, Default);
  883. Exit;
  884. end;
  885. { it will only reach here if there was a parsing error }
  886. InternalError('Failed to parse "code" constant');
  887. end;
  888. function ExpandDriveConst(C: String): String;
  889. begin
  890. Delete(C, 1, 6); { skip past 'drive:' }
  891. if ConvertConstPercentStr(C) then begin
  892. Result := PathExtractDrive(ExpandConstEx(C, CustomConsts));
  893. Exit;
  894. end;
  895. { it will only reach here if there was a parsing error }
  896. InternalError('Failed to parse "drive" constant');
  897. end;
  898. function ExpandCustomMessageConst(C: String): String;
  899. var
  900. I, ArgCount: Integer;
  901. MsgName: String;
  902. ArgValues: array[0..8] of String; { %1 through %9 }
  903. begin
  904. Delete(C, 1, 3); { skip past 'cm:' }
  905. I := ConstPos(',', C);
  906. if I = 0 then
  907. MsgName := C
  908. else
  909. MsgName := Copy(C, 1, I-1);
  910. { Prepare arguments. Excess arguments are ignored. }
  911. ArgCount := 0;
  912. while (I > 0) and (ArgCount <= High(ArgValues)) do begin
  913. Delete(C, 1, I);
  914. I := ConstPos(',', C);
  915. if I = 0 then
  916. ArgValues[ArgCount] := C
  917. else
  918. ArgValues[ArgCount] := Copy(C, 1, I-1);
  919. if not ConvertConstPercentStr(ArgValues[ArgCount]) then
  920. InternalError('Failed to parse "cm" constant');
  921. ArgValues[ArgCount] := ExpandConstEx(ArgValues[ArgCount], CustomConsts);
  922. Inc(ArgCount);
  923. end;
  924. { Look up the message value }
  925. if not GetCustomMessageValue(MsgName, Result) then
  926. InternalError(Format('Unknown custom message name "%s" in "cm" constant', [MsgName]));
  927. { Expand the message }
  928. Result := FmtMessage(PChar(Result), Slice(ArgValues, ArgCount));
  929. end;
  930. const
  931. FolderConsts: array[Boolean, TShellFolderID] of String = (
  932. { Also see FolderIDs }
  933. { User }
  934. ('userdesktop', 'userstartmenu', 'userprograms', 'userstartup',
  935. 'usersendto', 'commonfonts', 'userappdata', 'userdocs', 'usertemplates',
  936. 'userfavorites', 'localappdata', 'userpf', 'usercf', 'usersavedgames'),
  937. { Common }
  938. ('commondesktop', 'commonstartmenu', 'commonprograms', 'commonstartup',
  939. 'usersendto', 'commonfonts', 'commonappdata', 'commondocs', 'commontemplates',
  940. 'commonfavorites' { not accepted anymore by the compiler }, '', '', '', ''));
  941. NoUninstallConsts: array[0..6] of String =
  942. ('src', 'srcexe', 'userinfoname', 'userinfoorg', 'userinfoserial', 'hwnd',
  943. 'wizardhwnd');
  944. var
  945. OriginalCnst, ShellFolder: String;
  946. Common: Boolean;
  947. ShellFolderID: TShellFolderID;
  948. I: Integer;
  949. begin
  950. OriginalCnst := Cnst;
  951. HandleRenamedConstants(Cnst, nil);
  952. HandleAutoConstants(Cnst);
  953. if IsUninstaller then
  954. for I := Low(NoUninstallConsts) to High(NoUninstallConsts) do
  955. if NoUninstallConsts[I] = Cnst then
  956. NoUninstallConstError(NoUninstallConsts[I]);
  957. if Cnst = '\' then Result := '\'
  958. else if Cnst = 'app' then begin
  959. if IsUninstaller then begin
  960. if UninstallExpandedApp = '' then
  961. InternalError('An attempt was made to expand the "' + OriginalCnst + '" constant but Setup didn''t create the "app" dir');
  962. Result := UninstallExpandedApp;
  963. end else begin
  964. if WizardDirValue = '' then
  965. InternalError('An attempt was made to expand the "' + OriginalCnst + '" constant before it was initialized');
  966. Result := WizardDirValue;
  967. end;
  968. end
  969. else if Cnst = 'win' then Result := WinDir
  970. else if Cnst = 'sys' then Result := WinSystemDir
  971. else if Cnst = 'syswow64' then begin
  972. if WinSysWow64Dir <> '' then
  973. Result := WinSysWow64Dir
  974. else begin
  975. if IsWin64 then { sanity check }
  976. InternalError('Cannot expand "' + OriginalCnst + '" constant because there is no SysWOW64 directory');
  977. Result := WinSystemDir;
  978. end;
  979. end
  980. else if Cnst = 'sysnative' then begin
  981. if WinSysNativeDir <> '' then
  982. Result := WinSysNativeDir
  983. else
  984. Result := WinSystemDir;
  985. end
  986. else if Cnst = 'src' then Result := SourceDir
  987. else if Cnst = 'srcexe' then Result := SetupLdrOriginalFilename
  988. else if Cnst = 'tmp' then Result := TempInstallDir
  989. else if Cnst = 'sd' then Result := SystemDrive
  990. else if Cnst = 'commonpf' then begin
  991. if Is64BitInstallMode then
  992. Result := ProgramFiles64Dir
  993. else
  994. Result := ProgramFiles32Dir;
  995. end
  996. else if Cnst = 'commoncf' then begin
  997. if Is64BitInstallMode then
  998. Result := CommonFiles64Dir
  999. else
  1000. Result := CommonFiles32Dir;
  1001. end
  1002. else if Cnst = 'commonpf32' then Result := ProgramFiles32Dir
  1003. else if Cnst = 'commoncf32' then Result := CommonFiles32Dir
  1004. else if Cnst = 'commonpf64' then begin
  1005. if IsWin64 then
  1006. Result := ProgramFiles64Dir
  1007. else
  1008. InternalError('Cannot expand "' + OriginalCnst + '" constant on this version of Windows');
  1009. end
  1010. else if Cnst = 'commoncf64' then begin
  1011. if IsWin64 then
  1012. Result := CommonFiles64Dir
  1013. else
  1014. InternalError('Cannot expand "' + OriginalCnst + '" constant on this version of Windows');
  1015. end
  1016. else if Cnst = 'userfonts' then Result := ExpandConst('{localappdata}\Microsoft\Windows\Fonts') { supported by Windows 10 Version 1803 and newer. doesn't have a KNOWNFOLDERID. }
  1017. else if Cnst = 'dao' then Result := ExpandConst('{cf}\Microsoft Shared\DAO')
  1018. else if Cnst = 'cmd' then Result := CmdFilename
  1019. else if Cnst = 'computername' then Result := GetComputerNameString
  1020. else if Cnst = 'username' then Result := GetUserNameString
  1021. else if Cnst = 'groupname' then begin
  1022. if IsUninstaller then begin
  1023. if UninstallExpandedGroupName = '' then
  1024. InternalError('Cannot expand "' + OriginalCnst + '" constant because it was not available at install time');
  1025. Result := UninstallExpandedGroupName;
  1026. end
  1027. else begin
  1028. if WizardGroupValue = '' then
  1029. InternalError('An attempt was made to expand the "' + OriginalCnst + '" constant before it was initialized');
  1030. Result := WizardGroupValue;
  1031. end;
  1032. end
  1033. else if Cnst = 'sysuserinfoname' then Result := SysUserInfoName
  1034. else if Cnst = 'sysuserinfoorg' then Result := SysUserInfoOrg
  1035. else if Cnst = 'userinfoname' then Result := WizardUserInfoName
  1036. else if Cnst = 'userinfoorg' then Result := WizardUserInfoOrg
  1037. else if Cnst = 'userinfoserial' then Result := WizardUserInfoSerial
  1038. else if Cnst = 'uninstallexe' then Result := UninstallExeFilename
  1039. else if Cnst = 'group' then begin
  1040. if IsUninstaller then begin
  1041. if UninstallExpandedGroup = '' then
  1042. InternalError('Cannot expand "' + OriginalCnst + '" constant because it was not available at install time');
  1043. Result := UninstallExpandedGroup;
  1044. end
  1045. else begin
  1046. if WizardGroupValue = '' then
  1047. InternalError('An attempt was made to expand the "' + OriginalCnst + '" constant before it was initialized');
  1048. ShellFolder := GetShellFolder(not(shAlwaysUsePersonalGroup in SetupHeader.Options) and IsAdminInstallMode,
  1049. sfPrograms);
  1050. if ShellFolder = '' then
  1051. InternalError('Failed to expand "' + OriginalCnst + '" constant');
  1052. Result := AddBackslash(ShellFolder) + WizardGroupValue;
  1053. end;
  1054. end
  1055. else if Cnst = 'language' then begin
  1056. if IsUninstaller then
  1057. Result := UninstallExpandedLanguage
  1058. else
  1059. Result := PSetupLanguageEntry(Entries[seLanguage][ActiveLanguage]).Name
  1060. end
  1061. else if Cnst = 'hwnd' then begin
  1062. if Assigned(MainForm) then
  1063. Result := IntToStr(MainForm.Handle)
  1064. else
  1065. Result := '0';
  1066. end
  1067. else if Cnst = 'wizardhwnd' then begin
  1068. if Assigned(WizardForm) then
  1069. Result := IntToStr(WizardForm.Handle)
  1070. else
  1071. Result := '0';
  1072. end
  1073. else if Cnst = 'log' then Result := GetLogFileName
  1074. else if Cnst = 'dotnet11' then Result := GetDotNetVersionInstallRoot(rv32Bit, netbase11)
  1075. else if Cnst = 'dotnet20' then Result := GetDotNetVersionInstallRoot(InstallDefaultRegView, netbase20)
  1076. else if Cnst = 'dotnet2032' then Result := GetDotNetVersionInstallRoot(rv32Bit, netbase20)
  1077. else if Cnst = 'dotnet2064' then begin
  1078. if IsWin64 then
  1079. Result := GetDotNetVersionInstallRoot(rv64Bit, netbase20)
  1080. else
  1081. InternalError('Cannot expand "' + OriginalCnst + '" constant on this version of Windows');
  1082. end
  1083. else if Cnst = 'dotnet40' then Result := GetDotNetVersionInstallRoot(InstallDefaultRegView, netbase40)
  1084. else if Cnst = 'dotnet4032' then Result := GetDotNetVersionInstallRoot(rv32Bit, netbase40)
  1085. else if Cnst = 'dotnet4064' then begin
  1086. if IsWin64 then
  1087. Result := GetDotNetVersionInstallRoot(rv64Bit, netbase40)
  1088. else
  1089. InternalError('Cannot expand "' + OriginalCnst + '" constant on this version of Windows');
  1090. end
  1091. else if (Cnst <> '') and (Cnst[1] = '%') then Result := ExpandEnvConst(Cnst)
  1092. else if StrLComp(PChar(Cnst), 'reg:', 4) = 0 then Result := ExpandRegConst(Cnst)
  1093. else if StrLComp(PChar(Cnst), 'ini:', 4) = 0 then Result := ExpandIniConst(Cnst)
  1094. else if StrLComp(PChar(Cnst), 'param:', 6) = 0 then Result := ExpandParamConst(Cnst)
  1095. else if StrLComp(PChar(Cnst), 'code:', 5) = 0 then Result := ExpandCodeConst(Cnst)
  1096. else if StrLComp(PChar(Cnst), 'drive:', 6) = 0 then Result := ExpandDriveConst(Cnst)
  1097. else if StrLComp(PChar(Cnst), 'cm:', 3) = 0 then Result := ExpandCustomMessageConst(Cnst)
  1098. else begin
  1099. { Shell folder constants }
  1100. for Common := False to True do
  1101. for ShellFolderID := Low(ShellFolderID) to High(ShellFolderID) do
  1102. if Cnst = FolderConsts[Common, ShellFolderID] then begin
  1103. ShellFolder := GetShellFolder(Common, ShellFolderID);
  1104. if ShellFolder = '' then
  1105. InternalError(Format('Failed to expand shell folder constant "%s"', [OriginalCnst]));
  1106. Result := ShellFolder;
  1107. Exit;
  1108. end;
  1109. { Custom constants }
  1110. if Cnst <> '' then begin
  1111. I := 0;
  1112. while I < High(CustomConsts) do begin
  1113. if Cnst = CustomConsts[I] then begin
  1114. Result := CustomConsts[I+1];
  1115. Exit;
  1116. end;
  1117. Inc(I, 2);
  1118. end;
  1119. end;
  1120. { Unknown constant }
  1121. InternalError(Format('Unknown constant "%s"', [OriginalCnst]));
  1122. end;
  1123. end;
  1124. function ExpandConst(const S: String): String;
  1125. begin
  1126. Result := ExpandConstEx2(S, [''], True);
  1127. end;
  1128. function ExpandConstEx(const S: String; const CustomConsts: array of String): String;
  1129. begin
  1130. Result := ExpandConstEx2(S, CustomConsts, True);
  1131. end;
  1132. function ExpandConstEx2(const S: String; const CustomConsts: array of String;
  1133. const DoExpandIndividualConst: Boolean): String;
  1134. var
  1135. I, Start: Integer;
  1136. Cnst, ReplaceWith: String;
  1137. begin
  1138. Result := S;
  1139. I := 1;
  1140. while I <= Length(Result) do begin
  1141. if Result[I] = '{' then begin
  1142. if (I < Length(Result)) and (Result[I+1] = '{') then begin
  1143. { Change '{{' to '{' if not in an embedded constant }
  1144. Inc(I);
  1145. Delete(Result, I, 1);
  1146. end
  1147. else begin
  1148. Start := I;
  1149. { Find the closing brace, skipping over any embedded constants }
  1150. I := SkipPastConst(Result, I);
  1151. if I = 0 then { unclosed constant? }
  1152. InternalError('Unclosed constant');
  1153. Dec(I); { 'I' now points to the closing brace }
  1154. if DoExpandIndividualConst then begin
  1155. { Now translate the constant }
  1156. Cnst := Copy(Result, Start+1, I-(Start+1));
  1157. ReplaceWith := ExpandIndividualConst(Cnst, CustomConsts);
  1158. Delete(Result, Start, (I+1)-Start);
  1159. Insert(ReplaceWith, Result, Start);
  1160. I := Start + Length(ReplaceWith);
  1161. if (ReplaceWith <> '') and (PathLastChar(ReplaceWith)^ = '\') and
  1162. (I <= Length(Result)) and (Result[I] = '\') then
  1163. Delete(Result, I, 1);
  1164. end else
  1165. Inc(I); { Skip closing brace }
  1166. end;
  1167. end
  1168. else
  1169. Inc(I);
  1170. end;
  1171. end;
  1172. function ExpandConstIfPrefixed(const S: String): String;
  1173. const
  1174. ExpandPrefix = 'expand:';
  1175. begin
  1176. if Pos(ExpandPrefix, S) = 1 then begin
  1177. Inc(DisableCodeConsts);
  1178. try
  1179. Result := ExpandConst(Copy(S, Length(ExpandPrefix)+1, Maxint));
  1180. finally
  1181. Dec(DisableCodeConsts);
  1182. end;
  1183. end
  1184. else
  1185. Result := S;
  1186. end;
  1187. procedure InitMainNonSHFolderConsts;
  1188. function GetPath(const RegView: TRegView; const Name: PChar): String;
  1189. var
  1190. H: HKEY;
  1191. begin
  1192. if RegOpenKeyExView(RegView, HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, 0,
  1193. KEY_QUERY_VALUE, H) = ERROR_SUCCESS then begin
  1194. if not RegQueryStringValue(H, Name, Result) then
  1195. Result := '';
  1196. RegCloseKey(H);
  1197. end
  1198. else
  1199. Result := '';
  1200. end;
  1201. procedure ReadSysUserInfo;
  1202. var
  1203. RegView: TRegView;
  1204. K: HKEY;
  1205. begin
  1206. { Windows 7 x64 (and later?) is bugged: the owner and organization
  1207. are set to "Microsoft" on the 32-bit key. So on 64-bit Windows, read
  1208. from the 64-bit key. (The bug doesn't exist on 64-bit XP or Server 2003,
  1209. but it's safe to read the 64-bit key on those versions too.) }
  1210. if IsWin64 then
  1211. RegView := rv64Bit
  1212. else
  1213. RegView := rvDefault;
  1214. if RegOpenKeyExView(RegView, HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion',
  1215. 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  1216. RegQueryStringValue(K, 'RegisteredOwner', SysUserInfoName);
  1217. RegQueryStringValue(K, 'RegisteredOrganization', SysUserInfoOrg);
  1218. RegCloseKey(K);
  1219. end;
  1220. end;
  1221. begin
  1222. { Read Windows and Windows System dirs }
  1223. WinDir := GetWinDir;
  1224. WinSystemDir := GetSystemDir;
  1225. WinSysWow64Dir := GetSysWow64Dir;
  1226. WinSysNativeDir := GetSysNativeDir(IsWin64);
  1227. { Get system drive }
  1228. SystemDrive := GetEnv('SystemDrive'); {don't localize}
  1229. if SystemDrive = '' then begin
  1230. SystemDrive := PathExtractDrive(WinDir);
  1231. if SystemDrive = '' then
  1232. { In some rare case that PathExtractDrive failed, just default to C }
  1233. SystemDrive := 'C:';
  1234. end;
  1235. { Get 32-bit Program Files and Common Files dirs }
  1236. ProgramFiles32Dir := GetPath(rv32Bit, 'ProgramFilesDir');
  1237. if ProgramFiles32Dir = '' then
  1238. ProgramFiles32Dir := SystemDrive + '\Program Files'; {don't localize}
  1239. CommonFiles32Dir := GetPath(rv32Bit, 'CommonFilesDir');
  1240. if CommonFiles32Dir = '' then
  1241. CommonFiles32Dir := AddBackslash(ProgramFiles32Dir) + 'Common Files'; {don't localize}
  1242. { Get 64-bit Program Files and Common Files dirs }
  1243. if IsWin64 then begin
  1244. ProgramFiles64Dir := GetPath(rv64Bit, 'ProgramFilesDir');
  1245. if ProgramFiles64Dir = '' then
  1246. InternalError('Failed to get path of 64-bit Program Files directory');
  1247. CommonFiles64Dir := GetPath(rv64Bit, 'CommonFilesDir');
  1248. if CommonFiles64Dir = '' then
  1249. InternalError('Failed to get path of 64-bit Common Files directory');
  1250. end;
  1251. { Get path of command interpreter }
  1252. CmdFilename := AddBackslash(WinSystemDir) + 'cmd.exe';
  1253. { Get user info from system }
  1254. ReadSysUserInfo;
  1255. end;
  1256. procedure SaveStreamToTempFile(const Strm: TCustomMemoryStream;
  1257. const Filename: String);
  1258. var
  1259. ErrorCode: DWORD;
  1260. begin
  1261. try
  1262. Strm.SaveToFile(Filename);
  1263. except
  1264. { Display more useful error message than 'Stream write error' etc. }
  1265. on EStreamError do begin
  1266. ErrorCode := GetLastError;
  1267. raise Exception.Create(FmtSetupMessage(msgLastErrorMessage,
  1268. [SetupMessages[msgLdrCannotCreateTemp], IntToStr(ErrorCode),
  1269. Win32ErrorString(ErrorCode)]));
  1270. end;
  1271. end;
  1272. end;
  1273. procedure SaveResourceToTempFile(const ResName, Filename: String);
  1274. var
  1275. ResStrm: TResourceStream;
  1276. begin
  1277. ResStrm := TResourceStream.Create(HInstance, ResName, RT_RCDATA);
  1278. try
  1279. SaveStreamToTempFile(ResStrm, Filename);
  1280. finally
  1281. ResStrm.Free;
  1282. end;
  1283. end;
  1284. procedure CreateTempInstallDir;
  1285. { Initializes TempInstallDir and extracts the 64-bit helper into it if needed.
  1286. This is called by Setup, Uninstall, and RegSvr. }
  1287. var
  1288. Subdir, ResName, Filename: String;
  1289. ErrorCode: DWORD;
  1290. begin
  1291. TempInstallDir := CreateTempDir;
  1292. Log('Created temporary directory: ' + TempInstallDir);
  1293. if Debugging then
  1294. DebugNotifyTempDir(TempInstallDir);
  1295. { Create _isetup subdirectory to hold our internally-used files to ensure
  1296. they won't use any DLLs the install creator might've dumped into
  1297. TempInstallDir }
  1298. Subdir := AddBackslash(TempInstallDir) + '_isetup';
  1299. if not CreateDirectory(PChar(Subdir), nil) then begin
  1300. ErrorCode := GetLastError;
  1301. raise Exception.Create(FmtSetupMessage(msgLastErrorMessage,
  1302. [FmtSetupMessage1(msgErrorCreatingDir, Subdir), IntToStr(ErrorCode),
  1303. Win32ErrorString(ErrorCode)]));
  1304. end;
  1305. { Extract 64-bit helper EXE, if one is available for the current processor
  1306. architecture }
  1307. ResName := GetHelperResourceName;
  1308. if ResName <> '' then begin
  1309. Filename := Subdir + '\_setup64.tmp';
  1310. SaveResourceToTempFile(ResName, Filename);
  1311. SetHelperExeFilename(Filename);
  1312. end;
  1313. end;
  1314. function TempDeleteFileProc(const DisableFsRedir: Boolean;
  1315. const FileName: String; const Param: Pointer): Boolean;
  1316. var
  1317. Elapsed: DWORD;
  1318. label Retry;
  1319. begin
  1320. Retry:
  1321. Result := DeleteFileRedir(DisableFsRedir, FileName);
  1322. if not Result and
  1323. (GetLastError <> ERROR_FILE_NOT_FOUND) and
  1324. (GetLastError <> ERROR_PATH_NOT_FOUND) then begin
  1325. { If we get here, the file is probably still in use. On an SMP machine,
  1326. it's possible for an EXE to remain locked by Windows for a short time
  1327. after it terminates, causing DeleteFile to fail with ERROR_ACCESS_DENIED.
  1328. (I'm not sure this issue can really be seen here in practice; I could
  1329. only reproduce it consistently by calling DeleteFile() *immediately*
  1330. after waiting on the process handle.)
  1331. Retry if fewer than 2 seconds have passed since DelTree started,
  1332. otherwise assume the error must be permanent and give up. 2 seconds
  1333. ought to be more than enough for the SMP case. }
  1334. Elapsed := GetTickCount - DWORD(Param);
  1335. if Cardinal(Elapsed) < Cardinal(2000) then begin
  1336. Sleep(50);
  1337. goto Retry;
  1338. end;
  1339. end;
  1340. end;
  1341. procedure RemoveTempInstallDir;
  1342. { Removes TempInstallDir and all its contents. Stops the 64-bit helper first
  1343. if necessary. }
  1344. begin
  1345. { Stop 64-bit helper if it's running }
  1346. StopHelper(False);
  1347. SetHelperExeFilename('');
  1348. if TempInstallDir <> '' then begin
  1349. if Debugging then
  1350. DebugNotifyTempDir('');
  1351. if not DelTree(False, TempInstallDir, True, True, True, False, nil,
  1352. TempDeleteFileProc, Pointer(GetTickCount())) then
  1353. Log('Failed to remove temporary directory: ' + TempInstallDir);
  1354. end;
  1355. end;
  1356. procedure LoadSHFolderDLL;
  1357. var
  1358. Filename: String;
  1359. const
  1360. shfolder = 'shfolder.dll';
  1361. begin
  1362. Filename := AddBackslash(GetSystemDir) + shfolder;
  1363. { Ensure shell32.dll is pre-loaded so it isn't loaded/freed for each
  1364. individual SHGetFolderPath call }
  1365. SafeLoadLibrary(AddBackslash(GetSystemDir) + shell32, SEM_NOOPENFILEERRORBOX);
  1366. SHFolderDLLHandle := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
  1367. if SHFolderDLLHandle = 0 then
  1368. InternalError(Format('Failed to load DLL "%s"', [Filename]));
  1369. @SHGetFolderPathFunc := GetProcAddress(SHFolderDLLHandle, 'SHGetFolderPathW');
  1370. if @SHGetFolderPathFunc = nil then
  1371. InternalError('Failed to get address of SHGetFolderPath function');
  1372. end;
  1373. procedure UnloadSHFolderDLL;
  1374. begin
  1375. @SHGetFolderPathFunc := nil;
  1376. if SHFolderDLLHandle <> 0 then begin
  1377. FreeLibrary(SHFolderDLLHandle);
  1378. SHFolderDLLHandle := 0;
  1379. end;
  1380. end;
  1381. function GetShellFolderByCSIDL(Folder: Integer; const Create: Boolean): String;
  1382. const
  1383. CSIDL_FLAG_CREATE = $8000;
  1384. SHGFP_TYPE_CURRENT = 0;
  1385. var
  1386. Res: HRESULT;
  1387. Buf: array[0..MAX_PATH-1] of Char;
  1388. begin
  1389. { Note: Must pass Create=True or else SHGetFolderPath fails if the
  1390. specified CSIDL is valid but doesn't currently exist. }
  1391. if Create then
  1392. Folder := Folder or CSIDL_FLAG_CREATE;
  1393. { Work around a nasty bug in Windows Vista and Windows Server 2008 and maybe
  1394. later versions also: When a folder ID resolves to the root directory of a
  1395. drive ('X:\') and the CSIDL_FLAG_CREATE flag is passed, SHGetFolderPath
  1396. fails with code 0x80070005.
  1397. So, first try calling the function without CSIDL_FLAG_CREATE.
  1398. If and only if that fails, call it again with the flag.
  1399. Note: The calls *must* be issued in this order; if it's called with the
  1400. flag first, it seems to permanently cache the failure code, causing future
  1401. calls that don't include the flag to fail as well. }
  1402. if Folder and CSIDL_FLAG_CREATE <> 0 then
  1403. Res := SHGetFolderPathFunc(0, Folder and not CSIDL_FLAG_CREATE, 0,
  1404. SHGFP_TYPE_CURRENT, Buf)
  1405. else
  1406. Res := E_FAIL; { always issue the call below }
  1407. if Res <> S_OK then
  1408. Res := SHGetFolderPathFunc(0, Folder, 0, SHGFP_TYPE_CURRENT, Buf);
  1409. if Res = S_OK then
  1410. Result := RemoveBackslashUnlessRoot(PathExpand(Buf))
  1411. else begin
  1412. Result := '';
  1413. LogFmt('Warning: SHGetFolderPath failed with code 0x%.8x on folder 0x%.4x',
  1414. [Res, Folder]);
  1415. end;
  1416. end;
  1417. function GetShellFolderByGUID(Folder: TGUID; const Create: Boolean): String;
  1418. begin
  1419. if Assigned(SHGetKnownFolderPathFunc) then begin
  1420. var dwFlags: DWORD := 0;
  1421. if Create then
  1422. dwFlags := dwFlags or KF_FLAG_CREATE;
  1423. var Path: PWideChar;
  1424. { Note: Must pass Create=True or else SHGetKnownFolderPath fails if the
  1425. specified GUID is valid but doesn't currently exist. }
  1426. var Res := SHGetKnownFolderPathFunc(Folder, dwFlags, 0, Path);
  1427. if Res = S_OK then begin
  1428. Result := WideCharToString(Path);
  1429. CoTaskMemFree(Path);
  1430. end else begin
  1431. Result := '';
  1432. LogFmt('Warning: SHGetKnownFolderPath failed with code 0x%.8x', [Res]);
  1433. end;
  1434. end else
  1435. Result := '';
  1436. end;
  1437. function GetShellFolder(const Common: Boolean; const ID: TShellFolderID): String;
  1438. const
  1439. CSIDL_COMMON_STARTMENU = $0016;
  1440. CSIDL_COMMON_PROGRAMS = $0017;
  1441. CSIDL_COMMON_STARTUP = $0018;
  1442. CSIDL_COMMON_DESKTOPDIRECTORY = $0019;
  1443. CSIDL_APPDATA = $001A;
  1444. CSIDL_LOCAL_APPDATA = $001C;
  1445. CSIDL_COMMON_FAVORITES = $001F;
  1446. CSIDL_COMMON_APPDATA = $0023;
  1447. CSIDL_COMMON_TEMPLATES = $002D;
  1448. CSIDL_COMMON_DOCUMENTS = $002E;
  1449. FolderIDs: array[Boolean, TShellFolderID] of Integer = (
  1450. { Values must match FolderConsts }
  1451. { User }
  1452. (CSIDL_DESKTOPDIRECTORY, CSIDL_STARTMENU, CSIDL_PROGRAMS, CSIDL_STARTUP,
  1453. CSIDL_SENDTO, CSIDL_FONTS, CSIDL_APPDATA, CSIDL_PERSONAL,
  1454. CSIDL_TEMPLATES, CSIDL_FAVORITES, CSIDL_LOCAL_APPDATA, 0, 0, 0),
  1455. { Common }
  1456. (CSIDL_COMMON_DESKTOPDIRECTORY, CSIDL_COMMON_STARTMENU, CSIDL_COMMON_PROGRAMS, CSIDL_COMMON_STARTUP,
  1457. CSIDL_SENDTO, CSIDL_FONTS, CSIDL_COMMON_APPDATA, CSIDL_COMMON_DOCUMENTS,
  1458. CSIDL_COMMON_TEMPLATES, CSIDL_COMMON_FAVORITES, 0, 0, 0, 0));
  1459. FOLDERID_UserProgramFiles: TGUID = (D1:$5CD7AEE2; D2:$2219; D3:$4A67; D4:($B8,$5D,$6C,$9C,$E1,$56,$60,$CB));
  1460. FOLDERID_UserProgramFilesCommon: TGUID = (D1:$BCBD3057; D2:$CA5C; D3:$4622; D4:($B4,$2D,$BC,$56,$DB,$0A,$E5,$16));
  1461. FOLDERID_SavedGames: TGUID = (D1:$4C5C32FF; D2:$BB9D; D3:$43B0; D4:($B5,$B4,$2D,$72,$E5,$4E,$AA,$A4));
  1462. var
  1463. ShellFolder: String;
  1464. begin
  1465. if not ShellFoldersRead[Common, ID] then begin
  1466. if ID = sfUserProgramFiles then
  1467. ShellFolder := GetShellFolderByGUID(FOLDERID_UserProgramFiles, True)
  1468. else if ID = sfUserCommonFiles then
  1469. ShellFolder := GetShellFolderByGUID(FOLDERID_UserProgramFilesCommon, True)
  1470. else if ID = sfUserSavedGames then
  1471. ShellFolder := GetShellFolderByGUID(FOLDERID_SavedGames, True)
  1472. else
  1473. ShellFolder := GetShellFolderByCSIDL(FolderIDs[Common, ID], True);
  1474. ShellFolders[Common, ID] := ShellFolder;
  1475. ShellFoldersRead[Common, ID] := True;
  1476. end;
  1477. Result := ShellFolders[Common, ID];
  1478. end;
  1479. function InstallOnThisVersion(const MinVersion: TSetupVersionData;
  1480. const OnlyBelowVersion: TSetupVersionData): TInstallOnThisVersionResult;
  1481. var
  1482. Ver, Ver2, MinVer, OnlyBelowVer: Cardinal;
  1483. begin
  1484. Ver := WindowsVersion;
  1485. MinVer := MinVersion.NTVersion;
  1486. OnlyBelowVer := OnlyBelowVersion.NTVersion;
  1487. Result := irInstall;
  1488. if MinVer = 0 then
  1489. Result := irNotOnThisPlatform
  1490. else begin
  1491. if Ver < MinVer then
  1492. Result := irVersionTooLow
  1493. else if (LongRec(Ver).Hi = LongRec(MinVer).Hi) and
  1494. (NTServicePackLevel < MinVersion.NTServicePack) then
  1495. Result := irServicePackTooLow
  1496. else begin
  1497. if OnlyBelowVer <> 0 then begin
  1498. Ver2 := Ver;
  1499. { A build number of 0 on OnlyBelowVersion means 'match any build' }
  1500. if LongRec(OnlyBelowVer).Lo = 0 then
  1501. Ver2 := Ver2 and $FFFF0000; { set build number to zero on Ver2 also }
  1502. { Note: When OnlyBelowVersion includes a service pack level, the
  1503. version number test changes from a "<" to "<=" operation. Thus,
  1504. on Windows 2000 SP4, 5.0 and 5.0.2195 will fail, but 5.0sp5 and
  1505. 5.0.2195sp5 will pass. }
  1506. if (Ver2 > OnlyBelowVer) or
  1507. ((Ver2 = OnlyBelowVer) and
  1508. (OnlyBelowVersion.NTServicePack = 0)) or
  1509. ((LongRec(Ver).Hi = LongRec(OnlyBelowVer).Hi) and
  1510. (OnlyBelowVersion.NTServicePack <> 0) and
  1511. (NTServicePackLevel >= OnlyBelowVersion.NTServicePack)) then
  1512. Result := irVerTooHigh;
  1513. end;
  1514. end;
  1515. end;
  1516. end;
  1517. function GetSizeOfComponent(const ComponentName: String; const ExtraDiskSpaceRequired: Integer64): Integer64;
  1518. var
  1519. ComponentNameAsList: TStringList;
  1520. FileEntry: PSetupFileEntry;
  1521. I: Integer;
  1522. begin
  1523. Result := ExtraDiskSpaceRequired;
  1524. ComponentNameAsList := TStringList.Create();
  1525. try
  1526. ComponentNameAsList.Add(ComponentName);
  1527. for I := 0 to Entries[seFile].Count-1 do begin
  1528. FileEntry := PSetupFileEntry(Entries[seFile][I]);
  1529. with FileEntry^ do begin
  1530. if (Components <> '') and
  1531. ((Tasks = '') and (Check = '')) then begin {don't count tasks or scripted entries}
  1532. if ShouldProcessFileEntry(ComponentNameAsList, nil, FileEntry, True) then begin
  1533. if LocationEntry <> -1 then
  1534. Inc6464(Result, PSetupFileLocationEntry(Entries[seFileLocation][LocationEntry])^.OriginalSize)
  1535. else
  1536. Inc6464(Result, ExternalSize);
  1537. end;
  1538. end;
  1539. end;
  1540. end;
  1541. finally
  1542. ComponentNameAsList.Free();
  1543. end;
  1544. end;
  1545. function GetSizeOfType(const TypeName: String; const IsCustom: Boolean): Integer64;
  1546. var
  1547. ComponentTypes: TStringList;
  1548. I: Integer;
  1549. begin
  1550. Result.Hi := 0;
  1551. Result.Lo := 0;
  1552. ComponentTypes := TStringList.Create();
  1553. for I := 0 to Entries[seComponent].Count-1 do begin
  1554. with PSetupComponentEntry(Entries[seComponent][I])^ do begin
  1555. SetStringsFromCommaString(ComponentTypes, Types);
  1556. { For custom types, only count fixed components. Otherwise count all. }
  1557. if IsCustom then begin
  1558. if (coFixed in Options) and ListContains(ComponentTypes, TypeName) then
  1559. Inc6464(Result, Size);
  1560. end else begin
  1561. if ListContains(ComponentTypes, TypeName) then
  1562. Inc6464(Result, Size);
  1563. end;
  1564. end;
  1565. end;
  1566. ComponentTypes.Free();
  1567. end;
  1568. function IsRecurseableDirectory(const FindData: TWin32FindData): Boolean;
  1569. { Returns True if FindData is a directory that may be recursed into.
  1570. Intended only for use when processing external+recursesubdirs file entries. }
  1571. begin
  1572. Result :=
  1573. (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and
  1574. (FindData.dwFileAttributes and FILE_ATTRIBUTE_HIDDEN = 0) and
  1575. (StrComp(FindData.cFileName, '.') <> 0) and
  1576. (StrComp(FindData.cFileName, '..') <> 0);
  1577. end;
  1578. type
  1579. TEnumFilesProc = function(const DisableFsRedir: Boolean; const Filename: String;
  1580. const Param: Pointer): Boolean;
  1581. function DummyDeleteDirProc(const DisableFsRedir: Boolean; const Filename: String;
  1582. const Param: Pointer): Boolean;
  1583. begin
  1584. { We don't actually want to delete the dir, so just return success. }
  1585. Result := True;
  1586. end;
  1587. { Enumerates the files we're going to install and delete. Returns True on success.
  1588. Likewise EnumFilesProc should return True on success and return False
  1589. to break the enum and to cause EnumFiles to return False instead of True. }
  1590. function EnumFiles(const EnumFilesProc: TEnumFilesProc;
  1591. const WizardComponents, WizardTasks: TStringList; const Param: Pointer): Boolean;
  1592. function RecurseExternalFiles(const DisableFsRedir: Boolean;
  1593. const SearchBaseDir, SearchSubDir, SearchWildcard: String;
  1594. const SourceIsWildcard: Boolean; const CurFile: PSetupFileEntry): Boolean;
  1595. var
  1596. SearchFullPath, DestName: String;
  1597. H: THandle;
  1598. FindData: TWin32FindData;
  1599. begin
  1600. SearchFullPath := SearchBaseDir + SearchSubDir + SearchWildcard;
  1601. Result := True;
  1602. H := FindFirstFileRedir(DisableFsRedir, SearchFullPath, FindData);
  1603. if H <> INVALID_HANDLE_VALUE then begin
  1604. try
  1605. repeat
  1606. if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = 0 then begin
  1607. if SourceIsWildcard then
  1608. if FindData.dwFileAttributes and FILE_ATTRIBUTE_HIDDEN <> 0 then
  1609. Continue;
  1610. DestName := ExpandConst(CurFile^.DestName);
  1611. if not(foCustomDestName in CurFile^.Options) then
  1612. DestName := DestName + SearchSubDir + FindData.cFileName
  1613. else if SearchSubDir <> '' then
  1614. DestName := PathExtractPath(DestName) + SearchSubDir + PathExtractName(DestName);
  1615. if not EnumFilesProc(DisableFsRedir, DestName, Param) then begin
  1616. Result := False;
  1617. Exit;
  1618. end;
  1619. end;
  1620. until not FindNextFile(H, FindData);
  1621. finally
  1622. Windows.FindClose(H);
  1623. end;
  1624. end;
  1625. if foRecurseSubDirsExternal in CurFile^.Options then begin
  1626. H := FindFirstFileRedir(DisableFsRedir, SearchBaseDir + SearchSubDir + '*', FindData);
  1627. if H <> INVALID_HANDLE_VALUE then begin
  1628. try
  1629. repeat
  1630. if IsRecurseableDirectory(FindData) then
  1631. if not RecurseExternalFiles(DisableFsRedir, SearchBaseDir,
  1632. SearchSubDir + FindData.cFileName + '\', SearchWildcard,
  1633. SourceIsWildcard, CurFile) then begin
  1634. Result := False;
  1635. Exit;
  1636. end;
  1637. until not FindNextFile(H, FindData);
  1638. finally
  1639. Windows.FindClose(H);
  1640. end;
  1641. end;
  1642. end;
  1643. end;
  1644. var
  1645. I: Integer;
  1646. CurFile: PSetupFileEntry;
  1647. DisableFsRedir: Boolean;
  1648. SourceWildcard: String;
  1649. begin
  1650. Result := True;
  1651. { [Files] }
  1652. for I := 0 to Entries[seFile].Count-1 do begin
  1653. CurFile := PSetupFileEntry(Entries[seFile][I]);
  1654. if (CurFile^.FileType = ftUserFile) and
  1655. ShouldProcessFileEntry(WizardComponents, WizardTasks, CurFile, False) then begin
  1656. DisableFsRedir := ShouldDisableFsRedirForFileEntry(CurFile);
  1657. if CurFile^.LocationEntry <> -1 then begin
  1658. { Non-external file }
  1659. if not EnumFilesProc(DisableFsRedir, ExpandConst(CurFile^.DestName), Param) then begin
  1660. Result := False;
  1661. Exit;
  1662. end;
  1663. end
  1664. else begin
  1665. { External file }
  1666. SourceWildcard := ExpandConst(CurFile^.SourceFilename);
  1667. if not RecurseExternalFiles(DisableFsRedir, PathExtractPath(SourceWildcard), '',
  1668. PathExtractName(SourceWildcard), IsWildcard(SourceWildcard), CurFile) then begin
  1669. Result := False;
  1670. Exit;
  1671. end;
  1672. end;
  1673. end;
  1674. end;
  1675. { [InstallDelete] }
  1676. for I := 0 to Entries[seInstallDelete].Count-1 do
  1677. with PSetupDeleteEntry(Entries[seInstallDelete][I])^ do
  1678. if ShouldProcessEntry(WizardComponents, WizardTasks, Components, Tasks, Languages, Check) then begin
  1679. case DeleteType of
  1680. dfFiles, dfFilesAndOrSubdirs:
  1681. if not DelTree(InstallDefaultDisableFsRedir, ExpandConst(Name), False, True, DeleteType = dfFilesAndOrSubdirs, True,
  1682. DummyDeleteDirProc, EnumFilesProc, Param) then begin
  1683. Result := False;
  1684. Exit;
  1685. end;
  1686. dfDirIfEmpty:
  1687. if not DelTree(InstallDefaultDisableFsRedir, ExpandConst(Name), True, False, False, True,
  1688. DummyDeleteDirProc, EnumFilesProc, Param) then begin
  1689. Result := False;
  1690. Exit;
  1691. end;
  1692. end;
  1693. end;
  1694. end;
  1695. procedure EnumProc(const Filename: String; Param: Pointer);
  1696. begin
  1697. TStringList(Param).Add(PathLowercase(Filename));
  1698. end;
  1699. var
  1700. CheckForFileSL: TStringList;
  1701. function CheckForFile(const DisableFsRedir: Boolean; const AFilename: String;
  1702. const Param: Pointer): Boolean;
  1703. var
  1704. Filename: String;
  1705. J: Integer;
  1706. begin
  1707. Filename := AFilename;
  1708. if not DisableFsRedir then
  1709. Filename := ReplaceSystemDirWithSysWow64(Filename);
  1710. Filename := PathLowercase(Filename);
  1711. for J := 0 to CheckForFileSL.Count-1 do begin
  1712. if CheckForFileSL[J] = Filename then begin
  1713. LogFmt('Found pending rename or delete that matches one of our files: %s', [Filename]);
  1714. Result := False; { Break the enum, just need to know if any matches }
  1715. Exit;
  1716. end;
  1717. end;
  1718. Result := True; { Success! }
  1719. end;
  1720. { Checks if no file we're going to install or delete has a pending rename or delete. }
  1721. function PreviousInstallCompleted(const WizardComponents, WizardTasks: TStringList): Boolean;
  1722. begin
  1723. Result := True;
  1724. if Entries[seFile].Count = 0 then
  1725. Exit;
  1726. CheckForFileSL := TStringList.Create;
  1727. try
  1728. EnumFileReplaceOperationsFilenames(EnumProc, CheckForFileSL);
  1729. if CheckForFileSL.Count = 0 then
  1730. Exit;
  1731. Result := EnumFiles(CheckForFile, WizardComponents, WizardTasks, nil);
  1732. finally
  1733. CheckForFileSL.Free;
  1734. end;
  1735. end;
  1736. type
  1737. TArrayOfPWideChar = array[0..(MaxInt div SizeOf(PWideChar))-1] of PWideChar;
  1738. PArrayOfPWideChar = ^TArrayOfPWideChar;
  1739. var
  1740. RegisterFileBatchFilenames: PArrayOfPWideChar;
  1741. RegisterFileFilenamesBatchMax, RegisterFileFilenamesBatchCount: Integer;
  1742. function RegisterFile(const DisableFsRedir: Boolean; const AFilename: String;
  1743. const Param: Pointer): Boolean;
  1744. var
  1745. Filename, Text: String;
  1746. I, Len: Integer;
  1747. CheckFilter, Match: Boolean;
  1748. begin
  1749. Filename := AFilename;
  1750. { First: check filter and self. }
  1751. if Filename <> '' then begin
  1752. CheckFilter := Boolean(Param);
  1753. if CheckFilter then begin
  1754. Match := False;
  1755. Text := PathLowercase(PathExtractName(Filename));
  1756. for I := 0 to CloseApplicationsFilterList.Count-1 do begin
  1757. if WildcardMatch(PChar(Text), PChar(CloseApplicationsFilterList[I])) then begin
  1758. Match := True;
  1759. Break;
  1760. end;
  1761. end;
  1762. if not Match then begin
  1763. { No match with filter so exit but don't return an error. }
  1764. Result := True;
  1765. Exit;
  1766. end;
  1767. end;
  1768. if PathCompare(Filename, SetupLdrOriginalFilename) = 0 then begin
  1769. { Don't allow self to be registered but don't return an error. }
  1770. Result := True;
  1771. Exit;
  1772. end;
  1773. end;
  1774. { Secondly: check if we need to register this batch, either because the batch is full
  1775. or because we're done scanning and have leftovers. }
  1776. if ((Filename <> '') and (RegisterFileFilenamesBatchCount = RegisterFileFilenamesBatchMax)) or
  1777. ((Filename = '') and (RegisterFileFilenamesBatchCount > 0)) then begin
  1778. if RmRegisterResources(RmSessionHandle, RegisterFileFilenamesBatchCount, RegisterFileBatchFilenames, 0, nil, 0, nil) = ERROR_SUCCESS then begin
  1779. for I := 0 to RegisterFileFilenamesBatchCount-1 do
  1780. FreeMem(RegisterFileBatchFilenames[I]);
  1781. RegisterFileFilenamesBatchCount := 0;
  1782. end else begin
  1783. RmEndSession(RmSessionHandle);
  1784. RmSessionStarted := False;
  1785. end;
  1786. end;
  1787. { Finally: add this file to the batch. }
  1788. if RmSessionStarted and (FileName <> '') then begin
  1789. { From MSDN: "Installers should not disable file system redirection before calling
  1790. the Restart Manager API. This means that a 32-bit installer run on 64-bit Windows
  1791. is unable register a file in the %windir%\system32 directory." This is incorrect,
  1792. we can register such files by using the Sysnative alias. }
  1793. if DisableFsRedir then
  1794. Filename := ReplaceSystemDirWithSysNative(Filename, IsWin64);
  1795. if InitLogCloseApplications then
  1796. LogFmt('Found a file to register with RestartManager: %s', [Filename]);
  1797. Len := Length(Filename);
  1798. GetMem(RegisterFileBatchFilenames[RegisterFileFilenamesBatchCount], (Len + 1) * SizeOf(RegisterFileBatchFilenames[RegisterFileFilenamesBatchCount][0]));
  1799. StrPCopy(RegisterFileBatchFilenames[RegisterFileFilenamesBatchCount], Filename);
  1800. Inc(RegisterFileFilenamesBatchCount);
  1801. Inc(RmRegisteredFilesCount);
  1802. end;
  1803. Result := RmSessionStarted; { Break the enum if there was an error, else continue. }
  1804. end;
  1805. { Helper function for [Code] to register extra files. }
  1806. var
  1807. AllowCodeRegisterExtraCloseApplicationsResource: Boolean;
  1808. function CodeRegisterExtraCloseApplicationsResource(const DisableFsRedir: Boolean; const AFilename: String): Boolean;
  1809. begin
  1810. if AllowCodeRegisterExtraCloseApplicationsResource then
  1811. Result := RegisterFile(DisableFsRedir, AFilename, Pointer(False))
  1812. else begin
  1813. InternalError('Cannot call "RegisterExtraCloseApplicationsResource" function at this time');
  1814. Result := False;
  1815. end;
  1816. end;
  1817. { Register all files we're going to install or delete. Ends RmSession on errors. }
  1818. procedure RegisterResourcesWithRestartManager(const WizardComponents, WizardTasks: TStringList);
  1819. var
  1820. I: Integer;
  1821. begin
  1822. { Note: MSDN says we shouldn't call RmRegisterResources for each file because of speed, but calling
  1823. it once for all files adds extra memory usage, so calling it in batches. }
  1824. RegisterFileFilenamesBatchMax := 1000;
  1825. GetMem(RegisterFileBatchFilenames, RegisterFileFilenamesBatchMax * SizeOf(RegisterFileBatchFilenames[0]));
  1826. try
  1827. { Register our files. }
  1828. RmRegisteredFilesCount := 0;
  1829. EnumFiles(RegisterFile, WizardComponents, WizardTasks, Pointer(True));
  1830. { Ask [Code] for more files. }
  1831. if CodeRunner <> nil then begin
  1832. AllowCodeRegisterExtraCloseApplicationsResource := True;
  1833. try
  1834. try
  1835. CodeRunner.RunProcedures('RegisterExtraCloseApplicationsResources', [''], False);
  1836. except
  1837. Log('RegisterExtraCloseApplicationsResources raised an exception.');
  1838. Application.HandleException(nil);
  1839. end;
  1840. finally
  1841. AllowCodeRegisterExtraCloseApplicationsResource := False;
  1842. end;
  1843. end;
  1844. { Don't forget to register leftovers. }
  1845. if RmSessionStarted then
  1846. RegisterFile(False, '', nil);
  1847. finally
  1848. for I := 0 to RegisterFileFilenamesBatchCount-1 do
  1849. FreeMem(RegisterFileBatchFilenames[I]);
  1850. FreeMem(RegisterFileBatchFilenames);
  1851. end;
  1852. end;
  1853. procedure DebugNotifyEntry(EntryType: TEntryType; Number: Integer);
  1854. var
  1855. Kind: TDebugEntryKind;
  1856. B: Boolean;
  1857. begin
  1858. if not Debugging then Exit;
  1859. case EntryType of
  1860. seDir: Kind := deDir;
  1861. seFile: Kind := deFile;
  1862. seIcon: Kind := deIcon;
  1863. seIni: Kind := deIni;
  1864. seRegistry: Kind := deRegistry;
  1865. seInstallDelete: Kind := deInstallDelete;
  1866. seUninstallDelete: Kind := deUninstallDelete;
  1867. seRun: Kind := deRun;
  1868. seUninstallRun: Kind := deUninstallRun;
  1869. else
  1870. Exit;
  1871. end;
  1872. DebugNotify(Kind, Integer(OriginalEntryIndexes[EntryType][Number]), B);
  1873. end;
  1874. procedure CodeRunnerOnLog(const S: String);
  1875. begin
  1876. Log(S);
  1877. end;
  1878. procedure CodeRunnerOnLogFmt(const S: String; const Args: array of const);
  1879. begin
  1880. LogFmt(S, Args);
  1881. end;
  1882. procedure CodeRunnerOnDllImport(var DllName: String; var ForceDelayLoad: Boolean);
  1883. var
  1884. S, BaseName, FullName: String;
  1885. FirstFile: Boolean;
  1886. P: Integer;
  1887. begin
  1888. while True do begin
  1889. if Pos('setup:', DllName) = 1 then begin
  1890. if IsUninstaller then begin
  1891. DllName := '';
  1892. ForceDelayLoad := True;
  1893. Exit;
  1894. end;
  1895. Delete(DllName, 1, Length('setup:'));
  1896. end
  1897. else if Pos('uninstall:', DllName) = 1 then begin
  1898. if not IsUninstaller then begin
  1899. DllName := '';
  1900. ForceDelayLoad := True;
  1901. Exit;
  1902. end;
  1903. Delete(DllName, 1, Length('uninstall:'));
  1904. end
  1905. else
  1906. Break;
  1907. end;
  1908. if Pos('files:', DllName) = 1 then begin
  1909. if IsUninstaller then begin
  1910. { Uninstall doesn't do 'files:' }
  1911. DllName := '';
  1912. ForceDelayLoad := True;
  1913. end
  1914. else begin
  1915. S := Copy(DllName, Length('files:')+1, Maxint);
  1916. FirstFile := True;
  1917. repeat
  1918. P := ConstPos(',', S);
  1919. if P = 0 then
  1920. BaseName := S
  1921. else begin
  1922. BaseName := Copy(S, 1, P-1);
  1923. Delete(S, 1, P);
  1924. end;
  1925. BaseName := ExpandConst((BaseName));
  1926. FullName := AddBackslash(TempInstallDir) + BaseName;
  1927. if not NewFileExists(FullName) then
  1928. ExtractTemporaryFile(BaseName);
  1929. if FirstFile then begin
  1930. DllName := FullName;
  1931. FirstFile := False;
  1932. end;
  1933. until P = 0;
  1934. end;
  1935. end
  1936. else
  1937. DllName := ExpandConst(DllName);
  1938. end;
  1939. function CodeRunnerOnDebug(const Position: LongInt;
  1940. var ContinueStepOver: Boolean): Boolean;
  1941. begin
  1942. Result := DebugNotify(deCodeLine, Position, ContinueStepOver, CodeRunner.GetCallStack);
  1943. end;
  1944. function CodeRunnerOnDebugIntermediate(const Position: LongInt;
  1945. var ContinueStepOver: Boolean): Boolean;
  1946. begin
  1947. Result := DebugNotifyIntermediate(deCodeLine, Position, ContinueStepOver);
  1948. end;
  1949. procedure CodeRunnerOnException(const Exception: AnsiString; const Position: LongInt);
  1950. begin
  1951. if Debugging then
  1952. DebugNotifyException(String(Exception), deCodeLine, Position);
  1953. end;
  1954. procedure SetActiveLanguage(const I: Integer);
  1955. { Activates the specified language }
  1956. var
  1957. LangEntry: PSetupLanguageEntry;
  1958. J: Integer;
  1959. begin
  1960. if ActiveLanguage = I then
  1961. Exit;
  1962. LangEntry := Entries[seLanguage][I];
  1963. AssignSetupMessages(LangEntry.Data[1], Length(LangEntry.Data));
  1964. { Remove outdated < and > markers from the Back and Next buttons. Done here for now to avoid a Default.isl change. }
  1965. StringChange(SetupMessages[msgButtonBack], '< ', '');
  1966. StringChange(SetupMessages[msgButtonNext], ' >', '');
  1967. ActiveLanguage := I;
  1968. Finalize(LangOptions); { prevent leak on D2 }
  1969. LangOptions := LangEntry^;
  1970. if LangEntry.LicenseText <> '' then
  1971. ActiveLicenseText := LangEntry.LicenseText
  1972. else
  1973. ActiveLicenseText := SetupHeader.LicenseText;
  1974. if LangEntry.InfoBeforeText <> '' then
  1975. ActiveInfoBeforeText := LangEntry.InfoBeforeText
  1976. else
  1977. ActiveInfoBeforeText := SetupHeader.InfoBeforeText;
  1978. if LangEntry.InfoAfterText <> '' then
  1979. ActiveInfoAfterText := LangEntry.InfoAfterText
  1980. else
  1981. ActiveInfoAfterText := SetupHeader.InfoAfterText;
  1982. SetMessageBoxRightToLeft(LangOptions.RightToLeft);
  1983. SetMessageBoxCaption(mbInformation, PChar(SetupMessages[msgInformationTitle]));
  1984. SetMessageBoxCaption(mbConfirmation, PChar(SetupMessages[msgConfirmTitle]));
  1985. SetMessageBoxCaption(mbError, PChar(SetupMessages[msgErrorTitle]));
  1986. SetMessageBoxCaption(mbCriticalError, PChar(SetupMessages[msgErrorTitle]));
  1987. Application.Title := SetupMessages[msgSetupAppTitle];
  1988. for J := 0 to Entries[seType].Count-1 do begin
  1989. with PSetupTypeEntry(Entries[seType][J])^ do begin
  1990. case Typ of
  1991. ttDefaultFull: Description := SetupMessages[msgFullInstallation];
  1992. ttDefaultCompact: Description := SetupMessages[msgCompactInstallation];
  1993. ttDefaultCustom: Description := SetupMessages[msgCustomInstallation];
  1994. end;
  1995. end;
  1996. end;
  1997. { Tell the first instance to change its language too. (It's possible for
  1998. the first instance to display messages after Setup terminates, e.g. if it
  1999. fails to restart the computer.) }
  2000. if SetupNotifyWndPresent then
  2001. SendNotifyMessage(SetupNotifyWnd, WM_USER + 150, 10001, I);
  2002. end;
  2003. function GetLanguageEntryProc(Index: Integer; var Entry: PSetupLanguageEntry): Boolean;
  2004. begin
  2005. Result := False;
  2006. if Index < Entries[seLanguage].Count then begin
  2007. Entry := Entries[seLanguage][Index];
  2008. Result := True;
  2009. end;
  2010. end;
  2011. procedure ActivateDefaultLanguage;
  2012. { Auto-detects the most appropriate language and activates it.
  2013. Also initializes the ShowLanguageDialog and MatchedLangParameter variables.
  2014. Note: A like-named version of this function is also present in SetupLdr.dpr. }
  2015. var
  2016. I: Integer;
  2017. begin
  2018. MatchedLangParameter := False;
  2019. case DetermineDefaultLanguage(GetLanguageEntryProc,
  2020. SetupHeader.LanguageDetectionMethod, InitLang, I) of
  2021. ddNoMatch: ShowLanguageDialog := (SetupHeader.ShowLanguageDialog <> slNo);
  2022. ddMatch: ShowLanguageDialog := (SetupHeader.ShowLanguageDialog = slYes);
  2023. else
  2024. begin
  2025. { ddMatchLangParameter }
  2026. ShowLanguageDialog := False;
  2027. MatchedLangParameter := True;
  2028. end;
  2029. end;
  2030. SetActiveLanguage(I);
  2031. end;
  2032. procedure SetTaskbarButtonVisibility(const AVisible: Boolean);
  2033. var
  2034. ExStyle: Longint;
  2035. begin
  2036. { The taskbar button is hidden by setting the WS_EX_TOOLWINDOW style on the
  2037. application window. We can't simply hide the window because on D3+ the VCL
  2038. would just show it again in TApplication.UpdateVisible when the first form
  2039. is shown. }
  2040. TaskbarButtonHidden := not AVisible; { see WM_STYLECHANGING hook in Setup.dpr }
  2041. if (GetWindowLong(Application.Handle, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0) <> AVisible then begin
  2042. SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
  2043. SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  2044. ExStyle := GetWindowLong(Application.Handle, GWL_EXSTYLE);
  2045. if AVisible then
  2046. ExStyle := ExStyle and not WS_EX_TOOLWINDOW
  2047. else
  2048. ExStyle := ExStyle or WS_EX_TOOLWINDOW;
  2049. SetWindowLong(Application.Handle, GWL_EXSTYLE, ExStyle);
  2050. if AVisible then
  2051. { Show and activate when becoming visible }
  2052. ShowWindow(Application.Handle, SW_SHOW)
  2053. else
  2054. SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
  2055. SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  2056. end;
  2057. end;
  2058. procedure LogCompatibilityMode;
  2059. var
  2060. S: String;
  2061. begin
  2062. S := GetEnv('__COMPAT_LAYER');
  2063. if S <> '' then
  2064. LogFmt('Compatibility mode: %s (%s)', [SYesNo[True], S]);
  2065. end;
  2066. procedure LogWindowsVersion;
  2067. var
  2068. SP: String;
  2069. begin
  2070. if NTServicePackLevel <> 0 then begin
  2071. SP := ' SP' + IntToStr(Hi(NTServicePackLevel));
  2072. if Lo(NTServicePackLevel) <> 0 then
  2073. SP := SP + '.' + IntToStr(Lo(NTServicePackLevel));
  2074. end;
  2075. LogFmt('Windows version: %u.%u.%u%s (NT platform: %s)', [WindowsVersion shr 24,
  2076. (WindowsVersion shr 16) and $FF, WindowsVersion and $FFFF, SP, SYesNo[True]]);
  2077. LogFmt('64-bit Windows: %s', [SYesNo[IsWin64]]);
  2078. LogFmt('Processor architecture: %s', [SetupProcessorArchitectureNames[ProcessorArchitecture]]);
  2079. if IsAdmin then
  2080. Log('User privileges: Administrative')
  2081. else if IsPowerUserOrAdmin then
  2082. Log('User privileges: Power User')
  2083. else
  2084. Log('User privileges: None');
  2085. end;
  2086. function GetMessageBoxResultText(const AResult: Integer): String;
  2087. const
  2088. IDTRYAGAIN = 10;
  2089. IDCONTINUE = 11;
  2090. begin
  2091. case AResult of
  2092. IDOK: Result := 'OK';
  2093. IDCANCEL: Result := 'Cancel';
  2094. IDABORT: Result := 'Abort';
  2095. IDRETRY: Result := 'Retry';
  2096. IDIGNORE: Result := 'Ignore';
  2097. IDYES: Result := 'Yes';
  2098. IDNO: Result := 'No';
  2099. IDTRYAGAIN: Result := 'Try Again';
  2100. IDCONTINUE: Result := 'Continue';
  2101. else
  2102. Result := IntToStr(AResult);
  2103. end;
  2104. end;
  2105. function GetButtonsText(const Buttons: Cardinal): String;
  2106. const
  2107. { We don't use this type, but end users are liable to in [Code] }
  2108. MB_CANCELTRYCONTINUE = $00000006;
  2109. begin
  2110. case Buttons and MB_TYPEMASK of
  2111. MB_OK: Result := 'OK';
  2112. MB_OKCANCEL: Result := 'OK/Cancel';
  2113. MB_ABORTRETRYIGNORE: Result := 'Abort/Retry/Ignore';
  2114. MB_YESNOCANCEL: Result := 'Yes/No/Cancel';
  2115. MB_YESNO: Result := 'Yes/No';
  2116. MB_RETRYCANCEL: Result := 'Retry/Cancel';
  2117. MB_CANCELTRYCONTINUE: Result := 'Cancel/Try Again/Continue';
  2118. else
  2119. Result := IntToStr(Buttons and MB_TYPEMASK);
  2120. end;
  2121. end;
  2122. procedure LogSuppressedMessageBox(const Text: PChar; const Buttons: Cardinal;
  2123. const Default: Integer);
  2124. begin
  2125. Log(Format('Defaulting to %s for suppressed message box (%s):' + SNewLine,
  2126. [GetMessageBoxResultText(Default), GetButtonsText(Buttons)]) + Text);
  2127. end;
  2128. procedure LogMessageBox(const Text: PChar; const Buttons: Cardinal);
  2129. begin
  2130. Log(Format('Message box (%s):' + SNewLine,
  2131. [GetButtonsText(Buttons)]) + Text);
  2132. end;
  2133. function LoggedAppMessageBox(const Text, Caption: PChar; const Flags: Longint;
  2134. const Suppressible: Boolean; const Default: Integer): Integer;
  2135. begin
  2136. if InitSuppressMsgBoxes and Suppressible then begin
  2137. LogSuppressedMessageBox(Text, Flags, Default);
  2138. Result := Default;
  2139. end else begin
  2140. LogMessageBox(Text, Flags);
  2141. Result := AppMessageBox(Text, Caption, Flags);
  2142. if Result <> 0 then
  2143. LogFmt('User chose %s.', [GetMessageBoxResultText(Result)])
  2144. else
  2145. Log('AppMessageBox failed.');
  2146. end;
  2147. end;
  2148. function LoggedMsgBox(const Text, Caption: String; const Typ: TMsgBoxType;
  2149. const Buttons: Cardinal; const Suppressible: Boolean; const Default: Integer): Integer;
  2150. begin
  2151. if InitSuppressMsgBoxes and Suppressible then begin
  2152. LogSuppressedMessageBox(PChar(Text), Buttons, Default);
  2153. Result := Default;
  2154. end else begin
  2155. LogMessageBox(PChar(Text), Buttons);
  2156. Result := MsgBox(Text, Caption, Typ, Buttons);
  2157. if Result <> 0 then
  2158. LogFmt('User chose %s.', [GetMessageBoxResultText(Result)])
  2159. else
  2160. Log('MsgBox failed.');
  2161. end;
  2162. end;
  2163. function LoggedTaskDialogMsgBox(const Icon, Instruction, Text, Caption: String;
  2164. const Typ: TMsgBoxType; const Buttons: Cardinal; const ButtonLabels: array of String;
  2165. const ShieldButton: Integer; const Suppressible: Boolean; const Default: Integer;
  2166. const VerificationText: String = ''; const pfVerificationFlagChecked: PBOOL = nil): Integer;
  2167. begin
  2168. if InitSuppressMsgBoxes and Suppressible then begin
  2169. LogSuppressedMessageBox(PChar(Text), Buttons, Default);
  2170. Result := Default;
  2171. end else begin
  2172. LogMessageBox(PChar(Text), Buttons);
  2173. Result := TaskDialogMsgBox(Icon, Instruction, Text,
  2174. Caption, Typ, Buttons, ButtonLabels, ShieldButton, VerificationText, pfVerificationFlagChecked);
  2175. if Result <> 0 then begin
  2176. LogFmt('User chose %s.', [GetMessageBoxResultText(Result)]);
  2177. if pfVerificationFlagChecked <> nil then
  2178. LogFmt('User chose %s for the verification.', [SYesNo[pfVerificationFlagChecked^]]);
  2179. end else
  2180. Log('TaskDialogMsgBox failed.');
  2181. end;
  2182. end;
  2183. procedure RestartComputerFromThisProcess;
  2184. begin
  2185. RestartInitiatedByThisProcess := True;
  2186. { Note: Depending on the OS, RestartComputer may not return if successful }
  2187. if not RestartComputer then begin
  2188. { Hack for when called from RespawnSetupElevated: re-show the
  2189. application's taskbar button }
  2190. ShowWindow(Application.Handle, SW_SHOW);
  2191. { If another app denied the shutdown, we probably lost the foreground;
  2192. try to take it back. (Note: Application.BringToFront can't be used
  2193. because we have no visible forms, and MB_SETFOREGROUND doesn't make
  2194. the app's taskbar button blink.) }
  2195. SetForegroundWindow(Application.Handle);
  2196. LoggedMsgBox(SetupMessages[msgErrorRestartingComputer], '', mbError,
  2197. MB_OK, True, IDOK);
  2198. end;
  2199. end;
  2200. procedure RespawnSetupElevated(const AParams: String);
  2201. { Starts a new, elevated Setup(Ldr) process and waits until it terminates.
  2202. Does not return; either calls Halt or raises an exception. }
  2203. var
  2204. Cancelled: Boolean;
  2205. Server: TSpawnServer;
  2206. ParamNotifyWnd: HWND;
  2207. RespawnResults: record
  2208. ExitCode: DWORD;
  2209. NotifyRestartRequested: Boolean;
  2210. NotifyNewLanguage: Integer;
  2211. end;
  2212. begin
  2213. { Hide the taskbar button }
  2214. SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
  2215. SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  2216. Cancelled := False;
  2217. try
  2218. Server := TSpawnServer.Create;
  2219. try
  2220. if SetupNotifyWndPresent then
  2221. ParamNotifyWnd := SetupNotifyWnd
  2222. else
  2223. ParamNotifyWnd := Server.Wnd;
  2224. RespawnSelfElevated(SetupLdrOriginalFilename,
  2225. Format('/SPAWNWND=$%x /NOTIFYWND=$%x ', [Server.Wnd, ParamNotifyWnd]) +
  2226. AParams, RespawnResults.ExitCode);
  2227. RespawnResults.NotifyRestartRequested := Server.NotifyRestartRequested;
  2228. RespawnResults.NotifyNewLanguage := Server.NotifyNewLanguage;
  2229. finally
  2230. Server.Free;
  2231. end;
  2232. except
  2233. { If the user clicked Cancel on the dialog, halt with special exit code }
  2234. if ExceptObject is EAbort then
  2235. Cancelled := True
  2236. else begin
  2237. { Otherwise, re-show the taskbar button and re-raise }
  2238. ShowWindow(Application.Handle, SW_SHOW);
  2239. raise;
  2240. end;
  2241. end;
  2242. if Cancelled then
  2243. Halt(ecCancelledBeforeInstall);
  2244. if not SetupNotifyWndPresent then begin
  2245. { In the UseSetupLdr=no case, there is no notify window handle to pass to
  2246. RespawnSelfElevated, so it hosts one itself. Process the results. }
  2247. try
  2248. if (RespawnResults.NotifyNewLanguage >= 0) and
  2249. (RespawnResults.NotifyNewLanguage < Entries[seLanguage].Count) then
  2250. SetActiveLanguage(RespawnResults.NotifyNewLanguage);
  2251. if RespawnResults.NotifyRestartRequested then begin
  2252. { Note: Depending on the OS, this may not return if successful }
  2253. RestartComputerFromThisProcess;
  2254. end;
  2255. except
  2256. { In the unlikely event that something above raises an exception, handle
  2257. it here so the right exit code will still be returned below }
  2258. ShowWindow(Application.Handle, SW_SHOW);
  2259. Application.HandleException(nil);
  2260. end;
  2261. end;
  2262. Halt(RespawnResults.ExitCode);
  2263. end;
  2264. procedure InitializeCommonVars;
  2265. { Initializes variables shared between Setup and Uninstall }
  2266. begin
  2267. IsAdmin := IsAdminLoggedOn;
  2268. IsPowerUserOrAdmin := IsAdmin or IsPowerUserLoggedOn;
  2269. Randomize;
  2270. end;
  2271. procedure InitializeAdminInstallMode(const AAdminInstallMode: Boolean);
  2272. { Initializes IsAdminInstallMode and other global variables that depend on it }
  2273. const
  2274. RootKeys: array[Boolean] of HKEY = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE);
  2275. begin
  2276. LogFmt('Administrative install mode: %s', [SYesNo[AAdminInstallMode]]);
  2277. IsAdminInstallMode := AAdminInstallMode;
  2278. InstallModeRootKey := RootKeys[AAdminInstallMode];
  2279. LogFmt('Install mode root key: %s', [GetRegRootKeyName(InstallModeRootKey)]);
  2280. end;
  2281. procedure Initialize64BitInstallMode(const A64BitInstallMode: Boolean);
  2282. { Initializes Is64BitInstallMode and other global variables that depend on it }
  2283. begin
  2284. Is64BitInstallMode := A64BitInstallMode;
  2285. InstallDefaultDisableFsRedir := A64BitInstallMode;
  2286. ScriptFuncDisableFsRedir := A64BitInstallMode;
  2287. if A64BitInstallMode then
  2288. InstallDefaultRegView := rv64Bit
  2289. else
  2290. InstallDefaultRegView := rv32Bit;
  2291. end;
  2292. procedure Log64BitInstallMode;
  2293. begin
  2294. LogFmt('64-bit install mode: %s', [SYesNo[Is64BitInstallMode]]);
  2295. end;
  2296. procedure InitializeSetup;
  2297. { Initializes various vars used by the setup. This is called in the project
  2298. source. }
  2299. var
  2300. DecompressorDLL, DecryptDLL: TMemoryStream;
  2301. function ExtractLongWord(var S: String): LongWord;
  2302. var
  2303. P: Integer;
  2304. begin
  2305. P := PathPos(',', S);
  2306. if P = 0 then
  2307. raise Exception.Create('ExtractLongWord: Missing comma');
  2308. Result := LongWord(StrToInt(Copy(S, 1, P-1)));
  2309. Delete(S, 1, P);
  2310. end;
  2311. function ArchitecturesToStr(const Architectures: TSetupProcessorArchitectures): String;
  2312. procedure AppendLine(var S: String; const L: String);
  2313. begin
  2314. if S <> '' then
  2315. S := S + #13#10 + L
  2316. else
  2317. S := L;
  2318. end;
  2319. var
  2320. I: TSetupProcessorArchitecture;
  2321. begin
  2322. Result := '';
  2323. for I := Low(I) to High(I) do
  2324. if I in Architectures then
  2325. AppendLine(Result, SetupProcessorArchitectureNames[I]);
  2326. end;
  2327. procedure AbortInit(const Msg: TSetupMessageID);
  2328. begin
  2329. LoggedMsgBox(SetupMessages[Msg], '', mbCriticalError, MB_OK, True, IDOK);
  2330. Abort;
  2331. end;
  2332. procedure AbortInitFmt1(const Msg: TSetupMessageID; const Arg1: String);
  2333. begin
  2334. LoggedMsgBox(FmtSetupMessage(Msg, [Arg1]), '', mbCriticalError, MB_OK, True, IDOK);
  2335. Abort;
  2336. end;
  2337. procedure AbortInitServicePackRequired(const ServicePack: Word);
  2338. begin
  2339. LoggedMsgBox(FmtSetupMessage(msgWindowsServicePackRequired, ['Windows',
  2340. IntToStr(Hi(ServicePack))]), '', mbCriticalError, MB_OK, True, IDOK);
  2341. Abort;
  2342. end;
  2343. procedure ReadFileIntoStream(const Stream: TStream;
  2344. const R: TCompressedBlockReader);
  2345. type
  2346. PBuffer = ^TBuffer;
  2347. TBuffer = array[0..8191] of Byte;
  2348. var
  2349. Buf: PBuffer;
  2350. BytesLeft, Bytes: Longint;
  2351. begin
  2352. New(Buf);
  2353. try
  2354. R.Read(BytesLeft, SizeOf(BytesLeft));
  2355. while BytesLeft > 0 do begin
  2356. Bytes := BytesLeft;
  2357. if Bytes > SizeOf(Buf^) then Bytes := SizeOf(Buf^);
  2358. R.Read(Buf^, Bytes);
  2359. Stream.WriteBuffer(Buf^, Bytes);
  2360. Dec(BytesLeft, Bytes);
  2361. end;
  2362. finally
  2363. Dispose(Buf);
  2364. end;
  2365. end;
  2366. function ReadWizardImage(const R: TCompressedBlockReader): TBitmap;
  2367. var
  2368. MemStream: TMemoryStream;
  2369. begin
  2370. MemStream := TMemoryStream.Create;
  2371. try
  2372. ReadFileIntoStream(MemStream, R);
  2373. MemStream.Seek(0, soFromBeginning);
  2374. Result := TBitmap.Create;
  2375. Result.AlphaFormat := TAlphaFormat(SetupHeader.WizardImageAlphaFormat);
  2376. Result.LoadFromStream(MemStream);
  2377. finally
  2378. MemStream.Free;
  2379. end;
  2380. end;
  2381. procedure LoadDecompressorDLL;
  2382. var
  2383. Filename: String;
  2384. begin
  2385. Filename := AddBackslash(TempInstallDir) + '_isetup\_isdecmp.dll';
  2386. SaveStreamToTempFile(DecompressorDLL, Filename);
  2387. FreeAndNil(DecompressorDLL);
  2388. DecompressorDLLHandle := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
  2389. if DecompressorDLLHandle = 0 then
  2390. InternalError(Format('Failed to load DLL "%s"', [Filename]));
  2391. case SetupHeader.CompressMethod of
  2392. cmZip:
  2393. if not ZlibInitDecompressFunctions(DecompressorDLLHandle) then
  2394. InternalError('ZlibInitDecompressFunctions failed');
  2395. cmBzip:
  2396. if not BZInitDecompressFunctions(DecompressorDLLHandle) then
  2397. InternalError('BZInitDecompressFunctions failed');
  2398. end;
  2399. end;
  2400. procedure LoadDecryptDLL;
  2401. var
  2402. Filename: String;
  2403. begin
  2404. Filename := AddBackslash(TempInstallDir) + '_isetup\_iscrypt.dll';
  2405. SaveStreamToTempFile(DecryptDLL, Filename);
  2406. FreeAndNil(DecryptDLL);
  2407. DecryptDLLHandle := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
  2408. if DecryptDLLHandle = 0 then
  2409. InternalError(Format('Failed to load DLL "%s"', [Filename]));
  2410. if not ArcFourInitFunctions(DecryptDLLHandle) then
  2411. InternalError('ISCryptInitFunctions failed');
  2412. end;
  2413. var
  2414. Reader: TCompressedBlockReader;
  2415. procedure ReadEntriesWithoutVersion(const EntryType: TEntryType;
  2416. const Count: Integer; const Size: Integer);
  2417. var
  2418. I: Integer;
  2419. P: Pointer;
  2420. begin
  2421. Entries[EntryType].Capacity := Count;
  2422. for I := 0 to Count-1 do begin
  2423. P := AllocMem(Size);
  2424. SECompressedBlockRead(Reader, P^, Size, EntryStrings[EntryType],
  2425. EntryAnsiStrings[EntryType]);
  2426. Entries[EntryType].Add(P);
  2427. end;
  2428. end;
  2429. procedure ReadEntries(const EntryType: TEntryType; const Count: Integer;
  2430. const Size: Integer; const MinVersionOfs, OnlyBelowVersionOfs: Integer);
  2431. var
  2432. I: Integer;
  2433. P: Pointer;
  2434. begin
  2435. if Debugging then begin
  2436. OriginalEntryIndexes[EntryType] := TList.Create;
  2437. OriginalEntryIndexes[EntryType].Capacity := Count;
  2438. end;
  2439. Entries[EntryType].Capacity := Count;
  2440. for I := 0 to Count-1 do begin
  2441. P := AllocMem(Size);
  2442. SECompressedBlockRead(Reader, P^, Size, EntryStrings[EntryType],
  2443. EntryAnsiStrings[Entrytype]);
  2444. if (MinVersionOfs = -1) or
  2445. (InstallOnThisVersion(TSetupVersionData((@PByteArray(P)[MinVersionOfs])^),
  2446. TSetupVersionData((@PByteArray(P)[OnlyBelowVersionOfs])^)) = irInstall) then begin
  2447. Entries[EntryType].Add(P);
  2448. if Debugging then
  2449. OriginalEntryIndexes[EntryType].Add(Pointer(I));
  2450. end
  2451. else
  2452. SEFreeRec(P, EntryStrings[EntryType], EntryAnsiStrings[EntryType]);
  2453. end;
  2454. end;
  2455. function HandleInitPassword(const NeedPassword: Boolean): Boolean;
  2456. { Handles InitPassword and returns the updated value of NeedPassword }
  2457. { Also see Wizard.CheckPassword }
  2458. var
  2459. S: String;
  2460. PasswordOk: Boolean;
  2461. begin
  2462. Result := NeedPassword;
  2463. if NeedPassword and (InitPassword <> '') then begin
  2464. PasswordOk := False;
  2465. S := InitPassword;
  2466. if shPassword in SetupHeader.Options then
  2467. PasswordOk := TestPassword(S);
  2468. if not PasswordOk and (CodeRunner <> nil) then
  2469. PasswordOk := CodeRunner.RunBooleanFunctions('CheckPassword', [S], bcTrue, False, PasswordOk);
  2470. if PasswordOk then begin
  2471. Result := False;
  2472. if shEncryptionUsed in SetupHeader.Options then
  2473. FileExtractor.CryptKey := S;
  2474. end;
  2475. end;
  2476. end;
  2477. procedure SetupInstallMode;
  2478. begin
  2479. if InitVerySilent then
  2480. InstallMode := imVerySilent
  2481. else if InitSilent then
  2482. InstallMode := imSilent;
  2483. if InstallMode <> imNormal then begin
  2484. if InstallMode = imVerySilent then begin
  2485. Application.ShowMainForm := False;
  2486. SetTaskbarButtonVisibility(False);
  2487. end;
  2488. SetupHeader.Options := SetupHeader.Options - [shWindowVisible];
  2489. end;
  2490. end;
  2491. function RecurseExternalGetSizeOfFiles(const DisableFsRedir: Boolean;
  2492. const SearchBaseDir, SearchSubDir, SearchWildcard: String;
  2493. const SourceIsWildcard: Boolean; const RecurseSubDirs: Boolean): Integer64;
  2494. var
  2495. SearchFullPath: String;
  2496. H: THandle;
  2497. FindData: TWin32FindData;
  2498. I: Integer64;
  2499. begin
  2500. SearchFullPath := SearchBaseDir + SearchSubDir + SearchWildcard;
  2501. Result.Hi := 0;
  2502. Result.Lo := 0;
  2503. H := FindFirstFileRedir(DisableFsRedir, SearchFullPath, FindData);
  2504. if H <> INVALID_HANDLE_VALUE then begin
  2505. repeat
  2506. if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = 0 then begin
  2507. if SourceIsWildcard then
  2508. if FindData.dwFileAttributes and FILE_ATTRIBUTE_HIDDEN <> 0 then
  2509. Continue;
  2510. I.Hi := FindData.nFileSizeHigh;
  2511. I.Lo := FindData.nFileSizeLow;
  2512. Inc6464(Result, I);
  2513. end;
  2514. until not FindNextFile(H, FindData);
  2515. Windows.FindClose(H);
  2516. end;
  2517. if RecurseSubDirs then begin
  2518. H := FindFirstFileRedir(DisableFsRedir, SearchBaseDir + SearchSubDir + '*', FindData);
  2519. if H <> INVALID_HANDLE_VALUE then begin
  2520. try
  2521. repeat
  2522. if IsRecurseableDirectory(FindData) then begin
  2523. I := RecurseExternalGetSizeOfFiles(DisableFsRedir, SearchBaseDir,
  2524. SearchSubDir + FindData.cFileName + '\', SearchWildcard,
  2525. SourceIsWildcard, RecurseSubDirs);
  2526. Inc6464(Result, I);
  2527. end;
  2528. until not FindNextFile(H, FindData);
  2529. finally
  2530. Windows.FindClose(H);
  2531. end;
  2532. end;
  2533. end;
  2534. end;
  2535. { Also see Install.pas }
  2536. function ExistingInstallationAt(const RootKey: HKEY; const SubkeyName: String): Boolean;
  2537. var
  2538. K: HKEY;
  2539. begin
  2540. if RegOpenKeyExView(InstallDefaultRegView, RootKey, PChar(SubkeyName), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  2541. Result := True;
  2542. RegCloseKey(K);
  2543. end else
  2544. Result := False;
  2545. end;
  2546. procedure HandlePrivilegesRequiredOverrides(var ExtraRespawnParam: String);
  2547. var
  2548. ExistingAtAdminInstallMode, ExistingAtNonAdminInstallMode, DesireAnInstallMode, DesireAdminInstallMode: Boolean;
  2549. SubkeyName, AppName: String;
  2550. begin
  2551. if HasInitPrivilegesRequired and (proCommandLine in SetupHeader.PrivilegesRequiredOverridesAllowed) then begin
  2552. SetupHeader.PrivilegesRequired := InitPrivilegesRequired;
  2553. { We don't need to set ExtraRespawnParam since the existing command line
  2554. already contains the needed parameters and it will automatically be
  2555. passed on to any respawned Setup(Ldr). }
  2556. end else if proDialog in SetupHeader.PrivilegesRequiredOverridesAllowed then begin
  2557. if shUsePreviousPrivileges in SetupHeader.Options then begin
  2558. { Note: if proDialog is used and UsePreviousPrivileges is set to "yes"
  2559. then the compiler does not allow AppId to include constants but we
  2560. should still call ExpandConst to handle any '{{'. }
  2561. SubkeyName := GetUninstallRegSubkeyName(GetUninstallRegKeyBaseName(ExpandConst(SetupHeader.AppID)));
  2562. ExistingAtAdminInstallMode := ExistingInstallationAt(HKEY_LOCAL_MACHINE, SubkeyName);
  2563. ExistingAtNonAdminInstallMode := ExistingInstallationAt(HKEY_CURRENT_USER, SubkeyName);
  2564. end else begin
  2565. ExistingAtAdminInstallMode := False;
  2566. ExistingAtNonAdminInstallMode := False;
  2567. end;
  2568. DesireAnInstallMode := True;
  2569. DesireAdminInstallMode := False; { Silence compiler }
  2570. if ExistingAtAdminInstallMode and not ExistingAtNonAdminInstallMode then
  2571. DesireAdminInstallMode := True
  2572. else if not ExistingAtAdminInstallMode and ExistingAtNonAdminInstallMode then
  2573. DesireAdminInstallMode := False
  2574. else if not InitSuppressMsgBoxes then begin
  2575. { Ask user. Doesn't log since logging hasn't started yet. Also doesn't
  2576. use ExpandedAppName since it isn't set yet. Afterwards we need to tell
  2577. any respawned Setup(Ldr) about the user choice (and avoid asking again).
  2578. Will use the command line parameter for this. Allowing proDialog forces
  2579. allowing proCommandLine, so we can count on the parameter to work. }
  2580. if shAppNameHasConsts in SetupHeader.Options then
  2581. AppName := PathChangeExt(PathExtractName(SetupLdrOriginalFilename), '')
  2582. else
  2583. AppName := SetupHeader.AppName;
  2584. if SetupHeader.PrivilegesRequired = prLowest then begin
  2585. case TaskDialogMsgBox('MAINICON', SetupMessages[msgPrivilegesRequiredOverrideInstruction],
  2586. FmtSetupMessage(msgPrivilegesRequiredOverrideText2, [AppName]),
  2587. SetupMessages[msgPrivilegesRequiredOverrideTitle], mbInformation, MB_YESNOCANCEL,
  2588. [SetupMessages[msgPrivilegesRequiredOverrideCurrentUserRecommended], SetupMessages[msgPrivilegesRequiredOverrideAllUsers]], IDNO) of
  2589. IDYES: DesireAdminInstallMode := False;
  2590. IDNO: DesireAdminInstallMode := True;
  2591. IDCANCEL: Abort;
  2592. end;
  2593. end else begin
  2594. case TaskDialogMsgBox('MAINICON', SetupMessages[msgPrivilegesRequiredOverrideInstruction],
  2595. FmtSetupMessage(msgPrivilegesRequiredOverrideText1, [AppName]),
  2596. SetupMessages[msgPrivilegesRequiredOverrideTitle], mbInformation, MB_YESNOCANCEL,
  2597. [SetupMessages[msgPrivilegesRequiredOverrideAllUsersRecommended], SetupMessages[msgPrivilegesRequiredOverrideCurrentUser]], IDYES) of
  2598. IDYES: DesireAdminInstallMode := True;
  2599. IDNO: DesireAdminInstallMode := False;
  2600. IDCANCEL: Abort;
  2601. end;
  2602. end;
  2603. end else
  2604. DesireAnInstallMode := False; { No previous found and msgboxes are suppressed, just keep things as they are. }
  2605. if DesireAnInstallMode then begin
  2606. if DesireAdminInstallMode then begin
  2607. SetupHeader.PrivilegesRequired := prAdmin;
  2608. ExtraRespawnParam := '/ALLUSERS';
  2609. end else begin
  2610. SetupHeader.PrivilegesRequired := prLowest;
  2611. ExtraRespawnParam := '/CURRENTUSER';
  2612. end;
  2613. end;
  2614. end;
  2615. end;
  2616. var
  2617. ParamName, ParamValue: String;
  2618. ParamIsAutomaticInternal: Boolean;
  2619. StartParam: Integer;
  2620. I, N: Integer;
  2621. IsRespawnedProcess, EnableLogging, WantToSuppressMsgBoxes, Res: Boolean;
  2622. DebugWndValue: HWND;
  2623. LogFilename: String;
  2624. SetupFilename: String;
  2625. SetupFile: TFile;
  2626. TestID: TSetupID;
  2627. NameAndVersionMsg: String;
  2628. NextAllowedLevel: Integer;
  2629. LastShownComponentEntry, ComponentEntry: PSetupComponentEntry;
  2630. MinimumTypeSpace: Integer64;
  2631. SourceWildcard: String;
  2632. ExpandedSetupMutex, ExtraRespawnParam, RespawnParams: String;
  2633. begin
  2634. InitializeCommonVars;
  2635. { NewParamsForCode will hold all params except automatic internal ones like /SL5= and /DEBUGWND=
  2636. Also see Uninstall.ProcessCommandLine }
  2637. NewParamsForCode.Add(NewParamStr(0));
  2638. { Based on SetupLdr or not?
  2639. Parameters for launching SetupLdr-based installation are:
  2640. /SL5="<handle to SetupLdr's notify window>,<setup 0 data offset>,
  2641. <setup 1 data offset>,<original exe filename>"
  2642. }
  2643. SplitNewParamStr(1, ParamName, ParamValue);
  2644. if CompareText(ParamName, '/SL5=') = 0 then begin
  2645. StartParam := 2;
  2646. SetupLdrMode := True;
  2647. SetupNotifyWnd := ExtractLongWord(ParamValue);
  2648. SetupNotifyWndPresent := True;
  2649. SetupLdrOffset0 := ExtractLongWord(ParamValue);
  2650. SetupLdrOffset1 := ExtractLongWord(ParamValue);
  2651. SetupLdrOriginalFilename := ParamValue;
  2652. end
  2653. else begin
  2654. StartParam := 1;
  2655. SetupLdrOriginalFilename := NewParamStr(0);
  2656. end;
  2657. SourceDir := PathExtractDir(SetupLdrOriginalFilename);
  2658. IsRespawnedProcess := False;
  2659. EnableLogging := False;
  2660. WantToSuppressMsgBoxes := False;
  2661. DebugWndValue := 0;
  2662. for I := StartParam to NewParamCount do begin
  2663. SplitNewParamStr(I, ParamName, ParamValue);
  2664. ParamIsAutomaticInternal := False;
  2665. if CompareText(ParamName, '/Log') = 0 then begin
  2666. EnableLogging := True;
  2667. LogFilename := '';
  2668. end else if CompareText(ParamName, '/Log=') = 0 then begin
  2669. EnableLogging := True;
  2670. LogFilename := ParamValue;
  2671. end else if CompareText(ParamName, '/Silent') = 0 then
  2672. InitSilent := True
  2673. else if CompareText(ParamName, '/VerySilent') = 0 then
  2674. InitVerySilent := True
  2675. else if CompareText(ParamName, '/NoRestart') = 0 then
  2676. InitNoRestart := True
  2677. else if CompareText(ParamName, '/CloseApplications') = 0 then
  2678. InitCloseApplications := True
  2679. else if CompareText(ParamName, '/NoCloseApplications') = 0 then
  2680. InitNoCloseApplications := True
  2681. else if CompareText(ParamName, '/ForceCloseApplications') = 0 then
  2682. InitForceCloseApplications := True
  2683. else if CompareText(ParamName, '/NoForceCloseApplications') = 0 then
  2684. InitNoForceCloseApplications := True
  2685. else if CompareText(ParamName, '/LogCloseApplications') = 0 then
  2686. InitLogCloseApplications := True
  2687. else if CompareText(ParamName, '/RestartApplications') = 0 then
  2688. InitRestartApplications := True
  2689. else if CompareText(ParamName, '/NoRestartApplications') = 0 then
  2690. InitNoRestartApplications := True
  2691. else if CompareText(ParamName, '/NoIcons') = 0 then
  2692. InitNoIcons := True
  2693. else if CompareText(ParamName, '/NoCancel') = 0 then
  2694. InitNoCancel := True
  2695. else if CompareText(ParamName, '/Lang=') = 0 then
  2696. InitLang := ParamValue
  2697. else if CompareText(ParamName, '/Type=') = 0 then
  2698. InitSetupType := ParamValue
  2699. else if CompareText(ParamName, '/Components=') = 0 then begin
  2700. InitComponentsSpecified := True;
  2701. SetStringsFromCommaString(InitComponents, SlashesToBackslashes(ParamValue));
  2702. end else if CompareText(ParamName, '/Tasks=') = 0 then begin
  2703. InitDeselectAllTasks := True;
  2704. SetStringsFromCommaString(InitTasks, SlashesToBackslashes(ParamValue));
  2705. end else if CompareText(ParamName, '/MergeTasks=') = 0 then begin
  2706. InitDeselectAllTasks := False;
  2707. SetStringsFromCommaString(InitTasks, SlashesToBackslashes(ParamValue));
  2708. end else if CompareText(ParamName, '/LoadInf=') = 0 then
  2709. InitLoadInf := PathExpand(ParamValue)
  2710. else if CompareText(ParamName, '/SaveInf=') = 0 then
  2711. InitSaveInf := PathExpand(ParamValue)
  2712. else if CompareText(ParamName, '/DIR=') = 0 then
  2713. InitDir := ParamValue
  2714. else if CompareText(ParamName, '/GROUP=') = 0 then
  2715. InitProgramGroup := ParamValue
  2716. else if CompareText(ParamName, '/Password=') = 0 then
  2717. InitPassword := ParamValue
  2718. else if CompareText(ParamName, '/RestartExitCode=') = 0 then
  2719. InitRestartExitCode := StrToIntDef(ParamValue, 0)
  2720. else if CompareText(ParamName, '/SuppressMsgBoxes') = 0 then
  2721. WantToSuppressMsgBoxes := True
  2722. else if CompareText(ParamName, '/DETACHEDMSG') = 0 then { for debugging }
  2723. DetachedUninstMsgFile := True
  2724. else if CompareText(ParamName, '/SPAWNWND=') = 0 then begin
  2725. ParamIsAutomaticInternal := True; { sent by RespawnSetupElevated }
  2726. IsRespawnedProcess := True;
  2727. InitializeSpawnClient(StrToInt(ParamValue));
  2728. end else if CompareText(ParamName, '/NOTIFYWND=') = 0 then begin
  2729. ParamIsAutomaticInternal := True; { sent by RespawnSetupElevated }
  2730. { /NOTIFYWND= takes precedence over any previously set SetupNotifyWnd }
  2731. SetupNotifyWnd := StrToInt(ParamValue);
  2732. SetupNotifyWndPresent := True;
  2733. end else if CompareText(ParamName, '/DebugSpawnServer') = 0 then { for debugging }
  2734. EnterSpawnServerDebugMode { does not return }
  2735. else if CompareText(ParamName, '/DEBUGWND=') = 0 then begin
  2736. ParamIsAutomaticInternal := True; { sent by TCompileForm.StartProcess }
  2737. DebugWndValue := StrToInt(ParamValue);
  2738. end else if CompareText(ParamName, '/ALLUSERS') = 0 then begin
  2739. InitPrivilegesRequired := prAdmin;
  2740. HasInitPrivilegesRequired := True;
  2741. end else if CompareText(ParamName, '/CURRENTUSER') = 0 then begin
  2742. InitPrivilegesRequired := prLowest;
  2743. HasInitPrivilegesRequired := True;
  2744. end;
  2745. if not ParamIsAutomaticInternal then
  2746. NewParamsForCode.Add(NewParamStr(I));
  2747. end;
  2748. if InitLoadInf <> '' then
  2749. LoadInf(InitLoadInf, WantToSuppressMsgBoxes);
  2750. if WantToSuppressMsgBoxes and (InitSilent or InitVerySilent) then
  2751. InitSuppressMsgBoxes := True;
  2752. { Assign some default messages that may be used before the messages are read }
  2753. SetupMessages[msgSetupFileMissing] := SSetupFileMissing;
  2754. SetupMessages[msgSetupFileCorrupt] := SSetupFileCorrupt;
  2755. SetupMessages[msgSetupFileCorruptOrWrongVer] := SSetupFileCorruptOrWrongVer;
  2756. { Read setup-0.bin, or from EXE }
  2757. if not SetupLdrMode then begin
  2758. SetupFilename := PathChangeExt(SetupLdrOriginalFilename, '') + '-0.bin';
  2759. if not NewFileExists(SetupFilename) then
  2760. AbortInitFmt1(msgSetupFileMissing, PathExtractName(SetupFilename));
  2761. end
  2762. else
  2763. SetupFilename := SetupLdrOriginalFilename;
  2764. SetupFile := TFile.Create(SetupFilename, fdOpenExisting, faRead, fsRead);
  2765. try
  2766. SetupFile.Seek(SetupLdrOffset0);
  2767. if SetupFile.Read(TestID, SizeOf(TestID)) <> SizeOf(TestID) then
  2768. AbortInit(msgSetupFileCorruptOrWrongVer);
  2769. if TestID <> SetupID then
  2770. AbortInit(msgSetupFileCorruptOrWrongVer);
  2771. try
  2772. Reader := TCompressedBlockReader.Create(SetupFile, TLZMA1Decompressor);
  2773. try
  2774. { Header }
  2775. SECompressedBlockRead(Reader, SetupHeader, SizeOf(SetupHeader),
  2776. SetupHeaderStrings, SetupHeaderAnsiStrings);
  2777. { Language entries }
  2778. ReadEntriesWithoutVersion(seLanguage, SetupHeader.NumLanguageEntries,
  2779. SizeOf(TSetupLanguageEntry));
  2780. { CustomMessage entries }
  2781. ReadEntriesWithoutVersion(seCustomMessage, SetupHeader.NumCustomMessageEntries,
  2782. SizeOf(TSetupCustomMessageEntry));
  2783. { Permission entries }
  2784. ReadEntriesWithoutVersion(sePermission, SetupHeader.NumPermissionEntries,
  2785. SizeOf(TSetupPermissionEntry));
  2786. { Type entries }
  2787. ReadEntries(seType, SetupHeader.NumTypeEntries, SizeOf(TSetupTypeEntry),
  2788. Integer(@PSetupTypeEntry(nil).MinVersion),
  2789. Integer(@PSetupTypeEntry(nil).OnlyBelowVersion));
  2790. ActivateDefaultLanguage;
  2791. { Set Is64BitInstallMode if we're on Win64 and the processor architecture is
  2792. one on which a "64-bit mode" install should be performed. Doing this early
  2793. so that UsePreviousPrivileges knows where to look. Will log later. }
  2794. if ProcessorArchitecture in SetupHeader.ArchitecturesInstallIn64BitMode then begin
  2795. if not IsWin64 then begin
  2796. { A 64-bit processor was detected and 64-bit install mode was requested,
  2797. but IsWin64 is False, indicating required WOW64 APIs are not present }
  2798. AbortInit(msgWindowsVersionNotSupported);
  2799. end;
  2800. Initialize64BitInstallMode(True);
  2801. end
  2802. else
  2803. Initialize64BitInstallMode(False);
  2804. HandlePrivilegesRequiredOverrides(ExtraRespawnParam);
  2805. { Start a new, elevated Setup(Ldr) process if needed }
  2806. if not IsRespawnedProcess and
  2807. NeedToRespawnSelfElevated(not (SetupHeader.PrivilegesRequired in [prNone, prLowest]),
  2808. SetupHeader.PrivilegesRequired <> prLowest) then begin
  2809. FreeAndNil(Reader);
  2810. FreeAndNil(SetupFile);
  2811. RespawnParams := GetCmdTailEx(StartParam);
  2812. if ExtraRespawnParam <> '' then
  2813. RespawnParams := RespawnParams + ' ' + ExtraRespawnParam;
  2814. RespawnSetupElevated(RespawnParams);
  2815. { Note: RespawnSetupElevated does not return; it either calls Halt
  2816. or raises an exception. }
  2817. end;
  2818. { Application.Handle is now known to be the main window. Set the shutdown block reason. }
  2819. ShutdownBlockReasonCreate(Application.Handle, SetupMessages[msgWizardInstalling]);
  2820. { Initialize debug client }
  2821. if DebugWndValue <> 0 then
  2822. SetDebugWnd(DebugWndValue, False);
  2823. { Initialize logging }
  2824. if EnableLogging or (shSetupLogging in SetupHeader.Options) then begin
  2825. try
  2826. if LogFilename = '' then
  2827. StartLogging('Setup')
  2828. else
  2829. StartLoggingWithFixedFilename(LogFilename);
  2830. except
  2831. on E: Exception do begin
  2832. E.Message := 'Error creating log file:' + SNewLine2 + E.Message;
  2833. raise;
  2834. end;
  2835. end;
  2836. end;
  2837. Log('Setup version: ' + SetupTitle + ' version ' + SetupVersion);
  2838. Log('Original Setup EXE: ' + SetupLdrOriginalFilename);
  2839. Log('Setup command line: ' + GetCmdTail);
  2840. LogCompatibilityMode;
  2841. LogWindowsVersion;
  2842. NeedPassword := shPassword in SetupHeader.Options;
  2843. NeedSerial := False;
  2844. NeedsRestart := shAlwaysRestart in SetupHeader.Options;
  2845. { Component entries }
  2846. ReadEntries(seComponent, SetupHeader.NumComponentEntries, SizeOf(TSetupComponentEntry),
  2847. -1, -1);
  2848. { Task entries }
  2849. ReadEntries(seTask, SetupHeader.NumTaskEntries, SizeOf(TSetupTaskEntry),
  2850. -1, -1);
  2851. { Dir entries }
  2852. ReadEntries(seDir, SetupHeader.NumDirEntries, SizeOf(TSetupDirEntry),
  2853. Integer(@PSetupDirEntry(nil).MinVersion),
  2854. Integer(@PSetupDirEntry(nil).OnlyBelowVersion));
  2855. { File entries }
  2856. ReadEntries(seFile, SetupHeader.NumFileEntries, SizeOf(TSetupFileEntry),
  2857. Integer(@PSetupFileEntry(nil).MinVersion),
  2858. Integer(@PSetupFileEntry(nil).OnlyBelowVersion));
  2859. { Icon entries }
  2860. ReadEntries(seIcon, SetupHeader.NumIconEntries, SizeOf(TSetupIconEntry),
  2861. Integer(@PSetupIconEntry(nil).MinVersion),
  2862. Integer(@PSetupIconEntry(nil).OnlyBelowVersion));
  2863. { INI entries }
  2864. ReadEntries(seIni, SetupHeader.NumIniEntries, SizeOf(TSetupIniEntry),
  2865. Integer(@PSetupIniEntry(nil).MinVersion),
  2866. Integer(@PSetupIniEntry(nil).OnlyBelowVersion));
  2867. { Registry entries }
  2868. ReadEntries(seRegistry, SetupHeader.NumRegistryEntries, SizeOf(TSetupRegistryEntry),
  2869. Integer(@PSetupRegistryEntry(nil).MinVersion),
  2870. Integer(@PSetupRegistryEntry(nil).OnlyBelowVersion));
  2871. { InstallDelete entries }
  2872. ReadEntries(seInstallDelete, SetupHeader.NumInstallDeleteEntries, SizeOf(TSetupDeleteEntry),
  2873. Integer(@PSetupDeleteEntry(nil).MinVersion),
  2874. Integer(@PSetupDeleteEntry(nil).OnlyBelowVersion));
  2875. { UninstallDelete entries }
  2876. ReadEntries(seUninstallDelete, SetupHeader.NumUninstallDeleteEntries, SizeOf(TSetupDeleteEntry),
  2877. Integer(@PSetupDeleteEntry(nil).MinVersion),
  2878. Integer(@PSetupDeleteEntry(nil).OnlyBelowVersion));
  2879. { Run entries }
  2880. ReadEntries(seRun, SetupHeader.NumRunEntries, SizeOf(TSetupRunEntry),
  2881. Integer(@PSetupRunEntry(nil).MinVersion),
  2882. Integer(@PSetupRunEntry(nil).OnlyBelowVersion));
  2883. { UninstallRun entries }
  2884. ReadEntries(seUninstallRun, SetupHeader.NumUninstallRunEntries, SizeOf(TSetupRunEntry),
  2885. Integer(@PSetupRunEntry(nil).MinVersion),
  2886. Integer(@PSetupRunEntry(nil).OnlyBelowVersion));
  2887. { Wizard image }
  2888. Reader.Read(N, SizeOf(LongInt));
  2889. for I := 0 to N-1 do
  2890. WizardImages.Add(ReadWizardImage(Reader));
  2891. Reader.Read(N, SizeOf(LongInt));
  2892. for I := 0 to N-1 do
  2893. WizardSmallImages.Add(ReadWizardImage(Reader));
  2894. { Decompressor DLL }
  2895. DecompressorDLL := nil;
  2896. if SetupHeader.CompressMethod in [cmZip, cmBzip] then begin
  2897. DecompressorDLL := TMemoryStream.Create;
  2898. ReadFileIntoStream(DecompressorDLL, Reader);
  2899. end;
  2900. { Decryption DLL }
  2901. DecryptDLL := nil;
  2902. if shEncryptionUsed in SetupHeader.Options then begin
  2903. DecryptDLL := TMemoryStream.Create;
  2904. ReadFileIntoStream(DecryptDLL, Reader);
  2905. end;
  2906. finally
  2907. Reader.Free;
  2908. end;
  2909. Reader := TCompressedBlockReader.Create(SetupFile, TLZMA1Decompressor);
  2910. try
  2911. { File location entries }
  2912. ReadEntriesWithoutVersion(seFileLocation, SetupHeader.NumFileLocationEntries,
  2913. SizeOf(TSetupFileLocationEntry));
  2914. finally
  2915. Reader.Free;
  2916. end;
  2917. except
  2918. on ECompressDataError do
  2919. AbortInit(msgSetupFileCorrupt);
  2920. end;
  2921. finally
  2922. SetupFile.Free;
  2923. end;
  2924. InitializeAdminInstallMode(IsAdmin and (SetupHeader.PrivilegesRequired <> prLowest));
  2925. Log64BitInstallMode;
  2926. { Show "Select Language" dialog if necessary - requires "64-bit mode" to be
  2927. initialized else it might query the previous language from the wrong registry
  2928. view }
  2929. if Entries[seLanguage].Count > 1 then begin
  2930. if ShowLanguageDialog and not InitSilent and not InitVerySilent then begin
  2931. if not AskForLanguage then
  2932. Abort;
  2933. end else if not MatchedLangParameter and (shUsePreviousLanguage in SetupHeader.Options) then begin
  2934. { Replicate the dialog's UsePreviousLanguage functionality. }
  2935. { Note: if UsePreviousLanguage is set to "yes" then the compiler does not
  2936. allow AppId to include constants but we should still call ExpandConst
  2937. to handle any '{{'. }
  2938. I := GetPreviousLanguage(ExpandConst(SetupHeader.AppId));
  2939. if I <> -1 then
  2940. SetActiveLanguage(I);
  2941. end;
  2942. end;
  2943. { Check processor architecture }
  2944. if (SetupHeader.ArchitecturesAllowed <> []) and
  2945. not(ProcessorArchitecture in SetupHeader.ArchitecturesAllowed) then
  2946. AbortInitFmt1(msgOnlyOnTheseArchitectures, ArchitecturesToStr(SetupHeader.ArchitecturesAllowed));
  2947. { Check Windows version }
  2948. case InstallOnThisVersion(SetupHeader.MinVersion, SetupHeader.OnlyBelowVersion) of
  2949. irInstall: ;
  2950. irServicePackTooLow:
  2951. AbortInitServicePackRequired(SetupHeader.MinVersion.NTServicePack);
  2952. else
  2953. AbortInit(msgWindowsVersionNotSupported);
  2954. end;
  2955. { Check if the user lacks the required privileges }
  2956. case SetupHeader.PrivilegesRequired of
  2957. prPowerUser:
  2958. if not IsPowerUserOrAdmin then AbortInit(msgPowerUserPrivilegesRequired);
  2959. prAdmin:
  2960. if not IsAdmin then AbortInit(msgAdminPrivilegesRequired);
  2961. end;
  2962. { Init main constants, not depending on shfolder.dll/_shfoldr.dll }
  2963. InitMainNonSHFolderConsts;
  2964. { Create temporary directory and extract 64-bit helper EXE if necessary }
  2965. CreateTempInstallDir;
  2966. { Load system's "shfolder.dll" or extract "_shfoldr.dll" to TempInstallDir, and load it }
  2967. LoadSHFolderDLL;
  2968. { Extract "_isdecmp.dll" to TempInstallDir, and load it }
  2969. if SetupHeader.CompressMethod in [cmZip, cmBzip] then
  2970. LoadDecompressorDLL;
  2971. { Extract "_iscrypt.dll" to TempInstallDir, and load it }
  2972. if shEncryptionUsed in SetupHeader.Options then
  2973. LoadDecryptDLL;
  2974. { Start RestartManager session }
  2975. if InitCloseApplications or
  2976. ((shCloseApplications in SetupHeader.Options) and not InitNoCloseApplications) then begin
  2977. InitRestartManagerLibrary;
  2978. { Note from Old New Thing: "The RmStartSession function doesn't properly
  2979. null-terminate the session key <...>. To work around this bug, we pre-fill
  2980. the buffer with null characters <...>." Our key is pre-filled too since
  2981. it's global. }
  2982. if UseRestartManager and (RmStartSession(@RmSessionHandle, 0, RmSessionKey) = ERROR_SUCCESS) then begin
  2983. RmSessionStarted := True;
  2984. SetStringsFromCommaString(CloseApplicationsFilterList, SetupHeader.CloseApplicationsFilter);
  2985. end;
  2986. end;
  2987. { Set install mode }
  2988. SetupInstallMode;
  2989. { Load and initialize code }
  2990. if SetupHeader.CompiledCodeText <> '' then begin
  2991. CodeRunner := TScriptRunner.Create();
  2992. try
  2993. CodeRunner.NamingAttribute := CodeRunnerNamingAttribute;
  2994. CodeRunner.OnLog := CodeRunnerOnLog;
  2995. CodeRunner.OnLogFmt := CodeRunnerOnLogFmt;
  2996. CodeRunner.OnDllImport := CodeRunnerOnDllImport;
  2997. CodeRunner.OnDebug := CodeRunnerOnDebug;
  2998. CodeRunner.OnDebugIntermediate := CodeRunnerOnDebugIntermediate;
  2999. CodeRunner.OnException := CodeRunnerOnException;
  3000. CodeRunner.LoadScript(SetupHeader.CompiledCodeText, DebugClientCompiledCodeDebugInfo);
  3001. if not NeedPassword then
  3002. NeedPassword := CodeRunner.FunctionExists('CheckPassword', True);
  3003. NeedPassword := HandleInitPassword(NeedPassword);
  3004. if not NeedSerial then
  3005. NeedSerial := CodeRunner.FunctionExists('CheckSerial', True);
  3006. except
  3007. { Don't let DeinitSetup see a partially-initialized CodeRunner }
  3008. FreeAndNil(CodeRunner);
  3009. raise;
  3010. end;
  3011. try
  3012. Res := CodeRunner.RunBooleanFunctions('InitializeSetup', [''], bcFalse, False, True);
  3013. except
  3014. Log('InitializeSetup raised an exception (fatal).');
  3015. raise;
  3016. end;
  3017. if not Res then begin
  3018. Log('InitializeSetup returned False; aborting.');
  3019. Abort;
  3020. end;
  3021. end
  3022. else
  3023. NeedPassword := HandleInitPassword(NeedPassword);
  3024. { Expand AppName, AppVerName, and AppCopyright now since they're used often,
  3025. especially by the background window painting. }
  3026. ExpandedAppName := ExpandConst(SetupHeader.AppName);
  3027. if SetupHeader.AppVerName <> '' then
  3028. ExpandedAppVerName := ExpandConst(SetupHeader.AppVerName)
  3029. else begin
  3030. if not GetCustomMessageValue('NameAndVersion', NameAndVersionMsg) then
  3031. NameAndVersionMsg := '%1 %2'; { just in case }
  3032. ExpandedAppVerName := FmtMessage(PChar(NameAndVersionMsg),
  3033. [ExpandedAppName, ExpandConst(SetupHeader.AppVersion)]);
  3034. end;
  3035. ExpandedAppCopyright := ExpandConst(SetupHeader.AppCopyright);
  3036. ExpandedAppMutex := ExpandConst(SetupHeader.AppMutex);
  3037. ExpandedSetupMutex := ExpandConst(SetupHeader.SetupMutex);
  3038. { Update the shutdown block reason now that we have ExpandedAppName. }
  3039. ShutdownBlockReasonCreate(Application.Handle,
  3040. FmtSetupMessage1(msgShutdownBlockReasonInstallingApp, ExpandedAppName));
  3041. { Check if app is running }
  3042. while CheckForMutexes(ExpandedAppMutex) do
  3043. if LoggedMsgBox(FmtSetupMessage1(msgSetupAppRunningError, ExpandedAppName),
  3044. SetupMessages[msgSetupAppTitle], mbError, MB_OKCANCEL, True, IDCANCEL) <> IDOK then
  3045. Abort;
  3046. { Check if Setup is running and if not create mutexes }
  3047. while CheckForMutexes(ExpandedSetupMutex) do
  3048. if LoggedMsgBox(FmtSetupMessage1(msgSetupAppRunningError, SetupMessages[msgSetupAppTitle]),
  3049. SetupMessages[msgSetupAppTitle], mbError, MB_OKCANCEL, True, IDCANCEL) <> IDOK then
  3050. Abort;
  3051. CreateMutexes(ExpandedSetupMutex);
  3052. { Remove types that fail their 'languages' or 'check'. Can't do this earlier
  3053. because the InitializeSetup call above can't be done earlier. }
  3054. for I := 0 to Entries[seType].Count-1 do begin
  3055. if not ShouldProcessEntry(nil, nil, '', '', PSetupTypeEntry(Entries[seType][I]).Languages, PSetupTypeEntry(Entries[seType][I]).Check) then begin
  3056. SEFreeRec(Entries[seType][I], EntryStrings[seType], EntryAnsiStrings[seType]);
  3057. { Don't delete it yet so that the entries can be processed sequentially }
  3058. Entries[seType][I] := nil;
  3059. end;
  3060. end;
  3061. { Delete the nil-ed items now }
  3062. Entries[seType].Pack();
  3063. { Remove components }
  3064. NextAllowedLevel := 0;
  3065. LastShownComponentEntry := nil;
  3066. for I := 0 to Entries[seComponent].Count-1 do begin
  3067. ComponentEntry := PSetupComponentEntry(Entries[seComponent][I]);
  3068. if (ComponentEntry.Level <= NextAllowedLevel) and
  3069. (InstallOnThisVersion(ComponentEntry.MinVersion, ComponentEntry.OnlyBelowVersion) = irInstall) and
  3070. ShouldProcessEntry(nil, nil, '', '', ComponentEntry.Languages, ComponentEntry.Check) then begin
  3071. NextAllowedLevel := ComponentEntry.Level + 1;
  3072. LastShownComponentEntry := ComponentEntry;
  3073. end
  3074. else begin
  3075. { Not showing }
  3076. if Assigned(LastShownComponentEntry) and
  3077. (ComponentEntry.Level = LastShownComponentEntry.Level) and
  3078. (CompareText(ComponentEntry.Name, LastShownComponentEntry.Name) = 0) then begin
  3079. { It's a duplicate of the last shown item. Leave NextAllowedLevel
  3080. alone, so that any child items that follow can attach to the last
  3081. shown item. }
  3082. end
  3083. else begin
  3084. { Not a duplicate of the last shown item, so the next item must be
  3085. at the same level or less }
  3086. if NextAllowedLevel > ComponentEntry.Level then
  3087. NextAllowedLevel := ComponentEntry.Level;
  3088. { Clear LastShownComponentEntry so that no subsequent item can be
  3089. considered a duplicate of it. Needed in this case:
  3090. foo (shown)
  3091. foo\childA (not shown)
  3092. foo (not shown)
  3093. foo\childB
  3094. "foo\childB" should be hidden, not made a child of "foo" #1. }
  3095. LastShownComponentEntry := nil;
  3096. end;
  3097. Entries[seComponent][I] := nil;
  3098. SEFreeRec(ComponentEntry, EntryStrings[seComponent], EntryAnsiStrings[seComponent]);
  3099. end;
  3100. end;
  3101. Entries[seComponent].Pack();
  3102. { Set misc. variables }
  3103. HasCustomType := False;
  3104. for I := 0 to Entries[seType].Count-1 do begin
  3105. if toIsCustom in PSetupTypeEntry(Entries[seType][I]).Options then begin
  3106. HasCustomType := True;
  3107. Break;
  3108. end;
  3109. end;
  3110. HasComponents := Entries[seComponent].Count <> 0;
  3111. HasIcons := Entries[seIcon].Count <> 0;
  3112. HasTasks := Entries[seTask].Count <> 0;
  3113. { Calculate minimum disk space. If there are setup types, find the smallest
  3114. type and add the size of all files that don't belong to any component. Otherwise
  3115. calculate minimum disk space by adding all of the file's sizes. Also for each
  3116. "external" file, check the file size now, and store it the ExternalSize field
  3117. of the TSetupFileEntry record, except if an ExternalSize was specified by the
  3118. script. }
  3119. MinimumSpace := SetupHeader.ExtraDiskSpaceRequired;
  3120. for I := 0 to Entries[seFile].Count-1 do begin
  3121. with PSetupFileEntry(Entries[seFile][I])^ do begin
  3122. if LocationEntry <> -1 then begin { not an "external" file }
  3123. if Components = '' then { no types or a file that doesn't belong to any component }
  3124. if (Tasks = '') and (Check = '') then {don't count tasks and scripted entries}
  3125. Inc6464(MinimumSpace, PSetupFileLocationEntry(Entries[seFileLocation][LocationEntry])^.OriginalSize)
  3126. end else begin
  3127. if not(foExternalSizePreset in Options) then begin
  3128. try
  3129. if FileType <> ftUserFile then
  3130. SourceWildcard := NewParamStr(0)
  3131. else
  3132. SourceWildcard := ExpandConst(SourceFilename);
  3133. ExternalSize := RecurseExternalGetSizeOfFiles(
  3134. ShouldDisableFsRedirForFileEntry(PSetupFileEntry(Entries[seFile][I])),
  3135. PathExtractPath(SourceWildcard),
  3136. '', PathExtractName(SourceWildcard), IsWildcard(SourceWildcard),
  3137. foRecurseSubDirsExternal in Options);
  3138. except
  3139. { Ignore exceptions. One notable exception we want to ignore is
  3140. the one about "app" not being initialized. }
  3141. end;
  3142. end;
  3143. if Components = '' then { no types or a file that doesn't belong to any component }
  3144. if (Tasks = '') and (Check = '') then {don't count tasks or scripted entries}
  3145. Inc6464(MinimumSpace, ExternalSize);
  3146. end;
  3147. end;
  3148. end;
  3149. for I := 0 to Entries[seComponent].Count-1 do
  3150. with PSetupComponentEntry(Entries[seComponent][I])^ do
  3151. Size := GetSizeOfComponent(Name, ExtraDiskSpaceRequired);
  3152. if Entries[seType].Count > 0 then begin
  3153. for I := 0 to Entries[seType].Count-1 do begin
  3154. with PSetupTypeEntry(Entries[seType][I])^ do begin
  3155. Size := GetSizeOfType(Name, toIsCustom in Options);
  3156. if (I = 0) or (Compare64(Size, MinimumTypeSpace) < 0) then
  3157. MinimumTypeSpace := Size;
  3158. end;
  3159. end;
  3160. Inc6464(MinimumSpace, MinimumTypeSpace);
  3161. end;
  3162. end;
  3163. procedure DeinitSetup(const AllowCustomSetupExitCode: Boolean);
  3164. var
  3165. I: Integer;
  3166. begin
  3167. Log('Deinitializing Setup.');
  3168. if Assigned(CodeRunner) then begin
  3169. if AllowCustomSetupExitCode then begin
  3170. try
  3171. SetupExitCode := CodeRunner.RunIntegerFunctions('GetCustomSetupExitCode',
  3172. [''], bcNonZero, False, SetupExitCode);
  3173. except
  3174. Log('GetCustomSetupExitCode raised an exception.');
  3175. Application.HandleException(nil);
  3176. end;
  3177. end;
  3178. try
  3179. CodeRunner.RunProcedures('DeinitializeSetup', [''], False);
  3180. except
  3181. Log('DeinitializeSetup raised an exception.');
  3182. Application.HandleException(nil);
  3183. end;
  3184. FreeAndNil(CodeRunner);
  3185. end;
  3186. for I := 0 to DeleteFilesAfterInstallList.Count-1 do
  3187. DeleteFileRedir(DeleteFilesAfterInstallList.Objects[I] <> nil,
  3188. DeleteFilesAfterInstallList[I]);
  3189. DeleteFilesAfterInstallList.Clear;
  3190. for I := DeleteDirsAfterInstallList.Count-1 downto 0 do
  3191. RemoveDirectoryRedir(DeleteDirsAfterInstallList.Objects[I] <> nil,
  3192. DeleteDirsAfterInstallList[I]);
  3193. DeleteDirsAfterInstallList.Clear;
  3194. FreeFileExtractor;
  3195. { End RestartManager session }
  3196. if RmSessionStarted then
  3197. RmEndSession(RmSessionHandle);
  3198. { Free the _iscrypt.dll handle }
  3199. if DecryptDLLHandle <> 0 then
  3200. FreeLibrary(DecryptDLLHandle);
  3201. { Free the _isdecmp.dll handle }
  3202. if DecompressorDLLHandle <> 0 then
  3203. FreeLibrary(DecompressorDLLHandle);
  3204. { Free the shfolder.dll handles }
  3205. UnloadSHFolderDLL;
  3206. { Remove TempInstallDir, stopping the 64-bit helper first if necessary }
  3207. RemoveTempInstallDir;
  3208. { An attempt to restart while debugging is most likely an accident;
  3209. don't allow it }
  3210. if RestartSystem and Debugging then begin
  3211. Log('Not restarting Windows because Setup is being run from the debugger.');
  3212. RestartSystem := False;
  3213. end;
  3214. EndDebug;
  3215. ShutdownBlockReasonDestroy(Application.Handle);
  3216. if RestartSystem then begin
  3217. Log('Restarting Windows.');
  3218. if SetupNotifyWndPresent then begin
  3219. { Send a special message back to the first instance telling it to
  3220. restart the system after Setup returns }
  3221. SendNotifyMessage(SetupNotifyWnd, WM_USER + 150, 10000, 0);
  3222. end
  3223. else begin
  3224. { There is no other instance, so initiate the restart ourself.
  3225. Note: Depending on the OS, this may not return if successful. }
  3226. RestartComputerFromThisProcess;
  3227. end;
  3228. end;
  3229. end;
  3230. function BlendRGB(const Color1, Color2: TColor; const Blend: Integer): TColor;
  3231. { Blends Color1 and Color2. Blend must be between 0 and 255; 0 = all Color1,
  3232. 255 = all Color2. }
  3233. type
  3234. TColorBytes = array[0..3] of Byte;
  3235. var
  3236. I: Integer;
  3237. begin
  3238. Result := 0;
  3239. for I := 0 to 2 do
  3240. TColorBytes(Result)[I] := Integer(TColorBytes(Color1)[I] +
  3241. ((TColorBytes(Color2)[I] - TColorBytes(Color1)[I]) * Blend) div 255);
  3242. end;
  3243. function ExitSetupMsgBox: Boolean;
  3244. begin
  3245. Result := LoggedMsgBox(SetupMessages[msgExitSetupMessage], SetupMessages[msgExitSetupTitle],
  3246. mbConfirmation, MB_YESNO or MB_DEFBUTTON2, False, 0) = IDYES;
  3247. end;
  3248. procedure TerminateApp;
  3249. begin
  3250. { Work around shell32 bug: Don't use PostQuitMessage/Application.Terminate
  3251. here.
  3252. When ShellExecute is called with the name of a folder, it internally
  3253. creates a window used for DDE communication with Windows Explorer. After
  3254. ShellExecute returns, this window eventually receives a posted WM_DDE_ACK
  3255. message back from the DDE server (Windows Explorer), and in response, it
  3256. tries to flush the queue of DDE messages by using a PeekMessage loop.
  3257. Problem is, PeekMessage will return WM_QUIT messages posted with
  3258. PostQuitMessage regardless of the message range specified, and the loop was
  3259. not written with this in mind.
  3260. In previous IS versions, this was causing our WM_QUIT message to be eaten
  3261. if Application.Terminate was called very shortly after a shellexec [Run]
  3262. entry was processed (e.g. if DisableFinishedPage=yes).
  3263. A WM_QUIT message posted with PostMessage instead of PostQuitMessage will
  3264. not be returned by a GetMessage/PeekMessage call with a message range that
  3265. does not include WM_QUIT. }
  3266. PostMessage(0, WM_QUIT, 0, 0);
  3267. end;
  3268. { TMainForm }
  3269. constructor TMainForm.Create(AOwner: TComponent);
  3270. var
  3271. SystemMenu: HMenu;
  3272. begin
  3273. inherited;
  3274. InitializeFont;
  3275. if shWindowVisible in SetupHeader.Options then begin
  3276. { Should the main window not be sizable? }
  3277. if not(shWindowShowCaption in SetupHeader.Options) then
  3278. BorderStyle := bsNone
  3279. else
  3280. if not(shWindowResizable in SetupHeader.Options) then
  3281. BorderStyle := bsSingle;
  3282. { Make the main window full-screen. If the window is resizable, limit it
  3283. to just the work area because full-screen resizable windows don't cover
  3284. over the taskbar. }
  3285. BoundsRect := GetRectOfPrimaryMonitor(BorderStyle = bsSizeable);
  3286. { Before maximizing the window, ensure Handle is created now so the correct
  3287. 'restored' position is saved properly }
  3288. HandleNeeded;
  3289. { Maximize the window so that the taskbar is still accessible }
  3290. if shWindowStartMaximized in SetupHeader.Options then
  3291. WindowState := wsMaximized;
  3292. end
  3293. else begin
  3294. Application.ShowMainForm := False;
  3295. end;
  3296. if shDisableWelcomePage in SetupHeader.Options then
  3297. Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppVerName)
  3298. else
  3299. Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppName);
  3300. { Append the 'About Setup' item to the system menu }
  3301. SystemMenu := GetSystemMenu(Handle, False);
  3302. AppendMenu(SystemMenu, MF_SEPARATOR, 0, nil);
  3303. AppendMenu(SystemMenu, MF_STRING, 9999, PChar(SetupMessages[msgAboutSetupMenuItem]));
  3304. Application.HookMainWindow(MainWindowHook);
  3305. if Application.ShowMainForm then
  3306. { Show this form now, so that the focus stays on the wizard form that
  3307. InitializeWizard (called in the .dpr) shows }
  3308. Visible := True;
  3309. end;
  3310. destructor TMainForm.Destroy;
  3311. begin
  3312. Application.UnhookMainWindow(MainWindowHook);
  3313. inherited;
  3314. end;
  3315. procedure TMainForm.WMSysCommand(var Message: TWMSysCommand);
  3316. begin
  3317. if Message.CmdType = 9999 then
  3318. ShowAboutBox
  3319. else
  3320. inherited;
  3321. end;
  3322. procedure TMainForm.WMEraseBkgnd(var Message: TWMEraseBkgnd);
  3323. begin
  3324. { Since the form paints its entire client area in FormPaint, there is
  3325. no need for the VCL to ever erase the client area with the brush color.
  3326. Doing so only slows it down, so this message handler disables that default
  3327. behavior. }
  3328. Message.Result := 0;
  3329. end;
  3330. procedure TMainForm.FormPaint(Sender: TObject);
  3331. var
  3332. C1, C2: TColor;
  3333. CS: TPoint;
  3334. Z: Integer;
  3335. DrawTextFlags: UINT;
  3336. R, R2: TRect;
  3337. begin
  3338. with Canvas do begin
  3339. { Draw the blue background }
  3340. if SetupHeader.BackColor = SetupHeader.BackColor2 then begin
  3341. Brush.Color := SetupHeader.BackColor;
  3342. FillRect(ClientRect);
  3343. end
  3344. else begin
  3345. C1 := ColorToRGB(SetupHeader.BackColor);
  3346. C2 := ColorToRGB(SetupHeader.BackColor2);
  3347. CS := ClientRect.BottomRight;
  3348. for Z := 0 to 255 do begin
  3349. Brush.Color := BlendRGB(C1, C2, Z);
  3350. if not(shBackColorHorizontal in SetupHeader.Options) then
  3351. FillRect(Rect(0, MulDiv(CS.Y, Z, 255), CS.X, MulDiv(CS.Y, Z+1, 255)))
  3352. else
  3353. FillRect(Rect(MulDiv(CS.X, Z, 255), 0, MulDiv(CS.X, Z+1, 255), CS.Y));
  3354. end;
  3355. end;
  3356. { Draw the application name and copyright }
  3357. SetBkMode(Handle, TRANSPARENT);
  3358. DrawTextFlags := DT_WORDBREAK or DT_NOPREFIX or DT_NOCLIP;
  3359. if RightToLeft then
  3360. DrawTextFlags := DrawTextFlags or (DT_RIGHT or DT_RTLREADING);
  3361. SetFontNameSize(Font, LangOptions.TitleFontName,
  3362. LangOptions.TitleFontSize, 'Arial', 29);
  3363. if IsMultiByteString(AnsiString(ExpandedAppName)) then
  3364. { Don't use italics on Japanese characters }
  3365. Font.Style := [fsBold]
  3366. else
  3367. Font.Style := [fsBold, fsItalic];
  3368. R := ClientRect;
  3369. InflateRect(R, -8, -8);
  3370. R2 := R;
  3371. if RightToLeft then
  3372. OffsetRect(R2, -4, 4)
  3373. else
  3374. OffsetRect(R2, 4, 4);
  3375. Font.Color := clBlack;
  3376. DrawText(Handle, PChar(ExpandedAppName), -1, R2, DrawTextFlags);
  3377. Font.Color := clWhite;
  3378. DrawText(Handle, PChar(ExpandedAppName), -1, R, DrawTextFlags);
  3379. DrawTextFlags := DrawTextFlags xor DT_RIGHT;
  3380. SetFontNameSize(Font, LangOptions.CopyrightFontName,
  3381. LangOptions.CopyrightFontSize, 'Arial', 8);
  3382. Font.Style := [];
  3383. R := ClientRect;
  3384. InflateRect(R, -6, -6);
  3385. R2 := R;
  3386. DrawText(Handle, PChar(ExpandedAppCopyright), -1, R2, DrawTextFlags or
  3387. DT_CALCRECT);
  3388. R.Top := R.Bottom - (R2.Bottom - R2.Top);
  3389. R2 := R;
  3390. if RightToLeft then
  3391. OffsetRect(R2, -1, 1)
  3392. else
  3393. OffsetRect(R2, 1, 1);
  3394. Font.Color := clBlack;
  3395. DrawText(Handle, PChar(ExpandedAppCopyright), -1, R2, DrawTextFlags);
  3396. Font.Color := clWhite;
  3397. DrawText(Handle, PChar(ExpandedAppCopyright), -1, R, DrawTextFlags);
  3398. end;
  3399. end;
  3400. procedure TMainForm.FormResize(Sender: TObject);
  3401. begin
  3402. { Needs to redraw the background whenever the form is resized }
  3403. Repaint;
  3404. end;
  3405. procedure TMainForm.ShowAboutBox;
  3406. var
  3407. S: String;
  3408. begin
  3409. { Removing the About box or modifying any existing text inside it is a
  3410. violation of the Inno Setup license agreement; see LICENSE.TXT.
  3411. However, adding additional lines to the end of the About box is
  3412. permitted. }
  3413. S := SetupTitle + ' version ' + SetupVersion + SNewLine;
  3414. if SetupTitle <> 'Inno Setup' then
  3415. S := S + (SNewLine + 'Based on Inno Setup' + SNewLine);
  3416. S := S + ('Copyright (C) 1997-2024 Jordan Russell' + SNewLine +
  3417. 'Portions Copyright (C) 2000-2024 Martijn Laan' + SNewLine +
  3418. 'All rights reserved.' + SNewLine2 +
  3419. 'Inno Setup home page:' + SNewLine +
  3420. 'https://www.innosetup.com/');
  3421. S := S + SNewLine2 + 'RemObjects Pascal Script home page:' + SNewLine +
  3422. 'https://www.remobjects.com/ps';
  3423. if SetupMessages[msgAboutSetupNote] <> '' then
  3424. S := S + SNewLine2 + SetupMessages[msgAboutSetupNote];
  3425. if SetupMessages[msgTranslatorNote] <> '' then
  3426. S := S + SNewLine2 + SetupMessages[msgTranslatorNote];
  3427. StringChangeEx(S, '(C)', #$00A9, True);
  3428. LoggedMsgBox(S, SetupMessages[msgAboutSetupTitle], mbInformation, MB_OK, False, 0);
  3429. end;
  3430. class procedure TMainForm.ShowExceptionMsg(const S: String);
  3431. begin
  3432. Log('Exception message:');
  3433. LoggedAppMessageBox(PChar(S), PChar(Application.Title), MB_OK or MB_ICONSTOP, True, IDOK);
  3434. end;
  3435. class procedure TMainForm.ShowException(Sender: TObject; E: Exception);
  3436. begin
  3437. ShowExceptionMsg(AddPeriod(E.Message));
  3438. end;
  3439. procedure ProcessMessagesProc; far;
  3440. begin
  3441. Application.ProcessMessages;
  3442. end;
  3443. procedure TMainForm.SetStep(const AStep: TSetupStep; const HandleExceptions: Boolean);
  3444. begin
  3445. CurStep := AStep;
  3446. if CodeRunner <> nil then begin
  3447. try
  3448. CodeRunner.RunProcedures('CurStepChanged', [Ord(CurStep)], False);
  3449. except
  3450. if HandleExceptions then begin
  3451. Log('CurStepChanged raised an exception.');
  3452. Application.HandleException(Self);
  3453. end
  3454. else begin
  3455. Log('CurStepChanged raised an exception (fatal).');
  3456. raise;
  3457. end;
  3458. end;
  3459. end;
  3460. end;
  3461. procedure TMainForm.InitializeWizard;
  3462. begin
  3463. WizardForm := TWizardForm.Create(Application);
  3464. if CodeRunner <> nil then begin
  3465. try
  3466. CodeRunner.RunProcedures('InitializeWizard', [''], False);
  3467. except
  3468. Log('InitializeWizard raised an exception (fatal).');
  3469. raise;
  3470. end;
  3471. end;
  3472. WizardForm.FlipSizeAndCenterIfNeeded(shWindowVisible in SetupHeader.Options, MainForm, True);
  3473. WizardForm.SetCurPage(wpWelcome);
  3474. if InstallMode = imNormal then begin
  3475. WizardForm.ClickToStartPage; { this won't go past wpReady }
  3476. SetActiveWindow(Application.Handle); { ensure taskbar button is selected }
  3477. WizardForm.Show;
  3478. end
  3479. else
  3480. WizardForm.ClickThroughPages;
  3481. end;
  3482. function ShouldDisableFsRedirForRunEntry(const RunEntry: PSetupRunEntry): Boolean;
  3483. begin
  3484. Result := InstallDefaultDisableFsRedir;
  3485. if roRun32Bit in RunEntry.Options then
  3486. Result := False;
  3487. if roRun64Bit in RunEntry.Options then begin
  3488. if not IsWin64 then
  3489. InternalError('Cannot run files in 64-bit locations on this version of Windows');
  3490. Result := True;
  3491. end;
  3492. end;
  3493. procedure ProcessRunEntry(const RunEntry: PSetupRunEntry);
  3494. var
  3495. RunAsOriginalUser: Boolean;
  3496. ExpandedFilename, ExpandedParameters: String;
  3497. Wait: TExecWait;
  3498. DisableFsRedir: Boolean;
  3499. ErrorCode: Integer;
  3500. begin
  3501. try
  3502. Log('-- Run entry --');
  3503. RunAsOriginalUser := (roRunAsOriginalUser in RunEntry.Options);
  3504. if RunAsOriginalUser then
  3505. Log('Run as: Original user')
  3506. else
  3507. Log('Run as: Current user');
  3508. if not(roShellExec in RunEntry.Options) then
  3509. Log('Type: Exec')
  3510. else
  3511. Log('Type: ShellExec');
  3512. ExpandedFilename := ExpandConst(RunEntry.Name);
  3513. Log('Filename: ' + ExpandedFilename);
  3514. ExpandedParameters := ExpandConst(RunEntry.Parameters);
  3515. if not(roDontLogParameters in RunEntry.Options) and (ExpandedParameters <> '') then
  3516. Log('Parameters: ' + ExpandedParameters);
  3517. Wait := ewWaitUntilTerminated;
  3518. case RunEntry.Wait of
  3519. rwNoWait: Wait := ewNoWait;
  3520. rwWaitUntilIdle: Wait := ewWaitUntilIdle;
  3521. end;
  3522. if not(roShellExec in RunEntry.Options) then begin
  3523. DisableFsRedir := ShouldDisableFsRedirForRunEntry(RunEntry);
  3524. if not(roSkipIfDoesntExist in RunEntry.Options) or
  3525. NewFileExistsRedir(DisableFsRedir, ExpandedFilename) then begin
  3526. if not InstExecEx(RunAsOriginalUser, DisableFsRedir, ExpandedFilename,
  3527. ExpandedParameters, ExpandConst(RunEntry.WorkingDir),
  3528. Wait, RunEntry.ShowCmd, ProcessMessagesProc, ErrorCode) then
  3529. raise Exception.Create(FmtSetupMessage1(msgErrorExecutingProgram, ExpandedFilename) +
  3530. SNewLine2 + FmtSetupMessage(msgErrorFunctionFailedWithMessage,
  3531. ['CreateProcess', IntToStr(ErrorCode), Win32ErrorString(ErrorCode)]));
  3532. if Wait = ewWaitUntilTerminated then
  3533. Log(Format('Process exit code: %u', [ErrorCode]));
  3534. end
  3535. else
  3536. Log('File doesn''t exist. Skipping.');
  3537. end
  3538. else begin
  3539. if not(roSkipIfDoesntExist in RunEntry.Options) or FileOrDirExists(ExpandedFilename) then begin
  3540. if not InstShellExecEx(RunAsOriginalUser, ExpandConst(RunEntry.Verb),
  3541. ExpandedFilename, ExpandedParameters, ExpandConst(RunEntry.WorkingDir),
  3542. Wait, RunEntry.ShowCmd, ProcessMessagesProc, ErrorCode) then
  3543. raise Exception.Create(FmtSetupMessage1(msgErrorExecutingProgram, ExpandedFilename) +
  3544. SNewLine2 + FmtSetupMessage(msgErrorFunctionFailedWithMessage,
  3545. ['ShellExecuteEx', IntToStr(ErrorCode), Win32ErrorString(ErrorCode)]));
  3546. end
  3547. else
  3548. Log('File/directory doesn''t exist. Skipping.');
  3549. end;
  3550. except
  3551. Application.HandleException(nil);
  3552. end;
  3553. end;
  3554. procedure ShellExecuteAsOriginalUser(hWnd: HWND; Operation, FileName, Parameters, Directory: LPWSTR; ShowCmd: Integer); stdcall;
  3555. var
  3556. ErrorCode: Integer;
  3557. begin
  3558. InstShellExecEx(True, Operation, Filename, Parameters, Directory, ewNoWait, ShowCmd, ProcessMessagesProc, ErrorCode);
  3559. end;
  3560. function TMainForm.Install: Boolean;
  3561. procedure ProcessRunEntries;
  3562. var
  3563. CheckIfRestartNeeded: Boolean;
  3564. ChecksumBefore, ChecksumAfter: TMD5Digest;
  3565. WindowDisabler: TWindowDisabler;
  3566. I: Integer;
  3567. RunEntry: PSetupRunEntry;
  3568. begin
  3569. if Entries[seRun].Count <> 0 then begin
  3570. CheckIfRestartNeeded := (shRestartIfNeededByRun in SetupHeader.Options) and
  3571. not NeedsRestart;
  3572. if CheckIfRestartNeeded then
  3573. ChecksumBefore := MakePendingFileRenameOperationsChecksum;
  3574. WindowDisabler := nil;
  3575. try
  3576. for I := 0 to Entries[seRun].Count-1 do begin
  3577. RunEntry := PSetupRunEntry(Entries[seRun][I]);
  3578. if not(roPostInstall in RunEntry.Options) and
  3579. ShouldProcessRunEntry(WizardComponents, WizardTasks, RunEntry) then begin
  3580. { Disable windows during execution of [Run] entries so that a nice
  3581. "beep" is produced if the user tries clicking on WizardForm }
  3582. if WindowDisabler = nil then
  3583. WindowDisabler := TWindowDisabler.Create;
  3584. if RunEntry.StatusMsg <> '' then begin
  3585. try
  3586. WizardForm.StatusLabel.Caption := ExpandConst(RunEntry.StatusMsg);
  3587. except
  3588. { Don't die if the expansion fails with an exception. Just
  3589. display the exception message, and proceed with the default
  3590. status message. }
  3591. Application.HandleException(Self);
  3592. WizardForm.StatusLabel.Caption := SetupMessages[msgStatusRunProgram];
  3593. end;
  3594. end
  3595. else
  3596. WizardForm.StatusLabel.Caption := SetupMessages[msgStatusRunProgram];
  3597. WizardForm.StatusLabel.Update;
  3598. if roHideWizard in RunEntry.Options then begin
  3599. if WizardForm.Visible and not HideWizard then begin
  3600. HideWizard := True;
  3601. UpdateWizardFormVisibility;
  3602. end;
  3603. end
  3604. else begin
  3605. if HideWizard then begin
  3606. HideWizard := False;
  3607. UpdateWizardFormVisibility;
  3608. end;
  3609. end;
  3610. DebugNotifyEntry(seRun, I);
  3611. NotifyBeforeInstallEntry(RunEntry.BeforeInstall);
  3612. ProcessRunEntry(RunEntry);
  3613. NotifyAfterInstallEntry(RunEntry.AfterInstall);
  3614. end;
  3615. end;
  3616. finally
  3617. if HideWizard then begin
  3618. HideWizard := False;
  3619. UpdateWizardFormVisibility;
  3620. end;
  3621. WindowDisabler.Free;
  3622. if CheckIfRestartNeeded then begin
  3623. ChecksumAfter := MakePendingFileRenameOperationsChecksum;
  3624. if not MD5DigestsEqual(ChecksumBefore, ChecksumAfter) then
  3625. NeedsRestart := True;
  3626. end;
  3627. end;
  3628. Application.BringToFront;
  3629. end;
  3630. end;
  3631. procedure RestartApplications;
  3632. const
  3633. ERROR_FAIL_RESTART = 353;
  3634. var
  3635. Error: DWORD;
  3636. WindowDisabler: TWindowDisabler;
  3637. begin
  3638. if not NeedsRestart then begin
  3639. WizardForm.StatusLabel.Caption := SetupMessages[msgStatusRestartingApplications];
  3640. WizardForm.StatusLabel.Update;
  3641. Log('Attempting to restart applications.');
  3642. { Disable windows during application restart so that a nice
  3643. "beep" is produced if the user tries clicking on WizardForm }
  3644. WindowDisabler := TWindowDisabler.Create;
  3645. try
  3646. Error := RmRestart(RmSessionHandle, 0, nil);
  3647. finally
  3648. WindowDisabler.Free;
  3649. end;
  3650. Application.BringToFront;
  3651. if Error = ERROR_FAIL_RESTART then
  3652. Log('One or more applications could not be restarted.')
  3653. else if Error <> ERROR_SUCCESS then begin
  3654. RmEndSession(RmSessionHandle);
  3655. RmSessionStarted := False;
  3656. LogFmt('RmRestart returned an error: %d', [Error]);
  3657. end;
  3658. end else
  3659. Log('Need to restart Windows, not attempting to restart applications');
  3660. end;
  3661. var
  3662. Succeeded, ChangesEnvironment, ChangesAssociations: Boolean;
  3663. S: String;
  3664. begin
  3665. Result := False;
  3666. try
  3667. if not WizardForm.ValidateDirEdit then
  3668. Abort;
  3669. WizardDirValue := WizardForm.DirEdit.Text;
  3670. if not WizardForm.ValidateGroupEdit then
  3671. Abort;
  3672. WizardGroupValue := WizardForm.GroupEdit.Text;
  3673. WizardNoIcons := WizardForm.NoIconsCheck.Checked;
  3674. WizardSetupType := WizardForm.GetSetupType();
  3675. WizardForm.GetComponents(WizardComponents, WizardDeselectedComponents);
  3676. WizardForm.GetTasks(WizardTasks, WizardDeselectedTasks);
  3677. WizardPreparingYesRadio := WizardForm.PreparingYesRadio.Checked;
  3678. if InitSaveInf <> '' then
  3679. SaveInf(InitSaveInf);
  3680. Application.Restore;
  3681. Update;
  3682. if InstallMode = imSilent then begin
  3683. SetActiveWindow(Application.Handle); { ensure taskbar button is selected }
  3684. WizardForm.Show;
  3685. end;
  3686. WizardForm.Update;
  3687. SetStep(ssInstall, False);
  3688. ChangesEnvironment := EvalDirectiveCheck(SetupHeader.ChangesEnvironment);
  3689. ChangesAssociations := EvalDirectiveCheck(SetupHeader.ChangesAssociations);
  3690. PerformInstall(Succeeded, ChangesEnvironment, ChangesAssociations);
  3691. if not Succeeded then begin
  3692. { The user canceled the install or there was a fatal error }
  3693. TerminateApp;
  3694. Exit;
  3695. end;
  3696. { Can't cancel at any point after PerformInstall, so disable the button }
  3697. WizardForm.CancelButton.Enabled := False;
  3698. ProcessRunEntries;
  3699. if RmDoRestart and
  3700. (InitRestartApplications or
  3701. ((shRestartApplications in SetupHeader.Options) and not InitNoRestartApplications)) then
  3702. RestartApplications;
  3703. SetStep(ssPostInstall, True);
  3704. { Notify Windows of assocations/environment changes *after* ssPostInstall
  3705. since user might set more stuff there }
  3706. if ChangesAssociations then
  3707. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  3708. if ChangesEnvironment then
  3709. RefreshEnvironment;
  3710. if InstallMode <> imNormal then
  3711. WizardForm.Hide;
  3712. LogFmt('Need to restart Windows? %s', [SYesNo[NeedsRestart]]);
  3713. if NeedsRestart and not InitNoRestart then begin
  3714. with WizardForm do begin
  3715. ChangeFinishedLabel(ExpandSetupMessage(msgFinishedRestartLabel));
  3716. YesRadio.Visible := True;
  3717. NoRadio.Visible := True;
  3718. end;
  3719. end else begin
  3720. if CreatedIcon then
  3721. S := ExpandSetupMessage(msgFinishedLabel)
  3722. else
  3723. S := ExpandSetupMessage(msgFinishedLabelNoIcons);
  3724. with WizardForm do begin
  3725. ChangeFinishedLabel(S + SNewLine2 + SetupMessages[msgClickFinish]);
  3726. if not NeedsRestart then begin
  3727. UpdateRunList(WizardComponents, WizardTasks);
  3728. RunList.Visible := RunList.Items.Count > 0;
  3729. end;
  3730. end;
  3731. end;
  3732. if InstallMode = imNormal then begin
  3733. Application.Restore;
  3734. Update;
  3735. end;
  3736. Result := True;
  3737. except
  3738. { If an exception was raised, display the message, then terminate }
  3739. Application.HandleException(Self);
  3740. SetupExitCode := ecNextStepError;
  3741. TerminateApp;
  3742. end;
  3743. end;
  3744. procedure TMainForm.Finish(const FromPreparingPage: Boolean);
  3745. procedure WaitForForegroundLoss;
  3746. function IsForegroundProcess: Boolean;
  3747. var
  3748. W: HWND;
  3749. PID: DWORD;
  3750. begin
  3751. W := GetForegroundWindow;
  3752. Result := False;
  3753. if (W <> 0) and (GetWindowThreadProcessId(W, @PID) <> 0) then
  3754. Result := (PID = GetCurrentProcessId);
  3755. end;
  3756. var
  3757. StartTick: DWORD;
  3758. begin
  3759. StartTick := GetTickCount;
  3760. while IsForegroundProcess do begin
  3761. { Stop if it's taking too long (e.g. if the spawned process never
  3762. displays a window) }
  3763. if Cardinal(GetTickCount - StartTick) >= Cardinal(1000) then
  3764. Break;
  3765. ProcessMessagesProc;
  3766. WaitMessageWithTimeout(10);
  3767. ProcessMessagesProc;
  3768. end;
  3769. end;
  3770. procedure ProcessPostInstallRunEntries;
  3771. var
  3772. WindowDisabler: TWindowDisabler;
  3773. ProcessedNoWait: Boolean;
  3774. I: Integer;
  3775. RunEntry: PSetupRunEntry;
  3776. begin
  3777. WindowDisabler := nil;
  3778. try
  3779. ProcessedNoWait := False;
  3780. with WizardForm do begin
  3781. for I := 0 to RunList.Items.Count-1 do begin
  3782. if RunList.Checked[I] then begin
  3783. { Disable windows before processing the first entry }
  3784. if WindowDisabler = nil then
  3785. WindowDisabler := TWindowDisabler.Create;
  3786. RunEntry := PSetupRunEntry(Entries[seRun][Integer(RunList.ItemObject[I])]);
  3787. DebugNotifyEntry(seRun, Integer(RunList.ItemObject[I]));
  3788. NotifyBeforeInstallEntry(RunEntry.BeforeInstall);
  3789. ProcessRunEntry(RunEntry);
  3790. NotifyAfterInstallEntry(RunEntry.AfterInstall);
  3791. if RunEntry.Wait = rwNoWait then
  3792. ProcessedNoWait := True;
  3793. end;
  3794. end;
  3795. end;
  3796. { Give nowait processes some time to bring themselves to the
  3797. foreground before Setup exits. Without this delay, the application
  3798. underneath Setup can end up coming to the foreground instead.
  3799. (Note: Windows are already disabled at this point.) }
  3800. if ProcessedNoWait then
  3801. WaitForForegroundLoss;
  3802. finally
  3803. WindowDisabler.Free;
  3804. end;
  3805. end;
  3806. var
  3807. S: String;
  3808. begin
  3809. try
  3810. { Deactivate WizardForm so another application doesn't come to the
  3811. foreground when Hide is called. (Needed by WaitForForegroundLoss.) }
  3812. if GetForegroundWindow = WizardForm.Handle then
  3813. SetActiveWindow(Application.Handle);
  3814. WizardForm.Hide;
  3815. if not FromPreparingPage and not NeedsRestart then begin
  3816. ProcessPostInstallRunEntries;
  3817. end else begin
  3818. if FromPreparingPage then
  3819. SetupExitCode := ecPrepareToInstallFailedRestartNeeded
  3820. else if InitRestartExitCode <> 0 then
  3821. SetupExitCode := InitRestartExitCode;
  3822. if InitNoRestart then
  3823. RestartSystem := False
  3824. else begin
  3825. case InstallMode of
  3826. imNormal:
  3827. if FromPreparingPage then
  3828. RestartSystem := WizardForm.PreparingYesRadio.Checked
  3829. else
  3830. RestartSystem := WizardForm.YesRadio.Checked;
  3831. imSilent:
  3832. begin
  3833. if FromPreparingPage then
  3834. S := WizardForm.PrepareToInstallFailureMessage + SNewLine +
  3835. SNewLine + SNewLine + ExpandSetupMessage(msgPrepareToInstallNeedsRestart)
  3836. else
  3837. S := ExpandSetupMessage(msgFinishedRestartMessage);
  3838. RestartSystem :=
  3839. LoggedMsgBox(S, '', mbConfirmation, MB_YESNO, True, IDYES) = IDYES;
  3840. end;
  3841. imVerySilent:
  3842. RestartSystem := True;
  3843. end;
  3844. end;
  3845. if not RestartSystem then
  3846. Log('Will not restart Windows automatically.');
  3847. end;
  3848. SetStep(ssDone, True);
  3849. except
  3850. Application.HandleException(Self);
  3851. SetupExitCode := ecNextStepError;
  3852. end;
  3853. TerminateApp;
  3854. end;
  3855. procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  3856. function ConfirmCancel(const DefaultConfirm: Boolean): Boolean;
  3857. var
  3858. Cancel, Confirm: Boolean;
  3859. begin
  3860. Cancel := True;
  3861. Confirm := DefaultConfirm;
  3862. WizardForm.CallCancelButtonClick(Cancel, Confirm);
  3863. Result := Cancel and (not Confirm or ExitSetupMsgBox);
  3864. end;
  3865. begin
  3866. { Note: Setting CanClose to True causes Application.Terminate to be called;
  3867. we don't want that. }
  3868. CanClose := False;
  3869. if Assigned(WizardForm) and WizardForm.HandleAllocated and
  3870. IsWindowVisible(WizardForm.Handle) and IsWindowEnabled(WizardForm.Handle) and
  3871. WizardForm.CancelButton.CanFocus then begin
  3872. case CurStep of
  3873. ssPreInstall:
  3874. if ConfirmCancel((WizardForm.CurPageID <> wpPreparing) or (WizardForm.PrepareToInstallFailureMessage = '')) then begin
  3875. if WizardForm.CurPageID = wpPreparing then
  3876. SetupExitCode := ecPrepareToInstallFailed
  3877. else
  3878. SetupExitCode := ecCancelledBeforeInstall;
  3879. TerminateApp;
  3880. end;
  3881. ssInstall:
  3882. if (shAllowCancelDuringInstall in SetupHeader.Options) and not InitNoCancel then
  3883. if ConfirmCancel(True) then
  3884. NeedToAbortInstall := True;
  3885. end;
  3886. end;
  3887. end;
  3888. procedure TMainForm.WMGetDlgCode(var Message: TWMGetDlgCode);
  3889. begin
  3890. Message.Result := Message.Result or DLGC_WANTTAB;
  3891. end;
  3892. function EWP(Wnd: HWND; Param: LPARAM): BOOL; stdcall;
  3893. begin
  3894. { Note: GetParent is not used here because the other windows are not
  3895. actually child windows since they don't have WS_CHILD set. }
  3896. if GetWindowLong(Wnd, GWL_HWNDPARENT) <> Param then
  3897. Result := True
  3898. else begin
  3899. Result := False;
  3900. BringWindowToTop(Wnd);
  3901. end;
  3902. end;
  3903. procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
  3904. Shift: TShiftState);
  3905. begin
  3906. { If, for some reason, the user doesn't have a mouse and the main form was
  3907. activated, there would normally be no way to reactivate the child form.
  3908. But this reactivates the form if the user hits a key on the keyboard }
  3909. if not(ssAlt in Shift) then begin
  3910. Key := 0;
  3911. EnumThreadWindows(GetCurrentThreadId, @EWP, Handle);
  3912. end;
  3913. end;
  3914. procedure TMainForm.UpdateWizardFormVisibility;
  3915. var
  3916. ShouldShow: Boolean;
  3917. begin
  3918. { Note: We don't adjust WizardForm.Visible because on Delphi 3+, if all forms
  3919. have Visible set to False, the application taskbar button disappears. }
  3920. if Assigned(WizardForm) and WizardForm.HandleAllocated then begin
  3921. ShouldShow := WizardForm.Showing and not HideWizard and
  3922. not IsIconic(Application.Handle);
  3923. if (GetWindowLong(WizardForm.Handle, GWL_STYLE) and WS_VISIBLE <> 0) <> ShouldShow then begin
  3924. if ShouldShow then
  3925. ShowWindow(WizardForm.Handle, SW_SHOW)
  3926. else
  3927. ShowWindow(WizardForm.Handle, SW_HIDE);
  3928. end;
  3929. end;
  3930. end;
  3931. function TMainForm.MainWindowHook(var Message: TMessage): Boolean;
  3932. var
  3933. IsIcon: Boolean;
  3934. begin
  3935. Result := False;
  3936. case Message.Msg of
  3937. WM_WINDOWPOSCHANGED: begin
  3938. { When the application window is minimized or restored, also hide or
  3939. show WizardForm.
  3940. Note: MainForm is hidden/shown automatically because its owner
  3941. window is Application.Handle. }
  3942. IsIcon := IsIconic(Application.Handle);
  3943. if IsMinimized <> IsIcon then begin
  3944. IsMinimized := IsIcon;
  3945. UpdateWizardFormVisibility;
  3946. end;
  3947. end;
  3948. end;
  3949. end;
  3950. procedure TMainForm.WMShowWindow(var Message: TWMShowWindow);
  3951. begin
  3952. inherited;
  3953. { When showing, ensure WizardForm is the active window, not MainForm }
  3954. if Message.Show and (GetActiveWindow = Handle) and
  3955. Assigned(WizardForm) and WizardForm.HandleAllocated and
  3956. IsWindowVisible(WizardForm.Handle) then
  3957. SetActiveWindow(WizardForm.Handle);
  3958. end;
  3959. procedure InitIsWin64AndProcessorArchitecture;
  3960. const
  3961. PROCESSOR_ARCHITECTURE_INTEL = 0;
  3962. PROCESSOR_ARCHITECTURE_IA64 = 6;
  3963. PROCESSOR_ARCHITECTURE_AMD64 = 9;
  3964. PROCESSOR_ARCHITECTURE_ARM64 = 12;
  3965. IMAGE_FILE_MACHINE_I386 = $014c;
  3966. IMAGE_FILE_MACHINE_IA64 = $0200;
  3967. IMAGE_FILE_MACHINE_AMD64 = $8664;
  3968. IMAGE_FILE_MACHINE_ARM64 = $AA64;
  3969. var
  3970. KernelModule: HMODULE;
  3971. GetNativeSystemInfoFunc: procedure(var lpSystemInfo: TSystemInfo); stdcall;
  3972. IsWow64ProcessFunc: function(hProcess: THandle; var Wow64Process: BOOL): BOOL; stdcall;
  3973. IsWow64Process2Func: function(hProcess: THandle; var pProcessMachine, pNativeMachine: USHORT): BOOL; stdcall;
  3974. ProcessMachine, NativeMachine: USHORT;
  3975. Wow64Process: BOOL;
  3976. SysInfo: TSystemInfo;
  3977. begin
  3978. { The system is considered a "Win64" system if all of the following
  3979. conditions are true:
  3980. 1. One of the following two is true:
  3981. a. IsWow64Process2 is available, and returns True for the current process.
  3982. b. GetNativeSystemInfo is available +
  3983. IsWow64Process is available, and returns True for the current process.
  3984. 2. Wow64DisableWow64FsRedirection is available.
  3985. 3. Wow64RevertWow64FsRedirection is available.
  3986. 4. GetSystemWow64DirectoryA is available.
  3987. 5. RegDeleteKeyExA is available.
  3988. The system does not have to be one of the known 64-bit architectures
  3989. (AMD64, IA64, ARM64) to be considered a "Win64" system. }
  3990. IsWin64 := False;
  3991. KernelModule := GetModuleHandle(kernel32);
  3992. IsWow64Process2Func := GetProcAddress(KernelModule, 'IsWow64Process2');
  3993. if Assigned(IsWow64Process2Func) and
  3994. IsWow64Process2Func(GetCurrentProcess, ProcessMachine, NativeMachine) and
  3995. (ProcessMachine <> IMAGE_FILE_MACHINE_UNKNOWN) then begin
  3996. IsWin64 := True;
  3997. case NativeMachine of
  3998. IMAGE_FILE_MACHINE_I386: ProcessorArchitecture := paX86;
  3999. IMAGE_FILE_MACHINE_IA64: ProcessorArchitecture := paIA64;
  4000. IMAGE_FILE_MACHINE_AMD64: ProcessorArchitecture := paX64;
  4001. IMAGE_FILE_MACHINE_ARM64: ProcessorArchitecture := paARM64;
  4002. else
  4003. ProcessorArchitecture := paUnknown;
  4004. end;
  4005. end else begin
  4006. GetNativeSystemInfoFunc := GetProcAddress(KernelModule, 'GetNativeSystemInfo');
  4007. if Assigned(GetNativeSystemInfoFunc) then begin
  4008. GetNativeSystemInfoFunc(SysInfo);
  4009. IsWow64ProcessFunc := GetProcAddress(KernelModule, 'IsWow64Process');
  4010. if Assigned(IsWow64ProcessFunc) and
  4011. IsWow64ProcessFunc(GetCurrentProcess, Wow64Process) and
  4012. Wow64Process then
  4013. IsWin64 := True;
  4014. end else
  4015. GetSystemInfo(SysInfo);
  4016. case SysInfo.wProcessorArchitecture of
  4017. PROCESSOR_ARCHITECTURE_INTEL: ProcessorArchitecture := paX86;
  4018. PROCESSOR_ARCHITECTURE_IA64: ProcessorArchitecture := paIA64;
  4019. PROCESSOR_ARCHITECTURE_AMD64: ProcessorArchitecture := paX64;
  4020. PROCESSOR_ARCHITECTURE_ARM64: ProcessorArchitecture := paARM64;
  4021. else
  4022. ProcessorArchitecture := paUnknown;
  4023. end;
  4024. end;
  4025. if IsWin64 and
  4026. not (AreFsRedirectionFunctionsAvailable and
  4027. (GetProcAddress(KernelModule, 'GetSystemWow64DirectoryA') <> nil) and
  4028. (GetProcAddress(GetModuleHandle(advapi32), 'RegDeleteKeyExA') <> nil)) then
  4029. IsWin64 := False;
  4030. end;
  4031. procedure InitWindowsVersion;
  4032. type
  4033. TOSVersionInfoEx = packed record
  4034. dwOSVersionInfoSize: DWORD;
  4035. dwMajorVersion: DWORD;
  4036. dwMinorVersion: DWORD;
  4037. dwBuildNumber: DWORD;
  4038. dwPlatformId: DWORD;
  4039. szCSDVersion: array[0..127] of Char;
  4040. wServicePackMajor: Word;
  4041. wServicePackMinor: Word;
  4042. wSuiteMask: Word;
  4043. wProductType: Byte;
  4044. wReserved: Byte;
  4045. end;
  4046. var
  4047. OSVersionInfo: TOSVersionInfo;
  4048. OSVersionInfoEx: TOSVersionInfoEx;
  4049. begin
  4050. OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
  4051. if GetVersionEx(OSVersionInfo) then begin
  4052. WindowsVersion := (Byte(OSVersionInfo.dwMajorVersion) shl 24) or
  4053. (Byte(OSVersionInfo.dwMinorVersion) shl 16) or
  4054. Word(OSVersionInfo.dwBuildNumber);
  4055. { ^ Note: We MUST clip dwBuildNumber to 16 bits for Win9x compatibility }
  4056. OSVersionInfoEx.dwOSVersionInfoSize := SizeOf(OSVersionInfoEx);
  4057. if GetVersionEx(POSVersionInfo(@OSVersionInfoEx)^) then begin
  4058. NTServicePackLevel := (Byte(OSVersionInfoEx.wServicePackMajor) shl 8) or
  4059. Byte(OSVersionInfoEx.wServicePackMinor);
  4060. WindowsProductType := OSVersionInfoEx.wProductType;
  4061. WindowsSuiteMask := OSVersionInfoEx.wSuiteMask;
  4062. end;
  4063. end;
  4064. end;
  4065. procedure CreateEntryLists;
  4066. var
  4067. I: TEntryType;
  4068. begin
  4069. for I := Low(I) to High(I) do
  4070. Entries[I] := TList.Create;
  4071. end;
  4072. procedure FreeEntryLists;
  4073. var
  4074. I: TEntryType;
  4075. List: TList;
  4076. J: Integer;
  4077. P: Pointer;
  4078. begin
  4079. for I := High(I) downto Low(I) do begin
  4080. List := Entries[I];
  4081. if Assigned(List) then begin
  4082. Entries[I] := nil;
  4083. for J := List.Count-1 downto 0 do begin
  4084. P := List[J];
  4085. if EntryStrings[I] <> 0 then
  4086. SEFreeRec(P, EntryStrings[I], EntryAnsiStrings[I])
  4087. else
  4088. FreeMem(P);
  4089. end;
  4090. List.Free;
  4091. end;
  4092. FreeAndNil(OriginalEntryIndexes[I]);
  4093. end;
  4094. end;
  4095. procedure FreeWizardImages;
  4096. var
  4097. I: Integer;
  4098. begin
  4099. for I := WizardImages.Count-1 downto 0 do
  4100. TBitmap(WizardImages[I]).Free;
  4101. FreeAndNil(WizardImages);
  4102. for I := WizardSmallImages.Count-1 downto 0 do
  4103. TBitmap(WizardSmallImages[I]).Free;
  4104. FreeAndNil(WizardSmallImages);
  4105. end;
  4106. initialization
  4107. InitIsWin64AndProcessorArchitecture;
  4108. InitWindowsVersion;
  4109. InitComponents := TStringList.Create();
  4110. InitTasks := TStringList.Create();
  4111. NewParamsForCode := TStringList.Create();
  4112. WizardComponents := TStringList.Create();
  4113. WizardDeselectedComponents := TStringList.Create();
  4114. WizardTasks := TStringList.Create();
  4115. WizardDeselectedTasks := TStringList.Create();
  4116. CreateEntryLists;
  4117. DeleteFilesAfterInstallList := TStringList.Create;
  4118. DeleteDirsAfterInstallList := TStringList.Create;
  4119. CloseApplicationsFilterList := TStringList.Create;
  4120. WizardImages := TList.Create;
  4121. WizardSmallImages := TList.Create;
  4122. SHGetKnownFolderPathFunc := GetProcAddress(SafeLoadLibrary(AddBackslash(GetSystemDir) + shell32,
  4123. SEM_NOOPENFILEERRORBOX), 'SHGetKnownFolderPath');
  4124. finalization
  4125. FreeWizardImages;
  4126. FreeAndNil(CloseApplicationsFilterList);
  4127. FreeAndNil(DeleteDirsAfterInstallList);
  4128. FreeAndNil(DeleteFilesAfterInstallList);
  4129. FreeEntryLists;
  4130. FreeAndNil(WizardDeselectedTasks);
  4131. FreeAndNil(WizardTasks);
  4132. FreeAndNil(WizardDeselectedComponents);
  4133. FreeAndNil(WizardComponents);
  4134. FreeAndNil(NewParamsForCode);
  4135. FreeAndNil(InitTasks);
  4136. FreeAndNil(InitComponents);
  4137. end.