Posted by negativesilence in SWF Studio V3 on Apr 16 2008, 01:53 pm

I have this projector that has links to open PDFs, Word Doc's, Excel Files and HTML files as well. All files in one folder including the projector. My question is is it possible to add an autoupdate feature where the projector checks online if there are updated files available and overwrite the local copies? I'm thinking checking if a file exist on the web ( http://mysite.net/update.exe) it will update the local copies. If not then a message will appear saying they have the most updated files.

If this is possible, what commands can I look more into from the documentation so I can start working on it in my project?

thanks


Posted by AGo in SWF Studio V3 on Apr 16 2008, 03:25 pm

It's perfectly possible, just check out the HTTP or FTP plugin (whatever works better for your case) and maybe FileSys.fileVer/fileSize for comparison if the local files are up to date.


Posted by negativesilence in SWF Studio V3 on Apr 16 2008, 03:28 pm

awesome. I will look in those commands. thanks


Posted by northcode in SWF Studio V3 on Apr 17 2008, 09:26 am

I created a working automatic update example a while ago. You can find it over here.


Posted by negativesilence in SWF Studio V3 on Apr 17 2008, 10:38 am

thanks Northcode. I can't get the autoupdate file to work. I uploaded myapp.exe and trigget to the server, here are my settings:


   static var __protocol     = "HTTP";
   static var __host         = "negativesilence.net";
   static var __trigger      = "/autoupdate/trigger";
   static var __resource     = "/autoupdate/myapp.exe";
   static var __tempfile     = "myapp.temp";
   static var __updater      = "updater.exe";
   static var __updateprompt = "A newer version of the software is available.\n\nWould you like to download it now?";
   static var __regkey       = "Software\\CompanyName\\ProductName";


And I always get this error:

checking for updates
onGotTrigger: The requested resource could not be found, access is denied, or there was a server error.
last trigger:0 new trigger:
no download required


Posted by northcode in SWF Studio V3 on Apr 17 2008, 12:31 pm

Did you build a copy of MyApp.exe from the ZIP file AFTER making changes to the AS file and upload that to your server? If not the update will work once and then it will be trying to download MyApp.exe from 127.0.0.1 instead of from negativesilence.net.


Posted by negativesilence in SWF Studio V3 on Apr 17 2008, 12:59 pm

I tried that and got the same error. The update didn't work the first time. Also I'm thinking I need to reexport the myapp.swf first before rebuilding the myapp.exe. But when I tried to reexport from the .fla file, I got 27 Compile errors from the output window.. like:

There is no method sSDebug..
There is no method ....

Despite the errors I tried rebuilding the .exe from that swf if it will work but when I tried it, the commands don't seem to work anymore because no messages from the Trace window comes up.


Posted by mbd in SWF Studio V3 on Apr 17 2008, 03:58 pm

If you get compiler errors the SWF that is produced is useless. I still don't understand why the Flash IDE still produces and even allows you to test a SWF that has had compiler errors.

The reason for the errors is because you need to include the AS2 intrinsic classes in the classpath for your FLA.

Once you get a SWF to compile without errors, then the SWF is valid. It doesn't necessarily mean it will do exactly what you intended, but at least it will do what the code specifies.


Posted by negativesilence in SWF Studio V3 on Apr 17 2008, 04:32 pm

that worked! Thanks a lot. I will use this as a reference for the autoupdate feature in my project. thanks


Posted by negativesilence in SWF Studio V3 on Jun 18 2008, 02:33 pm

I am trying to setup this autoupdate in my application. Everything works except the restarting of the newly downloaded file. Here is the function that does that


   private function updateExeFile():Void
   {

      setStatus("performing update");
      var args = "/oldexe " + ssGlobals.ssExePath + " /newexe " + ssGlobals.ssWinTempDir + "\\" + __tempfile;
      ssCore.Shell.execute({path:ssGlobals.ssStartDir + "\\" + __updater, arguments:args});
      ssCore.App.quit({});

   }


I'm looking at the trace window and the last message is "performing update". The application never reopens. Help?


Posted by northcode in SWF Studio V3 on Jun 18 2008, 02:37 pm

Something is probably not configured properly. Change the call to ssCore.Shell.execute to look like this (below) and have a look at the results in the trace window to see where it's going wrong.


var r = ssCore.Shell.execute({path:ssGlobals.ssStartDir + "\\" + __updater, arguments:args});
setStatus(r.success + " " + r.Error.description);


Posted by negativesilence in SWF Studio V3 on Jun 18 2008, 03:26 pm


var r = ssCore.Shell.execute({path:ssGlobals.ssStartDir + "\\" + __updater, arguments:args});
      setStatus(r.success + " " + r.Error.description);
      setStatus("performing update");
      
      var args = "/oldexe " + ssGlobals.ssExePath + " /newexe " + ssGlobals.ssWinTempDir + "\\" + __tempfile;
      ssCore.App.quit({});


I got this error in trace window

true undefined
performing update


Posted by northcode in SWF Studio V3 on Jun 18 2008, 07:59 pm

If you got them in that order then you probably don't have synchronous commands enabled.


Posted by negativesilence in SWF Studio V3 on Jun 19 2008, 11:02 am

I have already enabled synchronous commands in the first frame. Still not sure why it's not working. When I test your sample file it works fine. :(


Posted by negativesilence in SWF Studio V3 on Jun 19 2008, 11:49 am

My application is about 125mb which I think is the reason why it's not working. I tried to remove the files embedded in it to make the size around 5mb and it reopened fine after the update. Could there be a solution?

Thanks for the help.


Posted by mbd in SWF Studio V3 on Jun 19 2008, 11:56 am

In your code you posted last, things are out of order. You are defining the args variable AFTER you've used it in the ssCore.Shell.execute call. So you aren't passing anything in the args for that command. Move the args definition above the ssCore.Shell.execute call.


Posted by negativesilence in SWF Studio V3 on Jun 19 2008, 12:17 pm

Actually, the last test I did I used this code:


   private function updateExeFile():Void
   {

      setStatus("performing update");
      var args = "/oldexe " + ssGlobals.ssExePath + " /newexe " + ssGlobals.ssWinTempDir + "\\" + __tempfile;
      var r = ssCore.Shell.execute({path:ssGlobals.ssStartDir + "\\" + __updater, arguments:args});
      setStatus(r.success + " " + r.Error.description);
      ssCore.App.quit({});

   }


Still got the same problem. Only the smaller file reopens. When its the 125mb projector it quits after the download and doesn't reopen.


Posted by negativesilence in SWF Studio V3 on Jun 19 2008, 12:32 pm

could it be because the updater.exe executes already while the newly download .tmp file is still replacing the old .exe file?


Posted by northcode in SWF Studio V3 on Jun 19 2008, 06:55 pm

The updater doesn't run until the download is complete and then the updater launches the new EXE only after it has been copied successfully over the old one.

Before the updater does the copy it makes 100 attempts at 10ms intervals (for a total of about a 1 second delay) to delete the original EXE. If that fails then the copy doesn't even take place. This is most likely where it's failing.

I'll build a new version of the updater utility that accepts a /delay switch on the command line. The default (if you don't provide a value) will be 1000ms (or 1 second). Passing 0 will mean wait forever and any other value will be the number of milliseconds to wait before abandoning the update.

