ScriptFunc_R.pas 87 KB

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