1
votes

Problem

I'm trying to start an application using QProcess, however i can't figure out how to supply arguments with whitespace in them. I have tried

What i have tried

QString appPath = "\"C:/Users/USER/Google Drive/projects/qt_projects/someproject/
ghostpdl-8.71-win32/gxps-871.exe\"";

QStringList arguments;
arguments << "-sDEVICE=pdfwrite" << "-sOutputFile=\"C:/Users/USER/Google Drive/
projects/qt_projects/someproject/output.pdf\"" << "-dNOPAUSE \"C:/Users/USER/
Google Drive/projects/qt_projects/someproject/file.xps\"";

QProcess *converter = new QProcess();
converter->start(appPath, arguments);

I would think this would be the same as running the console command (Which works):

  "C:/Users/USER/Google Drive/projects/qt_projects/someproject/
  ghostpdl-8.71-win32/gxps-871.exe" -sDEVICE=pdfwrite
  -sOutputFile="C:/Users/USER/Google Drive/projects/qt_projects/
  someproject/output.pdf" -dNOPAUSE "C:/Users/USER/Google Drive/
  projects/qt_projects/someproject/file.xps"

Can anyone explain to me how i acheive this?

3

3 Answers

1
votes

The key to understanding is: there is generally no such thing as "multiple command line arguments" on Windows. The command line is passed as a single string to the receiving application. On Unices, the command line is passed as multiple arguments, so it's saner there.

The rest of this discussion is about Windows.

The splitting of commandline into strings is up to the C runtime library of the application that you pass the arguments to. This behavior is not standardized. You need to refer to the documentation of the relevant C runtime to figure out how it does the trick. Yes, it's that bad.

Are there some programs that cannot be opened with Qt?

Not at all. All that you need to know is that before starting the process, Qt is joining the argument list with a space separator. If an argument contains spaces and does not begin with nor end with '"', it will be enclosed in '"'. If an argument contains '"', they are escaped. This is done in qprocess_win.cpp, qt_create_commandline(). This is done to be compatible with MSVC runtime. An application may of course prefer to do things in its own way, and, for example, not use msvcrt at all.

0
votes

The problem here is that you're separating the arguments by splitting them into an argument list. You can do this, but you'd need just one, single argument to pass to the command, which is encapsulated in quotes.

So, let's take the console command: -

"gxps-871.exe" -sDEVICE=pdfwrite -sOutputFile="C:/Users/USER/Google Drive/projects/qt_projects/someproject/output.pdf" -dNOPAUSE "C:/Users/USER/Google Drive/projects/qt_projects/someproject/file.xps"

I've removed the path to the command, for ease of reading.

The arguments need to be seen as one argument passed to the command

So we can create an argument string, but we're going to create one argument, so add quotes...

QString arg("\"<args to go here>\"");

Now we add the arguments, which are added inside the quotes to create a single argument, but escaping all other quotes to maintain the white space...

QString arg("\"-sDEVICE=pdfwrite -sOutputFile=\"C:/Users/USER/Google Drive/projects/qt_projects/someproject/output.pdf\" -dNOPAUSE \"C:/Users/USER/Google Drive/projects/qt_projects/someproject/file.xps\"\"");

Then set the appPath...

QString appPath = "\"C:/Users/USER/Google Drive/projects/qt_projects/someproject/ghostpdl-8.71-win32/gxps-871.exe\"";

Add the argument to a QStringList..

QStringList arguments;
arguments << arg;

Start the process...

converter->start(appPath, arguments);

The argument list here, is rather unnecessary and you can do all of this in just one line: -

converter->start("\"C:/Users/USER/Google Drive/projects/qt_projects/someproject/ghostpdl-8.71-win32/gxps-871.exe\" \"-sDEVICE=pdfwrite -sOutputFile=\"C:/Users/USER/Google Drive/projects/qt_projects/someproject/output.pdf\" -dNOPAUSE \"C:/Users/USER/Google Drive/projects/qt_projects/someproject/file.xps\"\"");

But it's easy to miss a quote, or an escape for a quote and it gets rather messy, don't you think?!

0
votes

According to this this blog post QProcess internally calls createProcess. A call to createProcess from a non-elevated process fails with ERROR_ELEVATION_REQUIRED if it tries to start an executable that requires elevation.

In the blog post he solved the problem by a call to shellexecute, however i could'nt make this work either. My final solution was to use the system() function from windows.h. With system() you can execute the same command as you would from cmd.exe. Example of usage:

#include <windows.h>
...
system(""C:\\test_folder\\ghostpdl-8.71-win32\\gxps-871.exe -sDEVICE=pdfwrite -
sOutputFile=\"C:\\test_folder\\output.pdf\" -dNOPAUSE \"C:\\test_folder\\file.xps\"
");