Reputation: 29
I've seen some examples of the CreateProcess() function on Stack Overflow, but I could not get the examples to work. I'm using Visual Studio but programming the straight C. Here is my latest attempt. I can get it to compile and execute, but I can't get it to start the application:
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ;
hr = CreateProcess((NULL, (LPTSTR) "C:\\Windows\\System32\\notepad.exe"), NULL,
NULL,NULL,FALSE,0,NULL,
NULL,&StartupInfo,&ProcessInfo);
int error_1 = 0;
if(!hr)
{
error_1 = GetLastError();
}
When I read 'error_1', it returns a '2', which based upon the System Error Codes indicates that "The system cannot find the file specified.". However, I'm sure the path is correct as I can use the path from the command line to start "Notepad". I can't see what I'm doing wrong.
Upvotes: 1
Views: 3157
Reputation: 596612
You need to get rid of the extra parenthesis around the first 2 parameter values you are passing.
But, more importantly, you need to get rid of the LPTSTR
type-cast. If your project is configured to compile for Unicode, CreateProcess()
will map to CreateProcessW()
, and LPTSTR
will map to wchar_t*
, thus you will be type-casting a narrow const char[]
literal to a wchar_t*
pointer and end up passing garbage to CreateProcessW()
, which could easily account for the error you are seeing. The correct way to create a TCHAR[]
string literal is to use the TEXT()
macro instead of a typecast (see Working with Strings on MSDN for more details):
hr = CreateProcess(NULL, TEXT("C:\\Windows\\System32\\notepad.exe"), NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
However, pay attention to the CreateProcess()
documentation:
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. IflpApplicationName
is NULL, the module name portion of lpCommandLine is limited toMAX_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.
You can do the following to avoid that:
TCHAR szCmdLine[] = TEXT("C:\\Windows\\System32\\notepad.exe");
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
Or:
WCHAR szCmdLine[] = L"C:\\Windows\\System32\\notepad.exe";
hr = CreateProcessW(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
Otherwise, use the ANSI version of CreateProcess()
directly, which you can safely pass a string literal to:
hr = CreateProcessA(NULL, "C:\\Windows\\System32\\notepad.exe", NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
On a side note, you don't need to specify the full path to notepad.exe
, as Windows knows where it is located. You can use "notepad.exe"
by itself.
However, if you do specify the full path, you have to take into account the bitness of your app. If your app is compiled for 32-bit, and is run on a 64-bit system, C:\Windows\System32\notepad.exe
will redirect to C:\Windows\SysWOW64\notepad.exe
, which is the 32-bit version of Notepad. If you want to run the 64-bit version of Notepad, you would have to use C:\Windows\Sysnative\notepad.exe
instead, per the WOW64 documentation:
The
%windir%\System32
directory is reserved for 64-bit applications. Most DLL file names were not changed when 64-bit versions of the DLLs were created, so 32-bit versions of the DLLs are stored in a different directory. WOW64 hides this difference by using a file system redirector.In most cases, whenever a 32-bit application attempts to access
%windir%\System32
, the access is redirected to%windir%\SysWOW64
. Access to%windir%\lastgood\system32
is redirected to%windir%\lastgood\SysWOW64
. Access to%windir%\regedit.exe
is redirected to%windir%\SysWOW64\regedit.exe
....
32-bit applications can access the native system directory by substituting
%windir%\Sysnative
for%windir%\System32
. WOW64 recognizesSysnative
as a special alias used to indicate that the file system should not redirect the access. This mechanism is flexible and easy to use, therefore, it is the recommended mechanism to bypass file system redirection. Note that 64-bit applications cannot use theSysnative
alias as it is a virtual directory not a real one.
Sysnative
only works in a 32-bit app running inside of the WOW64 emulator. you can use System32
in a 32-bit app running on a 32-bit system, and a 64-bit app running on a 64-bit system:
TCHAR szCmdLine[MAX_PATH];
#ifndef _WIN64
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
lstrcpy(szCmdLine, TEXT("C:\\Windows\\Sysnative\\notepad.exe"));
else
#endif
lstrcpy(szCmdLine, TEXT("C:\\Windows\\System32\\notepad.exe"));
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
However, you should take into account that not everyone installs Windows in the C:\Windows
folder, so you should ask Windows where the System folder is actually located:
TCHAR szSysDir[MAX_PATH];
#ifndef _WIN64
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
{
TCHAR szWinDir[MAX_PATH];
GetWindowsDirectory(szWinDir, MAX_PATH);
PathCombine(szSysDir, szWinDir, TEXT("Sysnative");
}
else
#endif
GetSystemDirectory(szSysDir, MAX_PATH);
TCHAR szCmdLine[MAX_PATH];
PathCombine(szCmdLine, szSysDir, TEXT("notepad.exe");
hr = CreateProcess(NULL, szCmdLine, NULL,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo);
Upvotes: 1