I am trying to start a server using CreateProcess(). Here is the Code:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
int result;
STARTUPINFO si;
PROCESS_INFORMATION pi;
CreateProcess("C:\\AP\\DatabaseBase\\dbntsrv.exe", "*** WHAT SHOULD I PUT HERE***", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
return 0;
}
I did not understand from the documentation what the 2nd parameter should be. Can you please help me with it?
Thank You
From MSDN:
lpCommandLine [in, out, optional]
The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null
character. If lpApplicationName is NULL, the module name portion of
lpCommandLine is limited to MAX_PATH characters.
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.
The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the
command line.
So NULL is OK there, at least. As soon as you don't pass arguments.
You use it to pass arguments to the .exe defined by the first parameter:
An example would be to call the cmd.exe and then run a script or use a zip utility:
void runCmd(const tstring& cmdString, STARTUPINFO &si, PROCESS_INFORMATION &pi)
{
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
si.cb = sizeof(si);
tstring cmd_exe_path(win_dir);
cmd_exe_path.append( _T("\\System32\\") ).append(CMD_PROCESS);
tstring argline( _T("/c ") );
argline += cmdString;
tstring curr_dir( cmdString.substr( 0, cmdString.rfind( _T('.') ) ) );
curr_dir.erase( curr_dir.find_last_of( _T("/\\") ) );
size_t pos = curr_dir.find( _T("\"") );
while( pos != tstring::npos )
{
curr_dir.erase( pos, pos + 1 );
pos = curr_dir.find( _T("\"") );
}
//USE FULL PATHS FOR SAFETY... Include wrapping quotes if spaces required in path
LOG(LOG_INFO,_T("runCmd(): Calling %s %s Dir[ %s ]"),cmd_exe_path.c_str(),argline.c_str(), curr_dir.c_str());
if( !CreateProcess( cmd_exe_path.c_str(), &argline[0], NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
NULL,curr_dir.c_str(),&si,&pi ) ) //this generates warning C6335 - resource leak... however handles should be closed by owner
{
DWORD dw = GetLastError();
std::string error( "runCmd(): Failed to create Shutdown process - error code is " );
error.append(boost::lexical_cast<std::string>(dw));
LOG(LOG_INFO,error.c_str());
throw std::exception(error.c_str());
}
LOG(LOG_INFO,"runCmd(): process starting with PID[%d] TID[%d]",pi.dwProcessId,pi.dwThreadId);
}
Related
I'm trying to write a program in C++ that launches an executable. When I try to run the program, nothing happens. But when I try to run the program on the same directory and drive the exe is in, it does work.
Here's the code:
else if (result1 == 0) {
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
{
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
CreateProcess(L"D:\\Games\\Origin Games\\Command and Conquer Red Alert\\RA95Launcher.exe", NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
When I do it like this:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
{
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
CreateProcess(L"D:\\Games\\Origin Games\\Command and Conquer Red Alert\\RA95Launcher.exe", NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, "D:\\Games\\Origin Games\\Command and Conquer Red Alert\\", &si, &pi);
I get the error:
argument of type "const char *" is incompatible with parameter of type "LPCWSTR"
Any help would be appreciated.
Most likely you should set the lpCurrentDirectory parameter to the directory the exe is in.
See: CreateProcess
It's often that executables like RA95Launcher.exe are depending on other files. Usually these are reffered to by a relative path from perspective of the Current Working Directory.
If you launch the process from within the directory the exe is in, your automatically in the correct Current Working Directory. If you have the launcher running at a different location, you'll need to specify it.
I get the error: argument of type "const char *" is incompatible with
parameter of type "LPCWSTR"
This means that you're trying to pass incompatible type to function. LPCWSTR is Windows.h typedef for const wchar_t*(a UTF-16 string), but CreateProcess requires ANSI string(LPCSTR). You can either call the appropriate function, in this case - CreateProcessW(W at the end of the function name means it takes UTF-16 strings as parameters) or make your string ANSI by removing L before it.
I want to create a process whose filename doesn’t have the .exe extension. This is the same question as Open an executable file without an “.exe” extension with ShellExecute had, only with CreateProcess. The answer to his question said to set the sei.lpClass = TEXT("exefile");. No such parameter in the STARTUPINFO structure.
Is there an equivalent solution for CreateProcess. Currently, it fails with no extension. Doesn’t even give a proper error message. Just crashes the program.
Edit2:
Sorry, here's a complete test program demonstrating my problem:
#include "stdafx.h"
#include <Windows.h>
LPCTSTR FILE_PATH_NAME = _tcsdup( TEXT( "C:\\File1.exe" ) ); // ok, launches new process correctly
//LPCTSTR FILE_PATH_NAME = _tcsdup( TEXT( "C:\\File1" ) ); // debug assertion in mfc
LPCTSTR FILE_PATH_NAME = _tcsdup( TEXT( "C:\\File1." ) ); // ok, launches new process correctly. Needs ending period (.) to work
LPTSTR commandLine = _tcsdup( TEXT( "1234" ) );
int main()
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &pi, sizeof( pi ) );
ZeroMemory( &si, sizeof( si ) );
si.cb = sizeof( si );
CreateProcess
(
FILE_PATH_NAME, // must be fully qualified file path name
commandLine, // Command line (cannot be const or literal str)
NULL, // Process handle is not inheritable
NULL, // Thread handle is not inheritable
FALSE, // handle inheritance false
0, // default
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to startupinfo structure
&pi // Pointer to process_information structure
);
DWORD lastError = GetLastError();
if( lastError != ERROR_SUCCESS )
{
// failed
}
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
return 0;
}
Edit3:
Crash image
I am trying to dump a portion of the windows registry in a .txt file using the CreateProcess function. The code is along the lines of
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
CString cmdLine = "\"C:\\WINDOWS\\regedit.exe\" /e \"c:\\dump\\TestReg.txt\"
\"HKEY_LOCAL_MACHINE\\SOFTWARE\\MYSOFT\\\"";
LPSTR pCmdLine = (LPSTR)(const char*)cmdLine;
BOOL oc = CreateProcess(NULL, pCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if(oc == TRUE)
{
WaitForSingleObject(pi.hProcess, 1000);
GetExitCodeProcess(pi.hProcess, &exitCode);
if(exitCode != 0) ret = -1;
}
What I know
The CreateProcess returns TRUE and the last blocks executes
The process waits for the end and exits normally
However no file is produced at the end
The command line string works fine in command line, even when it operates from the same directory where the program is operating.
I have found something that is potentially useful where someone had basically the same problem. In the end it resulted in a dependency clash but the link does not explain very well how it was detected or fixed.
Following the tutorial here, I decided to make a process class for C++ so that I did not have to constantly keep writing out the same code for starting a process. It does work starting the process, but when I pass a command line function, it does nothing. Example ("c:\\windows\\notepad.exe", "c:\\windows\\PFRO.txt"). What is the problem?
Note: format is just a basic formatting function, using vsprintf
class process
{
public:
static BOOL __stdcall start(LPCSTR _Proc_name, LPSTR _Command_line = NULL, LPSECURITY_ATTRIBUTES _Proc_attrib = NULL,
LPSECURITY_ATTRIBUTES _Thread_attrib = NULL, BOOL _Inherits_handles = FALSE, DWORD _Creation_flags = NULL,
LPVOID _Environment = NULL, LPCSTR _Cur_directory = NULL)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(_Proc_name, _Command_line, _Proc_attrib, _Thread_attrib,
_Inherits_handles, _Creation_flags, _Environment, _Cur_directory, &si, &pi))
{
fputs(format("process::start(...) failed [%d]\n", GetLastError()), stderr);
return false;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
};
int main()
{
process::start("c:\\windows\\notepad.exe", "c:\\windows\\PFRO.txt");
getchar();
}
When the command line parameter is parsed to provide arguments for a main function, the first token is taken to be the executable file. A called program might well try to open the second token as its file argument, and of course you there wasn't one.
The usual practice is to repeat the program name as the first token in the command line. For example
process::start("c:\\windows\\notepad.exe", "notepad c:\\windows\\PFRO.txt");
Related question: CreateProcess doesn't pass command line arguments.
Is there a difference between passing an argument vs. passing a parameter to an EXE when using CreateProcess (and/or ShellExecuteEx)?
I'm trying to call something like:
myExe.exe /myparam
with the code like :
TCHAR Buffer[MAX_PATH];
DWORD dwRet;
dwRet = GetCurrentDirectory(MAX_PATH, Buffer);
CString sCmd;
sCmd.Format ( "%s\\%s", Buffer, command);
CString sParam( "/myparam" );
sCmd += " " + sParam;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if (CreateProcess( NULL, sCmd.GetBuffer() , NULL, NULL, TRUE, 0, NULL, Buffer, &si, &pi))
{
::WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else
{
LPVOID lpMsgBuf = NULL;
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 );
CString msg;
msg.Format("Failed to start command line (error: %s) : %s\n",lpMsgBuf,sCmd);
AfxMessageBox(msg);
LocalFree(lpMsgBuf);
}
From what I understand from the other thread and MSDN is that it should be working properly and call the EXE with the parameter; doing the above code without adding the "/myparam" works like it should.
I've tried the EXE from the command line and from Explorer (by creating a shortcut and adding /myparam to the target name) and it's working alright.
Try this in case there are spaces in the path:
CString sCmd;
sCmd.Format ( "\"%s\\%s\"", Buffer, command);
Or else pass the parameters via the parameters argument.