0

I try to start blender.exe from inside my program (FaceModifier.exe) using QProcess (on Windows). The command follows this structure:

'path-to-blender' --background 'path-to-blend-file' --python 'path-to-python-script' -- 'additional-arg-for-python-script'

A full example (that works if I type it into cmd.exe) would be

"C:\Program Files\Blender Foundation\Blender\blender.exe" --background "C:\Program Files(x86)\FaceModifier\Resources\GenericHeadMesh.blend" --python "C:\Program Files(x86)\FaceModifier\python\local.py" -- "C:\Users\Gunnar\Documents\FaceModifier\Output\"

Now, inside my program I escape the paths and surround them with quotes so I have something like this

std::string blenderPath := "\"C:\\Program Files\\Blender Foundation\\Blender\\blender.exe\""

For QProcess I feed all my arguments into a QStringList with a leading /c so it is treated as a single command and pass it to cmd.exe.

My problem is that I can't get this to be executed. If I type the command (that I pass to QProcess, not the one from above) into cmd by hand neither.

My function that starts the process looks like this:

void PythonConnector::createSubprocess(const QStringList &args)
{
    QProcess *process = new Process();
    process->start("cmd.exe", args);
    process->waitForFinished(-1);

    QString result(process->readAll());
    qDebug() << "result: " << result;    // this gives just an empty string

    process->close();
}

I call it like this:

// for the documents path
CoInitialize(NULL);
TCHAR *myDocuments = 0;
SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &myDocuments);
CString temp(myDocuments);
CT2CA tempConv(temp);
std::string outputFolderPath(tempConv);
outputFolderPath += "\\FaceModifier\\Output\\";
outputFolderPath = pH.ExcapeString(outputFolderPath);
CoTaskMemFree(myDocuments);

blenderPath = pH.EscapeString(blenderPath);

std::string meshGlobalPath = "\"" + pH.GetResourcesPath() + "GenericHeadMesh.blend" + "\"";
std::string pythonGlobalPath = "\"" + pH.GetPythonPath() + "global.py" + "\"";

QStringList args;
args << "/c" << QString::fromStdString(blenderPath) << "--background" << QString::fromStdString(meshGlobalPath) << "--python" << QString::fromStdString(pythonGlobalPath) << "--" << QString::fromStdString("\"" + outputFolderPath "\"");
pC.createSubprocess(args);

blenderPath is passed to this function and read from registry in another function.
These are my other helper functions:

std::string PathHandler::GetResourcesPath()
{
    if(resourcesPath.empty())
        resourcesPath = GetFullPath("Resources\\");
    return resourcesPath;
}

std::string PathHandler::GetPythonPath()
{
    if(pythonPath.empty())
        pythonPath = GetFullPath("python\\");
    return pythonPath;
}

std::string PathHandler::GetFullPath(const std::string &relPath)
{
    char full[_MAX_PATH];
    _fullpath(full, relPath.c_str(), _MAX_PATH);
    return EscapeString(std::string(full));
}

std::string PathHandler::EscapeString(const std::string &input)
{
    std::regex toReplace("\\\\");
    std::string output(input.begin(), input.end());
    output = std::regex_replace(output, toReplace, "\\\\");
    return output;
}

Debugging the args list with qDebug results in these outputs (these are actually from debugging in Visual Studio 2013, therefore the different paths):

"/c"  
""C:\\Program Files\\Blender Foundation\\Blender\\blender.exe""  
"--background"  
""C:\\Users\\Gunnar\\documents\\visual studio 2013\\Projects\\FaceModifier\\x64\\Release\\Resources\\GenericHeadMesh.blend""  
"--python"  
""C:\\Users\\Gunnar\\documents\\visual studio 2013\\Projects\\FaceModifier\\x64\\Release\\python\\global.py""  
"--"  
""C:\\Users\\Gunnar\\Documents\\FaceModifier\\Output\\""

and the result debug from createSubprocess just gives "".

If I type this command into cmd by hand like this:

cmd /c "C:\Program Files\Blender Foundation\Blender\blender.exe" --background "C:\Users\Gunnar\documents\visual studio 2013\Projects\FaceModifier\x64\Release\Resources\GenericHeadMesh.blend" --python "C:\Users\Gunnar\documents\visual studio 2013\Projects\FaceModifier\x64\Release\python\global.py" -- "C:\Users\Gunnar\Documents\FaceModifier\Output\"

I get The command "C:\\Program" is either missspelled or couldn't be found. Same for various different quotings with and without escaping like this

cmd "/c \"C:\Program Files\Blender Foundation\Blender\blender.exe\" --background \"C:\Users\Gunnar\documents\visual studio 2013\Projects\FaceModifier\x64\Release\Resources\GenericHeadMesh.blend\" --python \"C:\Users\Gunnar\documents\visual studio 2013\Projects\FaceModifier\x64\Release\python\global.py\" -- \"C:\Users\Gunnar\Documents\FaceModifier\Output\\""

Just typing

cmd /c "C:\Program Files\Blender Foundation\Blender\blender.exe"

works fine, but that is obviously not what I need.

I can't wrap my head around how I have to build this so it works. Can somebody tell me what my mistake is?

UPDATE:
Ok, in theory it works now (thanks to ahmed), it really depands on the paths though. If I have the .blend and the .py in ...\Documents\FaceModifier it works, if they are in C:\Program Files (x86)\FaceModifier\ (where my program is installed) it doesn't work. How can I achieve that? I would prefer that so I don't have to copy those files over there.

Gunnar B.
  • 2,879
  • 2
  • 11
  • 17

1 Answers1

2

You don't need to quote or double quote file paths, QProccess already handle that, change this part of your code to:

std::string meshGlobalPath = pH.GetResourcesPath() + "GenericHeadMesh.blend" ;
std::string pythonGlobalPath = pH.GetPythonPath() + "global.py" ;

QStringList args;
args << "/c" << QString::fromStdString(blenderPath) << "--background" 
     << QString::fromStdString(meshGlobalPath) << "--python" 
     << QString::fromStdString(pythonGlobalPath) << "--"
     << QString::fromStdString(outputFolderPath);
ahmed
  • 5,430
  • 1
  • 20
  • 36
  • Ok, that somewhat works. I depands on where those files (.blend and .py) are. If they are in the `Program Files (x86)...` or the `documents\visual studio\...\x64\Release` I doesn't work. I guess this is related to permissions, but they are only read/executed with this command, no writing. Is there a way to get this to work so I don't have to move them over to the `output` folder? – Gunnar B. May 13 '16 at 16:37
  • did you try to run `blender.exe` directly without `cmd.exe`? – ahmed May 13 '16 at 17:59
  • 1
    Oh man, yes! QProcess starts blender directly know and I removed the `/c`, so the rest is everything starting from `--background` and it works now. Thank you very much! – Gunnar B. May 13 '16 at 18:52