ERROR_INVALID_HANDLE when calling GetModuleFileNameEx after CreateProcess - c++

After a successful call to CreateProcess, I am trying to get the path of the created process using GetModuleFileNameEx (lpApplicationName and lpCommandLine parameters can vary or be null so they aren't reliable in this case).
The problem is that GetModuleFileNameEx fails with error 6 (ERROR_INVALID_HANDLE), leaving its buffer with invalid data. I cannot understand the reason, since CreateProcess succeeds and process handle should have been saved correctly in pi.hProcess.
Hope you can shed some light, thanks in advance!
EDIT: An update: I noticed that removing the CREATE_SUSPENDED removes this problem too, but I need that flag set. How can I do?
// Defining GetModuleFileNameExA function
typedef DWORD (WINAPI *fGetModuleFileNameExA)
(
HANDLE hProcess,
HMODULE hModule,
LPSTR lpFilename,
DWORD nSize
);
//Load dinamically DLL function on program startup:
fGetModuleFileNameExA _GetModuleFileNameExA = (fGetModuleFileNameExA) GetProcAddress( LoadLibraryA("Psapi.dll"), "GetModuleFileNameExA");
// **** OTHER UNRELATED CODE HERE ****
PROCESS_INFORMATION pi;
//This call succeeds
if (!CreateProcessW( ApplicationName,
CommandLine,
NewProcess.lpProcessAttributes,
NewProcess.lpThreadAttributes,
NewProcess.bInheritHandles,
CREATE_SUSPENDED | CREATE_NEW_CONSOLE,
NULL,
CurrentDirectory,
&NewProcess.bufStartupInfo,
&pi)
) MessageBoxA(0, "Error creating process", "", 0);
char ProcessPath[MAX_PATH];
//Problem here: call fails with error 6
if (!_GetModuleFileNameExA(pi.hProcess, NULL, ProcessPath, MAX_PATH)) {GetLastError();}
//Invalid data is displayed
MessageBoxA(0, ProcessPath, "GetModuleFileNameEx",0);

From the CreateProcess documentation on MSDN:
Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to initialize, the process is terminated. To get the termination status of a process, call GetExitCodeProcess.
...
The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcess returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.
Similar question

Related

Using CreateProcess() and exit/close the opened Application

I am building a program that would open Sublime text and after a period of time would close the application itself . I can't figure out how to close the application using the existing code .
This is what I have so far :
STARTUPINFO siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
if (CreateProcess(L"C:\\Program Files\\Sublime Text 2\\sublime_text.exe",
L" source.cpp",
NULL,
NULL,
FALSE,
CREATE_DEFAULT_ERROR_MODE,
NULL,
NULL,
&siStartupInfo,
&piProcessInfo) == FALSE)
WaitForSingleObject(piProcessInfo.hProcess, INFINITE);
::CloseHandle(piProcessInfo.hThread);
::CloseHandle(piProcessInfo.hProcess);
First, you are calling WaitForSingleObject() and CloseHandle() if CreateProcess() fails, which is useless. Don't call those functions unless it succeeds instead.
Second, you are calling the Unicode version of CreateProcess(), which has a caveat that your code is not handling. Per 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. 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.
Third, if you want to terminate the process after a timeout, you could use TerminateProcess(), but that is brute force and should be avoided when possible. Sublime has a UI, so the preferred solution is to ask the UI to close itself down and then wait for it to do so, as documented on MSDN:
How To Terminate an Application "Cleanly" in Win32.
If you absolutely must shut down a process, follow these steps:
Post a WM_CLOSE to all Top-Level windows owned by the process that you want to shut down. Many Windows applications respond to this message by shutting down.
NOTE: A console application's response to WM_CLOSE depends on whether or not it has installed a control handler.
Use EnumWindows() to find the handles to your target windows. In your callback function, check to see if the windows' process ID matches the process you want to shut down. You can do this by calling GetWindowThreadProcessId(). Once you have established a match, use PostMessage() or SendMessageTimeout() to post the WM_CLOSE message to the window.
Use WaitForSingleObject() to wait for the handle of the process. Make sure you wait with a timeout value, because there are many situations in which the WM_CLOSE will not shut down the application. Remember to make the timeout long enough (either with WaitForSingleObject(), or with SendMessageTimeout()) so that a user can respond to any dialog boxes that were created in response to the WM_CLOSE message.
If the return value is WAIT_OBJECT_0, then the application closed itself down cleanly. If the return value is WAIT_TIMEOUT, then you must use TerminateProcess() to shutdown the application.
NOTE: If you are getting a return value from WaitForSingleObject() other then WAIT_OBJECT_0 or WAIT_TIMEOUT, use GetLastError() to determine the cause.
By following these steps, you give the application the best possible chance to shutdown cleanly (aside from IPC or user-intervention).
With that said, try something more like this:
BOOL CALLBACK SendWMCloseMsg(HWND hwnd, LPARAM lParam)
{
DWORD dwProcessId = 0;
GetWindowThreadProcessId(hwnd, &dwProcessId);
if (dwProcessId == lParam)
SendMessageTimeout(hwnd, WM_CLOSE, 0, 0, SMTO_ABORTIFHUNG, 30000, NULL);
return TRUE;
}
...
STARTUPINFO siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
WCHAR szFilename[] = L"C:\\full path to\\source.cpp";
if (CreateProcess(L"C:\\Program Files\\Sublime Text 2\\sublime_text.exe",
szFileName,
NULL,
NULL,
FALSE,
CREATE_DEFAULT_ERROR_MODE,
NULL,
NULL,
&siStartupInfo,
&piProcessInfo))
{
CloseHandle(piProcessInfo.hThread);
WaitForInputIdle(piProcessInfo.hProcess, INFINITE);
if (WaitForSingleObject(piProcessInfo.hProcess, SomeTimeoutHere) == WAIT_TIMEOUT)
{
EnumWindows(&SendWMCloseMsg, piProcessInfo.dwProcessId);
if (WaitForSingleObject(piProcessInfo.hProcess, AnotherTimeoutHere) == WAIT_TIMEOUT)
{
// application did not close in a timely manner, do something...
// in this example, just kill it. In a real world
// app, you should ask the user what to do...
TerminateProcess(piProcessInfo.hProcess, 0);
}
}
CloseHandle(piProcessInfo.hProcess);
}

EnumProcessModules failed with error 299 on 32bit win7

My code is running on win7 32bit, but when I use EnumProcessModules, it returned false and getlasterror() return error code 299, which declare that the program is 32bit and this statement can not be running on 64bit system.
I wonder why this happens, and why the system thinks that I am running on a 64bit OS?
The code I use:
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (hProcess)
{
HMODULE hMod = NULL;
DWORD cbNeeded = 0;
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
{
//do something here...
}
}
dwPid is the id of the process I want to manipulate.
PS.This error just happen on one of my test machine, others are fine. So This problem may be related to that specific machine or system configration?
Though It has been a while since you posted this question.But I thought of giving it a try .
Reason might be because You are using CreateProcessA in your code.. and suddenly calling EnumProcessModules.Thus windows is not able to create ModuleInfo by that time.And it returns error 299(Thinking its a 64 bit system.. as it fails to read the memory).
Actually I was stuck at this too and figured it out..after looking at your post.
Thanks
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
CreatProcess Remarks.. It ask to call WaitforInput Idle before proceeding.;-)
The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcess returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.

