I need help with my simple program, which tries to create a new process running Speech recognition.
When I open cmd and type in the command C:\Windows\Speech\Common\sapisvr.exe -SpeechUX then the speech recognition would successfully start. It will start even when running through system(C:\\Windows\\...) which basically just mimics cmd.
However, when creating the new process with CreateProcess() as below, the function fails. If I put whole path and argument into second parameter CreateProcess(NULL, TEXT("C:\\Windows...\\sapisvr.exe -SpeechUX"), ...), then I get a runtime exception: Access violation writing location
#include <windows.h>
int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(
TEXT("C:\\Windows\\Speech\\Common\\sapisvr.exe"), //Module name
TEXT(" -SpeechUX"), //command line params
NULL, //Process attributes
NULL, //Thread attributes
FALSE, //Handle inheritance
0, //No creation flags
NULL, //Use parent's environment
NULL, //Use parent's starting directory
&si, //Pointer to STARTUPINFO structure
&pi )) //Pointer to PROCESS_INFORMATION structure
{
printf("error creating process\n");
return 1;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
First I tried to test CreateProcess function with running notepad with an argument to open an existing file. When I put path to notepad.exe to first parameter and name of the file to the command line parameter, it didn't recognise it and opened a new file instead.
This whole applies as well to trying to run msconfig.exe from my program, which doesn't take any parameters, so I guess the problem is somewhere else, I just have no idea where.
I searched the web and none of the answers actually worked for me. I'm working in Visual Studio 2015 on Windows 8.1.
Thanks for help.
The CreateProcess function has a second argument as an LPTSTR. For the CreateProcessW version of this function, this must be a writeable buffer, not a string literal. Thus your program's behavior is undefined. Since you are getting an access violation writing to a location when calling CreateProcess, we will assume that CreateProcess is being mapped to CreateProcessW.
At the link posted, here is the quote:
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
So the fix is simply define an array, not a literal:
TCHAR commandParam[] = TEXT(" -SpeechUX");
if (!CreateProcess(TEXT("C:\\Windows\\Speech\\Common\\sapisvr.exe"),
commandParam,
...
}
or if passing NULL as the first argument:
TCHAR commandParam[] = TEXT("C:\\Windows\\Speech\\Common\\sapisvr.exe");
//...
if (!CreateProcess(NULL, commandParam, ...
Also, if CreateProcess returns an error, you should call GetLastError and optionally FormatMessage, to get the error that occurred, and not simply output that there is an error.
Related
I am trying to use the CreateProcess() function in order to launch an .exe application that is in a folder in my root directory (the directory where my VS solution is). Seems simple right? It probably is but I can't for the life of me notice what I have done wrong. Every time I try to launch the .exe I get the error message "CreateProcess failed code 2" which means that the .exe file I am trying to launch cant be found.
My code:
void HavNetProfiler::LaunchClumsy()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess((LPCTSTR)"Clumsy\\clumsy.exe", // No module name (use command line)
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Am I using this function wrong? Have I misunderstood how it works or have I simply missed some minor detail? I am calling the function LaunchClumsy() in a file that is placed in a different folder (that folder exists in the root folder just like the "Clumsy" folder though). Would that make a difference?
Thanks!
There are 2 immediate bugs in the code:
The LPCTSTR cast is wrong. If your code does not compile without that cast, you have passed an argument with the wrong character encoding. Change it to L"Clumsy\\clumsy.exe" to explicitly pass a wide-character string.
Using a relative path is very likely to fail. The system searches starting from the current working directory. That is a process-wide property, that can be altered by any thread, at any time. Use an absolute path instead.
Like in the following example I'm trying to start Googles Chrome browser from a Windows application using the Windows API function CreateProcess.
The problem I have is that I dont know the path to the Chrome application (or any other application in the Program path). How can I get this?
In the code below I commented three different examples. In case I start "calc", the Calculator is started as it is in the Windows/System32 path. In case I start Chrome with the full path to the application it runs too. But if I omit the path and just try to start "chrome" I get an error #2.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain()
{
char* cmd = "calc"; // works... calc.exe is in windows/system32
// char* cmd = "chrome"; // doesn't work... how can I add the path if it's not known (e.g. windows installed on D:\)
// char* cmd = "c:/program files (x86)/google/chrome/application/chrome"; // works (even without extension .exe)
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
cmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Note: if I enter "chrome" (without the quotes) in the Windows Run command window, Chrome starts too. What I'm looking for is the same functionality. However, my application can reside anywhere and is not necessarily located on the same drive as Chrome.
If you really must use CreateProcess then you will need to find out where it is installed and pass the full path to the executable. That's going to require some registry hacking.
However, I feel that there is an easier and more robust way. Chrome registers itself in the AppPaths registry so ShellExecuteEx with the file specified as L"chrome" and the default verb will do the job.
This is likely to be unrelated to WinAPI and the CreateProcess function, but only to the environment variable PATH. By default, it contains the path for all standard windows commands like calc or notepad, but you must add the path for other commands that you add later, be it under Program Files or anywhere else.
What to do:
carefully note the actual path of chrome
open Control Panel / System / Advanced system parameters
click Environment variables: you will find a PATH (case does not matter) in user and system variables.
add the path for chrome on one (system is meant meant for all users)
It should now be possible to launch chrome without specifying its full path.
NB: unsure for the actual labels for all of the above, my own box speaks french...
I want to use CreateProcess() to execute an ADB command that launches an application/activity. It works using the simpler system(command) function, but I want to eliminate the creation of the command line window by system(). Below is what I have right now. I have tried using different CreateProcess()es, like CreateProcessW and CreateProcessA, but to no avail.
char prog[] = "C:\\Program Files\\Android\\sdk\\platform-tools\\platform-tools\\adb.exe";
char args[] = "adb shell am start -a android.intent.action.MAIN -n com.example.dmiller.myapplication/.Blankscreen";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CreateProcess((LPCWSTR)prog, (LPWSTR)args, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
I got this partially from this answer How to use createprocess to execute adb program in PATH? but when the command should be executed in my program, nothing happens (when running system(cmd.c_str()), the appropriate app is launched on the attached device). Could anyone provide some help? Alternative methods are welcome as well.
UPDATE: I have applied some things from the below post to try to provide a better question. Code has been updated to my latest version.
CreateProcess doesn't pass command line arguments
Type-casting a char array to have type LPCWSTR doesn't make it so. The former is an array of one-byte characters. The latter is (a pointer to) an array of two-byte characters. The type cast tells the compiler that the one is really the other, and the compiler trusts you. It does not perform a conversion.
To fix this, declare prog and args to have type WCHAR or wchar_t instead of char, and use the L prefix on the literals:
WCHAR prog[] = L"...";
WCHAR args[] = L"...";
Then you can remove the LPCWSTR type casts because they won't be necessary anymore.
As usual, whenever you call an API function, it's wise to check the return value and look for any error codes. The documentation advises that you should check whether the function returns zero. If it does, call GetLastError to find out what the OS thinks the problem was.
I'm trying to create a function which opens a PDF in firefox separate from the main process. I believe I am having trouble with the parameters for createProcess... any help is greatly appreciated
EDIT: the batch file is being created, I have tested it several times, and to explain a bit:
The batch file is because I really don't know what I am doing, I am a student in computer science and this is a side project to help me at my job. I work at a law office and file the mail electronically as it comes in. I wanted to make a simple program that would loop through the scans directory, display the scan and prompt the user for information about the document. Therefore I need to be able to build a file path dynamically. Originally I was using "system" to open firefox and display the document. After a bit of trying I got it to work with a batch file. I then learned that system is a blocking command and that I would need to start a separate thread. This is where I ran into createprocess. I simply continued to use the batch file from my old system idea... And the more I think about it I can't remember which professor suggested the batch file or why...
void openPDF(char scansQueue[][MAX_NAME], int index)
{
// build bat file
fstream outfile;
outfile.open("C:\\firefox.bat");
if(outfile.good())cout<<"outfile good!!!!"<<endl;
outfile<<"\"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe\" \"C:\\Scans\\" <<scansQueue[index]<<"\"";
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if(!CreateProcess(NULL, L"C:\\firefox", NULL, NULL, false, 0, NULL, NULL, &si, &pi))cout<<"PROCESS FAILED TO EXECUTE!!!";
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
There are several problems with this code. A few has already been pointed out in the comments (closing potentially invalid handles on failure, possibility that the batch file can't be created, and the rather questionable command line). Here's a few more issues.
First, you can't run a batch file this way.
The documentation for CreateProcess clearly states:
To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.
Second, you are passing a string literal for lpCommandLine, something that's also explicitly outlawed by the documentation:
lpCommandLine [in, out, optional]
...
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
Finally, why are you creating a temporary batch file to run a single command? You could easily have written the CreateProcess call to start Firefox directly.
I am trying to create a program that calls another process using CreateProcess. After some problems, I change my program to just open a known program:
if( !CreateProcess( (LPWSTR)"C:\\Program Files\\Opera\\Opera.exe", // No module name (use command line)
NULL, ,
// Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
I found this example in msdn, but every time I run my program, windows (Vista) shows a error msg: The program stop running...
Does anybody know what is the problem?
Regards,
Leandro Lima
This line is wrong:
(LPWSTR)"C:\\Program Files\\Opera\\Opera.exe"
LPWSTR is a typedef for wchar_t*. So you're casting a plain string (array of chars, which will decay to a const char*) to a wchar_t*. The end result is likely not even null-terminated!
Either use CreateProcessA and drop the cast, or use a wide string:
L"C:\\Program Files\\Opera\\Opera.exe",