Index: dll/win32/shell32/classes.cpp =================================================================== --- dll/win32/shell32/classes.cpp (revision 63402) +++ dll/win32/shell32/classes.cpp (working copy) @@ -34,7 +34,7 @@ /* added because we do not want to have double dots */ if (szExtension[0] == '.') - bPrependDot = 0; + bPrependDot = FALSE; if (bPrependDot) szTemp[0] = '.'; @@ -66,7 +66,7 @@ /* added because we do not want to have double dots */ if (szExtension[0] == '.') - bPrependDot = 0; + bPrependDot = FALSE; if (bPrependDot) szTemp[0] = '.'; @@ -109,7 +109,7 @@ TRACE("%p %s %p\n", hkeyClass, debugstr_w(szVerb), szDest); - if (szVerb) + if (szVerb && *szVerb) { lstrcpynW(szDest, szVerb, len); return TRUE; @@ -173,7 +173,7 @@ return FALSE; ret = FALSE; - if (HCR_GetDefaultVerbW(hkeyClass, szVerb, sTempVerb, sizeof(sTempVerb))) + if (HCR_GetDefaultVerbW(hkeyClass, szVerb, sTempVerb, sizeof(sTempVerb)/sizeof(sTempVerb[0]))) { WCHAR sTemp[MAX_PATH]; wcscpy(sTemp, swShell); @@ -420,7 +420,7 @@ } } - TRACE("-- %s\n", szDest); + TRACE("-- (%s)\n", szDest); return ret; } @@ -489,7 +489,11 @@ { hr = psfDesktop->BindToObject(pidlFolder, NULL, IID_PPV_ARG(IShellFolder,&psfFolder)); if (SUCCEEDED(hr)) + { hr = psfFolder->GetAttributesOf(0, NULL, pdwAttributes); + psfFolder->Release(); + } + psfDesktop->Release(); } if (FAILED(hr)) return FALSE; Index: dll/win32/shell32/shell32_main.cpp =================================================================== --- dll/win32/shell32/shell32_main.cpp (revision 63402) +++ dll/win32/shell32/shell32_main.cpp (working copy) @@ -1075,7 +1075,7 @@ /************************************************************************* * AboutDlgProc (internal) */ -INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +static INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { static DWORD cxLogoBmp; static DWORD cyLogoBmp; Index: dll/win32/shell32/shell32_main.h =================================================================== --- dll/win32/shell32/shell32_main.h (revision 63402) +++ dll/win32/shell32/shell32_main.h (working copy) @@ -53,7 +53,6 @@ BOOL HCR_GetClassNameA(REFIID riid, LPSTR szDest, DWORD len); BOOL HCR_GetFolderAttributes(LPCITEMIDLIST pidlFolder, LPDWORD dwAttributes); -INT_PTR CALLBACK AboutDlgProc(HWND,UINT,WPARAM,LPARAM); DWORD WINAPI ParseFieldA(LPCSTR src, DWORD nField, LPSTR dst, DWORD len); DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len); @@ -173,11 +172,6 @@ #define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) #define HINSTANCE_16(h32) (LOWORD(h32)) -typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, - const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out); - -BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc); - extern WCHAR swShell32Name[MAX_PATH]; BOOL UNIXFS_is_rooted_at_desktop(void); Index: dll/win32/shell32/shlexec.cpp =================================================================== --- dll/win32/shell32/shlexec.cpp (revision 63402) +++ dll/win32/shell32/shlexec.cpp (working copy) @@ -28,6 +28,9 @@ #define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY) +typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, + const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out); + static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum) { bool firstCharQuote = false; @@ -382,7 +385,12 @@ } } - *res = '\0'; + used++; + if (res - out < static_cast(len)) + *res = '\0'; + else + out[len-1] = '\0'; + TRACE("used %i of %i space\n", used, len); if (out_len) *out_len = used; @@ -451,7 +459,7 @@ startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = psei->nShow; dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; - if (psei->fMask & SEE_MASK_NO_CONSOLE) + if (!(psei->fMask & SEE_MASK_NO_CONSOLE)) dwCreationFlags |= CREATE_NEW_CONSOLE; startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL); @@ -589,28 +597,46 @@ return found; } -static UINT SHELL_FindExecutableByOperation(LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen) +/************************************************************************* + * SHELL_FindExecutableByVerb [Internal] + * + * called from SHELL_FindExecutable or SHELL_execute_class + * in/out: + * classname a buffer, big enough, to get the key name to do actually the + * command "WordPad.Document.1\\shell\\open\\command" + * passed as "WordPad.Document.1" + * in: + * lpVerb the operation on it (open) + * commandlen the size of command buffer (in bytes) + * out: + * command a buffer, to store the command to do the + * operation on the file + * key a buffer, big enough, to get the key name to do actually the + * command "WordPad.Document.1\\shell\\open\\command" + * Can be NULL + */ +static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen) { static const WCHAR wCommand[] = L"\\command"; HKEY hkeyClass; WCHAR verb[MAX_PATH]; - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass)) + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, classname, 0, 0x02000000, &hkeyClass)) return SE_ERR_NOASSOC; - if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb) / sizeof(verb[0]))) + if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, sizeof(verb) / sizeof(verb[0]))) return SE_ERR_NOASSOC; RegCloseKey(hkeyClass); /* Looking for ...buffer\shell\\command */ - wcscat(filetype, L"\\shell\\"); - wcscat(filetype, verb); - wcscat(filetype, wCommand); + wcscat(classname, L"\\shell\\"); + wcscat(classname, verb); + wcscat(classname, wCommand); - if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command, + if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, command, &commandlen) == ERROR_SUCCESS) { commandlen /= sizeof(WCHAR); - if (key) wcscpy(key, filetype); + if (key) wcscpy(key, classname); #if 0 LPWSTR tmp; WCHAR param[256]; @@ -624,10 +650,10 @@ */ /* Get the parameters needed by the application from the associated ddeexec key */ - tmp = strstrW(filetype, wCommand); + tmp = strstrW(classname, wCommand); tmp[0] = '\0'; - wcscat(filetype, wDdeexec); - if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, param, + wcscat(classname, wDdeexec); + if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, param, ¶mlen) == ERROR_SUCCESS) { paramlen /= sizeof(WCHAR); @@ -651,7 +677,7 @@ * Utility for code sharing between FindExecutable and ShellExecute * in: * lpFile the name of a file - * lpOperation the operation on it (open) + * lpVerb the operation on it (open) * out: * lpResult a buffer, big enough :-(, to store the command to do the * operation on the file @@ -659,12 +685,12 @@ * command (it'll be used afterwards for more information * on the operation) */ -static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, +static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args) { WCHAR *extension = NULL; /* pointer to file extension */ - WCHAR filetype[256]; /* registry name for this filetype */ - LONG filetypelen = sizeof(filetype); /* length of above */ + WCHAR classname[256]; /* registry name for this file type */ + LONG classnamelen = sizeof(classname); /* length of above */ WCHAR command[1024]; /* command from registry */ WCHAR wBuffer[256]; /* Used to GetProfileString */ UINT retval = SE_ERR_NOASSOC; @@ -699,7 +725,7 @@ { TRACE("SearchPathW returned non-zero\n"); lpFile = xlpFile; - /* Hey, isn't this value ignored? Why make this call? Shouldn't we return here? --dank*/ + /* The file was found in the application-supplied default directory (or the system search path) */ } else if (lpPath && SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile)/sizeof(WCHAR), xlpFile, NULL)) { @@ -711,8 +737,7 @@ attribs = GetFileAttributesW(lpFile); if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY)) { - wcscpy(filetype, L"Folder"); - filetypelen = 6; /* strlen("Folder") */ + wcscpy(classname, L"Folder"); } else { @@ -736,7 +761,7 @@ /* Three places to check: */ /* 1. win.ini, [windows], programs (NB no leading '.') */ - /* 2. Registry, HKEY_CLASS_ROOT\\shell\open\command */ + /* 2. Registry, HKEY_CLASS_ROOT\\shell\open\command */ /* 3. win.ini, [extensions], extension (NB no leading '.' */ /* All I know of the order is that registry is checked before */ /* extensions; however, it'd make sense to check the programs */ @@ -773,28 +798,26 @@ } /* Check registry */ - if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, filetype, - &filetypelen) == ERROR_SUCCESS) + if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, classname, + &classnamelen) == ERROR_SUCCESS) { - filetypelen /= sizeof(WCHAR); - if (filetypelen == sizeof(filetype) / sizeof(WCHAR)) - filetypelen--; + classnamelen /= sizeof(WCHAR); + if (classnamelen == sizeof(classname) / sizeof(WCHAR)) + classnamelen--; - filetype[filetypelen] = '\0'; - TRACE("File type: %s\n", debugstr_w(filetype)); + classname[classnamelen] = '\0'; + TRACE("File type: %s\n", debugstr_w(classname)); } else { - *filetype = '\0'; - filetypelen = 0; + *classname = '\0'; } } - if (*filetype) + if (*classname) { - /* pass the operation string to SHELL_FindExecutableByOperation() */ - filetype[filetypelen] = '\0'; - retval = SHELL_FindExecutableByOperation(lpOperation, key, filetype, command, sizeof(command)); + /* pass the verb string to SHELL_FindExecutableByVerb() */ + retval = SHELL_FindExecutableByVerb(lpVerb, key, classname, command, sizeof(command)); if (retval > 32) { @@ -882,12 +905,14 @@ { WCHAR regkey[256]; WCHAR * endkey = regkey + wcslen(key); - WCHAR app[256], topic[256], ifexec[256], res[256]; + WCHAR app[256], topic[256], ifexec[256], static_res[256]; + WCHAR * dynamic_res=NULL; + WCHAR * res; LONG applen, topiclen, ifexeclen; WCHAR * exec; DWORD ddeInst = 0; DWORD tid; - DWORD resultLen; + DWORD resultLen, endkeyLen; HSZ hszApp, hszTopic; HCONV hConv; HDDEDATA hDdeData; @@ -894,8 +919,20 @@ unsigned ret = SE_ERR_NOASSOC; BOOL unicode = !(GetVersion() & 0x80000000); + if (strlenW(key) + 1 > sizeof(regkey) / sizeof(regkey[0])) + { + FIXME("input parameter %s larger than buffer\n", debugstr_w(key)); + return 2; + } wcscpy(regkey, key); - wcscpy(endkey, L"\\application"); + static const WCHAR wApplication[] = L"\\application"; + endkeyLen = sizeof(regkey) / sizeof(regkey[0]) - (endkey - regkey); + if (strlenW(wApplication) + 1 > endkeyLen) + { + FIXME("endkey %s overruns buffer\n", debugstr_w(wApplication)); + return 2; + } + wcscpy(endkey, wApplication); applen = sizeof(app); if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS) { @@ -908,6 +945,12 @@ /* Get application command from start string and find filename of application */ if (*start == '"') { + if (strlenW(start + 1) + 1 > sizeof(command) / sizeof(command[0])) + { + FIXME("size of input parameter %s larger than buffer\n", + debugstr_w(start + 1)); + return 2; + } wcscpy(command, start + 1); if ((ptr = wcschr(command, '"'))) * ptr = 0; @@ -915,8 +958,9 @@ } else { - LPWSTR p, space; - for (p = (LPWSTR)start; (space = const_cast(strchrW(p, ' '))); p = space + 1) + LPCWSTR p; + LPWSTR space; + for (p = start; (space = const_cast(strchrW(p, ' '))); p = space + 1) { int idx = space - start; memcpy(command, start, idx * sizeof(WCHAR)); @@ -933,6 +977,11 @@ ERR("Unable to find application path for command %s\n", debugstr_w(start)); return ERROR_ACCESS_DENIED; } + if (strlenW(ptr) + 1 > sizeof(app) / sizeof(app[0])) + { + FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr)); + return 2; + } wcscpy(app, ptr); /* Remove extensions (including .so) */ @@ -945,8 +994,14 @@ assert(ptr); *ptr = 0; } - - wcscpy(endkey, L"\\topic"); + + static const WCHAR wTopic[] = L"\\topic"; + if (strlenW(wTopic) + 1 > endkeyLen) + { + FIXME("endkey %s overruns buffer\n", debugstr_w(wTopic)); + return 2; + } + wcscpy(endkey, wTopic); topiclen = sizeof(topic); if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS) { @@ -986,7 +1041,13 @@ SetLastError(ERROR_DDE_FAIL); return 30; /* whatever */ } - strcpyW(endkey, L"\\ifexec"); + static const WCHAR wIfexec[] = L"\\ifexec"; + if (strlenW(wIfexec) + 1 > endkeyLen) + { + FIXME("endkey %s overruns buffer\n", debugstr_w(wIfexec)); + return 2; + } + strcpyW(endkey, wIfexec); ifexeclen = sizeof(ifexec); if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS) { @@ -994,9 +1055,14 @@ } } - SHELL_ArgifyW(res, sizeof(res) / sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen); - if (resultLen > sizeof(res) / sizeof(WCHAR)) - ERR("Argify buffer not large enough, truncated\n"); + SHELL_ArgifyW(static_res, sizeof(static_res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen); + if (resultLen > sizeof(static_res)/sizeof(WCHAR)) + { + res = dynamic_res = static_cast(HeapAlloc(GetProcessHeap(), 0, resultLen * sizeof(WCHAR))); + SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL); + } + else + res = static_res; TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res)); /* It's documented in the KB 330337 that IE has a bug and returns @@ -1019,6 +1085,8 @@ WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst)); ret = 33; + HeapFree(GetProcessHeap(), 0, dynamic_res); + DdeDisconnect(hConv); error: @@ -1296,7 +1364,7 @@ memset(&ici, 0, sizeof ici); ici.cbSize = sizeof ici; - ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI)); + ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI)); ici.nShow = sei->nShow; ici.lpVerb = MAKEINTRESOURCEA(def); ici.hwnd = sei->hwnd; @@ -1411,9 +1479,11 @@ return r; } +static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc); + static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) { - WCHAR execCmd[1024], wcmd[1024]; + WCHAR execCmd[1024], classname[1024]; /* launch a document by fileclass like 'WordPad.Document.1' */ /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */ /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */ @@ -1420,25 +1490,50 @@ ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL); DWORD resultLen; BOOL done; + UINT_PTR rslt; + + /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */ + if (cmask != SEE_MASK_CLASSNAME) + { + WCHAR wcmd[1024]; + HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL, + (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL, + psei->lpVerb, + execCmd, sizeof(execCmd)); - HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL, - (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL, - psei->lpVerb, - execCmd, sizeof(execCmd)); + /* FIXME: get the extension of lpFile, check if it fits to the lpClass */ + TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName)); - /* FIXME: get the extension of lpFile, check if it fits to the lpClass */ - TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName)); + wcmd[0] = '\0'; + done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen); + if (!done && wszApplicationName[0]) + { + strcatW(wcmd, L" "); + if (*wszApplicationName != '"') + { + strcatW(wcmd, L"\""); + strcatW(wcmd, wszApplicationName); + strcatW(wcmd, L"\""); + } + else + strcatW(wcmd, wszApplicationName); + } + if (resultLen > sizeof(wcmd) / sizeof(WCHAR)) + ERR("Argify buffer not large enough... truncating\n"); + return execfunc(wcmd, NULL, FALSE, psei, psei_out); + } + + strcpyW(classname, psei->lpClass); + rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd)); - wcmd[0] = '\0'; - done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen); - if (!done && wszApplicationName[0]) - { - strcatW(wcmd, L" "); - strcatW(wcmd, wszApplicationName); - } - if (resultLen > sizeof(wcmd) / sizeof(WCHAR)) - ERR("Argify buffer not large enough... truncating\n"); - return execfunc(wcmd, NULL, FALSE, psei, psei_out); + TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd)); + if (33 > rslt) + return rslt; + rslt = SHELL_quote_and_execute( execCmd, L"", classname, + wszApplicationName, NULL, psei, + psei_out, execfunc ); + return rslt; + } static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen) @@ -1448,7 +1543,7 @@ BOOL appKnownSingular = FALSE; /* last chance to translate IDList: now also allow CLSID paths */ - if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)))) { + if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)/sizeof(WCHAR)))) { if (buffer[0] == ':' && buffer[1] == ':') { /* open shell folder for the specified class GUID */ if (strlenW(buffer) + 1 > parametersLen) @@ -1487,7 +1582,7 @@ return appKnownSingular; } -static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) +static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) { UINT_PTR retval; DWORD len; @@ -1513,10 +1608,10 @@ strcatW(wszQuotedCmd, wszParameters); } - TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol)); + TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname)); - if (*lpstrProtocol) - retval = execute_from_key(lpstrProtocol, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out); + if (*wszKeyname) + retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out); else retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out); HeapFree(GetProcessHeap(), 0, wszQuotedCmd); @@ -1523,7 +1618,7 @@ return retval; } -static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) +static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) { static const WCHAR wShell[] = L"\\shell\\"; static const WCHAR wCommand[] = L"\\command"; @@ -1540,9 +1635,9 @@ iSize = strlenW(lpFile); TRACE("Got URL: %s\n", debugstr_w(lpFile)); - /* Looking for ...protocol\shell\lpOperation\command */ + /* Looking for ...\shell\\command */ len = iSize + lstrlenW(wShell) + lstrlenW(wCommand) + 1; - if (psei->lpVerb) + if (psei->lpVerb && *psei->lpVerb) len += lstrlenW(psei->lpVerb); else len += lstrlenW(wszOpen); @@ -1550,16 +1645,9 @@ memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR)); lpstrProtocol[iSize] = '\0'; strcatW(lpstrProtocol, wShell); - strcatW(lpstrProtocol, psei->lpVerb ? psei->lpVerb : wszOpen); + strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb : wszOpen); strcatW(lpstrProtocol, wCommand); - /* Remove File Protocol from lpFile */ - /* In the case file://path/file */ - if (!strncmpiW(lpFile, wFile, iSize)) - { - lpFile += iSize; - while (*lpFile == ':') lpFile++; - } retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters, wcmd, execfunc, psei, psei_out); HeapFree(GetProcessHeap(), 0, lpstrProtocol); @@ -1566,7 +1654,7 @@ return retval; } -void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename) +static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename) { WCHAR msg[2048]; DWORD_PTR msgArguments[3] = { (DWORD_PTR)filename, 0, 0 }; @@ -1591,7 +1679,7 @@ /************************************************************************* * SHELL_execute [Internal] */ -BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) +static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) { static const DWORD unsupportedFlags = SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY | @@ -1608,7 +1696,7 @@ SHELLEXECUTEINFOW sei_tmp; /* modifiable copy of SHELLEXECUTEINFO struct */ WCHAR wfileName[MAX_PATH]; WCHAR *env; - WCHAR lpstrProtocol[256]; + WCHAR wszKeyname[256]; LPCWSTR lpFile; UINT_PTR retval = SE_ERR_NOASSOC; BOOL appKnownSingular = FALSE; @@ -1766,36 +1854,40 @@ dwApplicationNameLen ); } - /* expand environment strings */ - len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0); - if (len > 0) + /* convert file URLs */ + if (UrlIsFileUrlW(sei_tmp.lpFile)) { LPWSTR buf; - buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + DWORD size; - ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1); + size = MAX_PATH; + buf = static_cast(HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))); + if (!buf || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0))) + { + HeapFree(GetProcessHeap(), 0, buf); + return SE_ERR_OOM; + } + HeapFree(GetProcessHeap(), 0, wszApplicationName); - dwApplicationNameLen = len + 1; + dwApplicationNameLen = lstrlenW(buf) + 1; wszApplicationName = buf; - /* appKnownSingular unmodified */ - sei_tmp.lpFile = wszApplicationName; } - - if (*sei_tmp.lpParameters) + else /* or expand environment strings (not both!) */ { - len = ExpandEnvironmentStringsW(sei_tmp.lpParameters, NULL, 0); + len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0); if (len > 0) { LPWSTR buf; - len++; - buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - ExpandEnvironmentStringsW(sei_tmp.lpParameters, buf, len); - if (wszParameters != parametersBuffer) - HeapFree(GetProcessHeap(), 0, wszParameters); - wszParameters = buf; - parametersLen = len; - sei_tmp.lpParameters = wszParameters; + buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + + ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1); + HeapFree(GetProcessHeap(), 0, wszApplicationName); + dwApplicationNameLen = len + 1; + wszApplicationName = buf; + /* appKnownSingular unmodified */ + + sei_tmp.lpFile = wszApplicationName; } } @@ -1849,6 +1941,7 @@ /* terminate previous command string after the quote character */ *end = L'\0'; + lpFile = wfileName; } else { @@ -1880,14 +1973,12 @@ } } - lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR)); + lpFile = sei_tmp.lpFile; } } else - lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR)); + lpFile = sei_tmp.lpFile; - lpFile = wfileName; - wcmd = wcmdBuffer; len = lstrlenW(wszApplicationName) + 3; if (sei_tmp.lpParameters[0]) @@ -1919,10 +2010,10 @@ /* Else, try to find the executable */ wcmd[0] = L'\0'; - retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, lpstrProtocol, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters); + retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters); if (retval > 32) /* Found */ { - retval = SHELL_quote_and_execute(wcmd, wszParameters, lpstrProtocol, + retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname, wszApplicationName, env, &sei_tmp, sei, execfunc); HeapFree(GetProcessHeap(), 0, env); @@ -1941,7 +2032,7 @@ { swprintf(lpQuotedFile, L"\"%s\"", lpFile); retval = SHELL_quote_and_execute(wExec, lpQuotedFile, - lpstrProtocol, + wszKeyname, wszApplicationName, env, &sei_tmp, sei, execfunc); HeapFree(GetProcessHeap(), 0, env); @@ -1953,12 +2044,12 @@ } else if (PathIsURLW(lpFile)) /* File not found, check for URL */ { - retval = SHELL_execute_url(lpFile, L"file", wcmd, &sei_tmp, sei, execfunc ); + retval = SHELL_execute_url(lpFile, wcmd, &sei_tmp, sei, execfunc ); } /* Check if file specified is in the form www.??????.*** */ else if (!strncmpiW(lpFile, L"www", 3)) { - /* if so, append lpFile http:// and call ShellExecute */ + /* if so, prefix lpFile with http:// and call ShellExecute */ WCHAR lpstrTmpFile[256]; strcpyW(lpstrTmpFile, L"http://"); strcatW(lpstrTmpFile, lpFile); @@ -1998,19 +2089,19 @@ /************************************************************************* * ShellExecuteA [SHELL32.290] */ -HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, +HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd) { SHELLEXECUTEINFOA sei; TRACE("%p,%s,%s,%s,%s,%d\n", - hWnd, debugstr_a(lpOperation), debugstr_a(lpFile), + hWnd, debugstr_a(lpVerb), debugstr_a(lpFile), debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd); sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_FLAG_NO_UI; sei.hwnd = hWnd; - sei.lpVerb = lpOperation; + sei.lpVerb = lpVerb; sei.lpFile = lpFile; sei.lpParameters = lpParameters; sei.lpDirectory = lpDirectory; @@ -2090,10 +2181,10 @@ /************************************************************************* * ShellExecuteW [SHELL32.294] * from shellapi.h - * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, + * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd); */ -HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile, +HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd) { SHELLEXECUTEINFOW sei; @@ -2102,7 +2193,7 @@ sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_FLAG_NO_UI; sei.hwnd = hwnd; - sei.lpVerb = lpOperation; + sei.lpVerb = lpVerb; sei.lpFile = lpFile; sei.lpParameters = lpParameters; sei.lpDirectory = lpDirectory; @@ -2122,7 +2213,7 @@ * * FIXME: the callback function most likely doesn't work the same way on Windows. */ -EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, +EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback) { SHELLEXECUTEINFOW seiW; @@ -2129,7 +2220,7 @@ WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL; HANDLE hProcess = 0; - seiW.lpVerb = lpOperation ? __SHCloneStrAtoW(&wVerb, lpOperation) : NULL; + seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL; seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL; seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL; seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;