You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Setup.dpr 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. {*
  2. * This application launches the dmdirc java-based installer.
  3. *
  4. * DMDirc - Open Source IRC Client
  5. * Copyright (c) 2006-2008 Chris Smith, Shane Mc Cormack, Gregory Holmes
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. *}
  25. program Setup;
  26. {$MODE Delphi}
  27. // Use this instead of {$APPTYPE XXX}
  28. // APP_XXX is the same as {$APPTYPE XXX}
  29. // Defaults to console
  30. // This is a work-around for a bug in FPC Cross Compiling to windows in delphi
  31. // mode (IsConsole is always true)
  32. {$DEFINE APP_GUI}
  33. // This block actually does the work for the above work-around
  34. {$IFDEF APP_GUI}
  35. {$APPTYPE GUI}
  36. {$ELSE}
  37. {$IFDEF APP_FS}
  38. {$APPTYPE FS}
  39. {$ELSE}
  40. {$IFDEF APP_TOOL}
  41. {$DEFINE APP_CONSOLE}
  42. {$APPTYPE TOOL}
  43. {$ELSE}
  44. {$DEFINE APP_CONSOLE}
  45. {$APPTYPE CONSOLE}
  46. {$ENDIF}
  47. {$ENDIF}
  48. {$ENDIF}
  49. // If this is defined, lazarus-specific code (gui progress bar) will be compiled
  50. // without it, a wget console window will be used for progress instead.
  51. // This is automatically set by the build script when lazarus is detected in /usr/lib/lazarus
  52. // You can forcibly define or undefine it here.
  53. // {$DEFINE LAZARUS}
  54. // {$UNDEF LAZARUS}
  55. uses
  56. {$IFDEF LAZARUS}Interfaces, Forms, ComCtrls, Buttons, Messages, Controls, StdCtrls,{$ENDIF}
  57. Windows, SysUtils, classes, registry, strutils;
  58. {$IFDEF LAZARUS}
  59. type
  60. TProgressForm = class(TForm)
  61. ProgressBar: TProgressBar;
  62. CancelButton: TButton;
  63. CaptionLabel: TLabel;
  64. constructor Create(AOwner: TComponent); override;
  65. private
  66. procedure onButtonClick(Sender: TObject);
  67. public
  68. procedure setProgress(value: integer);
  69. end;
  70. {$ENDIF}
  71. const
  72. {$I SetupConsts.inc}
  73. // This is also part of the above work-around.
  74. {$IFDEF APP_CONSOLE}
  75. IsConsole: boolean = true;
  76. {$ELSE}
  77. IsConsole: boolean = false;
  78. {$ENDIF}
  79. var
  80. {$IFDEF LAZARUS} form: TProgressForm; {$ENDIF}
  81. terminateDownload: boolean = false;
  82. {$IFDEF LAZARUS}
  83. constructor TProgressForm.Create(AOwner: TComponent);
  84. begin
  85. inherited;
  86. self.Width := 500;
  87. self.Height := 80;
  88. self.Position := poScreenCenter;
  89. self.BorderStyle := bsSingle;
  90. CaptionLabel := TLabel.create(self);
  91. CaptionLabel.Parent := self;
  92. CaptionLabel.Width := 490;
  93. CaptionLabel.Height := 15;
  94. CaptionLabel.Top := 5;
  95. CaptionLabel.Left := 5;
  96. CaptionLabel.Caption := 'Downloading JRE - 0%';
  97. ProgressBar := TProgressBar.create(self);
  98. ProgressBar.Parent := self;
  99. ProgressBar.Width := 490;
  100. ProgressBar.Height := 20;
  101. ProgressBar.Top := CaptionLabel.Top+CaptionLabel.Height+5;
  102. ProgressBar.Left := 5;
  103. ProgressBar.Visible := true;
  104. ProgressBar.Max := 100;
  105. ProgressBar.Position := 0;
  106. CancelButton := TButton.create(self);
  107. CancelButton.Parent := self;
  108. CancelButton.Width := 80;
  109. CancelButton.Height := 25;
  110. CancelButton.Top := ProgressBar.Top+ProgressBar.Height+5;
  111. CancelButton.Left := Round((self.Width/2) - (CancelButton.Width/2));
  112. CancelButton.Visible := true;
  113. CancelButton.Caption := 'Cancel';
  114. CancelButton.onClick := self.onButtonClick;
  115. self.Caption := pChar('DMDirc Setup - '+CaptionLabel.Caption);;
  116. Application.Title := self.Caption;
  117. end;
  118. procedure TProgressForm.onButtonClick(Sender: TObject);
  119. begin
  120. terminateDownload := true;
  121. end;
  122. procedure TProgressForm.setProgress(value: integer);
  123. begin
  124. ProgressBar.Position := value;
  125. CaptionLabel.Caption := pchar('Downloading JRE - '+inttostr(value)+'%');
  126. self.Caption := pChar('DMDirc Setup - '+CaptionLabel.Caption);;
  127. Application.Title := self.Caption;
  128. end;
  129. {$ENDIF}
  130. function askQuestion(Question: String): boolean;
  131. begin
  132. Result := MessageBox(0, PChar(Question), 'DMDirc Setup', MB_YESNO or MB_ICONQUESTION) = IDYES;
  133. end;
  134. procedure showError(ErrorMessage: String; addFooter: boolean = true);
  135. begin
  136. if IsConsole then begin
  137. writeln('');
  138. writeln('-----------------------------------------------------------------------');
  139. writeln('Sorry, setup is unable to continue.!');
  140. writeln('-----------------------------------------------------------------------');
  141. writeln('Reason:');
  142. writeln('----------');
  143. writeln(ErrorMessage);
  144. if addFooter then begin
  145. writeln('-----------------------------------------------------------------------');
  146. writeln('If you feel this is incorrect, or you require some further assistance,');
  147. writeln('please feel free to contact us.');
  148. end;
  149. writeln('-----------------------------------------------------------------------');
  150. readln();
  151. end
  152. else begin
  153. if addFooter then begin
  154. ErrorMessage := ErrorMessage+#13#10;
  155. ErrorMessage := ErrorMessage+#13#10+'If you feel this is incorrect, or you require some further assistance,';
  156. ErrorMessage := ErrorMessage+#13#10+'please feel free to contact us.';
  157. end;
  158. MessageBox(0, PChar(ErrorMessage), 'Sorry, setup is unable to continue', MB_OK + MB_ICONSTOP);
  159. end;
  160. end;
  161. procedure showmessage(message: String);
  162. begin
  163. if IsConsole then begin
  164. writeln('');
  165. writeln('-----------------------------------------------------------------------');
  166. writeln('Information:!');
  167. writeln('-----------------------------------------------------------------------');
  168. writeln(message);
  169. writeln('-----------------------------------------------------------------------');
  170. readln();
  171. end
  172. else begin
  173. MessageBox(0, PChar(message), 'DMDirc Setup', MB_OK + MB_ICONINFORMATION);
  174. end;
  175. end;
  176. // Run an application and don't wait for it to finish.
  177. function Launch(sProgramToRun: String; hide: boolean = false): TProcessInformation;
  178. var
  179. StartupInfo: TStartupInfo;
  180. begin
  181. FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
  182. with StartupInfo do begin
  183. cb := SizeOf(TStartupInfo);
  184. dwFlags := STARTF_USESHOWWINDOW;
  185. if hide then wShowWindow := SW_HIDE
  186. else wShowWindow := SW_SHOWNORMAL;
  187. end;
  188. CreateProcess(nil, PChar(sProgramToRun), nil, nil, False, NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, Result);
  189. end;
  190. // Run an application and wait for it to finish.
  191. function ExecAndWait(sProgramToRun: String; hide: boolean = false): Longword;
  192. var
  193. ProcessInfo: TProcessInformation;
  194. begin
  195. ProcessInfo := Launch(sProgramToRun, hide);
  196. getExitCodeProcess(ProcessInfo.hProcess, Result);
  197. while Result=STILL_ACTIVE do begin
  198. sleep(1000);
  199. GetExitCodeProcess(ProcessInfo.hProcess, Result);
  200. end;
  201. end;
  202. procedure dowriteln(line: String);
  203. begin
  204. if IsConsole then writeln(line);
  205. end;
  206. procedure dowrite(line: String);
  207. begin
  208. if IsConsole then write(line);
  209. end;
  210. function GetFileSizeByName(name: String): Integer;
  211. var
  212. hand: THandle;
  213. begin
  214. Result := 0;
  215. if FileExists(name) then begin
  216. try
  217. hand := CreateFile(PChar(name), GENERIC_READ, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  218. Result := GetFileSize(hand, nil);
  219. finally
  220. try
  221. CloseHandle(hand);
  222. except
  223. Result := -1;
  224. end;
  225. end;
  226. end;
  227. end;
  228. function downloadJRE(message: String = 'Would you like to download the java JRE?'): boolean;
  229. var
  230. ProcessInfo: TProcessInformation;
  231. processResult: Longword;
  232. url: String;
  233. dir: String;
  234. line: String;
  235. f: TextFile;
  236. bits: TStringList;
  237. match: boolean;
  238. {$IFDEF LAZARUS}
  239. wantedsize: double;
  240. currentsize: double;
  241. {$ENDIF}
  242. begin
  243. dir := IncludeTrailingPathDelimiter(ExtractFileDir(paramstr(0)));
  244. url := 'http://www.dmdirc.com/getjava/windows/all';
  245. Result := false;
  246. ExecAndWait('wget.exe -o '+dir+'wgetoutput --spider '+url, true);
  247. AssignFile(f, dir+'wgetoutput');
  248. Reset(f);
  249. line := '';
  250. match := false;
  251. while not Eof(f) do begin
  252. ReadLn(f, line);
  253. match := IsWild(line,'Length:*',True);
  254. if match then break;
  255. end;
  256. if match then begin
  257. bits := TStringList.create;
  258. try
  259. bits.Clear;
  260. bits.Delimiter := ' ';
  261. bits.DelimitedText := line;
  262. {$IFDEF LAZARUS}
  263. try
  264. wantedsize := strtoint(StringReplace(bits[1], ',', '', [rfReplaceAll]))
  265. except
  266. wantedsize := 0;
  267. end;
  268. {$ENDIF}
  269. if askQuestion(message+' (Download Size: '+AnsiMidStr(bits[2], 2, length(bits[2])-2)+')') then begin
  270. {$IFDEF LAZARUS}
  271. ProcessInfo := Launch('wget.exe '+url+' -O jre.exe', true);
  272. form.show();
  273. if wantedsize <= 0 then begin
  274. form.setProgress(50);
  275. end;
  276. {$ELSE}
  277. ProcessInfo := Launch('wget.exe '+url+' -O jre.exe');
  278. {$ENDIF}
  279. getExitCodeProcess(ProcessInfo.hProcess, processResult);
  280. while (processResult=STILL_ACTIVE) and (not terminateDownload) do begin
  281. // Update progress bar.
  282. {$IFDEF LAZARUS}
  283. if wantedsize > 0 then begin
  284. currentsize := GetFileSizeByName('jre.exe');
  285. if (currentsize > 0) then form.setProgress(Round((currentsize/wantedsize)*100));
  286. end;
  287. Application.ProcessMessages;
  288. {$ENDIF}
  289. sleep(10);
  290. GetExitCodeProcess(ProcessInfo.hProcess, processResult);
  291. end;
  292. {$IFDEF LAZARUS}form.hide();{$ENDIF}
  293. if (terminateDownload) then begin
  294. Result := false;
  295. {$IFDEF LAZARUS}
  296. TerminateProcess(ProcessInfo.hProcess, 0);
  297. showError('JRE Download was aborted', false);
  298. {$ENDIF}
  299. end
  300. else Result := processResult = 0;
  301. if not Result then showError('JRE Download Failed', false);
  302. end;
  303. finally
  304. bits.free;
  305. end;
  306. end;
  307. end;
  308. function installJRE(isUpgrade: boolean): boolean;
  309. var
  310. question: String;
  311. needDownload: boolean;
  312. canContinue: boolean;
  313. begin
  314. Result := false;
  315. needDownload := not FileExists(IncludeTrailingPathDelimiter(ExtractFileDir(paramstr(0)))+'jre.exe');
  316. if needDownload then begin
  317. if not isUpgrade then question := 'Java was not detected on your machine. Would you like to download and install it now?'
  318. else question := 'The version of java detected on your machine is not compatible with DMDirc. Would you like to download and install a compatible version now?';
  319. end
  320. else begin
  321. if not isUpgrade then question := 'Java was not detected on your machine. Would you like to install it now?'
  322. else question := 'The version of java detected on your machine is not compatible with DMDirc. Would you like to install a compatible version now?';
  323. end;
  324. canContinue := true;
  325. if (needDownload) then begin
  326. canContinue := downloadJRE(question);
  327. end;
  328. if canContinue then begin
  329. // Final result of this function is the return value of installing java.
  330. if needDownload or askQuestion(question) then begin
  331. showmessage('The Java installer will now run. Please follow the instructions given.'+#13#10+'The DMDirc installation will continue afterwards.');
  332. Result := (ExecAndWait('jre.exe') = 0);
  333. end;
  334. end
  335. end;
  336. var
  337. errorMessage: String;
  338. javaCommand: String = 'javaw.exe';
  339. params: String = '';
  340. dir: String = '';
  341. Reg: TRegistry;
  342. begin
  343. {$IFDEF LAZARUS}
  344. Application.Initialize;
  345. Application.CreateForm(TProgressForm, form);
  346. {$ENDIF}
  347. if IsConsole then begin
  348. writeln('-----------------------------------------------------------------------');
  349. writeln('Welcome to the DMDirc installer.');
  350. writeln('-----------------------------------------------------------------------');
  351. writeln('This will install DMDirc on your computer.');
  352. writeln('');
  353. writeln('Please wait whilst the GUI part of the installer loads...');
  354. writeln('-----------------------------------------------------------------------');
  355. // end
  356. // else begin
  357. // errorMessage := 'This will install DMDirc on your computer, please click OK to continue, or Cancel to abort.';
  358. // if (MessageBox(0, PChar(errorMessage), 'DMDirc Installer', MB_OKCANCEL + MB_ICONINFORMATION) <> IDOK) then begin
  359. // exit;
  360. // end;
  361. end;
  362. errorMessage := '';
  363. dowrite('Checking for DMDirc.jar.. ');
  364. if FileExists('DMDirc.jar') then begin
  365. dowriteln('Success!');
  366. dowrite('Checking for JVM.. ');
  367. if (ExecAndWait(javaCommand+' -version') <> 0) then begin
  368. dowriteln('Failed!');
  369. if not installJRE(false) then begin
  370. showError('Sorry, DMDirc setup can not continue without java', false);
  371. exit;
  372. end;
  373. end
  374. else begin
  375. if IsConsole then begin
  376. writeln('Success!');
  377. write('Starting installer.. ');
  378. javaCommand := 'java.exe';
  379. end;
  380. end;
  381. Reg := TRegistry.Create;
  382. Reg.RootKey := HKEY_LOCAL_MACHINE;
  383. if Reg.OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DMDirc', false) then begin
  384. dir := Reg.ReadString('InstallDir');
  385. if (dir <> '') then begin
  386. params := params+' --directory "'+dir+'"';
  387. end;
  388. end;
  389. Reg.CloseKey;
  390. Reg.Free;
  391. if (ReleaseNumber <> '') then begin
  392. params := params+' --release '+ReleaseNumber;
  393. end;
  394. if (ExecAndWait(javaCommand+' -cp DMDirc.jar com.dmdirc.installer.Main '+params) <> 0) then begin
  395. dowriteln('Failed!');
  396. if not installJRE(true) then begin
  397. showError('Sorry, DMDirc setup can not continue without an updated version of java', false);
  398. exit;
  399. end
  400. else begin
  401. // Try again now that java is installed.
  402. ExecAndWait(javaCommand+' -cp DMDirc.jar com.dmdirc.installer.Main '+params);
  403. end;
  404. end;
  405. end
  406. else begin
  407. dowriteln('Failed!');
  408. errorMessage := errorMessage+'DMDirc.jar was not found.';
  409. errorMessage := errorMessage+#13#10;
  410. errorMessage := errorMessage+#13#10+'This is likely because of a corrupt installer build.';
  411. errorMessage := errorMessage+#13#10+'Please check http://www.dmdirc.com/ for an updated build.';
  412. showError(errorMessage);
  413. end;
  414. if IsConsole then begin
  415. writeln('');
  416. writeln('-----------------------------------------------------------------------');
  417. writeln('Installation Completed. Thank you for choosing DMDirc');
  418. writeln('-----------------------------------------------------------------------');
  419. end;
  420. end.