How to set PROCESS_SET_QUOTA to process? - c++

I want to use SetProcessWorkingSetSize function, and on MSDN i see this:
"The handle must have the PROCESS_SET_QUOTA access right. For more information, see Process Security and Access Rights."
So, how can i set PROCESS_SET_QUOTA to process handle?
I want to write program that runs executable with working set limits, so there is main piece of code:
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
GetStartupInfo(&si);
si.dwFlags = 0;
PROCESS_INFORMATION pi;
if (!CreateProcess(
exePath.c_str(),
cmdParametersBuffer,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi))
{
cout << "error" << endl;
}
SetProcessWorkingSetSize(pi.hProcess, 20 * 4 * 1024, 100*1024*1024);

Did you actually try the code you have showed and it is not working for you? If so, what error is GetLastError() reporting?
If you read the documentation, it says:
Process Security and Access Rights
PROCESS_ALL_ACCESS
All possible access rights for a process object.
...
The handle returned by the CreateProcess function has PROCESS_ALL_ACCESS access to the process object
So you should be able to call SetProcessWorkingSetSize() after CreateProcess() exits, exactly like you have showed, without doing anything extra to enable PROCESS_SET_QUOTA rights, as it should already be enabled.

Your example code is calling SetProcessWorkingSetSize() successfully, as the error you get is 0. If you got an error like 0x522 ERROR_PRIVILEGE_NOT_HELD then you'd know the call failed.
It might help to know that an app is expected to be able to allocate more memory than its the working set size. The OS will page out memory from RAM. If you use Task Manager to view the Working Set for your process, is it actually exceeding the quota you set?
You might also need to use SetProcessWorkingSetSizeEx wth flag QUOTA_LIMITS_HARDWS_MAX_ENABLE to force the OS to actually apply your setting.

Related

How to check Win32 CreateProcess() failed reason using ProcMon. exclude GetLastError()

I am having an issue with checking CreateProcess() failure reason, there was a code in production which doesn't log GetLastError() when CreateProcess() failed so i am running ProcMon to check the reason but unable to find the reason (Will procMon log the failure reason something like "C:\dummy.exe path not found or permission denied" ?).
Is there a way (tools ?) to check why CreateProcess() is failing without considering GetLastError() ?
I can't debug customer environment (no access to me) but I can change the code & provide new build & it takes long time due to process. i am currently looking for quick options available. Below is the sample code not exact production code.
int main()
{
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
TCHAR dymmypath[_MAX_PATH] = _T("C:\\dummy.exe");
static TCHAR TempPathString[_MAX_PATH];
STARTUPINFO si = { sizeof(si) }; //default set up
PROCESS_INFORMATION pi; //data structure for CreateProcess
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWMINIMIZED;
if (!CreateProcess(dymmypath, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, TempPathString, &si, &pi))
{
printf("Failed");
}
else {
printf("Success");
}
return 0;
}
i am running ProcMon to check the reason but unable to find the reason (Will procMon log the failure reason something like "C:\dummy.exe path not found or permission denied" ?).
Only if the request reaches the filesystem, ie to look for the EXE file, which in your case it sounds like it is not doing that, likely because CreateProcess() is failing to validate your input parameters before it reaches into the filesystem.
Is there a way (tools ?) to check why CreateProcess() is failing without considering GetLastError() ?
As others said, you could try attaching a debugger to your running app, and put a breakpoint in the CreateProcess function itself.
Another option is to use a tool like API Monitor, which will show you the actual API calls your program makes, what their parameter values are, reported error codes, etc.
I can't debug customer environment (no access to me) but I can change the code & provide new build
Then that is what you should do. Fix your code to do proper logging of error codes, don't ignore them anymore.
it takes long time due to process.
Well, that is your own fault for not optimizing your build process better, or breaking up your app into more manageable pieces, etc.
Just at first glance, I see TempPathString is initialized to "", which is not a valid path. So while you're fixing that issue, that's your chance to add proper error handling.
The tool you're looking for is a debugger. You should attach the debugger of your choice, set a breakpoint on the return of CreateProcess, and check the error there.
Besides debugging and error handling (logging etc), you'll have to just get creative. Compare a working environment against production for example.

How to open a program and make it run on the currently open console app in C++ [duplicate]

