[2 days left] What’s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now


Killing a Word session

Posted on 1999-01-19
Medium Priority
Last Modified: 2008-03-10

I created a Word session from C++ using:

hErrorCode = ShellExecute (hParent, "open", "winword.exe", sTemplate, NULL, SW_HIDE);

I like to close it, but I always have the system error 6 (invalide handle) using:

HWND hParent;
LPDWORD pExitCode;
UINT uExitCode;
hWord = (HANDLE) lErrorCode;
Response = GetExitCodeProcess(hWord, pExitCode);
if (Response == 0)
   lReturnCode = GetLastError();
 uExitCode = (UINT) pExitCode;
 Response = TerminateProcess(hWord, uExitCode);

Obviously it is a wrong type conversion.

Can you help me?

Question by:SergeD
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
  • 3
LVL 22

Expert Comment

ID: 1184548
The return value of ShellExecute is an HINSTANCE, that is not a process handle (which is what TerminateProcess needs.  You cannot get the process handle using ShellExecute().  Use CreateProcess() instead.

Expert Comment

ID: 1184549
The return value of ShellExecute can't be used as a process handle. The online help says that the value that ShellExecute returns
. "a value greater than 32 if successful, or an error value that is less than or equal to 32 otherwise. The following table lists the error values. The return value is cast as an HINSTANCE for backward compatibility with 16-bit Microsoft® Windows® applications. It is not a true HINSTANCE, however. The only thing that can be done with the returned HINSTANCE is to cast it to an integer and compare it with the value 32 or one of the error codes below." ...

Use CreateProcess instead of ShellExecute to obtain the process handle, or find the process id (the method depends if it is Windows 95/98 or Windows NT, I'm not familiar with anything else but NT) and use OpenProcess for that process id. And furthermore, before trying to use the TerminateProcess call, try to send a WM_CLOSE window message to the Word's main window (for example using using FindWindow).
LVL 22

Expert Comment

ID: 1184550
Note The last parameter to CreateProcess() is a pointer to a PROCESS_INFORMATION structure.  This gets filled in with the new process's handle and its primary thread's handle.  You need to use this process handle.  Both these handles must be closed when you are done with them.  You probably don't need the thread handle so you can close it immediately.  The process handle you can close when you terminate the process.

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.


Author Comment

ID: 1184551
Thanx nietod (and stefanr).

The problem with CreateProcess is that the system will not use a running Word session if it exists, but will create a new one for each single call. That's not really what I'm looking for. I definitevely need a ShellExecute (unless there is another function that can do the job. I'm not aware of such other function).

Unfortunately the problem remains. How to kill a running session created (or not) with ShellExecute)?

Thanx to both of you.


Accepted Solution

stefanr earned 100 total points
ID: 1184552
There is another form for ShellExecute, namely ShellExecuteEx, that can return additional information like a process handle.
In the online help it says


Performs an action on a file.

Returns a nonzero value if successful, or zero otherwise. To get extended error information, call the GetLastError function.
Address of a SHELLEXECUTEINFO structure that contains and receives information about the application being executed.
If the function succeeds, it sets the hInstApp member of the SHELLEXECUTEINFO structure to the instance handle to the application that the function started. If the function fails, hInstApp is one of the SE_ERR_ error values indicating the cause of the failure. (An instance handle will always be greater than 32 and an error value less than 32.) Note that the SE_ERR_ error values are for compatibility with the ShellExecute function; use the GetLastError function to retrieve error information.

The error values returned by GetLastError correspond to the SE_ERR_ values and may be one of the following: ERROR_FILE_NOT_FOUND  The specified file was not found.  
ERROR_PATH_NOT_FOUND  The specified path was not found.  
ERROR_DDE_FAIL  The DDE transaction failed.  
ERROR_NO_ASSOCIATION  There is no application associated with the given file name extension.  
ERROR_ACCESS_DENIED  Access to the specified file is denied.  
ERROR_DLL_NOT_FOUND  One of the library files necessary to run the application can't be found.  
ERROR_CANCELLED  The function prompted the user for the location of the application, but the user canceled the request.  
ERROR_NOT_ENOUGH_MEMORY  There is not enough memory to perform the specified action.  
ERROR_SHARING_VIOLATION  A sharing violation occurred.

And the SHELLEXECUTEINFO structure has the following definition

typedef struct _SHELLEXECUTEINFO{
    DWORD cbSize;
    ULONG fMask;
    HWND hwnd;
    LPCTSTR lpVerb;
    LPCTSTR lpFile;
    LPCTSTR lpParameters;
    LPCTSTR lpDirectory;
    int nShow;
    HINSTANCE hInstApp;

    // Optional members
    LPVOID lpIDList;
    LPCSTR lpClass;
    HKEY hkeyClass;
    DWORD dwHotKey;
    HANDLE hIcon;
    HANDLE hProcess;

The last member of the structure is a hProcess which is described as

Handle to the newly started application. This member is set on return and is always NULL if fMask is not set to SEE_MASK_NOCLOSEPROCESS.

That hProcess is what you need to kill a process. Still, it is recommended to send a WM_CLOSE message to the main window as described before, and if that fails call TerminateProcess.
LVL 22

Expert Comment

ID: 1184553
For what its worth, I agree with stefanr that you should use TerminateProcess only as a last resort.  Try to close Word by sending it a WM_CLOSE command first.

Author Comment

ID: 1184554
Hi Lads,

sorry for the delay.
I have tried the SendMessage function, but it requires the windows handle of the application (HWND). With the ShellExecute, I have the process handle (HINSTANCE). How can I get the windows handle? Specially in the case where I'm launching a Word session with the HIDE parameter (I cannot use the GetActiveWindows function)?

Have you read 1984? Sometimes C++ appears to be really like this!


LVL 22

Expert Comment

ID: 1184555
You can use FindWindow() or use EnumWindows() along with GetWindowThreadProcessId().

Expert Comment

ID: 1184556
In the MSDN Article Q178893 (HOWTO: Terminate an Application "Cleanly" in Win32) it says that

."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. For additional information, please see the following article in the Microsoft Knowledge Base:

   TITLE     : HOWTO: Detect Closure of Command Window from a Console

   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)."...

Unfortunately, there seem not to be a simple way of matching the process id retrieved with GetWindowThreadProcessId to the hProcess returned by the ShellExecuteEx function. I can only find functions to retrieve the process id of the CURRENT process. Maybe there would be a way using the Performance Data (on NT) or the Tool Help functions (on Windows 95/98).
One simpler idea would be to use the HWND obtained through the EnumWindows callback function and call GetWindowText. If the obtained caption string contains the text "Microsoft Word" you would be pretty sure that you have found it. Then you could send it the WM_CLOSE message.
LVL 22

Expert Comment

ID: 1184557
CreateProcess() returns the child process's handle and ID, as well as the primary thread's handle and ID, unfortuantely ShellExecute() does not.

You can try obtaining a window's proccess ID and converting it to a handle using OpenProcess(), and then comparing that with the handle you have for the word process.  However, I don't think that two handles to a process are necessarily the same, but you could try that.

Author Comment

ID: 1184558
Thank you both for your suggestions!

I haven't too much time to investigate now all your suggestions, so I close the question and hope that I will find a definitive solution next week.

Thank you for all

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

649 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