CreateProcess can not run a application - c++

I just want to create a process to run a application on windows my code as below:
//init the structure
STARTUPINFOW StartupInfo;
ZeroMemory(&StartupInfo,sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow = true ;
PROCESS_INFORMATION ProcessInfo;
ZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
DWORD dwExitCode = 0;
LPCWSTR cmdFormat = "xxxxxx"; // this is the applocation's path
LPWSTR cmd = new wchar_t[256*sizeof(wchar_t)];
wcscpy_s(cmd, wcslen(cmdFormat)+1,cmdFormat);
int ret = CreateProcessW(cmd,
NULL,
NULL,
NULL,
false,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&StartupInfo,
&ProcessInfo);
if(ret)
{
CloseHandle(ProcessInfo.hThread);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
CloseHandle(ProcessInfo.hProcess);
}
if(dwExitCode==0)
{
DWORD errorcode = GetLastError();
std::cout<<"ERROR: "<<errorcode<<std::endl;
}
I use this function that I can create new process to run notepad.exe and some other applications
Q1: but when I close the application the dwExitCode = 0 and the errorcode 1803
Q2: some application can not run just exit immediately

Following function always works for me:
static int createProcess(string cmdLine, bool isWait, LPDWORD pExitCode)
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
::ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
::ZeroMemory(&pi, sizeof(pi));
// reset last error
::SetLastError(0);
// Start the child process.
BOOL bCreateProcess = ::CreateProcessA(NULL, // No module name (use command line)
(LPSTR) cmdLine.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW, // 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
if(!bCreateProcess)
{
// create process failed,
//Logger::trace(error, getClassName(), "createProcess", getFormattedStringA("create process failed with error:%d, Commad line:'%s',isWait:%d",GetLastError(), cmdLine.c_str(), isWait),"CreateProcess Failed");
return 0;
}
//Logger::trace(info, getClassName(), "createProcess", getFormattedStringA("created process,Commad line:'%s',isWait:%d,Result:%d", cmdLine.c_str(), isWait,bCreateProcess),"Launched Process");
// Wait until child process exits.
if(isWait)
{
::WaitForSingleObject(pi.hProcess, INFINITE);
if(pExitCode)
{
::GetExitCodeProcess(pi.hProcess, pExitCode);
}
}
::CloseHandle( pi.hProcess );
pi.hProcess = NULL;
::CloseHandle( pi.hThread );
pi.hThread = NULL;
return 1; // return non zero. function succeeded
}

Yes I find the root cause some application need some local resource ,so maybe need the parent's starting directory

Related

How to execute commands from an attached console

I'm coding a WinAPI GUI program that needs calling ftp and possibly other console programs while getting their console output to act accordingly ie. waiting for ftp to complete execution before reading all its output wouldn't do.
My current approach is calling CreateProcess() to create a cmd.exe process potentially hiding the ugly console window, AttachConsole() to make it my own, GetStdHandle() to get input and output handles, SetConsoleCursorPosition() to the end of the console buffer, and WriteConsole() with commands such as ftp\n or dir\n. Yet this commands are written but not executed. However, I can manually use the same console ( using CreateProcess() with CREATE_NEW_CONSOLE flag ) to type ftp press enter and get it executed.
Previous approaches involved:
Calling ftp directly with CreateProcess() and redirected inputs/outputs.
Couldn't get ftp output until the CreateProcess() process had already ended.
Using system().
Was advised against its usage before getting any output.
My current stripped down code:
// Next two structures might be a bit misleading, they were used for the 1. previous
// approach
PROCESS_INFORMATION piProcInfo;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION));
STARTUPINFO siStartInfo;
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
SECURITY_ATTRIBUTES security;
security.nLength = sizeof(SECURITY_ATTRIBUTES);
security.lpSecurityDescriptor = NULL;
security.bInheritHandle = FALSE;
CreateProcess( NULL, "cmd", &security, &security, FALSE, NORMAL_PRIORITY_CLASS |
CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &piProcInfo);
uint32_t pidConsole = piProcInfo.dwProcessId;
while ( ! AttachConsole(pidConsole) ){};
HANDLE myConsoleIn, myConsoleOut;
myConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
myConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
Sleep(100);
CONSOLE_SCREEN_BUFFER_INFO myConsoleCursorInformation = {};
GetConsoleScreenBufferInfo(myConsoleOut,&myConsoleCursorInformation);
SetConsoleCursorPosition(myConsoleOut,myConsoleCursorInformation.dwSize);
CHAR myConsoleBuffer[200]="dir\n";
DWORD myConsoleProcessed;
WriteConsole( myConsoleOut, myConsoleBuffer, 4, &myConsoleProcessed, NULL);
How can I get a command written in the console to execute? Is there an alternative to my attempt of ending commands with a trailing \n ie. using WriteConsole() with a dir\n or ftp\n argument.
I thought about sending a keypress to the process in question after typing the desired command. Yet the created console needs not only to manually press the enter key but also having dir, ftp or whatever command to be manually typed.
Please feel free to point out any missing information !
How can I get a command written in the console to execute? Is there an
alternative to my attempt of ending commands with a trailing \n ie.
using WriteConsole() with a dir\n or ftp\n argument.
Try the following code to see if it works:
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
const wchar_t *cmdPath = L"C:\\Windows\\System32\\cmd.exe";
wchar_t *cmdArgs = (wchar_t *)L"C:\\Windows\\System32\\cmd.exe /k dir";
BOOL result = CreateProcess(cmdPath, cmdArgs, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
DWORD errCode = GetLastError();
if (!result)
{
std::cout << "Create Process failed: " << GetLastError() << std::endl;
}
/K Run Command and then return to the CMD prompt.
This is useful for testing, to examine variables
Use /C if you want "Run Command and then terminate".
Update: Complete code for communicating with a child process(cmd.exe) using pipes.
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
#define BUFSIZE 1024
void ErrorExit(LPCTSTR lpszFunction)
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(1);
}
void ReadFromPipe(void)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;)
{
DWORD bytesAvail = 0;
if (!PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, 0, NULL, &bytesAvail, NULL)) {
std::cout << "Failed to call PeekNamedPipe" << std::endl;
}
if (bytesAvail) {
DWORD n;
BOOL success = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &n, NULL);
if (!success || n == 0) {
}
bSuccess = WriteFile(hParentStdOut, chBuf,n, &dwWritten, NULL);
}
else
{
break;
}
}
}
void WriteToPipe(void)
{
DWORD dwWritten;
BOOL bSuccess = FALSE;
CHAR buf[] = "dir\n";
bSuccess = WriteFile(g_hChildStd_IN_Wr, buf, sizeof(buf)-1, &dwWritten, NULL);
}
int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES saAttr;
printf("\n->Start of parent execution.\n");
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
ErrorExit(TEXT("StdoutRd CreatePipe"));
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT("Stdout SetHandleInformation"));
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
ErrorExit(TEXT("Stdin CreatePipe"));
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT("Stdin SetHandleInformation"));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(STARTUPINFO);
si.hStdError = g_hChildStd_OUT_Wr;
si.hStdOutput = g_hChildStd_OUT_Wr;
si.hStdInput = g_hChildStd_IN_Rd;
si.dwFlags |= STARTF_USESTDHANDLES;
TCHAR cmdPath[] = TEXT("C:\\Windows\\System32\\cmd.exe");
BOOL result = CreateProcess(cmdPath, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
DWORD errCode = GetLastError();
if (!result)
{
std::cout << "Create Process failed: " << GetLastError() << std::endl;
}
for (;;)
{
ReadFromPipe();
WriteToPipe();
}
}

