Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium


HPROCESS & ShellExecute()

Posted on 2003-02-21
Medium Priority
Last Modified: 2013-12-03
I need to use ShellExecute() (or ShellExecuteEx()) to run the app associated with a file. So far no problem....

However, I then need to wait for the application launched by ShellExecute(Ex) to end. So I need the process handle to use with WaitForSingleObject(). And I can't find a reliable way to get the process handle (or process id).

Every technique I looked at has a problem:
1. ShellExecuteEx doesn't always return the HPROCESS. e.g. if Word is already running before calling ShellExecuteEx() the HPROCESS returned is NULL.
2. Using a kernel mode driver to access the native NT object manager requires that the user has service install priveleges - which won't always be the case (this is the technique used by HandleEx, www.sysinternals.com , and it's clones on www.codeguru.com). It also means relying on undocumented functionality in NT. :-(

Can anyone help?

(My target OS is NT4, Win2K & XP)
Question by:abancroft
  • 4
  • 2
  • 2
  • +1

Expert Comment

ID: 7998218
Hi abancroft!

Below sample code about this :


ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.lpFile = (LPCSTR)szPath;
sei.lpParameters = (LPCSTR)szParams;
sei.nShow = SW_SHOW;


if (sei.hProcess)
    WaitForSingleObject(sei.hProcess, INFINITE);
    //do there what you need

LVL 49

Expert Comment

ID: 7998423
The documentation says that Avdey's code will fail for exactly the reason that abancroft cited.

My only idea is this:

Call FindExecutable(...) to obtain the name of the program that should be used to open the target data file (eg, obtain "d:\path\winword.exe" when passing in "myfile.doc").  Then use CreateProcess(...) to open that program, passing in the name of the file as the command-line parameter.

Perhaps it would be worth checking this out:  The HINSTANCE might have an undocumented meaning in this case where DDE was used to open the document.  Try setting the SEE_MASK_FLAG_DDEWAIT flag and seeing if there is any hope there.

-- Dan
LVL 20

Expert Comment

ID: 7998751
Perhaps FindExecutable + CreateProcess works better? Perhaps that works without DDE...
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

LVL 49

Expert Comment

ID: 7999998
You could play around with the START command of a DOS box.  
   START /WAIT MyProg.Exe
is said to wait until MyProg.Exe (or MyFile.Doc?) is finished.  Maybe the programmers of the START command have found an answer to your problem.

Also, I don't think you can ever be 100% certain.  For instance, some programs limit themsleves to running just one copy.  Thy set a system global Mutex and early on in the startup they check to see if it is set, and if so, they post a message to the other (original) program telling it to come to the front and to open any file passed as a command-line parm.  In this case, the program that was launched would quit right away, so the desired processing (that is, taking action on the filename passed as a parameter) would not be finished.

There may be other angles of attack.  Please answer these questions:
1) Why do you wish to know when the executed program finishes?  
2) What is your actual goal?.

-- Dan

Expert Comment

ID: 8002073
Hi guys !
What can i said ? I check this code under NT4.0 (launch *.bmp file, i.e. szPath == "x:\path\filename.bmp", szParams == "") and it's work fine.
LVL 49

Expert Comment

ID: 8002126
Try that with a WORD file (myfile.doc) when MS WORD is already running with another document open.  That is the question posted by abancroft.
-- Dan

Author Comment

ID: 8009175
Wow - lots of activity over a weekend! (maybe that's how to rack up expert points....:-)

Avdey - ShellExecuteEx() will not work. I describe one situation where the hProcess will always be NULL in the question.

DanRollins - I wasn't aware of the FindExecutable() API, despite looking! (sometimes it's difficult to find what you're looking for in MSDN). It may help somewhat, but as you say some programs limit themselves to one instance (the program I work on does this using the technique you describe).

In detail, here's what I'm trying to do:
1. In a database, the user can store files.
2. From the app, the user can double click on a 'file' & it is saved to a temp file & opened using the app associated with.
3. Now the user can edit the file - but when they save it, it is saved to the temp file, not the DB.

So far, so good. But it'd be nice if we could update the file in the DB when the user saves to the temp file (i.e. keep them in sync). No problem, just use FindFirstChangeNotification/FindNextChangeNotification.

But I need to know when the user has finished editing the file, so I can shut down my app and delete the temp file. To do this, I thought I'd get the process handle of the editing app & use WaitForSingleObject.

But it turns out that 'get the process handle' is a difficult task.
LVL 49

Accepted Solution

DanRollins earned 800 total points
ID: 8010268
Thanks for the complete description.

The important part -- getting the updates into the database -- is done.  I think you have the 96% and are working on the last 4%.   Maybe you can squeeze out another 2% by using FindExecutable and EnumProcess and then learn when that program closes.  When it does, you can know to cleanup the temp.

Then what's left is just a few programs that the user saved but left Word or Excel open for some reason.   You can get 1% more by handling WM_QUERYENDSESSION (indicate Windows is about to restart).

Now the last 1%:  
Use a recognizable naming scheme (such as  
for your temp files.  When your program starts up, go through and delete all such files -- they were left over from the last time that your program ran and the system crashed.

-- Dan

Author Comment

ID: 8011896
FindExecutable and EnumProcess work very well:
1. Record original file attributes in a WIN32_FIND_DATA.
2. Figure out the EXE using FindExecutable().
3. Launch using ShellExecute()
4. Get the process handle(s) using EnumProcess/EnumProcessModules/GetModuleFileNameEx.
5. Wait for process(es) to finish
6. Get new file attributes in a WIN32_FIND_DATA
7. Compare both WIN32_FIND_DATA structs to see if file has changed.

This works for straight app launching (e.g. notepad), DDE programs (e.g. Word, IE) and singleton apps (e.g. Outlook).

Thx Dan.

Featured Post

[Webinar] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Screencast - Getting to Know the Pipeline

564 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question