CreateProcess fails with error 998

I have a homebrew Win32 script interpreter called Wintasks which has worked perfectly for 15 years. It dispatches win32 executables using CreateProcess(). It still works fine on Win7-32, but under Win7-64 if any command line arguments are used when Wintasks is invoked the CreateProcess fails with error 998 (memory access violation). Remove the command line arguments from the Wintasks run and all is well.
Wintasks gets its first parameter (the task script to run) from the Winmain lpszCmdLine parameter, and having only that present works. Putting even a blank after the task script filename causes the problem. Parameters can be accessed successfully in all circumstances referencing __argv[].
When run from MSVC5 (as said, it is an old program) under debug everything works, so I cannot solve the problem that way, it is just the Release executable which gives the problem. Running exactly the same copy of Wintasks using exactly the same task script file from a Win32 VM shows no problem.
I would be grateful for any inspiration. I append the code from Wintasks which runs the CreateProcess.
DWORD WinExecX(LPSTR cmdline, int winstate)
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInformation;
BOOL CreateProcessStatus;
DWORD retval;
DWORD fdwCreate = 0; /* flags for CreateProcess */
memset(&StartupInfo,0,sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.dwFlags=STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow=winstate;
openerr=0;
CreateProcessStatus = CreateProcess( NULL, /*(LPTSTR)name,*/
cmdline,
NULL,
NULL,
FALSE, /* changed 2000-10-18 */
fdwCreate,
NULL, /*envblk,*/
NULL,
&StartupInfo,
&ProcessInformation
);
if(!CreateProcessStatus)
{
openerr=GetLastError();
return 0;
}
elevel=retval = (DWORD)ProcessInformation.hProcess;
CloseHandle(ProcessInformation.hThread);
return retval;
}

Stack Walking a debugged process

I'm opened opening a process (with C++/Windows) using
if( CreateProcessA( NULL, // No module name (use command line)
(LPSTR)path, //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
where
DWORD creationFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
and then I'm trying to stackwalk it with
bool ok = StackWalk64(IMAGE_FILE_MACHINE_I386,m_ps.Handle ,m_th.Handle,
&m_stackframe, &m_threadContext,
0, NULL, NULL, 0);
but stackwalk just gives me the top address and the next one is 0, while I know there are more addresses in the stack.
Does anybody know what's the problem?
thanks :)
It's impossible to tell based on this snippet. There's so much you have to set up correctly in order for this to work. Check out the logic at this detailed blog post.
Post more code if you can post a bigger but not too big sample. How are you setting up the STACKFRAME and CONTEXT structures? Are you looping on StackWalk64? Any given call only returns one stack frame.
oops... I forget to call "ContinueDebugEvent" after receiving events from the debugged process - so it stayed paused and the StackWalk was infact correct. :)

Program stop to running when calls a process

I am trying to create a program that calls another process using CreateProcess. After some problems, I change my program to just open a known program:
if( !CreateProcess( (LPWSTR)"C:\\Program Files\\Opera\\Opera.exe", // No module name (use command line)
NULL, ,
// Command line
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
)
I found this example in msdn, but every time I run my program, windows (Vista) shows a error msg: The program stop running...
Does anybody know what is the problem?
Regards,
Leandro Lima
This line is wrong:
(LPWSTR)"C:\\Program Files\\Opera\\Opera.exe"
LPWSTR is a typedef for wchar_t*. So you're casting a plain string (array of chars, which will decay to a const char*) to a wchar_t*. The end result is likely not even null-terminated!
Either use CreateProcessA and drop the cast, or use a wide string:
L"C:\\Program Files\\Opera\\Opera.exe",