C++ CreateprocessA Failed Error

I use this code but i get a failed error: 2 i know that means the file doesn't exist but no idea what am doing wrong.
DWORD size = 1024;
TCHAR buff[1024];
int err = AssocQueryString(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE, _T(".html"), NULL, buff, &size);
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
LPCSTR BrowLoc = (LPCSTR)buff;
if (!CreateProcessA(BrowLoc, // No module name (use command line)
NULL,
NULL, // Process handle not inheritable
NULL, // Thread handle not inhberitable
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());
getchar();
return 0;
}
I guess you are using unicode. In that case, force using multi-byte character for AssocQueryString().
Use the code below for the first 3 lines.
DWORD size = 1024;
char buff[1024];
int err = AssocQueryStringA(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE, ".html", NULL, buff, &size);

Get pid of started process c++

I try to get PID of process which i started by my app.
DWORD dwPid = GetProcessId(pi.hProcess);
Somewhere on this forum is this solution but i dont have func "GetProcessId"
To start process i'm using:
BOOL bSuccess = FALSE;
LPTSTR pszCmd = NULL;
PROCESS_INFORMATION pi;// = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);
pszCmd = ""; /* assign something useful */
bSuccess = CreateProcess("D:\\program\\program.exe",NULL, NULL, NULL, TRUE, 0, NULL, "D:\\program", &si, &pi);
if (bSuccess)
{
}
It is possible to run my code in this started program without dll ?
According to the documentation on PROCESS_INFORMATION, you can access the process id directly from the PROCESS_INFORMATION struct by accessing the dwProcessId member:
DWORD dwPid = pi.dwProcessId;

Problems with opening a process with DEBUG flags

