10 out of 64 rated this helpful Rate this topic

ShellExecuteEx function

Performs an operation on a specified file.

Syntax

BOOL ShellExecuteEx(
  __inout  LPSHELLEXECUTEINFO lpExecInfo
);

Parameters

lpExecInfo [in, out]

Type: LPSHELLEXECUTEINFO

A pointer to a SHELLEXECUTEINFO structure that contains and receives information about the application being executed.

Return value

Type: BOOL

Returns TRUE if successful; otherwise, FALSE. Call GetLastError for extended error information.

Remarks

Because ShellExecuteEx can delegate execution to Shell extensions (data sources, context menu handlers, verb implementations) that are activated using Component Object Model (COM), COM should be initialized before ShellExecuteEx is called. Some Shell extensions require the COM single-threaded apartment (STA) type. In that case, COM should be initialized as shown here:

CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)

There are instances where ShellExecuteEx does not use one of these types of Shell extension and those instances would not require COM to be initialized at all. Nonetheless, it is good practice to always initalize COM before using this function.

When DLLs are loaded into your process, you acquire a lock known as a loader lock. The DllMain function always executes under the loader lock. It is important that you do not call ShellExecuteEx while you hold a loader lock. Because ShellExecuteEx is extensible, you could load code that does not function properly in the presence of a loader lock, risking a deadlock and therefore an unresponsive thread.

With multiple monitors, if you specify an HWND and set the lpVerb member of the SHELLEXECUTEINFO structure pointed to by lpExecInfo to "Properties", any windows created by ShellExecuteEx might not appear in the correct position.

If the function succeeds, it sets the hInstApp member of the SHELLEXECUTEINFO structure to a value greater than 32. If the function fails, hInstApp is set to the SE_ERR_XXX error value that best indicates the cause of the failure. Although hInstApp is declared as an HINSTANCE for compatibility with 16-bit Windows applications, it is not a true HINSTANCE. It can be cast only to an int and can be compared only to either the value 32 or the SE_ERR_XXX error codes.

The SE_ERR_XXX error values are provided for compatibility with ShellExecute. To retrieve more accurate error information, use GetLastError. It may return one of the following values.

ErrorDescription
ERROR_FILE_NOT_FOUND The specified file was not found.
ERROR_PATH_NOT_FOUND The specified path was not found.
ERROR_DDE_FAIL The Dynamic Data Exchange (DDE) transaction failed.
ERROR_NO_ASSOCIATION There is no application associated with the specified 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 additional information, 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.

 

Requirements

Minimum supported client

Windows XP

Minimum supported server

Windows 2000 Server

Header

Shellapi.h

Library

Shell32.lib

DLL

Shell32.dll (version 3.51 or later)

Unicode and ANSI names

ShellExecuteExW (Unicode) and ShellExecuteExA (ANSI)

See also

ShellExecute
IShellExecuteHook
CoInitializeEx

 

 

Send comments about this topic to Microsoft

Build date: 9/7/2011

Did you find this helpful?
(2000 characters remaining)
Community Content Add
Annotations FAQ
Missing Text
MISSING TEXT
MISSING TEXT
Still Missing
Open with VB 2008 to the Summary Tab
This didn't work>>> 'Private Declare Function ShellExecuteEx Lib "shell32.dll" (ByVal SEI As SHELLEXECUTEINFO) As Integer Used this>>> Private Declare Function ShellExecuteEx Lib "shell32.dll" Alias "ShellExecuteExA" (ByRef lpExecInfo As SHELLEXECUTEINFO) As Boolean To get the Summary Tab Set lpParameters to "summary"
Messages still appear

SEE_MASK_FLAG_NO_UISEE_MASK_FLAG_NO_UISEE_MASK_FLAG_NO_UI
SEE_MASK_FLAG_NO_UI does not disable the message popup indicating there is no association found for the file.  (search internet or select from list of programs choice)

Returns (hInstApp==42) when a file association is not set for a file, and the dialog pops up.


