Need some help with a rar (etc) -> 7zip convert button

The button below does what it should.. except it does all the extraction first, then packs all the extracted files once for each file selected.

What I expect it to do, is to run ALL commands in the button once for each selected file, not each line for each selected file.

I have tried every modifier I could find which might do what I want,
but no luck.

So far I have this (I use the gui versions of both archivers, the advantage is that it supports more formats to extract from, as opposed to the commandline version of rar):

Suggestions? or hopefully, a solution?

<?xml version="1.0"?> Convert to 7-Zip Convert to 7-Zip #newcommand CreateFolder /temp/tmpcnv @nofilenamequoting @sync:"c:\program files\winrar\winrar.exe" x "{filepath$}" "{alias|temp}\tmpcnv\" @sync:cd "{alias|temp}\tmpcnv\" @sync:"c:\program files\7-zip\7zg.exe" a -t7z -mx9 -r "{sourcepath}\{file$|nopath|noext}.7z" *.* @sync:cd "{sourcepath}" delete quiet force "{alias|temp}\tmpcnv" @useactivelister

The intention with this button is to introduce a missing function for 7zip,
the ability to convert from other archivetypes to its own (similar to what winrar can do).

You see I have some sync statements there.. I have tried this with and without it, no difference.
Same with using @norunbatch, @runbatch, @runonce, @firstfileonly and so on.

Is there any way to handle errors from external programs in a button?

I also noticed that @set doesn't expand dopus variables, eg @set test={sourcepath} makes {$test} contain {sourcepath}, not the sourcepath itself.
Is this correct behaviour, or am I doing something wrong.

I see buttons also supports the @script modifier, but there isn't any way to pass variables from dopus to a script.. or anything else really.. same seems true with the opposite. Only partially developed so far?

I ask all these questions because I've encountered them all while trying to
get this one to work as it should.

I've checked the reference rather thoroghly, but these questions doesn't seem to find any answer there.

Rather a bit drunk at the moment... so can't/won't work out if there's some other simple syntax changes to your button that would easily make this work the way you'd like... buuuuuuut:

Would you be opposed to just using another tool like IZArc to do the conversion? they have the function built-in, and unlike WinRAR it's free...

[quote="steje"]
Would you be opposed to just using another tool like IZArc to do the conversion? they have the function built-in, and unlike WinRAR it's free...[/quote]

Well, yes and no.. I own a lifetime license to winrar, and have 7-zip installed, so there isn't any cost for me.
Just another mostly unnecessary tool to install I guess.

However, In addition to needing the function, one of the reasons I started with this is to "get to know" DO, especially how to create something more than a oneliner.

It isn't so straightforward as I initially thought though, as DO runs the first command for all selected files, then the second, etc, instead of looping the commands for each selected file.

You could do it using a vbScript. Create a button like this:

<?xml version="1.0"?>
<button backcol="none" display="both" textcol="none">
	<label>Execute Script</label>
	<tip>Execute Script</tip>
	<icon1>#newcommand</icon1>
	<function type="normal">
		<instruction>@nofilenamequoting </instruction>
		<instruction>@sync:WScript.exe &quot;C:\Program Files\GPSoftware\Directory Opus\Scripts\DoIt.vbs&quot; &quot;{filepath$}&quot;</instruction>
		<instruction>@useactivelister </instruction>
	</function>
</button>

Then create a "DoIt.vbs" file in "C:\Program Files\GPSoftware\Directory Opus\Scripts", which looks like this:

Set objShell = CreateObject("WScript.Shell")
Set objFS = CreateObject("Scripting.FileSystemObject")

strSourceFolder = objFS.GetParentFolderName(WScript.Arguments.Unnamed.Item(0))
strFileName = objFS.GetFileName(WScript.Arguments.Unnamed.Item(0))
strFileNameNoExt = Left(strFileName, InStrRev(strFileName, ".") - 1)

If LCase(Right(strFileName, 4)) <> ".rar" Then
	WScript.Quit 1
End If