I'm trying to open a process with my debugger using CreateProcess with the DEBUG_PROCESS and DEBUG_ONLY_THIS_PROCESS flags and the the process is opened, but then when I try to call SymInitialize with the handle I receive, it fails.
This is my code:
#include <windows.h>
#include <stdio.h>
#include <dbghelp.h>
#pragma (lib, "dbghelp.lib");
bool EnablePrivilege(LPCTSTR lpszPrivilegeName, BOOL bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
bool ret;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
return FALSE;
if (!LookupPrivilegeValue(NULL, lpszPrivilegeName, &luid))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
ret = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
CloseHandle(hToken);
return ret;
}
void main()
{
EnablePrivilege(SE_DEBUG_NAME, TRUE);
STARTUPINFOA startInfo;
PROCESS_INFORMATION processInfo;
ZeroMemory( &startInfo, sizeof(startInfo) );
startInfo.cb = sizeof(startInfo);
ZeroMemory( &processInfo, sizeof(processInfo) );
DWORD creationFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
const char* comLine = "Some process path and name";
// Start the child process.
if( CreateProcessA( NULL, // No module name (use command line)
(LPSTR)comLine, //argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
creationFlags, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startInfo, // Pointer to STARTUPINFO structure
&processInfo ) // Pointer to PROCESS_INFORMATION structure
== false )
{
printf("FAIL!");
return;
}
SetLastError(0);
bool ok = SymInitialize(processInfo.hProcess, NULL, true);
int err = GetLastError();
}
If I call CreateProcess with no creation flags, symInitialize succeed.
What am I doing wrong?
Your error is result of calling MAKE_HRESULT macro as
MAKE_HRESULT(ERROR_SEVERITY_ERROR, FACILITY_NULL, ERROR_INVALID_DATA)
So your error code is not trash. Documentaion doesn't say what kind of data might be invalid in this context. I will try to see what exactly is causing the problem.
EDIT:
This code works for me
#include <windows.h>
#include <stdio.h>
#include <dbghelp.h>
#include <WinError.h>
bool EnablePrivilege(LPCTSTR lpszPrivilegeName, BOOL bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
bool ret;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
return FALSE;
if (!LookupPrivilegeValue(NULL, lpszPrivilegeName, &luid))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
ret = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
CloseHandle(hToken);
return ret;
}
void main()
{
EnablePrivilege(SE_DEBUG_NAME, TRUE);
STARTUPINFOA startInfo;
PROCESS_INFORMATION processInfo;
ZeroMemory( &startInfo, sizeof(startInfo) );
startInfo.cb = sizeof(startInfo);
ZeroMemory( &processInfo, sizeof(processInfo) );
DWORD creationFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
const char* comLine = "C:\\Windows\\Notepad.exe";
// Start the child process.
if( CreateProcessA( NULL, // No module name (use command line)
(LPSTR)comLine,// argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
creationFlags, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startInfo, // Pointer to STARTUPINFO structure
&processInfo ) // Pointer to PROCESS_INFORMATION structure
== false )
{
printf("FAIL!");
return;
}
SetLastError(0);
bool ok = SymInitialize(processInfo.hProcess, NULL, true);
HRESULT err = HRESULT_FROM_WIN32(GetLastError());
}
I don't know why it doesn't for you - I am running windows XP, it might be a difference. For me SymInitialize returns true, and GetLastError returns 0x800700cb, which means only that it didn't found evirnment variable pointing it to directory with symbol files.
This might be stupid question, but perhaps you are missing some debugging libraries in your system? Have you tried installing eg. Debugging Tools for
Windows? I would reccomend 'Download Debugging Tools from the Windows SDK' option - read the description. I guess every programming IDE around would install it for you or have you install it before debugging anything, but it's always best to check.
When process is just created with DEBUG_PROCESS flag no symbols are loaded. It is required to wait for some LOAD_DLL_DEBUG_EVENT and then call SymInitialize().

How to launch an exe by command prompt and get text from command prompt window

jarsigner.exe takes a parameter and prints some text to console:
string command = "jarsigner.exe -verify test.jar";
system(command.c_str());
when I run this code, command prompt window appears and
it prints jar is verified or jar is unsigned to console.
How can I get this result string from the console?
You can try ReadConsoleOutputCharacter.
I used Google to find this.
EDIT: Does jarsigner not return error codes? Like 0 on success and 1 on failure? You could use CreateProcess and trap the return code.
You could redirect stdout to to a file (jarsigner.exe > outfile.txt) and then parse the contents of the file using a utility like a perl or shell script.
Alternatively, you can redirect stdout in your application using the dup, _open_osfhandle, or freopen functions.
i created new process and redirect its stdout to text file, it works.
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
HANDLE hOutFile;
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
ZeroMemory( &sa, sizeof(sa) );
si.cb = sizeof(si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES ;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true;
// Create output file and get file handle
hOutFile = CreateFile ( TEXT(outFilePath.c_str()),
FILE_SHARE_WRITE,
0,
&sa, // provide SECURITY_ATTRIBUTES
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Assign StartInfo StdOutput to file handle
si.hStdOutput = hOutFile ;
LPTSTR szCmdline = TEXT( command.c_str() );
if( !CreateProcess( NULL, // No module name (use command line)
szCmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
true, // Set handle inheritance to TRUE
0, // No creation flags
NULL, // Use parent's environment block
TEXT(jarSignerExeDir.c_str()), // Use jarSignerExeDir FOR starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
ShowMessage( "CreateProcess failed (%d).\n" + GetLastError() );
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process,thread and file handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
CloseHandle(hOutFile);