Using lpExecInfo->lpClass and lpExecInfo->hkeyClass

If you are afraid ShellExecute(Ex) might misidentify the file type, because the path might be ambiguous or if you use a non-standard type system, you can force one by filling the lpClass or hkeyClass fields in lpExecInfo. You set lpClass to either the extension (e.g. ".txt") or the URL scheme (e.g. "http") or the OLE ProgId/ClassId; better yet, you use AssocQueryKey to retrieve the appropriate hkeyClass for the given class name and verb. For example, this is how you safely execute URLs with ShellExecute(Ex):

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <shellapi.h>
#include <shlwapi.h>
#include <wininet.h>

#include <strsafe.h>

BOOL ShellExecuteURLExInternal(LPSHELLEXECUTEINFO lpExecInfo)
{
    BOOL bRet;
    DWORD dwErr;
    HRESULT hr;
    PARSEDURL pu;
    TCHAR szSchemeBuffer[INTERNET_MAX_SCHEME_LENGTH + 1];
    HKEY hkeyClass;

    /* Default error codes */
    bRet = FALSE;
    dwErr = ERROR_INVALID_PARAMETER;
    hr = S_OK;

    lpExecInfo->hInstApp =
        (HINSTANCE)UlongToHandle(SE_ERR_ACCESSDENIED);

    /* Validate parameters */
    if
    (
        lpExecInfo->cbSize == sizeof(*lpExecInfo) &&
        lpExecInfo->lpFile != NULL &&
        (lpExecInfo->fMask & SEE_MASK_INVOKEIDLIST) == 0 &&
        (lpExecInfo->fMask & SEE_MASK_CLASSNAME) == 0 &&
        (lpExecInfo->fMask & 0x00400000) == 0 /* SEE_MASK_FILEANDURL */
    )
    {
        /* Extract the scheme out of the URL */
        pu.cbSize = sizeof(pu);
        hr = ParseURL(lpExecInfo->lpFile, &pu);

        /* Is the URL really, unambiguously an URL? */
        if
        (
            SUCCEEDED(hr) &&
            pu.pszProtocol == lpExecInfo->lpFile &&
            pu.pszProtocol[pu.cchProtocol] == TEXT(':')
        )
        {
            /* We need the scheme name NUL-terminated, so we copy it */
            hr = StringCbCopyN
            (
                szSchemeBuffer,
                sizeof(szSchemeBuffer),
                pu.pszProtocol,
                pu.cchProtocol * sizeof(TCHAR)
            );

            if(SUCCEEDED(hr))
            {
                /* Is the URL scheme a registered ProgId? */
                hr = AssocQueryKey
                (
                    ASSOCF_INIT_IGNOREUNKNOWN,
                    ASSOCKEY_CLASS,
                    szSchemeBuffer,
                    NULL,
                    &hkeyClass
                );

                if(SUCCEEDED(hr))
                {
                    /* Is the ProgId really an URL scheme? */
                    dwErr = RegQueryValueEx
                    (
                        hkeyClass,
                        TEXT("URL Protocol"),
                        NULL,
                        NULL,
                        NULL,
                        NULL
                    );

                    /* All clear! */
                    if(dwErr == NO_ERROR || dwErr == ERROR_MORE_DATA)
                    {
                        /* Don't let ShellExecuteEx guess */
                        lpExecInfo->fMask |= SEE_MASK_CLASSKEY;
                        lpExecInfo->lpClass = NULL;
                        lpExecInfo->hkeyClass = hkeyClass;

                        /* Finally, execute the URL */
                        bRet = ShellExecuteEx(lpExecInfo);

                        /* To preserve ShellExecuteEx's last error */
                        dwErr = NO_ERROR;
                    }

                    RegCloseKey(hkeyClass);
                }
            }
        }
    }

    /* Last error was a HRESULT */
    if(FAILED(hr))
    {
        /* Try to dissect it */
        if(HRESULT_FACILITY(hr) == FACILITY_WIN32)
            dwErr = HRESULT_CODE(hr);
        else
            dwErr = hr;
    }

    /* We have a last error to set */
    if(dwErr)
        SetLastError(dwErr);

    return bRet;
}