When I call CreateProcess in Windows, the new process doesn't seem to inherit the console of the calling process. I made a test program that runs "ruby xtest", xtest being a script that writes "hello" to standard output. I ran this test program from Emacs, and get no output. I also tried the following code calling GetStdHandle, but again, no output. Then I tried passing CREATE_NEW_CONSOLE in dwCreationFlags to CreateProcess, which made a whole new window with the Ruby output. Finally, I made a simple fork/exec
test program and compiled it using Cygwin's GCC. This program worked: the Ruby output showed up in Emacs as expected. I tried to decipher the Cygwin source code in http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/spawn.cc?rev=1.268&content-type=text/x-cvsweb-markup&cvsroot=src but failed. So, how do you make the new process inherit the console of the parent process such that the output from the child shows up as expected?
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess(0, "ruby xtest", 0, 0, 1, 0, 0, 0, &si, &pi)) die("CreateProcess");
I know, this thread is rather old, however, I just ran into the same problem.
Just as for the TS, the console handle was inherited and working fine under Cygwin, but not on a Windows console. Instead, the output on stdout was neither shown, nor any error was reported. Inherited Pipe handles worked still fine.
I took me some time to identify the (now obvious) problem: CreateProcess() was called with CREATE_NO_WINDOW. Dropping this flag, console output is fine. (Though, according to the code of the TS, they never set this flag in the first place.)
Hope this might be helpful for people who also stumble across this thread, like myself.
According to Microsoft documentation, lpCommandLine (2. parameter):
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.
When I stopped using a constant here it worked for me. I didn't need the STARTF_USESTDHANDLES and GetStdHandle thing.
This code from a console prg runs and outputs another console exe in the same console:
FillChar(SI, SizeOf(SI), 0);
SI.cb:=SizeOf(SI);
FillChar(PI, SizeOf(PI), 0);
if CreateProcess(nil, CmdLineVar, nil, nil, False, 0, nil, nil, SI, PI) then ...
I've done this by passing in pipes for hStdInput, hStdOutput, and hStdError and manually routing data from the hStdOutput and hStdError pipes to the console.
Not sure if debeige ever solved this, but I needed the same thing, but starting up another thread to listen to stdout output, just to put it on stdout seemed nuts to me.
The following works for me, and is slightly different than what he originally posted. I thought at first it wouldn't work if you don't set si.cb, but when I commented that in mine, it still worked, so... YMMV.
STARTUPINFO siStartInfo;
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
siStartInfo.hStdInput = g_hChildStd_IN_Rd; // my outgoing pipe
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(
NULL,
szCmdline,
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&siStartInfo,
&piProcInfo);

How to duplicate current process?

What's the easiest way to duplicate the current process, to spawn another instance in Windows? I know Linux has fork(), but all I need is to run main in the same process again, probably using CreateProcess() with the correct arguments.
As #DavidHeffernan commented:
STARTUPINFO si;
::memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
::CreateProcess(NULL, ::GetCommandLine(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
Cygwin implements fork() within its managed environment, but even that is an intricate square dance in getting the child to catch up with the parent to accurately replicate POSIX behavior.
It seems like you don't need to emulate fork(), but fork()/exec(). For that, gathering the environment variables, program parameters and passing them to CreateProcess() should be enough. There are options to copy the file descriptors to the child too. See CreateProcess's documentation.

CreateProcess works on some computers, not on others. Why?

I work on an app that calls another app via CreateProcess. I'm on Win7 64 bits. The called app is a console that receive data through a pipe. The calling code looks like this:
STARTUPINFOA si;
PROCESS_INFORMATION pi;
GetStartupInfoA(&si);
memset( &si, 0, sizeof(STARTUPINFOA) );
memset( &pi, 0, sizeof(pi) );
si.cb = sizeof(STARTUPINFOA);
char cmdline[MAX_PATH];
sprintf(cmdline,"\"%s\" %s",AppToCallName,PipeName);
BOOL bRet = CreateProcessA(NULL,cmdline,NULL,NULL,FALSE,CREATE_NEW_CONSOLE|CREATE_BREAKAWAY_FROM_JOB,NULL,NULL,&si,&pi);
On my computers (I tried on two), it works. On other ones, it returns (bRet=)FALSE then GetLastError() returns 5 which means ACCESS_DENIED.
I cannot figure out where is the problem. And the bad thing is that it works for me so I can't debug it!
My setup is:
Win7 Pro 64 bits SP1
VStudio 2005 SP1
(Compiler used: Intel C++ 9.1
I will be glad to furnish more setup info if you need it!
Any idea?
CreateProcess uses the same permissions as the calling process it also will terminate the process if it has not initialized properly so you should wait and verify the process launched even if CreateProcess returns success. However your access denied issue is probably related to your calling process not having execute or write permissions on whatever application you were attempting to launch on the target machine.
In addition to GetLastError when the function succeeds check GetExitCodeProcess as that will probably be your next problem.
Also for reference: http://msdn.microsoft.com/en-us/library/ms682425(v=vs.85).aspx

Using a handle to collect output from CreateProcess()

I am using CreateProcess() to run an external console application in Windows from my GUI application. I would like to somehow gather the output to know whether there were errors. Now I know I have to do something with hStdOutput, but I fail to understand what. I am new to c++ and an inexperienced programmer and I actually don't know what to do with a handle or how to light a pipe.
How do I get the output to some kind of variable (or file)?
This is what I have a the moment:
void email::run(string path,string cmd){
WCHAR * ppath=new(nothrow) WCHAR[path.length()*2];
memset(ppath,' ',path.length()*2);
WCHAR * pcmd= new(nothrow) WCHAR[cmd.length()*2];
memset(pcmd,' ',cmd.length()*2);
string tempstr;
ToWCHAR(path,ppath); //creates WCHAR from my std::string
ToWCHAR(cmd,pcmd);
STARTUPINFO info={sizeof(info)};
info.dwFlags = STARTF_USESHOWWINDOW; //hide process
PROCESS_INFORMATION processInfo;
if (CreateProcess(ppath,pcmd, NULL, NULL, FALSE, 0, NULL, NULL, &info, &processInfo))
{
::WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
delete[](ppath);
delete[](pcmd);
}
This code probably makes any decent programmer scream, but (I shouldn't even say it:) It works ;-)
The Question: How do I use hStdOutput to read the output to a file (for instance)?
Microsoft has an example in its knowledge base that demonstrates how to capture the output of a child console process. The basic principle is that the parent process creates pipes (one per standard handle to redirect) and passes the handles to CreateProcess.
The child process does not need to be modified for this to work, which is important if you do not have control over the child's source.
More information: How to spawn console processes with redirected standard handles