2

How does one pass the command line arguments of the current process to a QProcess, ideally avoiding any conversions? I.e. whatever "junk" was passed to the current process is supposed to be passed to the sub-process, without the fallout of conversions between char*, wchar_t and QString.

The question is motivated by this answer.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313

1 Answers1

2

Windows

The native command line returned by GetCommandLine() is a wchar_t array that begins with the executable name/path. QProcess has the setNativeArguments method available on Windows, and that method can be used to append the arguments part of the command line. The main job is then to parse the command line to find the beginning of the arguments:

QString getWindowsCommandLineArguments() {
   const wchar_t *args = GetCommandLine();
   bool oddBackslash = false, quoted = false, whitespace = false;
   // skip the executable name according to Windows command line parsing rules
   while (auto c = *args) {
      if (c == L'\\')
         oddBackslash ^= 1;
      else if (c == L'"')
         quoted ^= !oddBackslash;
      else if (c == L' ' || c == L'\t')
         whitespace = !quoted;
      else if (whitespace)
         break;
      else
         oddBackslash = false;
      args++;
   }
   return QString::fromRawData(reinterpret_cast<const QChar*>(args), lstrlen(args));
}

Then:

QProcess process;
process.setNativeArguments(getWindowsCommandLineArguments());

Other Platforms

The equivalent to setNativeArguments is not available on other platforms, thus the best we can do is to pass the arguments via a QString roundtrip. This will work fine as long as the arguments are valid in the current 8-bit encoding. The arguments must be captured at the beginning of main, because Qt may remove the arguments it interprets itself:

QStringList &setProcessArguments() {
   static QStringList args;
   return args;
} 
const QStringList &processArguments() { return setProcessArguments(); }
int main(int argc, char **argv) {
   setProcessArguments().reserve(argc-1);
   for (int i = 1; i < argc; ++i)
      setProcessArguments().append(QString::fromLocal8Bit(argv[i]));

   QCoreApplication app{argc, argv}; // may modify argc, argv
   ...
}

QProcess process;
process.setArguments(processArguments());
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313