Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
634 views
in Technique[技术] by (71.8m points)

vbscript - Inno Setup Copy Files and Folders to an Existing Zip File

Is there a way to copy files from a folder to a zip file using Inno Setup?

My installer script creates a Temp Folder and I would like to move the content (mix of files and folders) to an existing zip file. I don't need compression or anything fancy...

I thought, and I know this is dumb, that this would be possible using FileCopy because (as far as I know) MS Windows treats copying to a zip folder in a similar way as copying to a directory.

[Update 1] Ok - found a vbs script that does what I want, after some minor changes:

Dim fso, winShell, h, MyTarget, MySource

MySource = Wscript.Arguments.Item(0)
MyTarget = Wscript.Arguments.Item(1)

Set fso = CreateObject("Scripting.FileSystemObject")
Set winShell = createObject("shell.application")
Set h = fso.getFile(MyTarget)

'Wscript.Echo "Adding " & MySource & " to " & MyTarget

winShell.NameSpace(MyTarget).CopyHere winShell.NameSpace(MySource).Items

do
    wscript.sleep 500
    max = h.size
loop while h.size > max 

Set winShell = Nothing
Set fso = Nothing

And ran it from command line like this: Cmd (run as admin) C:MyScriptLocationWScript ZipScript.vbs "MySourceDirPath" "MyDestDirPathMyZipFile.zip"

So now I need to get it to run from Inno :-)

[Update 2] Ok - got it running from Inno, revised the script:

Dim objFSO, objTxt, winShell, h
Dim myFolder, myZipFile
Const ForWriting = 2

myFolder = Wscript.Arguments.Item(0)
myZipFile = Wscript.Arguments.Item(1)
Wscript.Echo "Planning to add Source: " & myFolder & " to Target: " & myZipFile

Set objFSO = CreateObject( "Scripting.FileSystemObject" )
Wscript.Echo "Creating myZipFile" & myZipFile
' Create an empty ZIP file
    Set objTxt = objFSO.OpenTextFile( myZipFile, ForWriting, True )
    objTxt.Write "PK" & Chr(5) & Chr(6) & String( 18, Chr(0) )
    objTxt.Close
    Set objTxt = Nothing

Set winShell = createObject("shell.application")
Set h = objFSO.getFile(myZipFile)
Wscript.Echo "Started Copy Process" & myZipFile
winShell.NameSpace(myZipFile).CopyHere winShell.NameSpace(myFolder).Items, true

do
    wscript.sleep 1000
    max = h.size
loop while h.size > max 

Set winShell = Nothing
Set objFSO = Nothing

I am running from Inno using:

[Run]
Filename: "PackItUp.vbs"; Parameters: """{code:GetDataDir_S|0}Temp"" ""{code:GetDataDir_S|0}myZip.zip"""; WorkingDir: "{code:GetDataDir_S|0}"; Flags: shellexec runascurrentuser

Which seems to work, but I am unsure if this is a good solution.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is a nice feature that I've never heard about. The Folder object CopyHere method can append files or folders to existing archive files. With late binding you can write as little as this (even the VB script in your question was overcomplicated since this method accepts also file name passed as string):

procedure CopyToArchive(const Archive, Content: string);
var
  Shell: Variant;
  Folder: Variant;
begin
  Shell := CreateOleObject('Shell.Application');
  Folder := Shell.NameSpace(Archive);
  Folder.CopyHere(Content);
end;

The Archive parameter in the above function must be the name of an existing archive file (I've tested only ZIP archive since I don't know what other formats Windows Shell supports this way). The Content parameter can be the name of the file or folder that you want to include to the given archive file. Usage can be like this. The first call shows how to copy file to the archive, the second how to copy folder:

CopyToArchive('C:ExistingArchive.zip', 'C:FileToCopy.txt');
CopyToArchive('C:ExistingArchive.zip', 'C:FolderToCopy');

The CopyHere method also provides a set of options, by which you can refine behavior of this method. Since I'm not sure which options can be used for archives and since there's a lot of combinations, I'll just post here their translation and the way how to use them keeping their (optional) usage on you (for more information see the linked MSDN reference):

[Code]
const
  FOF_SILENT = $0004; // do not display a progress dialog box
  FOF_RENAMEONCOLLISION = $0008; // give the file being operated on a new name in a move, copy, or rename operation if a file with the target name already exists
  FOF_NOCONFIRMATION = $0010; // respond with "Yes to All" for any dialog box that is displayed
  FOF_ALLOWUNDO = $0040; // preserve undo information, if possible
  FOF_FILESONLY = $0080; // perform the operation on files only if a wildcard file name (*.*) is specified
  FOF_SIMPLEPROGRESS = $0100; // display a progress dialog box but do not show the file names
  FOF_NOCONFIRMMKDIR = $0200; // do not confirm the creation of a new directory if the operation requires one to be created
  FOF_NOERRORUI = $0400; // do not display a user interface if an error occurs
  FOF_NOCOPYSECURITYATTRIBS = $0800; // do not copy the security attributes of the file
  FOF_NORECURSION = $1000; // only operate in the local directory. Do not operate recursively into subdirectories
  FOF_NO_CONNECTED_ELEMENTS = $2000; // do not copy connected files as a group. Only copy the specified files

procedure CopyToArchive(const Archive, Content: string);
var
  Shell: Variant;
  Folder: Variant;
begin
  Shell := CreateOleObject('Shell.Application');
  Folder := Shell.NameSpace(Archive);
  // this will display the progress dialog and suppress showing errors
  Folder.CopyHere(Content, FOF_SIMPLEPROGRESS or FOF_NOERRORUI);
end;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...