Wizard.pas 114 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003
  1. unit Wizard;
  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. Wizard form
  8. }
  9. interface
  10. {$I VERSION.INC}
  11. uses
  12. Windows, SysUtils, Messages, Classes, Graphics, Controls,
  13. Forms, Dialogs, StdCtrls, ExtCtrls,
  14. SetupForm, Struct, Int64Em, NewCheckListBox, RichEditViewer, NewStaticText,
  15. SetupTypes, NewProgressBar, MsgIDs, PasswordEdit, FolderTreeView, BitmapImage,
  16. NewNotebook, BidiCtrls;
  17. type
  18. TWizardForm = class;
  19. TWizardPage = class;
  20. TWizardPageClass = class of TWizardPage;
  21. TWizardPageStyle = set of (psAlwaysSkip, psNoButtons);
  22. TWizardPageNotifyEvent = procedure(Sender: TWizardPage) of object;
  23. TWizardPageButtonEvent = function(Sender: TWizardPage): Boolean of object;
  24. TWizardPageCancelEvent = procedure(Sender: TWizardPage; var ACancel, AConfirm: Boolean) of object;
  25. TWizardPageShouldSkipEvent = function(Sender: TWizardPage): Boolean of object;
  26. TWizardPage = class(TComponent)
  27. private
  28. FID: Integer;
  29. FOuterNotebookPage: TNewNotebookPage;
  30. FInnerNotebookPage: TNewNotebookPage;
  31. FCaption: String;
  32. FDescription: String;
  33. FOnActivate: TWizardPageNotifyEvent;
  34. FOnBackButtonClick: TWizardPageButtonEvent;
  35. FOnCancelButtonClick: TWizardPageCancelEvent;
  36. FOnNextButtonClick: TWizardPageButtonEvent;
  37. FOnShouldSkipPage: TWizardPageShouldSkipEvent;
  38. FStyle: TWizardPageStyle;
  39. FWizardForm: TWizardForm;
  40. function GetSurface: TNewNotebookPage;
  41. function GetSurfaceColor: TColor;
  42. function GetSurfaceHeight: Integer;
  43. function GetSurfaceWidth: Integer;
  44. procedure SetCaption(const Value: String);
  45. procedure SetDescription(const Value: String);
  46. procedure SyncCaptionAndDescription;
  47. protected
  48. procedure Activate; virtual;
  49. procedure BackButtonClick(var AContinue: Boolean); virtual;
  50. procedure CancelButtonClick(var ACancel, AConfirm: Boolean); virtual;
  51. procedure NextButtonClick(var AContinue: Boolean); virtual;
  52. procedure ShouldSkipPage(var AShouldSkip: Boolean); virtual;
  53. property InnerNotebookPage: TNewNotebookPage read FInnerNotebookPage;
  54. property OuterNotebookPage: TNewNotebookPage read FOuterNotebookPage;
  55. property Style: TWizardPageStyle read FStyle write FStyle;
  56. public
  57. constructor Create(AOwner: TComponent); override;
  58. destructor Destroy; override;
  59. published
  60. property Caption: String read FCaption write SetCaption;
  61. property Description: String read FDescription write SetDescription;
  62. property ID: Integer read FID;
  63. property Surface: TNewNotebookPage read GetSurface;
  64. property SurfaceColor: TColor read GetSurfaceColor;
  65. property SurfaceHeight: Integer read GetSurfaceHeight;
  66. property SurfaceWidth: Integer read GetSurfaceWidth;
  67. property OnActivate: TWizardPageNotifyEvent read FOnActivate write FOnActivate;
  68. property OnBackButtonClick: TWizardPageButtonEvent read FOnBackButtonClick write FOnBackButtonClick;
  69. property OnCancelButtonClick: TWizardPageCancelEvent read FOnCancelButtonClick write FOnCancelButtonClick;
  70. property OnNextButtonClick: TWizardPageButtonEvent read FOnNextButtonClick write FOnNextButtonClick;
  71. property OnShouldSkipPage: TWizardPageShouldSkipEvent read FOnShouldSkipPage write FOnShouldSkipPage;
  72. end;
  73. TWizardForm = class(TSetupForm)
  74. FCancelButton: TNewButton;
  75. FNextButton: TNewButton;
  76. FBackButton: TNewButton;
  77. FOuterNotebook: TNewNotebook;
  78. FInnerNotebook: TNewNotebook;
  79. FWelcomePage: TNewNotebookPage;
  80. FInnerPage: TNewNotebookPage;
  81. FFinishedPage: TNewNotebookPage;
  82. FLicensePage: TNewNotebookPage;
  83. FPasswordPage: TNewNotebookPage;
  84. FInfoBeforePage: TNewNotebookPage;
  85. FUserInfoPage: TNewNotebookPage;
  86. FSelectDirPage: TNewNotebookPage;
  87. FSelectComponentsPage: TNewNotebookPage;
  88. FSelectProgramGroupPage: TNewNotebookPage;
  89. FSelectTasksPage: TNewNotebookPage;
  90. FReadyPage: TNewNotebookPage;
  91. FPreparingPage: TNewNotebookPage;
  92. FInstallingPage: TNewNotebookPage;
  93. FInfoAfterPage: TNewNotebookPage;
  94. FDiskSpaceLabel: TNewStaticText;
  95. FDirEdit: TEdit;
  96. FGroupEdit: TNewEdit;
  97. FNoIconsCheck: TNewCheckBox;
  98. FPasswordLabel: TNewStaticText;
  99. FPasswordEdit: TPasswordEdit;
  100. FPasswordEditLabel: TNewStaticText;
  101. FReadyMemo: TNewMemo;
  102. FTypesCombo: TNewComboBox;
  103. FBevel: TBevel;
  104. FWizardBitmapImage: TBitmapImage;
  105. FWelcomeLabel1: TNewStaticText;
  106. FInfoBeforeMemo: TRichEditViewer;
  107. FInfoBeforeClickLabel: TNewStaticText;
  108. FMainPanel: TPanel;
  109. FBevel1: TBevel;
  110. FPageNameLabel: TNewStaticText;
  111. FPageDescriptionLabel: TNewStaticText;
  112. FWizardSmallBitmapImage: TBitmapImage;
  113. FReadyLabel: TNewStaticText;
  114. FFinishedLabel: TNewStaticText;
  115. FYesRadio: TNewRadioButton;
  116. FNoRadio: TNewRadioButton;
  117. FWizardBitmapImage2: TBitmapImage;
  118. FWelcomeLabel2: TNewStaticText;
  119. FLicenseLabel1: TNewStaticText;
  120. FLicenseMemo: TRichEditViewer;
  121. FInfoAfterMemo: TRichEditViewer;
  122. FInfoAfterClickLabel: TNewStaticText;
  123. FComponentsList: TNewCheckListBox;
  124. FComponentsDiskSpaceLabel: TNewStaticText;
  125. FBeveledLabel: TNewStaticText;
  126. FStatusLabel: TNewStaticText;
  127. FFilenameLabel: TNewStaticText;
  128. FProgressGauge: TNewProgressBar;
  129. FSelectDirLabel: TNewStaticText;
  130. FSelectStartMenuFolderLabel: TNewStaticText;
  131. FSelectComponentsLabel: TNewStaticText;
  132. FSelectTasksLabel: TNewStaticText;
  133. FLicenseAcceptedRadio: TNewRadioButton;
  134. FLicenseNotAcceptedRadio: TNewRadioButton;
  135. FUserInfoNameLabel: TNewStaticText;
  136. FUserInfoNameEdit: TNewEdit;
  137. FUserInfoOrgLabel: TNewStaticText;
  138. FUserInfoOrgEdit: TNewEdit;
  139. FPreparingErrorBitmapImage: TBitmapImage;
  140. FPreparingLabel: TNewStaticText;
  141. FFinishedHeadingLabel: TNewStaticText;
  142. FUserInfoSerialLabel: TNewStaticText;
  143. FUserInfoSerialEdit: TNewEdit;
  144. FTasksList: TNewCheckListBox;
  145. FRunList: TNewCheckListBox;
  146. FDirBrowseButton: TNewButton;
  147. FGroupBrowseButton: TNewButton;
  148. FSelectDirBitmapImage: TBitmapImage;
  149. FSelectGroupBitmapImage: TBitmapImage;
  150. FSelectDirBrowseLabel: TNewStaticText;
  151. FSelectStartMenuFolderBrowseLabel: TNewStaticText;
  152. FPreparingYesRadio: TNewRadioButton;
  153. FPreparingNoRadio: TNewRadioButton;
  154. FPreparingMemo: TNewMemo;
  155. procedure NextButtonClick(Sender: TObject);
  156. procedure BackButtonClick(Sender: TObject);
  157. procedure CancelButtonClick(Sender: TObject);
  158. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  159. procedure NoIconsCheckClick(Sender: TObject);
  160. procedure TypesComboChange(Sender: TObject);
  161. procedure ComponentsListClickCheck(Sender: TObject);
  162. procedure LicenseAcceptedRadioClick(Sender: TObject);
  163. procedure LicenseNotAcceptedRadioClick(Sender: TObject);
  164. procedure UserInfoEditChange(Sender: TObject);
  165. procedure DirBrowseButtonClick(Sender: TObject);
  166. procedure GroupBrowseButtonClick(Sender: TObject);
  167. procedure FormResize(Sender: TObject);
  168. private
  169. { Private declarations }
  170. FPageList: TList;
  171. FCurPageID, FNextPageID: Integer;
  172. ExpandedDefaultDirName, ExpandedDefaultGroupName: String;
  173. FPrevAppDir, PrevGroup, PrevSetupType, PrevUserInfoName, PrevUserInfoOrg, PrevUserInfoSerial: String;
  174. PrevNoIcons: Boolean;
  175. PrevSelectedComponents, PrevDeselectedComponents: TStringList;
  176. PrevSelectedTasks, PrevDeselectedTasks: TStringList;
  177. DisableDirPage, DisableProgramGroupPage: Boolean;
  178. InitialSelectedComponents: TStringList;
  179. InitialSetupTypeIndex: Integer;
  180. HasLargeComponents: Boolean;
  181. DoneWithWizard: Boolean;
  182. PrepareToInstallNeedsRestart: Boolean;
  183. EnableAnchorOuterPagesOnResize: Boolean;
  184. EnableAdjustReadyLabelHeightOnResize: Boolean;
  185. procedure AdjustFocus;
  186. procedure CalcCurrentComponentsSpace;
  187. procedure ChangeReadyLabel(const S: String);
  188. function CheckSerialOk: Boolean;
  189. procedure CreateTaskButtons(const SelectedComponents: TStringList);
  190. procedure FindPreviousData;
  191. function GetPreviousPageID: Integer;
  192. function PrepareToInstall(const WizardComponents, WizardTasks: TStringList): String;
  193. function QueryRestartManager(const WizardComponents, WizardTasks: TStringList): String;
  194. procedure RegisterExistingPage(const ID: Integer;
  195. const AOuterNotebookPage, AInnerNotebookPage: TNewNotebookPage;
  196. const ACaption, ADescription: String);
  197. procedure SelectComponents(const SelectComponents, DeselectComponents: TStringList; const KeepFixedComponents: Boolean); overload;
  198. procedure SelectComponentsFromType(const TypeName: String; const OnlySelectFixedComponents: Boolean);
  199. procedure SelectTasks(const SelectTasks, DeselectTasks: TStringList); overload;
  200. function ShouldSkipPage(const PageID: Integer): Boolean;
  201. procedure UpdateComponentSizes;
  202. procedure UpdateComponentSizesEnum(Index: Integer; HasChildren: Boolean; Ext: LongInt);
  203. procedure UpdateCurPageButtonState;
  204. procedure UpdatePage(const PageID: Integer);
  205. procedure UpdateSelectTasksPage;
  206. procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
  207. protected
  208. procedure CreateParams(var Params: TCreateParams); override;
  209. public
  210. { Public declarations }
  211. PrepareToInstallFailureMessage: String;
  212. constructor Create(AOwner: TComponent); override;
  213. destructor Destroy; override;
  214. procedure AddPage(const APage: TWizardPage; const AfterID: Integer);
  215. function AdjustLabelHeight(const ALabel: TNewStaticText): Integer;
  216. procedure CallCancelButtonClick(var ACancel, AConfirm: Boolean);
  217. procedure ChangeFinishedLabel(const S: String);
  218. procedure ClickToStartPage;
  219. procedure ClickThroughPages;
  220. procedure DirTreeRename(Sender: TCustomFolderTreeView; var NewName: string; var Accept: Boolean);
  221. procedure GetComponents(SelectedComponents, DeselectedComponents: TStringList);
  222. procedure GetSelectedComponents(Components: TStringList; const Descriptions, IndentDescriptions: Boolean);
  223. procedure GetSelectedTasks(Tasks: TStringList; const Descriptions, IndentDescriptions, GroupDescriptions: Boolean);
  224. function GetSetupType: PSetupTypeEntry;
  225. procedure GetTasks(SelectedTasks, DeselectedTasks: TStringList);
  226. procedure GroupTreeRename(Sender: TCustomFolderTreeView; var NewName: string; var Accept: Boolean);
  227. procedure IncTopDecHeight(const AControl: TControl; const Amount: Integer);
  228. function PageFromID(const ID: Integer): TWizardPage;
  229. function PageIndexFromID(const ID: Integer): Integer;
  230. procedure SetCurPage(const NewPageID: Integer);
  231. procedure SelectComponents(const ASelectComponents: TStringList); overload;
  232. procedure SelectTasks(const ASelectTasks: TStringList); overload;
  233. procedure FlipSizeAndCenterIfNeeded(const ACenterInsideControl: Boolean;
  234. const CenterInsideControlCtl: TWinControl; const CenterInsideControlInsideClientArea: Boolean); override;
  235. procedure UpdateRunList(const SelectedComponents, SelectedTasks: TStringList);
  236. function ValidateDirEdit: Boolean;
  237. function ValidateGroupEdit: Boolean;
  238. published
  239. property CurPageID: Integer read FCurPageID;
  240. property PrevAppDir: String read FPrevAppDir;
  241. property CancelButton: TNewButton read FCancelButton;
  242. property NextButton: TNewButton read FNextButton;
  243. property BackButton: TNewButton read FBackButton;
  244. property OuterNotebook: TNewNotebook read FOuterNotebook;
  245. property InnerNotebook: TNewNotebook read FInnerNotebook;
  246. property WelcomePage: TNewNotebookPage read FWelcomePage;
  247. property InnerPage: TNewNotebookPage read FInnerPage;
  248. property FinishedPage: TNewNotebookPage read FFinishedPage;
  249. property LicensePage: TNewNotebookPage read FLicensePage;
  250. property PasswordPage: TNewNotebookPage read FPasswordPage;
  251. property InfoBeforePage: TNewNotebookPage read FInfoBeforePage;
  252. property UserInfoPage: TNewNotebookPage read FUserInfoPage;
  253. property SelectDirPage: TNewNotebookPage read FSelectDirPage;
  254. property SelectComponentsPage: TNewNotebookPage read FSelectComponentsPage;
  255. property SelectProgramGroupPage: TNewNotebookPage read FSelectProgramGroupPage;
  256. property SelectTasksPage: TNewNotebookPage read FSelectTasksPage;
  257. property ReadyPage: TNewNotebookPage read FReadyPage;
  258. property PreparingPage: TNewNotebookPage read FPreparingPage;
  259. property InstallingPage: TNewNotebookPage read FInstallingPage;
  260. property InfoAfterPage: TNewNotebookPage read FInfoAfterPage;
  261. property DiskSpaceLabel: TNewStaticText read FDiskSpaceLabel;
  262. property DirEdit: TEdit read FDirEdit;
  263. property GroupEdit: TNewEdit read FGroupEdit;
  264. property NoIconsCheck: TNewCheckBox read FNoIconsCheck;
  265. property PasswordLabel: TNewStaticText read FPasswordLabel;
  266. property PasswordEdit: TPasswordEdit read FPasswordEdit;
  267. property PasswordEditLabel: TNewStaticText read FPasswordEditLabel;
  268. property ReadyMemo: TNewMemo read FReadyMemo;
  269. property TypesCombo: TNewComboBox read FTypesCombo;
  270. property Bevel: TBevel read FBevel;
  271. property WizardBitmapImage: TBitmapImage read FWizardBitmapImage;
  272. property WelcomeLabel1: TNewStaticText read FWelcomeLabel1;
  273. property InfoBeforeMemo: TRichEditViewer read FInfoBeforeMemo;
  274. property InfoBeforeClickLabel: TNewStaticText read FInfoBeforeClickLabel;
  275. property MainPanel: TPanel read FMainPanel;
  276. property Bevel1: TBevel read FBevel1;
  277. property PageNameLabel: TNewStaticText read FPageNameLabel;
  278. property PageDescriptionLabel: TNewStaticText read FPageDescriptionLabel;
  279. property WizardSmallBitmapImage: TBitmapImage read FWizardSmallBitmapImage;
  280. property ReadyLabel: TNewStaticText read FReadyLabel;
  281. property FinishedLabel: TNewStaticText read FFinishedLabel;
  282. property YesRadio: TNewRadioButton read FYesRadio;
  283. property NoRadio: TNewRadioButton read FNoRadio;
  284. property WizardBitmapImage2: TBitmapImage read FWizardBitmapImage2;
  285. property WelcomeLabel2: TNewStaticText read FWelcomeLabel2;
  286. property LicenseLabel1: TNewStaticText read FLicenseLabel1;
  287. property LicenseMemo: TRichEditViewer read FLicenseMemo;
  288. property InfoAfterMemo: TRichEditViewer read FInfoAfterMemo;
  289. property InfoAfterClickLabel: TNewStaticText read FInfoAfterClickLabel;
  290. property ComponentsList: TNewCheckListBox read FComponentsList;
  291. property ComponentsDiskSpaceLabel: TNewStaticText read FComponentsDiskSpaceLabel;
  292. property BeveledLabel: TNewStaticText read FBeveledLabel;
  293. property StatusLabel: TNewStaticText read FStatusLabel;
  294. property FilenameLabel: TNewStaticText read FFileNameLabel;
  295. property ProgressGauge: TNewProgressBar read FProgressGauge;
  296. property SelectDirLabel: TNewStaticText read FSelectDirLabel;
  297. property SelectStartMenuFolderLabel: TNewStaticText read FSelectStartMenuFolderLabel;
  298. property SelectComponentsLabel: TNewStaticText read FSelectComponentsLabel;
  299. property SelectTasksLabel: TNewStaticText read FSelectTasksLabel;
  300. property LicenseAcceptedRadio: TNewRadioButton read FLicenseAcceptedRadio;
  301. property LicenseNotAcceptedRadio: TNewRadioButton read FLicenseNotAcceptedRadio;
  302. property UserInfoNameLabel: TNewStaticText read FUserInfoNameLabel;
  303. property UserInfoNameEdit: TNewEdit read FUserInfoNameEdit;
  304. property UserInfoOrgLabel: TNewStaticText read FUserInfoOrgLabel;
  305. property UserInfoOrgEdit: TNewEdit read FUserInfoOrgEdit;
  306. property PreparingErrorBitmapImage: TBitmapImage read FPreparingErrorBitmapImage;
  307. property PreparingLabel: TNewStaticText read FPreparingLabel;
  308. property FinishedHeadingLabel: TNewStaticText read FFinishedHeadingLabel;
  309. property UserInfoSerialLabel: TNewStaticText read FUserInfoSerialLabel;
  310. property UserInfoSerialEdit: TNewEdit read FUserInfoSerialEdit;
  311. property TasksList: TNewCheckListBox read FTasksList;
  312. property RunList: TNewCheckListBox read FRunList;
  313. property DirBrowseButton: TNewButton read FDirBrowseButton;
  314. property GroupBrowseButton: TNewButton read FGroupBrowseButton;
  315. property SelectDirBitmapImage: TBitmapImage read FSelectDirBitmapImage;
  316. property SelectGroupBitmapImage: TBitmapImage read FSelectGroupBitmapImage;
  317. property SelectDirBrowseLabel: TNewStaticText read FSelectDirBrowseLabel;
  318. property SelectStartMenuFolderBrowseLabel: TNewStaticText read FSelectStartMenuFolderBrowseLabel;
  319. property PreparingYesRadio: TNewRadioButton read FPreparingYesRadio;
  320. property PreparingNoRadio: TNewRadioButton read FPreparingNoRadio;
  321. property PreparingMemo: TNewMemo read FPreparingMemo;
  322. end;
  323. var
  324. WizardForm: TWizardForm;
  325. function ExpandSetupMessage(const Msg: String): String; overload;
  326. function ExpandSetupMessage(const ID: TSetupMessageID): String; overload;
  327. function ListContains(const List: TStringList; const S: String): Boolean;
  328. procedure TidyUpDirName(var Path: String);
  329. procedure TidyUpGroupName(var Path: String);
  330. function ValidateCustomDirEdit(const AEdit: TEdit;
  331. const AllowUNCPath, AllowRootDirectory, AllowNetworkDrive: Boolean): Boolean;
  332. implementation
  333. uses
  334. ShellApi, ShlObj, Types, Msgs, Main, PathFunc, CmnFunc, CmnFunc2,
  335. MD5, InstFunc, SelFolderForm, Extract, Logging, RestartManager, ScriptRunner;
  336. {$R *.DFM}
  337. const
  338. BadDirChars = '/:*?"<>|';
  339. var
  340. CurrentComponentsSpace: Integer64;
  341. function IntToKBStr(const I: Integer64): String;
  342. var
  343. X: Extended;
  344. begin
  345. X := Comp(I) / 1024;
  346. if Frac(X) > 0 then
  347. X := Int(X) + 1; { always round up }
  348. Result := Format('%.0n', [X]);
  349. end;
  350. function IntToMBStr(const I: Integer64): String;
  351. var
  352. X: Extended;
  353. begin
  354. X := (Comp(I) / 1048576) * 10; { * 10 to include a decimal }
  355. if Frac(X) > 0 then
  356. X := Int(X) + 1; { always round up }
  357. X := X / 10;
  358. Result := Format('%.1n', [X]);
  359. end;
  360. function IntToGBStr(const I: Integer64): String;
  361. var
  362. X: Extended;
  363. begin
  364. X := (Comp(I) / 1073741824) * 100; { * 100 to include 2 decimals }
  365. if Frac(X) > 0 then
  366. X := Int(X) + 1; { always round up }
  367. X := X / 100;
  368. Result := Format('%.2n', [X]);
  369. end;
  370. function ExpandSetupMessageEx(const Msg: String; const Space: Integer64): String; overload;
  371. begin
  372. Result := Msg;
  373. {don't localize these}
  374. StringChange(Result, '[name]', ExpandedAppName);
  375. StringChange(Result, '[name/ver]', ExpandedAppVerName);
  376. StringChange(Result, '[kb]', IntToKBStr(Space));
  377. StringChange(Result, '[mb]', IntToMBStr(Space));
  378. StringChange(Result, '[gb]', IntToGBStr(Space));
  379. end;
  380. function ExpandSetupMessageEx(const ID: TSetupMessageID; const Space: Integer64): String; overload;
  381. begin
  382. Result := ExpandSetupMessageEx(SetupMessages[ID], Space);
  383. end;
  384. function ExpandMBOrGBSetupMessage(const MBID, GBID: TSetupMessageID;
  385. const Space: Integer64): String;
  386. begin
  387. if Comp(Space) > 1048471142 then begin
  388. { Don't allow it to display 1000.0 MB or more. Takes the 'always round up' into account:
  389. 1048471142 bytes = 999.8999996185303 MB = '999.9 MB',
  390. 1048471143 bytes = 999.9000005722046 MB = '1,000.0 MB'. }
  391. Result := ExpandSetupMessageEx(GBID, Space)
  392. end else
  393. Result := ExpandSetupMessageEx(MBID, Space);
  394. end;
  395. function ExpandSetupMessage(const Msg: String): String; overload;
  396. begin
  397. Result := ExpandSetupMessageEx(Msg, MinimumSpace);
  398. end;
  399. function ExpandSetupMessage(const ID: TSetupMessageID): String; overload;
  400. begin
  401. Result := ExpandSetupMessageEx(ID, MinimumSpace);
  402. end;
  403. function ListContains(const List: TStringList; const S: String): Boolean;
  404. { Similar to "List.IndexOf(S) <> -1", except it uses CompareText instead of
  405. AnsiCompareText (which is locale-sensitive and thus unsuitable for our
  406. purposes). }
  407. var
  408. I: Integer;
  409. begin
  410. for I := 0 to List.Count-1 do
  411. if CompareText(List[I], S) = 0 then begin
  412. Result := True;
  413. Exit;
  414. end;
  415. Result := False;
  416. end;
  417. procedure TidyUpDirName(var Path: String);
  418. { Tidies up a directory name }
  419. begin
  420. { Trim spaces, normalize slashes, remove any trailing backslash, then repeat
  421. the process if necessary (e.g. in the 'C:\Program Files\My Program\ \'
  422. case) }
  423. repeat
  424. Path := RemoveBackslashUnlessRoot(PathNormalizeSlashes(Trim(Path)));
  425. until Length(Path) = Length(Trim(Path));
  426. end;
  427. procedure TidyUpGroupName(var Path: String);
  428. { Tidies up a program group name }
  429. begin
  430. { Trim spaces, remove leading/extra/trailing backslash(es), then repeat the
  431. process if necessary (e.g. in the '\ \My Program\ \' case) }
  432. repeat
  433. Path := Trim(Path);
  434. while (Path <> '') and PathCharIsSlash(Path[1]) do
  435. Delete(Path, 1, 1);
  436. Path := RemoveBackslash(PathNormalizeSlashes(Path));
  437. until Length(Path) = Length(Trim(Path));
  438. end;
  439. function ContainsControlCharacters(const S: String): Boolean;
  440. { Returns True if S contains any control characters (#0..#31) }
  441. var
  442. I: Integer;
  443. begin
  444. for I := 1 to Length(S) do
  445. if S[I] <= #31 then begin
  446. Result := True;
  447. Exit;
  448. end;
  449. Result := False;
  450. end;
  451. function PathComponentsContainTrailingSpaces(const S: String): Boolean;
  452. { Returns True if one or more components of the path contain trailing spaces,
  453. which are invalid in Win32. }
  454. var
  455. P: PChar;
  456. begin
  457. P := PChar(S);
  458. while P^ <> #0 do begin
  459. if (P^ = ' ') and ((P[1] = '\') or (P[1] = #0)) then begin
  460. Result := True;
  461. Exit;
  462. end;
  463. P := PathStrNextChar(P);
  464. end;
  465. Result := False;
  466. end;
  467. function PathComponentsContainInvalidDots(const S: String): Boolean;
  468. { Returns True if one or more components of the path contain only dots,
  469. i.e. '.', '..', '...', etc. One or two dots represent relative paths; three
  470. or more dots are invalid. }
  471. var
  472. P: PChar;
  473. HasDots: Boolean;
  474. begin
  475. P := PChar(S);
  476. while P^ <> #0 do begin
  477. { Skip over leading spaces; we want ' .' to return True also }
  478. while P^ = ' ' do
  479. Inc(P);
  480. HasDots := False;
  481. while P^ = '.' do begin
  482. HasDots := True;
  483. Inc(P);
  484. end;
  485. { Skip over trailing spaces; we want '. ' to return True also }
  486. while P^ = ' ' do
  487. Inc(P);
  488. if HasDots and ((P^ = '\') or (P^ = #0)) then begin
  489. Result := True;
  490. Exit;
  491. end;
  492. { Skip to next component }
  493. while (P^ <> #0) and (P^ <> '\') do
  494. P := PathStrNextChar(P);
  495. if P^ = '\' then
  496. Inc(P);
  497. end;
  498. Result := False;
  499. end;
  500. function SpaceString(const S: String): String;
  501. var
  502. I: Integer;
  503. begin
  504. Result := '';
  505. for I := 1 to Length(S) do begin
  506. if S[I] = ' ' then Continue;
  507. if Result <> '' then Result := Result + ' ';
  508. Result := Result + S[I];
  509. end;
  510. end;
  511. function TWizardForm.AdjustLabelHeight(const ALabel: TNewStaticText): Integer;
  512. { Increases or decreases a label's height so that all text fits.
  513. Returns the difference in height. }
  514. begin
  515. Result := ALabel.AdjustHeight;
  516. end;
  517. procedure TWizardForm.IncTopDecHeight(const AControl: TControl; const Amount: Integer);
  518. begin
  519. AControl.SetBounds(AControl.Left, AControl.Top + Amount,
  520. AControl.Width, AControl.Height - Amount);
  521. end;
  522. function TWizardForm.CheckSerialOk(): Boolean;
  523. begin
  524. if NeedSerial and (CodeRunner <> nil) then begin
  525. WizardUserInfoName := UserInfoNameEdit.Text;
  526. WizardUserInfoOrg := UserInfoOrgEdit.Text;
  527. WizardUserInfoSerial := UserInfoSerialEdit.Text;
  528. Result := CodeRunner.RunBooleanFunctions('CheckSerial', [UserInfoSerialEdit.Text], bcTrue, True, False)
  529. end else
  530. Result := True;
  531. end;
  532. procedure TWizardForm.CalcCurrentComponentsSpace();
  533. var
  534. SelectedComponents: TStringList;
  535. I: Integer;
  536. CurFile: PSetupFileEntry;
  537. begin
  538. CurrentComponentsSpace := SetupHeader.ExtraDiskSpaceRequired;
  539. SelectedComponents := TStringList.Create();
  540. GetSelectedComponents(SelectedComponents, False, False);
  541. //we can't simply sum component sizes because of shared files -> add file sizes
  542. for I := 0 to Entries[seFile].Count-1 do begin
  543. CurFile := PSetupFileEntry(Entries[seFile][I]);
  544. if (CurFile.Tasks = '') and (CurFile.Check = '') and {don't count tasks or scripted entries}
  545. ShouldProcessFileEntry(SelectedComponents, nil, CurFile, True) then begin
  546. with CurFile^ do begin
  547. if LocationEntry <> -1 then
  548. Inc6464(CurrentComponentsSpace, PSetupFileLocationEntry(Entries[seFileLocation][LocationEntry])^.OriginalSize)
  549. else
  550. Inc6464(CurrentComponentsSpace, ExternalSize)
  551. end;
  552. end;
  553. end;
  554. //don't forget to add extradiskspacerequired values
  555. for I := 0 to Entries[seComponent].Count-1 do
  556. with PSetupComponentEntry(Entries[seComponent][I])^ do
  557. if ListContains(SelectedComponents, Name) then
  558. Inc6464(CurrentComponentsSpace, ExtraDiskSpaceRequired);
  559. SelectedComponents.Free();
  560. ComponentsDiskSpaceLabel.Caption := ExpandMBOrGBSetupMessage(
  561. msgComponentsDiskSpaceMBLabel, msgComponentsDiskSpaceGBLabel, CurrentComponentsSpace);
  562. end;
  563. procedure TWizardForm.UpdateComponentSizesEnum(Index: Integer; HasChildren: Boolean; Ext: LongInt);
  564. var
  565. ComponentEntry: PSetupComponentEntry;
  566. ComponentSize, ChildrenSize: Integer64;
  567. begin
  568. ComponentEntry := PSetupComponentEntry(ComponentsList.ItemObject[Index]);
  569. ChildrenSize.Hi := 0;
  570. ChildrenSize.Lo := 0;
  571. if HasChildren then
  572. ComponentsList.EnumChildrenOf(Index, UpdateComponentSizesEnum, LongInt(@ChildrenSize));
  573. ComponentSize := ComponentEntry.Size;
  574. Inc6464(ComponentSize, ChildrenSize);
  575. if ComponentsList.Checked[Index] then
  576. Inc6464(Integer64(Pointer(Ext)^), ComponentSize);
  577. if (ComponentSize.Lo <> 0) or (ComponentSize.Hi <> 0) then begin
  578. if not HasLargeComponents then
  579. ComponentsList.ItemSubItem[Index] := FmtSetupMessage1(msgComponentSize1, IntToKBStr(ComponentSize))
  580. else
  581. ComponentsList.ItemSubItem[Index] := FmtSetupMessage1(msgComponentSize2, IntToMBStr(ComponentSize));
  582. end else
  583. ComponentsList.ItemSubItem[Index] := '';
  584. end;
  585. procedure TWizardForm.UpdateComponentSizes();
  586. var
  587. Size: Integer64;
  588. begin
  589. if shShowComponentSizes in SetupHeader.Options then begin
  590. Size.Hi := 0;
  591. Size.Lo := 0;
  592. ComponentsList.EnumChildrenOf(-1, UpdateComponentSizesEnum, LongInt(@Size));
  593. end;
  594. end;
  595. { TWizardPage }
  596. constructor TWizardPage.Create(AOwner: TComponent);
  597. begin
  598. inherited;
  599. FWizardForm := AOwner as TWizardForm;
  600. end;
  601. destructor TWizardPage.Destroy;
  602. begin
  603. if Assigned(FWizardForm) and Assigned(FWizardForm.FPageList) then
  604. FWizardForm.FPageList.Remove(Self);
  605. inherited;
  606. end;
  607. procedure TWizardPage.Activate;
  608. begin
  609. if Assigned(FOnActivate) then
  610. FOnActivate(Self);
  611. end;
  612. procedure TWizardPage.BackButtonClick(var AContinue: Boolean);
  613. begin
  614. if Assigned(FOnBackButtonClick) then
  615. AContinue := FOnBackButtonClick(Self);
  616. end;
  617. procedure TWizardPage.CancelButtonClick(var ACancel, AConfirm: Boolean);
  618. begin
  619. if Assigned(FOnCancelButtonClick) then
  620. FOnCancelButtonClick(Self, ACancel, AConfirm);
  621. end;
  622. procedure TWizardPage.NextButtonClick(var AContinue: Boolean);
  623. begin
  624. if Assigned(FOnNextButtonClick) then
  625. AContinue := FOnNextButtonClick(Self);
  626. end;
  627. procedure TWizardPage.ShouldSkipPage(var AShouldSkip: Boolean);
  628. begin
  629. if Assigned(FOnShouldSkipPage) then
  630. AShouldSkip := FOnShouldSkipPage(Self);
  631. end;
  632. function TWizardPage.GetSurface: TNewNotebookPage;
  633. begin
  634. if FOuterNotebookPage = FWizardForm.InnerPage then
  635. Result := FInnerNotebookPage
  636. else
  637. Result := FOuterNotebookPage;
  638. end;
  639. function TWizardPage.GetSurfaceColor: TColor;
  640. begin
  641. Result := TNewNotebook(Surface.Parent).Color;
  642. end;
  643. function TWizardPage.GetSurfaceHeight: Integer;
  644. begin
  645. Result := Surface.Parent.Height;
  646. end;
  647. function TWizardPage.GetSurfaceWidth: Integer;
  648. begin
  649. Result := Surface.Parent.Width;
  650. end;
  651. procedure TWizardPage.SetCaption(const Value: String);
  652. begin
  653. FCaption := ExpandSetupMessage(Value);
  654. SyncCaptionAndDescription;
  655. end;
  656. procedure TWizardPage.SetDescription(const Value: String);
  657. begin
  658. FDescription := ExpandSetupMessage(Value);
  659. SyncCaptionAndDescription;
  660. end;
  661. procedure TWizardPage.SyncCaptionAndDescription;
  662. begin
  663. if FWizardForm.CurPageID = FID then begin
  664. FWizardForm.PageNameLabel.Caption := FCaption;
  665. FWizardForm.PageDescriptionLabel.Caption := FDescription;
  666. end;
  667. end;
  668. { TWizardForm }
  669. constructor TWizardForm.Create(AOwner: TComponent);
  670. { Do all initialization of the wizard form. We're overriding Create instead of
  671. using the FormCreate event, because if an exception is raised in FormCreate
  672. it's not propagated out. }
  673. function SelectBestImage(WizardImages: TList; TargetWidth, TargetHeight: Integer): TBitmap;
  674. var
  675. TargetArea, Difference, SmallestDifference, I: Integer;
  676. begin
  677. { Find the image with the smallest area difference compared to the target area. }
  678. TargetArea := TargetWidth*TargetHeight;
  679. SmallestDifference := -1;
  680. Result := nil;
  681. for I := 0 to WizardImages.Count-1 do begin
  682. Difference := Abs(TargetArea-TBitmap(WizardImages[I]).Width*TBitmap(WizardImages[I]).Height);
  683. if (SmallestDifference = -1) or (Difference < SmallestDifference) then begin
  684. Result := WizardImages[I];
  685. SmallestDifference := Difference;
  686. end;
  687. end;
  688. end;
  689. var
  690. X, W1, W2: Integer;
  691. SystemMenu: HMENU;
  692. P: String;
  693. I, DefaultSetupTypeIndex: Integer;
  694. DfmDefault, IgnoreInitComponents: Boolean;
  695. TypeEntry: PSetupTypeEntry;
  696. ComponentEntry: PSetupComponentEntry;
  697. SaveClientWidth, SaveClientHeight: Integer;
  698. begin
  699. inherited;
  700. FPageList := TList.Create;
  701. InitialSelectedComponents := TStringList.Create();
  702. PrevSelectedComponents := TStringList.Create();
  703. PrevDeselectedComponents := TStringList.Create();
  704. PrevSelectedTasks := TStringList.Create();
  705. PrevDeselectedTasks := TStringList.Create();
  706. MainPanel.ParentBackground := False;
  707. { Prior to scaling the form, shrink WizardSmallBitmapImage if it's currently
  708. larger than WizardSmallImage. This way, stretching will not occur if the
  709. user specifies a smaller-than-default image and WizardImageStretch=yes,
  710. except if the form has to be scaled (e.g. due to Large Fonts). }
  711. if WizardSmallImages.Count = 1 then begin
  712. I := WizardSmallBitmapImage.Height - TBitmap(WizardSmallImages[0]).Height;
  713. if I > 0 then begin
  714. WizardSmallBitmapImage.Height := WizardSmallBitmapImage.Height - I;
  715. WizardSmallBitmapImage.Top := WizardSmallBitmapImage.Top + (I div 2);
  716. end;
  717. I := WizardSmallBitmapImage.Width - TBitmap(WizardSmallImages[0]).Width;
  718. if I > 0 then begin
  719. WizardSmallBitmapImage.Width := WizardSmallBitmapImage.Width - I;
  720. WizardSmallBitmapImage.Left := WizardSmallBitmapImage.Left + (I div 2);
  721. end;
  722. end;
  723. { Not sure why the following is needed but various things related to
  724. positioning and anchoring don't work without this (you get positions of
  725. page controls back as if there was no anchoring until the page handle
  726. is automatically created. Cause might be related to the comment in
  727. TNewNotebook.AlignControls. }
  728. for I := 0 to OuterNotebook.PageCount-1 do
  729. OuterNotebook.Pages[I].HandleNeeded;
  730. for I := 0 to InnerNotebook.PageCount-1 do
  731. InnerNotebook.Pages[I].HandleNeeded;
  732. InitializeFont;
  733. SetFontNameSize(WelcomeLabel1.Font, LangOptions.WelcomeFontName,
  734. LangOptions.WelcomeFontSize, '', 12);
  735. WelcomeLabel1.Font.Style := [fsBold];
  736. PageNameLabel.Font.Style := [fsBold];
  737. if shWindowVisible in SetupHeader.Options then
  738. Caption := SetupMessages[msgSetupAppTitle]
  739. else if shDisableWelcomePage in SetupHeader.Options then
  740. Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppVerName)
  741. else
  742. Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppName);
  743. { Set BorderStyle and BorderIcons:
  744. -WindowVisible + WizardResizable = sizeable
  745. -not WindowVisible + WizardResizable = sizeable + minimize
  746. -WindowVisible + not WizardResizable = dialog = .dfm default = do nothing
  747. -not WindowVisible + not WizardResizable = single + minimize }
  748. DfmDefault := (shWindowVisible in SetupHeader.Options) and not (shWizardResizable in SetupHeader.Options);
  749. if not DfmDefault then begin
  750. { Save ClientWidth/ClientHeight and restore them after changing BorderStyle. }
  751. SaveClientWidth := ClientWidth;
  752. SaveClientHeight := ClientHeight;
  753. if not(shWindowVisible in SetupHeader.Options) then
  754. BorderIcons := BorderIcons + [biMinimize];
  755. if not(shWizardResizable in SetupHeader.Options) then
  756. BorderStyle := bsSingle
  757. else
  758. BorderStyle := bsSizeable;
  759. ClientWidth := SaveClientWidth;
  760. ClientHeight := SaveClientHeight;
  761. end;
  762. if shWizardResizable in SetupHeader.Options then begin
  763. EnableAnchorOuterPagesOnResize := True;
  764. { Do not allow user to resize it smaller than 100% nor larger than 150%. }
  765. Constraints.MinHeight := Height;
  766. Constraints.MinWidth := Width;
  767. Constraints.MaxHeight := MulDiv(Height, 150, 100);
  768. Constraints.MaxWidth := MulDiv(Width, 150, 100);
  769. end;
  770. { Position the buttons, and scale their size }
  771. W1 := CalculateButtonWidth([SetupMessages[msgButtonBack], SetupMessages[msgButtonCancel],
  772. SetupMessages[msgButtonFinish], SetupMessages[msgButtonInstall],
  773. SetupMessages[msgButtonNext]]); { width of each button }
  774. W2 := ScalePixelsX(10); { margin, and space between Next & Cancel }
  775. BackButton.Width := W1;
  776. NextButton.Width := W1;
  777. CancelButton.Width := W1;
  778. X := ClientWidth - W2 - W1;
  779. CancelButton.Left := X;
  780. Dec(X, W2);
  781. Dec(X, W1);
  782. NextButton.Left := X;
  783. Dec(X, W1);
  784. BackButton.Left := X;
  785. { Initialize wizard style }
  786. if SetupHeader.WizardStyle = wsModern then begin
  787. OuterNotebook.Color := clWindow;
  788. Bevel1.Visible := False;
  789. end;
  790. { Initialize images }
  791. WizardBitmapImage.Bitmap := SelectBestImage(WizardImages, WizardBitmapImage.Width, WizardBitmapImage.Height);
  792. WizardBitmapImage.Center := True;
  793. WizardBitmapImage.Stretch := (shWizardImageStretch in SetupHeader.Options);
  794. WizardBitmapImage2.Bitmap := WizardBitmapImage.Bitmap;
  795. WizardBitmapImage2.Center := True;
  796. WizardBitmapImage2.Stretch := (shWizardImageStretch in SetupHeader.Options);
  797. WizardSmallBitmapImage.Bitmap := SelectBestImage(WizardSmallImages, WizardSmallBitmapImage.Width, WizardSmallBitmapImage.Height);
  798. WizardSmallBitmapImage.Stretch := (shWizardImageStretch in SetupHeader.Options);
  799. SelectDirBitmapImage.InitializeFromIcon(HInstance, 'Z_DIRICON', SelectDirPage.Color, [32, 48, 64]); {don't localize}
  800. SelectGroupBitmapImage.InitializeFromIcon(HInstance, 'Z_GROUPICON', SelectProgramGroupPage.Color, [32, 48, 64]); {don't localize}
  801. PreparingErrorBitmapImage.InitializeFromIcon(HInstance, 'Z_STOPICON', PreparingPage.Color, [16, 24, 32]); {don't localize}
  802. { Initialize wpWelcome page }
  803. RegisterExistingPage(wpWelcome, WelcomePage, nil, '', '');
  804. WelcomeLabel1.Caption := ExpandSetupMessage(msgWelcomeLabel1) + SNewLine;
  805. AdjustLabelHeight(WelcomeLabel1);
  806. IncTopDecHeight(WelcomeLabel2, (WelcomeLabel1.Top + WelcomeLabel1.Height) -
  807. WelcomeLabel2.Top);
  808. WelcomeLabel2.Caption := ExpandSetupMessage(msgWelcomeLabel2) + SNewLine2 +
  809. SetupMessages[msgClickNext];
  810. { Initialize wpLicense page }
  811. RegisterExistingPage(wpLicense, InnerPage, LicensePage,
  812. SetupMessages[msgWizardLicense], SetupMessages[msgLicenseLabel]);
  813. LicenseLabel1.Caption := ExpandSetupMessage(msgLicenseLabel3);
  814. I := AdjustLabelHeight(LicenseLabel1);
  815. IncTopDecHeight(LicenseMemo, I);
  816. LicenseAcceptedRadio.Caption := SetupMessages[msgLicenseAccepted];
  817. LicenseNotAcceptedRadio.Caption := SetupMessages[msgLicenseNotAccepted];
  818. { Initialize wpPassword page }
  819. RegisterExistingPage(wpPassword, InnerPage, PasswordPage,
  820. SetupMessages[msgWizardPassword], SetupMessages[msgPasswordLabel1]);
  821. PasswordLabel.Caption := SetupMessages[msgPasswordLabel3];
  822. PasswordEditLabel.Caption := SetupMessages[msgPasswordEditLabel];
  823. I := AdjustLabelHeight(PasswordLabel);
  824. PasswordEditLabel.Top := PasswordEditLabel.Top + I;
  825. Inc(I, AdjustLabelHeight(PasswordEditLabel));
  826. PasswordEdit.Top := PasswordEdit.Top + I;
  827. { Initialize wpInfoBefore page }
  828. RegisterExistingPage(wpInfoBefore, InnerPage, InfoBeforePage,
  829. SetupMessages[msgWizardInfoBefore], SetupMessages[msgInfoBeforeLabel]);
  830. InfoBeforeClickLabel.Caption := SetupMessages[msgInfoBeforeClickLabel];
  831. I := AdjustLabelHeight(InfoBeforeClickLabel);
  832. IncTopDecHeight(InfoBeforeMemo, I);
  833. { Initialize wpUserInfo page }
  834. RegisterExistingPage(wpUserInfo, InnerPage, UserInfoPage,
  835. SetupMessages[msgWizardUserInfo], SetupMessages[msgUserInfoDesc]);
  836. UserInfoNameLabel.Caption := SetupMessages[msgUserInfoName];
  837. I := AdjustLabelHeight(UserInfoNameLabel);
  838. UserInfoNameEdit.Top := UserInfoNameEdit.Top + I;
  839. UserInfoOrgLabel.Top := UserInfoOrgLabel.Top + I;
  840. UserInfoOrgLabel.Caption := SetupMessages[msgUserInfoOrg];
  841. Inc(I, AdjustLabelHeight(UserInfoOrgLabel));
  842. UserInfoOrgEdit.Top := UserInfoOrgEdit.Top + I;
  843. if NeedSerial then begin
  844. UserInfoSerialLabel.Top := UserInfoSerialLabel.Top + I;
  845. UserInfoSerialLabel.Caption := SetupMessages[msgUserInfoSerial];
  846. Inc(I, AdjustLabelHeight(UserInfoSerialLabel));
  847. UserInfoSerialEdit.Top := UserInfoSerialEdit.Top + I;
  848. end else begin
  849. UserInfoSerialLabel.Visible := False;
  850. UserInfoSerialEdit.Visible := False;
  851. end;
  852. { Initialize wpSelectDir page }
  853. RegisterExistingPage(wpSelectDir, InnerPage, SelectDirPage,
  854. SetupMessages[msgWizardSelectDir], ExpandSetupMessage(msgSelectDirDesc));
  855. SelectDirLabel.Caption := ExpandSetupMessage(msgSelectDirLabel3);
  856. X := SelectDirBitmapImage.Left + SelectDirBitmapImage.Width + ScalePixelsX(12);
  857. SelectDirLabel.SetBounds(X, SelectDirLabel.Top,
  858. SelectDirLabel.Width - (X - SelectDirLabel.Left), SelectDirLabel.Height);
  859. AdjustLabelHeight(SelectDirLabel);
  860. if SelectDirLabel.Height < SelectDirBitmapImage.Height then
  861. SelectDirLabel.Top := SelectDirLabel.Top +
  862. (SelectDirBitmapImage.Height - (SelectDirLabel.Height - 1)) div 2;
  863. SelectDirBrowseLabel.Caption := ExpandSetupMessage(msgSelectDirBrowseLabel);
  864. I := IntMax(
  865. SelectDirBitmapImage.Top + SelectDirBitmapImage.Height + ScalePixelsY(12),
  866. SelectDirLabel.Top + SelectDirLabel.Height - 1 + ScalePixelsY(13)) -
  867. SelectDirBrowseLabel.Top;
  868. SelectDirBrowseLabel.Top := SelectDirBrowseLabel.Top + I;
  869. Inc(I, AdjustLabelHeight(SelectDirBrowseLabel));
  870. DirEdit.Top := DirEdit.Top + I;
  871. TryEnableAutoCompleteFileSystem(DirEdit.Handle);
  872. DirBrowseButton.Caption := SetupMessages[msgButtonWizardBrowse];
  873. X := CalculateButtonWidth([SetupMessages[msgButtonWizardBrowse]]);
  874. DirBrowseButton.SetBounds(InnerNotebook.Width - X,
  875. DirBrowseButton.Top + I, X, DirBrowseButton.Height);
  876. DirEdit.Width := DirBrowseButton.Left - ScalePixelsX(10) - DirEdit.Left;
  877. DiskSpaceLabel.Caption := ExpandMBOrGBSetupMessage(
  878. msgDiskSpaceMBLabel, msgDiskSpaceGBLabel, MinimumSpace);
  879. DiskSpaceLabel.Top := DiskSpaceLabel.Top - AdjustLabelHeight(DiskSpaceLabel);
  880. { Initialize wpSelectComponents page }
  881. RegisterExistingPage(wpSelectComponents, InnerPage, SelectComponentsPage,
  882. SetupMessages[msgWizardSelectComponents], ExpandSetupMessage(msgSelectComponentsDesc));
  883. SelectComponentsLabel.Caption := ExpandSetupMessage(msgSelectComponentsLabel2);
  884. I := AdjustLabelHeight(SelectComponentsLabel);
  885. TypesCombo.Top := TypesCombo.Top + I;
  886. IncTopDecHeight(ComponentsList, I);
  887. ComponentsDiskSpaceLabel.Caption := ExpandMBOrGBSetupMessage(
  888. msgComponentsDiskSpaceMBLabel, msgComponentsDiskSpaceGBLabel, MinimumSpace);
  889. AdjustLabelHeight(ComponentsDiskSpaceLabel);
  890. if HasCustomType and (Entries[seType].Count = 1) then begin
  891. TypesCombo.Visible := False;
  892. IncTopDecHeight(ComponentsList, TypesCombo.Top - ComponentsList.Top);
  893. end;
  894. { Initialize wpSelectProgramGroup page }
  895. RegisterExistingPage(wpSelectProgramGroup, InnerPage, SelectProgramGroupPage,
  896. SetupMessages[msgWizardSelectProgramGroup], ExpandSetupMessage(msgSelectStartMenuFolderDesc));
  897. SelectStartMenuFolderLabel.Caption := ExpandSetupMessage(msgSelectStartMenuFolderLabel3);
  898. X := SelectGroupBitmapImage.Left + SelectGroupBitmapImage.Width + ScalePixelsX(12);
  899. SelectStartMenuFolderLabel.SetBounds(X, SelectStartMenuFolderLabel.Top,
  900. SelectStartMenuFolderLabel.Width - (X - SelectStartMenuFolderLabel.Left),
  901. SelectStartMenuFolderLabel.Height);
  902. AdjustLabelHeight(SelectStartMenuFolderLabel);
  903. if SelectStartMenuFolderLabel.Height < SelectGroupBitmapImage.Height then
  904. SelectStartMenuFolderLabel.Top := SelectStartMenuFolderLabel.Top +
  905. (SelectGroupBitmapImage.Height - (SelectStartMenuFolderLabel.Height - 1)) div 2;
  906. SelectStartMenuFolderBrowseLabel.Caption := ExpandSetupMessage(msgSelectStartMenuFolderBrowseLabel);
  907. I := IntMax(
  908. SelectGroupBitmapImage.Top + SelectGroupBitmapImage.Height + ScalePixelsY(12),
  909. SelectStartMenuFolderLabel.Top + SelectStartMenuFolderLabel.Height - 1 + ScalePixelsY(13)) -
  910. SelectStartMenuFolderBrowseLabel.Top;
  911. SelectStartMenuFolderBrowseLabel.Top := SelectStartMenuFolderBrowseLabel.Top + I;
  912. Inc(I, AdjustLabelHeight(SelectStartMenuFolderBrowseLabel));
  913. GroupEdit.Top := GroupEdit.Top + I;
  914. GroupBrowseButton.Caption := SetupMessages[msgButtonWizardBrowse];
  915. X := CalculateButtonWidth([SetupMessages[msgButtonWizardBrowse]]);
  916. GroupBrowseButton.SetBounds(InnerNotebook.Width - X,
  917. GroupBrowseButton.Top + I, X, GroupBrowseButton.Height);
  918. GroupEdit.Width := GroupBrowseButton.Left - ScalePixelsX(10) - GroupEdit.Left;
  919. NoIconsCheck.Caption := SetupMessages[msgNoProgramGroupCheck2];
  920. { Initialize wpSelectTasks page }
  921. RegisterExistingPage(wpSelectTasks, InnerPage, SelectTasksPage,
  922. SetupMessages[msgWizardSelectTasks], ExpandSetupMessage(msgSelectTasksDesc));
  923. SelectTasksLabel.Caption := ExpandSetupMessage(msgSelectTasksLabel2);
  924. I := AdjustLabelHeight(SelectTasksLabel);
  925. IncTopDecHeight(TasksList, I);
  926. TasksList.BorderStyle := bsNone;
  927. TasksList.MinItemHeight := ScalePixelsY(22);
  928. TasksList.ShowLines := shShowTasksTreeLines in SetupHeader.Options;
  929. { Initialize wpReady page }
  930. RegisterExistingPage(wpReady, InnerPage, ReadyPage,
  931. SetupMessages[msgWizardReady], ExpandSetupMessage(msgReadyLabel1));
  932. { Initialize wpPreparing page }
  933. RegisterExistingPage(wpPreparing, InnerPage, PreparingPage,
  934. SetupMessages[msgWizardPreparing], ExpandSetupMessage(msgPreparingDesc));
  935. { Initialize wpInstalling page }
  936. RegisterExistingPage(wpInstalling, InnerPage, InstallingPage,
  937. SetupMessages[msgWizardInstalling], ExpandSetupMessage(msgInstallingLabel));
  938. { Initialize wpInfoAfter page }
  939. RegisterExistingPage(wpInfoAfter, InnerPage, InfoAfterPage,
  940. SetupMessages[msgWizardInfoAfter], SetupMessages[msgInfoAfterLabel]);
  941. InfoAfterClickLabel.Caption := SetupMessages[msgInfoAfterClickLabel];
  942. I := AdjustLabelHeight(InfoAfterClickLabel);
  943. IncTopDecHeight(InfoAfterMemo, I);
  944. { Initialize wpFinished page }
  945. RegisterExistingPage(wpFinished, FinishedPage, nil, '', '');
  946. SetFontNameSize(FinishedHeadingLabel.Font, LangOptions.WelcomeFontName,
  947. LangOptions.WelcomeFontSize, '', 12);
  948. FinishedHeadingLabel.Font.Style := [fsBold];
  949. FinishedHeadingLabel.Caption := ExpandSetupMessage(msgFinishedHeadingLabel) +
  950. SNewLine;
  951. AdjustLabelHeight(FinishedHeadingLabel);
  952. FinishedLabel.Top := FinishedHeadingLabel.Top + FinishedHeadingLabel.Height;
  953. YesRadio.Caption := SetupMessages[msgYesRadio];
  954. NoRadio.Caption := SetupMessages[msgNoRadio];
  955. RunList.MinItemHeight := ScalePixelsY(22);
  956. { Initialize BeveledLabel }
  957. if SetupMessages[msgBeveledLabel] <> '' then
  958. BeveledLabel.Caption := ' ' + SetupMessages[msgBeveledLabel] + ' '
  959. else
  960. BeveledLabel.Caption := '';
  961. { Don't set UseRichEdit to True on the TRichEditViewers unless they are going
  962. to be used. There's no need to load riched*.dll unnecessarily. }
  963. if ActiveLicenseText <> '' then begin
  964. LicenseMemo.UseRichEdit := True;
  965. LicenseMemo.RTFText := ActiveLicenseText;
  966. end;
  967. if ActiveInfoBeforeText <> '' then begin
  968. InfoBeforeMemo.UseRichEdit := True;
  969. InfoBeforeMemo.RTFText := ActiveInfoBeforeText;
  970. end;
  971. if ActiveInfoAfterText <> '' then begin
  972. InfoAfterMemo.UseRichEdit := True;
  973. InfoAfterMemo.RTFText := ActiveInfoAfterText;
  974. end;
  975. { Append an 'About Setup' item to the wizard form also }
  976. SystemMenu := GetSystemMenu(Handle, False);
  977. AppendMenu(SystemMenu, MF_SEPARATOR, 0, nil);
  978. AppendMenu(SystemMenu, MF_STRING, 9999, PChar(SetupMessages[msgAboutSetupMenuItem]));
  979. { Read settings from a previous install if available }
  980. FindPreviousData;
  981. DisableDirPage := (SetupHeader.DisableDirPage = dpYes) or
  982. ((SetupHeader.DisableDirPage = dpAuto) and (PrevAppDir <> ''));
  983. DisableProgramGroupPage := (SetupHeader.DisableProgramGroupPage = dpYes) or
  984. ((SetupHeader.DisableProgramGroupPage = dpAuto) and (PrevGroup <> ''));
  985. DefaultSetupTypeIndex := -1; //assigned later
  986. IgnoreInitComponents := False;
  987. { Assign default user name & organization on User Info page }
  988. if shUserInfoPage in SetupHeader.Options then begin
  989. if PrevUserInfoName = '' then begin
  990. UserInfoNameEdit.Text := ExpandConst(SetupHeader.DefaultUserInfoName);
  991. UserInfoOrgEdit.Text := ExpandConst(SetupHeader.DefaultUserInfoOrg);
  992. UserInfoSerialEdit.Text := ExpandConst(SetupHeader.DefaultUserInfoSerial);
  993. end
  994. else begin
  995. UserInfoNameEdit.Text := PrevUserInfoName;
  996. UserInfoOrgEdit.Text := PrevUserInfoOrg;
  997. UserInfoSerialEdit.Text := PrevUserInfoSerial;
  998. end;
  999. end;
  1000. { Assign default directory name }
  1001. if shCreateAppDir in SetupHeader.Options then begin
  1002. ExpandedDefaultDirName := ExpandConst(SetupHeader.DefaultDirName);
  1003. if InitDir <> '' then
  1004. P := ExpandConstIfPrefixed(InitDir)
  1005. else begin
  1006. P := PrevAppDir;
  1007. if P = '' then
  1008. P := ExpandedDefaultDirName;
  1009. end;
  1010. P := RemoveBackslashUnlessRoot(PathExpand(P));
  1011. DirEdit.Text := P;
  1012. end
  1013. else
  1014. DirEdit.Text := WinDir;
  1015. { Fill types list and assign default type }
  1016. if Entries[seType].Count > 0 then begin
  1017. //first fill list
  1018. TypesCombo.Clear();
  1019. for I := 0 to Entries[seType].Count-1 do begin
  1020. TypeEntry := PSetupTypeEntry(Entries[seType][I]);
  1021. TypesCombo.Items.AddObject(ExpandConst(TypeEntry.Description), TObject(TypeEntry));
  1022. { If a setup type was specified on the command line, use it as default }
  1023. if (DefaultSetupTypeIndex = -1) and (InitSetupType <> '') and
  1024. (CompareText(TypeEntry.Name, InitSetupType) = 0) then begin
  1025. DefaultSetupTypeIndex := I;
  1026. { If components are specified as well, they should be ignored if the
  1027. setup type is non-custom }
  1028. if not (toIsCustom in TypeEntry.Options) then
  1029. IgnoreInitComponents := True;
  1030. end;
  1031. end;
  1032. { Use setup type from previous installation if no type was specified on the
  1033. command line (or if the type specified doesn't exist) }
  1034. if (DefaultSetupTypeIndex = -1) and (PrevSetupType <> '') then begin
  1035. for I := 0 to Entries[seType].Count-1 do begin
  1036. TypeEntry := PSetupTypeEntry(Entries[seType][I]);
  1037. if CompareText(TypeEntry.Name, PrevSetupType) = 0 then begin
  1038. DefaultSetupTypeIndex := I;
  1039. Break;
  1040. end;
  1041. end;
  1042. end;
  1043. //now assign default type
  1044. if DefaultSetupTypeIndex <> -1 then
  1045. TypesCombo.ItemIndex := DefaultSetupTypeIndex
  1046. else
  1047. TypesCombo.ItemIndex := 0;
  1048. end;
  1049. { Fill components list and assign default components}
  1050. //first fill list
  1051. ComponentsList.Clear();
  1052. ComponentsList.Flat := shFlatComponentsList in SetupHeader.Options;
  1053. for I := 0 to Entries[seComponent].Count-1 do begin
  1054. ComponentEntry := PSetupComponentEntry(Entries[seComponent][I]);
  1055. if coExclusive in ComponentEntry.Options then
  1056. ComponentsList.AddRadioButton(ExpandConst(ComponentEntry.Description), '', ComponentEntry.Level,
  1057. False, not (coFixed in ComponentEntry.Options), TObject(ComponentEntry))
  1058. else
  1059. ComponentsList.AddCheckBox(ExpandConst(ComponentEntry.Description), '', ComponentEntry.Level,
  1060. False, not (coFixed in ComponentEntry.Options), ComponentEntry.Used,
  1061. not (coDontInheritCheck in ComponentEntry.Options), TObject(ComponentEntry));
  1062. if (ComponentEntry.Size.Hi <> 0) or (ComponentEntry.Size.Lo >= LongWord(1024*1024)) then
  1063. HasLargeComponents := True;
  1064. end;
  1065. //now assign default components
  1066. if not IgnoreInitComponents and InitComponentsSpecified and HasCustomType then begin
  1067. for I := 0 to Entries[seType].Count-1 do begin
  1068. TypeEntry := PSetupTypeEntry(Entries[seType][I]);
  1069. if toIsCustom in TypeEntry.Options then begin
  1070. TypesCombo.ItemIndex := I;
  1071. SelectComponentsFromType(TypeEntry.Name, True);
  1072. SelectComponents(InitComponents, nil, True);
  1073. Break;
  1074. end;
  1075. end;
  1076. end else begin
  1077. if DefaultSetupTypeIndex <> -1 then begin
  1078. TypeEntry := PSetupTypeEntry(Entries[seType][DefaultSetupTypeIndex]);
  1079. if toIsCustom in TypeEntry.Options then begin
  1080. //the previous setup type is a custom type: first select the default components
  1081. //for the default type (usually the full type). needed for new components.
  1082. SelectComponentsFromType(PSetupTypeEntry(Entries[seType][0]).Name, False);
  1083. //then select/deselect the custom type's fixed components
  1084. SelectComponentsFromType(TypeEntry.Name, True);
  1085. //now restore the customization
  1086. SelectComponents(PrevSelectedComponents, PrevDeselectedComponents, True);
  1087. end else begin
  1088. //this is not a custom type, so just select components based on the previous type
  1089. SelectComponentsFromType(TypeEntry.Name, False);
  1090. end;
  1091. end else if Entries[seType].Count > 0 then begin
  1092. TypeEntry := PSetupTypeEntry(Entries[seType][0]);
  1093. SelectComponentsFromType(TypeEntry.Name, False);
  1094. end;
  1095. end;
  1096. UpdateComponentSizes;
  1097. CalcCurrentComponentsSpace;
  1098. //Show or hide the components list based on the selected type
  1099. if HasCustomType then begin
  1100. TypeEntry := PSetupTypeEntry(Entries[seType][TypesCombo.ItemIndex]);
  1101. if (toIsCustom in TypeEntry.Options) or (shAlwaysShowComponentsList in SetupHeader.Options) then
  1102. ComponentsList.Visible := True
  1103. else
  1104. ComponentsList.Visible := False;
  1105. end else
  1106. ComponentsList.Visible := False;
  1107. ComponentsDiskSpaceLabel.Visible := ComponentsList.Visible;
  1108. //Store the initial setup type and components (only necessary if customizable)
  1109. if HasCustomType then begin
  1110. InitialSetupTypeIndex := TypesCombo.ItemIndex;
  1111. GetSelectedComponents(InitialSelectedComponents, False, False);
  1112. end;
  1113. { Assign default group name }
  1114. ExpandedDefaultGroupName := ExpandConst(SetupHeader.DefaultGroupName);
  1115. if (InitProgramGroup <> '') and not DisableProgramGroupPage then
  1116. { ^ InitProgramGroup currently isn't supported for installations with
  1117. DisableProgramGroupPage set. If the wizard page isn't displayed, it
  1118. doesn't get a chance to validate the program group name specified. }
  1119. P := ExpandConstIfPrefixed(InitProgramGroup)
  1120. else begin
  1121. if (PrevGroup = '') or (PrevGroup = '(Default)') then
  1122. P := ExpandedDefaultGroupName
  1123. else
  1124. P := PrevGroup;
  1125. end;
  1126. GroupEdit.Text := P;
  1127. if shAllowNoIcons in SetupHeader.Options then begin
  1128. if InitNoIcons or PrevNoIcons then
  1129. NoIconsCheck.Checked := True;
  1130. NoIconsCheck.Visible := True;
  1131. end
  1132. else
  1133. NoIconsCheck.Visible := False;
  1134. end;
  1135. procedure TWizardForm.FormResize(Sender: TObject);
  1136. procedure AnchorOuterPage(const Page: TNewNotebookPage;
  1137. const BitmapImage: TBitmapImage);
  1138. var
  1139. ExpectedAnchors: TAnchors;
  1140. Ctl: TControl;
  1141. I, NewLeft, NewWidth: Integer;
  1142. begin
  1143. { BitmapImage's size is already corrected by the Anchors property but this
  1144. doesn't keep the aspect ratio. Calculate and set new width to restore the
  1145. aspect ratio and update all the other controls in the page for this. Don't
  1146. do this if [Code] made any change to BitmapImage's Visible, Align or Anchors
  1147. signalling that it wants a custom layout. }
  1148. if ControlsFlipped then
  1149. ExpectedAnchors := [akTop, akRight, akBottom]
  1150. else
  1151. ExpectedAnchors := [akLeft, akTop, akBottom];
  1152. if BitmapImage.Visible and (BitmapImage.Align = alNone) and (BitmapImage.Anchors = ExpectedAnchors) then begin
  1153. if BaseUnitX = 0 then
  1154. InternalError('AnchorOuterPage: BaseUnitX = 0');
  1155. NewWidth := MulDiv(BitmapImage.Height, ScalePixelsX(164), ScalePixelsY(314)); //164x314 is the original bitmapimage size
  1156. if ControlsFlipped then
  1157. BitmapImage.Left := ClientWidth - NewWidth;
  1158. BitmapImage.Width := NewWidth;
  1159. for I := 0 to Page.ControlCount-1 do begin
  1160. Ctl := Page.Controls[I];
  1161. if Ctl <> BitmapImage then begin
  1162. NewLeft := BitmapImage.Width + ScalePixelsX(12); //12 is original space between bitmapimage and controls
  1163. Ctl.Width := ClientWidth - ScalePixelsX(20) - NewLeft; //20 is original space between controls and right border
  1164. if not ControlsFlipped then
  1165. Ctl.Left := NewLeft;
  1166. end;
  1167. end;
  1168. end;
  1169. end;
  1170. begin
  1171. if EnableAnchorOuterPagesOnResize then begin
  1172. AnchorOuterPage(WelcomePage, WizardBitmapImage);
  1173. AnchorOuterPage(FinishedPage, WizardBitmapImage2);
  1174. end;
  1175. if EnableAdjustReadyLabelHeightOnResize then
  1176. IncTopDecHeight(ReadyMemo, AdjustLabelHeight(ReadyLabel));
  1177. end;
  1178. procedure TWizardForm.FlipSizeAndCenterIfNeeded(const ACenterInsideControl: Boolean;
  1179. const CenterInsideControlCtl: TWinControl; const CenterInsideControlInsideClientArea: Boolean);
  1180. begin
  1181. if ShouldSizeX or ShouldSizeY then
  1182. EnableAnchorOuterPagesOnResize := True;
  1183. inherited;
  1184. end;
  1185. destructor TWizardForm.Destroy;
  1186. begin
  1187. FreeAndNil(PrevDeselectedComponents);
  1188. FreeAndNil(PrevSelectedTasks);
  1189. FreeAndNil(PrevDeselectedTasks);
  1190. FreeAndNil(PrevSelectedComponents);
  1191. FreeAndNil(InitialSelectedComponents);
  1192. FreeAndNil(FPageList);
  1193. inherited;
  1194. end;
  1195. procedure TWizardForm.CreateParams(var Params: TCreateParams);
  1196. begin
  1197. inherited;
  1198. { Ensure the form is *always* on top of MainForm by making MainForm
  1199. the "parent" of the form. }
  1200. Params.WndParent := MainForm.Handle;
  1201. end;
  1202. function TWizardForm.PageIndexFromID(const ID: Integer): Integer;
  1203. { Given a page ID, returns the index of the page in FPageList. An exception is
  1204. raised if a page with the specified ID is not found. }
  1205. var
  1206. I: Integer;
  1207. begin
  1208. for I := 0 to FPageList.Count-1 do begin
  1209. if TWizardPage(FPageList[I]).ID = ID then begin
  1210. Result := I;
  1211. Exit;
  1212. end;
  1213. end;
  1214. InternalError(Format('Could not find page with ID %d', [ID]));
  1215. Result := -1; { avoid compiler warning }
  1216. end;
  1217. function TWizardForm.PageFromID(const ID: Integer): TWizardPage;
  1218. begin
  1219. Result := FPageList[PageIndexFromID(ID)];
  1220. end;
  1221. procedure TWizardForm.RegisterExistingPage(const ID: Integer;
  1222. const AOuterNotebookPage, AInnerNotebookPage: TNewNotebookPage;
  1223. const ACaption, ADescription: String);
  1224. var
  1225. P: TWizardPage;
  1226. begin
  1227. FPageList.Expand;
  1228. P := TWizardPage.Create(Self);
  1229. P.FID := ID;
  1230. P.FOuterNotebookPage := AOuterNotebookPage;
  1231. P.FInnerNotebookPage := AInnerNotebookPage;
  1232. P.Caption := ACaption;
  1233. P.Description := ADescription;
  1234. FPageList.Add(P);
  1235. end;
  1236. procedure TWizardForm.AddPage(const APage: TWizardPage; const AfterID: Integer);
  1237. { Adds a new wizard page entry in FPageList, and an associated page in
  1238. InnerNotebook. AfterID specifies where the page should be inserted, or -1
  1239. which inserts the page at the end. }
  1240. var
  1241. InsertIndex: Integer;
  1242. NotebookPage: TNewNotebookPage;
  1243. begin
  1244. if AfterID <> -1 then
  1245. InsertIndex := PageIndexFromID(AfterID) + 1
  1246. else
  1247. InsertIndex := FPageList.Count;
  1248. FPageList.Expand;
  1249. Inc(FNextPageID);
  1250. if FNextPageID = 1 then
  1251. FNextPageID := 100;
  1252. NotebookPage := TNewNotebookPage.Create(APage);
  1253. NotebookPage.Notebook := InnerNotebook;
  1254. NotebookPage.HandleNeeded; { See TWizardForm.Create comment }
  1255. APage.FID := FNextPageID;
  1256. APage.FOuterNotebookPage := InnerPage;
  1257. APage.FInnerNotebookPage := NotebookPage;
  1258. FPageList.Insert(InsertIndex, APage);
  1259. end;
  1260. { Also see GetPreviousData in Main.pas }
  1261. procedure TWizardForm.FindPreviousData;
  1262. var
  1263. H: HKEY;
  1264. S, ExpandedAppId: String;
  1265. begin
  1266. ExpandedAppId := ExpandConst(SetupHeader.AppId);
  1267. if ExpandedAppId <> '' then begin
  1268. if RegOpenKeyExView(InstallDefaultRegView, InstallModeRootKey,
  1269. PChar(GetUninstallRegSubkeyName(GetUninstallRegKeyBaseName(ExpandedAppId))),
  1270. 0, KEY_QUERY_VALUE, H) = ERROR_SUCCESS then begin
  1271. try
  1272. { do not localize or change the following strings }
  1273. if shUsePreviousAppDir in SetupHeader.Options then
  1274. RegQueryStringValue(H, 'Inno Setup: App Path', FPrevAppDir);
  1275. if shUsePreviousGroup in SetupHeader.Options then begin
  1276. RegQueryStringValue(H, 'Inno Setup: Icon Group', PrevGroup);
  1277. if RegValueExists(H, 'Inno Setup: No Icons') then
  1278. PrevNoIcons := True;
  1279. end;
  1280. if shUsePreviousSetupType in SetupHeader.Options then begin
  1281. RegQueryStringValue(H, 'Inno Setup: Setup Type', PrevSetupType);
  1282. if RegQueryStringValue(H, 'Inno Setup: Selected Components', S) then
  1283. SetStringsFromCommaString(PrevSelectedComponents, S);
  1284. if RegQueryStringValue(H, 'Inno Setup: Deselected Components', S) then
  1285. SetStringsFromCommaString(PrevDeselectedComponents, S);
  1286. end;
  1287. if shUsePreviousTasks in SetupHeader.Options then begin
  1288. if RegQueryStringValue(H, 'Inno Setup: Selected Tasks', S) then
  1289. SetStringsFromCommaString(PrevSelectedTasks, S);
  1290. if RegQueryStringValue(H, 'Inno Setup: Deselected Tasks', S) then
  1291. SetStringsFromCommaString(PrevDeselectedTasks, S);
  1292. end;
  1293. if shUsePreviousUserInfo in SetupHeader.Options then begin
  1294. RegQueryStringValue(H, 'Inno Setup: User Info: Name', PrevUserInfoName);
  1295. RegQueryStringValue(H, 'Inno Setup: User Info: Organization', PrevUserInfoOrg);
  1296. RegQueryStringValue(H, 'Inno Setup: User Info: Serial', PrevUserInfoSerial);
  1297. end;
  1298. finally
  1299. RegCloseKey(H);
  1300. end;
  1301. end;
  1302. end;
  1303. end;
  1304. procedure TWizardForm.ChangeReadyLabel(const S: String);
  1305. begin
  1306. ReadyLabel.Caption := S;
  1307. IncTopDecHeight(ReadyMemo, AdjustLabelHeight(ReadyLabel));
  1308. EnableAdjustReadyLabelHeightOnResize := True;
  1309. end;
  1310. procedure TWizardForm.ChangeFinishedLabel(const S: String);
  1311. var
  1312. Y: Integer;
  1313. begin
  1314. FinishedLabel.Caption := S + SNewLine;
  1315. AdjustLabelHeight(FinishedLabel);
  1316. Y := FinishedLabel.Top + FinishedLabel.Height;
  1317. IncTopDecHeight(RunList, Y-YesRadio.Top);
  1318. YesRadio.Top := Y;
  1319. NoRadio.Top := Y + ScalePixelsY(22);
  1320. end;
  1321. procedure TWizardForm.UpdateRunList(const SelectedComponents, SelectedTasks: TStringList);
  1322. var
  1323. RunEntry: PSetupRunEntry;
  1324. Caption: String;
  1325. I: Integer;
  1326. begin
  1327. RunList.Items.Clear();
  1328. for I := 0 to Entries[seRun].Count-1 do begin
  1329. RunEntry := PSetupRunEntry(Entries[seRun][I]);
  1330. if (roPostInstall in RunEntry.Options) and ShouldProcessRunEntry(SelectedComponents, SelectedTasks, RunEntry) then begin
  1331. try
  1332. if RunEntry.Description <> '' then
  1333. Caption := ExpandConst(RunEntry.Description)
  1334. else if not(roShellExec in RunEntry.Options) then
  1335. Caption := FmtSetupMessage1(msgRunEntryExec, PathExtractName(ExpandConst(RunEntry.Name)))
  1336. else
  1337. Caption := FmtSetupMessage1(msgRunEntryShellExec, PathExtractName(ExpandConst(RunEntry.Name)));
  1338. except
  1339. { An exception here killing the entire Setup is not too desirable,
  1340. as post-install [Run] entries are normally unimportant. Just
  1341. display the message and move on. }
  1342. Application.HandleException(Self);
  1343. Caption := '[Error]';
  1344. end;
  1345. RunList.AddCheckBox(Caption, '', 0, not(roUnchecked in RunEntry.Options), True, True, True, TObject(I));
  1346. end;
  1347. end;
  1348. end;
  1349. procedure TWizardForm.CreateTaskButtons(const SelectedComponents: TStringList);
  1350. var
  1351. SaveSelectedTasks, SaveDeselectedTasks: TStringList;
  1352. LastShownTaskEntry, TaskEntry: PSetupTaskEntry;
  1353. NextAllowedLevel, I: Integer;
  1354. Description, GroupDescription: String;
  1355. LastGroupDescription: String;
  1356. begin
  1357. SaveDeselectedTasks := nil;
  1358. SaveSelectedTasks := TStringList.Create;
  1359. try
  1360. SaveDeselectedTasks := TStringList.Create;
  1361. { Save state of current items (if any) }
  1362. GetTasks(SaveSelectedTasks, SaveDeselectedTasks);
  1363. TasksList.Items.Clear();
  1364. LastGroupDescription := '';
  1365. { Create the task items with their default checked states }
  1366. NextAllowedLevel := 0;
  1367. LastShownTaskEntry := nil;
  1368. for I := 0 to Entries[seTask].Count-1 do begin
  1369. TaskEntry := PSetupTaskEntry(Entries[seTask][I]);
  1370. if (TaskEntry.Level <= NextAllowedLevel) and
  1371. (InstallOnThisVersion(TaskEntry.MinVersion, TaskEntry.OnlyBelowVersion) = irInstall) and
  1372. ShouldProcessEntry(SelectedComponents, nil, TaskEntry.Components, '', TaskEntry.Languages, TaskEntry.Check) then begin
  1373. Description := ExpandConst(TaskEntry.Description);
  1374. GroupDescription := ExpandConst(TaskEntry.GroupDescription);
  1375. { See if we should add a group label }
  1376. if (TaskEntry.Level = 0) and (GroupDescription <> LastGroupDescription) then begin
  1377. TasksList.AddGroup(GroupDescription, '', 0, nil);
  1378. LastGroupDescription := GroupDescription;
  1379. end;
  1380. { Create a check box or radio button }
  1381. if toExclusive in TaskEntry.Options then
  1382. TasksList.AddRadioButton(Description, '', TaskEntry.Level,
  1383. not InitDeselectAllTasks and not(toUnchecked in TaskEntry.Options),
  1384. True, TObject(TaskEntry))
  1385. else
  1386. TasksList.AddCheckBox(Description, '', TaskEntry.Level,
  1387. not InitDeselectAllTasks and not(toUnchecked in TaskEntry.Options),
  1388. True, TaskEntry.Used, not(toDontInheritCheck in TaskEntry.Options),
  1389. TObject(TaskEntry));
  1390. NextAllowedLevel := TaskEntry.Level + 1;
  1391. LastShownTaskEntry := TaskEntry;
  1392. end
  1393. else begin
  1394. { Not showing }
  1395. if Assigned(LastShownTaskEntry) and
  1396. (TaskEntry.Level = LastShownTaskEntry.Level) and
  1397. (CompareText(TaskEntry.Name, LastShownTaskEntry.Name) = 0) then begin
  1398. { It's a duplicate of the last shown item. Leave NextAllowedLevel
  1399. alone, so that any child items that follow can attach to the last
  1400. shown item. }
  1401. end
  1402. else begin
  1403. { Not a duplicate of the last shown item, so the next item must be
  1404. at the same level or less }
  1405. if NextAllowedLevel > TaskEntry.Level then
  1406. NextAllowedLevel := TaskEntry.Level;
  1407. { Clear LastShownTaskEntry so that no subsequent item can be
  1408. considered a duplicate of it. Needed in this case:
  1409. foo (shown)
  1410. foo\childA (not shown)
  1411. foo (not shown)
  1412. foo\childB
  1413. "foo\childB" should be hidden, not made a child of "foo" #1. }
  1414. LastShownTaskEntry := nil;
  1415. end;
  1416. end;
  1417. end;
  1418. { Restore the previous checked state of the items we just created }
  1419. if not InitDeselectAllTasks then begin
  1420. for I := 0 to TasksList.Items.Count-1 do begin
  1421. TaskEntry := PSetupTaskEntry(TasksList.ItemObject[I]);
  1422. if TaskEntry <> nil then begin
  1423. if ListContains(PrevSelectedTasks, TaskEntry.Name) then
  1424. TasksList.Checked[I] := not(toCheckedOnce in TaskEntry.Options)
  1425. else if ListContains(PrevDeselectedTasks, TaskEntry.Name) then
  1426. TasksList.Checked[I] := False;
  1427. end;
  1428. end;
  1429. end;
  1430. { Override previous state with tasks specified on the command line }
  1431. if InitTasks.Count > 0 then begin
  1432. for I := 0 to TasksList.Items.Count-1 do begin
  1433. TaskEntry := PSetupTaskEntry(TasksList.ItemObject[I]);
  1434. if TaskEntry <> nil then begin
  1435. if ListContains(InitTasks, '*' + TaskEntry.Name) then
  1436. TasksList.CheckItem(I, coCheckWithChildren)
  1437. else if ListContains(InitTasks, TaskEntry.Name) then
  1438. TasksList.Checked[I] := True
  1439. else if ListContains(InitTasks, '!' + TaskEntry.Name) then
  1440. TasksList.Checked[I] := False;
  1441. end;
  1442. end;
  1443. end;
  1444. { Finally, restore any saved state from when the page was last shown }
  1445. SelectTasks(SaveSelectedTasks, SaveDeselectedTasks);
  1446. finally
  1447. SaveDeselectedTasks.Free;
  1448. SaveSelectedTasks.Free;
  1449. end;
  1450. end;
  1451. function TWizardForm.GetSetupType(): PSetupTypeEntry;
  1452. var
  1453. Index: Integer;
  1454. begin
  1455. Index := TypesCombo.ItemIndex;
  1456. if Index <> -1 then
  1457. Result := PSetupTypeEntry(TypesCombo.Items.Objects[TypesCombo.ItemIndex])
  1458. else
  1459. Result := nil;
  1460. end;
  1461. procedure TWizardForm.SelectComponents(const SelectComponents, DeselectComponents: TStringList; const KeepFixedComponents: Boolean);
  1462. var
  1463. I: Integer;
  1464. ComponentEntry: PSetupComponentEntry;
  1465. begin
  1466. for I := 0 to Entries[seComponent].Count-1 do begin
  1467. ComponentEntry := PSetupComponentEntry(Entries[seComponent][I]);
  1468. if not (KeepFixedComponents and (coFixed in ComponentEntry.Options)) then begin
  1469. if SelectComponents <> nil then begin
  1470. if ListContains(SelectComponents, '*' + ComponentEntry.Name) then begin
  1471. ComponentsList.CheckItem(I, coCheckWithChildren);
  1472. Continue;
  1473. end;
  1474. if ListContains(SelectComponents, ComponentEntry.Name) then begin
  1475. ComponentsList.Checked[I] := True;
  1476. Continue;
  1477. end;
  1478. if ListContains(SelectComponents, '!' + ComponentEntry.Name) then begin
  1479. ComponentsList.Checked[I] := False;
  1480. Continue;
  1481. end;
  1482. end;
  1483. if DeselectComponents <> nil then begin
  1484. if ListContains(DeselectComponents, ComponentEntry.Name) then
  1485. ComponentsList.Checked[I] := False;
  1486. end;
  1487. end;
  1488. end;
  1489. end;
  1490. procedure TWizardForm.SelectComponents(const ASelectComponents: TStringList);
  1491. begin
  1492. SelectComponents(ASelectComponents, nil, False);
  1493. UpdateComponentSizes;
  1494. CalcCurrentComponentsSpace;
  1495. end;
  1496. procedure TWizardForm.SelectTasks(const SelectTasks, DeselectTasks: TStringList);
  1497. var
  1498. I: Integer;
  1499. TaskEntry: PSetupTaskEntry;
  1500. begin
  1501. for I := 0 to TasksList.Items.Count-1 do begin
  1502. TaskEntry := PSetupTaskEntry(TasksList.ItemObject[I]);
  1503. if TaskEntry <> nil then begin
  1504. if SelectTasks <> nil then begin
  1505. if ListContains(SelectTasks, TaskEntry.Name) then begin
  1506. TasksList.Checked[I] := True;
  1507. Continue;
  1508. end;
  1509. if ListContains(SelectTasks, '!' + TaskEntry.Name) then begin
  1510. TasksList.Checked[I] := False;
  1511. Continue;
  1512. end;
  1513. end;
  1514. if DeselectTasks <> nil then begin
  1515. if ListContains(DeselectTasks, TaskEntry.Name) then
  1516. TasksList.Checked[I] := False;
  1517. end;
  1518. end;
  1519. end;
  1520. end;
  1521. procedure TWizardForm.SelectTasks(const ASelectTasks: TStringList);
  1522. begin
  1523. SelectTasks(ASelectTasks, nil);
  1524. end;
  1525. procedure TWizardForm.SelectComponentsFromType(const TypeName: String; const OnlySelectFixedComponents: Boolean);
  1526. var
  1527. ComponentTypes: TStringList;
  1528. ComponentEntry: PSetupComponentEntry;
  1529. I: Integer;
  1530. begin
  1531. ComponentTypes := TStringList.Create();
  1532. for I := 0 to Entries[seComponent].Count-1 do begin
  1533. ComponentEntry := PSetupComponentEntry(Entries[seComponent][I]);
  1534. if not OnlySelectFixedComponents or (coFixed in ComponentEntry.Options) then begin
  1535. SetStringsFromCommaString(ComponentTypes, ComponentEntry.Types);
  1536. ComponentsList.Checked[I] := ListContains(ComponentTypes, TypeName);
  1537. end;
  1538. end;
  1539. ComponentTypes.Free();
  1540. end;
  1541. procedure TWizardForm.UpdateSelectTasksPage;
  1542. var
  1543. SelectedComponents: TStringList;
  1544. begin
  1545. SelectedComponents := TStringList.Create();
  1546. try
  1547. GetSelectedComponents(SelectedComponents, False, False);
  1548. CreateTaskButtons(SelectedComponents);
  1549. finally
  1550. SelectedComponents.Free();
  1551. end;
  1552. end;
  1553. procedure TWizardForm.GetSelectedComponents(Components: TStringList; const Descriptions, IndentDescriptions: Boolean);
  1554. function GetString(ComponentEntry: PSetupComponentEntry; Descriptions: Boolean): String;
  1555. begin
  1556. if Descriptions then begin
  1557. Result := ExpandConst(ComponentEntry.Description);
  1558. if IndentDescriptions then
  1559. Result := StringOfChar(' ', 3*ComponentEntry.Level) + Result;
  1560. end else
  1561. Result := ComponentEntry.Name;
  1562. end;
  1563. var
  1564. ComponentEntry: PSetupComponentEntry;
  1565. I: Integer;
  1566. begin
  1567. Components.Clear();
  1568. for I := 0 to ComponentsList.Items.Count-1 do begin
  1569. if ComponentsList.Checked[I] then begin
  1570. ComponentEntry := PSetupComponentEntry(ComponentsList.ItemObject[I]);
  1571. Components.Add(GetString(ComponentEntry, Descriptions));
  1572. end;
  1573. end;
  1574. end;
  1575. procedure TWizardForm.GetSelectedTasks(Tasks: TStringList; const Descriptions, IndentDescriptions, GroupDescriptions: Boolean);
  1576. function GetString(TaskEntry: PSetupTaskEntry; Descriptions, IndentDescriptions: Boolean; IndentLevel: Integer): String;
  1577. begin
  1578. if Descriptions then begin
  1579. Result := RemoveAccelChar(ExpandConst(TaskEntry.Description));
  1580. if IndentDescriptions then
  1581. Result := StringOfChar(' ', 3*IndentLevel) + Result;
  1582. end else
  1583. Result := TaskEntry.Name;
  1584. end;
  1585. var
  1586. TaskEntry: PSetupTaskEntry;
  1587. I, IndentLevel: Integer;
  1588. GroupDescription, LastGroupDescription: String;
  1589. begin
  1590. Tasks.Clear();
  1591. if GroupDescriptions then
  1592. LastGroupDescription := '';
  1593. for I := 0 to TasksList.Items.Count-1 do begin
  1594. if TasksList.Checked[I] and (TasksList.ItemObject[I] <> nil) then begin
  1595. TaskEntry := PSetupTaskEntry(TasksList.ItemObject[I]);
  1596. if GroupDescriptions then begin
  1597. GroupDescription := ExpandConst(TaskEntry.GroupDescription);
  1598. if (TaskEntry.Level = 0) and (GroupDescription <> LastGroupDescription) then begin
  1599. if GroupDescription <> '' then
  1600. Tasks.Add(RemoveAccelChar(GroupDescription));
  1601. LastGroupDescription := GroupDescription;
  1602. end;
  1603. IndentLevel := TaskEntry.Level;
  1604. if LastGroupDescription <> '' then
  1605. Inc(IndentLevel);
  1606. end else
  1607. IndentLevel := TaskEntry.Level;
  1608. Tasks.Add(GetString(TaskEntry, Descriptions, IndentDescriptions, IndentLevel));
  1609. end;
  1610. end;
  1611. end;
  1612. procedure TWizardForm.GetComponents(SelectedComponents, DeselectedComponents: TStringList);
  1613. { Gets names of components that are currently selected and deselected }
  1614. var
  1615. I: Integer;
  1616. ComponentEntry: PSetupComponentEntry;
  1617. begin
  1618. SelectedComponents.Clear;
  1619. if DeselectedComponents <> nil then
  1620. DeselectedComponents.Clear;
  1621. for I := 0 to ComponentsList.Items.Count-1 do begin
  1622. ComponentEntry := PSetupComponentEntry(ComponentsList.ItemObject[I]);
  1623. if ComponentsList.Checked[I] then
  1624. SelectedComponents.Add(ComponentEntry.Name)
  1625. else if DeselectedComponents <> nil then
  1626. DeselectedComponents.Add(ComponentEntry.Name);
  1627. end;
  1628. end;
  1629. procedure TWizardForm.GetTasks(SelectedTasks, DeselectedTasks: TStringList);
  1630. { Gets names of tasks that are currently selected and deselected }
  1631. var
  1632. I: Integer;
  1633. TaskEntry: PSetupTaskEntry;
  1634. begin
  1635. SelectedTasks.Clear;
  1636. if DeselectedTasks <> nil then
  1637. DeselectedTasks.Clear;
  1638. for I := 0 to TasksList.Items.Count-1 do begin
  1639. TaskEntry := PSetupTaskEntry(TasksList.ItemObject[I]);
  1640. if TaskEntry <> nil then begin
  1641. if TasksList.Checked[I] then
  1642. SelectedTasks.Add(TaskEntry.Name)
  1643. else if DeselectedTasks <> nil then
  1644. DeselectedTasks.Add(TaskEntry.Name);
  1645. end;
  1646. end;
  1647. end;
  1648. function TWizardForm.PrepareToInstall(const WizardComponents, WizardTasks: TStringList): String;
  1649. var
  1650. CodeNeedsRestart: Boolean;
  1651. Y: Integer;
  1652. begin
  1653. Result := '';
  1654. PrepareToInstallNeedsRestart := False;
  1655. PreparingErrorBitmapImage.Visible := False;
  1656. PreparingLabel.Visible := False;
  1657. PreparingYesRadio.Visible := False;
  1658. PreparingNoRadio.Visible := False;
  1659. PreparingMemo.Visible := False;
  1660. if not PreviousInstallCompleted(WizardComponents, WizardTasks) then begin
  1661. Result := ExpandSetupMessage(msgPreviousInstallNotCompleted);
  1662. PrepareToInstallNeedsRestart := True;
  1663. end else if (CodeRunner <> nil) and CodeRunner.FunctionExists('PrepareToInstall', True) then begin
  1664. SetCurPage(wpPreparing);
  1665. BackButton.Visible := False;
  1666. NextButton.Visible := False;
  1667. CancelButton.Enabled := False;
  1668. if InstallMode = imSilent then begin
  1669. SetActiveWindow(Application.Handle); { ensure taskbar button is selected }
  1670. WizardForm.Show;
  1671. end;
  1672. WizardForm.Update;
  1673. try
  1674. DownloadTemporaryFileProcessMessages := True;
  1675. CodeNeedsRestart := False;
  1676. Result := CodeRunner.RunStringFunctions('PrepareToInstall', [@CodeNeedsRestart], bcNonEmpty, True, '');
  1677. PrepareToInstallNeedsRestart := (Result <> '') and CodeNeedsRestart;
  1678. finally
  1679. DownloadTemporaryFileProcessMessages := False;
  1680. UpdateCurPageButtonState;
  1681. end;
  1682. Application.BringToFront;
  1683. end;
  1684. if Result <> '' then begin
  1685. if PrepareToInstallNeedsRestart then
  1686. PreparingLabel.Caption := Result +
  1687. SNewLine + SNewLine + SNewLine + ExpandSetupMessage(msgPrepareToInstallNeedsRestart) + SNewLine
  1688. else
  1689. PreparingLabel.Caption := Result +
  1690. SNewLine + SNewLine + SNewLine + SetupMessages[msgCannotContinue];
  1691. AdjustLabelHeight(PreparingLabel);
  1692. PreparingErrorBitmapImage.Visible := True;
  1693. PreparingLabel.Visible := True;
  1694. if PrepareToInstallNeedsRestart then begin
  1695. Y := PreparingLabel.Top + PreparingLabel.Height;
  1696. PreparingYesRadio.Top := Y;
  1697. PreparingYesRadio.Anchors := [akLeft, akTop, akRight];
  1698. PreparingYesRadio.Caption := SetupMessages[msgYesRadio];
  1699. PreparingYesRadio.Visible := True;
  1700. PreparingNoRadio.Top := Y + ScalePixelsY(22);
  1701. PreparingNoRadio.Anchors := [akLeft, akTop, akRight];
  1702. PreparingNoRadio.Caption := SetupMessages[msgNoRadio];
  1703. PreparingNoRadio.Visible := True;
  1704. end;
  1705. end;
  1706. end;
  1707. function TWizardForm.QueryRestartManager(const WizardComponents, WizardTasks: TStringList): String;
  1708. procedure CheckAndAddRebootReasonToString(var S: String; const RebootReasons, RebootReason: Integer; const RebootReasonString: String);
  1709. begin
  1710. if (RebootReasons and RebootReason) <> 0 then begin
  1711. if S <> '' then
  1712. S := S + '+';
  1713. S := S + RebootReasonString;
  1714. end;
  1715. end;
  1716. function RebootReasonsToString(const RebootReasons: Integer): String;
  1717. var
  1718. UnknownReasons: Integer;
  1719. begin
  1720. Result := '';
  1721. if RebootReasons <> RmRebootReasonNone then begin
  1722. CheckAndAddRebootReasonToString(Result, RebootReasons, RmRebootReasonPermissionDenied, 'Permission Denied');
  1723. CheckAndAddRebootReasonToString(Result, RebootReasons, RmRebootReasonSessionMismatch, 'Session Mismatch');
  1724. CheckAndAddRebootReasonToString(Result, RebootReasons, RmRebootReasonCriticalProcess, 'Critical Process');
  1725. CheckAndAddRebootReasonToString(Result, RebootReasons, RmRebootReasonCriticalService, 'Critical Service');
  1726. CheckAndAddRebootReasonToString(Result, RebootReasons, RmRebootReasonDetectedSelf, 'Detected Self');
  1727. UnknownReasons := RebootReasons and not (RmRebootReasonNone or RmRebootReasonPermissionDenied or
  1728. RmRebootReasonSessionMismatch or RmRebootReasonCriticalProcess or
  1729. RmRebootReasonCriticalService or RmRebootReasonDetectedSelf);
  1730. CheckAndAddRebootReasonToString(Result, RebootReasons, UnknownReasons, Format('Unknown Reason(s) %d', [UnknownReasons]));
  1731. Result := ': ' + Result;
  1732. end;
  1733. Result := IntToStr(RebootReasons) + Result;
  1734. end;
  1735. type
  1736. TArrayOfProcessInfo = array[0..(MaxInt div SizeOf(RM_PROCESS_INFO))-1] of RM_PROCESS_INFO;
  1737. PArrayOfProcessInfo = ^TArrayOfProcessInfo;
  1738. var
  1739. Y, I: Integer;
  1740. ProcessInfosCount, ProcessInfosCountNeeded, RebootReasons: Integer;
  1741. ProcessInfos: PArrayofProcessInfo;
  1742. AppName: String;
  1743. begin
  1744. { Clear existing registered resources if we get here a second time (user clicked Back after first time). There
  1745. doesn't seem to be function to do this directly, so restart the session instead. }
  1746. if RmRegisteredFilesCount <> 0 then begin
  1747. RmEndSession(RmSessionHandle);
  1748. if RmStartSession(@RmSessionHandle, 0, RmSessionKey) <> ERROR_SUCCESS then
  1749. RmSessionStarted := False;
  1750. end;
  1751. if RmSessionStarted then
  1752. RegisterResourcesWithRestartManager(WizardComponents, WizardTasks); { This will update RmSessionStarted and RmRegisteredFilesCount }
  1753. if RmSessionStarted then begin
  1754. LogFmt('Found %d files to register with RestartManager.', [RmRegisteredFilesCount]);
  1755. if RmRegisteredFilesCount > 0 then begin
  1756. ProcessInfosCount := 0;
  1757. ProcessInfosCountNeeded := 5; { Start with 5 to hopefully avoid a realloc }
  1758. ProcessInfos := nil;
  1759. try
  1760. Log('Calling RestartManager''s RmGetList.');
  1761. while ProcessInfosCount < ProcessInfosCountNeeded do begin
  1762. if ProcessInfos <> nil then
  1763. FreeMem(ProcessInfos);
  1764. GetMem(ProcessInfos, ProcessInfosCountNeeded * SizeOf(ProcessInfos[0]));
  1765. ProcessInfosCount := ProcessInfosCountNeeded;
  1766. if not RmGetList(RmSessionHandle, @ProcessInfosCountNeeded, @ProcessInfosCount, ProcessInfos, @RebootReasons) in [ERROR_SUCCESS, ERROR_MORE_DATA] then begin
  1767. RmEndSession(RmSessionHandle);
  1768. RmSessionStarted := False;
  1769. Break;
  1770. end;
  1771. end;
  1772. if RmSessionStarted then begin
  1773. Log('RmGetList finished successfully.');
  1774. if ProcessInfosCount > 0 then begin
  1775. for I := 0 to ProcessInfosCount-1 do begin
  1776. AppName := WideCharToString(ProcessInfos[I].strAppName);
  1777. LogFmt('RestartManager found an application using one of our files: %s', [AppName]);
  1778. if RebootReasons = RmRebootReasonNone then begin
  1779. if Result <> '' then
  1780. Result := Result + #13#10;
  1781. Result := Result + AppName;
  1782. end;
  1783. end;
  1784. LogFmt('Can use RestartManager to avoid reboot? %s (%s)', [SYesNo[RebootReasons = RmRebootReasonNone], RebootReasonsToString(RebootReasons)]);
  1785. end else
  1786. Log('RestartManager found no applications using one of our files.');
  1787. end else
  1788. Log('RmGetList failed.');
  1789. finally
  1790. if ProcessInfos <> nil then
  1791. FreeMem(ProcessInfos);
  1792. end;
  1793. end;
  1794. end;
  1795. if Result <> '' then begin
  1796. if InitRestartApplications or
  1797. ((shRestartApplications in SetupHeader.Options) and not InitNoRestartApplications) then
  1798. PreparingLabel.Caption := SetupMessages[msgApplicationsFound2]
  1799. else
  1800. PreparingLabel.Caption := SetupMessages[msgApplicationsFound];
  1801. Y := PreparingLabel.Top + PreparingLabel.Height + ScalePixelsY(12);
  1802. PreparingMemo.Top := Y;
  1803. IncTopDecHeight(PreparingMemo, AdjustLabelHeight(PreparingLabel));
  1804. AdjustLabelHeight(PreparingLabel);
  1805. PreparingErrorBitmapImage.Visible := True;
  1806. PreparingLabel.Visible := True;
  1807. PreparingMemo.Text := Result;
  1808. PreparingMemo.Visible := True;
  1809. Y := PreparingMemo.Top + PreparingMemo.Height + ScalePixelsY(12);
  1810. PreparingYesRadio.Top := Y;
  1811. PreparingYesRadio.Anchors := [akLeft, akRight, akBottom];
  1812. PreparingYesRadio.Caption := SetupMessages[msgCloseApplications];
  1813. PreparingYesRadio.Visible := True;
  1814. PreparingNoRadio.Top := Y + ScalePixelsY(22);
  1815. PreparingNoRadio.Anchors := [akLeft, akRight, akBottom];
  1816. PreparingNoRadio.Caption := SetupMessages[msgDontCloseApplications];
  1817. PreparingNoRadio.Visible := True;
  1818. end;
  1819. end;
  1820. procedure TWizardForm.UpdatePage(const PageID: Integer);
  1821. procedure ReadyMemoAppend(const Lines: String);
  1822. begin
  1823. if Lines <> '' then begin
  1824. if ReadyMemo.Lines.Count > 0 then
  1825. ReadyMemo.Lines.Append('');
  1826. ReadyMemo.Lines.Append(Lines);
  1827. end;
  1828. end;
  1829. procedure UpdateReadyPage;
  1830. const
  1831. Space = ' ';
  1832. var
  1833. TypeEntry: PSetupTypeEntry;
  1834. SelectedComponents, SelectedTasks: TStringList;
  1835. S, MemoUserInfoInfo, MemoDirInfo, MemoGroupInfo, MemoTypeInfo, MemoComponentsInfo, MemoTasksInfo: String;
  1836. I: Integer;
  1837. begin
  1838. ReadyMemo.Visible := False;
  1839. if not (shDisableReadyMemo in SetupHeader.Options) then begin
  1840. ReadyMemo.Lines.Clear();
  1841. if shUserInfoPage in SetupHeader.Options then begin
  1842. MemoUserInfoInfo := SetupMessages[msgReadyMemoUserInfo];
  1843. MemoUserInfoInfo := MemoUserInfoInfo+SNewLine+Space+UserInfoNameEdit.Text;
  1844. if UserInfoOrgEdit.Text <> '' then
  1845. MemoUserInfoInfo := MemoUserInfoInfo+SNewLine+Space+UserInfoOrgEdit.Text;
  1846. end;
  1847. if (shAlwaysShowDirOnReadyPage in SetupHeader.Options) or
  1848. (not DisableDirPage and
  1849. (shCreateAppDir in SetupHeader.Options)) then begin
  1850. MemoDirInfo := SetupMessages[msgReadyMemoDir];
  1851. MemoDirInfo := MemoDirInfo+SNewLine+Space+DirEdit.Text;
  1852. end else
  1853. MemoDirInfo := '';
  1854. if HasComponents then begin
  1855. TypeEntry := GetSetupType();
  1856. if TypeEntry <> nil then begin
  1857. MemoTypeInfo := SetupMessages[msgReadyMemoType];
  1858. MemoTypeInfo := MemoTypeInfo+SNewLine+Space+ExpandConst(TypeEntry.Description);
  1859. end else
  1860. MemoTypeInfo := ''; { can get here if all types failed their Check }
  1861. SelectedComponents := TStringList.Create();
  1862. GetSelectedComponents(SelectedComponents, True, True);
  1863. if SelectedComponents.Count > 0 then begin
  1864. MemoComponentsInfo := SetupMessages[msgReadyMemoComponents];
  1865. for I := 0 to SelectedComponents.Count-1 do
  1866. MemoComponentsInfo := MemoComponentsInfo+SNewLine+Space+SelectedComponents[I];
  1867. end else
  1868. MemoComponentsInfo := '';
  1869. SelectedComponents.Free();
  1870. end;
  1871. if HasIcons and not NoIconsCheck.Checked and
  1872. ((shAlwaysShowGroupOnReadyPage in SetupHeader.Options) or
  1873. not DisableProgramGroupPage) then begin
  1874. MemoGroupInfo := SetupMessages[msgReadyMemoGroup];
  1875. MemoGroupInfo := MemoGroupInfo+SNewLine+Space+GroupEdit.Text;
  1876. end else
  1877. MemoGroupInfo := '';
  1878. SelectedTasks := TStringList.Create();
  1879. GetSelectedTasks(SelectedTasks, True, True, True);
  1880. if SelectedTasks.Count > 0 then begin
  1881. MemoTasksInfo := SetupMessages[msgReadyMemoTasks];
  1882. for I := 0 to SelectedTasks.Count-1 do
  1883. MemoTasksInfo := MemoTasksInfo+SNewLine+Space+SelectedTasks[I];
  1884. end else
  1885. MemoTasksInfo := '';
  1886. SelectedTasks.Free();
  1887. if (CodeRunner <> nil) and CodeRunner.FunctionExists('UpdateReadyMemo', True) then begin
  1888. try
  1889. ReadyMemo.Lines.Text := CodeRunner.RunStringFunctions('UpdateReadyMemo',
  1890. [Space, SNewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo,
  1891. MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo], bcNonEmpty, True, '');
  1892. except
  1893. Application.HandleException(Self);
  1894. end;
  1895. end else begin
  1896. ReadyMemoAppend(MemoUserInfoInfo);
  1897. ReadyMemoAppend(MemoDirInfo);
  1898. ReadyMemoAppend(MemoTypeInfo);
  1899. ReadyMemoAppend(MemoComponentsInfo);
  1900. ReadyMemoAppend(MemoGroupInfo);
  1901. ReadyMemoAppend(MemoTasksInfo);
  1902. end;
  1903. ReadyMemo.SelStart := 0;
  1904. ReadyMemo.SelLength := 0;
  1905. end;
  1906. if ReadyMemo.Lines.Count > 0 then begin
  1907. S := SetupMessages[msgReadyLabel2a];
  1908. ChangeReadyLabel(S);
  1909. ReadyMemo.Visible := True;
  1910. end else begin
  1911. S := SetupMessages[msgReadyLabel2b];
  1912. ChangeReadyLabel(S);
  1913. end;
  1914. end;
  1915. begin
  1916. case PageID of
  1917. wpSelectTasks: UpdateSelectTasksPage;
  1918. wpReady: UpdateReadyPage;
  1919. end;
  1920. end;
  1921. procedure TWizardForm.AdjustFocus;
  1922. var
  1923. NewActiveControl: TWinControl;
  1924. begin
  1925. if CurPageID = wpReady then
  1926. NewActiveControl := NextButton
  1927. else if (CurPageID = wpPreparing) and (PrepareToInstallFailureMessage <> '') and not PrepareToInstallNeedsRestart then
  1928. NewActiveControl := CancelButton
  1929. else if (CurPageID = wpPreparing) and (PrepareToInstallFailureMessage = '') and PreparingYesRadio.CanFocus then
  1930. NewActiveControl := PreparingYesRadio
  1931. else
  1932. NewActiveControl := FindNextControl(nil, True, True, False);
  1933. if (NewActiveControl = BackButton) and NextButton.CanFocus then
  1934. NewActiveControl := NextButton;
  1935. ActiveControl := NewActiveControl;
  1936. end;
  1937. function TWizardForm.GetPreviousPageID: Integer;
  1938. { Finds ID of previous page (not counting skipped pages), or -1 if there is
  1939. no previous page to return to. }
  1940. var
  1941. CurPageIndex, I: Integer;
  1942. begin
  1943. CurPageIndex := PageIndexFromID(CurPageID);
  1944. for I := CurPageIndex-1 downto 0 do begin
  1945. Result := TWizardPage(FPageList[I]).ID;
  1946. { Never go back to wpInstalling }
  1947. if Result = wpInstalling then
  1948. Break;
  1949. if not ShouldSkipPage(Result) then
  1950. Exit;
  1951. end;
  1952. Result := -1;
  1953. end;
  1954. procedure TWizardForm.UpdateCurPageButtonState;
  1955. var
  1956. PageIndex: Integer;
  1957. Page: TWizardPage;
  1958. Flags: UINT;
  1959. begin
  1960. PageIndex := PageIndexFromID(CurPageID);
  1961. Page := FPageList[PageIndex];
  1962. if not(psNoButtons in Page.Style) then begin
  1963. BackButton.Visible := (CurPageID <> wpInstalling) and (GetPreviousPageID <> -1);
  1964. NextButton.Visible := CurPageID <> wpInstalling;
  1965. case CurPageID of
  1966. wpLicense: NextButton.Enabled := LicenseAcceptedRadio.Checked;
  1967. wpPreparing: NextButton.Enabled := (PrepareToInstallFailureMessage = '') or PrepareToInstallNeedsRestart;
  1968. else
  1969. NextButton.Enabled := True;
  1970. end;
  1971. CancelButton.Visible := (PageIndex <= PageIndexFromID(wpInstalling)) and
  1972. not ((CurPageID = wpPreparing) and PrepareToInstallNeedsRestart);
  1973. CancelButton.Enabled := (CurPageID <> wpInstalling) or
  1974. ((shAllowCancelDuringInstall in SetupHeader.Options) and not InitNoCancel);
  1975. end
  1976. else begin
  1977. BackButton.Visible := False;
  1978. NextButton.Visible := False;
  1979. CancelButton.Visible := False;
  1980. end;
  1981. { Set the enabled state of the close button to match the Cancel button }
  1982. if CancelButton.CanFocus then
  1983. Flags := 0
  1984. else
  1985. Flags := MF_GRAYED;
  1986. EnableMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, MF_BYCOMMAND or Flags);
  1987. end;
  1988. procedure TWizardForm.SetCurPage(const NewPageID: Integer);
  1989. { Changes which page is currently visible }
  1990. var
  1991. Page: TWizardPage;
  1992. begin
  1993. Page := PageFromID(NewPageID);
  1994. FCurPageID := NewPageID;
  1995. { Select the page in the notebooks }
  1996. if Assigned(Page.InnerNotebookPage) then
  1997. InnerNotebook.ActivePage := Page.InnerNotebookPage;
  1998. OuterNotebook.ActivePage := Page.OuterNotebookPage;
  1999. { Set the page description }
  2000. Page.SyncCaptionAndDescription;
  2001. BeveledLabel.Visible := (BeveledLabel.Caption <> '') and
  2002. not(CurPageID in [wpWelcome, wpFinished]);
  2003. { Set button visibility and captions }
  2004. UpdateCurPageButtonState;
  2005. BackButton.Caption := SetupMessages[msgButtonBack];
  2006. if CurPageID = wpReady then begin
  2007. NextButton.Caption := SetupMessages[msgButtonInstall];
  2008. CancelButton.Caption := SetupMessages[msgButtonCancel];
  2009. end else if ((CurPageID = wpPreparing) and PrepareToInstallNeedsRestart) or (CurPageID = wpFinished) then begin
  2010. NextButton.Caption := SetupMessages[msgButtonFinish];
  2011. CancelButton.Caption := SetupMessages[msgButtonCancel];
  2012. end else begin
  2013. NextButton.Caption := SetupMessages[msgButtonNext];
  2014. CancelButton.Caption := SetupMessages[msgButtonCancel];
  2015. end;
  2016. { Adjust focus }
  2017. AdjustFocus;
  2018. { If on the wpUserInfo page, check the serial now, after the rest of the
  2019. page is initialized in case the event function happens to display a
  2020. message box or raise an exception }
  2021. if CurPageID = wpUserInfo then begin
  2022. try
  2023. NextButton.Enabled := CheckSerialOk();
  2024. except
  2025. NextButton.Enabled := False;
  2026. Application.HandleException(Self);
  2027. end;
  2028. end;
  2029. try
  2030. PageFromID(CurPageID).Activate;
  2031. except
  2032. Application.HandleException(Self);
  2033. end;
  2034. try
  2035. if CodeRunner <> nil then
  2036. CodeRunner.RunProcedures('CurPageChanged', [CurPageID], False);
  2037. except
  2038. Application.HandleException(Self);
  2039. end;
  2040. end;
  2041. function TWizardForm.ShouldSkipPage(const PageID: Integer): Boolean;
  2042. begin
  2043. if (PageID = wpReady) and not Visible then begin
  2044. Result := False;
  2045. Exit;
  2046. end;
  2047. Result :=
  2048. (psAlwaysSkip in PageFromID(PageID).Style) or
  2049. ((PageID = wpWelcome) and (shDisableWelcomePage in SetupHeader.Options)) or
  2050. ((PageID = wpLicense) and ((ActiveLicenseText = '') or (InstallMode <> imNormal))) or
  2051. ((PageID = wpPassword) and not NeedPassword) or
  2052. ((PageID = wpInfoBefore) and (ActiveInfoBeforeText = '')) or
  2053. ((PageID = wpUserInfo) and not(shUserInfoPage in SetupHeader.Options)) or
  2054. ((PageID = wpSelectDir) and (DisableDirPage or not(shCreateAppDir in SetupHeader.Options))) or
  2055. ((PageID = wpSelectComponents) and not HasComponents) or
  2056. ((PageID = wpSelectProgramGroup) and (DisableProgramGroupPage or not HasIcons)) or
  2057. ((PageID = wpSelectTasks) and (TasksList.Items.Count = 0)) or
  2058. ((PageID = wpReady) and (shDisableReadyPage in SetupHeader.Options)) or
  2059. ((PageID = wpPreparing)) or
  2060. ((PageID = wpInfoAfter) and (ActiveInfoAfterText = '')) or
  2061. ((PageID = wpFinished) and (shDisableFinishedPage in SetupHeader.Options) and not (NeedsRestart and not InitNoRestart));
  2062. if not Result and not (PageID in [wpPreparing]) then begin
  2063. try
  2064. PageFromID(PageID).ShouldSkipPage(Result);
  2065. except
  2066. Application.HandleException(Self);
  2067. end;
  2068. if not Result then begin
  2069. try
  2070. if CodeRunner <> nil then
  2071. Result := CodeRunner.RunBooleanFunctions('ShouldSkipPage', [PageID], bcTrue, False, Result);
  2072. except
  2073. Application.HandleException(Self);
  2074. end;
  2075. end;
  2076. end;
  2077. end;
  2078. procedure TWizardForm.NextButtonClick(Sender: TObject);
  2079. function CheckPassword: Boolean;
  2080. { Also see Main.HandleInitPassword }
  2081. var
  2082. S: String;
  2083. SaveCursor: HCURSOR;
  2084. begin
  2085. Result := False;
  2086. S := PasswordEdit.Text;
  2087. if shPassword in SetupHeader.Options then
  2088. Result := TestPassword(S);
  2089. if not Result and (CodeRunner <> nil) then
  2090. Result := CodeRunner.RunBooleanFunctions('CheckPassword', [S], bcTrue, False, Result);
  2091. if Result then begin
  2092. NeedPassword := False;
  2093. if shEncryptionUsed in SetupHeader.Options then
  2094. FileExtractor.CryptKey := S;
  2095. PasswordEdit.Text := '';
  2096. end else begin
  2097. { Delay for 750 ms when an incorrect password is entered to
  2098. discourage brute-force attempts }
  2099. if Visible then begin
  2100. SaveCursor := GetCursor;
  2101. SetCursor(LoadCursor(0, IDC_WAIT));
  2102. Sleep(750);
  2103. SetCursor(SaveCursor);
  2104. end;
  2105. LoggedMsgBox(SetupMessages[msgIncorrectPassword], '', mbError, MB_OK, True, IDOK);
  2106. if Visible then begin
  2107. PasswordEdit.Text := '';
  2108. PasswordEdit.SetFocus;
  2109. end;
  2110. end;
  2111. end;
  2112. function CheckUserInfoPage: Boolean;
  2113. begin
  2114. UserInfoNameEdit.Text := Trim(UserInfoNameEdit.Text);
  2115. UserInfoOrgEdit.Text := Trim(UserInfoOrgEdit.Text);
  2116. { Note: We don't require a user name to be entered on silent installs,
  2117. since the default value in the registry could be blank (at least this
  2118. was the case for one user). }
  2119. Result := (UserInfoNameEdit.Text <> '') or (InstallMode <> imNormal);
  2120. if Result then begin
  2121. WizardUserInfoName := UserInfoNameEdit.Text;
  2122. WizardUserInfoOrg := UserInfoOrgEdit.Text;
  2123. WizardUserInfoSerial := UserInfoSerialEdit.Text;
  2124. end
  2125. else begin
  2126. LoggedMsgBox(SetupMessages[msgUserInfoNameRequired], '', mbError, MB_OK, True, IDOK);
  2127. if Visible then
  2128. UserInfoNameEdit.SetFocus;
  2129. end;
  2130. end;
  2131. function CheckSelectDirPage: Boolean;
  2132. var
  2133. T: String;
  2134. FreeSpace, TotalSpace: Integer64;
  2135. begin
  2136. Result := False;
  2137. if not ValidateDirEdit then
  2138. Exit;
  2139. T := DirEdit.Text;
  2140. if InstallMode = imNormal then begin
  2141. { Check if there's enough free disk space }
  2142. if GetSpaceOnNearestMountPoint(False, T, FreeSpace, TotalSpace) then begin
  2143. if Compare64(FreeSpace, MinimumSpace) < 0 then
  2144. { If not, show warning }
  2145. if LoggedMsgBox(FmtSetupMessage(msgDiskSpaceWarning,
  2146. [IntToKBStr(MinimumSpace), IntToKBStr(FreeSpace)]),
  2147. SetupMessages[msgDiskSpaceWarningTitle],
  2148. mbConfirmation, MB_YESNO or MB_DEFBUTTON2, True, IDYES) <> IDYES then
  2149. Exit;
  2150. end;
  2151. { Check if directory already exists }
  2152. if ((SetupHeader.DirExistsWarning = ddYes) or
  2153. ((SetupHeader.DirExistsWarning = ddAuto) and (T <> PrevAppDir))) and
  2154. DirExists(T) then
  2155. { If so, ask if user wants to install there anyway }
  2156. if LoggedMsgBox(FmtSetupMessage1(msgDirExists, T), SetupMessages[msgDirExistsTitle],
  2157. mbConfirmation, MB_YESNO, True, IDYES) <> IDYES then Exit;
  2158. { Check if directory *doesn't* already exist }
  2159. if (shEnableDirDoesntExistWarning in SetupHeader.Options) and
  2160. not DirExists(T) then
  2161. { If not, ask if user wants to install there anyway }
  2162. if LoggedMsgBox(FmtSetupMessage1(msgDirDoesntExist, T), SetupMessages[msgDirDoesntExistTitle],
  2163. mbConfirmation, MB_YESNO, True, IDYES) <> IDYES then Exit;
  2164. end;
  2165. Result := True;
  2166. WizardDirValue := T;
  2167. end;
  2168. function CheckSelectComponentsPage: Boolean;
  2169. var
  2170. ComponentEntry: PSetupComponentEntry;
  2171. FreeSpace, TotalSpace: Integer64;
  2172. S: String;
  2173. I: Integer;
  2174. begin
  2175. Result := False;
  2176. if InstallMode = imNormal then begin
  2177. if GetSpaceOnNearestMountPoint(False, DirEdit.Text, FreeSpace, TotalSpace) then begin
  2178. if Compare64(FreeSpace, CurrentComponentsSpace) < 0 then
  2179. if LoggedMsgBox(FmtSetupMessage(msgDiskSpaceWarning,
  2180. [IntToKBStr(CurrentComponentsSpace), IntToKBStr(FreeSpace)]),
  2181. SetupMessages[msgDiskSpaceWarningTitle],
  2182. mbConfirmation, MB_YESNO or MB_DEFBUTTON2, True, IDYES) <> IDYES then
  2183. Exit;
  2184. end;
  2185. //now see if there are unchecked components that are already installed
  2186. if PrevSelectedComponents.Count > 0 then begin
  2187. S := '';
  2188. for I := 0 to ComponentsList.Items.Count-1 do begin
  2189. if not ComponentsList.Checked[I] then begin
  2190. ComponentEntry := PSetupComponentEntry(ComponentsList.ItemObject[I]);
  2191. if not (coDisableNoUninstallWarning in ComponentEntry.Options) then begin
  2192. if ListContains(PrevSelectedComponents, ComponentEntry.Name) then begin
  2193. if S <> '' then
  2194. S := S + #13;
  2195. S := S + ExpandConst(ComponentEntry.Description);
  2196. end;
  2197. end;
  2198. end;
  2199. end;
  2200. if (S <> '') and (LoggedMsgBox(FmtSetupMessage1(msgNoUninstallWarning, S),
  2201. SetupMessages[msgNoUninstallWarningTitle], mbConfirmation, MB_YESNO, True, IDYES) <> IDYES) then
  2202. Exit;
  2203. end;
  2204. end;
  2205. Result := True;
  2206. end;
  2207. function CheckSelectProgramGroupPage: Boolean;
  2208. begin
  2209. Result := ValidateGroupEdit;
  2210. if Result then
  2211. WizardGroupValue := GroupEdit.Text;
  2212. end;
  2213. var
  2214. PageIndex: Integer;
  2215. Continue: Boolean;
  2216. NewPageID: Integer;
  2217. WizardComponents, WizardTasks: TStringList;
  2218. label Again;
  2219. begin
  2220. if CurPageID = wpInstalling then
  2221. Exit;
  2222. case CurPageID of
  2223. wpLicense: if not LicenseAcceptedRadio.Checked then Exit; { paranoia }
  2224. wpPassword: if not CheckPassword then Exit;
  2225. wpUserInfo: if not CheckUserInfoPage then Exit;
  2226. wpSelectDir: if not CheckSelectDirPage then Exit;
  2227. wpSelectComponents: if not CheckSelectComponentsPage then Exit;
  2228. wpSelectProgramGroup: if not CheckSelectProgramGroupPage then Exit;
  2229. wpReady: if (InstallMode = imNormal) and not Visible then Exit;
  2230. end;
  2231. Continue := True;
  2232. PageFromID(CurPageID).NextButtonClick(Continue);
  2233. if not Continue then
  2234. Exit;
  2235. if CodeRunner <> nil then
  2236. if CodeRunner.RunBooleanFunctions( 'NextButtonClick', [CurPageID], bcFalse, False, True) = False then
  2237. Exit;
  2238. { Go to the next page, or close wizard if it was on the last page }
  2239. Again:
  2240. NewPageID := CurPageID;
  2241. PageIndex := PageIndexFromID(NewPageID);
  2242. repeat
  2243. case NewPageID of
  2244. wpUserInfo: begin
  2245. { Ensure these variables are still set when a user's ShouldSkipPage
  2246. function returns True for the wpUserInfo page }
  2247. WizardUserInfoName := UserInfoNameEdit.Text;
  2248. WizardUserInfoOrg := UserInfoOrgEdit.Text;
  2249. WizardUserInfoSerial := UserInfoSerialEdit.Text;
  2250. end;
  2251. wpSelectDir: WizardDirValue := RemoveBackslashUnlessRoot(DirEdit.Text);
  2252. wpSelectProgramGroup: WizardGroupValue := RemoveBackslashUnlessRoot(GroupEdit.Text);
  2253. wpPreparing, wpFinished: begin
  2254. { Note: wpPreparing only 'gets' here if there was no PrepareToInstall failure or if
  2255. PrepareToInstallNeedsRestart is true, else the Cancel button is used instead of the Next button }
  2256. if (NewPageID <> wpPreparing) or (PrepareToInstallFailureMessage <> '') then begin
  2257. DoneWithWizard := True;
  2258. MainForm.Finish(NewPageID = wpPreparing);
  2259. Exit;
  2260. end;
  2261. end;
  2262. end;
  2263. Inc(PageIndex);
  2264. NewPageID := TWizardPage(FPageList[PageIndex]).ID;
  2265. UpdatePage(NewPageID);
  2266. case NewPageID of
  2267. wpPreparing: begin
  2268. WizardComponents := nil;
  2269. WizardTasks := nil;
  2270. try
  2271. WizardComponents := TStringList.Create;
  2272. WizardForm.GetComponents(WizardComponents, nil);
  2273. WizardTasks := TStringList.Create;
  2274. WizardForm.GetTasks(WizardTasks, nil);
  2275. PrepareToInstallFailureMessage := PrepareToInstall(WizardComponents, WizardTasks);
  2276. if PrepareToInstallFailureMessage <> '' then begin
  2277. LogFmt('PrepareToInstall failed: %s', [PrepareToInstallFailureMessage]);
  2278. LogFmt('Need to restart Windows? %s', [SYesNo[PrepareToInstallNeedsRestart]]);
  2279. Break; { stop on the page }
  2280. end else if RmSessionStarted then begin
  2281. SetCurPage(wpPreparing); { controls are already hidden by PrepareToInstall }
  2282. BackButton.Visible := False;
  2283. NextButton.Visible := False;
  2284. if InstallMode = imSilent then begin
  2285. SetActiveWindow(Application.Handle); { ensure taskbar button is selected }
  2286. WizardForm.Show;
  2287. end;
  2288. try
  2289. WizardForm.Update;
  2290. RmFoundApplications := QueryRestartManager(WizardComponents, WizardTasks) <> '';
  2291. if RmFoundApplications then
  2292. Break; { stop on the page }
  2293. finally
  2294. UpdateCurPageButtonState;
  2295. end;
  2296. end;
  2297. finally
  2298. WizardTasks.Free;
  2299. WizardComponents.Free;
  2300. end;
  2301. end;
  2302. wpInstalling: begin
  2303. SetCurPage(NewPageID);
  2304. { Start the actual installation process }
  2305. if not MainForm.Install then begin
  2306. { The installation process failed }
  2307. DoneWithWizard := True;
  2308. Exit;
  2309. end;
  2310. goto Again;
  2311. end;
  2312. end;
  2313. until not ShouldSkipPage(NewPageID);
  2314. SetCurPage(NewPageID);
  2315. end;
  2316. procedure TWizardForm.BackButtonClick(Sender: TObject);
  2317. var
  2318. Continue: Boolean;
  2319. PrevPageID: Integer;
  2320. begin
  2321. if CurPageID = wpInstalling then
  2322. Exit;
  2323. Continue := True;
  2324. PageFromID(CurPageID).BackButtonClick(Continue);
  2325. if not Continue then
  2326. Exit;
  2327. if CodeRunner <> nil then
  2328. if CodeRunner.RunBooleanFunctions('BackButtonClick', [CurPageID], bcFalse, False, True) = False then
  2329. Exit;
  2330. PrevPageID := GetPreviousPageID;
  2331. if PrevPageID <> -1 then
  2332. SetCurPage(PrevPageID);
  2333. end;
  2334. procedure TWizardForm.CancelButtonClick(Sender: TObject);
  2335. begin
  2336. { Clicking Cancel will do the same thing as the Close button }
  2337. Close;
  2338. end;
  2339. procedure TWizardForm.CallCancelButtonClick(var ACancel, AConfirm: Boolean);
  2340. begin
  2341. PageFromID(CurPageID).CancelButtonClick(ACancel, AConfirm);
  2342. if not ACancel then
  2343. Exit;
  2344. if CodeRunner <> nil then
  2345. CodeRunner.RunProcedures('CancelButtonClick', [CurPageID, @ACancel,
  2346. @AConfirm], False);
  2347. end;
  2348. procedure TWizardForm.FormClose(Sender: TObject; var Action: TCloseAction);
  2349. begin
  2350. { Redirect an attempt to close this form to MainForm }
  2351. MainForm.Close;
  2352. Action := caNone;
  2353. end;
  2354. procedure TWizardForm.TypesComboChange(Sender: TObject);
  2355. var
  2356. TypeEntry: PSetupTypeEntry;
  2357. begin
  2358. //select the components for this type. if the type is custom only select
  2359. //fixed components
  2360. TypeEntry := PSetupTypeEntry(TypesCombo.Items.Objects[TypesCombo.ItemIndex]);
  2361. SelectComponentsFromType(TypeEntry.Name, (toIsCustom in TypeEntry.Options));
  2362. //if customization is possible remember the type and components that are
  2363. //selected, so that we can reselect the setup type later if after customization
  2364. //the user didn't really change anything
  2365. //also hide the components list if necessary
  2366. if HasCustomType then begin
  2367. InitialSetupTypeIndex := TypesCombo.ItemIndex;
  2368. GetSelectedComponents(InitialSelectedComponents, False, False);
  2369. if not (shAlwaysShowComponentsList in SetupHeader.Options) then begin
  2370. ComponentsList.Visible := toIsCustom in TypeEntry.Options;
  2371. ComponentsDiskSpaceLabel.Visible := ComponentsList.Visible;
  2372. end;
  2373. end;
  2374. UpdateComponentSizes;
  2375. CalcCurrentComponentsSpace;
  2376. end;
  2377. procedure TWizardForm.ComponentsListClickCheck(Sender: TObject);
  2378. var
  2379. SelectedComponents: TStringList;
  2380. TypeEntry: PSetupTypeEntry;
  2381. Equals: Boolean;
  2382. I: Integer;
  2383. begin
  2384. //first see if this current selection equals the initial selection
  2385. //if so, reselect the initial setup type
  2386. SelectedComponents := TStringList.Create();
  2387. GetSelectedComponents(SelectedComponents, False, False);
  2388. Equals := SelectedComponents.Equals(InitialSelectedComponents);
  2389. SelectedComponents.Free();
  2390. if Equals then begin
  2391. //select the intial type
  2392. TypesCombo.ItemIndex := InitialSetupTypeIndex;
  2393. end else begin
  2394. //select a custom type
  2395. for I := 0 to Entries[seType].Count-1 do begin
  2396. TypeEntry := Entries[seType][I];
  2397. if (toIsCustom in TypeEntry.Options) then begin
  2398. TypesCombo.ItemIndex := TypesCombo.Items.IndexOfObject(TObject(TypeEntry));
  2399. SelectComponentsFromType(TypeEntry.Name, True);
  2400. Break;
  2401. end;
  2402. end
  2403. end;
  2404. UpdateComponentSizes;
  2405. CalcCurrentComponentsSpace;
  2406. end;
  2407. procedure TWizardForm.NoIconsCheckClick(Sender: TObject);
  2408. const
  2409. ColorChange: array[Boolean] of TColor = (clBtnFace, clWindow);
  2410. begin
  2411. GroupEdit.Enabled := not NoIconsCheck.Checked;
  2412. GroupEdit.Color := ColorChange[GroupEdit.Enabled];
  2413. GroupBrowseButton.Enabled := not NoIconsCheck.Checked;
  2414. end;
  2415. procedure TWizardForm.WMSysCommand(var Message: TWMSysCommand);
  2416. begin
  2417. if Message.CmdType and $FFF0 = SC_MINIMIZE then
  2418. { A minimize button is shown on the wizard form when (shWindowVisible in
  2419. SetupHeader.Options). When it is clicked we want to minimize the whole
  2420. application. }
  2421. Application.Minimize
  2422. else
  2423. if Message.CmdType = 9999 then
  2424. MainForm.ShowAboutBox
  2425. else
  2426. inherited;
  2427. end;
  2428. procedure TWizardForm.LicenseAcceptedRadioClick(Sender: TObject);
  2429. begin
  2430. if CurPageID = wpLicense then
  2431. NextButton.Enabled := True;
  2432. end;
  2433. procedure TWizardForm.LicenseNotAcceptedRadioClick(Sender: TObject);
  2434. begin
  2435. if CurPageID = wpLicense then
  2436. NextButton.Enabled := False;
  2437. end;
  2438. procedure TWizardForm.UserInfoEditChange(Sender: TObject);
  2439. begin
  2440. if CurPageID = wpUserInfo then begin
  2441. try
  2442. NextButton.Enabled := CheckSerialOk();
  2443. except
  2444. NextButton.Enabled := False;
  2445. raise;
  2446. end;
  2447. end;
  2448. end;
  2449. function TWizardForm.ValidateDirEdit: Boolean;
  2450. begin
  2451. Result := ValidateCustomDirEdit(DirEdit, shAllowUNCPath in SetupHeader.Options,
  2452. shAllowRootDirectory in SetupHeader.Options,
  2453. shAllowNetworkDrive in SetupHeader.Options);
  2454. end;
  2455. const
  2456. SHPPFW_NONE = $00000000;
  2457. var
  2458. SHPathPrepareForWriteFunc: function(hwnd: HWND; punkEnableModless: Pointer;
  2459. pszPath: PChar; dwFlags: DWORD): HRESULT; stdcall;
  2460. procedure ReconnectPath(const Path: String);
  2461. { Attempts to re-establish the connection to Path if it's on a network drive
  2462. since mapped network drives are initially disconnected in elevated processes. }
  2463. var
  2464. WindowList: Pointer;
  2465. begin
  2466. { If this fails, we shouldn't display any message boxes since the install
  2467. might be running silently with /SUPPRESSMSGBOXES and this is indeed so:
  2468. The SHPathPrepareForWrite documentation claims that "user interface
  2469. windows will not be created" when hwnd is NULL. }
  2470. if Assigned(SHPathPrepareForWriteFunc) then begin
  2471. { "Just in case" it tries to display UI anyway (it never did in tests),
  2472. disable our windows }
  2473. WindowList := DisableTaskWindows(0);
  2474. try
  2475. SHPathPrepareForWriteFunc(0, nil, PChar(Path), SHPPFW_NONE);
  2476. finally
  2477. EnableTaskWindows(WindowList);
  2478. end;
  2479. end;
  2480. end;
  2481. function ValidateCustomDirEdit(const AEdit: TEdit;
  2482. const AllowUNCPath, AllowRootDirectory, AllowNetworkDrive: Boolean): Boolean;
  2483. { Checks if AEdit.Text contains a valid-looking pathname, and returns True
  2484. if so. May alter AEdit.Text to remove redundant spaces and backslashes. }
  2485. var
  2486. T: String;
  2487. IsUNCPath: Boolean;
  2488. I: Integer;
  2489. P: PChar;
  2490. RootPath: String;
  2491. begin
  2492. Result := False;
  2493. T := AEdit.Text;
  2494. TidyUpDirName(T);
  2495. AEdit.Text := T;
  2496. { Check if the path is too long.
  2497. Note: There's no sense in allowing paths to be as long as MAX_PATH (260)
  2498. since there wouldn't be any room left to append a filename. 240 should be
  2499. a reasonable limit. }
  2500. if Length(T) > 240 then begin
  2501. LoggedMsgBox(SetupMessages[msgDirNameTooLong], '', mbError, MB_OK, True, IDOK);
  2502. Exit;
  2503. end;
  2504. { Check for UNC pathname }
  2505. IsUNCPath := (Length(T) >= 2) and (T[1] = '\') and (T[2] = '\');
  2506. if IsUNCPath and not AllowUNCPath then begin
  2507. LoggedMsgBox(SetupMessages[msgCannotInstallToUNCPath], '', mbError, MB_OK, True, IDOK);
  2508. Exit;
  2509. end;
  2510. if not IsUNCPath then begin
  2511. { Check if is at least 4 chars long and it has a drive letter, colon,
  2512. and backslash }
  2513. if not AllowRootDirectory then
  2514. I := 4
  2515. else
  2516. I := 3;
  2517. if (Length(T) < I) or not CharInSet(UpCase(T[1]), ['A'..'Z']) or
  2518. (T[2] <> ':') or (T[3] <> '\') then begin
  2519. LoggedMsgBox(SetupMessages[msgInvalidPath], '', mbError, MB_OK, True, IDOK);
  2520. Exit;
  2521. end;
  2522. end
  2523. else begin
  2524. { Check if there's at least one backslash at least one character past the
  2525. initial '\\' }
  2526. P := @PChar(Pointer(T))[2]; { the casts avoid a UniqueString call... }
  2527. if PathStrScan(P, '\') <= P then begin
  2528. LoggedMsgBox(SetupMessages[msgInvalidPath], '', mbError, MB_OK, True, IDOK);
  2529. Exit;
  2530. end;
  2531. end;
  2532. { Verify that no path components contain control characters, end in spaces,
  2533. or consist only of dots }
  2534. if ContainsControlCharacters(T) or
  2535. PathComponentsContainTrailingSpaces(T) or
  2536. PathComponentsContainInvalidDots(T) then begin
  2537. LoggedMsgBox(SetupMessages[msgInvalidDirName], '', mbError, MB_OK, True, IDOK);
  2538. Exit;
  2539. end;
  2540. { Check for invalid characters after 'x:' or '\\' }
  2541. if PathLastDelimiter(BadDirChars, Copy(T, 3, Maxint)) <> 0 then begin
  2542. LoggedMsgBox(FmtSetupMessage1(msgBadDirName32, SpaceString(BadDirChars)), '',
  2543. mbError, MB_OK, True, IDOK);
  2544. Exit;
  2545. end;
  2546. { Check if it's a valid drive, reconnecting it first if necessary }
  2547. RootPath := RemoveBackslashUnlessRoot(AddBackslash(PathExtractDrive(T)));
  2548. ReconnectPath(RootPath);
  2549. if not DirExists(RootPath) then begin
  2550. LoggedMsgBox(SetupMessages[msgInvalidDrive], '', mbError, MB_OK, True, IDOK);
  2551. Exit;
  2552. end;
  2553. { After reconnecting, check if it's a disallowed network drive }
  2554. if not IsUNCPath and not AllowNetworkDrive and
  2555. (GetDriveType(PChar(RootPath)) = DRIVE_REMOTE) then begin
  2556. LoggedMsgBox(SetupMessages[msgCannotInstallToNetworkDrive], '', mbError, MB_OK, True, IDOK);
  2557. Exit;
  2558. end;
  2559. Result := True;
  2560. end;
  2561. function TWizardForm.ValidateGroupEdit: Boolean;
  2562. var
  2563. T: String;
  2564. begin
  2565. Result := False;
  2566. if not NoIconsCheck.Checked then begin
  2567. T := GroupEdit.Text;
  2568. TidyUpGroupName(T);
  2569. GroupEdit.Text := T;
  2570. { Check if the path is too long }
  2571. if Length(T) > 120 then begin
  2572. LoggedMsgBox(SetupMessages[msgGroupNameTooLong], '', mbError, MB_OK, True, IDOK);
  2573. Exit;
  2574. end;
  2575. { Verify that no path components contain control characters or end in
  2576. spaces }
  2577. if ContainsControlCharacters(T) or
  2578. PathComponentsContainTrailingSpaces(T) then begin
  2579. LoggedMsgBox(SetupMessages[msgInvalidGroupName], '', mbError, MB_OK, True, IDOK);
  2580. Exit;
  2581. end;
  2582. if T = '' then begin
  2583. LoggedMsgBox(SetupMessages[msgMustEnterGroupName], '', mbError, MB_OK, True, IDOK);
  2584. Exit;
  2585. end;
  2586. { Check for invalid characters }
  2587. if PathLastDelimiter(BadDirChars, T) <> 0 then begin
  2588. LoggedMsgBox(FmtSetupMessage1(msgBadGroupName, SpaceString(BadDirChars)),
  2589. '', mbError, MB_OK, True, IDOK);
  2590. Exit;
  2591. end;
  2592. end;
  2593. Result := True;
  2594. end;
  2595. procedure TWizardForm.DirBrowseButtonClick(Sender: TObject);
  2596. var
  2597. NewFolderName, Path: String;
  2598. begin
  2599. NewFolderName := Trim(PathExtractName(RemoveBackslashUnlessRoot(ExpandedDefaultDirName)));
  2600. { If ExpandedDefaultDirName is a root directory, there will be no name }
  2601. if NewFolderName = '' then
  2602. NewFolderName := Trim(SetupMessages[msgNewFolderName]);
  2603. Path := DirEdit.Text;
  2604. if ShowSelectFolderDialog(False, shAppendDefaultDirName in SetupHeader.Options,
  2605. Path, NewFolderName) then
  2606. DirEdit.Text := Path;
  2607. end;
  2608. procedure TWizardForm.GroupBrowseButtonClick(Sender: TObject);
  2609. var
  2610. NewFolderName, Path: String;
  2611. begin
  2612. NewFolderName := Trim(PathExtractName(ExpandedDefaultGroupName));
  2613. if NewFolderName = '' then
  2614. NewFolderName := Trim(SetupMessages[msgNewFolderName]);
  2615. Path := GroupEdit.Text;
  2616. if ShowSelectFolderDialog(True, shAppendDefaultGroupName in SetupHeader.Options,
  2617. Path, NewFolderName) then
  2618. GroupEdit.Text := Path;
  2619. end;
  2620. { also used by ScriptDlg! }
  2621. procedure TWizardForm.DirTreeRename(Sender: TCustomFolderTreeView;
  2622. var NewName: string; var Accept: Boolean);
  2623. const
  2624. NewFolderBadDirChars = '\' + BadDirChars;
  2625. begin
  2626. NewName := Trim(NewName);
  2627. if (NewName = '') or PathComponentsContainInvalidDots(NewName) then begin
  2628. Accept := False;
  2629. LoggedMsgBox(SetupMessages[msgInvalidDirName], '', mbError, MB_OK, True, IDOK);
  2630. Exit;
  2631. end;
  2632. if PathLastDelimiter(NewFolderBadDirChars, NewName) <> 0 then begin
  2633. Accept := False;
  2634. LoggedMsgBox(FmtSetupMessage1(msgBadDirName32, SpaceString(NewFolderBadDirChars)),
  2635. '', mbError, MB_OK, True, IDOK);
  2636. Exit;
  2637. end;
  2638. end;
  2639. procedure TWizardForm.GroupTreeRename(Sender: TCustomFolderTreeView;
  2640. var NewName: string; var Accept: Boolean);
  2641. const
  2642. NewFolderBadDirChars = '\' + BadDirChars;
  2643. begin
  2644. NewName := Trim(NewName);
  2645. if (NewName = '') or PathComponentsContainInvalidDots(NewName) then begin
  2646. Accept := False;
  2647. LoggedMsgBox(SetupMessages[msgInvalidGroupName], '', mbError, MB_OK, True, IDOK);
  2648. Exit;
  2649. end;
  2650. if PathLastDelimiter(NewFolderBadDirChars, NewName) <> 0 then begin
  2651. Accept := False;
  2652. LoggedMsgBox(FmtSetupMessage1(msgBadGroupName, SpaceString(NewFolderBadDirChars)),
  2653. '', mbError, MB_OK, True, IDOK);
  2654. Exit;
  2655. end;
  2656. end;
  2657. procedure TWizardForm.ClickToStartPage;
  2658. { Simulates clicks on the Next button until Setup is ready to start.
  2659. This is called on non-silent installs. }
  2660. begin
  2661. while ShouldSkipPage(CurPageID) and NextButton.CanFocus do
  2662. NextButton.Click;
  2663. end;
  2664. procedure TWizardForm.ClickThroughPages;
  2665. { Simulates clicks on the Next button until Setup is ready to terminate.
  2666. This is called on silent installs. }
  2667. var
  2668. BeforeID: Integer;
  2669. begin
  2670. while True do begin
  2671. if (CurPageID = wpPreparing) and (PrepareToInstallFailureMessage <> '') and not (PrepareToInstallNeedsRestart and not InitNoRestart) then begin
  2672. { Special handling needed for wpPreparing since it displays its error
  2673. message inline on the wizard. Since the wizard isn't currently visible,
  2674. we have to display the message in a message box if it won't be displayed
  2675. by a reboot confirmation message box later on. }
  2676. LoggedMsgBox(PrepareToInstallFailureMessage, '',
  2677. mbCriticalError, MB_OK, True, IDOK);
  2678. if PrepareToInstallNeedsRestart then
  2679. SetupExitCode := ecPrepareToInstallFailedRestartNeeded
  2680. else
  2681. SetupExitCode := ecPrepareToInstallFailed;
  2682. Abort;
  2683. { Note: no special handling if it stops on wpPreparing because of in-use
  2684. files ((CurPageID = wpPreparing) and (PrepareToInstallFailureMessage = '')),
  2685. instead it will always choose to close applications when running silently
  2686. unless /NOCLOSEAPPLICATIONS was used. }
  2687. end;
  2688. BeforeID := CurPageID;
  2689. { Simulate a click on NextButton if it's enabled & visible }
  2690. try
  2691. if NextButton.CanFocus then
  2692. NextButton.Click;
  2693. except
  2694. { Mustn't propagate post-install exceptions }
  2695. if MainForm.CurStep <= ssInstall then
  2696. raise
  2697. else
  2698. Application.HandleException(Self);
  2699. end;
  2700. if DoneWithWizard then
  2701. Break;
  2702. { If the page didn't change, there must've been an error }
  2703. if CurPageID = BeforeID then begin
  2704. if MainForm.CurStep <= ssInstall then begin
  2705. Log('Failed to proceed to next wizard page; aborting.');
  2706. Abort;
  2707. end
  2708. else begin
  2709. { After installation, we can't abort since e.g. a restart might be
  2710. needed. Instead, to avoid getting stuck in a loop, show the wizard
  2711. (even though this is a silent install) and let the user deal with the
  2712. problem on their own.
  2713. The taskbar button will be hidden at this point on very silent
  2714. installs (see SetupInstallMode); re-show it. }
  2715. Log('Failed to proceed to next wizard page; showing wizard.');
  2716. SetTaskbarButtonVisibility(True);
  2717. Application.Restore;
  2718. SetActiveWindow(Application.Handle); { ensure taskbar button is selected }
  2719. WizardForm.Show;
  2720. Break;
  2721. end;
  2722. end;
  2723. end;
  2724. end;
  2725. initialization
  2726. SHPathPrepareForWriteFunc := GetProcAddress(SafeLoadLibrary(AddBackslash(GetSystemDir) + shell32,
  2727. SEM_NOOPENFILEERRORBOX), 'SHPathPrepareForWriteW');
  2728. end.