I'm using the ShellExecuteEx function in a C++ program to launch an Uninstall.lnk file. In my program, I'd like to wait for the uninstaller to finish. My first attempt was to set the SEE_MASK_NOCLOSEPROCESS flag in the SHELLEXECUTEINFO structure and then call WaitForSingleObject on the hProcess handle available in the SHELLEXECUTEINFO structure passed to ShellExecuteEx, but that still seemed to return way too early.
My current suspicion is that this is because the process launched by ShellExecuteEx (does it launch a new shell?) creates new child processes, but doesn't wait for them. So I'm trying to create a "wait for my child process and all the children it launches" function. To do so, I'm trying to use job objects.
I created a job object using CreateJobObject, assigned the process handle returned by ShellExecuteEx to the job and then attempted to wait for the job object. Unfortunately assigning the process to the job failed, and I think this is due to insufficient access rights.
Does anybody know how to set the PROCESS_SET_QUOTA and PROCESS_TERMINATE access rights (which are required for AssignProcessToJobObject to succeed, according to the MSDN) on a process handle, or another way to wait for the process launched by ShellExecuteEx to finish?
UPDATE: I should point out that I'm also launching other applications, not just Uninstall.lnk. One of them is e.g. a ClickOnce application, which is effectively a simple XML file with the file extension .application.
Vista uses job objects for launching links. Therefor the process you try to assign to another job object might already be assigned.
See: this question
Why not to execute target file instead of openning Uninstall.lnk? You could use IShellLink to get shortcut target. Then you'll be able to execute target file via ShellExecuteEx using SEE_MASK_NOCLOSEPROCESS flag.
Related
Can someone please explain to me what is the differance between:
OpenProcess and CreatProcess.
(I am trying to inject a DLL into a program and I dont know which one to use.)
OpenProcess is passed a process ID for an existing process, and returns a process handle for that process.
CreateProcess creates a brand new process, returning a handle to that new process (amongst other things).
If you want to inject into a process that is already running, then you will need OpenProcess.
In relation to injecting a .dll into another process,there are a couple of major benefits and differences between OpenProcess and CreateProcess.
The first is timing. You can inject the dll before the target process has had a chance to perform any of their own code by creating the process in a suspended state (dwCreationFlags with CREATE_SUSPENDED(0x00000004) set). Don't forget to resume the process once you are ready for it to execute.
The second is privilege. The process handle returned by CreateProcess automatically has PROCESS_ALL_ACCESS without the need to set SeDebugPrivilege first. OpenProcess does require your program to gain this privilege before it is allowed to use the PROCESS_ALL_ACCESS flag.
Some other minor things to remember:
CreateProcess cannot be called on a running process, but you can always call OpenProcess after CreateProcess if you needed to for whatever reason.
CreateProcess requires you to CloseHandle both the process and thread handles returned in PROCESS_INFORMATION, where OpenProcess only requires you to CloseHandle on it's return value (No thread handle gets opened).
If you need to change the Environment for whatever reason(unlikely), you'll have to use CreateProcess.
Further reading can be found:
CreateProcess
OpenProcess
process-security-and-access-rights
I have two processes: ProcessA and ProcessB.
When i launch my application, i call ProcessA which uses CreateProcess() to launch ProcessB. ProcessA is killed by ProcessB when my application receives command A. Likewise, ProcessB should relaunch ProcessA when it receives command B.
Where i am stuck on is on the process of relaunching ProcessA. Since ProcessA has the code to relaunch ProcessB, i cannot stop it from relaunching another instance of ProcessB. Ideally, i want to have only 1 instance of ProcessB.
For creating ProcessB from ProcessA, i have the following code:
for(int i32Index = 0; i32Index < NUM_PROCESS; i32Index++)
{
wcscpy(wcPath,Directorypath.c_str());
wcscat(wcPath,wcProcess[i32Index]);
RETAILMSG(1,(_T("Path:%s\r\n"),wcPath));
bCreateProcessSuccess = CreateProcess(wcPath, // 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
if(bCreateProcessSuccess == FALSE)
{
RETAILMSG(1,(_T("Create process failed:%d\r\n"),GetLastError()));
}
else
{
RETAILMSG(1,(_T("Loading Exes\r\n")));
}
Pretty straightforward, basic code. I basically repeat this in ProcessB, but so that it creates ProcessA.
Now, im stuck on how i would be able to implement the condition to launch ProcessA without it launching ProcessB again. I initially thought of using a flag, but that flag would be reset since launching ProcessA would reset the flag as it is local to the function.
Also, to clarify: this is in windows embedded compact environment so both processes exist as different subprojects so to access ProcessA from ProcessB would require IPC.
My next idea was to use CreateEvent() with WaitForSingleObject() to check if the event is signaled, but i realized that the wait duration would have to be infinite, which would cause an issue the first time i launch my application.
So, is there any type of windows(wince) api that would solve this? (Or some kind of fancy coding i cannot think of?)
There are a few ways you could do this but two options are:
When you launch ProcessA again, pass it a command line argument using the lpCommandLine parameter (e.g. /nolaunch). ProcessA can then get its command line using GetCommandLine when it starts up and see if it contains the /nolaunch string.
In both ProcessA and ProcessB, use the CreateSemaphore or CreateMutex function to create a named semaphore/mutex. In ProcessB, that's all you have to do - just make sure you don't close the handle until the process exits. In ProcessA, after creating the semaphore/mutex check if GetLastError() returns ERROR_ALREADY_EXISTS - this indicates that ProcessB still has the semaphore/mutex open (and therefore is already running).
There are multiple ways you can sole this:
1. Holding a mutex
In processB you can hold a named mutex and lock it. When processB will be created, it will try to lock the mutex and fail, and than it will kill itself. You can also check if the mutex is locked in processA and prevent the processB creation from the beginning.
2. Sending an argument to process creation
CreateProcess supports sending command line arguments to the created process via the second argument. You can use it as an indicator to whether you should create processB or not.
3. Going through the process list
You can go through the current process list and check if ProcessB is already running. Might want to look into Taking a Snapshot and Viewing Processes.
How can I detect the name of the application that created my application's process?
For example, if someone wanted, they could call CreateProcess and pass it the suspended flag and inject into my application.
Is there a way to block CreateProcess or to figure out what process created an instance of my application?
I've hooked loadlibrary, createthread and all the other easy stuff but CreateProcess seems like it can bypass that.
I'm doing it for fun and learning, not for real world use. I just haven't seen anything that detects CreateProcess..
Any ideas at all?
You can find the parent process ID using the tool help library:
Call CreateToolhelp32Snapshot.
Call Process32First and Process32Next to enumerate the processes.
At some point you will encounter a PROCESSENTRY32 struct for which th32ProcessID is the process ID of your process.
Read out the th32ParentProcessID member to find the process ID of your parent.
Now that you know the parent process, you can enumerate again to gain information about it.
Be prepared for the parent process to have been terminated before you reach this point.
I have a EXE1 which requires an Config file when launched.
I am using ShellExecuteEx to launch EXE1 from EXE2.
It is working fine as such but the if the config file is not preset for EXE1 then it do not get launched however ShellExecuteEx returns TRUE(1) .
I am checking the return value of ShellExecuteEx to Disable the "Launch" BUtton in EXE2 which launch the EXE1.
Since ShellExecuteEx returns TRUE(1) so Launch button is Disable which wrong functionality.
I tried this with CreateProcess as well, it also behaves in the same way.
How can I Ensure exe is launched or not.
You would have to signal from the second program into the first program in some way -- by using shared memory, mutants, or some other interprocess communication method.
ShellExecuteEx only cares about whether the executable is able to start, not whether it's able to do what you expected it to.
Alternately, use CreateProcess instead and monitor for the return code of the child process.
ShellExecuteEx returns true if it's able to launch the executable. It does not actually convey the return code from the launched application.
You can use WaitForSingleObject to wait for few milliseconds on the launched application's handle (hProcess) in SHELLEXECUTEINFO struct. If WaitForSingleObject returns WAIT_OBJECT_0 or WAIT_ABANDONED, you can 'assume' that the launched application has exited. If the launched application continues to run, then your wait would timeout. However, this is not a foolproof method. A more robust way would be to have some IPC mechanism like pipe between applications.
I have a program which needs to invoke a process to perform an operation and wait for it to complete the operation. The problem is that the invoked process clones itself and exits, which causes the wait api to return when the process exits. How can I wait for the cloned process to finish execution and return?
I am using the windows JOB object as mentioned in http://www.microsoft.com/msj/0399/jobkernelobj/jobkernelobj.aspx, But I am not sure if this is the best way.
umm, I'm pretty sure you can can the spawner process id from any process. I'd iterate through all the processes, find the one's who's parent id matches the one of the process you spawned, and wait for it to die.
alternatively (I mean, thats pretty hack) what is the child child process doing? is there some other way you could detect when it has finished doing what it is meant to do?
a hack way to get a process's parent id
http://www.codeguru.com/cpp/w-p/win32/article.php/c1437
takes a handle, and using the method in the code above, returns the parent id.
http://msdn.microsoft.com/en-us/library/ms684280(VS.85).aspx
OpenProcess takes an id, gets a handle to it (if you're lucky)
http://msdn.microsoft.com/en-us/library/ms684320(VS.85).aspx
GetProcessId takes a handle, gets it's id.
http://msdn.microsoft.com/en-us/library/ms683215(VS.85).aspx
GetExitCodeProcess takes a handle, returns whether the process is done or not.
http://msdn.microsoft.com/en-us/library/ms683189(VS.85).aspx
so appart from using hidden nt calls that it expressly tells you not to, you would basically have to create your process, get it's id, then spam all the process, opening them and checking their parent ids against the id of the process you created, if you didn't find one, then it's done, if you do, spam it with GetExitCodeProcess until its done.
I haven't tested any of this, but it looks like A way to do it. though if it's THE BEST way to do it I might just have to loose all faith in windows...
+1 for using job objects ;)
Assuming the process that you're running isn't spawning the cloned version of itself in such a way that it breaks out of the job...
You should be able to simply monitor the job events and act on JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO (see JOBOBJECT_ASSOCIATE_COMPLETION_PORT and SetInformationJobObject()). Monitoring the job in this way will also give you notifications of the processId's of new processes created within the job and details of when they exit.
If you have control over the source of invoked process, one possible solution would be to make it wait for the process it spawns by cloning itself.