ScriptFunc_R.pas 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065
  1. unit ScriptFunc_R;
  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. Script support functions (run time)
  8. }
  9. interface
  10. {$I VERSION.INC}
  11. uses
  12. uPSRuntime;
  13. procedure ScriptFuncLibraryRegister_R(ScriptInterpreter: TPSExec);
  14. implementation
  15. uses
  16. Windows, ScriptFunc,
  17. Forms, uPSUtils, SysUtils, Classes, Graphics, Controls, TypInfo, ActiveX,
  18. Struct, ScriptDlg, Main, PathFunc, CmnFunc, CmnFunc2, FileClass, RedirFunc,
  19. Install, InstFunc, InstFnc2, Msgs, MsgIDs, NewDisk, BrowseFunc, Wizard, VerInfo,
  20. SetupTypes, Int64Em, MD5, SHA1, Logging, SetupForm, RegDLL, Helper,
  21. SpawnClient, UninstProgressForm, ASMInline, DotNet, Msi, BitmapImage;
  22. var
  23. ScaleBaseUnitsInitialized: Boolean;
  24. ScaleBaseUnitX, ScaleBaseUnitY: Integer;
  25. procedure NoSetupFuncError(const C: AnsiString); overload;
  26. begin
  27. InternalError(Format('Cannot call "%s" function during Setup', [C]));
  28. end;
  29. procedure NoUninstallFuncError(const C: AnsiString); overload;
  30. begin
  31. InternalError(Format('Cannot call "%s" function during Uninstall', [C]));
  32. end;
  33. procedure NoSetupFuncError(const C: UnicodeString); overload;
  34. begin
  35. InternalError(Format('Cannot call "%s" function during Setup', [C]));
  36. end;
  37. procedure NoUninstallFuncError(const C: UnicodeString); overload;
  38. begin
  39. InternalError(Format('Cannot call "%s" function during Uninstall', [C]));
  40. end;
  41. function StackGetAnsiString(Stack: TPSStack; ItemNo: LongInt): AnsiString;
  42. begin
  43. Result := Stack.GetAnsiString(ItemNo);
  44. end;
  45. procedure StackSetAnsiString(Stack: TPSStack; ItemNo: LongInt; const Data: AnsiString);
  46. begin
  47. Stack.SetAnsiString(ItemNo, Data);
  48. end;
  49. function GetMainForm: TMainForm;
  50. begin
  51. Result := MainForm;
  52. if Result = nil then
  53. InternalError('An attempt was made to access MainForm before it has been created');
  54. end;
  55. function GetWizardForm: TWizardForm;
  56. begin
  57. Result := WizardForm;
  58. if Result = nil then
  59. InternalError('An attempt was made to access WizardForm before it has been created');
  60. end;
  61. function GetUninstallProgressForm: TUninstallProgressForm;
  62. begin
  63. Result := UninstallProgressForm;
  64. if Result = nil then
  65. InternalError('An attempt was made to access UninstallProgressForm before it has been created');
  66. end;
  67. function GetMsgBoxCaption: String;
  68. var
  69. ID: TSetupMessageID;
  70. begin
  71. if IsUninstaller then
  72. ID := msgUninstallAppTitle
  73. else
  74. ID := msgSetupAppTitle;
  75. Result := SetupMessages[ID];
  76. end;
  77. procedure InitializeScaleBaseUnits;
  78. var
  79. Font: TFont;
  80. begin
  81. if ScaleBaseUnitsInitialized then
  82. Exit;
  83. Font := TFont.Create;
  84. try
  85. SetFontNameSize(Font, LangOptions.DialogFontName, LangOptions.DialogFontSize,
  86. '', 8);
  87. CalculateBaseUnitsFromFont(Font, ScaleBaseUnitX, ScaleBaseUnitY);
  88. finally
  89. Font.Free;
  90. end;
  91. ScaleBaseUnitsInitialized := True;
  92. end;
  93. {---}
  94. { ScriptDlg }
  95. function ScriptDlgProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  96. var
  97. PStart: Cardinal;
  98. NewPage: TWizardPage;
  99. NewInputQueryPage: TInputQueryWizardPage;
  100. NewInputOptionPage: TInputOptionWizardPage;
  101. NewInputDirPage: TInputDirWizardPage;
  102. NewInputFilePage: TInputFileWizardPage;
  103. NewOutputMsgPage: TOutputMsgWizardPage;
  104. NewOutputMsgMemoPage: TOutputMsgMemoWizardPage;
  105. NewOutputProgressPage: TOutputProgressWizardPage;
  106. NewOutputMarqueeProgressPage: TOutputMarqueeProgressWizardPage;
  107. {$IFNDEF PS_NOINT64}
  108. NewDownloadPage: TDownloadWizardPage;
  109. P: PPSVariantProcPtr;
  110. OnDownloadProgress: TOnDownloadProgress;
  111. {$ENDIF}
  112. NewSetupForm: TSetupForm;
  113. begin
  114. PStart := Stack.Count-1;
  115. Result := True;
  116. if Proc.Name = 'PAGEFROMID' then begin
  117. if IsUninstaller then
  118. NoUninstallFuncError(Proc.Name);
  119. Stack.SetClass(PStart, GetWizardForm.PageFromID(Stack.GetInt(PStart-1)));
  120. end else if Proc.Name = 'PAGEINDEXFROMID' then begin
  121. if IsUninstaller then
  122. NoUninstallFuncError(Proc.Name);
  123. Stack.SetInt(PStart, GetWizardForm.PageIndexFromID(Stack.GetInt(PStart-1)));
  124. end else if Proc.Name = 'CREATECUSTOMPAGE' then begin
  125. if IsUninstaller then
  126. NoUninstallFuncError(Proc.Name);
  127. NewPage := TWizardPage.Create(GetWizardForm);
  128. try
  129. NewPage.Caption := Stack.GetString(PStart-2);
  130. NewPage.Description := Stack.GetString(PStart-3);
  131. GetWizardForm.AddPage(NewPage, Stack.GetInt(PStart-1));
  132. except
  133. NewPage.Free;
  134. raise;
  135. end;
  136. Stack.SetClass(PStart, NewPage);
  137. end else if Proc.Name = 'CREATEINPUTQUERYPAGE' then begin
  138. if IsUninstaller then
  139. NoUninstallFuncError(Proc.Name);
  140. NewInputQueryPage := TInputQueryWizardPage.Create(GetWizardForm);
  141. try
  142. NewInputQueryPage.Caption := Stack.GetString(PStart-2);
  143. NewInputQueryPage.Description := Stack.GetString(PStart-3);
  144. GetWizardForm.AddPage(NewInputQueryPage, Stack.GetInt(PStart-1));
  145. NewInputQueryPage.Initialize(Stack.GetString(PStart-4));
  146. except
  147. NewInputQueryPage.Free;
  148. raise;
  149. end;
  150. Stack.SetClass(PStart, NewInputQueryPage);
  151. end else if Proc.Name = 'CREATEINPUTOPTIONPAGE' then begin
  152. if IsUninstaller then
  153. NoUninstallFuncError(Proc.Name);
  154. NewInputOptionPage := TInputOptionWizardPage.Create(GetWizardForm);
  155. try
  156. NewInputOptionPage.Caption := Stack.GetString(PStart-2);
  157. NewInputOptionPage.Description := Stack.GetString(PStart-3);
  158. GetWizardForm.AddPage(NewInputOptionPage, Stack.GetInt(PStart-1));
  159. NewInputOptionPage.Initialize(Stack.GetString(PStart-4),
  160. Stack.GetBool(PStart-5), Stack.GetBool(PStart-6));
  161. except
  162. NewInputOptionPage.Free;
  163. raise;
  164. end;
  165. Stack.SetClass(PStart, NewInputOptionPage);
  166. end else if Proc.Name = 'CREATEINPUTDIRPAGE' then begin
  167. if IsUninstaller then
  168. NoUninstallFuncError(Proc.Name);
  169. NewInputDirPage := TInputDirWizardPage.Create(GetWizardForm);
  170. try
  171. NewInputDirPage.Caption := Stack.GetString(PStart-2);
  172. NewInputDirPage.Description := Stack.GetString(PStart-3);
  173. GetWizardForm.AddPage(NewInputDirPage, Stack.GetInt(PStart-1));
  174. NewInputDirPage.Initialize(Stack.GetString(PStart-4), Stack.GetBool(PStart-5),
  175. Stack.GetString(PStart-6));
  176. except
  177. NewInputDirPage.Free;
  178. raise;
  179. end;
  180. Stack.SetClass(PStart, NewInputDirPage);
  181. end else if Proc.Name = 'CREATEINPUTFILEPAGE' then begin
  182. if IsUninstaller then
  183. NoUninstallFuncError(Proc.Name);
  184. NewInputFilePage := TInputFileWizardPage.Create(GetWizardForm);
  185. try
  186. NewInputFilePage.Caption := Stack.GetString(PStart-2);
  187. NewInputFilePage.Description := Stack.GetString(PStart-3);
  188. GetWizardForm.AddPage(NewInputFilePage, Stack.GetInt(PStart-1));
  189. NewInputFilePage.Initialize(Stack.GetString(PStart-4));
  190. except
  191. NewInputFilePage.Free;
  192. raise;
  193. end;
  194. Stack.SetClass(PStart, NewInputFilePage);
  195. end else if Proc.Name = 'CREATEOUTPUTMSGPAGE' then begin
  196. if IsUninstaller then
  197. NoUninstallFuncError(Proc.Name);
  198. NewOutputMsgPage := TOutputMsgWizardPage.Create(GetWizardForm);
  199. try
  200. NewOutputMsgPage.Caption := Stack.GetString(PStart-2);
  201. NewOutputMsgPage.Description := Stack.GetString(PStart-3);
  202. GetWizardForm.AddPage(NewOutputMsgPage, Stack.GetInt(PStart-1));
  203. NewOutputMsgPage.Initialize(Stack.GetString(PStart-4));
  204. except
  205. NewOutputMsgPage.Free;
  206. raise;
  207. end;
  208. Stack.SetClass(PStart, NewOutputMsgPage);
  209. end else if Proc.Name = 'CREATEOUTPUTMSGMEMOPAGE' then begin
  210. if IsUninstaller then
  211. NoUninstallFuncError(Proc.Name);
  212. NewOutputMsgMemoPage := TOutputMsgMemoWizardPage.Create(GetWizardForm);
  213. try
  214. NewOutputMsgMemoPage.Caption := Stack.GetString(PStart-2);
  215. NewOutputMsgMemoPage.Description := Stack.GetString(PStart-3);
  216. GetWizardForm.AddPage(NewOutputMsgMemoPage, Stack.GetInt(PStart-1));
  217. NewOutputMsgMemoPage.Initialize(Stack.GetString(PStart-4),
  218. StackGetAnsiString(Stack, PStart-5));
  219. except
  220. NewOutputMsgMemoPage.Free;
  221. raise;
  222. end;
  223. Stack.SetClass(PStart, NewOutputMsgMemoPage);
  224. end else if Proc.Name = 'CREATEOUTPUTPROGRESSPAGE' then begin
  225. if IsUninstaller then
  226. NoUninstallFuncError(Proc.Name);
  227. NewOutputProgressPage := TOutputProgressWizardPage.Create(GetWizardForm);
  228. try
  229. NewOutputProgressPage.Caption := Stack.GetString(PStart-1);
  230. NewOutputProgressPage.Description := Stack.GetString(PStart-2);
  231. GetWizardForm.AddPage(NewOutputProgressPage, -1);
  232. NewOutputProgressPage.Initialize;
  233. except
  234. NewOutputProgressPage.Free;
  235. raise;
  236. end;
  237. Stack.SetClass(PStart, NewOutputProgressPage);
  238. end else if Proc.Name = 'CREATEOUTPUTMARQUEEPROGRESSPAGE' then begin
  239. if IsUninstaller then
  240. NoUninstallFuncError(Proc.Name);
  241. NewOutputMarqueeProgressPage := TOutputMarqueeProgressWizardPage.Create(GetWizardForm);
  242. try
  243. NewOutputMarqueeProgressPage.Caption := Stack.GetString(PStart-1);
  244. NewOutputMarqueeProgressPage.Description := Stack.GetString(PStart-2);
  245. GetWizardForm.AddPage(NewOutputMarqueeProgressPage, -1);
  246. NewOutputMarqueeProgressPage.Initialize;
  247. except
  248. NewOutputMarqueeProgressPage.Free;
  249. raise;
  250. end;
  251. Stack.SetClass(PStart, NewOutputMarqueeProgressPage);
  252. {$IFNDEF PS_NOINT64}
  253. end else if Proc.Name = 'CREATEDOWNLOADPAGE' then begin
  254. if IsUninstaller then
  255. NoUninstallFuncError(Proc.Name);
  256. P := Stack.Items[PStart-3];
  257. { ProcNo 0 means nil was passed by the script }
  258. if P.ProcNo <> 0 then
  259. OnDownloadProgress := TOnDownloadProgress(Caller.GetProcAsMethod(P.ProcNo))
  260. else
  261. OnDownloadProgress := nil;
  262. NewDownloadPage := TDownloadWizardPage.Create(GetWizardForm);
  263. try
  264. NewDownloadPage.Caption := Stack.GetString(PStart-1);
  265. NewDownloadPage.Description := Stack.GetString(PStart-2);
  266. GetWizardForm.AddPage(NewDownloadPage, -1);
  267. NewDownloadPage.Initialize;
  268. NewDownloadPage.OnDownloadProgress := OnDownloadProgress;
  269. except
  270. NewDownloadPage.Free;
  271. raise;
  272. end;
  273. Stack.SetClass(PStart, NewDownloadPage);
  274. {$ENDIF}
  275. end else if Proc.Name = 'SCALEX' then begin
  276. InitializeScaleBaseUnits;
  277. Stack.SetInt(PStart, MulDiv(Stack.GetInt(PStart-1), ScaleBaseUnitX, OrigBaseUnitX));
  278. end else if Proc.Name = 'SCALEY' then begin
  279. InitializeScaleBaseUnits;
  280. Stack.SetInt(PStart, MulDiv(Stack.GetInt(PStart-1), ScaleBaseUnitY, OrigBaseUnitY));
  281. end else if Proc.Name = 'CREATECUSTOMFORM' then begin
  282. NewSetupForm := TSetupForm.CreateNew(nil);
  283. try
  284. NewSetupForm.AutoScroll := False;
  285. NewSetupForm.BorderStyle := bsDialog;
  286. NewSetupForm.InitializeFont;
  287. except
  288. NewSetupForm.Free;
  289. raise;
  290. end;
  291. Stack.SetClass(PStart, NewSetupForm);
  292. end else
  293. Result := False;
  294. end;
  295. { NewDisk }
  296. function NewDiskProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  297. var
  298. PStart: Cardinal;
  299. S: String;
  300. begin
  301. PStart := Stack.Count-1;
  302. Result := True;
  303. if Proc.Name = 'SELECTDISK' then begin
  304. S := Stack.GetString(PStart-3);
  305. Stack.SetBool(PStart, SelectDisk(Stack.GetInt(PStart-1), Stack.GetString(PStart-2), S));
  306. Stack.SetString(PStart-3, S);
  307. end else
  308. Result := False;
  309. end;
  310. { BrowseFunc }
  311. function BrowseFuncProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  312. var
  313. PStart: Cardinal;
  314. S: String;
  315. ParentWnd: HWND;
  316. begin
  317. PStart := Stack.Count-1;
  318. Result := True;
  319. if Proc.Name = 'BROWSEFORFOLDER' then begin
  320. if Assigned(WizardForm) then
  321. ParentWnd := WizardForm.Handle
  322. else
  323. ParentWnd := 0;
  324. S := Stack.GetString(PStart-2);
  325. Stack.SetBool(PStart, BrowseForFolder(Stack.GetString(PStart-1), S, ParentWnd, Stack.GetBool(PStart-3)));
  326. Stack.SetString(PStart-2, S);
  327. end else if Proc.Name = 'GETOPENFILENAME' then begin
  328. if Assigned(WizardForm) then
  329. ParentWnd := WizardForm.Handle
  330. else
  331. ParentWnd := 0;
  332. S := Stack.GetString(PStart-2);
  333. Stack.SetBool(PStart, NewGetOpenFileName(Stack.GetString(PStart-1), S, Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), ParentWnd));
  334. Stack.SetString(PStart-2, S);
  335. end else if Proc.Name = 'GETOPENFILENAMEMULTI' then begin
  336. if Assigned(WizardForm) then
  337. ParentWnd := WizardForm.Handle
  338. else
  339. ParentWnd := 0;
  340. Stack.SetBool(PStart, NewGetOpenFileNameMulti(Stack.GetString(PStart-1), TStrings(Stack.GetClass(PStart-2)), Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), ParentWnd));
  341. end else if Proc.Name = 'GETSAVEFILENAME' then begin
  342. if Assigned(WizardForm) then
  343. ParentWnd := WizardForm.Handle
  344. else
  345. ParentWnd := 0;
  346. S := Stack.GetString(PStart-2);
  347. Stack.SetBool(PStart, NewGetSaveFileName(Stack.GetString(PStart-1), S, Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), ParentWnd));
  348. Stack.SetString(PStart-2, S);
  349. end else
  350. Result := False;
  351. end;
  352. { CmnFunc }
  353. function CmnFuncProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  354. var
  355. PStart: Cardinal;
  356. begin
  357. PStart := Stack.Count-1;
  358. Result := True;
  359. if Proc.Name = 'MINIMIZEPATHNAME' then begin
  360. Stack.SetString(PStart, MinimizePathName(Stack.GetString(PStart-1), TFont(Stack.GetClass(PStart-2)), Stack.GetInt(PStart-3)));
  361. end else
  362. Result := False;
  363. end;
  364. { CmnFunc2 }
  365. function CmnFunc2Proc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  366. procedure CrackCodeRootKey(CodeRootKey: HKEY; var RegView: TRegView;
  367. var RootKey: HKEY);
  368. begin
  369. if (CodeRootKey and not CodeRootKeyValidFlags) = HKEY_AUTO then begin
  370. { Change HKA to HKLM or HKCU, keeping our special flag bits. }
  371. CodeRootKey := (CodeRootKey and CodeRootKeyValidFlags) or InstallModeRootKey;
  372. end else begin
  373. { Allow only predefined key handles (8xxxxxxx). Can't accept handles to
  374. open keys because they might have our special flag bits set.
  375. Also reject unknown flags which may have a meaning in the future. }
  376. if (CodeRootKey shr 31 <> 1) or
  377. ((CodeRootKey and CodeRootKeyFlagMask) and not CodeRootKeyValidFlags <> 0) then
  378. InternalError('Invalid RootKey value');
  379. end;
  380. if CodeRootKey and CodeRootKeyFlag32Bit <> 0 then
  381. RegView := rv32Bit
  382. else if CodeRootKey and CodeRootKeyFlag64Bit <> 0 then begin
  383. if not IsWin64 then
  384. InternalError('Cannot access 64-bit registry keys on this version of Windows');
  385. RegView := rv64Bit;
  386. end
  387. else
  388. RegView := InstallDefaultRegView;
  389. RootKey := CodeRootKey and not CodeRootKeyFlagMask;
  390. end;
  391. function GetSubkeyOrValueNames(const RegView: TRegView; const RootKey: HKEY;
  392. const SubKeyName: String; Arr: PPSVariantIFC; const Subkey: Boolean): Boolean;
  393. const
  394. samDesired: array [Boolean] of REGSAM = (KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS);
  395. var
  396. K: HKEY;
  397. I: Cardinal;
  398. Buf, S: String;
  399. BufSize, R: DWORD;
  400. begin
  401. Result := False;
  402. SetString(Buf, nil, 512);
  403. if RegOpenKeyExView(RegView, RootKey, PChar(SubKeyName), 0, samDesired[Subkey], K) <> ERROR_SUCCESS then
  404. Exit;
  405. try
  406. PSDynArraySetLength(Pointer(Arr.Dta^), Arr.aType, 0);
  407. I := 0;
  408. while True do begin
  409. BufSize := Length(Buf);
  410. if Subkey then
  411. R := RegEnumKeyEx(K, I, @Buf[1], BufSize, nil, nil, nil, nil)
  412. else
  413. R := RegEnumValue(K, I, @Buf[1], BufSize, nil, nil, nil, nil);
  414. case R of
  415. ERROR_SUCCESS: ;
  416. ERROR_NO_MORE_ITEMS: Break;
  417. ERROR_MORE_DATA:
  418. begin
  419. { Double the size of the buffer and try again }
  420. if Length(Buf) >= 65536 then begin
  421. { Sanity check: If we tried a 64 KB buffer and it's still saying
  422. there's more data, something must be seriously wrong. Bail. }
  423. Exit;
  424. end;
  425. SetString(Buf, nil, Length(Buf) * 2);
  426. Continue;
  427. end;
  428. else
  429. Exit; { unknown failure... }
  430. end;
  431. PSDynArraySetLength(Pointer(Arr.Dta^), Arr.aType, I+1);
  432. SetString(S, PChar(@Buf[1]), BufSize);
  433. VNSetString(PSGetArrayField(Arr^, I), S);
  434. Inc(I);
  435. end;
  436. finally
  437. RegCloseKey(K);
  438. end;
  439. Result := True;
  440. end;
  441. var
  442. PStart: Cardinal;
  443. ExistingFilename: String;
  444. RegView: TRegView;
  445. K, RootKey: HKEY;
  446. S, N, V: String;
  447. DataS: AnsiString;
  448. Typ, ExistingTyp, Data, Size: DWORD;
  449. Arr: TPSVariantIFC;
  450. I: Integer;
  451. begin
  452. PStart := Stack.Count-1;
  453. Result := True;
  454. if Proc.Name = 'FILEEXISTS' then begin
  455. Stack.SetBool(PStart, NewFileExistsRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  456. end else if Proc.Name = 'DIREXISTS' then begin
  457. Stack.SetBool(PStart, DirExistsRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  458. end else if Proc.Name = 'FILEORDIREXISTS' then begin
  459. Stack.SetBool(PStart, FileOrDirExistsRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  460. end else if Proc.Name = 'GETINISTRING' then begin
  461. Stack.SetString(PStart, GetIniString(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3), Stack.GetString(PStart-4)));
  462. end else if Proc.Name = 'GETINIINT' then begin
  463. Stack.SetInt(PStart, GetIniInt(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetInt(PStart-3), Stack.GetInt(PStart-4), Stack.GetInt(PStart-5), Stack.GetString(PStart-6)));
  464. end else if Proc.Name = 'GETINIBOOL' then begin
  465. Stack.SetBool(PStart, GetIniBool(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetBool(PStart-3), Stack.GetString(PStart-4)));
  466. end else if Proc.Name = 'INIKEYEXISTS' then begin
  467. Stack.SetBool(PStart, IniKeyExists(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3)));
  468. end else if Proc.Name = 'ISINISECTIONEMPTY' then begin
  469. Stack.SetBool(PStart, IsIniSectionEmpty(Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  470. end else if Proc.Name = 'SETINISTRING' then begin
  471. Stack.SetBool(PStart, SetIniString(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3), Stack.GetString(PStart-4)));
  472. end else if Proc.Name = 'SETINIINT' then begin
  473. Stack.SetBool(PStart, SetIniInt(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetInt(PStart-3), Stack.GetString(PStart-4)));
  474. end else if Proc.Name = 'SETINIBOOL' then begin
  475. Stack.SetBool(PStart, SetIniBool(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetBool(PStart-3), Stack.GetString(PStart-4)));
  476. end else if Proc.Name = 'DELETEINIENTRY' then begin
  477. DeleteIniEntry(Stack.GetString(PStart), Stack.GetString(PStart-1), Stack.GetString(PStart-2));
  478. end else if Proc.Name = 'DELETEINISECTION' then begin
  479. DeleteIniSection(Stack.GetString(PStart), Stack.GetString(PStart-1));
  480. end else if Proc.Name = 'GETENV' then begin
  481. Stack.SetString(PStart, GetEnv(Stack.GetString(PStart-1)));
  482. end else if Proc.Name = 'GETCMDTAIL' then begin
  483. Stack.SetString(PStart, GetCmdTail());
  484. end else if Proc.Name = 'PARAMCOUNT' then begin
  485. if NewParamsForCode.Count = 0 then
  486. InternalError('NewParamsForCode not set');
  487. Stack.SetInt(PStart, NewParamsForCode.Count-1);
  488. end else if Proc.Name = 'PARAMSTR' then begin
  489. I := Stack.GetInt(PStart-1);
  490. if (I >= 0) and (I < NewParamsForCode.Count) then
  491. Stack.SetString(PStart, NewParamsForCode[I])
  492. else
  493. Stack.SetString(PStart, '');
  494. end else if Proc.Name = 'ADDBACKSLASH' then begin
  495. Stack.SetString(PStart, AddBackslash(Stack.GetString(PStart-1)));
  496. end else if Proc.Name = 'REMOVEBACKSLASH' then begin
  497. Stack.SetString(PStart, RemoveBackslash(Stack.GetString(PStart-1)));
  498. end else if Proc.Name = 'REMOVEBACKSLASHUNLESSROOT' then begin
  499. Stack.SetString(PStart, RemoveBackslashUnlessRoot(Stack.GetString(PStart-1)));
  500. end else if Proc.Name = 'ADDQUOTES' then begin
  501. Stack.SetString(PStart, AddQuotes(Stack.GetString(PStart-1)));
  502. end else if Proc.Name = 'REMOVEQUOTES' then begin
  503. Stack.SetString(PStart, RemoveQuotes(Stack.GetString(PStart-1)));
  504. end else if Proc.Name = 'GETSHORTNAME' then begin
  505. Stack.SetString(PStart, GetShortNameRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  506. end else if Proc.Name = 'GETWINDIR' then begin
  507. Stack.SetString(PStart, GetWinDir());
  508. end else if Proc.Name = 'GETSYSTEMDIR' then begin
  509. Stack.SetString(PStart, GetSystemDir());
  510. end else if Proc.Name = 'GETSYSWOW64DIR' then begin
  511. Stack.SetString(PStart, GetSysWow64Dir());
  512. end else if Proc.Name = 'GETSYSNATIVEDIR' then begin
  513. Stack.SetString(PStart, GetSysNativeDir(IsWin64));
  514. end else if Proc.Name = 'GETTEMPDIR' then begin
  515. Stack.SetString(PStart, GetTempDir());
  516. end else if Proc.Name = 'STRINGCHANGE' then begin
  517. S := Stack.GetString(PStart-1);
  518. Stack.SetInt(PStart, StringChange(S, Stack.GetString(PStart-2), Stack.GetString(PStart-3)));
  519. Stack.SetString(PStart-1, S);
  520. end else if Proc.Name = 'STRINGCHANGEEX' then begin
  521. S := Stack.GetString(PStart-1);
  522. Stack.SetInt(PStart, StringChangeEx(S, Stack.GetString(PStart-2), Stack.GetString(PStart-3), Stack.GetBool(PStart-4)));
  523. Stack.SetString(PStart-1, S);
  524. end else if Proc.Name = 'USINGWINNT' then begin
  525. Stack.SetBool(PStart, True);
  526. end else if Proc.Name = 'FILECOPY' then begin
  527. ExistingFilename := Stack.GetString(PStart-1);
  528. if PathCompare(ExistingFilename, SetupLdrOriginalFilename) <> 0 then
  529. Stack.SetBool(PStart, CopyFileRedir(ScriptFuncDisableFsRedir,
  530. ExistingFilename, Stack.GetString(PStart-2), Stack.GetBool(PStart-3)))
  531. else
  532. Stack.SetBool(PStart, False);
  533. end else if Proc.Name = 'CONVERTPERCENTSTR' then begin
  534. S := Stack.GetString(PStart-1);
  535. Stack.SetBool(PStart, ConvertPercentStr(S));
  536. Stack.SetString(PStart-1, S);
  537. end else if Proc.Name = 'REGKEYEXISTS' then begin
  538. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  539. S := Stack.GetString(PStart-2);
  540. if RegOpenKeyExView(RegView, RootKey, PChar(S), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  541. Stack.SetBool(PStart, True);
  542. RegCloseKey(K);
  543. end else
  544. Stack.SetBool(PStart, False);
  545. end else if Proc.Name = 'REGVALUEEXISTS' then begin
  546. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  547. S := Stack.GetString(PStart-2);
  548. if RegOpenKeyExView(RegView, RootKey, PChar(S), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  549. N := Stack.GetString(PStart-3);
  550. Stack.SetBool(PStart, RegValueExists(K, PChar(N)));
  551. RegCloseKey(K);
  552. end else
  553. Stack.SetBool(PStart, False);
  554. end else if Proc.Name = 'REGDELETEKEYINCLUDINGSUBKEYS' then begin
  555. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  556. S := Stack.GetString(PStart-2);
  557. Stack.SetBool(PStart, RegDeleteKeyIncludingSubkeys(RegView, RootKey, PChar(S)) = ERROR_SUCCESS);
  558. end else if Proc.Name = 'REGDELETEKEYIFEMPTY' then begin
  559. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  560. S := Stack.GetString(PStart-2);
  561. Stack.SetBool(PStart, RegDeleteKeyIfEmpty(RegView, RootKey, PChar(S)) = ERROR_SUCCESS);
  562. end else if Proc.Name = 'REGDELETEVALUE' then begin
  563. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  564. S := Stack.GetString(PStart-2);
  565. if RegOpenKeyExView(RegView, RootKey, PChar(S), 0, KEY_SET_VALUE, K) = ERROR_SUCCESS then begin
  566. N := Stack.GetString(PStart-3);
  567. Stack.SetBool(PStart, RegDeleteValue(K, PChar(N)) = ERROR_SUCCESS);
  568. RegCloseKey(K);
  569. end else
  570. Stack.SetBool(PStart, False);
  571. end else if Proc.Name = 'REGGETSUBKEYNAMES' then begin
  572. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  573. Arr := NewTPSVariantIFC(Stack[PStart-3], True);
  574. Stack.SetBool(PStart, GetSubkeyOrValueNames(RegView, RootKey,
  575. Stack.GetString(PStart-2), @Arr, True));
  576. end else if Proc.Name = 'REGGETVALUENAMES' then begin
  577. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  578. Arr := NewTPSVariantIFC(Stack[PStart-3], True);
  579. Stack.SetBool(PStart, GetSubkeyOrValueNames(RegView, RootKey,
  580. Stack.GetString(PStart-2), @Arr, False));
  581. end else if Proc.Name = 'REGQUERYSTRINGVALUE' then begin
  582. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  583. S := Stack.GetString(PStart-2);
  584. if RegOpenKeyExView(RegView, RootKey, PChar(S), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  585. N := Stack.GetString(PStart-3);
  586. S := Stack.GetString(PStart-4);
  587. Stack.SetBool(PStart, RegQueryStringValue(K, PChar(N), S));
  588. Stack.SetString(PStart-4, S);
  589. RegCloseKey(K);
  590. end else
  591. Stack.SetBool(PStart, False);
  592. end else if Proc.Name = 'REGQUERYMULTISTRINGVALUE' then begin
  593. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  594. S := Stack.GetString(PStart-2);
  595. if RegOpenKeyExView(RegView, RootKey, PChar(S), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  596. N := Stack.GetString(PStart-3);
  597. S := Stack.GetString(PStart-4);
  598. Stack.SetBool(PStart, RegQueryMultiStringValue(K, PChar(N), S));
  599. Stack.SetString(PStart-4, S);
  600. RegCloseKey(K);
  601. end else
  602. Stack.SetBool(PStart, False);
  603. end else if Proc.Name = 'REGQUERYDWORDVALUE' then begin
  604. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  605. S := Stack.GetString(PStart-2);
  606. if RegOpenKeyExView(RegView, RootKey, PChar(S), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  607. N := Stack.GetString(PStart-3);
  608. Size := SizeOf(Data);
  609. if (RegQueryValueEx(K, PChar(N), nil, @Typ, @Data, @Size) = ERROR_SUCCESS) and (Typ = REG_DWORD) then begin
  610. Stack.SetInt(PStart-4, Data);
  611. Stack.SetBool(PStart, True);
  612. end else
  613. Stack.SetBool(PStart, False);
  614. RegCloseKey(K);
  615. end else
  616. Stack.SetBool(PStart, False);
  617. end else if Proc.Name = 'REGQUERYBINARYVALUE' then begin
  618. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  619. S := Stack.GetString(PStart-2);
  620. if RegOpenKeyExView(RegView, RootKey, PChar(S), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  621. N := Stack.GetString(PStart-3);
  622. if RegQueryValueEx(K, PChar(N), nil, @Typ, nil, @Size) = ERROR_SUCCESS then begin
  623. SetLength(DataS, Size);
  624. if RegQueryValueEx(K, PChar(N), nil, @Typ, @DataS[1], @Size) = ERROR_SUCCESS then begin
  625. StackSetAnsiString(Stack, PStart-4, DataS);
  626. Stack.SetBool(PStart, True);
  627. end else
  628. Stack.SetBool(PStart, False);
  629. end else
  630. Stack.SetBool(PStart, False);
  631. RegCloseKey(K);
  632. end else
  633. Stack.SetBool(PStart, False);
  634. end else if Proc.Name = 'REGWRITESTRINGVALUE' then begin
  635. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  636. S := Stack.GetString(PStart-2);
  637. if RegCreateKeyExView(RegView, RootKey, PChar(S), 0, nil, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE or KEY_SET_VALUE, nil, K, nil) = ERROR_SUCCESS then begin
  638. N := Stack.GetString(PStart-3);
  639. V := Stack.GetString(PStart-4);
  640. if (RegQueryValueEx(K, PChar(N), nil, @ExistingTyp, nil, nil) = ERROR_SUCCESS) and (ExistingTyp = REG_EXPAND_SZ) then
  641. Typ := REG_EXPAND_SZ
  642. else
  643. Typ := REG_SZ;
  644. if RegSetValueEx(K, PChar(N), 0, Typ, PChar(V), (Length(V)+1)*SizeOf(V[1])) = ERROR_SUCCESS then
  645. Stack.SetBool(PStart, True)
  646. else
  647. Stack.SetBool(PStart, False);
  648. RegCloseKey(K);
  649. end else
  650. Stack.SetBool(PStart, False);
  651. end else if Proc.Name = 'REGWRITEEXPANDSTRINGVALUE' then begin
  652. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  653. S := Stack.GetString(PStart-2);
  654. if RegCreateKeyExView(RegView, RootKey, PChar(S), 0, nil, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nil, K, nil) = ERROR_SUCCESS then begin
  655. N := Stack.GetString(PStart-3);
  656. V := Stack.GetString(PStart-4);
  657. if RegSetValueEx(K, PChar(N), 0, REG_EXPAND_SZ, PChar(V), (Length(V)+1)*SizeOf(V[1])) = ERROR_SUCCESS then
  658. Stack.SetBool(PStart, True)
  659. else
  660. Stack.SetBool(PStart, False);
  661. RegCloseKey(K);
  662. end else
  663. Stack.SetBool(PStart, False);
  664. end else if Proc.Name = 'REGWRITEMULTISTRINGVALUE' then begin
  665. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  666. S := Stack.GetString(PStart-2);
  667. if RegCreateKeyExView(RegView, RootKey, PChar(S), 0, nil, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nil, K, nil) = ERROR_SUCCESS then begin
  668. N := Stack.GetString(PStart-3);
  669. V := Stack.GetString(PStart-4);
  670. { Multi-string data requires two null terminators: one after the last
  671. string, and one to mark the end.
  672. Delphi's String type is implicitly null-terminated, so only one null
  673. needs to be added to the end. }
  674. if (V <> '') and (V[Length(V)] <> #0) then
  675. V := V + #0;
  676. if RegSetValueEx(K, PChar(N), 0, REG_MULTI_SZ, PChar(V), (Length(V)+1)*SizeOf(V[1])) = ERROR_SUCCESS then
  677. Stack.SetBool(PStart, True)
  678. else
  679. Stack.SetBool(PStart, False);
  680. RegCloseKey(K);
  681. end else
  682. Stack.SetBool(PStart, False);
  683. end else if Proc.Name = 'REGWRITEDWORDVALUE' then begin
  684. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  685. S := Stack.GetString(PStart-2);
  686. if RegCreateKeyExView(RegView, RootKey, PChar(S), 0, nil, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nil, K, nil) = ERROR_SUCCESS then begin
  687. N := Stack.GetString(PStart-3);
  688. Data := Stack.GetInt(PStart-4);
  689. if RegSetValueEx(K, PChar(N), 0, REG_DWORD, @Data, SizeOf(Data)) = ERROR_SUCCESS then
  690. Stack.SetBool(PStart, True)
  691. else
  692. Stack.SetBool(PStart, False);
  693. RegCloseKey(K);
  694. end else
  695. Stack.SetBool(PStart, False);
  696. end else if Proc.Name = 'REGWRITEBINARYVALUE' then begin
  697. CrackCodeRootKey(Stack.GetInt(PStart-1), RegView, RootKey);
  698. S := Stack.GetString(PStart-2);
  699. if RegCreateKeyExView(RegView, RootKey, PChar(S), 0, nil, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nil, K, nil) = ERROR_SUCCESS then begin
  700. N := Stack.GetString(PStart-3);
  701. DataS := StackGetAnsiString(Stack, PStart-4);
  702. if RegSetValueEx(K, PChar(N), 0, REG_BINARY, @DataS[1], Length(DataS)) = ERROR_SUCCESS then
  703. Stack.SetBool(PStart, True)
  704. else
  705. Stack.SetBool(PStart, False);
  706. RegCloseKey(K);
  707. end else
  708. Stack.SetBool(PStart, False);
  709. end else if (Proc.Name = 'ISADMIN') or (Proc.Name = 'ISADMINLOGGEDON') then begin
  710. Stack.SetBool(PStart, IsAdmin);
  711. end else if Proc.Name = 'ISPOWERUSERLOGGEDON' then begin
  712. Stack.SetBool(PStart, IsPowerUserLoggedOn());
  713. end else if Proc.Name= 'ISADMININSTALLMODE' then begin
  714. Stack.SetBool(PStart, IsAdminInstallMode);
  715. end else if Proc.Name = 'FONTEXISTS' then begin
  716. Stack.SetBool(PStart, FontExists(Stack.GetString(PStart-1)));
  717. end else if Proc.Name = 'GETUILANGUAGE' then begin
  718. Stack.SetInt(PStart, GetUILanguage);
  719. end else if Proc.Name = 'ADDPERIOD' then begin
  720. Stack.SetString(PStart, AddPeriod(Stack.GetString(PStart-1)));
  721. end else if Proc.Name = 'CHARLENGTH' then begin
  722. Stack.SetInt(PStart, PathCharLength(Stack.GetString(PStart-1), Stack.GetInt(PStart-2)));
  723. end else if Proc.Name = 'SETNTFSCOMPRESSION' then begin
  724. Stack.SetBool(PStart, SetNTFSCompressionRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), Stack.GetBool(PStart-2)));
  725. end else if Proc.Name = 'ISWILDCARD' then begin
  726. Stack.SetBool(PStart, IsWildcard(Stack.GetString(PStart-1)));
  727. end else if Proc.Name = 'WILDCARDMATCH' then begin
  728. S := Stack.GetString(PStart-1);
  729. N := Stack.GetString(PStart-2);
  730. Stack.SetBool(PStart, WildcardMatch(PChar(S), PChar(N)));
  731. end else
  732. Result := False;
  733. end;
  734. { Install }
  735. function InstallProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  736. var
  737. PStart: Cardinal;
  738. P: PPSVariantProcPtr;
  739. OnDownloadProgress: TOnDownloadProgress;
  740. begin
  741. if IsUninstaller then
  742. NoUninstallFuncError(Proc.Name);
  743. PStart := Stack.Count-1;
  744. Result := True;
  745. if Proc.Name = 'EXTRACTTEMPORARYFILE' then begin
  746. ExtractTemporaryFile(Stack.GetString(PStart));
  747. end else if Proc.Name = 'EXTRACTTEMPORARYFILES' then begin
  748. Stack.SetInt(PStart, ExtractTemporaryFiles(Stack.GetString(PStart-1)));
  749. {$IFNDEF PS_NOINT64}
  750. end else if Proc.Name = 'DOWNLOADTEMPORARYFILE' then begin
  751. P := Stack.Items[PStart-4];
  752. { ProcNo 0 means nil was passed by the script }
  753. if P.ProcNo <> 0 then
  754. OnDownloadProgress := TOnDownloadProgress(Caller.GetProcAsMethod(P.ProcNo))
  755. else
  756. OnDownloadProgress := nil;
  757. Stack.SetInt64(PStart, DownloadTemporaryFile(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3), OnDownloadProgress));
  758. end else if Proc.Name = 'SETDOWNLOADCREDENTIALS' then begin
  759. SetDownloadCredentials(Stack.GetString(PStart),Stack.GetString(PStart-1));
  760. end else if Proc.Name = 'DOWNLOADTEMPORARYFILESIZE' then begin
  761. Stack.SetInt64(PStart, DownloadTemporaryFileSize(Stack.GetString(PStart-1)));
  762. end else if Proc.Name = 'DOWNLOADTEMPORARYFILEDATE' then begin
  763. Stack.SetString(PStart, DownloadTemporaryFileDate(Stack.GetString(PStart-1)));{$ENDIF}
  764. end else
  765. Result := False;
  766. end;
  767. { InstFunc }
  768. procedure ProcessMessagesProc; far;
  769. begin
  770. Application.ProcessMessages;
  771. end;
  772. function InstFuncProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  773. var
  774. PStart: Cardinal;
  775. Filename: String;
  776. WindowDisabler: TWindowDisabler;
  777. ResultCode, ErrorCode: Integer;
  778. FreeBytes, TotalBytes: Integer64;
  779. RunAsOriginalUser: Boolean;
  780. begin
  781. PStart := Stack.Count-1;
  782. Result := True;
  783. if Proc.Name = 'CHECKFORMUTEXES' then begin
  784. Stack.SetBool(PStart, CheckForMutexes(Stack.GetString(PStart-1)));
  785. end else if Proc.Name = 'DECREMENTSHAREDCOUNT' then begin
  786. if Stack.GetBool(PStart-1) then begin
  787. if not IsWin64 then
  788. InternalError('Cannot access 64-bit registry keys on this version of Windows');
  789. Stack.SetBool(PStart, DecrementSharedCount(rv64Bit, Stack.GetString(PStart-2)));
  790. end
  791. else
  792. Stack.SetBool(PStart, DecrementSharedCount(rv32Bit, Stack.GetString(PStart-2)));
  793. end else if Proc.Name = 'DELAYDELETEFILE' then begin
  794. DelayDeleteFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart), Stack.GetInt(PStart-1), 250, 250);
  795. end else if Proc.Name = 'DELTREE' then begin
  796. Stack.SetBool(PStart, DelTree(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), Stack.GetBool(PStart-2), Stack.GetBool(PStart-3), Stack.GetBool(PStart-4), False, nil, nil, nil));
  797. end else if Proc.Name = 'GENERATEUNIQUENAME' then begin
  798. Stack.SetString(PStart, GenerateUniqueName(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  799. end else if Proc.Name = 'GETCOMPUTERNAMESTRING' then begin
  800. Stack.SetString(PStart, GetComputerNameString());
  801. end else if Proc.Name = 'GETMD5OFFILE' then begin
  802. Stack.SetString(PStart, MD5DigestToString(GetMD5OfFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1))));
  803. end else if Proc.Name = 'GETMD5OFSTRING' then begin
  804. Stack.SetString(PStart, MD5DigestToString(GetMD5OfAnsiString(StackGetAnsiString(Stack, PStart-1))));
  805. end else if Proc.Name = 'GETMD5OFUNICODESTRING' then begin
  806. Stack.SetString(PStart, MD5DigestToString(GetMD5OfUnicodeString(Stack.GetString(PStart-1))));
  807. end else if Proc.Name = 'GETSHA1OFFILE' then begin
  808. Stack.SetString(PStart, SHA1DigestToString(GetSHA1OfFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1))));
  809. end else if Proc.Name = 'GETSHA1OFSTRING' then begin
  810. Stack.SetString(PStart, SHA1DigestToString(GetSHA1OfAnsiString(StackGetAnsiString(Stack, PStart-1))));
  811. end else if Proc.Name = 'GETSHA1OFUNICODESTRING' then begin
  812. Stack.SetString(PStart, SHA1DigestToString(GetSHA1OfUnicodeString(Stack.GetString(PStart-1))));
  813. end else if Proc.Name = 'GETSHA256OFFILE' then begin
  814. Stack.SetString(PStart, GetSHA256OfFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  815. end else if Proc.Name = 'GETSHA256OFSTRING' then begin
  816. Stack.SetString(PStart, GetSHA256OfAnsiString(StackGetAnsiString(Stack, PStart-1)));
  817. end else if Proc.Name = 'GETSHA256OFUNICODESTRING' then begin
  818. Stack.SetString(PStart, GetSHA256OfUnicodeString(Stack.GetString(PStart-1)));
  819. end else if Proc.Name = 'GETSPACEONDISK' then begin
  820. if GetSpaceOnDisk(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), FreeBytes, TotalBytes) then begin
  821. if Stack.GetBool(PStart-2) then begin
  822. Div64(FreeBytes, 1024*1024);
  823. Div64(TotalBytes, 1024*1024);
  824. end;
  825. { Cap at 2 GB, as [Code] doesn't support 64-bit integers }
  826. if (FreeBytes.Hi <> 0) or (FreeBytes.Lo and $80000000 <> 0) then
  827. FreeBytes.Lo := $7FFFFFFF;
  828. if (TotalBytes.Hi <> 0) or (TotalBytes.Lo and $80000000 <> 0) then
  829. TotalBytes.Lo := $7FFFFFFF;
  830. Stack.SetUInt(PStart-3, FreeBytes.Lo);
  831. Stack.SetUInt(PStart-4, TotalBytes.Lo);
  832. Stack.SetBool(PStart, True);
  833. end else
  834. Stack.SetBool(PStart, False);
  835. {$IFNDEF PS_NOINT64}
  836. end else if Proc.Name = 'GETSPACEONDISK64' then begin
  837. if GetSpaceOnDisk(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), FreeBytes, TotalBytes) then begin
  838. Stack.SetInt64(PStart-2, Int64(FreeBytes.Hi) shl 32 + FreeBytes.Lo);
  839. Stack.SetInt64(PStart-3, Int64(TotalBytes.Hi) shl 32 + TotalBytes.Lo);
  840. Stack.SetBool(PStart, True);
  841. end else
  842. Stack.SetBool(PStart, False);
  843. {$ENDIF}
  844. end else if Proc.Name = 'GETUSERNAMESTRING' then begin
  845. Stack.SetString(PStart, GetUserNameString());
  846. end else if Proc.Name = 'INCREMENTSHAREDCOUNT' then begin
  847. if Stack.GetBool(PStart) then begin
  848. if not IsWin64 then
  849. InternalError('Cannot access 64-bit registry keys on this version of Windows');
  850. IncrementSharedCount(rv64Bit, Stack.GetString(PStart-1), Stack.GetBool(PStart-2));
  851. end
  852. else
  853. IncrementSharedCount(rv32Bit, Stack.GetString(PStart-1), Stack.GetBool(PStart-2));
  854. end else if (Proc.Name = 'EXEC') or (Proc.Name = 'EXECASORIGINALUSER') then begin
  855. RunAsOriginalUser := Proc.Name = 'EXECASORIGINALUSER';
  856. if IsUninstaller and RunAsOriginalUser then
  857. NoUninstallFuncError(Proc.Name);
  858. Filename := Stack.GetString(PStart-1);
  859. if PathCompare(Filename, SetupLdrOriginalFilename) <> 0 then begin
  860. { Disable windows so the user can't utilize our UI during the InstExec
  861. call }
  862. WindowDisabler := TWindowDisabler.Create;
  863. try
  864. Stack.SetBool(PStart, InstExecEx(RunAsOriginalUser,
  865. ScriptFuncDisableFsRedir, Filename, Stack.GetString(PStart-2),
  866. Stack.GetString(PStart-3), TExecWait(Stack.GetInt(PStart-5)),
  867. Stack.GetInt(PStart-4), ProcessMessagesProc, ResultCode));
  868. finally
  869. WindowDisabler.Free;
  870. end;
  871. Stack.SetInt(PStart-6, ResultCode);
  872. end else begin
  873. Stack.SetBool(PStart, False);
  874. Stack.SetInt(PStart-6, ERROR_ACCESS_DENIED);
  875. end;
  876. end else if (Proc.Name = 'SHELLEXEC') or (Proc.Name = 'SHELLEXECASORIGINALUSER') then begin
  877. RunAsOriginalUser := Proc.Name = 'SHELLEXECASORIGINALUSER';
  878. if IsUninstaller and RunAsOriginalUser then
  879. NoUninstallFuncError(Proc.Name);
  880. Filename := Stack.GetString(PStart-2);
  881. if PathCompare(Filename, SetupLdrOriginalFilename) <> 0 then begin
  882. { Disable windows so the user can't utilize our UI during the
  883. InstShellExec call }
  884. WindowDisabler := TWindowDisabler.Create;
  885. try
  886. Stack.SetBool(PStart, InstShellExecEx(RunAsOriginalUser,
  887. Stack.GetString(PStart-1), Filename, Stack.GetString(PStart-3),
  888. Stack.GetString(PStart-4), TExecWait(Stack.GetInt(PStart-6)),
  889. Stack.GetInt(PStart-5), ProcessMessagesProc, ErrorCode));
  890. finally
  891. WindowDisabler.Free;
  892. end;
  893. Stack.SetInt(PStart-7, ErrorCode);
  894. end else begin
  895. Stack.SetBool(PStart, False);
  896. Stack.SetInt(PStart-7, ERROR_ACCESS_DENIED);
  897. end;
  898. end else if Proc.Name = 'ISPROTECTEDSYSTEMFILE' then begin
  899. Stack.SetBool(PStart, IsProtectedSystemFile(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  900. end else if Proc.Name = 'MAKEPENDINGFILERENAMEOPERATIONSCHECKSUM' then begin
  901. Stack.SetString(PStart, MD5DigestToString(MakePendingFileRenameOperationsChecksum));
  902. end else if Proc.Name = 'MODIFYPIFFILE' then begin
  903. Stack.SetBool(PStart, ModifyPifFile(Stack.GetString(PStart-1), Stack.GetBool(PStart-2)));
  904. end else if Proc.Name = 'REGISTERSERVER' then begin
  905. RegisterServer(False, Stack.GetBool(PStart), Stack.GetString(PStart-1), Stack.GetBool(PStart-2));
  906. end else if Proc.Name = 'UNREGISTERSERVER' then begin
  907. try
  908. RegisterServer(True, Stack.GetBool(PStart-1), Stack.GetString(PStart-2), Stack.GetBool(PStart-3));
  909. Stack.SetBool(PStart, True);
  910. except
  911. Stack.SetBool(PStart, False);
  912. end;
  913. end else if Proc.Name = 'UNREGISTERFONT' then begin
  914. UnregisterFont(Stack.GetString(PStart), Stack.GetString(PStart-1), Stack.GetBool(PStart-2));
  915. end else if Proc.Name = 'RESTARTREPLACE' then begin
  916. RestartReplace(ScriptFuncDisableFsRedir, Stack.GetString(PStart), Stack.GetString(PStart-1));
  917. end else if Proc.Name = 'FORCEDIRECTORIES' then begin
  918. Stack.SetBool(PStart, ForceDirectories(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  919. end else
  920. Result := False;
  921. end;
  922. { InstFnc2 }
  923. function InstFnc2Proc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  924. var
  925. PStart: Cardinal;
  926. begin
  927. PStart := Stack.Count-1;
  928. Result := True;
  929. if Proc.Name = 'CREATESHELLLINK' then begin
  930. Stack.SetString(PStart, CreateShellLink(Stack.GetString(PStart-1),
  931. Stack.GetString(PStart-2), Stack.GetString(PStart-3),
  932. Stack.GetString(PStart-4), Stack.GetString(PStart-5),
  933. Stack.GetString(PStart-6), Stack.GetInt(PStart-7),
  934. Stack.GetInt(PStart-8), 0, '', nil, False, False));
  935. end else if Proc.Name = 'REGISTERTYPELIBRARY' then begin
  936. if Stack.GetBool(PStart) then
  937. HelperRegisterTypeLibrary(False, Stack.GetString(PStart-1))
  938. else
  939. RegisterTypeLibrary(Stack.GetString(PStart-1));
  940. end else if Proc.Name = 'UNREGISTERTYPELIBRARY' then begin
  941. try
  942. if Stack.GetBool(PStart-1) then
  943. HelperRegisterTypeLibrary(True, Stack.GetString(PStart-2))
  944. else
  945. UnregisterTypeLibrary(Stack.GetString(PStart-2));
  946. Stack.SetBool(PStart, True);
  947. except
  948. Stack.SetBool(PStart, False);
  949. end;
  950. end else if Proc.Name = 'UNPINSHELLLINK' then begin
  951. Stack.SetBool(PStart, UnpinShellLink(Stack.GetString(PStart-1)));
  952. end else
  953. Result := False;
  954. end;
  955. { Main }
  956. function MainProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  957. function CustomMessage(const MsgName: String): String;
  958. begin
  959. if not GetCustomMessageValue(MsgName, Result) then
  960. InternalError(Format('Unknown custom message name "%s"', [MsgName]));
  961. end;
  962. var
  963. PStart: Cardinal;
  964. MinVersion, OnlyBelowVersion: TSetupVersionData;
  965. StringList: TStringList;
  966. S: String;
  967. Components, Suppressible: Boolean;
  968. Default: Integer;
  969. Arr: TPSVariantIFC;
  970. N, I: Integer;
  971. ButtonLabels: array of String;
  972. begin
  973. PStart := Stack.Count-1;
  974. Result := True;
  975. if Proc.Name = 'GETWIZARDFORM' then begin
  976. Stack.SetClass(PStart, GetWizardForm);
  977. end else if Proc.Name = 'GETMAINFORM' then begin
  978. Stack.SetClass(PStart, GetMainForm);
  979. end else if Proc.Name = 'ACTIVELANGUAGE' then begin
  980. Stack.SetString(PStart, ExpandConst('{language}'));
  981. end else if (Proc.Name = 'WIZARDISCOMPONENTSELECTED') or (Proc.Name = 'ISCOMPONENTSELECTED') or
  982. (Proc.Name = 'WIZARDISTASKSELECTED') or (Proc.Name = 'ISTASKSELECTED') then begin
  983. if IsUninstaller then
  984. NoUninstallFuncError(Proc.Name);
  985. StringList := TStringList.Create();
  986. try
  987. Components := (Proc.Name = 'WIZARDISCOMPONENTSELECTED') or (Proc.Name = 'ISCOMPONENTSELECTED');
  988. if Components then
  989. GetWizardForm.GetSelectedComponents(StringList, False, False)
  990. else
  991. GetWizardForm.GetSelectedTasks(StringList, False, False, False);
  992. S := Stack.GetString(PStart-1);
  993. StringChange(S, '/', '\');
  994. if Components then
  995. Stack.SetBool(PStart, ShouldProcessEntry(StringList, nil, S, '', '', ''))
  996. else
  997. Stack.SetBool(PStart, ShouldProcessEntry(nil, StringList, '', S, '', ''));
  998. finally
  999. StringList.Free();
  1000. end;
  1001. end else if Proc.Name = 'EXPANDCONSTANT' then begin
  1002. Stack.SetString(PStart, ExpandConst(Stack.GetString(PStart-1)));
  1003. end else if Proc.Name = 'EXPANDCONSTANTEX' then begin
  1004. Stack.SetString(PStart, ExpandConstEx(Stack.GetString(PStart-1), [Stack.GetString(PStart-2), Stack.GetString(PStart-3)]));
  1005. end else if Proc.Name = 'EXITSETUPMSGBOX' then begin
  1006. Stack.SetBool(PStart, ExitSetupMsgBox());
  1007. end else if Proc.Name = 'GETSHELLFOLDERBYCSIDL' then begin
  1008. Stack.SetString(PStart, GetShellFolderByCSIDL(Stack.GetInt(PStart-1), Stack.GetBool(PStart-2)));
  1009. end else if Proc.Name = 'INSTALLONTHISVERSION' then begin
  1010. if not StrToSetupVersionData(Stack.GetString(PStart-1), MinVersion) then
  1011. InternalError('InstallOnThisVersion: Invalid MinVersion string')
  1012. else if not StrToSetupVersionData(Stack.GetString(PStart-2), OnlyBelowVersion) then
  1013. InternalError('InstallOnThisVersion: Invalid OnlyBelowVersion string')
  1014. else
  1015. Stack.SetBool(PStart, (InstallOnThisVersion(MinVersion, OnlyBelowVersion) = irInstall));
  1016. end else if Proc.Name = 'GETWINDOWSVERSION' then begin
  1017. Stack.SetUInt(PStart, WindowsVersion);
  1018. end else if Proc.Name = 'GETWINDOWSVERSIONSTRING' then begin
  1019. Stack.SetString(PStart, Format('%u.%.2u.%u', [WindowsVersion shr 24,
  1020. (WindowsVersion shr 16) and $FF, WindowsVersion and $FFFF]));
  1021. end else if (Proc.Name = 'MSGBOX') or (Proc.Name = 'SUPPRESSIBLEMSGBOX') then begin
  1022. if Proc.Name = 'MSGBOX' then begin
  1023. Suppressible := False;
  1024. Default := 0;
  1025. end else begin
  1026. Suppressible := True;
  1027. Default := Stack.GetInt(PStart-4);
  1028. end;
  1029. Stack.SetInt(PStart, LoggedMsgBox(Stack.GetString(PStart-1), GetMsgBoxCaption, TMsgBoxType(Stack.GetInt(PStart-2)), Stack.GetInt(PStart-3), Suppressible, Default));
  1030. end else if (Proc.Name = 'TASKDIALOGMSGBOX') or (Proc.Name = 'SUPPRESSIBLETASKDIALOGMSGBOX') then begin
  1031. if Proc.Name = 'TASKDIALOGMSGBOX' then begin
  1032. Suppressible := False;
  1033. Default := 0;
  1034. end else begin
  1035. Suppressible := True;
  1036. Default := Stack.GetInt(PStart-7);
  1037. end;
  1038. Arr := NewTPSVariantIFC(Stack[PStart-5], True);
  1039. N := PSDynArrayGetLength(Pointer(Arr.Dta^), Arr.aType);
  1040. SetLength(ButtonLabels, N);
  1041. for I := 0 to N-1 do
  1042. ButtonLabels[I] := VNGetString(PSGetArrayField(Arr, I));
  1043. Stack.SetInt(PStart, LoggedTaskDialogMsgBox('', Stack.GetString(PStart-1), Stack.GetString(PStart-2), GetMsgBoxCaption, TMsgBoxType(Stack.GetInt(PStart-3)), Stack.GetInt(PStart-4), ButtonLabels, Stack.GetInt(PStart-6), Suppressible, Default));
  1044. end else if Proc.Name = 'ISWIN64' then begin
  1045. Stack.SetBool(PStart, IsWin64);
  1046. end else if Proc.Name = 'IS64BITINSTALLMODE' then begin
  1047. Stack.SetBool(PStart, Is64BitInstallMode);
  1048. end else if Proc.Name = 'PROCESSORARCHITECTURE' then begin
  1049. Stack.SetInt(PStart, Integer(ProcessorArchitecture));
  1050. end else if Proc.Name = 'ISX86' then begin
  1051. Stack.SetBool(PStart, ProcessorArchitecture = paX86);
  1052. end else if Proc.Name = 'ISX64' then begin
  1053. Stack.SetBool(PStart, ProcessorArchitecture = paX64);
  1054. end else if Proc.Name = 'ISIA64' then begin
  1055. Stack.SetBool(PStart, ProcessorArchitecture = paIA64);
  1056. end else if Proc.Name = 'ISARM64' then begin
  1057. Stack.SetBool(PStart, ProcessorArchitecture = paARM64);
  1058. end else if Proc.Name = 'CUSTOMMESSAGE' then begin
  1059. Stack.SetString(PStart, CustomMessage(Stack.GetString(PStart-1)));
  1060. end else if Proc.Name = 'RMSESSIONSTARTED' then begin
  1061. Stack.SetBool(PStart, RmSessionStarted);
  1062. end else if Proc.Name = 'REGISTEREXTRACLOSEAPPLICATIONSRESOURCE' then begin
  1063. Stack.SetBool(PStart, CodeRegisterExtraCloseApplicationsResource(Stack.GetBool(PStart-1), Stack.GetString(PStart-2)));
  1064. end else
  1065. Result := False;
  1066. end;
  1067. type
  1068. { *Must* keep this in synch with ScriptFunc_C }
  1069. TWindowsVersion = packed record
  1070. Major: Cardinal;
  1071. Minor: Cardinal;
  1072. Build: Cardinal;
  1073. ServicePackMajor: Cardinal;
  1074. ServicePackMinor: Cardinal;
  1075. NTPlatform: Boolean;
  1076. ProductType: Byte;
  1077. SuiteMask: Word;
  1078. end;
  1079. procedure _GetWindowsVersionEx(var Version: TWindowsVersion);
  1080. begin
  1081. Version.Major := WindowsVersion shr 24;
  1082. Version.Minor := (WindowsVersion shr 16) and $FF;
  1083. Version.Build := WindowsVersion and $FFFF;
  1084. Version.ServicePackMajor := Hi(NTServicePackLevel);
  1085. Version.ServicePackMinor := Lo(NTServicePackLevel);
  1086. Version.NTPlatform := True;
  1087. Version.ProductType := WindowsProductType;
  1088. Version.SuiteMask := WindowsSuiteMask;
  1089. end;
  1090. { Msgs }
  1091. function MsgsProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1092. var
  1093. PStart: Cardinal;
  1094. begin
  1095. PStart := Stack.Count-1;
  1096. Result := True;
  1097. if Proc.Name = 'SETUPMESSAGE' then begin
  1098. Stack.SetString(PStart, SetupMessages[TSetupMessageID(Stack.GetInt(PStart-1))]);
  1099. end else
  1100. Result := False;
  1101. end;
  1102. function _FmtMessage(const S: String; const Args: array of String): String;
  1103. begin
  1104. Result := FmtMessage(PChar(S), Args);
  1105. end;
  1106. { System }
  1107. function SystemProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1108. var
  1109. PStart: Cardinal;
  1110. F: TFile;
  1111. TmpFileSize: Integer64;
  1112. begin
  1113. PStart := Stack.Count-1;
  1114. Result := True;
  1115. if Proc.Name = 'RANDOM' then begin
  1116. Stack.SetInt(PStart, Random(Stack.GetInt(PStart-1)));
  1117. end else if Proc.Name = 'FILESIZE' then begin
  1118. try
  1119. F := TFileRedir.Create(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), fdOpenExisting, faRead, fsReadWrite);
  1120. try
  1121. Stack.SetInt(PStart-2, F.CappedSize);
  1122. Stack.SetBool(PStart, True);
  1123. finally
  1124. F.Free;
  1125. end;
  1126. except
  1127. Stack.SetBool(PStart, False);
  1128. end;
  1129. {$IFNDEF PS_NOINT64}
  1130. end else if Proc.Name = 'FILESIZE64' then begin
  1131. try
  1132. F := TFileRedir.Create(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), fdOpenExisting, faRead, fsReadWrite);
  1133. try
  1134. TmpFileSize := F.Size; { Make sure we access F.Size only once }
  1135. Stack.SetInt64(PStart-2, Int64(TmpFileSize.Hi) shl 32 + TmpFileSize.Lo);
  1136. Stack.SetBool(PStart, True);
  1137. finally
  1138. F.Free;
  1139. end;
  1140. except
  1141. Stack.SetBool(PStart, False);
  1142. end;
  1143. {$ENDIF}
  1144. end else if Proc.Name = 'SET8087CW' then begin
  1145. Set8087CW(Stack.GetInt(PStart));
  1146. end else if Proc.Name = 'GET8087CW' then begin
  1147. Stack.SetInt(PStart, Get8087CW);
  1148. end else
  1149. Result := False;
  1150. end;
  1151. { SysUtils }
  1152. type
  1153. { *Must* keep this in synch with ScriptFunc_C }
  1154. TFindRec = record
  1155. Name: String;
  1156. Attributes: LongWord;
  1157. SizeHigh: LongWord;
  1158. SizeLow: LongWord;
  1159. CreationTime: TFileTime;
  1160. LastAccessTime: TFileTime;
  1161. LastWriteTime: TFileTime;
  1162. AlternateName: String;
  1163. FindHandle: THandle;
  1164. end;
  1165. function SysUtilsProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1166. { ExtractRelativePath is not in Delphi 2's SysUtils. Use the one from Delphi 7.01. }
  1167. function NewExtractRelativePath(BaseName, DestName: string): string;
  1168. var
  1169. BasePath, DestPath: string;
  1170. BaseLead, DestLead: PChar;
  1171. BasePtr, DestPtr: PChar;
  1172. function ExtractFilePathNoDrive(const FileName: string): string;
  1173. begin
  1174. Result := PathExtractPath(FileName);
  1175. Delete(Result, 1, Length(PathExtractDrive(FileName)));
  1176. end;
  1177. function Next(var Lead: PChar): PChar;
  1178. begin
  1179. Result := Lead;
  1180. if Result = nil then Exit;
  1181. Lead := PathStrScan(Lead, '\');
  1182. if Lead <> nil then
  1183. begin
  1184. Lead^ := #0;
  1185. Inc(Lead);
  1186. end;
  1187. end;
  1188. begin
  1189. { For consistency with the PathExtract* functions, normalize slashes so
  1190. that forward slashes and multiple slashes work with this function also }
  1191. BaseName := PathNormalizeSlashes(BaseName);
  1192. DestName := PathNormalizeSlashes(DestName);
  1193. if PathCompare(PathExtractDrive(BaseName), PathExtractDrive(DestName)) = 0 then
  1194. begin
  1195. BasePath := ExtractFilePathNoDrive(BaseName);
  1196. UniqueString(BasePath);
  1197. DestPath := ExtractFilePathNoDrive(DestName);
  1198. UniqueString(DestPath);
  1199. BaseLead := Pointer(BasePath);
  1200. BasePtr := Next(BaseLead);
  1201. DestLead := Pointer(DestPath);
  1202. DestPtr := Next(DestLead);
  1203. while (BasePtr <> nil) and (DestPtr <> nil) and (PathCompare(BasePtr, DestPtr) = 0) do
  1204. begin
  1205. BasePtr := Next(BaseLead);
  1206. DestPtr := Next(DestLead);
  1207. end;
  1208. Result := '';
  1209. while BaseLead <> nil do
  1210. begin
  1211. Result := Result + '..\'; { Do not localize }
  1212. Next(BaseLead);
  1213. end;
  1214. if (DestPtr <> nil) and (DestPtr^ <> #0) then
  1215. Result := Result + DestPtr + '\';
  1216. if DestLead <> nil then
  1217. Result := Result + DestLead; // destlead already has a trailing backslash
  1218. Result := Result + PathExtractName(DestName);
  1219. end
  1220. else
  1221. Result := DestName;
  1222. end;
  1223. { Use our own FileSearch function which includes these improvements over
  1224. Delphi's version:
  1225. - it supports MBCS and uses Path* functions
  1226. - it uses NewFileExistsRedir instead of FileExists
  1227. - it doesn't search the current directory unless it's told to
  1228. - it always returns a fully-qualified path }
  1229. function NewFileSearch(const DisableFsRedir: Boolean;
  1230. const Name, DirList: String): String;
  1231. var
  1232. I, P, L: Integer;
  1233. begin
  1234. { If Name is absolute, drive-relative, or root-relative, don't search DirList }
  1235. if PathDrivePartLengthEx(Name, True) <> 0 then begin
  1236. Result := PathExpand(Name);
  1237. if NewFileExistsRedir(DisableFsRedir, Result) then
  1238. Exit;
  1239. end
  1240. else begin
  1241. P := 1;
  1242. L := Length(DirList);
  1243. while True do begin
  1244. while (P <= L) and (DirList[P] = ';') do
  1245. Inc(P);
  1246. if P > L then
  1247. Break;
  1248. I := P;
  1249. while (P <= L) and (DirList[P] <> ';') do
  1250. Inc(P, PathCharLength(DirList, P));
  1251. Result := PathExpand(PathCombine(Copy(DirList, I, P - I), Name));
  1252. if NewFileExistsRedir(DisableFsRedir, Result) then
  1253. Exit;
  1254. end;
  1255. end;
  1256. Result := '';
  1257. end;
  1258. var
  1259. PStart: Cardinal;
  1260. OldName: String;
  1261. NewDateSeparator, NewTimeSeparator: Char;
  1262. OldDateSeparator, OldTimeSeparator: Char;
  1263. begin
  1264. PStart := Stack.Count-1;
  1265. Result := True;
  1266. if Proc.Name = 'BEEP' then begin
  1267. Beep();
  1268. end else if Proc.Name = 'TRIM' then begin
  1269. Stack.SetString(PStart, Trim(Stack.GetString(PStart-1)));
  1270. end else if Proc.Name = 'TRIMLEFT' then begin
  1271. Stack.SetString(PStart, TrimLeft(Stack.GetString(PStart-1)));
  1272. end else if Proc.Name = 'TRIMRIGHT' then begin
  1273. Stack.SetString(PStart, TrimRight(Stack.GetString(PStart-1)));
  1274. end else if Proc.Name = 'GETCURRENTDIR' then begin
  1275. Stack.SetString(PStart, GetCurrentDir());
  1276. end else if Proc.Name = 'SETCURRENTDIR' then begin
  1277. Stack.SetBool(PStart, SetCurrentDir(Stack.GetString(PStart-1)));
  1278. end else if Proc.Name = 'EXPANDFILENAME' then begin
  1279. Stack.SetString(PStart, PathExpand(Stack.GetString(PStart-1)));
  1280. end else if Proc.Name = 'EXPANDUNCFILENAME' then begin
  1281. Stack.SetString(PStart, ExpandUNCFileName(Stack.GetString(PStart-1)));
  1282. end else if Proc.Name = 'EXTRACTRELATIVEPATH' then begin
  1283. Stack.SetString(PStart, NewExtractRelativePath(Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  1284. end else if Proc.Name = 'EXTRACTFILEDIR' then begin
  1285. Stack.SetString(PStart, PathExtractDir(Stack.GetString(PStart-1)));
  1286. end else if Proc.Name = 'EXTRACTFILEDRIVE' then begin
  1287. Stack.SetString(PStart, PathExtractDrive(Stack.GetString(PStart-1)));
  1288. end else if Proc.Name = 'EXTRACTFILEEXT' then begin
  1289. Stack.SetString(PStart, PathExtractExt(Stack.GetString(PStart-1)));
  1290. end else if Proc.Name = 'EXTRACTFILENAME' then begin
  1291. Stack.SetString(PStart, PathExtractName(Stack.GetString(PStart-1)));
  1292. end else if Proc.Name = 'EXTRACTFILEPATH' then begin
  1293. Stack.SetString(PStart, PathExtractPath(Stack.GetString(PStart-1)));
  1294. end else if Proc.Name = 'CHANGEFILEEXT' then begin
  1295. Stack.SetString(PStart, PathChangeExt(Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  1296. end else if Proc.Name = 'FILESEARCH' then begin
  1297. Stack.SetString(PStart, NewFileSearch(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  1298. end else if Proc.Name = 'RENAMEFILE' then begin
  1299. OldName := Stack.GetString(PStart-1);
  1300. if PathCompare(OldName, SetupLdrOriginalFilename) <> 0 then
  1301. Stack.SetBool(PStart, MoveFileRedir(ScriptFuncDisableFsRedir, OldName, Stack.GetString(PStart-2)))
  1302. else
  1303. Stack.SetBool(PStart, False);
  1304. end else if Proc.Name = 'DELETEFILE' then begin
  1305. Stack.SetBool(PStart, DeleteFileRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  1306. end else if Proc.Name = 'CREATEDIR' then begin
  1307. Stack.SetBool(PStart, CreateDirectoryRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  1308. end else if Proc.Name = 'REMOVEDIR' then begin
  1309. Stack.SetBool(PStart, RemoveDirectoryRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1)));
  1310. end else if Proc.Name = 'COMPARESTR' then begin
  1311. Stack.SetInt(PStart, CompareStr(Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  1312. end else if Proc.Name = 'COMPARETEXT' then begin
  1313. Stack.SetInt(PStart, CompareText(Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  1314. end else if Proc.Name = 'SAMESTR' then begin
  1315. Stack.SetBool(PStart, CompareStr(Stack.GetString(PStart-1), Stack.GetString(PStart-2)) = 0);
  1316. end else if Proc.Name = 'SAMETEXT' then begin
  1317. Stack.SetBool(PStart, CompareText(Stack.GetString(PStart-1), Stack.GetString(PStart-2)) = 0);
  1318. end else if Proc.Name = 'GETDATETIMESTRING' then begin
  1319. OldDateSeparator := FormatSettings.DateSeparator;
  1320. OldTimeSeparator := FormatSettings.TimeSeparator;
  1321. try
  1322. NewDateSeparator := Stack.GetString(PStart-2)[1];
  1323. NewTimeSeparator := Stack.GetString(PStart-3)[1];
  1324. if NewDateSeparator <> #0 then
  1325. FormatSettings.DateSeparator := NewDateSeparator;
  1326. if NewTimeSeparator <> #0 then
  1327. FormatSettings.TimeSeparator := NewTimeSeparator;
  1328. Stack.SetString(PStart, FormatDateTime(Stack.GetString(PStart-1), Now()));
  1329. finally
  1330. FormatSettings.TimeSeparator := OldTimeSeparator;
  1331. FormatSettings.DateSeparator := OldDateSeparator;
  1332. end;
  1333. end else if Proc.Name = 'SYSERRORMESSAGE' then begin
  1334. Stack.SetString(PStart, Win32ErrorString(Stack.GetInt(PStart-1)));
  1335. end else
  1336. Result := False;
  1337. end;
  1338. procedure FindDataToFindRec(const FindData: TWin32FindData;
  1339. var FindRec: TFindRec);
  1340. begin
  1341. FindRec.Name := FindData.cFileName;
  1342. FindRec.Attributes := FindData.dwFileAttributes;
  1343. FindRec.SizeHigh := FindData.nFileSizeHigh;
  1344. FindRec.SizeLow := FindData.nFileSizeLow;
  1345. FindRec.CreationTime := FindData.ftCreationTime;
  1346. FindRec.LastAccessTime := FindData.ftLastAccessTime;
  1347. FindRec.LastWriteTime := FindData.ftLastWriteTime;
  1348. FindRec.AlternateName := FindData.cAlternateFileName;
  1349. end;
  1350. function _FindFirst(const FileName: String; var FindRec: TFindRec): Boolean;
  1351. var
  1352. FindHandle: THandle;
  1353. FindData: TWin32FindData;
  1354. begin
  1355. FindHandle := FindFirstFileRedir(ScriptFuncDisableFsRedir, FileName, FindData);
  1356. if FindHandle <> INVALID_HANDLE_VALUE then begin
  1357. FindRec.FindHandle := FindHandle;
  1358. FindDataToFindRec(FindData, FindRec);
  1359. Result := True;
  1360. end
  1361. else begin
  1362. FindRec.FindHandle := 0;
  1363. Result := False;
  1364. end;
  1365. end;
  1366. function _FindNext(var FindRec: TFindRec): Boolean;
  1367. var
  1368. FindData: TWin32FindData;
  1369. begin
  1370. Result := (FindRec.FindHandle <> 0) and FindNextFile(FindRec.FindHandle, FindData);
  1371. if Result then
  1372. FindDataToFindRec(FindData, FindRec);
  1373. end;
  1374. procedure _FindClose(var FindRec: TFindRec);
  1375. begin
  1376. if FindRec.FindHandle <> 0 then begin
  1377. Windows.FindClose(FindRec.FindHandle);
  1378. FindRec.FindHandle := 0;
  1379. end;
  1380. end;
  1381. { VerInfo }
  1382. function VerInfoProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1383. var
  1384. PStart: Cardinal;
  1385. VersionNumbers: TFileVersionNumbers;
  1386. begin
  1387. PStart := Stack.Count-1;
  1388. Result := True;
  1389. if Proc.Name = 'GETVERSIONNUMBERS' then begin
  1390. if GetVersionNumbersRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), VersionNumbers) then begin
  1391. Stack.SetInt(PStart-2, VersionNumbers.MS);
  1392. Stack.SetInt(PStart-3, VersionNumbers.LS);
  1393. Stack.SetBool(PStart, True);
  1394. end else
  1395. Stack.SetBool(PStart, False);
  1396. end else if Proc.Name = 'GETVERSIONCOMPONENTS' then begin
  1397. if GetVersionNumbersRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), VersionNumbers) then begin
  1398. Stack.SetUInt(PStart-2, VersionNumbers.MS shr 16);
  1399. Stack.SetUInt(PStart-3, VersionNumbers.MS and $FFFF);
  1400. Stack.SetUInt(PStart-4, VersionNumbers.LS shr 16);
  1401. Stack.SetUInt(PStart-5, VersionNumbers.LS and $FFFF);
  1402. Stack.SetBool(PStart, True);
  1403. end else
  1404. Stack.SetBool(PStart, False);
  1405. end else if Proc.Name = 'GETVERSIONNUMBERSSTRING' then begin
  1406. if GetVersionNumbersRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), VersionNumbers) then begin
  1407. Stack.SetString(PStart-2, Format('%u.%u.%u.%u', [VersionNumbers.MS shr 16,
  1408. VersionNumbers.MS and $FFFF, VersionNumbers.LS shr 16, VersionNumbers.LS and $FFFF]));
  1409. Stack.SetBool(PStart, True);
  1410. end else
  1411. Stack.SetBool(PStart, False);
  1412. end else if Proc.Name = 'GETPACKEDVERSION' then begin
  1413. if GetVersionNumbersRedir(ScriptFuncDisableFsRedir, Stack.GetString(PStart-1), VersionNumbers) then begin
  1414. Stack.SetInt64(PStart-2, (Int64(VersionNumbers.MS) shl 32) or VersionNumbers.LS);
  1415. Stack.SetBool(PStart, True);
  1416. end else
  1417. Stack.SetBool(PStart, False);
  1418. end else if Proc.Name = 'PACKVERSIONNUMBERS' then begin
  1419. Stack.SetInt64(PStart, Int64((UInt64(Stack.GetUInt(PStart-1)) shl 32) or Stack.GetUInt(PStart-2)));
  1420. end else if Proc.Name = 'PACKVERSIONCOMPONENTS' then begin
  1421. VersionNumbers.MS := (Stack.GetUInt(PStart-1) shl 16) or (Stack.GetUInt(PStart-2) and $FFFF);
  1422. VersionNumbers.LS := (Stack.GetUInt(PStart-3) shl 16) or (Stack.GetUInt(PStart-4) and $FFFF);
  1423. Stack.SetInt64(PStart, Int64((UInt64(VersionNumbers.MS) shl 32) or VersionNumbers.LS));
  1424. end else if Proc.Name = 'COMPAREPACKEDVERSION' then begin
  1425. Stack.SetInt(PStart, Compare64(Integer64(Stack.GetInt64(PStart-1)), Integer64(Stack.GetInt64(PStart-2))));
  1426. end else if Proc.Name = 'SAMEPACKEDVERSION' then begin
  1427. Stack.SetBool(PStart, Compare64(Integer64(Stack.GetInt64(PStart-1)), Integer64(Stack.GetInt64(PStart-2))) = 0);
  1428. end else if Proc.Name = 'UNPACKVERSIONNUMBERS' then begin
  1429. VersionNumbers.MS := UInt64(Stack.GetInt64(PStart)) shr 32;
  1430. VersionNumbers.LS := UInt64(Stack.GetInt64(PStart)) and $FFFFFFFF;
  1431. Stack.SetUInt(PStart-1, VersionNumbers.MS);
  1432. Stack.SetUInt(PStart-2, VersionNumbers.LS);
  1433. end else if Proc.Name = 'UNPACKVERSIONCOMPONENTS' then begin
  1434. VersionNumbers.MS := UInt64(Stack.GetInt64(PStart)) shr 32;
  1435. VersionNumbers.LS := UInt64(Stack.GetInt64(PStart)) and $FFFFFFFF;
  1436. Stack.SetUInt(PStart-1, VersionNumbers.MS shr 16);
  1437. Stack.SetUInt(PStart-2, VersionNumbers.MS and $FFFF);
  1438. Stack.SetUInt(PStart-3, VersionNumbers.LS shr 16);
  1439. Stack.SetUInt(PStart-4, VersionNumbers.LS and $FFFF);
  1440. end else if Proc.Name = 'VERSIONTOSTR' then begin
  1441. VersionNumbers.MS := UInt64(Stack.GetInt64(PStart-1)) shr 32;
  1442. VersionNumbers.LS := UInt64(Stack.GetInt64(PStart-1)) and $FFFFFFFF;
  1443. Stack.SetString(PStart, Format('%u.%u.%u.%u', [VersionNumbers.MS shr 16,
  1444. VersionNumbers.MS and $FFFF, VersionNumbers.LS shr 16, VersionNumbers.LS and $FFFF]));
  1445. end else if Proc.Name = 'STRTOVERSION' then begin
  1446. if StrToVersionNumbers(Stack.GetString(PStart-1), VersionNumbers) then begin
  1447. Stack.SetInt64(PStart-2, (Int64(VersionNumbers.MS) shl 32) or VersionNumbers.LS);
  1448. Stack.SetBool(PStart, True);
  1449. end else
  1450. Stack.SetBool(PStart, False);
  1451. end else
  1452. Result := False;
  1453. end;
  1454. type
  1455. TDllProc = function(const Param1, Param2: Longint): Longint; stdcall;
  1456. { Windows }
  1457. function WindowsProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1458. var
  1459. PStart: Cardinal;
  1460. DllProc: TDllProc;
  1461. DllHandle: THandle;
  1462. S: AnsiString;
  1463. begin
  1464. PStart := Stack.Count-1;
  1465. Result := True;
  1466. if Proc.Name = 'SLEEP' then begin
  1467. Sleep(Stack.GetInt(PStart));
  1468. end else if Proc.Name = 'FINDWINDOWBYCLASSNAME' then begin
  1469. Stack.SetInt(PStart, FindWindow(PChar(Stack.GetString(PStart-1)), nil));
  1470. end else if Proc.Name = 'FINDWINDOWBYWINDOWNAME' then begin
  1471. Stack.SetInt(PStart, FindWindow(nil, PChar(Stack.GetString(PStart-1))));
  1472. end else if Proc.Name = 'SENDMESSAGE' then begin
  1473. Stack.SetInt(PStart, SendMessage(Stack.GetInt(PStart-1), Stack.GetInt(PStart-2), Stack.GetInt(PStart-3), Stack.GetInt(PStart-4)));
  1474. end else if Proc.Name = 'POSTMESSAGE' then begin
  1475. Stack.SetBool(PStart, PostMessage(Stack.GetInt(PStart-1), Stack.GetInt(PStart-2), Stack.GetInt(PStart-3), Stack.GetInt(PStart-4)));
  1476. end else if Proc.Name = 'SENDNOTIFYMESSAGE' then begin
  1477. Stack.SetBool(PStart, SendNotifyMessage(Stack.GetInt(PStart-1), Stack.GetInt(PStart-2), Stack.GetInt(PStart-3), Stack.GetInt(PStart-4)));
  1478. end else if Proc.Name = 'REGISTERWINDOWMESSAGE' then begin
  1479. Stack.SetInt(PStart, RegisterWindowMessage(PChar(Stack.GetString(PStart-1))));
  1480. end else if Proc.Name = 'SENDBROADCASTMESSAGE' then begin
  1481. Stack.SetInt(PStart, SendMessage(HWND_BROADCAST, Stack.GetInt(PStart-1), Stack.GetInt(PStart-2), Stack.GetInt(PStart-3)));
  1482. end else if Proc.Name = 'POSTBROADCASTMESSAGE' then begin
  1483. Stack.SetBool(PStart, PostMessage(HWND_BROADCAST, Stack.GetInt(PStart-1), Stack.GetInt(PStart-2), Stack.GetInt(PStart-3)));
  1484. end else if Proc.Name = 'SENDBROADCASTNOTIFYMESSAGE' then begin
  1485. Stack.SetBool(PStart, SendNotifyMessage(HWND_BROADCAST, Stack.GetInt(PStart-1), Stack.GetInt(PStart-2), Stack.GetInt(PStart-3)));
  1486. end else if Proc.Name = 'LOADDLL' then begin
  1487. DllHandle := SafeLoadLibrary(Stack.GetString(PStart-1), SEM_NOOPENFILEERRORBOX);
  1488. if DllHandle <> 0 then
  1489. Stack.SetInt(PStart-2, 0)
  1490. else
  1491. Stack.SetInt(PStart-2, GetLastError());
  1492. Stack.SetInt(PStart, DllHandle);
  1493. end else if Proc.Name = 'CALLDLLPROC' then begin
  1494. @DllProc := GetProcAddress(Stack.GetInt(PStart-1), PChar(Stack.GetString(PStart-2)));
  1495. if Assigned(DllProc) then begin
  1496. Stack.SetInt(PStart-5, DllProc(Stack.GetInt(PStart-3), Stack.GetInt(PStart-4)));
  1497. Stack.SetBool(PStart, True);
  1498. end else
  1499. Stack.SetBool(PStart, False);
  1500. end else if Proc.Name = 'FREEDLL' then begin
  1501. Stack.SetBool(PStart, FreeLibrary(Stack.GetInt(PStart-1)));
  1502. end else if Proc.Name = 'CREATEMUTEX' then begin
  1503. Windows.CreateMutex(nil, False, PChar(Stack.GetString(PStart)));
  1504. end else if Proc.Name = 'OEMTOCHARBUFF' then begin
  1505. S := StackGetAnsiString(Stack, PStart);
  1506. OemToCharBuffA(PAnsiChar(S), PAnsiChar(S), Length(S));
  1507. StackSetAnsiString(Stack, PStart, S);
  1508. end else if Proc.Name = 'CHARTOOEMBUFF' then begin
  1509. S := StackGetAnsiString(Stack, PStart);
  1510. CharToOemBuffA(PAnsiChar(S), PAnsiChar(S), Length(S));
  1511. StackSetAnsiString(Stack, PStart, S);
  1512. end else
  1513. Result := False;
  1514. end;
  1515. { Ole2 }
  1516. function Ole2Proc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1517. begin
  1518. Result := True;
  1519. if Proc.Name = 'COFREEUNUSEDLIBRARIES' then begin
  1520. CoFreeUnusedLibraries;
  1521. end else
  1522. Result := False;
  1523. end;
  1524. { Logging }
  1525. function LoggingProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1526. var
  1527. PStart: Cardinal;
  1528. begin
  1529. PStart := Stack.Count-1;
  1530. Result := True;
  1531. if Proc.Name = 'LOG' then begin
  1532. Log(Stack.GetString(PStart));
  1533. end else
  1534. Result := False;
  1535. end;
  1536. { Other }
  1537. var
  1538. ASMInliners: array of Pointer;
  1539. function OtherProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, Stack: TPSStack): Boolean;
  1540. function GetExceptionMessage: String;
  1541. var
  1542. Code: TPSError;
  1543. E: TObject;
  1544. begin
  1545. Code := Caller.LastEx;
  1546. if Code = erNoError then
  1547. Result := '(There is no current exception)'
  1548. else begin
  1549. E := Caller.LastExObject;
  1550. if Assigned(E) and (E is Exception) then
  1551. Result := Exception(E).Message
  1552. else
  1553. Result := String(PSErrorToString(Code, Caller.LastExParam));
  1554. end;
  1555. end;
  1556. function GetCodePreviousData(const ExpandedAppID, ValueName, DefaultValueData: String): String;
  1557. begin
  1558. { do not localize or change the following string }
  1559. Result := GetPreviousData(ExpandedAppId, 'Inno Setup CodeFile: ' + ValueName, DefaultValueData);
  1560. end;
  1561. { Also see RegisterUninstallInfo in Install.pas }
  1562. function SetCodePreviousData(const PreviousDataKey: HKEY; const ValueName, ValueData: String): Boolean;
  1563. begin
  1564. if ValueData <> '' then begin
  1565. { do not localize or change the following string }
  1566. Result := RegSetValueEx(PreviousDataKey, PChar('Inno Setup CodeFile: ' + ValueName), 0, REG_SZ, PChar(ValueData), (Length(ValueData)+1)*SizeOf(ValueData[1])) = ERROR_SUCCESS
  1567. end else
  1568. Result := True;
  1569. end;
  1570. function LoadStringFromFile(const FileName: String; var S: AnsiString): Boolean;
  1571. var
  1572. F: TFile;
  1573. N: Cardinal;
  1574. begin
  1575. try
  1576. F := TFileRedir.Create(ScriptFuncDisableFsRedir, FileName, fdOpenExisting, faRead, fsRead);
  1577. try
  1578. N := F.CappedSize;
  1579. SetLength(S, N);
  1580. F.ReadBuffer(S[1], N);
  1581. finally
  1582. F.Free;
  1583. end;
  1584. Result := True;
  1585. except
  1586. Result := False;
  1587. end;
  1588. end;
  1589. function LoadStringsFromFile(const FileName: String; Arr: PPSVariantIFC): Boolean;
  1590. var
  1591. F: TTextFileReader;
  1592. I: Integer;
  1593. S: String;
  1594. begin
  1595. try
  1596. F := TTextFileReaderRedir.Create(ScriptFuncDisableFsRedir, FileName, fdOpenExisting, faRead, fsRead);
  1597. try
  1598. PSDynArraySetLength(Pointer(Arr.Dta^), Arr.aType, 0);
  1599. I := 0;
  1600. while not F.Eof do begin
  1601. S := F.ReadLine;
  1602. PSDynArraySetLength(Pointer(Arr.Dta^), Arr.aType, I+1);
  1603. VNSetString(PSGetArrayField(Arr^, I), S);
  1604. Inc(I);
  1605. end;
  1606. finally
  1607. F.Free;
  1608. end;
  1609. Result := True;
  1610. except
  1611. Result := False;
  1612. end;
  1613. end;
  1614. function SaveStringToFile(const FileName: String; const S: AnsiString; Append: Boolean): Boolean;
  1615. var
  1616. F: TFile;
  1617. begin
  1618. try
  1619. if Append then
  1620. F := TFileRedir.Create(ScriptFuncDisableFsRedir, FileName, fdOpenAlways, faWrite, fsNone)
  1621. else
  1622. F := TFileRedir.Create(ScriptFuncDisableFsRedir, FileName, fdCreateAlways, faWrite, fsNone);
  1623. try
  1624. F.SeekToEnd;
  1625. F.WriteAnsiString(S);
  1626. finally
  1627. F.Free;
  1628. end;
  1629. Result := True;
  1630. except
  1631. Result := False;
  1632. end;
  1633. end;
  1634. function SaveStringsToFile(const FileName: String; const Arr: PPSVariantIFC; Append, UTF8, UTF8NoPreamble: Boolean): Boolean;
  1635. var
  1636. F: TTextFileWriter;
  1637. I, N: Integer;
  1638. S: String;
  1639. begin
  1640. try
  1641. if Append then
  1642. F := TTextFileWriterRedir.Create(ScriptFuncDisableFsRedir, FileName, fdOpenAlways, faWrite, fsNone)
  1643. else
  1644. F := TTextFileWriterRedir.Create(ScriptFuncDisableFsRedir, FileName, fdCreateAlways, faWrite, fsNone);
  1645. try
  1646. if UTF8 and UTF8NoPreamble then
  1647. F.UTF8NoPreamble := UTF8NoPreamble;
  1648. N := PSDynArrayGetLength(Pointer(Arr.Dta^), Arr.aType);
  1649. for I := 0 to N-1 do begin
  1650. S := VNGetString(PSGetArrayField(Arr^, I));
  1651. if not UTF8 then
  1652. F.WriteAnsiLine(AnsiString(S))
  1653. else
  1654. F.WriteLine(S);
  1655. end;
  1656. finally
  1657. F.Free;
  1658. end;
  1659. Result := True;
  1660. except
  1661. Result := False;
  1662. end;
  1663. end;
  1664. function CreateCallback(P: PPSVariantProcPtr): LongWord;
  1665. var
  1666. ProcRec: TPSInternalProcRec;
  1667. Method: TMethod;
  1668. Inliner: TASMInline;
  1669. ParamCount, SwapFirst, SwapLast: Integer;
  1670. S: tbtstring;
  1671. begin
  1672. { ProcNo 0 means nil was passed by the script }
  1673. if P.ProcNo = 0 then
  1674. InternalError('Invalid Method value');
  1675. { Calculate parameter count of our proc, will need this later. }
  1676. ProcRec := Caller.GetProcNo(P.ProcNo) as TPSInternalProcRec;
  1677. S := ProcRec.ExportDecl;
  1678. GRFW(S);
  1679. ParamCount := 0;
  1680. while S <> '' do begin
  1681. Inc(ParamCount);
  1682. GRFW(S);
  1683. end;
  1684. { Turn our proc into a callable TMethod - its Code will point to
  1685. ROPS' MyAllMethodsHandler and its Data to a record identifying our proc.
  1686. When called, MyAllMethodsHandler will use the record to call our proc. }
  1687. Method := MkMethod(Caller, P.ProcNo);
  1688. { Wrap our TMethod with a dynamically generated stdcall callback which will
  1689. do two things:
  1690. -Remember the Data pointer which MyAllMethodsHandler needs.
  1691. -Handle the calling convention mismatch.
  1692. Based on InnoCallback by Sherlock Software, see
  1693. http://www.sherlocksoftware.org/page.php?id=54 and
  1694. https://github.com/thenickdude/InnoCallback. }
  1695. Inliner := TASMInline.create;
  1696. try
  1697. Inliner.Pop(EAX); //get the retptr off the stack
  1698. SwapFirst := 2;
  1699. SwapLast := ParamCount-1;
  1700. //Reverse the order of parameters from param3 onwards in the stack
  1701. while SwapLast > SwapFirst do begin
  1702. Inliner.Mov(ECX, Inliner.Addr(ESP, SwapFirst * 4)); //load the first item of the pair
  1703. Inliner.Mov(EDX, Inliner.Addr(ESP, SwapLast * 4)); //load the last item of the pair
  1704. Inliner.Mov(Inliner.Addr(ESP, SwapFirst * 4), EDX);
  1705. Inliner.Mov(Inliner.Addr(ESP, SwapLast * 4), ECX);
  1706. Inc(SwapFirst);
  1707. Dec(SwapLast);
  1708. end;
  1709. if ParamCount >= 1 then
  1710. Inliner.Pop(EDX); //load param1
  1711. if ParamCount >= 2 then
  1712. Inliner.Pop(ECX); //load param2
  1713. Inliner.Push(EAX); //put the retptr back onto the stack
  1714. Inliner.Mov(EAX, LongWord(Method.Data)); //Load the self ptr
  1715. Inliner.Jmp(Method.Code); //jump to the wrapped proc
  1716. SetLength(ASMInliners, Length(ASMInliners) + 1);
  1717. ASMInliners[High(ASMInliners)] := Inliner.SaveAsMemory;
  1718. Result := LongWord(ASMInliners[High(ASMInliners)]);
  1719. finally
  1720. Inliner.Free;
  1721. end;
  1722. end;
  1723. var
  1724. PStart: Cardinal;
  1725. TypeEntry: PSetupTypeEntry;
  1726. StringList: TStringList;
  1727. S: String;
  1728. AnsiS: AnsiString;
  1729. Arr: TPSVariantIFC;
  1730. ErrorCode: Cardinal;
  1731. N, I: Integer;
  1732. AscendingTrySizes: array of Integer;
  1733. begin
  1734. PStart := Stack.Count-1;
  1735. Result := True;
  1736. if Proc.Name = 'BRINGTOFRONTANDRESTORE' then begin
  1737. Application.BringToFront();
  1738. Application.Restore();
  1739. end else if Proc.Name = 'WIZARDDIRVALUE' then begin
  1740. if IsUninstaller then
  1741. NoUninstallFuncError(Proc.Name);
  1742. Stack.SetString(PStart, RemoveBackslashUnlessRoot(GetWizardForm.DirEdit.Text));
  1743. end else if Proc.Name = 'WIZARDGROUPVALUE' then begin
  1744. if IsUninstaller then
  1745. NoUninstallFuncError(Proc.Name);
  1746. Stack.SetString(PStart, RemoveBackslashUnlessRoot(GetWizardForm.GroupEdit.Text));
  1747. end else if Proc.Name = 'WIZARDNOICONS' then begin
  1748. if IsUninstaller then
  1749. NoUninstallFuncError(Proc.Name);
  1750. Stack.SetBool(PStart, GetWizardForm.NoIconsCheck.Checked);
  1751. end else if Proc.Name = 'WIZARDSETUPTYPE' then begin
  1752. if IsUninstaller then
  1753. NoUninstallFuncError(Proc.Name);
  1754. TypeEntry := GetWizardForm.GetSetupType();
  1755. if TypeEntry <> nil then begin
  1756. if Stack.GetBool(PStart-1) then
  1757. Stack.SetString(PStart, TypeEntry.Description)
  1758. else
  1759. Stack.SetString(PStart, TypeEntry.Name);
  1760. end
  1761. else
  1762. Stack.SetString(PStart, '');
  1763. end else if (Proc.Name = 'WIZARDSELECTEDCOMPONENTS') or (Proc.Name = 'WIZARDSELECTEDTASKS') then begin
  1764. if IsUninstaller then
  1765. NoUninstallFuncError(Proc.Name);
  1766. StringList := TStringList.Create();
  1767. try
  1768. if Proc.Name = 'WIZARDSELECTEDCOMPONENTS' then
  1769. GetWizardForm.GetSelectedComponents(StringList, Stack.GetBool(PStart-1), False)
  1770. else
  1771. GetWizardForm.GetSelectedTasks(StringList, Stack.GetBool(PStart-1), False, False);
  1772. Stack.SetString(PStart, StringsToCommaString(StringList));
  1773. finally
  1774. StringList.Free();
  1775. end;
  1776. end else if (Proc.Name = 'WIZARDSELECTCOMPONENTS') or (Proc.Name = 'WIZARDSELECTTASKS') then begin
  1777. if IsUninstaller then
  1778. NoUninstallFuncError(Proc.Name);
  1779. StringList := TStringList.Create();
  1780. try
  1781. S := Stack.GetString(PStart);
  1782. StringChange(S, '/', '\');
  1783. SetStringsFromCommaString(StringList, S);
  1784. if Proc.Name = 'WIZARDSELECTCOMPONENTS' then
  1785. GetWizardForm.SelectComponents(StringList)
  1786. else
  1787. GetWizardForm.SelectTasks(StringList);
  1788. finally
  1789. StringList.Free();
  1790. end;
  1791. end else if Proc.Name = 'WIZARDSILENT' then begin
  1792. if IsUninstaller then
  1793. NoUninstallFuncError(Proc.Name);
  1794. Stack.SetBool(PStart, InstallMode <> imNormal);
  1795. end else if Proc.Name = 'ISUNINSTALLER' then begin
  1796. Stack.SetBool(PStart, IsUninstaller);
  1797. end else if Proc.Name = 'UNINSTALLSILENT' then begin
  1798. if not IsUninstaller then
  1799. NoSetupFuncError(Proc.Name);
  1800. Stack.SetBool(PStart, UninstallSilent);
  1801. end else if Proc.Name = 'CURRENTFILENAME' then begin
  1802. if IsUninstaller then
  1803. NoUninstallFuncError(Proc.Name);
  1804. if CheckOrInstallCurrentFilename <> '' then
  1805. Stack.SetString(PStart, CheckOrInstallCurrentFilename)
  1806. else
  1807. InternalError('An attempt was made to call the "CurrentFilename" function from outside a "Check", "BeforeInstall" or "AfterInstall" event function belonging to a "[Files]" entry');
  1808. end else if Proc.Name = 'CURRENTSOURCEFILENAME' then begin
  1809. if IsUninstaller then
  1810. NoUninstallFuncError(Proc.Name);
  1811. if CheckOrInstallCurrentSourceFilename <> '' then
  1812. Stack.SetString(PStart, CheckOrInstallCurrentSourceFilename)
  1813. else
  1814. InternalError('An attempt was made to call the "CurrentSourceFilename" function from outside a "Check", "BeforeInstall" or "AfterInstall" event function belonging to a "[Files]" entry with flag "external"');
  1815. end else if Proc.Name = 'CASTSTRINGTOINTEGER' then begin
  1816. Stack.SetInt(PStart, Integer(PChar(Stack.GetString(PStart-1))));
  1817. end else if Proc.Name = 'CASTINTEGERTOSTRING' then begin
  1818. Stack.SetString(PStart, String(PChar(Stack.GetInt(PStart-1))));
  1819. end else if Proc.Name = 'ABORT' then begin
  1820. Abort;
  1821. end else if Proc.Name = 'GETEXCEPTIONMESSAGE' then begin
  1822. Stack.SetString(PStart, GetExceptionMessage);
  1823. end else if Proc.Name = 'RAISEEXCEPTION' then begin
  1824. raise Exception.Create(Stack.GetString(PStart));
  1825. end else if Proc.Name = 'SHOWEXCEPTIONMESSAGE' then begin
  1826. TMainForm.ShowExceptionMsg(AddPeriod(GetExceptionMessage));
  1827. end else if Proc.Name = 'TERMINATED' then begin
  1828. Stack.SetBool(PStart, Application.Terminated);
  1829. end else if Proc.Name = 'GETPREVIOUSDATA' then begin
  1830. if IsUninstaller then
  1831. Stack.SetString(PStart, GetCodePreviousData(UninstallExpandedAppId, Stack.GetString(PStart-1), Stack.GetString(PStart-2)))
  1832. else
  1833. Stack.SetString(PStart, GetCodePreviousData(ExpandConst(SetupHeader.AppId), Stack.GetString(PStart-1), Stack.GetString(PStart-2)));
  1834. end else if Proc.Name = 'SETPREVIOUSDATA' then begin
  1835. Stack.SetBool(PStart, SetCodePreviousData(Stack.GetInt(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3)));
  1836. end else if Proc.Name = 'LOADSTRINGFROMFILE' then begin
  1837. AnsiS := StackGetAnsiString(Stack, PStart-2);
  1838. Stack.SetBool(PStart, LoadStringFromFile(Stack.GetString(PStart-1), AnsiS));
  1839. StackSetAnsiString(Stack, PStart-2, AnsiS);
  1840. end else if Proc.Name = 'LOADSTRINGSFROMFILE' then begin
  1841. Arr := NewTPSVariantIFC(Stack[PStart-2], True);
  1842. Stack.SetBool(PStart, LoadStringsFromFile(Stack.GetString(PStart-1), @Arr));
  1843. end else if Proc.Name = 'SAVESTRINGTOFILE' then begin
  1844. Stack.SetBool(PStart, SaveStringToFile(Stack.GetString(PStart-1), StackGetAnsiString(Stack, PStart-2), Stack.GetBool(PStart-3)));
  1845. end else if Proc.Name = 'SAVESTRINGSTOFILE' then begin
  1846. Arr := NewTPSVariantIFC(Stack[PStart-2], True);
  1847. Stack.SetBool(PStart, SaveStringsToFile(Stack.GetString(PStart-1), @Arr, Stack.GetBool(PStart-3), False, False));
  1848. end else if Proc.Name = 'SAVESTRINGSTOUTF8FILE' then begin
  1849. Arr := NewTPSVariantIFC(Stack[PStart-2], True);
  1850. Stack.SetBool(PStart, SaveStringsToFile(Stack.GetString(PStart-1), @Arr, Stack.GetBool(PStart-3), True, False));
  1851. end else if Proc.Name = 'SAVESTRINGSTOUTF8FILENOPREAMBLE' then begin
  1852. Arr := NewTPSVariantIFC(Stack[PStart-2], True);
  1853. Stack.SetBool(PStart, SaveStringsToFile(Stack.GetString(PStart-1), @Arr, Stack.GetBool(PStart-3), True, True));
  1854. end else if Proc.Name = 'ENABLEFSREDIRECTION' then begin
  1855. Stack.SetBool(PStart, not ScriptFuncDisableFsRedir);
  1856. if Stack.GetBool(PStart-1) then
  1857. ScriptFuncDisableFsRedir := False
  1858. else begin
  1859. if not IsWin64 then
  1860. InternalError('Cannot disable FS redirection on this version of Windows');
  1861. ScriptFuncDisableFsRedir := True;
  1862. end;
  1863. end else if Proc.Name = 'GETUNINSTALLPROGRESSFORM' then begin
  1864. Stack.SetClass(PStart, GetUninstallProgressForm);
  1865. end else if Proc.Name = 'CREATECALLBACK' then begin
  1866. Stack.SetInt(PStart, CreateCallback(Stack.Items[PStart-1]));
  1867. end else if Proc.Name = 'ISDOTNETINSTALLED' then begin
  1868. Stack.SetBool(PStart, IsDotNetInstalled(InstallDefaultRegView, TDotNetVersion(Stack.GetInt(PStart-1)), Stack.GetInt(PStart-2)));
  1869. end else if Proc.Name = 'ISMSIPRODUCTINSTALLED' then begin
  1870. Stack.SetBool(PStart, IsMsiProductInstalled(Stack.GetString(PStart-1), Stack.GetInt64(PStart-2), ErrorCode));
  1871. if ErrorCode <> 0 then
  1872. raise Exception.Create(Win32ErrorString(ErrorCode));
  1873. end else if Proc.Name = 'INITIALIZEBITMAPIMAGEFROMICON' then begin
  1874. Arr := NewTPSVariantIFC(Stack[PStart-4], True);
  1875. N := PSDynArrayGetLength(Pointer(Arr.Dta^), Arr.aType);
  1876. SetLength(AscendingTrySizes, N);
  1877. for I := 0 to N-1 do
  1878. AscendingTrySizes[I] := VNGetInt(PSGetArrayField(Arr, I));
  1879. Stack.SetBool(PStart, TBitmapImage(Stack.GetClass(PStart-1)).InitializeFromIcon(0, PChar(Stack.GetString(PStart-2)), Stack.GetInt(PStart-3), AscendingTrySizes));
  1880. end else
  1881. Result := False;
  1882. end;
  1883. {---}
  1884. procedure ScriptFuncLibraryRegister_R(ScriptInterpreter: TPSExec);
  1885. function ExtractName(const S: String): String;
  1886. var
  1887. P: Integer;
  1888. begin
  1889. Result := S;
  1890. if CompareText(Copy(Result, 1, Length('function')), 'function') = 0 then
  1891. Delete(Result, 1, Length('function'))
  1892. else if CompareText(Copy(Result, 1, Length('procedure')), 'procedure') = 0 then
  1893. Delete(Result, 1, Length('procedure'));
  1894. P := Pos('(', Result);
  1895. if P = 0 then
  1896. P := Pos(':', Result);
  1897. if P = 0 then
  1898. P := Pos(';', Result);
  1899. Delete(Result, P, Maxint);
  1900. Result := Trim(Result);
  1901. end;
  1902. procedure RegisterFunctionTable(const FunctionTable: array of AnsiString;
  1903. const ProcPtr: TPSProcPtr);
  1904. var
  1905. I: Integer;
  1906. begin
  1907. for I := Low(FunctionTable) to High(FunctionTable) do
  1908. ScriptInterpreter.RegisterFunctionName(AnsiString(ExtractName(String(FunctionTable[I]))),
  1909. ProcPtr, nil, nil);
  1910. end;
  1911. begin
  1912. RegisterFunctionTable(ScriptDlgTable, @ScriptDlgProc);
  1913. RegisterFunctionTable(NewDiskTable, @NewDiskProc);
  1914. RegisterFunctionTable(BrowseFuncTable, @BrowseFuncProc);
  1915. RegisterFunctionTable(CmnFuncTable, @CmnFuncProc);
  1916. RegisterFunctionTable(CmnFunc2Table, @CmnFunc2Proc);
  1917. RegisterFunctionTable(InstallTable, @InstallProc);
  1918. RegisterFunctionTable(InstFuncTable, @InstFuncProc);
  1919. RegisterFunctionTable(InstFnc2Table, @InstFnc2Proc);
  1920. RegisterFunctionTable(MainTable, @MainProc);
  1921. RegisterFunctionTable(MsgsTable, @MsgsProc);
  1922. RegisterFunctionTable(SystemTable, @SystemProc);
  1923. RegisterFunctionTable(SysUtilsTable, @SysUtilsProc);
  1924. RegisterFunctionTable(VerInfoTable, @VerInfoProc);
  1925. RegisterFunctionTable(WindowsTable, @WindowsProc);
  1926. RegisterFunctionTable(Ole2Table, @Ole2Proc);
  1927. RegisterFunctionTable(LoggingTable, @LoggingProc);
  1928. RegisterFunctionTable(OtherTable, @OtherProc);
  1929. ScriptInterpreter.RegisterDelphiFunction(@_FindFirst, 'FindFirst', cdRegister);
  1930. ScriptInterpreter.RegisterDelphiFunction(@_FindNext, 'FindNext', cdRegister);
  1931. ScriptInterpreter.RegisterDelphiFunction(@_FindClose, 'FindClose', cdRegister);
  1932. ScriptInterpreter.RegisterDelphiFunction(@_FmtMessage, 'FmtMessage', cdRegister);
  1933. ScriptInterpreter.RegisterDelphiFunction(@Format, 'Format', cdRegister);
  1934. ScriptInterpreter.RegisterDelphiFunction(@_GetWindowsVersionEx, 'GetWindowsVersionEx', cdRegister);
  1935. end;
  1936. procedure FreeASMInliners;
  1937. var
  1938. I: Integer;
  1939. begin
  1940. for I := 0 to High(ASMInliners) do
  1941. FreeMem(ASMInliners[I]);
  1942. SetLength(ASMInliners, 0);
  1943. end;
  1944. initialization
  1945. finalization
  1946. FreeASMInliners;
  1947. end.