I'm running this code.

SHELLEXECUTEINFO ExecuteInfo = { 0 };

    ExecuteInfo.cbSize       = sizeof(ExecuteInfo);
    ExecuteInfo.fMask        = 0;                
    ExecuteInfo.hwnd         = nullptr;                
    ExecuteInfo.lpVerb       = L"open";                                     
    ExecuteInfo.lpFile       = L"C:\\progra~1\\intern~1\\iexplore.exe";     
    ExecuteInfo.lpParameters = L"http://www.google.co.uk";              
    ExecuteInfo.lpDirectory  = nullptr;                                     
    ExecuteInfo.nShow        = SW_SHOW;
    ExecuteInfo.hInstApp     = nullptr;

    ShellExecuteEx(&ExecuteInfo);

    Sleep(5000);

    CloseWindow((HWND)ExecuteInfo.hwnd);

    exit(GetLastError());

It's not closing the window.
And it's exiting with code 1400 (invalid window handle)

Any idea's what I'm doing wrong?

Dani AI

Generated

The root cause is mixing window handles (HWND) with kernel object handles. SHELLEXECUTEINFO::hwnd is an input parent-window (not the created app's window), and WaitForSingleObject expects a kernel HANDLE (process/thread/event). Passing the hwnd to WaitForSingleObject produces WAIT_FAILED / GetLastError 6 (invalid handle). This explains the 1400/invalid-window-handle symptom and the WAIT_FAILED you saw. (learn.microsoft.com)

Correct sequence (summary): 1) check ShellExecuteEx return; 2) request a process handle by setting fMask = SEE_MASK_NOCLOSEPROCESS; 3) if sei.hProcess is non-NULL, call WaitForSingleObject(sei.hProcess, timeout) and then CloseHandle(sei.hProcess). Note that ShellExecuteEx still may return NULL for hProcess if no new process was created (for example a URL opened in an existing browser process or a DDE activation). Internet Explorer adds extra complications: Protected Mode and broker/low-integrity processes can mean the handle returned is not the visible UI process (or none at all). (learn.microsoft.com)

If a visible HWND is required, either attach via COM (ShellWindows / IWebBrowser2 as recommended) or locate the window for the launched PID by enumerating top-level windows and matching GetWindowThreadProcessId. Use EnumWindows + GetWindowThreadProcessId and filter by visibility/class to find the main IE frame. As suggested, waiting is correct — just wait on the process handle rather than an HWND. Example pattern (illustrative):

// request a process handle
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
ShellExecuteEx(&sei);
if (sei.hProcess) {
    WaitForSingleObject(sei.hProcess, 5000);
    CloseHandle(sei.hProcess);
} else {
    // fallback: EnumWindows/GetWindowThreadProcessId or use ShellWindows/IWebBrowser2
}

References: the SHELLEXECUTEINFO/hProcess behavior, WaitForSingleObject signature, window-enumeration approach, and IE protected-mode notes. (learn.microsoft.com)

Recommended Answers

All 5 Replies

you should call WaitForSingleObject() instead of Sleep(). Also you need to validate ShellExecute() did not return an error number.

Thank you for your reply.

If I add if(WaitForSingleObject(ExecuteInfo.hwnd,INFINITE) == 0xFFFFFFFF){exit(GetLastError());}; It errors out on that call with 0xfffffff (WAIT_FAILED) with get last error being 6 (The handle is invalid)

Which looks pretty much the same, I tested the execute function like so if (!ShellExecuteEx(&ExecuteInfo)) {exit(MessageBox(nullptr, L"ShellExecuteEx fail", L"Error", MB_OK));};
which appears to be fine.

I am expecting that call to fill in the HWND member, am I correct on that?

Seeing as you're wanting to close the window, the main problem you're going to have is that with protected mode/IE7+ the first process created is a broker process that then then launches a low integrity process. This second process is the one you see, but the handle returned from ShellExecuteEx or CreateProcess is the handle to the broker process, which isn't of much use to you.

Using the com interface IWebBrowser2 would allow you to close the window:

#include <ExDisp.h>
#include <comutil.h>

#pragma comment (lib, "comsupp")

int wmain()
{
    if (SUCCEEDED(OleInitialize(nullptr)))
    {
        IWebBrowser2 *pBrowser = nullptr;

        CoCreateInstance(
            CLSID_InternetExplorer, 
            nullptr, 
            CLSCTX_LOCAL_SERVER, 
            IID_IWebBrowser2, 
            reinterpret_cast<void**>(&pBrowser)
            );

        if (pBrowser)
        {
            VARIANT vEmpty;
            VariantInit(&vEmpty);

            _bstr_t strURL = L"http://www.google.co.uk";

            HRESULT hr = pBrowser->Navigate(strURL, &vEmpty, &vEmpty, &vEmpty, &vEmpty);
            if (SUCCEEDED(hr))
            {
                pBrowser->put_Visible(VARIANT_TRUE);
                // wait 5 seconds
                Sleep(5000);               
            }

            // close window and clean up
            pBrowser->Quit();
            pBrowser->Release();
        }

        OleUninitialize();
    }

    return 0;
}

nullptr, thank you for that, I never thought about doing it that way.
I do need the window handle though for other reasons, but the get_HWND method gives me that too.

Thank you very much for your time and help.
Suzie.

(edit)
I'm curious, is it possible with COM method, to interface with an already running instance on Internet Explorer?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.