diff --git a/dlls/shell32/shell.c b/dlls/shell32/shell.c index 4b755f6f582..419e2fd0ab2 100644 --- a/dlls/shell32/shell.c +++ b/dlls/shell32/shell.c @@ -611,13 +611,14 @@ DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len ) /************************************************************************* * SHELL_Execute16 [Internal] */ -static UINT SHELL_Execute16(WCHAR *lpCmd, void* env, LPSHELLEXECUTEINFOW seiW, BOOL shWait) +static UINT SHELL_Execute16(const WCHAR *lpCmd, void *env, BOOL shWait, + LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out) { UINT ret; char sCmd[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, lpCmd, -1, sCmd, MAX_PATH, NULL, NULL); - ret = WinExec16(sCmd, seiW->nShow); - seiW->hInstApp = HINSTANCE_32(ret); + ret = WinExec16(sCmd, (UINT16)psei->nShow); + psei_out->hInstApp = HINSTANCE_32(ret); return ret; } diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 49390ac3758..050d2c3e7f7 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -228,8 +228,10 @@ inline static WCHAR * __SHCloneStrAtoW(WCHAR ** target, const char * source) #define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) #define HINSTANCE_16(h32) (LOWORD(h32)) -typedef UINT (*SHELL_ExecuteW32)(WCHAR *lpCmd, void *env, LPSHELLEXECUTEINFOW sei, BOOL shWait); -BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc); +typedef UINT (*SHELL_ExecuteW32)(const WCHAR *lpCmd, void *env, BOOL shWait, + LPSHELLEXECUTEINFOW sei, LPSHELLEXECUTEINFOW sei_out); + +BOOL WINAPI ShellExecuteExW32(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc); extern WCHAR swShell32Name[MAX_PATH]; extern char sShell32Name[MAX_PATH]; diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index e4779158eff..028caee922d 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -129,19 +129,20 @@ static BOOL SHELL_ArgifyW(WCHAR* res, int len, const WCHAR* fmt, const WCHAR* lp * SHELL_ExecuteW [Internal] * */ -static UINT SHELL_ExecuteW(WCHAR *lpCmd, void *env, LPSHELLEXECUTEINFOW sei, BOOL shWait) +static UINT SHELL_ExecuteW(const WCHAR *lpCmd, void *env, BOOL shWait, + LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out) { STARTUPINFOW startup; PROCESS_INFORMATION info; UINT retval = 31; - TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(sei->lpDirectory)); + TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory)); ZeroMemory(&startup,sizeof(STARTUPINFOW)); startup.cb = sizeof(STARTUPINFOW); startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = sei->nShow; - if (CreateProcessW(NULL, lpCmd, NULL, NULL, FALSE, 0, - env, sei->lpDirectory, &startup, &info)) + startup.wShowWindow = psei->nShow; + if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, 0, + env, *psei->lpDirectory? psei->lpDirectory: NULL, &startup, &info)) { /* Give 30 seconds to the app to come up, if desired. Probably only needed when starting app immediately before making a DDE connection. */ @@ -149,8 +150,8 @@ static UINT SHELL_ExecuteW(WCHAR *lpCmd, void *env, LPSHELLEXECUTEINFOW sei, BOO if (WaitForInputIdle( info.hProcess, 30000 ) == -1) WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() ); retval = 33; - if(sei->fMask & SEE_MASK_NOCLOSEPROCESS) - sei->hProcess = info.hProcess; + if (psei->fMask & SEE_MASK_NOCLOSEPROCESS) + psei_out->hProcess = info.hProcess; else CloseHandle( info.hProcess ); CloseHandle( info.hThread ); @@ -163,7 +164,7 @@ static UINT SHELL_ExecuteW(WCHAR *lpCmd, void *env, LPSHELLEXECUTEINFOW sei, BOO TRACE("returning %u\n", retval); - sei->hInstApp = (HINSTANCE)retval; + psei_out->hInstApp = (HINSTANCE)retval; return retval; } @@ -535,7 +536,8 @@ static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv, */ static unsigned dde_connect(WCHAR* key, WCHAR* start, WCHAR* ddeexec, const WCHAR* lpFile, void *env, - LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) + SHELL_ExecuteW32 execfunc, + LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out) { static const WCHAR wApplication[] = {'\\','a','p','p','l','i','c','a','t','i','o','n',0}; static const WCHAR wTopic[] = {'\\','t','o','p','i','c',0}; @@ -579,7 +581,7 @@ static unsigned dde_connect(WCHAR* key, WCHAR* start, WCHAR* ddeexec, { static const WCHAR wIfexec[] = {'\\','i','f','e','x','e','c',0}; TRACE("Launching '%s'\n", debugstr_w(start)); - ret = execfunc(start, env, sei, TRUE); + ret = execfunc(start, env, TRUE, psei, psei_out); if (ret < 32) { TRACE("Couldn't launch\n"); @@ -616,7 +618,8 @@ static unsigned dde_connect(WCHAR* key, WCHAR* start, WCHAR* ddeexec, * execute_from_key [Internal] */ static UINT execute_from_key(LPWSTR key, LPCWSTR lpFile, void *env, - LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) + SHELL_ExecuteW32 execfunc, + LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out) { WCHAR cmd[1024] = {0}; LONG cmdlen = sizeof(cmd); @@ -640,7 +643,7 @@ static UINT execute_from_key(LPWSTR key, LPCWSTR lpFile, void *env, if (RegQueryValueW(HKEY_CLASSES_ROOT, key, param, ¶mlen) == ERROR_SUCCESS) { TRACE("Got ddeexec %s => %s\n", debugstr_w(key), debugstr_w(param)); - retval = dde_connect(key, cmd, param, lpFile, env, sei, execfunc); + retval = dde_connect(key, cmd, param, lpFile, env, execfunc, psei, psei_out); } else { @@ -648,7 +651,7 @@ static UINT execute_from_key(LPWSTR key, LPCWSTR lpFile, void *env, cmdlen /= sizeof(WCHAR); cmd[cmdlen] = '\0'; SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile); - retval = execfunc(param, env, sei, FALSE); + retval = execfunc(param, env, FALSE, psei, psei_out); } } else TRACE("ooch\n"); @@ -721,7 +724,10 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun static const WCHAR wWww[] = {'w','w','w',0}; static const WCHAR wFile[] = {'f','i','l','e',0}; static const WCHAR wHttp[] = {'h','t','t','p',':','/','/',0}; - WCHAR wszApplicationName[MAX_PATH+2],wszCommandline[1024],wszPidl[20],wfileName[MAX_PATH]; + + WCHAR wszApplicationName[MAX_PATH+2], wszCommandline[1024], wszDir[MAX_PATH]; + SHELLEXECUTEINFOW sei_tmp; /* modifyable copy of SHELLEXECUTEINFO struct */ + WCHAR wszPidl[20], wfileName[MAX_PATH]; LPWSTR pos; void *env; int gap, len; @@ -729,49 +735,67 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun LPCWSTR lpFile; UINT retval = 31; WCHAR wcmd[1024]; + WCHAR buffer[MAX_PATH]; BOOL done; + /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */ + memcpy(&sei_tmp, sei, sizeof(sei_tmp)); + TRACE("mask=0x%08lx hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n", - sei->fMask, sei->hwnd, debugstr_w(sei->lpVerb), - debugstr_w(sei->lpFile), debugstr_w(sei->lpParameters), - debugstr_w(sei->lpDirectory), sei->nShow, - (sei->fMask & SEE_MASK_CLASSNAME) ? debugstr_w(sei->lpClass) : "not used"); + sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb), + debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters), + debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow, + (sei_tmp.fMask & SEE_MASK_CLASSNAME) ? debugstr_w(sei_tmp.lpClass) : "not used"); sei->hProcess = NULL; - ZeroMemory(wszApplicationName,MAX_PATH); - if (sei->lpFile) - strcpyW(wszApplicationName, sei->lpFile); - ZeroMemory(wszCommandline,1024); - if (sei->lpParameters) - strcpyW(wszCommandline, sei->lpParameters); + /* make copies of all path/command strings */ + if (sei_tmp.lpFile) + strcpyW(wszApplicationName, sei_tmp.lpFile); + else + *wszApplicationName = '\0'; - if (sei->fMask & (SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY | + if (sei_tmp.lpParameters) + strcpyW(wszCommandline, sei_tmp.lpParameters); + else + *wszCommandline = '\0'; + + if (sei_tmp.lpDirectory) + strcpyW(wszDir, sei_tmp.lpDirectory); + else + *wszDir = '\0'; + + /* adjust string pointers to point to the new buffers */ + sei_tmp.lpFile = wszApplicationName; + sei_tmp.lpParameters = wszCommandline; + sei_tmp.lpDirectory = wszDir; + + if (sei_tmp.fMask & (SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY | SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI | SEE_MASK_UNICODE | SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_HMONITOR )) { - FIXME("flags ignored: 0x%08lx\n", sei->fMask); + FIXME("flags ignored: 0x%08lx\n", sei_tmp.fMask); } /* process the IDList */ - if ( (sei->fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST) /*0x0c*/ + if ((sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST) /*0x0c*/ { wszApplicationName[0] = '"'; - SHGetPathFromIDListW(sei->lpIDList,wszApplicationName + 1); + SHGetPathFromIDListW(sei_tmp.lpIDList, wszApplicationName+1); strcatW(wszApplicationName, wQuote); - TRACE("-- idlist=%p (%s)\n", sei->lpIDList, debugstr_w(wszApplicationName)); + TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName)); } else { - if (sei->fMask & SEE_MASK_IDLIST ) + if (sei_tmp.fMask & SEE_MASK_IDLIST) { static const WCHAR wI[] = {'%','I',0}, wP[] = {':','%','p',0}; pos = strstrW(wszCommandline, wI); if (pos) { LPVOID pv; - HGLOBAL hmem = SHAllocShared ( sei->lpIDList, ILGetSize(sei->lpIDList), 0); + HGLOBAL hmem = SHAllocShared(sei_tmp.lpIDList, ILGetSize(sei_tmp.lpIDList), 0); pv = SHLockShared(hmem,0); sprintfW(wszPidl,wP,pv ); SHUnlockShared(pv); @@ -784,14 +808,14 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun } } - if (sei->fMask & (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)) + if (sei_tmp.fMask & (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)) { /* launch a document by fileclass like 'WordPad.Document.1' */ /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */ /* FIXME: szCommandline should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */ - HCR_GetExecuteCommandW((sei->fMask & SEE_MASK_CLASSKEY) ? sei->hkeyClass : NULL, - (sei->fMask & SEE_MASK_CLASSNAME) ? sei->lpClass: NULL, - (sei->lpVerb) ? sei->lpVerb : wszOpen, + HCR_GetExecuteCommandW((sei_tmp.fMask & SEE_MASK_CLASSKEY) ? sei_tmp.hkeyClass : NULL, + (sei_tmp.fMask & SEE_MASK_CLASSNAME) ? sei_tmp.lpClass: NULL, + (sei_tmp.lpVerb) ? sei_tmp.lpVerb : wszOpen, wszCommandline, sizeof(wszCommandline)/sizeof(WCHAR)); /* FIXME: get the extension of lpFile, check if it fits to the lpClass */ @@ -804,15 +828,27 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun strcatW(wcmd, wSpace); strcatW(wcmd, wszApplicationName); } - retval = execfunc(wcmd, NULL, sei, FALSE); + retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei); if (retval > 32) return TRUE; else return FALSE; } + /* expand environment strings */ + if (ExpandEnvironmentStringsW(sei_tmp.lpFile, buffer, MAX_PATH)) + lstrcpyW(wszApplicationName, buffer); + + if (*sei_tmp.lpParameters) + if (ExpandEnvironmentStringsW(sei_tmp.lpParameters, buffer, MAX_PATH)) + lstrcpyW(wszCommandline, buffer); + + if (*sei_tmp.lpDirectory) + if (ExpandEnvironmentStringsW(sei_tmp.lpDirectory, buffer, MAX_PATH)) + lstrcpyW(wszDir, buffer); + /* Else, try to execute the filename */ - TRACE("execute:'%s','%s'\n", debugstr_w(wszApplicationName), debugstr_w(wszCommandline)); + TRACE("execute:'%s','%s','%s'\n", debugstr_w(wszApplicationName), debugstr_w(wszCommandline), debugstr_w(wszDir)); strcpyW(wfileName, wszApplicationName); lpFile = wfileName; @@ -821,13 +857,13 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun strcatW(wszApplicationName, wszCommandline); } - retval = execfunc(wszApplicationName, NULL, sei, FALSE); + retval = execfunc(wszApplicationName, NULL, FALSE, &sei_tmp, sei); if (retval > 32) return TRUE; /* Else, try to find the executable */ wcmd[0] = '\0'; - retval = SHELL_FindExecutable(sei->lpDirectory, lpFile, sei->lpVerb, wcmd, lpstrProtocol, &env); + retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, lpstrProtocol, &env); if (retval > 32) /* Found */ { WCHAR wszQuotedCmd[MAX_PATH+2]; @@ -841,11 +877,11 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun strcatW(wszQuotedCmd, wSpace); strcatW(wszQuotedCmd, wszCommandline); } - TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(sei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol)); + TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(sei_tmp.lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol)); if (*lpstrProtocol) - retval = execute_from_key(lpstrProtocol, wszApplicationName, env, sei, execfunc); + retval = execute_from_key(lpstrProtocol, wszApplicationName, env, execfunc, &sei_tmp, sei); else - retval = execfunc(wszQuotedCmd, env, sei, FALSE); + retval = execfunc(wszQuotedCmd, env, FALSE, &sei_tmp, sei); if (env) HeapFree( GetProcessHeap(), 0, env ); } else if (PathIsURLW((LPWSTR)lpFile)) /* File not found, check for URL */ @@ -866,7 +902,7 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun strncpyW(lpstrProtocol, lpFile, iSize); lpstrProtocol[iSize] = '\0'; strcatW(lpstrProtocol, wShell); - strcatW(lpstrProtocol, sei->lpVerb? sei->lpVerb: wszOpen); + strcatW(lpstrProtocol, sei_tmp.lpVerb? sei_tmp.lpVerb: wszOpen); strcatW(lpstrProtocol, wCommand); /* Remove File Protocol from lpFile */ @@ -876,7 +912,7 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun lpFile += iSize; while (*lpFile == ':') lpFile++; } - retval = execute_from_key(lpstrProtocol, lpFile, NULL, sei, execfunc); + retval = execute_from_key(lpstrProtocol, lpFile, NULL, execfunc, &sei_tmp, sei); } /* Check if file specified is in the form www.??????.*** */ else if (!strncmpiW(lpFile, wWww, 3)) @@ -885,7 +921,7 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun WCHAR lpstrTmpFile[256]; strcpyW(lpstrTmpFile, wHttp); strcatW(lpstrTmpFile, lpFile); - retval = (UINT)ShellExecuteW(sei->hwnd, sei->lpVerb, lpstrTmpFile, NULL, NULL, 0); + retval = (UINT)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0); } TRACE("retval %u\n", retval);