So I used this code in order to start a console application with arguments:
#include <iostream>
#include <windows.h>
using namespace std;
void StartProgram(char argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CreateProcess
(
TEXT("PlayerDebug.exe"),
(LPSTR)argv,
NULL,NULL,FALSE,
CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW,
NULL,NULL,
&si, &pi
);
};
int main()
{
StartProgram("sound.wav");
return 0;
}
"PlayerDebug.exe" display the arguments used to call it. But when I run it with CreateProcess the way I showed, it doesen't display anything. I checked and in Task Manager it seems to appear, but still does not display the arguments. I also tried to write cout << argv; in function void StartProgram(char argv[]) and it returned "sound.wav", which is correct. But it seems the argument is not passed to PlayerDebug.exe and I don't know why.
What I did wrong?
(I'm new at C++ programming)
The second parameter to CreateProcess is the full command line, not just the parameters to the EXE. Lets take two examples :
CreateProcess ("c:\\notepad.exe",
"c:\\notepad.exe c:\\wibble.txt",
...);
will work fine (if there is a copy of notepad.exe and a file called wibble.txt in the root of C:), whereas
CreateProcess ("c:\\notepad.exe",
"c:\\wibble.txt",
...);
will launch the EXE but fail to open the file. What this means is that when the help systems calls the second parameter the command line, it ain't lying - it wants the whole command line.
Note that you can use NULL as the first parameter if the whole command line is in the second param. That's how I normally use it in fact.
Related
I have a function that is supposed to launch another process:
DWORD WINAPI StartCalc(LPVOID lpParam) {
STARTUPINFOW info;
PROCESS_INFORMATION processInfo;
std::wstring cmd = L"C:\\Windows\\System32\\calc.exe";
BOOL hR = CreateProcessW(NULL, (LPWSTR)cmd.c_str(), NULL, NULL, TRUE, 0, NULL, NULL,
&info, &processInfo);
if (hR == 0) {
DWORD errorMessageID = ::GetLastError();
printf("Error creating process\n");
return 1;
}
return 0;
}
I get an exception in ntdll.dll "Access violation reading location 0xFFFFFFFFFFFFFFFF". I know there are a few common mistakes that might cause this:
Inconsistent calling conventions. I am using __stdcall
Encoding issues. I storing strings as wide chars
The problem happens in both x64 and x86 builds
The problems happens when I try to create other Windows processes
What am i doing wrong?
EDIT: This actually isn't a problem with casting cmd.c_str() as a (LPWSTR), that part appears to be fine. I needed to initialize the STARTUPINFO struct: STARTUPINFO info = { 0 };
BOOL hR = CreateProcessW(NULL, (LPWSTR)cmd.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo);
^^^^^
That's a cast. A great rule of thumb is "spot the cast, you spot the error".
It's true here. CreateProcessW must be passed a writable string. That means, no literal, and also no c_str() result.
From the documentation:
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.
Pass a real non-const pointer, don't play hide-the-const. &cmd[0] should work, that's guaranteed to be a writable string. To be super-safe, increase your wstring capacity beyond just what you needed, because CreateProcessW is going to use it as a working buffer.
I'm writing a game. When it starts up, I want to call the Windows 10 GetCurrentPackageFullName() function to see if my app is running as a Universal Windows Program or not.
However, GetCurrentPackageFullName() does not exist in Windows 7 and earlier, so when people run my game on their systems, they get this error:
Is there a way to avoid this error by first checking if the function even exists in kernel32.dll and if not then simply not call it? I've tried the following but it doesn't seem to work:
try {
//do we even have this function?
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
PGNSI pGNSI;
SYSTEM_INFO si;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
pGNSI = (PGNSI) GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetCurrentPackageFullName");
//ok this exists, now let's use it
if(pGNSI != NULL) {
//then I call the function here
}
} catch (int e) {
//do nothing, just don't crash
}
Using GetProcAddress() and not calling the function if NULL is the correct solution.
I think there are two problems:
You should call LoadLibrary() instead of GetModuleHandle().
Where you have the comment //then I call the function here, I suspect that you are still calling the GetCurrentPackageFullName() function statically. You need to call the function via the pGNSI pointer instead so you won't have the function statically linked into the program.
Consider two C++ projects:
Project 1:
// projectOne.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
Sleep(5000);
system("projectTwo.exe");
return 0;
}
Project 2:
// projectTwo.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
Sleep(5000);
system("projectOne.exe");
return 0;
}
The behavior I seek is: projectOne starts => start projectTwo => projectOne ends => projectTwo will start projectOne => projectTwo ends => projectOne will start projectTwo.
However, the programs are not ending. For example, when projectOne starts projectTwo, it will not end projectOne when return 0; is run within projectOne. So after a few minutes, there will be multiple versions of the programs running at the same time. I was thinking it had to do with the system command. Maybe it waits until the project is complete until it goes to the next line of code, and this results in circling, but I am not sure. How can I fix this? I need the programs to end after one of them is called using the system command. I hope this question is clear.
system blocks the running thread until system returns and system will not return until the executed process has terminated.
There are many ways to solve this problem. The simplest and most likely to be portable is to use a std::thread to run system in a thread that runs concurrent to the main processing thread.
std::thread procthread([processToRun] {system(processToRun.c_str());});
procthread.detach();
Short, sweet, and as portable as anything calling system can be. The first line creates a thread and executes a lambda function that runs system on the provided process name. The second line disconnects the thread from the std::thread object and allows the thread to run free. Otherwise if procthread goes out of scope the thread will be terminated and bad things will very likely happen.
If you can't do this because your development system does not support C++11 or better, you can use operating system-specific threading, but if you have to use system-specific thread creation calls, you might as well use system-specific process creation calls to directly create the new process.
In POSIX systems, posix_spawn will likely be the go-to function. I don't have a machine at my disposal to test this on at the moment, so I'll just link to Starting a process using posix_spawn.
Under Windows, use CreateProcess or your variant of choice. The following code is based on Microsoft's Creating Processes documentation page and modified to be a little less Microsoft specific and not wait for the spawned process to complete before continuing execution.
char processToRun[] = "process to run"; //NOTE: Not a std::string!
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
processToRun, // Command line DANGER! won't accept const char*
// cannot use std::string::c_str
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
{
std::cerr << "CreateProcess failed ("<<GetLastError()<<").\n";
return false;
}
// do stuff
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
Your approach makes in an endless loop and it will not end!!
You are spawning multiple instances of projectOne and projectTwo which in turn are creating more.. It's recursive -_-
EDIT
System WAITS!
SOLUTION
int execl(char * pathname, char * arg0, arg1, ..., argn, NULL);
I've a Vc++ code an A.EXE project (MBCS) and a static library project (Unicode). The static library (*.lib) project has the code like below which tries to launch a different exe (pwrtest.exe for example) from within it. BUt the code is crashing when the CReateProcess() statement is executed.
Error is "Unhandled Eception at (ntdll.dll) in "A.EXE":
::Access Vioaltion reading location 0xCCCCCCCC
I made sure that the values in appPath & workdir are correct.
They are values like this ::
c:\Users\abcd\xyz\somedirectory\abc etc...
with directory names separated by double slashes "\".
I really don't understand what is the problem.
Also I've put a try catch statement but when I step in to code (F10) on the line CreateProcess() it immidiately crashes and throws exception as above.
So it's not even coming to catch statement.
As Create process() is a C API & C types are always prone to memory elaks etc.. , just wondering if there is a C++ STD:: library counterpart (some container function API) which is much simpler but doing the job of CreateProcess() C API.
PROCESS_INFORMATION pI;
STARTUPINFO sI;
LPTSTR appPath;
LPTSTR workDir;
wchar_t cwd[_MAX_PATH];
GetCurrentDirectory(_MAX_PATH, cwd);
wchar_t TestEXEPath[_MAX_PATH];
wcscpy(TestEXEPath, cwd);
wcscat(TestEXEPath, L"\\somedircetory\\abc\\pwrtest.exe /sleep /c:1");
appPath = TestEXEPath;
wchar_t workDirForTestEXE[_MAX_PATH];
wcscpy(workDirForTestEXE, cwd);
wcscat(workDirForTestEXE, L"\\somedirectory\\abc");
workDir = workDirForTestEXE;
try
{
if (!CreateProcess(NULL, appPath, NULL, NULL, FALSE, 0, NULL, workDir, &sI, &pI))
{
......
}
{
......
}
}
catch (exception& exType)
{
std::cout << "ExType is" << exType.what() << endl;
}
Your variable sI is uninitialized, and it's an input parameter. When CreateProcess reads from it, all sorts of bad things can happen. Several of the members are defined as pointers to strings. Reading from an invalid pointer is not a C++ exception, which is why your catch statement didn't handle it.
The fix is quite simple, change
STARTUPINFO sI;
to
STARTUPINFO sI = {sizeof sI};
There's no function in the standard C++ library half as powerful as the OS-specific CreateProcess. You're using the ability of CreateProcess to control the initial working directory, something that system, spawn, and exec can't do. (fork + cwd + exec can, but that's a very bad way to do things on Windows)
hello i want to get startet with programming with WIN32, therefore i wrote a programm that creates a process but in the line of code where i create the process the programm gets an error an dosn't work (abend). i don't know if the code in programm 1 is wrong or the code in the second programm that should be created by the first. ( I don't know if the code in the first programm after "createprocess" is right because i didn't get further with debugging, because in this line i get the error.(i tested it without the cout,waitforobject and close handle but i didn't work either )).
First Programm:
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
void main()
{
bool ret;
bool retwait;
STARTUPINFO startupinfo;
GetStartupInfo (&startupinfo);
PROCESS_INFORMATION pro2info;
ret = CreateProcess(NULL, L"D:\\betriebssystemePRA1PRO2.exe", NULL, NULL, false, CREATE_NEW_CONSOLE, NULL,
NULL, &startupinfo, &pro2info);
cout<<"hProcess: "<<pro2info.hProcess<<endl;
cout<<"dwProcessId: "<<pro2info.dwProcessId <<endl;
retwait= WaitForSingleObject (pro2info.hProcess, 100);
retwait= WaitForSingleObject (pro2info.hProcess, 100);
CloseHandle (pro2info.hProcess);//prozesshandle schließen
retwait= WaitForSingleObject (pro2info.hProcess, 100);
ExitProcess(0);
}
Seconde Programm:
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
void main()
{
int b;
b=GetCurrentProcessId();
cout<<b<<endl;
cout<<"Druecken Sie Enter zum Beenden"<<endl;
cin.get();
//warten bis Benutzer bestätigt
Sleep (700);
ExitProcess(0);
cout<<"test";
}
Thanks in advance
Notice the type of the lpCommandLine parameter to CreateProcess -- it is LPTSTR, not LPCTSTR, i.e. it is not const.
This means that CreateProcess reserves the right to actually modify the contents of lpCommandLine. However, you have provided a pointer to a string literal as parameter, and string literals are immutable (they come from your program's read-only data segment and attempts to alter them will typically result in an access violation error.)
To fix this, simply change your code not to use an immutable string literal:
wchar_t wcsCommandLine[] = L"D:\\betriebssystemePRA1PRO2.exe";
ret = CreateProcess(NULL, wcsCommandLine, NULL, NULL, ...
Interestingly enough, CreateProcessW (UNICODE) attempts to write to lpCommandLine whereas CreateProcessA (ANSI) does not, and surprise -- your first program is built as UNICODE (were you to build it as ANSI it would work out of the box, at least on Windows XP.)
I can confirm that, with the above modification, your code works.
Also note that:
unless you need to specify D:\\betriebssystemePRA1PRO2.exe's window title, position etc. you do not need to supply a STARTUPINFO structure at all, you can simply pass lpStartupInfo as NULL and a default will be used
you should not be calling WaitForSingleObject on a closed handle
You must set the size of the startupinfo struct:
startupinfo.cb = sizeof(startupinfo);
Maybe this is why CreateProcess is failing.
And by the way - why are you calling GetStartupInfo? You should just zero out the memory of startupinfo (besides setting the size as mentioned above).
See an example here.