If you were ambitious, or didn't want to wait for me, you could always write your own version of updater.exe using SWF Studio ;)


Posted by negativesilence in SWF Studio V3 on Jun 20 2008, 01:38 am


QUOTE: from northcode;44694

If you were ambitious, or didn't want to wait for me, you could always write your own version of updater.exe using SWF Studio ;)


uhmmm...


Posted by northcode in SWF Studio V3 on Jun 20 2008, 01:36 pm

Ok, here's the new version of updater.exe that implements the delay argument ;)

attachments: updater.zip  


Posted by negativesilence in SWF Studio V3 on Jun 20 2008, 02:17 pm

it worked. you are the best.


Posted by negativesilence in SWF Studio V3 on Jul 08 2008, 10:27 am

How easy would it be to change the autoupdate.as to use FTP instead of the HTTP plugin? I tried a few things from ftp download example but did not succeed. need help pls?

thanks


Posted by northcode in SWF Studio V3 on Jul 08 2008, 05:07 pm

I'd have to have a pretty good reason to switch from HTTP to FTP since the HTTP version is a lot easier to set up. You can still implement a password system with HTTP if that's the issue. Switching to FTP would not be hard, but you would you replace the trigger check with FTP too or just the file download part?


Posted by negativesilence in SWF Studio V3 on Jul 08 2008, 05:10 pm

I just need to have the download part use ftp This is because the executable file is a large file and we don't want it using all the bandwidth of the site.


Posted by northcode in SWF Studio V3 on Jul 08 2008, 09:20 pm

How are you saving bandwidth by using FTP? All the bits are coming from the same place unless your FTP server is on another machine on a different network.


Posted by negativesilence in SWF Studio V3 on Jul 08 2008, 10:05 pm