intRetVal = objFS.CreateFolder("C:\Temp\Unzipped")

intRetVal = objShell.Run("c:\program files\winrar\winrar.exe x """ & WScript.Arguments.Unnamed.Item(0) & """ C:\Temp\Unzipped", 1, True)
intRetVal = objShell.Run("c:\program files\7-zip\7zg.exe a -t7z -mx9 -r """ & strSourceFolder & "\" & strFileNameNoExt & ".7z C:\Temp\Unzipped\*.*", 1, True)

intRetVal = objFS.DeleteFolder("C:\Temp\Unzipped", True)

WScript.Quit 0

I couldn't test the script because I don't hae 7zip installed. It could appear, that the objShell.Run calls need to be modified in some way to work properly.

...just as a workaround.

W@ng

This might work, though I haven't tried it (don't have WinRAR.exe):

<?xml version="1.0"?> <button backcol="none" display="label" textcol="none"> <label>Convert to 7-Zip</label> <tip>Convert to 7-Zip</tip> <icon1>#newcommand</icon1> <function type="batch"> <instruction>@nofilenamequoting </instruction> <instruction>mkdir &quot;{alias|temp}\tmpcnv&quot;</instruction> <instruction>&quot;c:\program files\winrar\winrar.exe&quot; x &quot;{filepath$}&quot; &quot;{alias|temp}\tmpcnv\{file$|noext}&quot;</instruction> <instruction>cd &quot;{alias|temp}\tmpcnv\&quot;</instruction> <instruction>&quot;c:\program files\7-zip\7zg.exe&quot; a -t7z -mx9 -r &quot;{sourcepath}\{file$|nopath|noext}.7z&quot; &quot;{file$|noext}\*.*&quot;</instruction> <instruction>rmdir /Q /S &quot;{alias|temp}\tmpcnv&quot;</instruction> </function> </button>

I changed the button type to MS-DOS (to simplify things) and the command to:

@nofilenamequoting mkdir "{alias|temp}\tmpcnv" "c:\program files\winrar\winrar.exe" x "{filepath$}" "{alias|temp}\tmpcnv\{file$|noext}" cd "{alias|temp}\tmpcnv\" "c:\program files\7-zip\7zg.exe" a -t7z -mx9 -r "{sourcepath}\{file$|nopath|noext}.7z" "{file$|noext}\*.*" rmdir /Q /S "{alias|temp}\tmpcnv"

This extracts each file into its own directory, then compresses each of those into .7z files. Only problem is you'll probably end up with an unwanted subdirectory at the top of the .7z files. (Maybe the 7z commandline provides a way to prevent that? I'm not familiar enough with it.)

If that's no good then I think you'll need to go with W@ng's idea of passing the filename to a separate Opus User Command, or a VBScript, or a DOS batch file which does the work. Opus will always run each line of a command in turn for all filenames before moving on to the next line. That usually makes sense but there are cases like this one where it gets in the way. If you need a sequence of commands to be run for one filename before moving on to the next filename then you have to move that sequence into something else to make it happen.

If it's an MS-DOS type of button then you can use the usual DOS batch commands for that, but keep in mind that strange things will happen if you mix in any Opus commands. (Behind the scenes, Opus splits the batch up into smaller batch files every time it has to run an Opus command, so conditional logic and loops will be broken.)

For non-DOS scripts there isn't any way to handle errors. Opus commands don't have any branching or conditional logic. (That's not quite true. You can make them do different things when Ctrl/Alt/Shift are held down but that's not relevant here.)

Essentially, if you want to do anything complex with conditional logic you are often better off writing a VBScript which you run from Opus, using Opus to pass in arguments like lists of selected files, source and destination directories, and so on.

(If you need to pass a lot of selected files then you can avoid command-line length limits by using the filem modified. For example, {allfilepath|filem} will write all the selected file paths into a temporary file and then pass the name of the temporary file to the program/script.)

It works fine here. This button will echo the source path, not "{sourcepath}":

