Reputation: 435
When I use ShellExecuteEx with such a command "-unused parameter -action capturescreenshot -filename C:\\ATDK\\Screenshots\\abcd.jbg"
everything works fine and Executor.exe starts with char* argv[]
having all the approx. 9 parameters. But when the command has for a couple symbols more, e.g. file name is "abc...xyz.jpg" then that process has argc == 1 and the command is empty. So the command is OK before sending to ShellExecute After I changed that to the ShellExecute, not Ex, it works! Command can be very long, and it's passed successfully. Can anybody explain what is the difference? Here's a code with the SHELLEXECUTEINFO I filled up.
std::wstringstream wss;
wss << L"-unused" << " " // added because we need to pass some info as 0 parameter
<< L"parameter" << " " // added because EU parser sucks
<< L"-action" << " "
<< L"capturescreenshot" << " "
<< L"-filename" << " "
<< L"C:\\ATDK\\Screenshots\\abc.jpg";
SHELLEXECUTEINFO shell_info;
ZeroMemory(&shell_info, sizeof(shell_info));
shell_info.cbSize = sizeof(SHELLEXECUTEINFO);
shell_info.fMask = SEE_MASK_ASYNCOK | SEE_MASK_NO_CONSOLE;
shell_info.hwnd = NULL;
shell_info.lpVerb = NULL;
shell_info.lpFile = L"C:/ATDK/Executor";
shell_info.lpParameters = (LPCWSTR)wss.str().c_str();
shell_info.lpDirectory = NULL;
shell_info.nShow = SW_MINIMIZE;
shell_info.hInstApp = NULL;
// 1
ShellExecuteEx(&shell_info);
// this sucks,
// GetLastError returns err code 2147483658,
//FormatMessage returns The data necessary to complete this operation is not yet available
// 2
ShellExecute(NULL, NULL, L"C:/ATDK/Executor", (LPCWSTR)wss.str().c_str(), NULL, NULL);
// OK!
Upvotes: 0
Views: 494
Reputation: 51511
Your bug is here:
shell_info.lpParameters = (LPCWSTR)wss.str().c_str();
wss.str()
returns a temporary object, that no longer exists after the end of the full expression in which it is created. Using it after that point is undefined behavior.
To solve this you will have to construct a std::wstring
object, that lives long enough for the call to ShellExecuteEx
to return.
std::wstringstream wss;
wss << L"-unused" << " "
<< L"parameter" << " "
// ...
SHELLEXECUTEINFO shell_info;
ZeroMemory(&shell_info, sizeof(shell_info));
// Construct string object from string stream
std::wstring params{ wss.str() };
shell_info.cbSize = sizeof(SHELLEXECUTEINFO);
shell_info.fMask = SEE_MASK_ASYNCOK | SEE_MASK_NO_CONSOLE;
shell_info.hwnd = NULL;
shell_info.lpVerb = NULL;
shell_info.lpFile = L"C:\\ATDK\\Executor"; // Path separator on Windows is \
shell_info.lpParameters = params.c_str(); // Use string object that survives the call
shell_info.lpDirectory = NULL;
shell_info.nShow = SW_MINIMIZE;
shell_info.hInstApp = NULL;
ShellExecuteEx(&shell_info);
Note that your second call
ShellExecute(NULL, NULL, L"C:\\ATDK\\Executor", wss.str().c_str(), NULL, NULL);
reliably works. Even though wss.str()
still returns a temporary, it is valid until the end of the full expression (i.e. throughout the function call).
Upvotes: 5