From 9607151e38b4e6b24195907a664b2351919c2974 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Fri, 23 Jun 2006 18:32:38 +0200 Subject: [PATCH] shell32: Fix computation of default verb. Compute the default verb as documented on MSDN instead of blindly assuming it is 'open'. This fixes the WordViewer association in some cases. --- dlls/shell32/classes.c | 86 ++++++++++++++++++++++++++++++------- dlls/shell32/shell32_main.h | 1 + dlls/shell32/shlexec.c | 25 ++++++----- 3 files changed, 86 insertions(+), 26 deletions(-) diff --git a/dlls/shell32/classes.c b/dlls/shell32/classes.c index eb9d9e9563a..f6db0dc3738 100644 --- a/dlls/shell32/classes.c +++ b/dlls/shell32/classes.c @@ -117,30 +117,86 @@ BOOL HCR_MapTypeToValueA(LPCSTR szExtension, LPSTR szFileType, LONG len, BOOL bP return TRUE; } +static const WCHAR swShell[] = {'s','h','e','l','l','\\',0}; +static const WCHAR swOpen[] = {'o','p','e','n',0}; +static const WCHAR swCommand[] = {'\\','c','o','m','m','a','n','d',0}; + +BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len ) +{ + WCHAR sTemp[MAX_PATH]; + LONG size; + HKEY hkey; + + TRACE("%p %s %p\n", hkeyClass, debugstr_w(szVerb), szDest); + + if (szVerb) + { + lstrcpynW(szDest, szVerb, len); + return TRUE; + } + + size=len; + *szDest='\0'; + if (!RegQueryValueW(hkeyClass, swShell, szDest, &size) && *szDest) + { + /* The MSDN says to first try the default verb */ + lstrcpyW(sTemp, swShell); + lstrcatW(sTemp, szDest); + lstrcatW(sTemp, swCommand); + if (!RegOpenKeyExW(hkeyClass, sTemp, 0, 0, &hkey)) + { + RegCloseKey(hkey); + TRACE("default verb=%s\n", debugstr_w(szDest)); + return TRUE; + } + } + + /* then fallback to 'open' */ + lstrcpyW(sTemp, swShell); + lstrcatW(sTemp, swOpen); + lstrcatW(sTemp, swCommand); + if (!RegOpenKeyExW(hkeyClass, sTemp, 0, 0, &hkey)) + { + RegCloseKey(hkey); + lstrcpynW(szDest, swOpen, len); + TRACE("default verb=open\n"); + return TRUE; + } + + /* and then just use the first verb on Windows >= 2000 */ + if (!RegEnumKeyW(hkeyClass, 0, szDest, len) && *szDest) + { + TRACE("default verb=first verb=%s\n", debugstr_w(szDest)); + return TRUE; + } + + TRACE("no default verb!\n"); + return FALSE; +} BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len ) { - static const WCHAR swShell[] = {'s','h','e','l','l','\\',0}; - static const WCHAR swCommand[] = {'\\','c','o','m','m','a','n','d',0}; - BOOL ret = FALSE; + WCHAR sTempVerb[MAX_PATH]; + BOOL ret; TRACE("%p %s %s %p\n", hkeyClass, debugstr_w(szClass), debugstr_w(szVerb), szDest); if (szClass) RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, 0x02000000, &hkeyClass); + if (!hkeyClass) + return FALSE; + ret = FALSE; - if (hkeyClass) - { - WCHAR sTemp[MAX_PATH]; - lstrcpyW(sTemp, swShell); - lstrcatW(sTemp, szVerb); - lstrcatW(sTemp, swCommand); - - ret = (ERROR_SUCCESS == SHGetValueW(hkeyClass, sTemp, NULL, NULL, szDest, &len)); - - if (szClass) - RegCloseKey(hkeyClass); - } + if (HCR_GetDefaultVerbW(hkeyClass, szVerb, sTempVerb, sizeof(sTempVerb))) + { + WCHAR sTemp[MAX_PATH]; + lstrcpyW(sTemp, swShell); + lstrcatW(sTemp, sTempVerb); + lstrcatW(sTemp, swCommand); + ret = (ERROR_SUCCESS == SHGetValueW(hkeyClass, sTemp, NULL, NULL, szDest, &len)); + } + if (szClass) + RegCloseKey(hkeyClass); TRACE("-- %s\n", debugstr_w(szDest) ); return ret; diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 32d002f780c..e13c8506a3e 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -57,6 +57,7 @@ INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags ); /* Classes Root */ BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG len, BOOL bPrependDot); +BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len ); BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len ); BOOL HCR_GetDefaultIconW(LPCWSTR szClass, LPWSTR szDest, DWORD len, int* picon_idx); BOOL HCR_GetDefaultIconFromGUIDW(REFIID riid, LPWSTR szDest, DWORD len, int* picon_idx); diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index f626b1d8dce..955f32349db 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -426,10 +426,18 @@ end: static UINT SHELL_FindExecutableByOperation(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen) { static const WCHAR wCommand[] = {'\\','c','o','m','m','a','n','d',0}; + HKEY hkeyClass; + WCHAR verb[MAX_PATH]; + + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass)) + return 31; /* default - 'No association was found' */ + if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb))) + return 31; /* default - 'No association was found' */ + RegCloseKey(hkeyClass); /* Looking for ...buffer\shell\\command */ strcatW(filetype, wszShell); - strcatW(filetype, lpOperation); + strcatW(filetype, verb); strcatW(filetype, wCommand); if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command, @@ -508,10 +516,10 @@ UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, if (key) *key = '\0'; /* trap NULL parameters on entry */ - if ((lpFile == NULL) || (lpResult == NULL) || (lpOperation == NULL)) + if ((lpFile == NULL) || (lpResult == NULL)) { - WARN("(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n", - debugstr_w(lpFile), debugstr_w(lpOperation), debugstr_w(lpResult)); + WARN("(lpFile=%s,lpResult=%s): NULL parameter\n", + debugstr_w(lpFile), debugstr_w(lpResult)); return 2; /* File not found. Close enough, I guess. */ } @@ -1292,7 +1300,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) ULONG cmask=(sei_tmp.fMask & SEE_MASK_CLASSALL); HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? sei_tmp.hkeyClass : NULL, (cmask == SEE_MASK_CLASSNAME) ? sei_tmp.lpClass: NULL, - (sei_tmp.lpVerb) ? sei_tmp.lpVerb : wszOpen, + sei_tmp.lpVerb, wszParameters, sizeof(wszParameters)/sizeof(WCHAR)); /* FIXME: get the extension of lpFile, check if it fits to the lpClass */ @@ -1332,7 +1340,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY) && HCR_GetExecuteCommandW(0, wszFolder, - sei_tmp.lpVerb?sei_tmp.lpVerb:wszOpen, + sei_tmp.lpVerb, buffer, sizeof(buffer))) { SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen, buffer, target, sei_tmp.lpIDList, NULL); @@ -1427,11 +1435,6 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) strcatW(wcmd, wszParameters); } - /* We set the default to open, and that should generally work. - But that is not really the way the MS docs say to do it. */ - if (!sei_tmp.lpVerb) - sei_tmp.lpVerb = wszOpen; - retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei); if (retval > 32) { HeapFree(GetProcessHeap(), 0, wszApplicationName);