that's exactly how the ftp server is setup =)


Posted by northcode in SWF Studio V3 on Jul 09 2008, 12:06 am

If the machine the FTP server is on also has an HTTP server running you can still use the HTTP approach. If not, then this example shows how to download a file using the FTP plugin.

Drop this in a new FLA so you can play with it and modify it for your needs. Once you have it working you can replace the HTTP download code with this stuff in your application.


ssCore.init();
ssDefaults.synchronousCommands = true;

// Specify the FTP server, username and password for your FTP account, the direction you are 
// transferring the file, the location of the file to transfer and its destination.

ssCore.FTP.host({host:"server.com"});
ssCore.FTP.authUser({userID:"userid"});
ssCore.FTP.authPswd({password:"password"});
ssCore.FTP.direction({direction:"download"});
ssCore.FTP.localFile({localFile:"startdir://file.txt"});
ssCore.FTP.remoteFile({remoteFile:"file.txt"});

// Now connect to the FTP server and call our "connected" function when the connection 
// has been made successfully, or the connection attempt has failed.

ssCore.FTP.connect({}, {callback:"connected", scope:this});

function connected(return_obj, callback_obj, error_obj)
{
   if (return_obj.success)
   {
      // The connection was successful so we begin an FTP transfer.
      ssCore.FTP.open({}, {callback:"opened", scope:this});
   }
   else
   {
      // If an error occurs we display the description in the SWF Studio Trace tab.
      ssDebug.trace("ERROR: "+error_obj.description);
   }
}

function opened(return_obj, callback_obj, error_obj)
{
   if (return_obj.success)
   {
      // If the open was successful we transfer the data.
      ssCore.FTP.transfer({}, {callback:"fileTransferred", scope:this});
   }
   else
   {
      // If an error occurs we display the description in the SWF Studio Trace tab.
      ssDebug.trace("ERROR: "+error_obj.description);
   
      // Because we successfully connected we should also disconnect.
      ssCore.FTP.disconnect();
   }
}

function fileTransferred(return_obj, callback_obj, error_obj)
{
   if (return_obj.success)
   {
      ssDebug.trace("File was transferred successfully");
   }
   else
   {
      // If an error occurs we display the description in the SWF Studio Trace tab.
      ssDebug.trace("ERROR: "+error_obj.description);
   }

   // Because we successfully started an open we should execute the close command.
   ssCore.FTP.close();
   
   // Because we successfully connected we should also disconnect
   ssCore.FTP.disconnect();
}


Posted by Clovis in SWF Studio V3 on Jul 09 2008, 05:55 am


QUOTE: from northcode;44696
Ok, here's the new version of updater.exe that implements the delay argument ;)

Hi, could you tell me what is the correct syntax to use this new argument?


Posted by northcode in SWF Studio V3 on Jul 09 2008, 09:21 am


QUOTE:
...updater utility that accepts a /delay switch on the command line. The default (if you don't provide a value) will be 1000ms (or 1 second). Passing 0 will mean wait forever and any other value will be the number of milliseconds to wait before abandoning the update.

This is just a new command line argument for updater.exe. So in addition to /oldexe and /newexe you can now specify /delay and a value in milliseconds. Using /delay 0 means wait forever.


Posted by Clovis in SWF Studio V3 on Jul 09 2008, 10:51 am

Thank you, this is really useful :)


Posted by negativesilence in SWF Studio V3 on Jul 09 2008, 11:57 am

I'm setting up the updating via ftp. I keep getting asynchronous-only error for FTP.connect. How do I get around this? thanks

checking for updates
onGotTrigger: undefined
last trigger:34 new trigger:35
Specified command is asynchronous-only. "FTP.connect"
ERROR: Could not connect to the specified host.


Posted by mbd in SWF Studio V3 on Jul 09 2008, 12:12 pm

Just like in Tim's example, you should be specifying a callback function that will be called when FTP.connect is complete. You are checking the return object from the command instead, which won't work. The command is still being executed, but if you are trying to do something right after the FTP.connect command, then that's where the failure will occur, since the FTP.connect hasn't actually executed yet.

When a command is executed asynchronously the API will communicate to the SWF Studio player via fscommand. fscommands are queued by the Flash player and executed to the container program (usually the browser, but in this case the SWF Studio player) only AFTER all other ActionScript has executed in that frame.

By default all commands are executed asynchronously. When you set ssDefaults.synchronousCommands to true, this changes so that the default is synchronous. However, async-only commands will ALWAYS be executed asynchronously. A return object is passed in that case, just in case you are expecting the command's data synchronously.

