tags:

views:

274

answers:

6

One of the ways our app is distributed (on Windows) is as a ZIP archive. Inside this archive is a batch file used for starting the app. The user is supposed to unzip the archive before running our app, but frequently users ignore our instructions and try to run the app without unzipping the archive first. When users do this, the app fails to start, but it's not obvious (to the user) exactly what caused the failure. We'd like to detect from within the batch file whether it's being run from inside a ZIP archive, and if so, show the user a message reminding him to unzip the archive first.

However, it's not clear at all to me how to detect this condition. While the batch variable %cmdcmdline% contains the command which ran the batch file, there seems to be no way to use the path to reliably tell whether the path points into a ZIP archive. For example, I put the following batch file, named test.bat, into a ZIP archive:

echo %cmdcmdline%
pause

The output, when run from within the archive, was:

cmd /c ""C:\Users\liana\AppData\Local\Temp\Temp1_test.zip\test.bat" "

Now, it seems likely that Temp1_test.zip is a ZIP archive, not a real directory, but there's no guarantee that it is. Clearly, Windows knows how to tell the difference, so there must be some more reliable way than simply checking whether ".zip" shows up in the path somewhere. But how?

+1  A: 

Why does it fail? I presume you're missing some files because Windows only unzipped the batch file and not the entire archive. If that's true you can check to see if those files exist when the batch file starts.

John Kugelman
+3  A: 

Your program isn't actually being run from "Within" the archive. The archive is first expanded out to a temporary directory (The location for which can vary depending on which archiving tool is being used), before being run.

With this in mind it becomes clear that it isn't ever possible to tell for sure one way or another, so perhaps the best thing to do is instead to check for the presence of the other files you need to run your program, relative to the batch file's location.

Jasoon
Aha! I hadn't realized that what I was seeing in my example was a bona fide path, rather than some contraption invented by the Windows shell. I think I can simply test for the existence of one of our other files, which is guaranteed not to exist in the temp directory if the batch file was run from the archive.
uckelman
No, checking for the existence of another file won't work. WinRAR extracts the entire archive to a temporary directory when attempting to run, so that file would be there. I haven't tested it, but I find it very likely that most other archivers do the same, since it improves the chances of opening the file correctly (in case of dependencies on other files in the archive).
Michael Madsen
In the event that *all* of the files were extracted, however, there would be no problem---the app would run, so in that case we don't want to warn the user. It's only the state where partial extraction has happened that there's a problem.
uckelman
Yep - Some archives will deliberately not extract the full archive in case it's just too large (Or contains massive files that you don't want to view), and some will provide it as an option (Extract One, Extract All).Seems like the best thing to do then would be to check for the existance of some large files/directories, or try and roll a size check on the location itself.
Jasoon
A: 

The Windows shell (explorer.exe) associates the .zip extension with the internal zip-folder handler. You can rename anything to .zip and the shell will attempt to treat it as such. The zip-folder handler is a shell extension that, over time, has become fairly integrated into the shell.

The Windows command line environment, which your batch file operates in, has no concept of zipped folders. In that case all you can do is look for the .zip extension.

One thing you can do is distribute your package as an .msi instead, then you won't have these problems.

jeffamaphone
Distributing as an .msi is no good in this particular case, as the ZIP archive is intended to be our "generic" bundle. (There's also a shell script for starting the app in the ZIP archive as well.)
uckelman
+1  A: 

Check if another file in the archive exists in the same dir?

if not exist "%~dp0\someotherfile" goto print_please_unzip_ffs_message

%~dp0 is the directory of the bat file (drive and directory of argument zero, which is the bat-file itself)

Marcus Lindblom
I think that should be "exist", not "exists".
uckelman
Yeah right. Should've tested first. :)
Marcus Lindblom
A: 

If you create a batch file named "setup.bat" Windows will silently unzip ALL the files in the zip file to the temp directory instead of prompting the user if they want to do so.

In setup.bat you can then begin with cd /d %~dp0 to change to the currently executing directory. You can then just run your program as normal, or do some sort of installation.

joshperry
Are you saying that setup.bat will be run automatically by Windows? I'm not seeing that behavior on Vista.
uckelman
no, I'm saying that if you double-click a file called setup.bat in a zip file that windows archive system will extract ALL the files to the temp directory and run the setup.bat file instead of extracting and running just the file that was double-clicked.
joshperry
really? wow! thanks!
PA
A: 

Or you could distribute your app as a self-extracting zip archive. Doing that would strongly encourage users to run the SFX before running the app. (Although, (for some archivers) an SFX is also a ZIP, so they could rename the SFX to a .zip and then they'd be back to what you have today).

Cheeso
We already distribute a Windows installer. The ZIP archive is for people who either (1) can't install on the (Windows) system they're using, or (2) are using some OS other than Windows, Mac OS X, or Linux, for which we also provide packages. Distributing as an SFX might prevent the archive from serving purpose #2.
uckelman
@uckelman, An SFX ZIP is still a completely legal and format compliant ZIP file, so it is likely to to be usable on other platforms. It won't be self extracting anywhere other than on the platform for which the extraction stub was built, however.
RBerteig
@RBerteig - Careful! There is no "spec" for an SFX ZIP. Therefore each zip tool or library may construct an SFX differently. Some zip tools create custom SFX files which are not actually zip files. WinZip and DotNetZip are two for which your statement is true: an SFX is a ZIP.
Cheeso
More: In cases where an SFX ZIP is a ZIP, I would say it more strongly. Rather than "it is likely to be usable", I would say "it will be usable". You may have to rename the file (from .exe to .zip) to indicate that it is a zip file to the non-Windows platform. On the other hand, if @uckelman wants a single unpack/extract approach, then he is correct that an SFX won't suffice for multi-platform use.
Cheeso
@Cheeso, I should have relaxed my statement to say that an SFX *need not violate the ZIP format spec*, as it allows for putting non-ZIP-file content before, after, or even within the span of the file containing the compressed data and its directory. That makes it easy to create an SFX that is also a ZIP, but certainly it is possible to create them deliberately non-ZIP compliant. I certainly agree that a SFX ZIP is not a *good* cross-platform distribution tool.
RBerteig