2424
2525#include " AutoUpdater.h"
2626#include " CoreServices.h"
27+ #ifdef _WIN32
28+ #include < windows.h>
29+ #include < shellapi.h>
30+ #endif
2731
2832// ==============================================================================
2933LatestVersionCheckerAndUpdater::LatestVersionCheckerAndUpdater ()
@@ -141,16 +145,16 @@ void LatestVersionCheckerAndUpdater::run()
141145 #endif
142146 }();
143147
144- #if JUCE_WINDOWS
145148 String requiredFilename (" open-ephys-" + versionString + " -" + osString + " .zip" );
149+
150+ #if JUCE_WINDOWS
146151 File exeDir = File::getSpecialLocation (File::SpecialLocationType::currentExecutableFile).getParentDirectory ();
147152 if (exeDir.findChildFiles (File::findFiles, false , " unins*" ).size () > 0 )
148153 {
149154 requiredFilename = " Install-Open-Ephys-GUI-" + versionString + " .exe" ;
150155 }
151- #elif
152- String requiredFilename (" open-ephys-" + versionString + " -" + osString + " .zip" );
153156#endif
157+
154158 for (auto & asset : parsedAssets)
155159 {
156160 if (asset.name == requiredFilename)
@@ -288,7 +292,7 @@ class UpdateDialog : public Component
288292 TextButton chooseButton { " Download" }, cancelButton { " Cancel" };
289293 ToggleButton dontAskAgainButton { " Don't ask again" };
290294 std::unique_ptr<Drawable> juceIcon;
291- Rectangle<int > juceIconBounds { 10 , 10 , 64 , 64 };
295+ juce:: Rectangle<int > juceIconBounds { 10 , 10 , 64 , 64 };
292296
293297 DialogWindow* parentWindow = nullptr ;
294298};
@@ -305,7 +309,9 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Asset&
305309 if (targetFolder == File{})
306310 return ;
307311
308- downloadAndInstall (asset, targetFolder);
312+ File targetFile = targetFolder.getChildFile (asset.name ).getNonexistentSibling ();
313+
314+ downloadAndInstall (asset, targetFile);
309315 }
310316}
311317
@@ -329,14 +335,14 @@ void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVe
329335}
330336
331337// ==============================================================================
332- class DownloadAndInstallThread : private ThreadWithProgressWindow
338+ class DownloadThread : private ThreadWithProgressWindow
333339{
334340public:
335- DownloadAndInstallThread (const LatestVersionCheckerAndUpdater::Asset& a,
336- const File& t,
337- std::function<void ()>&& cb)
341+ DownloadThread (const LatestVersionCheckerAndUpdater::Asset& a,
342+ const File& t,
343+ std::function<void ()>&& cb)
338344 : ThreadWithProgressWindow (" Downloading New Version" , true , true ),
339- asset (a), targetFolder (t), completionCallback (std::move (cb))
345+ asset (a), targetFile (t), completionCallback (std::move (cb))
340346 {
341347 launchThread (3 );
342348 }
@@ -346,24 +352,17 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow
346352 {
347353 setProgress (0.0 );
348354
349- File targetFile = targetFolder.getChildFile (asset.name ).getNonexistentSibling ();
350355 auto result = download (targetFile);
351356
352- // if (result.wasOk() && ! threadShouldExit())
353- // result = install (zipData);
354-
355357 if (result.failed ())
356358 {
357- MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
358- " Downloading Failed" ,
359- result.getErrorMessage ()); } );
359+ AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
360+ " Downloading Failed" ,
361+ result.getErrorMessage ());
360362 }
361363 else
362364 {
363- AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
364- " Download finished!" ,
365- " New binaries can be found at: " +
366- targetFile.getFullPathName ());
365+ setProgress (-1.0 );
367366 MessageManager::callAsync (completionCallback);
368367 }
369368 }
@@ -406,7 +405,10 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow
406405
407406 setProgress ((double )total / (double )asset.size );
408407
409- setStatusMessage (" Downloading... " + File::descriptionOfSizeInBytes (total));
408+ setStatusMessage (" Downloading... "
409+ + File::descriptionOfSizeInBytes (total)
410+ + " / "
411+ + File::descriptionOfSizeInBytes (asset.size ));
410412 }
411413
412414 out->flush ();
@@ -416,132 +418,68 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow
416418 return Result::fail (" Failed to download from: " + asset.url );
417419 }
418420
419- Result install (const File& dest)
420- {
421- setStatusMessage (" Installing..." );
422-
423- ZipFile zip (dest);
424-
425- // if (zip.getNumEntries() == 0)
426- // return Result::fail ("The downloaded file was not a valid JUCE file!");
427-
428- // struct ScopedDownloadFolder
429- // {
430- // explicit ScopedDownloadFolder (const File& installTargetFolder)
431- // {
432- // folder = installTargetFolder.getSiblingFile (installTargetFolder.getFileNameWithoutExtension() + "_download").getNonexistentSibling();
433- // jassert (folder.createDirectory());
434- // }
435-
436- // ~ScopedDownloadFolder() { folder.deleteRecursively(); }
437-
438- // File folder;
439- // };
440-
441- // ScopedDownloadFolder unzipTarget (targetFolder);
442-
443- // if (! unzipTarget.folder.isDirectory())
444- // return Result::fail ("Couldn't create a temporary folder to unzip the new version!");
445-
446- // auto r = zip.uncompressTo (unzipTarget.folder);
447-
448- // if (r.failed())
449- // return r;
450-
451- // if (threadShouldExit())
452- // return Result::fail ("Cancelled");
453-
454- // #if JUCE_LINUX || JUCE_BSD || JUCE_MAC
455- // r = setFilePermissions (unzipTarget.folder, zip);
456-
457- // if (r.failed())
458- // return r;
459-
460- // if (threadShouldExit())
461- // return Result::fail ("Cancelled");
462- // #endif
463-
464- // if (targetFolder.exists())
465- // {
466- // auto oldFolder = targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling();
467-
468- // if (! targetFolder.moveFileTo (oldFolder))
469- // return Result::fail ("Could not remove the existing folder!\n\n"
470- // "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"
471- // "Please select a folder that is writable by the current user.");
472- // }
473-
474- // if (! unzipTarget.folder.getChildFile ("JUCE").moveFileTo (targetFolder))
475- // return Result::fail ("Could not overwrite the existing folder!\n\n"
476- // "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"
477- // "Please select a folder that is writable by the current user.");
478-
479- // return Result::ok();
480- }
481-
482- Result setFilePermissions (const File& root, const ZipFile& zip)
483- {
484- // constexpr uint32 executableFlag = (1 << 22);
485-
486- // for (int i = 0; i < zip.getNumEntries(); ++i)
487- // {
488- // auto* entry = zip.getEntry (i);
489-
490- // if ((entry->externalFileAttributes & executableFlag) != 0 && entry->filename.getLastCharacter() != '/')
491- // {
492- // auto exeFile = root.getChildFile (entry->filename);
493-
494- // if (! exeFile.exists())
495- // return Result::fail ("Failed to find executable file when setting permissions " + exeFile.getFileName());
496-
497- // if (! exeFile.setExecutePermission (true))
498- // return Result::fail ("Failed to set executable file permission for " + exeFile.getFileName());
499- // }
500- // }
501-
502- // return Result::ok();
503- }
504-
505421 const LatestVersionCheckerAndUpdater::Asset asset;
506- File targetFolder ;
422+ File targetFile ;
507423 std::function<void ()> completionCallback;
508424};
509425
510- static void restartProcess (const File& targetFolder )
426+ static void runInstaller (const File& targetFile )
511427{
512- #if JUCE_MAC || JUCE_LINUX || JUCE_BSD
513- #if JUCE_MAC
514- auto newProcess = targetFolder.getChildFile (" Projucer.app" ).getChildFile (" Contents" ).getChildFile (" MacOS" ).getChildFile (" Projucer" );
515- #elif JUCE_LINUX || JUCE_BSD
516- auto newProcess = targetFolder.getChildFile (" Projucer" );
517- #endif
518-
519- StringArray command (" /bin/sh" , " -c" , " while killall -0 Projucer; do sleep 5; done; " + newProcess.getFullPathName ().quoted ());
520- #elif JUCE_WINDOWS
521- auto newProcess = targetFolder.getChildFile (" Projucer.exe" );
522-
523- auto command = " cmd.exe /c\" @echo off & for /l %a in (0) do ( tasklist | find \" Projucer\" >nul & ( if errorlevel 1 ( "
524- + targetFolder.getChildFile (" Projucer.exe" ).getFullPathName ().quoted () + " & exit /b ) else ( timeout /t 10 >nul ) ) )\" " ;
525- #endif
526-
527- if (newProcess.existsAsFile ())
428+ bool runInstaller = AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
429+ " Quit Open Ephys GUI?" ,
430+ " To run the installer, the current instance of GUI needs to be closed."
431+ " \n Are you sure you want to continue?" ,
432+ " Yes" , " No" );
433+
434+ if (runInstaller)
528435 {
529- ChildProcess restartProcess;
530- restartProcess.start (command, 0 );
436+ #if JUCE_WINDOWS
437+ if (targetFile.existsAsFile ())
438+ {
439+ auto returnCode = ShellExecute (NULL , (LPCSTR)" runas" , targetFile.getFullPathName ().toRawUTF8 (), NULL , NULL , SW_SHOW);
531440
532- JUCEApplication::getInstance ()->systemRequestedQuit ();
441+ if ((int )returnCode > 31 )
442+ JUCEApplication::getInstance ()->systemRequestedQuit ();
443+ else
444+ LOGE (" Failed to run the installer: " , GetLastError ());
445+ }
446+ #endif
533447 }
534448}
535449
536- void LatestVersionCheckerAndUpdater::downloadAndInstall (const Asset& asset, const File& targetFolder )
450+ void LatestVersionCheckerAndUpdater::downloadAndInstall (const Asset& asset, const File& targetFile )
537451{
538- installer.reset (new DownloadAndInstallThread (asset, targetFolder,
539- [this , targetFolder]
540- {
541- installer.reset ();
452+ #if JUCE_WINDOWS
453+ File exeDir = File::getSpecialLocation (
454+ File::SpecialLocationType::currentExecutableFile).getParentDirectory ();
455+
456+ if (exeDir.findChildFiles (File::findFiles, false , " unins*" ).size () > 0 )
457+ {
458+ downloader.reset (new DownloadThread (asset, targetFile,
459+ [this , targetFile]
460+ {
461+ downloader.reset ();
462+ runInstaller (targetFile);
463+
464+ }));
465+ }
466+ else
467+ #endif
468+ {
469+ AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
470+ " Download successful!" ,
471+ " Please extract the zip file located at: \n " +
472+ targetFile.getFullPathName ().quoted () +
473+ " \n to your desired location and then run the updated version from there. "
474+ " You can also overwrite the current installation after quitting the current instance." );
475+
476+ downloader.reset (new DownloadThread (asset, targetFile,
477+ [this ]
478+ {
479+ downloader.reset ();
542480
543- // restartProcess (targetFolder );
544- }));
481+ }) );
482+ }
545483}
546484
547485// ==============================================================================
0 commit comments