Also, when you specify a callback function the command will be executed asynchronously, or when you set the sync property of the callback object as false.


Posted by negativesilence in SWF Studio V3 on Aug 28 2008, 12:27 pm

Is this the correct way of adding that /delay switch? For some reason, the updater is not consistent. It doesn't execute most of the time. Thanks


   private function updateExeFile():Void
   {
      
      setStatus("performing update");
      var args = "/delay 0" + "/oldexe " + ssGlobals.ssExePath + " /newexe " + ssGlobals.ssWinTempDir + "\\" + __tempfile;
      var r = ssCore.Shell.execute({path:"tempdir://" + __updater, arguments:args});
      setStatus(r.success + " " + r.Error.description);
      ssCore.App.quit({});

   }


Posted by northcode in SWF Studio V3 on Aug 28 2008, 02:05 pm

I can't remember exactly how I did the command line switch parsing, but I'd I'd change the "/oldexe " string to " /oldexe " to make sure that the updater doesn't get confused.


Posted by negativesilence in SWF Studio V3 on Aug 28 2008, 06:12 pm

hmm. Still not working all the time and I still get a "true Undefined" in the tracebox.


Posted by northcode in SWF Studio V3 on Aug 28 2008, 08:59 pm

The "true" means that the updater was launched, the "undefined" means there was no error from the call to Shell.execute so everything is okay there. If the updater isn't launching your app it's either because you're passing the wrong path (trace those out and make sure they're right) or because you're using the older version of the updater utility (the one that doesn't have a delay argument).


Posted by negativesilence in SWF Studio V3 on Aug 29 2008, 12:09 pm

I'm pretty sure I'm using the updater.exe that has the delay argument. I believe the updater started failing when I switched from http to ftp. Not really sure why that happened but here is my as file. Thanks again for checking.



//--------------------------------------------------------------------------------
// This class requires that ssDefaults.synchronousCommands be enabled (true).
//--------------------------------------------------------------------------------

class AutoUpdateFTP
{

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   static var __protocol     = "HTTP";
   static var __host         = "negativesilence.net";
   static var __trigger      = "/test/trigger";
   static var __resource     = "/WorkflowTool.exe";
   static var __tempfile     = "WorkflowTool.tmp";
   static var __updater      = "tempdir://updater.exe";
   static var __updateprompt = "A newer version of the Workflow Tool is available.\n\nWould you like to download it now?";
   static var __regkey       = "Software\\CCHWorkflowTool\\WorkflowTool";

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private var totalBytes:Number;

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   static var __instance:AutoUpdateFTP;

   static function get():AutoUpdateFTP
   {
      
      if (__instance==null)
      {
         __instance=new AutoUpdateFTP();
      }

      return __instance;

   }

   //--------------------------------------------------------------------------------
   // We use this to display status information during the update check and during 
   // the download process. If you want to do something other than write to the trace
   // tab, replace this code with something else to give your users feedback.
   //--------------------------------------------------------------------------------