BOOL ShellExecuteURLEx(LPSHELLEXECUTEINFO lpExecInfo)
{
    BOOL bRet;
    SHELLEXECUTEINFO ExecInfo;

    /* We use a copy of the parameters, because you never know */
    CopyMemory(&ExecInfo, lpExecInfo, sizeof(ExecInfo));

    /* Do the magic */
    bRet = ShellExecuteURLExInternal(&ExecInfo);

    /* These need to be copied back */
    lpExecInfo->hInstApp = ExecInfo.hInstApp;
    lpExecInfo->hProcess = ExecInfo.hProcess;
    return bRet;
}

HINSTANCE ShellExecuteURL
(
    HWND hwnd,
    LPCTSTR lpOperation,
    LPCTSTR lpFile,
    LPCTSTR lpParameters,
    LPCTSTR lpDirectory,
    INT nShowCmd
)
{
    SHELLEXECUTEINFO ExecuteInfo;

    ExecuteInfo.fMask = SEE_MASK_FLAG_NO_UI; /* Odd but true */
    ExecuteInfo.hwnd = hwnd;
    ExecuteInfo.cbSize = sizeof(ExecuteInfo);
    ExecuteInfo.lpVerb = lpOperation;
    ExecuteInfo.lpFile = lpFile;
    ExecuteInfo.lpParameters = lpParameters;
    ExecuteInfo.lpDirectory = lpDirectory;
    ExecuteInfo.nShow = nShowCmd;

    ShellExecuteURLExInternal(&ExecuteInfo);

    return ExecuteInfo.hInstApp;
}

Note that we use ParseURL instead of more sophisticated functions like InternetCrackUrl because it's much more forgiving, and we only need to extract the scheme anyway

vb.net syntax
<DllImport("shell32.dll", EntryPoint:="ShellExecuteEx")> _
Private Shared Function ShellExecute(ByRef s As SHELLEXECUTEINFO) As Integer
End Function
C# syntax
[DllImport("shell32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool ShellExecuteEx(ShellExecuteInfo info);
How to display file/folder properties dialog (VB.net)
Input: File Patch to display File Properties and handle to Form

Public Shared Sub DisplayFileProperties(ByVal xFileName As String, ByVal hwnd As IntPtr)
Const SEE_MASK_INVOKEIDLIST As Integer = &HC
Const SW_SHOW As Integer = 5
Dim shInfo As New SHELLEXECUTEINFO()
With shInfo
.cbSize = Marshal.SizeOf(shInfo)
.lpFile = xFileName
.nShow = SW_SHOW
.fMask = SEE_MASK_INVOKEIDLIST
.lpVerb = "properties"
.hwnd = hwnd
End With
ShellExecute(shInfo)
End Sub

<StructLayout(LayoutKind.Sequential)> Private Structure SHELLEXECUTEINFO
Public cbSize As Integer
Public fMask As Integer
Public hwnd As IntPtr
Public lpVerb As String
Public lpFile As String
Public lpParameters As String
Public lpDirectory As String
Public nShow As Integer
Public hInstApp As IntPtr
Public lpIDList As IntPtr
Public lpClass As String
Public hkeyClass As IntPtr
Public dwHotKey As Integer
Public hIcon As IntPtr
Public hProcess As IntPtr
End Structure
ShellExecuteEx ignores current input desktop.
ShellExecuteEx ignores the current input desktop. It always uses winsta0\default.
Instead use ShellExecute or CreateProcess.
Failing with ERROR_NOT_SUPPORTED
Perhaps it should be noted that the function fails with GetLastError() == ERROR_NOT_SUPPORTED when starting executable that requires elevation on Windows Vista and the SEE_MASK_FLAG_DDEWAIT was not used. At least this is how it behaves on my laptop. The solution obviously is to include the flag.