Reputation: 2989
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.
Upvotes: 0
Views: 575
Reputation: 5590
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);
Upvotes: 2