   private function setStatus(s:String):Void
   {
      
      ssDebug.trace(s);

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private function onGotTrigger(r, c, e):Void
   {
   
      var trigger = "0";
      
      setStatus("onGotTrigger: " + e.description);

      r = ssCore.downloader.getBuffer({});
      
      if (r.success)
      {
         trigger = r.result;
      }
      else
      {
         setStatus("onGotTrigger failed: " + r.Error.description);
      }
         
      ssCore.downloader.stop({});
      ssCore.Plugin.unload({alias:"downloader"});
         
      this.doUpdateCheck(trigger);

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private function doUpdateCheck(trigger)
   {
   
      var last = getLastTrigger();
      var softwareVersion:Number;
      softwareVersion = 5;
      
      setStatus("last trigger:"+last + " new trigger:"+trigger);
      
      if (softwareVersion != trigger){
   
         if (Number(trigger) > Number(last))
         {
         
            var r = ssCore.App.showMsgBox({prompt:__updateprompt, buttons:"yesno", icon:"question"});
            
            if (r.success)
            {
               if (r.result == "YES")
               {
                  saveTrigger(trigger);
                  startDownload();
               }
               else
               {
                  setStatus("download cancelled by user");
               }
            }
         }
         else
         {
            onCheckingComplete();
            setStatus("no download required");
         }
      }
      else
      {
         onCheckingComplete();
         setStatus("no download required because of version number");
      }

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private function getLastTrigger():String
   {
      
      var v = "0";
      
      var r = ssCore.Registry.getValue({rootKey:"HKEY_LOCAL_MACHINE", subKey:__regkey, valueName:"Trigger"});
      
      if (r.success)
      {
         v = r.result;
      }
         
      return v;                            

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private function saveTrigger(trigger:String):Void
   {
   
      var r = ssCore.Registry.setValue({rootKey:"HKEY_LOCAL_MACHINE", subKey:__regkey, valueName:"Trigger", type:"REG_SZ", value:trigger});

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   public function startDownload():Void
   
   {
      ssCore.FTP.passiveMode({passive:true});
      ssCore.FTP.connect({}, {callback:"connected", scope:this});
      
      ssCore.FTP.host({host:"hostname here"});
      ssCore.FTP.authUser({userID:"username"});
      ssCore.FTP.authPswd({password:"password"});
      ssCore.FTP.direction({direction:"download"});
      ssCore.FTP.localFile({localFile:ssGlobals.ssWinTempDir + "\\" + __tempfile});
      ssCore.FTP.remoteFile({remoteFile:"/LEGALFTP/workflowtool/WorkflowTool.exe"});
      

   }
   
   public function connected(return_obj, callback_obj, error_obj)
      {
         if (return_obj.success)
         {
           // The connection was successful so we begin an FTP transfer.
           ssCore.FTP.open({}, {callback:"opened", scope:this});
         }
         else
         {
           // If an error occurs we display the description in the SWF Studio Trace tab.
           ssDebug.trace("ERROR: "+error_obj.description);
         }
      }
      
   public function opened(return_obj, callback_obj, error_obj)
      {
         if (return_obj.success)
         {
           // If the open was successful we transfer the data.
           ssCore.FTP.getFileSize({},{callback:"onContentLength", scope:this});
            ssCore.FTP.setNotify({event:"onProgress"}, {callback: "onDownloadProgress", scope:this});
            ssCore.FTP.transfer({}, {callback:"onDownloadComplete", scope:this}); 
         }
         else
         {
           // If an error occurs we display the description in the SWF Studio Trace tab.
           ssDebug.trace("ERROR: "+error_obj.description);
         
           // Because we successfully connected we should also disconnect.
           ssCore.FTP.disconnect();
         }
      }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   public function stopDownload():Void
   {
      
      ssCore.ftp.close({});
      ssCore.Plugin.unload({alias:"downloader"});

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private function onContentLength(r, c, e):Void
   {
      
      if (r.success) 
      {
         this.totalBytes = Number(r.result); 
      }
      else 
      {
         setStatus("error downloading file (1) " + r.Error.description);
      }

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private function onDownloadProgress(r, c, e):Void
   {
      
      // note: totalBytes can be -1 if we couldn't get the length from the server
      // but we're not handling that specific case (might look funny to the user)

      var percent = Math.round(Number(r.result)*100/this.totalBytes);
      setStatus("downloading " + percent + "%");
      _root.downloadBox.easeAlpha(100, 3);
      _root.downloadBox._x = 362;
      _root.downloadBox._y = 334;
      _root.downloadBox.downloadText.text = "downloading " + percent + "%";

   }
   
   private function onCheckingProgress():Void
   {
      
      // note: totalBytes can be -1 if we couldn't get the length from the server
      // but we're not handling that specific case (might look funny to the user)

      _root.downloadBox.easeAlpha(100, 3);
      _root.downloadBox._x = 362;
      _root.downloadBox._y = 334;
      _root.downloadBox.downloadText.text = "Checking for latest version...";

   }
   
   
   private function onCheckingComplete():Void
   {
      
         _root.downloadBox.downloadText.text = "You have the latest version";
         _root.downloadBox.easeAlpha(0, 5);
         _root.downloadBox.downloadText.text.easeAlpha(0, 5);
         _root.downloadBox._x = -300;
         _root.downloadBox._y = 334;

   }

   //--------------------------------------------------------------------------------
   //
   //--------------------------------------------------------------------------------

   private function onDownloadComplete(r, c, e):Void
   {
   
      stopDownload();
      
      if (r.success) 
      {
         setStatus("download completed successfully");
         _root.downloadBox._alpha = 0;
         _root.downloadBox._x = -300;
         _root.downloadBox._y = 334;
         _root.downloadBox.downloadText.text = "download completed successfully";
         updateExeFile();
      }
      else 
      {
         setStatus("error downloading file (2) " + r.Error.description);
      }

   }

   
   private function updateExeFile():Void
   {
      
      setStatus("performing update");
      var args = "/delay 0 " + " /oldexe " + ssGlobals.ssExePath + " /newexe " + ssGlobals.ssWinTempDir + "\\" + __tempfile;
      var r = ssCore.Shell.execute({path:__updater, arguments:args});
      setStatus(r.success + " " + r.Error.description);
      setStatus(ssGlobals.ssExePath);
      setStatus(ssGlobals.ssWinTempDir);
      setStatus(__updater);
      ssCore.App.quit({});

   }

   //--------------------------------------------------------------------------------
   // Call this function to check for updates and kick off prompting the user, the
   // download and the actual update.
   //--------------------------------------------------------------------------------
   
   public function checkForUpdates():Void
   {   
   
      var trigger = "0";

      ssCore.Plugin.load({plugin:"http", alias:"downloader"});
      
      ssCore.downloader.protocol({protocol:__protocol});
      ssCore.downloader.host({host:__host});
      ssCore.downloader.resource({resource:__trigger}); 
      
      var r = ssCore.downloader.start({});
      
      if (r.success)
      {
         onCheckingProgress();
         setStatus("checking for updates");
         ssCore.downloader.read({}, {callback:"onGotTrigger", scope:this});
      }
      else
      {
         setStatus("checkForUpdates failed: " + r.Error.description);
      }
      
   }
   
}




Posted by negativesilence in SWF Studio V3 on Aug 29 2008, 02:02 pm

With the above code, the updater is successful about 30% of the time. When it fails, The application will quit and the temp file doesn't even replace the old file. It just sits in my temp folder. Thanks


Posted by AGo in SWF Studio V3 on Aug 30 2008, 12:02 am

So if I got you right your only problem is that while the actual update check and download process works correctly, and only the copy action fails?

In that case, try to remove the App.quit command and close the app by yourself once you see the process is completed and the paths are traced out. If it works then we know it's a timing issue.

If it is not working, check if updater.exe is actually running in the task manager.


Posted by negativesilence in SWF Studio V3 on Sep 01 2008, 04:19 pm

I removed the app.quit command and still the copy action failed.

I opened task manager and I tried to double click the updater.exe (with /delay argument) a few times and I didn't see it appear in the task manager. However, when I tried to open the old updater.exe, I see it in the task manager for about a second then disappears.


Posted by negativesilence in SWF Studio V3 on Sep 02 2008, 12:36 pm

I played with the code and the updater worked 2 out of 5 times I tested. This is with the /delay 0 argument. Could be something with the updater.exe? Thanks for the help..


Posted by negativesilence in SWF Studio V3 on Sep 09 2008, 07:50 am

Changing the updateExeFile() function to below seems to have fixed the problem


   private function updateExeFile():Void
   {
      
      setStatus("performing update");
      var args = "/oldexe " + ssGlobals.ssExePath + " /newexe " + ssGlobals.ssWinTempDir + "\\" + __tempfile;
      var r = ssCore.Shell.execute({path:__updater, arguments:args});
         if (r.success) 
         {
            ssCore.App.quit({});
            setStatus("performing update done......");
         }
         else 
         {
            setStatus("update failed......");
         }
   }


Thanks


Posted by Miss Jones in SWF Studio V3 on Feb 26 2009, 01:23 am


QUOTE:
I created a working automatic update example a while ago. You can find it over here.

Thanks, Northcode, for this example. I have worked through it and read through this thread a couple of times. There's no "updater.fla" in the zip file, only updater.exe. So this is my question... you have written this exe file as a utility for us to use with our own spf projects? Or did you intend for us to write our own updater.fla code, calling the functions in AutoUpdate.as modified with our own variables?

Also, once I have an updater.exe working with my software, am I correct in thinking it needs to be bundled in the zip file with my software so that the software can auto-update?

I'm really enjoying SWF Studio, by the way. It's a great product!


Posted by northcode in SWF Studio V3 on Feb 26 2009, 10:57 am

There's no FLA for updater.exe, it's a C++ program that is called from AutoUpdate.as to swap out a running EXE file for a freshly downloaded one. And you got it right, it's just a tool for you to use in your projects, although it's probably not very useful outside the scope of the auto update utility :)

QUOTE:
Also, once I have an updater.exe working with my software, am I correct in thinking it needs to be bundled in the zip file with my software so that the software can auto-update?The updater.exe just needs to be distributed with your main EXE so it can call it after an update, you don't need to download it every time (it's not going to change).


Posted by Miss Jones in SWF Studio V3 on Feb 27 2009, 07:40 am

This is very useful.


Posted by Miss Jones in SWF Studio V3 on Mar 27 2009, 03:59 am

I've got this AutoUpdate working really well with my program. But I have another question, or request for advice.

When I put the latest version of my software on my webpage, I want it to be in a secure location not easily accessed by the general public. If I want that page only accessible through a password, how do I make the software autoUpdate itself without asking the customer to enter the password?

Would I compile the password into the FLA file? That would make it difficult to change the password, wouldn't it? Or would it be smarter to write my own version of updater.exe and include it there? Since software does this all the time - I have a number of programs that autoupdate - there must be some accepted standard procedure for doing this, but I haven't been able to figure out what it is. Is there another way to do this that doesn't involve a password?

I can't tell, strictly speaking, if this is actually a SWF studio question or something else - but any advice would be greatly appreciated!


Posted by northcode in SWF Studio V3 on Mar 27 2009, 10:19 am

You could add a password to the page on your server using htaccess and Basic Authentication and pass the username and password in the HTTP headers. You could also implement your own password system on the server side using a form (which you can easily supply values for using the HTTP plugin) or you could HTTPS. There are many ways to secure the server side, including just not telling anyone where the real download location is or obfuscating the data that you're downloading and fixing it up on the client side.

The real problem is how to handle getting updated authentication information to the client so it can supply it the next time it connects to do an update. Aside from giving each user a unique login when they purchase I don't have any silver bullets for you, but it's probably worth discussing here.


Posted by AGo in SWF Studio V3 on Mar 27 2009, 01:09 pm

first of all: just forget about the idea that you need to modify updater.exe. This file has absolutely nothing to do with the actual update itself, it only closes the old exe, overwrites the old exe file with a new one you already freshly downloaded, and finaly starts the new exe. that´s all. no internet connection of any kind involved.

Now the basic question is: Why do you need to secure the files you offer for the autoupdate process?
And if you need to secure the files on the server with a password, why would
you ever need to change it?
Everybody who does not know the old password will have no access anyway, and everybody who is able to learn the old password e.g. by using a network sniffer will easily be able to figure out the new password again, since somehow
your autoupdater needs to deliver the new pw the same way it did with the old pw, right? so if the attacker knows how to get the old one, he will now
how to get the new one as well.

To get around these problems with updating credentials, in cryptography so called Challenge-Response-Authentications are used.
These protocols require both parties (server and client) to authenticate against each other.
In a nutshell works like that:
Both parties know a shared secret (e.g. a strong encryption key), and need
to proof that to the other side.
simple example: Server S uses key K to encrypt a random number N with K,
sends the encrypted N to client C, C uses K to decrypt N, uses K to encrypt N+1, sends that to the server, the server decrypts that, and if it matches the N+1 the server sent it will grant the client privileges to access the
requested resources.

Now do this "handshake" via a https secured connection (get a widely trusted certificate for that, e.g. VeriSign or Thawte, self signed certs should not be used for this) and you should be all set on a somewhat secure way.

hope that helps


Posted by Miss Jones in SWF Studio V3 on Mar 28 2009, 07:42 am

I really appreciate you both taking the time to respond. It will take me a while to work through and try your ideas, but now I feel like I have somewhere to start!


Posted by Miss Jones in SWF Studio V3 on Apr 07 2009, 03:30 am

I have been trying to make htaccess work with this to make a secure download. I added in the static vars __username and __password with the other static vars at the beginning of AutoUpdate.as. Then I changed startDownload() like this:

QUOTE:
public function startDownload():Void

{
ssCore.Plugin.load({plugin:"http", alias:"downloader"});
var returnObject = ssCore.Plugin.isPluginLoaded( "http" );
ssDebug.trace(returnObject.result);



ssCore.downloader.protocol({protocol:"HTTP"});
ssCore.downloader.host({host:__host});
ssCore.downloader.resource({resource:__resource});
ssCore.downloader.local({path:ssGlobals.ssWinTempDir + "\\" + __tempfile});
ssCore.downloader.authUser({userID:__username});
ssCore.downloader.authPswd({password:__password});


var r = ssCore.downloader.start({});
ssDebug.trace("r.success: " + r.success);
if (r.success)
{

ssCore.downloader.getContentLength({},{callback:"onContentLength", scope:this});
ssCore.downloader.setNotify({event:"onProgress"}, {callback: "onDownloadProgress", scope:this});
ssCore.downloader.read({}, {callback:"onDownloadComplete", scope:this});
}
else
{

setStatus(r.Error.description);
stopDownload();
}

}

//--------------------------------------------------------------------------------
//


Alternatively, I have tried startDownload() with this code to set the authUser and authPswd:

QUOTE:
var returnObject = ssCore.Plugin.isPluginLoaded( "http" );
ssDebug.trace(returnObject.result);

var ro_user = ssCore.HTTP.authUser({userID:__username});
ssDebug.trace(ro_user.result);
var ro_pswd = ssCore.HTTP.authPswd({password:__password});
ssDebug.trace(ro_pswd.result);


I put all those trace statements in there to see why it wasn't working. I got back "false" to the isPluginLoaded query whether I tried "http" or "downloader." I got back undefined to everything else.

I have tried various versions with the .htaccess file, setting it to restrict use just to "myapp.exe" as well as to the whole folder. It's definitely working because if I restrict access simply to "myapp.exe" it will read the trigger and tell me a new download is available. It just won't download (unless I delete the .htaccess file; then everything downloads as usual).

I've studied the HTTP plugin examples on the Examples page, but I'm sure I'm missing something. Can you explain how this works in a little more detail so I can see where I am going wrong? Thanks so much for all your help.


Posted by northcode in SWF Studio V3 on Apr 07 2009, 09:28 am

What method of authentication are you using in the htaccess file? When you use authUser and authPswd the HTTP plugin assume Basic authentication. If you're using Digest authentication then it won't work. I don't think we mention that explicitly in the help, if that's the case, I'll fix that.


Posted by Miss Jones in SWF Studio V3 on Apr 08 2009, 12:54 am

No, I was definitely using basic. I have tried a few variants on the htaccess file, but they are all something along these lines:

QUOTE:
AuthName "Restricted Area"
AuthType Basic
AuthUserFile restricted/subscriber/.htpasswd
AuthGroupFile /dev/null

require valid-user


Can you see anything I'm doing wrong? Thanks so much!


Posted by northcode in SWF Studio V3 on Apr 08 2009, 01:10 am

Send me a url along with a userid and password (by email to support@northcode.com) and I'll try it from here and see if I can get it to work.


Posted by Miss Jones in SWF Studio V3 on Apr 15 2009, 03:38 am

Now...This works perfectly on my English OS. So I have been trying it on a Japanese system, and some baffling problems have appeared.

This is what happens. The program checks for updates, finds it needs an update, downloads the newest version, and hangs there. It does not close, and it does not install the newest version.

There seem to be two problems upon closer inspection. It does not appear to save the "Trigger" value to the Japanese registry. I thought that perhaps the Registry names appeared in Japanese and therefore made no sense to the program, but when I checked the only part in Japanese is "My computer," and this program doesn't read that anyway. "HKEY_LOCAL_MACHINE" and "SOFTWARE" are both in English, only there is no newly created folder with my software's name, nor is there a saved Trigger. The result is the same whether the Japanese OS is XP or Vista.

Not having a trigger doesn't seem to stop it from downloading, because the trigger I've got is always greater than nothing. And the download bar I created using onContentLength() and onDownloadProgress() works fine, but it gets to the end of the download and just hangs there. So it looks like var r = ssCore.Shell.execute({path:__updater, arguments:args}); doesn't get called or doesn't work with the Japanese OS.

I just wonder if you have any ideas of anything different I should try with this program since it has to work with a Japanese OS. I've been trying to research differences between registries on Japanese and English systems, and haven't come up with anything very useful. Any other suggestions would be greatly appreciated - but if you don't have any ideas, thanks anyway for all the great support so far.


Posted by northcode in SWF Studio V3 on Apr 15 2009, 08:55 am

Are you using 3.6 build 147 or one of the development builds we've made available?

What folder is the updater EXE and the newly downloaded EXE? Does it have Japanese characters in the path?


Posted by Miss Jones in SWF Studio V3 on Apr 16 2009, 12:05 am

I've got version 3.6, Build 147.

Darn! I thought you had a pretty good idea with checking the file path for Japanese characters, but it's exactly the same in both the English and Japanese OS: C:\Program Files\My App\myApp.exe (or updater.exe) . The only thing I could see different was that onscreen the Japanese file paths use a character that looks like a Yen sign () in place of the backslash. However, if I try to copy and paste that, it converts itself to a backslash, so I'm guessing the computer is still reading it correctly.

Can you think of anything else I'm forgetting to check? Thanks so much.


Posted by northcode in SWF Studio V3 on Apr 16 2009, 11:07 am

3.6 build 147 did have some issues with Japanese systems. If you send your serial number to support@northcode.com we'll send you a link to the current development build so you can see if that fixes your problem before we spend a lot of time debugging.