<?xml version="1.0"?> <button backcol="none" display="both" textcol="none"> <label>Test</label> <icon1>#selectwild</icon1> <function type="batch"> <instruction>@set test = {sourcepath}</instruction> <instruction>echo {$test}</instruction> <instruction>pause</instruction> </function> </button>

I think (not completely sure) that the @script modifier is only useful with Rename buttons at the moment.

To pass variables from Opus to a script just use the command line. Here's an example script written to be called from Opus:

[One Hotkey for 2 commands)

This wasn't really obvious, and didn't find any information about how
it runs a button command in the reference, and it probably should be documented as it is rather unusual.

I got my button to work however.. What really is necessary of all these
quotes etc I don't know, but at last it works.

<?xml version="1.0"?>
<button backcol="none" display="icon" textcol="none">
	<label>CONVERTTO7Z</label>
	<tip>Convert Archive to 7Zip</tip>
	<template>FNAME,DESTNAME</template>
	<icon1>#usercommand</icon1>
	<function type="normal">
		<instruction>CreateFolder /temp/tmpcnv</instruction>
		<instruction>@nofilenamequoting</instruction>
		<instruction>@useactivelister</instruction>
		<instruction>@sync:&quot;c:\program files\winrar\winrar.exe&quot; x &quot;&amp;FNAME&amp;&quot; &quot;{alias|temp}\tmpcnv\&quot;</instruction>
		<instruction>@sync:cd &quot;{alias|temp}\tmpcnv\&quot;</instruction>
		<instruction>@sync:&quot;c:\program files\7-zip\7zg.exe&quot; a -t7z -mx9 -r &quot;&amp;DESTNAME&amp;&quot; *.*</instruction>
		<instruction>@sync:cd &quot;{sourcepath}&quot;</instruction>
		<instruction>delete quiet force &quot;{alias|temp}\tmpcnv&quot;</instruction>
	</function>
</button>


<?xml version="1.0"?>
<button backcol="none" display="label" textcol="none">
	<label>Convert to 7-Zip</label>
	<tip>Convert to 7-Zip</tip>
	<icon1>#newcommand</icon1>
	<function type="normal">
		<instruction>@nofilenamequoting </instruction>
		<instruction>@useactivelister</instruction>
		<instruction>CONVERTTO7Z &quot;{filepath$}&quot; &quot;{sourcepath}\{file$|nopath|noext}.7z&quot;</instruction>
	</function>
</button>

This will extract any winrar supported format to wintempdir\tempcnv, then 7zip it with ultra compression, then remove the tmpcnv temporary directory/folder.

So far at least.. No guarantees..

If it's an MS-DOS type of button then you can use the usual DOS batch commands for that, but keep in mind that strange things will happen if you mix in any Opus commands. (Behind the scenes, Opus splits the batch up into smaller batch files every time it has to run an Opus command, so conditional logic and loops will be broken.)

For non-DOS scripts there isn't any way to handle errors. Opus commands don't have any branching or conditional logic. (That's not quite true. You can make them do different things when Ctrl/Alt/Shift are held down but that's not relevant here.)

Essentially, if you want to do anything complex with conditional logic you are often better off writing a VBScript which you run from Opus, using Opus to pass in arguments like lists of selected files, source and destination directories, and so on.

(If you need to pass a lot of selected files then you can avoid command-line length limits by using the filem modified. For example, {allfilepath|filem} will write all the selected file paths into a temporary file and then pass the name of the temporary file to the program/script.)
[/quote]

Good to know.. Sometimes errorhandling is essensial.

Apparently variables cant be expanded when used with {dlgchoose} and probably partners.

This works fine: {dlgchoose|{sourcepath}|1}
This doesn't work: {dlgchoose|{$test}|1}

It do work where it matters most, only can't use those in dialogs.

[quote="nudel"]

I think (not completely sure) that the @script modifier is only useful with Rename buttons at the moment.

To pass variables from Opus to a script just use the command line. Here's an example script written to be called from Opus:

[One Hotkey for 2 commands)[/quote]

Thank you for the info..
I hope they make real scripting in DO more usable in a future version though.