This content has been marked as final. Show 11 replies
AH HA!<br /><br /><light bulb goes off><br /><br />Is this on Windows?<br /><br />Windows, by default, strips the ampersand character from most (all?) control titles. In Windows-speak, the ampersand means that the following character is an accelerator.<br /><br />Try substituting a double-&& where the single & exists in the string. In other words ...<br /><br />local s='Black&&White'<br />LrDialogs.message("Display s",s,'info')
Thanks for the note. That explained part of the issue. I can now display the ampersand on the screen, but no in the actual place I want. I am, basically, passing a string like C:\Program Files\blabla\Black&White\run.exe to LrTasks.execute and it never gets run.
I am spitting out the command to a log file and it seems the right path. What I am currently doing as a work around is having a small java program that gets a commmand line argument and runs that in shell. The java bridge works, but I would like to remove as much garbage as possible.
I suspect your problem is that you need to escape the space in C:\Program Files\...
Actually, I am putting the whole string in "", so I doubt the problem can be space.
local r,msg=LrTasks.execute( cmd )
Logger.logf("Done launching DS, ret was %d", r)
Logger.logf("reason, %s", msg)
The logger sends "C:\Program Files\....\somefile.exe"; which means I should be fine there. However, I think someting may be going on under the hood with LrTasks implemenatio when it tries to get the command string passed to it.
This is getting to be quite the walk in the wilderness, isn't it?
To say that the Windows team chose some shell unusual escaping patterns would be a major exercise in understatement. Unfortunately, cmd.exe doesn't respond to quotes around the path name when you pass it in through the OS. The interactive shell behaves differently than the underlying OS call.
In this case, you need to replace space with up-arrow+space ("^ "). Why? Who knows ...
The following code is excerpted from the site where Lightroom calls out for post-processing actions:
local function shellEscape_str( param, escapeSpacesOnWin )
if WIN_ENV then
-- Windows cmd.exe has some truly goofy shell-escaping techniques. *sigh*
param = param:gsub( '%^', '^^' )
param = param:gsub( '&', '^&' )
param = param:gsub( '|', '^|' )
param = param:gsub( '%(', '^(' )
param = param:gsub( '%)', '^)' )
param = param:gsub( '<', '^<' )
param = param:gsub( '>', '^>' )
if param:find( ' ' ) then
if escapeSpacesOnWin then
param = param:gsub( ' ', '^ ' )
param = param:gsub( '"', '""' ) -- " (make Mac syntax colorizer happy)
param = string.format( '"%s"', param )
param = param:gsub( '\\', '\\\\' )
param = param:gsub( ' ', '\\ ' )
param = param:gsub( '%*', '\\*' )
param = param:gsub( '#', '\\#' )
param = param:gsub( '"', '\\"' )
param = param:gsub( "'", "\\'" )
param = param:gsub( '%$', '\\$' )
param = param:gsub( '|', '\\|' )
param = param:gsub( '&', '\\&' )
param = param:gsub( '%?', '\\?' )
param = param:gsub( ';', '\\;' )
param = param:gsub( '~', '\\~' )
param = param:gsub( '%(', '\\(' )
param = param:gsub( '%)', '\\)' )
param = param:gsub( '<', '\\<' )
param = param:gsub( '>', '\\>' )
param = param:gsub( '!', '\\!' )
param = param:gsub( '%^', '\\^' )
This gets passed to LrTasks.execute (OK, our internal variant of that) with roughly the following sequence:
LrTasks.execute( "cmd /c " .. shellEscape_str( pathToApplication, true ) .. " " .. otherArgs )
-- otherArgs is formed by calling shellEscape_str( path, false ) on the file paths you want to pass to the app.
(This isn't the exact code, but a rough paraphrase of it.)
BTW, the blue emoticon :( in the above code snippet is supposed to be percent, left-paren
: ( without the space
Thanks Erick. Lots of characters to watch out for.
I had incredible trouble trying to get LrTasks.execute to launch an app successfully, i.e. it never worked. Finally, the technique I used that succeeded was to use cmd.exe's "start" command. The shell escaping seems to be interpreted differently there. An added benefit of going this route is that even though Lightroom launches a hidden shell window, the start command launches a new one that lets you see command output that may be useful for debugging. If you want to hide this new window, just pass /B as an argument. Keep in mind that the "start" command is asynchronous so more than likely you'll need to also use the /WAIT option. You may also need to pass a dummy value for the window title that "start" expects. The command ends up looking like this for debug mode:
start /WAIT "dummy title" myapp.exe
and for non-debug mode:
start /B /WAIT "dummy title" myapp.exe
In my app, myapp.exe is actually a quoted string that looks like this, no need for funky escapes:
That is very interesting. I have only used start to open a file in its default application!
For my case here, I am launching a GUI application so some of the args does not apply, but still getting rid of the escaping is a big plus.
@Eric: your former post was very useful as it takes into account all the possibilities, not just &. Thanks.
I wonder if it would be useful to expose the shellEscape function to the SDK so that we can all make use of consistent and correct escaping that Lr has already worked out. My hunch is that peoples' intuition with LrTasks.execute() on Windows is that arguments are being passed directly to CreateProcess and not within a shell as Lr does (i.e. prefixed by "cmd.exe /c"). That would mean that users' instincts for debugging escaping problems aren't quite accurate.
Good suggestion, thanks.