https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bfcbda227f99c1b59e8ed…
commit bfcbda227f99c1b59e8ed71f5e0f59f793d496a1
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sun Aug 5 20:39:17 2018 +0900
Commit: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito(a)reactos.org>
CommitDate: Sun Aug 5 13:39:17 2018 +0200
[SHELL32] Fix handling of multiple parameters in the 'Run' dialog (#665)
The "Run" dialog failed when multiple parameters wee specified.
We use instead a newly-created ShellExecCmdLine() helper function to fix the problem
(as found via API-tracing on Windows).
Note that ShellExecCmdLine() starts to be exported with Vista+.
- Implement ShellExecCmdLine() function in shell32.
- Add URL support.
- Fix RunDlgProc function in shell32.
- Add a testcase for ShellExecCmdLine() function.
CORE-14790
---
dll/win32/shell32/dialogs/dialogs.cpp | 25 +-
dll/win32/shell32/shlexec.cpp | 180 +++++++
modules/rostests/apitests/shell32/CMakeLists.txt | 1 +
.../rostests/apitests/shell32/ShellExecCmdLine.cpp | 582 +++++++++++++++++++++
modules/rostests/apitests/shell32/testlist.c | 2 +
sdk/include/reactos/undocshell.h | 15 +
6 files changed, 790 insertions(+), 15 deletions(-)
diff --git a/dll/win32/shell32/dialogs/dialogs.cpp
b/dll/win32/shell32/dialogs/dialogs.cpp
index 168b066e28..77c1bdf5cc 100644
--- a/dll/win32/shell32/dialogs/dialogs.cpp
+++ b/dll/win32/shell32/dialogs/dialogs.cpp
@@ -527,7 +527,6 @@ static INT_PTR CALLBACK RunDlgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARA
HWND htxt = GetDlgItem(hwnd, IDC_RUNDLG_EDITPATH);
INT ic;
WCHAR *psz, *parent = NULL;
- SHELLEXECUTEINFOW sei;
NMRUNFILEDLGW nmrfd;
ic = GetWindowTextLengthW(htxt);
@@ -537,9 +536,6 @@ static INT_PTR CALLBACK RunDlgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARA
return TRUE;
}
- ZeroMemory(&sei, sizeof(sei));
- sei.cbSize = sizeof(sei);
-
/*
* Allocate a new MRU entry, we need to add two characters
* for the terminating "\\1" part, then the NULL
character.
@@ -552,10 +548,7 @@ static INT_PTR CALLBACK RunDlgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARA
}
GetWindowTextW(htxt, psz, ic + 1);
-
- sei.hwnd = hwnd;
- sei.nShow = SW_SHOWNORMAL;
- sei.lpFile = psz;
+ StrTrimW(psz, L" \t");
/*
* The precedence is the following: first the user-given
@@ -563,12 +556,13 @@ static INT_PTR CALLBACK RunDlgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARA
* directory is computed if the RFF_CALCDIRECTORY is set,
* otherwise no current directory is defined.
*/
+ LPCWSTR pszStartDir;
if (prfdp->lpstrDirectory)
- sei.lpDirectory = prfdp->lpstrDirectory;
+ pszStartDir = prfdp->lpstrDirectory;
else if (prfdp->uFlags & RFF_CALCDIRECTORY)
- sei.lpDirectory = parent = RunDlg_GetParentDir(sei.lpFile);
+ pszStartDir = parent = RunDlg_GetParentDir(psz);
else
- sei.lpDirectory = NULL;
+ pszStartDir = NULL;
/* Hide the dialog for now on, we will show it up in case of retry
*/
ShowWindow(hwnd, SW_HIDE);
@@ -585,9 +579,9 @@ static INT_PTR CALLBACK RunDlgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARA
nmrfd.hdr.code = RFN_VALIDATE;
nmrfd.hdr.hwndFrom = hwnd;
nmrfd.hdr.idFrom = 0;
- nmrfd.lpFile = sei.lpFile;
- nmrfd.lpDirectory = sei.lpDirectory;
- nmrfd.nShow = sei.nShow;
+ nmrfd.lpFile = psz;
+ nmrfd.lpDirectory = pszStartDir;
+ nmrfd.nShow = SW_SHOWNORMAL;
lRet = SendMessageW(prfdp->hwndOwner, WM_NOTIFY, 0,
(LPARAM)&nmrfd.hdr);
@@ -598,7 +592,8 @@ static INT_PTR CALLBACK RunDlgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARA
break;
case RF_OK:
- if (ShellExecuteExW(&sei))
+ if (SUCCEEDED(ShellExecCmdLine(hwnd, psz, pszStartDir,
SW_SHOWNORMAL, NULL,
+ SECL_ALLOW_NONEXE)))
{
/* Call again GetWindowText in case the contents of the
edit box has changed? */
GetWindowTextW(htxt, psz, ic + 1);
diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp
index 478a3c20b4..55b3d051fe 100644
--- a/dll/win32/shell32/shlexec.cpp
+++ b/dll/win32/shell32/shlexec.cpp
@@ -21,11 +21,13 @@
*/
#include "precomp.h"
+#include <undocshell.h>
WINE_DEFAULT_DEBUG_CHANNEL(exec);
static const WCHAR wszOpen[] = L"open";
static const WCHAR wszExe[] = L".exe";
+static const WCHAR wszCom[] = L".com";
#define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
@@ -2322,3 +2324,181 @@ OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int
cmdshow)
OpenAs_RunDLLW(hwnd, hinst, pszCmdLineW, cmdshow);
SHFree(pszCmdLineW);
}
+
+/*************************************************************************/
+
+static LPCWSTR
+SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
+{
+ LPCWSTR pch;
+ size_t ich = 0;
+ if (*psz == L'"')
+ {
+ // 1st argument is quoted. the string in quotes is quoted 1st argument.
+ // [pch] --> [pszArg0+ich]
+ for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch)
+ {
+ if (*pch == L'"' && pch[1] == L'"')
+ {
+ // doubled double quotations found!
+ pszArg0[ich] = L'"';
+ }
+ else if (*pch == L'"')
+ {
+ // single double quotation found!
+ ++pch;
+ break;
+ }
+ else
+ {
+ // otherwise
+ pszArg0[ich] = *pch;
+ }
+ }
+ }
+ else
+ {
+ // 1st argument is unquoted. non-space sequence is 1st argument.
+ // [pch] --> [pszArg0+ich]
+ for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0;
++ich, ++pch)
+ {
+ pszArg0[ich] = *pch;
+ }
+ }
+ pszArg0[ich] = 0;
+
+ // skip space
+ while (iswspace(*pch))
+ ++pch;
+
+ return pch;
+}
+
+HRESULT WINAPI ShellExecCmdLine(
+ HWND hwnd,
+ LPCWSTR pwszCommand,
+ LPCWSTR pwszStartDir,
+ int nShow,
+ LPVOID pUnused,
+ DWORD dwSeclFlags)
+{
+ SHELLEXECUTEINFOW info;
+ DWORD dwSize, dwError, dwType, dwFlags = SEE_MASK_DOENVSUBST | SEE_MASK_NOASYNC;
+ LPCWSTR pszVerb = NULL;
+ WCHAR szFile[MAX_PATH], szFile2[MAX_PATH];
+ HRESULT hr;
+ LPCWSTR pchParams;
+ LPWSTR lpCommand = NULL;
+
+ if (pwszCommand == NULL)
+ RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE,
+ 1, (ULONG_PTR*)pwszCommand);
+
+ __SHCloneStrW(&lpCommand, pwszCommand);
+ StrTrimW(lpCommand, L" \t");
+
+ if (dwSeclFlags & SECL_NO_UI)
+ dwFlags |= SEE_MASK_FLAG_NO_UI;
+ if (dwSeclFlags & SECL_LOG_USAGE)
+ dwFlags |= SEE_MASK_FLAG_LOG_USAGE;
+ if (dwSeclFlags & SECL_USE_IDLIST)
+ dwFlags |= SEE_MASK_INVOKEIDLIST;
+
+ if (dwSeclFlags & SECL_RUNAS)
+ {
+ dwSize = 0;
+ hr = AssocQueryStringW(0, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL,
&dwSize);
+ if (SUCCEEDED(hr) && dwSize != 0)
+ {
+ pszVerb = L"runas";
+ }
+ }
+
+ if (UrlIsFileUrlW(lpCommand))
+ {
+ StringCchCopyW(szFile, _countof(szFile), lpCommand);
+ pchParams = NULL;
+ }
+ else
+ {
+ pchParams = SplitParams(lpCommand, szFile, _countof(szFile));
+ if (SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(NULL, szFile, wszExe, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(NULL, szFile, wszCom, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(pwszStartDir, szFile, NULL, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(pwszStartDir, szFile, wszExe, _countof(szFile2), szFile2, NULL)
||
+ SearchPathW(pwszStartDir, szFile, wszCom, _countof(szFile2), szFile2, NULL))
+ {
+ StringCchCopyW(szFile, _countof(szFile), szFile2);
+ pchParams = NULL;
+ }
+ else if (SearchPathW(NULL, lpCommand, NULL, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(NULL, lpCommand, wszExe, _countof(szFile2), szFile2, NULL)
||
+ SearchPathW(NULL, lpCommand, wszCom, _countof(szFile2), szFile2, NULL)
||
+ SearchPathW(pwszStartDir, lpCommand, NULL, _countof(szFile2), szFile2,
NULL) ||
+ SearchPathW(pwszStartDir, lpCommand, wszExe, _countof(szFile2), szFile2,
NULL) ||
+ SearchPathW(pwszStartDir, lpCommand, wszCom, _countof(szFile2), szFile2,
NULL))
+ {
+ StringCchCopyW(szFile, _countof(szFile), szFile2);
+ pchParams = NULL;
+ }
+
+ if (!(dwSeclFlags & SECL_ALLOW_NONEXE))
+ {
+ if (!GetBinaryTypeW(szFile, &dwType))
+ {
+ SHFree(lpCommand);
+
+ if (!(dwSeclFlags & SECL_NO_UI))
+ {
+ WCHAR szText[128 + MAX_PATH], szFormat[128];
+ LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat,
_countof(szFormat));
+ StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
+ MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
+ }
+ return CO_E_APPNOTFOUND;
+ }
+ }
+ else
+ {
+ if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
+ {
+ SHFree(lpCommand);
+
+ if (!(dwSeclFlags & SECL_NO_UI))
+ {
+ WCHAR szText[128 + MAX_PATH], szFormat[128];
+ LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat,
_countof(szFormat));
+ StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
+ MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
+ }
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ }
+
+ ZeroMemory(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = dwFlags;
+ info.hwnd = hwnd;
+ info.lpVerb = pszVerb;
+ info.lpFile = szFile;
+ info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL;
+ info.lpDirectory = pwszStartDir;
+ info.nShow = nShow;
+ if (ShellExecuteExW(&info))
+ {
+ if (info.lpIDList)
+ CoTaskMemFree(info.lpIDList);
+
+ SHFree(lpCommand);
+
+ return S_OK;
+ }
+
+ dwError = GetLastError();
+
+ SHFree(lpCommand);
+
+ return HRESULT_FROM_WIN32(dwError);
+}
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt
b/modules/rostests/apitests/shell32/CMakeLists.txt
index 545d2cc26e..8201a6f12e 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -18,6 +18,7 @@ list(APPEND SOURCE
PathResolve.cpp
SHCreateFileExtractIconW.cpp
SHParseDisplayName.cpp
+ ShellExecCmdLine.cpp
ShellExecuteEx.cpp
ShellState.cpp
menu.cpp
diff --git a/modules/rostests/apitests/shell32/ShellExecCmdLine.cpp
b/modules/rostests/apitests/shell32/ShellExecCmdLine.cpp
new file mode 100644
index 0000000000..c540321a65
--- /dev/null
+++ b/modules/rostests/apitests/shell32/ShellExecCmdLine.cpp
@@ -0,0 +1,582 @@
+/*
+ * PROJECT: ReactOS API tests
+ * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE: Test for ShellExecCmdLine
+ * PROGRAMMERS: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
+ */
+#include "shelltest.h"
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define NDEBUG
+#include <debug.h>
+#include <stdio.h>
+
+//#define ShellExecCmdLine ShellExecCmdLine
+
+#ifndef SECL_NO_UI
+ #define SECL_NO_UI 0x2
+ #define SECL_LOG_USAGE 0x8
+ #define SECL_USE_IDLIST 0x10
+ #define SECL_ALLOW_NONEXE 0x20
+ #define SECL_RUNAS 0x40
+#endif
+
+#ifdef ShellExecCmdLine
+
+#define shell32_hInstance GetModuleHandle(NULL)
+#define IDS_FILE_NOT_FOUND (-1)
+
+static const WCHAR wszOpen[] = L"open";
+static const WCHAR wszExe[] = L".exe";
+static const WCHAR wszCom[] = L".com";
+
+static __inline void __SHCloneStrW(WCHAR **target, const WCHAR *source)
+{
+ *target = (WCHAR *)SHAlloc((lstrlenW(source) + 1) * sizeof(WCHAR) );
+ lstrcpyW(*target, source);
+}
+
+static LPCWSTR
+SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
+{
+ LPCWSTR pch;
+ size_t ich = 0;
+ if (*psz == L'"')
+ {
+ // 1st argument is quoted. the string in quotes is quoted 1st argument.
+ // [pch] --> [pszArg0+ich]
+ for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch)
+ {
+ if (*pch == L'"' && pch[1] == L'"')
+ {
+ // doubled double quotations found!
+ pszArg0[ich] = L'"';
+ }
+ else if (*pch == L'"')
+ {
+ // single double quotation found!
+ ++pch;
+ break;
+ }
+ else
+ {
+ // otherwise
+ pszArg0[ich] = *pch;
+ }
+ }
+ }
+ else
+ {
+ // 1st argument is unquoted. non-space sequence is 1st argument.
+ // [pch] --> [pszArg0+ich]
+ for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0;
++ich, ++pch)
+ {
+ pszArg0[ich] = *pch;
+ }
+ }
+ pszArg0[ich] = 0;
+
+ // skip space
+ while (iswspace(*pch))
+ ++pch;
+
+ return pch;
+}
+
+HRESULT WINAPI ShellExecCmdLine(
+ HWND hwnd,
+ LPCWSTR pwszCommand,
+ LPCWSTR pwszStartDir,
+ int nShow,
+ LPVOID pUnused,
+ DWORD dwSeclFlags)
+{
+ SHELLEXECUTEINFOW info;
+ DWORD dwSize, dwError, dwType, dwFlags = SEE_MASK_DOENVSUBST | SEE_MASK_NOASYNC;
+ LPCWSTR pszVerb = NULL;
+ WCHAR szFile[MAX_PATH], szFile2[MAX_PATH];
+ HRESULT hr;
+ LPCWSTR pchParams;
+ LPWSTR lpCommand = NULL;
+
+ if (pwszCommand == NULL)
+ RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE,
+ 1, (ULONG_PTR*)pwszCommand);
+
+ __SHCloneStrW(&lpCommand, pwszCommand);
+ StrTrimW(lpCommand, L" \t");
+
+ if (dwSeclFlags & SECL_NO_UI)
+ dwFlags |= SEE_MASK_FLAG_NO_UI;
+ if (dwSeclFlags & SECL_LOG_USAGE)
+ dwFlags |= SEE_MASK_FLAG_LOG_USAGE;
+ if (dwSeclFlags & SECL_USE_IDLIST)
+ dwFlags |= SEE_MASK_INVOKEIDLIST;
+
+ if (dwSeclFlags & SECL_RUNAS)
+ {
+ dwSize = 0;
+ hr = AssocQueryStringW(0, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL,
&dwSize);
+ if (SUCCEEDED(hr) && dwSize != 0)
+ {
+ pszVerb = L"runas";
+ }
+ }
+
+ if (UrlIsFileUrlW(lpCommand))
+ {
+ StringCchCopyW(szFile, _countof(szFile), lpCommand);
+ pchParams = NULL;
+ }
+ else
+ {
+ pchParams = SplitParams(lpCommand, szFile, _countof(szFile));
+ if (SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(NULL, szFile, wszExe, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(NULL, szFile, wszCom, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(pwszStartDir, szFile, NULL, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(pwszStartDir, szFile, wszExe, _countof(szFile2), szFile2, NULL)
||
+ SearchPathW(pwszStartDir, szFile, wszCom, _countof(szFile2), szFile2, NULL))
+ {
+ StringCchCopyW(szFile, _countof(szFile), szFile2);
+ pchParams = NULL;
+ }
+ else if (SearchPathW(NULL, lpCommand, NULL, _countof(szFile2), szFile2, NULL) ||
+ SearchPathW(NULL, lpCommand, wszExe, _countof(szFile2), szFile2, NULL)
||
+ SearchPathW(NULL, lpCommand, wszCom, _countof(szFile2), szFile2, NULL)
||
+ SearchPathW(pwszStartDir, lpCommand, NULL, _countof(szFile2), szFile2,
NULL) ||
+ SearchPathW(pwszStartDir, lpCommand, wszExe, _countof(szFile2), szFile2,
NULL) ||
+ SearchPathW(pwszStartDir, lpCommand, wszCom, _countof(szFile2), szFile2,
NULL))
+ {
+ StringCchCopyW(szFile, _countof(szFile), szFile2);
+ pchParams = NULL;
+ }
+
+ if (!(dwSeclFlags & SECL_ALLOW_NONEXE))
+ {
+ if (!GetBinaryTypeW(szFile, &dwType))
+ {
+ SHFree(lpCommand);
+
+ if (!(dwSeclFlags & SECL_NO_UI))
+ {
+ WCHAR szText[128 + MAX_PATH], szFormat[128];
+ LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat,
_countof(szFormat));
+ StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
+ MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
+ }
+ return CO_E_APPNOTFOUND;
+ }
+ }
+ else
+ {
+ if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
+ {
+ SHFree(lpCommand);
+
+ if (!(dwSeclFlags & SECL_NO_UI))
+ {
+ WCHAR szText[128 + MAX_PATH], szFormat[128];
+ LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat,
_countof(szFormat));
+ StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
+ MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
+ }
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ }
+
+ ZeroMemory(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = dwFlags;
+ info.hwnd = hwnd;
+ info.lpVerb = pszVerb;
+ info.lpFile = szFile;
+ info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL;
+ info.lpDirectory = pwszStartDir;
+ info.nShow = nShow;
+ if (ShellExecuteExW(&info))
+ {
+ if (info.lpIDList)
+ CoTaskMemFree(info.lpIDList);
+
+ SHFree(lpCommand);
+
+ return S_OK;
+ }
+
+ dwError = GetLastError();
+
+ SHFree(lpCommand);
+
+ return HRESULT_FROM_WIN32(dwError);
+}
+#else
+ typedef HRESULT (WINAPI *SHELLEXECCMDLINE)(HWND, LPCWSTR, LPCWSTR, INT, LPVOID,
DWORD);
+ SHELLEXECCMDLINE g_pShellExecCmdLine = NULL;
+#endif
+
+typedef struct TEST_ENTRY
+{
+ INT lineno;
+ HRESULT hr;
+ BOOL bAllowNonExe;
+ LPCWSTR pwszWindowClass;
+ LPCWSTR pwszCommand;
+ LPCWSTR pwszStartDir;
+} TEST_ENTRY;
+
+static const char s_testfile1[] = "Test File.txt";
+static const char s_testfile2[] = "Test File.bat";
+static char s_notepad[] = "notepad.exe";
+
+static const TEST_ENTRY s_entries[] =
+{
+ // NULL
+ { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, NULL },
+ { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, L"." },
+ { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, L"system32" },
+ { __LINE__, (HRESULT)0xDEADFACE, FALSE, NULL, NULL, L"C:\\Program Files"
},
+ { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, NULL },
+ { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, L"." },
+ { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, L"system32" },
+ { __LINE__, (HRESULT)0xDEADFACE, TRUE, NULL, NULL, L"C:\\Program Files" },
+ // notepad
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad", NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad", L"."
},
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad",
L"system32" },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad",
L"C:\\Program Files" },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad \"Test
File.txt\"", NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad \"Test
File.txt\"", L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad", NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad", L"."
},
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad",
L"system32" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad",
L"C:\\Program Files" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad \"Test
File.txt\"", NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad \"Test
File.txt\"", L"." },
+ // notepad.exe
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe", NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe",
L"." },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe",
L"system32" },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe",
L"C:\\Program Files" },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe \"Test
File.txt\"", NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"notepad.exe \"Test
File.txt\"", L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe", NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe",
L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe",
L"system32" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe",
L"C:\\Program Files" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe \"Test
File.txt\"", NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"notepad.exe \"Test
File.txt\"", L"." },
+ // C:\notepad.exe
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad",
L"C:\\notepad.exe", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad",
L"C:\\notepad.exe", L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad",
L"C:\\notepad.exe", L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad",
L"C:\\notepad.exe", L"C:\\Program Files" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe
\"Test File.txt\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"C:\\notepad.exe
\"Test File.txt\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"C:\\notepad.exe", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"C:\\notepad.exe", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"C:\\notepad.exe", L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"C:\\notepad.exe", L"C:\\Program Files" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"C:\\notepad.exe \"Test File.txt\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"C:\\notepad.exe \"Test File.txt\"", L"." },
+ // "notepad"
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"",
NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"",
L"." },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"",
L"system32" },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"",
L"C:\\Program Files" },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"
\"Test File.txt\"", NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad\"
\"Test File.txt\"", L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"",
NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"",
L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"",
L"system32" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"",
L"C:\\Program Files" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"
\"Test File.txt\"", NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad\"
\"Test File.txt\"", L"." },
+ // "notepad.exe"
+ { __LINE__, S_OK, FALSE, L"Notepad",
L"\"notepad.exe\"", NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad",
L"\"notepad.exe\"", L"." },
+ { __LINE__, S_OK, FALSE, L"Notepad",
L"\"notepad.exe\"", L"system32" },
+ { __LINE__, S_OK, FALSE, L"Notepad",
L"\"notepad.exe\"", L"C:\\Program Files" },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\"
\"Test File.txt\"", NULL },
+ { __LINE__, S_OK, FALSE, L"Notepad", L"\"notepad.exe\"
\"Test File.txt\"", L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"",
NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"",
L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"",
L"system32" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"",
L"C:\\Program Files" },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"
\"Test File.txt\"", NULL },
+ { __LINE__, S_OK, TRUE, L"Notepad", L"\"notepad.exe\"
\"Test File.txt\"", L"." },
+ // test program.exe
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test
program.exe", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test
program.exe", L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test
program.exe", L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test
program.exe", L"C:\\Program Files" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe
\"Test File.txt\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"test program.exe
\"Test File.txt\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"test program.exe", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"test program.exe", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"test program.exe", L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"test program.exe", L"C:\\Program Files" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"test program.exe \"Test File.txt\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"test program.exe \"Test File.txt\"", L"." },
+ // "test program"
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program\"", L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program\"", L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program\"", L"C:\\Program Files" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program\" \"Test File.txt\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program\" \"Test File.txt\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program\"", L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program\"", L"C:\\Program Files" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program\" \"Test File.txt\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program\" \"Test File.txt\"", L"." },
+ // "test program.exe"
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program.exe\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program.exe\"", L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program.exe\"", L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program.exe\"", L"C:\\Program Files" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program.exe\" \"Test File.txt\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"test
program.exe\" \"Test File.txt\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program.exe\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program.exe\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program.exe\"", L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program.exe\"", L"C:\\Program Files" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program.exe\" \"Test File.txt\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"test program.exe\" \"Test File.txt\"", L"."
},
+ // invalid program
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid
program", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid
program", L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid
program", L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid
program", L"C:\\Program Files" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program
\"Test File.txt\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"invalid program
\"Test File.txt\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"invalid program", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"invalid program", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"invalid program", L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"invalid program", L"C:\\Program Files" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"invalid program \"Test File.txt\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"invalid program \"Test File.txt\"", L"." },
+ // \"invalid program.exe\"
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid
program.exe\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid
program.exe\"", L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid
program.exe\"", L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid
program.exe\"", L"C:\\Program Files" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid
program.exe\" \"Test File.txt\"", NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", L"\"invalid
program.exe\" \"Test File.txt\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"invalid program.exe\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"invalid program.exe\"", L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"invalid program.exe\"", L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"invalid program.exe\"", L"C:\\Program Files" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"invalid program.exe\" \"Test File.txt\"", NULL },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
L"\"invalid program.exe\" \"Test File.txt\"", L"."
},
+};
+
+static void DoEntry(const TEST_ENTRY *pEntry)
+{
+ HRESULT hr;
+ DWORD dwSeclFlags;
+
+ if (pEntry->bAllowNonExe)
+ dwSeclFlags = SECL_NO_UI | SECL_ALLOW_NONEXE;
+ else
+ dwSeclFlags = SECL_NO_UI;
+
+ _SEH2_TRY
+ {
+#ifdef ShellExecCmdLine
+ hr = ShellExecCmdLine(NULL, pEntry->pwszCommand, pEntry->pwszStartDir,
+ SW_SHOWNORMAL, NULL, dwSeclFlags);
+#else
+ hr = (*g_pShellExecCmdLine)(NULL, pEntry->pwszCommand,
pEntry->pwszStartDir,
+ SW_SHOWNORMAL, NULL, dwSeclFlags);
+#endif
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ hr = 0xDEADFACE;
+ }
+ _SEH2_END;
+
+ ok(hr == pEntry->hr, "Line %d: hr expected 0x%lX, was 0x%lX\n",
pEntry->lineno, pEntry->hr, hr);
+
+#define RETRY_COUNT 5
+#define RETRY_INTERVAL 250
+ if (SUCCEEDED(hr) && pEntry->pwszWindowClass)
+ {
+ BOOL bFound = FALSE;
+ Sleep(RETRY_INTERVAL / 2);
+ for (int i = 0; i < RETRY_COUNT; ++i)
+ {
+ HWND hwnd = FindWindowW(pEntry->pwszWindowClass, NULL);
+ if (hwnd)
+ {
+ bFound = TRUE;
+ SendMessage(hwnd, WM_CLOSE, 0, 0);
+ break;
+ }
+ Sleep(RETRY_INTERVAL);
+ }
+ ok(bFound, "Line %d: The window not found\n", pEntry->lineno);
+ }
+#undef RETRY_COUNT
+#undef RETRY_INTERVAL
+}
+
+START_TEST(ShellExecCmdLine)
+{
+ using namespace std;
+
+#ifndef ShellExecCmdLine
+ HMODULE hShell32 = GetModuleHandleA("shell32");
+ g_pShellExecCmdLine = (SHELLEXECCMDLINE)GetProcAddress(hShell32,
(LPCSTR)(INT_PTR)265);
+ if (!g_pShellExecCmdLine)
+ {
+ skip("ShellExecCmdLine is not found\n");
+ return;
+ }
+#endif
+
+ // s_testfile1
+ FILE *fp = fopen(s_testfile1, "wb");
+ ok(fp != NULL, "failed to create a test file\n");
+ fclose(fp);
+
+ // s_testfile2
+ fp = fopen(s_testfile2, "wb");
+ ok(fp != NULL, "failed to create a test file\n");
+ if (fp)
+ {
+ fprintf(fp, "echo OK\n");
+ }
+ fclose(fp);
+
+ for (size_t i = 0; i < _countof(s_entries); ++i)
+ {
+ DoEntry(&s_entries[i]);
+ }
+
+ WCHAR buf0[MAX_PATH];
+ WCHAR buf1[MAX_PATH];
+ WCHAR buf2[MAX_PATH];
+ TEST_ENTRY additionals[] =
+ {
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf0, NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf0, L"."
},
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf0,
L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf1, NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf1, L"."
},
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf1,
L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf2, NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf2, L"."
},
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, L"Notepad", buf2,
L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
buf0, NULL }, // FIXME
+ { __LINE__, S_OK, TRUE, L"Notepad", buf0, L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
buf0, L"system32" }, // FIXME
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
buf1, NULL }, // FIXME
+ { __LINE__, S_OK, TRUE, L"Notepad", buf1, L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", buf1, L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, L"Notepad",
buf2, NULL }, // FIXME
+ { __LINE__, S_OK, TRUE, L"Notepad", buf2, L"." },
+ { __LINE__, S_OK, TRUE, L"Notepad", buf2, L"system32" },
+ };
+
+ wsprintfW(buf0, L"%hs", s_testfile1);
+ wsprintfW(buf1, L"\"%hs\"", s_testfile1);
+ wsprintfW(buf2, L"\"%hs\" \"Test File.txt\"",
s_testfile1);
+ for (size_t i = 0; i < _countof(additionals); ++i)
+ {
+ DoEntry(&additionals[i]);
+ }
+
+ TEST_ENTRY additionals2[] =
+ {
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf0, NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf0, L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf0, L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf1, NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf1, L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf1, L"system32" },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf2, NULL },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf2, L"." },
+ { __LINE__, CO_E_APPNOTFOUND, FALSE, NULL, buf2, L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf0, NULL },
// FIXME
+ { __LINE__, S_OK, TRUE, NULL, buf0, L"." },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf0,
L"system32" }, // FIXME
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf1, NULL },
// FIXME
+ { __LINE__, S_OK, TRUE, NULL, buf1, L"." },
+ { __LINE__, S_OK, TRUE, NULL, buf1, L"system32" },
+ { __LINE__, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), TRUE, NULL, buf2, NULL },
// FIXME
+ { __LINE__, S_OK, TRUE, NULL, buf2, L"." },
+ { __LINE__, S_OK, TRUE, NULL, buf2, L"system32" },
+ };
+
+ wsprintfW(buf0, L"%hs", s_testfile2);
+ wsprintfW(buf1, L"\"%hs\"", s_testfile2);
+ wsprintfW(buf2, L"\"%hs\" \"Test File.txt\"",
s_testfile2);
+ for (size_t i = 0; i < _countof(additionals2); ++i)
+ {
+ DoEntry(&additionals2[i]);
+ }
+
+ char path[MAX_PATH];
+ ok((INT_PTR)FindExecutableA("notepad.exe", NULL, s_notepad) >= 32,
"FindExecutableA failed\n");
+ ok(GetModuleFileNameA(NULL, path, _countof(path)), "GetModuleFileNameA
failed\n");
+ char *pch = strrchr(path, '\\');
+
+ if (pch == NULL)
+ {
+ skip("pch == NULL\n");
+ }
+ else
+ {
+ // create "My Directory"
+ strcpy(pch, "\\My Directory");
+ if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)
+ ok(CreateDirectoryA(path, NULL), "CreateDirectoryA failed\n");
+
+ // create "My Directory\\Notepad.exe" as clone of Notepad.exe
+ strcpy(pch, "\\My Directory\\Notepad.exe");
+ ok(CopyFileA(s_notepad, path, FALSE), "CopyFileA failed\n");
+
+ wsprintfW(buf0, L"%hs", path);
+ wsprintfW(buf1, L"\"%hs\"", path);
+ wsprintfW(buf2, L"\"%hs\" \"Test File.txt\"",
path);
+ TEST_ENTRY additionals3[] =
+ {
+ { __LINE__, S_OK, FALSE, NULL, buf0, NULL },
+ { __LINE__, S_OK, FALSE, NULL, buf0, L"." },
+ { __LINE__, S_OK, FALSE, NULL, buf0, L"system32" },
+ { __LINE__, S_OK, FALSE, NULL, buf1, NULL },
+ { __LINE__, S_OK, FALSE, NULL, buf1, L"." },
+ { __LINE__, S_OK, FALSE, NULL, buf1, L"system32" },
+ { __LINE__, S_OK, FALSE, NULL, buf2, NULL },
+ { __LINE__, S_OK, FALSE, NULL, buf2, L"." },
+ { __LINE__, S_OK, FALSE, NULL, buf2, L"system32" },
+ { __LINE__, S_OK, TRUE, NULL, buf0, NULL },
+ { __LINE__, S_OK, TRUE, NULL, buf0, L"." },
+ { __LINE__, S_OK, TRUE, NULL, buf0, L"system32" },
+ { __LINE__, S_OK, TRUE, NULL, buf1, NULL },
+ { __LINE__, S_OK, TRUE, NULL, buf1, L"." },
+ { __LINE__, S_OK, TRUE, NULL, buf1, L"system32" },
+ { __LINE__, S_OK, TRUE, NULL, buf2, NULL },
+ { __LINE__, S_OK, TRUE, NULL, buf2, L"." },
+ { __LINE__, S_OK, TRUE, NULL, buf2, L"system32" },
+ };
+ for (size_t i = 0; i < _countof(additionals3); ++i)
+ {
+ DoEntry(&additionals3[i]);
+ }
+
+ DeleteFileA(path);
+
+ strcpy(pch, "\\My Directory");
+ RemoveDirectory(path);
+ }
+
+ // clean up
+ ok(DeleteFileA(s_testfile1), "failed to delete the test file\n");
+ ok(DeleteFileA(s_testfile2), "failed to delete the test file\n");
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c
b/modules/rostests/apitests/shell32/testlist.c
index b2e1b78876..1b5339ea5e 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -15,6 +15,7 @@ extern void func_menu(void);
extern void func_OpenAs_RunDLL(void);
extern void func_PathResolve(void);
extern void func_SHCreateFileExtractIconW(void);
+extern void func_ShellExecCmdLine(void);
extern void func_ShellExecuteEx(void);
extern void func_ShellState(void);
extern void func_SHParseDisplayName(void);
@@ -33,6 +34,7 @@ const struct test winetest_testlist[] =
{ "OpenAs_RunDLL", func_OpenAs_RunDLL },
{ "PathResolve", func_PathResolve },
{ "SHCreateFileExtractIconW", func_SHCreateFileExtractIconW },
+ { "ShellExecCmdLine", func_ShellExecCmdLine },
{ "ShellExecuteEx", func_ShellExecuteEx },
{ "ShellState", func_ShellState },
{ "SHParseDisplayName", func_SHParseDisplayName },
diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h
index 24d6e82f55..c2a0b37c6b 100644
--- a/sdk/include/reactos/undocshell.h
+++ b/sdk/include/reactos/undocshell.h
@@ -546,6 +546,21 @@ WORD WINAPI ArrangeWindows(
WORD cKids,
CONST HWND * lpKids);
+/* Flags for ShellExecCmdLine */
+#define SECL_NO_UI 0x2
+#define SECL_LOG_USAGE 0x8
+#define SECL_USE_IDLIST 0x10
+#define SECL_ALLOW_NONEXE 0x20
+#define SECL_RUNAS 0x40
+
+HRESULT WINAPI ShellExecCmdLine(
+ HWND hwnd,
+ LPCWSTR pwszCommand,
+ LPCWSTR pwszStartDir,
+ int nShow,
+ LPVOID pUnused,
+ DWORD dwSeclFlags);
+
/* RegisterShellHook types */
#define RSH_DEREGISTER 0
#define RSH_REGISTER 1