diff --git a/dll/shellext/netshell/shfldr_netconnect.cpp b/dll/shellext/netshell/shfldr_netconnect.cpp index 30689990fcd..38e743fb533 100644 --- a/dll/shellext/netshell/shfldr_netconnect.cpp +++ b/dll/shellext/netshell/shfldr_netconnect.cpp @@ -672,6 +672,7 @@ HRESULT WINAPI CNetConUiObject::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) } case IDS_NET_STATUS: { + // TODO: Windows does not display this with an owner window return ShowNetConnectionStatus(m_lpOleCmd, m_pidl, lpcmi->hwnd); } case IDS_NET_REPAIR: @@ -837,27 +838,6 @@ HRESULT WINAPI CNetworkConnections::GetCurFolder(PIDLIST_ABSOLUTE *pidl) return S_OK; } -/************************************************************************ - * ISF_NetConnect_ShellExecuteHookW_Execute - */ -HRESULT WINAPI CNetworkConnections::Execute(LPSHELLEXECUTEINFOW pei) -{ - PCUITEMID_CHILD pidl = ILFindLastID((ITEMIDLIST*)pei->lpIDList); - PNETCONIDSTRUCT pdata = ILGetConnData(pidl); - if (!pdata) - { - ERR("Got invalid pidl\n"); - return E_FAIL; - } - - if (pdata->Status == NCS_CONNECTED) - { - return ShowNetConnectionStatus(m_lpOleCmd, pidl, pei->hwnd); - } - - return S_OK; -} - HRESULT WINAPI CNetworkConnections::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) { FIXME("CNetworkConnections::Initialize()\n"); diff --git a/dll/shellext/netshell/shfldr_netconnect.h b/dll/shellext/netshell/shfldr_netconnect.h index 4e081739020..21486cd65ce 100644 --- a/dll/shellext/netshell/shfldr_netconnect.h +++ b/dll/shellext/netshell/shfldr_netconnect.h @@ -14,8 +14,7 @@ class CNetworkConnections: public IShellExtInit, public IShellFolder2, public IOleCommandTarget, - public IShellFolderViewCB, - public IShellExecuteHookW + public IShellFolderViewCB { public: CNetworkConnections(); @@ -57,9 +56,6 @@ class CNetworkConnections: // IShellFolderViewCB STDMETHOD(MessageSFVCB)(UINT uMsg, WPARAM wParam, LPARAM lParam) override; - // IShellExecuteHookW - STDMETHOD(Execute)(LPSHELLEXECUTEINFOW pei) override; - private: /* both paths are parsible from the desktop */ @@ -77,7 +73,6 @@ class CNetworkConnections: COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB) - COM_INTERFACE_ENTRY_IID(IID_IShellExecuteHookW, IShellExecuteHookW) END_COM_MAP() DECLARE_NO_REGISTRY() diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp b/dll/win32/shell32/CDefaultContextMenu.cpp index 6f9a8aef4f7..c815e75fb75 100644 --- a/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/dll/win32/shell32/CDefaultContextMenu.cpp @@ -1397,10 +1397,9 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFOEX lpcmi, LPCITEMIDLIST pid if (!sei.lpClass && (lpcmi->fMask & (CMIC_MASK_HASLINKNAME | CMIC_MASK_HASTITLE)) && unicode) sei.lpClass = lpcmi->lpTitleW; // Forward .lnk path from CShellLink::DoOpen (for consrv STARTF_TITLEISLINKNAME) - ShellExecuteExW(&sei); + HRESULT hr = ShellExecuteExW(&sei) ? S_OK : HResultFromWin32(GetLastError()); ILFree(pidlFull); - - return S_OK; + return hr; } HRESULT diff --git a/dll/win32/shell32/propsheet.cpp b/dll/win32/shell32/propsheet.cpp index 7768e16c358..a24faf3314e 100644 --- a/dll/win32/shell32/propsheet.cpp +++ b/dll/win32/shell32/propsheet.cpp @@ -27,7 +27,7 @@ SHELL_InitializeExtension(REFCLSID clsid, PCIDLIST_ABSOLUTE pidlFolder, IDataObj { *ppv = NULL; IUnknown *pUnk; - HRESULT hr = SHCoCreateInstance(NULL, &clsid, NULL, riid, (void**)&pUnk); + HRESULT hr = SHExtCoCreateInstance(NULL, &clsid, NULL, riid, (void**)&pUnk); if (SUCCEEDED(hr)) { CComPtr Init; diff --git a/dll/win32/shell32/shell32.spec b/dll/win32/shell32/shell32.spec index 58da27c1864..c10620c236e 100644 --- a/dll/win32/shell32/shell32.spec +++ b/dll/win32/shell32/shell32.spec @@ -98,7 +98,7 @@ 99 stdcall -noname SetAppStartingCursor(long long) 100 stdcall SHRestricted(long) 101 stdcall OpenAs_RunDLLA(long long str long) -102 stdcall SHCoCreateInstance(wstr ptr long ptr ptr) +102 stdcall SHCoCreateInstance(wstr ptr ptr ptr ptr) 103 stdcall SignalFileOpen(ptr) 104 stdcall OpenAs_RunDLLW(long long wstr long) 105 stdcall Activate_RunDLL(ptr ptr wstr long) @@ -467,3 +467,4 @@ 755 stdcall -noname PathIsEqualOrSubFolder(wstr wstr) 756 stub -noname DeleteFileThumbnail 757 stdcall -version=0x600+ DisplayNameOfW(ptr ptr long ptr long) +866 stdcall -version=0x600+ SHExtCoCreateInstance(wstr ptr ptr ptr ptr) diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp index ec9db2fd305..3552cac5a4a 100644 --- a/dll/win32/shell32/shlexec.cpp +++ b/dll/win32/shell32/shlexec.cpp @@ -33,6 +33,42 @@ EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath); typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out); +static int Win32ErrFromHInst(HINSTANCE hInst) +{ + if ((SIZE_T)hInst > 32) + return ERROR_SUCCESS; + switch ((SIZE_T)hInst) + { + case SE_ERR_FNF: + case SE_ERR_PNF: + case SE_ERR_ACCESSDENIED: + case SE_ERR_OOM: + return (UINT)(SIZE_T)hInst; + case SE_ERR_SHARE: + return ERROR_SHARING_VIOLATION; + case SE_ERR_DDETIMEOUT: + case SE_ERR_DDEFAIL: + case SE_ERR_DDEBUSY: + return ERROR_DDE_FAIL; + case SE_ERR_DLLNOTFOUND: + return ERROR_DLL_NOT_FOUND; + //case SE_ERR_ASSOCINCOMPLETE: Note: Windows treats this as a success code + case SE_ERR_NOASSOC: + return ERROR_NO_ASSOCIATION; + case 10: + return ERROR_OLD_WIN_VERSION; + case 12: + return ERROR_APP_WRONG_OS; + case 15: + return ERROR_RMODE_APP; + case 16: + return ERROR_SINGLE_INSTANCE_APP; + case 20: + return ERROR_INVALID_DLL; + } + return -1; +} + // Is the current process a rundll32.exe? static BOOL SHELL_InRunDllProcess(VOID) { @@ -60,6 +96,57 @@ static UINT_PTR InvokeOpenWith(HWND hWndOwner, SHELLEXECUTEINFOW &sei) return SUCCEEDED(hr) ? 42 : SE_ERR_NOASSOC; } +static HRESULT InvokeShellExecuteHook(PCWSTR pszClsid, LPSHELLEXECUTEINFOW pSEI) +{ + CComPtr pUnk; + if (FAILED(SHExtCoCreateInstance(pszClsid, NULL, NULL, IID_PPV_ARG(IUnknown, &pUnk)))) + return S_FALSE; + CComPtr pWide; + if (SUCCEEDED(pUnk->QueryInterface(IID_PPV_ARG(IShellExecuteHookW, &pWide)))) + return pWide->Execute(pSEI); + HRESULT hr = S_FALSE; +#if 0 // TODO + CComPtr pAnsi; + if (SUCCEEDED(pUnk->QueryInterface(IID_PPV_ARG(IShellExecuteHookA, &pAnsi)))) + { + SHELLEXECUTEINFOA sei = *(SHELLEXECUTEINFOA*)pSEI; + // TODO: Convert the strings + hr = pAnsi->Execute(sei); + pSEI->hProcess = sei.hProcess; + pSEI->hInstApp = sei.hInstApp; + } +#endif + return hr; +} + +static HRESULT TryShellExecuteHooks(LPSHELLEXECUTEINFOW pSEI) +{ + // https://devblogs.microsoft.com/oldnewthing/20080910-00/?p=20933 claims hooks + // were removed in Vista but this is incorrect, they are disabled by default. + // https://groups.google.com/g/microsoft.public.platformsdk.shell/c/ixdOX1--IKk + // says they are now controlled by the EnableShellExecuteHooks policy. + if (pSEI->fMask & SEE_MASK_NO_HOOKS) + return S_FALSE; + if (LOBYTE(GetVersion()) >= 6 && !SH32_InternalRestricted(REST_SH32_ENABLESHELLEXECUTEHOOKS)) + return S_FALSE; + + HRESULT hr = S_FALSE; + HKEY hKey; + LRESULT res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REGSTR_PATH_EXPLORER L"\\ShellExecuteHooks", 0, KEY_READ, &hKey); + if (res != ERROR_SUCCESS) + return S_FALSE; + for (UINT i = 0; hr == S_FALSE; ++i) + { + WCHAR szClsid[42]; + DWORD cch = _countof(szClsid); + if (RegEnumValueW(hKey, i, szClsid, &cch, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + break; + hr = InvokeShellExecuteHook(szClsid, pSEI); + } + RegCloseKey(hKey); + return hr; +} + static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum) { bool firstCharQuote = false; @@ -1968,6 +2055,20 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ? debugstr_w(sei_tmp.lpClass) : "not used"); + // Call hooks before expanding and resolving strings + HRESULT hr = TryShellExecuteHooks(sei); + if (hr != S_FALSE) + { + int err = Win32ErrFromHInst(sei->hInstApp); + if (err <= 0) + { + sei->hInstApp = (HINSTANCE)UlongToHandle(42); + return TRUE; + } + SetLastError(err); + return FALSE; + } + /* make copies of all path/command strings */ CHeapPtr wszApplicationName; DWORD dwApplicationNameLen = MAX_PATH + 2; @@ -2083,16 +2184,6 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) (sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) != SEE_MASK_INVOKEIDLIST) { LPCITEMIDLIST pidl = (LPCITEMIDLIST)sei_tmp.lpIDList; - - CComPtr pSEH; - HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellExecuteHookW, &pSEH), NULL); - if (SUCCEEDED(hr)) - { - hr = pSEH->Execute(&sei_tmp); - if (hr == S_OK) - return TRUE; - } - hr = SHGetNameAndFlagsW(pidl, SHGDN_FORPARSING, wszApplicationName, dwApplicationNameLen, NULL); if (FAILED(hr)) { @@ -2117,7 +2208,7 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) if ((sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST) { - HRESULT hr = ShellExecute_ContextMenuVerb(&sei_tmp); + hr = ShellExecute_ContextMenuVerb(&sei_tmp); if (SUCCEEDED(hr)) { sei->hInstApp = (HINSTANCE)42; @@ -2157,7 +2248,7 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) StrCmpNW(sei_tmp.lpFile, L"::{", 3) == 0)) { CComHeapPtr pidlParsed; - HRESULT hr = SHParseDisplayName(sei_tmp.lpFile, NULL, &pidlParsed, 0, NULL); + hr = SHParseDisplayName(sei_tmp.lpFile, NULL, &pidlParsed, 0, NULL); if (SUCCEEDED(hr) && SHELL_InvokePidl(&sei_tmp, pidlParsed)) { sei_tmp.hInstApp = (HINSTANCE)UlongToHandle(42); @@ -2352,7 +2443,7 @@ HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd); sei.cbSize = sizeof(sei); - sei.fMask = SEE_MASK_FLAG_NO_UI; + sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNKNOWN_0x1000; sei.hwnd = hWnd; sei.lpVerb = lpVerb; sei.lpFile = lpFile; @@ -2520,7 +2611,7 @@ HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, TRACE("\n"); sei.cbSize = sizeof(sei); - sei.fMask = SEE_MASK_FLAG_NO_UI; + sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNKNOWN_0x1000; sei.hwnd = hwnd; sei.lpVerb = lpVerb; sei.lpFile = lpFile; diff --git a/dll/win32/shell32/wine/PolicyData.h b/dll/win32/shell32/wine/PolicyData.h index 24de8cec9cb..a06984f8c52 100644 --- a/dll/win32/shell32/wine/PolicyData.h +++ b/dll/win32/shell32/wine/PolicyData.h @@ -305,3 +305,8 @@ DEFINE_POLICY( REST_USEDESKTOPINICACHE, "Explorer", "UseDesk // NOTE: This is a SHDOCVW-only policy. // DEFINE_POLICY( 0x50000024, "Explorer", "NoFileUrl" ), + +#if defined(__REACTOS__) && defined(_SHELL32_) +// Internal SHELL32 policies (keep these at the end of the list) +DEFINE_POLICY( REST_SH32_ENABLESHELLEXECUTEHOOKS, "Explorer", "EnableShellExecuteHooks" ), +#endif diff --git a/dll/win32/shell32/wine/shell32_main.h b/dll/win32/shell32/wine/shell32_main.h index c983a487d84..0cd360feba8 100644 --- a/dll/win32/shell32/wine/shell32_main.h +++ b/dll/win32/shell32/wine/shell32_main.h @@ -37,7 +37,10 @@ extern HMODULE huser32 DECLSPEC_HIDDEN; extern HINSTANCE shell32_hInstance DECLSPEC_HIDDEN; extern int (WINAPI* SHELL_StrCmpLogical)(PCWSTR s1, PCWSTR s2); -BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList); +enum { + REST_SH32_ENABLESHELLEXECUTEHOOKS = 0x00060001, // POLID_EnableShellExecuteHooks +}; +DWORD SH32_InternalRestricted(DWORD rest); /* Iconcache */ #define INVALID_INDEX -1 @@ -48,6 +51,7 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags ) DE extern INT ShellLargeIconSize; extern INT ShellSmallIconSize; extern INT ShellIconBPP; +BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList); /* Classes Root */ HRESULT HCR_GetProgIdKeyOfExtension(PCWSTR szExtension, PHKEY phKey, BOOL AllowFallback); diff --git a/dll/win32/shell32/wine/shellole.c b/dll/win32/shell32/wine/shellole.c index 6ede109f92e..e9cd279d850 100644 --- a/dll/win32/shell32/wine/shellole.c +++ b/dll/win32/shell32/wine/shellole.c @@ -193,6 +193,17 @@ end: return hres; } +HRESULT WINAPI SHExtCoCreateInstance( + _In_opt_ LPCWSTR aclsid, + _In_opt_ const CLSID *clsid, + _In_opt_ LPUNKNOWN pUnkOuter, + _In_ REFIID refiid, + _Out_ LPVOID *ppv) +{ + // TODO: Verify that this CLSID is allowed if REST_ENFORCESHELLEXTSECURITY is active + return SHCoCreateInstance(aclsid, clsid, pUnkOuter, refiid, ppv); +} + #ifndef __REACTOS__ /************************************************************************* * DllGetClassObject [SHELL32.@] diff --git a/dll/win32/shell32/wine/shpolicy.c b/dll/win32/shell32/wine/shpolicy.c index 8753f8cb573..06388e3cd50 100644 --- a/dll/win32/shell32/wine/shpolicy.c +++ b/dll/win32/shell32/wine/shpolicy.c @@ -163,7 +163,7 @@ static BOOL SHELL_QueryRestrictionsChanged(VOID) * b: 98Lite 2.0 (which uses many of these policy keys) http://www.98lite.net/ * c: 'The Windows 95 Registry', by John Woram, 1996 MIS: Press */ -DWORD WINAPI SHRestricted (RESTRICTIONS rest) +DWORD WINAPI SHRestricted(RESTRICTIONS rest) { TRACE("(0x%08lX)\n", rest); @@ -177,6 +177,12 @@ DWORD WINAPI SHRestricted (RESTRICTIONS rest) return SHRestrictionLookup(rest, NULL, s_PolicyTable, g_RestValues); } +DWORD SH32_InternalRestricted(DWORD rest) +{ + /* assert((rest & 0x00060000) == 0x00060000) */ + return SHRestricted(rest); +} + /************************************************************************* * SHSettingsChanged [SHELL32.244] * diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h index 9ceb08cc374..9d3af701068 100644 --- a/sdk/include/reactos/shellutils.h +++ b/sdk/include/reactos/shellutils.h @@ -670,7 +670,7 @@ public: #define CmicFlagsToSeeFlags(flags) ((flags) & SEE_CMIC_COMMON_FLAGS) static inline UINT SeeFlagsToCmicFlags(UINT flags) { - if (flags & SEE_MASK_CLASSNAME) + if ((flags & (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)) == SEE_MASK_CLASSNAME) flags &= ~(SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE); return flags & SEE_CMIC_COMMON_FLAGS; } diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h index 800b2b1c1cf..aab3a4ffa9f 100644 --- a/sdk/include/reactos/undocshell.h +++ b/sdk/include/reactos/undocshell.h @@ -678,10 +678,12 @@ HRESULT WINAPI ShellExecCmdLine( * CMINVOKECOMMANDINFOEX structure. */ #define SEE_MASK_UNKNOWN_0x1000 0x00001000 // FIXME: Name +#define SEE_MASK_NO_HOOKS 0x00002000 // https://www.yisu.com/ask/30968554.html #define SEE_MASK_HASLINKNAME 0x00010000 #define SEE_MASK_FLAG_SEPVDM 0x00020000 #define SEE_MASK_USE_RESERVED 0x00040000 #define SEE_MASK_HASTITLE 0x00080000 +#define SEE_MASK_FILEANDURL 0x00400000 // https://textslashplain.com/2019/09/25/web-to-app-communication-directinvoke/ HINSTANCE WINAPI RealShellExecuteA( @@ -783,6 +785,13 @@ HRESULT WINAPI SHCreateDefClassObject( void WINAPI SHFreeUnusedLibraries(void); +HRESULT WINAPI SHExtCoCreateInstance( + _In_opt_ LPCWSTR aclsid, + _In_opt_ const CLSID *clsid, + _In_opt_ LPUNKNOWN pUnkOuter, + _In_ REFIID refiid, + _Out_ LPVOID *ppv); + /* SHCreateLinks flags */ #define SHCLF_PREFIXNAME 0x01 #define SHCLF_CREATEONDESKTOP 0x02