Reputation: 43477
Consider the following code and its executable - runner.exe
:
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
int main(int argc, char *argv[])
{
SHELLEXECUTEINFO shExecInfo;
shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
shExecInfo.fMask = NULL;
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = "open";
shExecInfo.lpFile = argv[1];
string Params = "";
for ( int i = 2; i < argc; ++i )
Params += argv[i] + ' ';
shExecInfo.lpParameters = Params.c_str();
shExecInfo.lpDirectory = NULL;
shExecInfo.nShow = SW_SHOWNORMAL;
shExecInfo.hInstApp = NULL;
ShellExecuteEx(&shExecInfo);
return 0;
}
These two batch files both do what they're supposed to, which is run notepad.exe and run notepad.exe and tell it to try to open test.txt:
1.
runner.exe notepad.exe
2.
runner.exe notepad.exe test.txt
Now, consider this batch file:
3.
runner.exe runner.exe notepad.exe
This one should run runner.exe and send notepad.exe as one of its command line arguments, shouldn't it? Then, that second instance of runner.exe should run notepad.exe - which doesn't happen, I get a "Windows cannot find 'am'. Make sure you typed the name correctly, and then try again" error. If I print the argc
argument, it's 14 for the second instance of runner.exe, and they are all weird stuff like Files\Microsoft, SQL, Files\Common and so on. I can't figure out why this happens. I want to be able to string as many runner.exe calls using command line arguments as possible, or at least 2. How can I do that?
I am using Windows 7 if that makes a difference.
Upvotes: 0
Views: 2418
Reputation: 111130
I think the problem is how you create the command line parameters for your next call:
Params += argv[i] + ' ';
does not work as expected. Try the following out:
#include <windows.h>
#include <fstream>
#include <iostream>
#include <tchar.h>
using namespace std;
#ifdef _UNICODE
typedef std::wstring tstring;
#else
typedef std::string tstring;
#endif
int _tmain(int argc, TCHAR *argv[])
{
{
std::ofstream f("C:\\output.txt", std::ios::app);
f << "app called" << std::endl;
}
SHELLEXECUTEINFO shExecInfo;
shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
shExecInfo.fMask = NULL;
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = _T("open");
shExecInfo.lpFile = argv[1];
tstring Params(_T(""));
for ( int i = 2; i < argc; ++i )
{
Params += argv[i];
Params += _T(' ');
}
shExecInfo.lpParameters = Params.c_str();
shExecInfo.lpDirectory = NULL;
shExecInfo.nShow = SW_SHOWNORMAL;
shExecInfo.hInstApp = NULL;
ShellExecuteEx(&shExecInfo);
return 0;
}
Upvotes: 1
Reputation: 76541
The problem is this line:
Params += argv[i] + ' '
Because argv[i]
is of type char *
that adding 32 to argv[i]
so will give you a pointer to the middle of random memory.
I would rewrite that to:
Params += std::string(argv[i]) + ' ';
Or if you wanted to be real good, you can modify that to only add a space when it's really necesssary:
for ( int i = 2; i < argc; ++i )
{
if (!Params.empty())
Params += ' ';
Params += argv[i];
}
Upvotes: 1
Reputation: 110108
You have a bug in this line:
Params += argv[i] + ' ';
This will add 32 to the pointer argv[i]
, which isn't what you want. You can separate it to two lines:
Params += argv[i];
Params += ' ';
Or use:
Params += string(argv[i]) + ' ';
You may also want to add quotes around each parameter in case it contains spaces.
I'd also set fMask
to SEE_MASK_NOASYNC
, because MSDN states:
Applications that exit immediately after calling ShellExecuteEx should specify this flag.
Upvotes: 3