mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
Invoke shortcuts through IContextMenu, rather than trying to access
them directly.
This commit is contained in:
parent
a1b1f997f1
commit
32d5240178
2 changed files with 264 additions and 140 deletions
|
@ -266,70 +266,6 @@ HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, U
|
|||
return hr;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* SHELL_ResolveShortCutW [Internal]
|
||||
* read shortcut file at 'wcmd'
|
||||
*/
|
||||
static HRESULT SHELL_ResolveShortCutW(LPWSTR wcmd, LPWSTR wargs, LPWSTR wdir, HWND hwnd, LPCWSTR lpVerb, int* pshowcmd, LPITEMIDLIST* ppidl)
|
||||
{
|
||||
IShellFolder* psf;
|
||||
|
||||
HRESULT hr = SHGetDesktopFolder(&psf);
|
||||
|
||||
*ppidl = NULL;
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
LPITEMIDLIST pidl;
|
||||
ULONG l;
|
||||
|
||||
hr = IShellFolder_ParseDisplayName(psf, 0, 0, wcmd, &l, &pidl, 0);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
IShellLinkW* psl;
|
||||
|
||||
hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl, &IID_IShellLinkW, NULL, (LPVOID*)&psl);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = IShellLinkW_Resolve(psl, hwnd, 0);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = IShellLinkW_GetPath(psl, wcmd, MAX_PATH, NULL, SLGP_UNCPRIORITY);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (!*wcmd) {
|
||||
/* We could not translate the PIDL in the shell link into a valid file system path - so return the PIDL instead. */
|
||||
hr = IShellLinkW_GetIDList(psl, ppidl);
|
||||
|
||||
if (SUCCEEDED(hr) && *ppidl) {
|
||||
/* We got a PIDL instead of a file system path - try to translate it. */
|
||||
if (SHGetPathFromIDListW(*ppidl, wcmd)) {
|
||||
SHFree(*ppidl);
|
||||
*ppidl = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
/* get command line arguments, working directory and display mode if available */
|
||||
IShellLinkW_GetWorkingDirectory(psl, wdir, MAX_PATH);
|
||||
IShellLinkW_GetArguments(psl, wargs, MAX_PATH);
|
||||
IShellLinkW_GetShowCmd(psl, pshowcmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IShellLinkW_Release(psl);
|
||||
}
|
||||
|
||||
SHFree(pidl);
|
||||
}
|
||||
|
||||
IShellFolder_Release(psf);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* SHELL_ExecuteW [Internal]
|
||||
*
|
||||
|
@ -983,6 +919,262 @@ HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpR
|
|||
return (HINSTANCE)retval;
|
||||
}
|
||||
|
||||
/* FIXME: is this already implemented somewhere else? */
|
||||
static HKEY ShellExecute_GetClassKey( LPSHELLEXECUTEINFOW sei )
|
||||
{
|
||||
LPCWSTR ext = NULL, lpClass = NULL;
|
||||
LPWSTR cls = NULL;
|
||||
DWORD type = 0, sz = 0;
|
||||
HKEY hkey = 0;
|
||||
LONG r;
|
||||
|
||||
if (sei->fMask & SEE_MASK_CLASSALL)
|
||||
return sei->hkeyClass;
|
||||
|
||||
if (sei->fMask & SEE_MASK_CLASSNAME)
|
||||
lpClass = sei->lpClass;
|
||||
else
|
||||
{
|
||||
ext = PathFindExtensionW( sei->lpFile );
|
||||
TRACE("ext = %s\n", debugstr_w( ext ) );
|
||||
if (!ext)
|
||||
return hkey;
|
||||
|
||||
r = RegOpenKeyW( HKEY_CLASSES_ROOT, ext, &hkey );
|
||||
if (r != ERROR_SUCCESS )
|
||||
return hkey;
|
||||
|
||||
r = RegQueryValueExW( hkey, NULL, 0, &type, NULL, &sz );
|
||||
if ( r == ERROR_SUCCESS && type == REG_SZ )
|
||||
{
|
||||
sz += sizeof (WCHAR);
|
||||
cls = HeapAlloc( GetProcessHeap(), 0, sz );
|
||||
cls[0] = 0;
|
||||
RegQueryValueExW( hkey, NULL, 0, &type, (LPBYTE) cls, &sz );
|
||||
}
|
||||
|
||||
RegCloseKey( hkey );
|
||||
lpClass = cls;
|
||||
}
|
||||
|
||||
TRACE("class = %s\n", debugstr_w(lpClass) );
|
||||
|
||||
hkey = 0;
|
||||
if ( lpClass )
|
||||
RegOpenKeyW( HKEY_CLASSES_ROOT, lpClass, &hkey );
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, cls );
|
||||
|
||||
return hkey;
|
||||
}
|
||||
|
||||
static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei )
|
||||
{
|
||||
LPCITEMIDLIST pidllast = NULL;
|
||||
IDataObject *dataobj = NULL;
|
||||
IShellFolder *shf = NULL;
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
HRESULT r;
|
||||
|
||||
if (sei->fMask & SEE_MASK_CLASSALL)
|
||||
pidl = sei->lpIDList;
|
||||
else
|
||||
{
|
||||
WCHAR fullpath[MAX_PATH];
|
||||
|
||||
fullpath[0] = 0;
|
||||
r = GetFullPathNameW( sei->lpFile, MAX_PATH, fullpath, NULL );
|
||||
if (!r)
|
||||
goto end;
|
||||
|
||||
pidl = ILCreateFromPathW( fullpath );
|
||||
}
|
||||
|
||||
r = SHBindToParent( pidl, &IID_IShellFolder, (LPVOID*)&shf, &pidllast );
|
||||
if ( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
IShellFolder_GetUIObjectOf( shf, NULL, 1, &pidllast,
|
||||
&IID_IDataObject, NULL, (LPVOID*) &dataobj );
|
||||
|
||||
end:
|
||||
if ( pidl != sei->lpIDList )
|
||||
ILFree( pidl );
|
||||
if ( shf )
|
||||
IShellFolder_Release( shf );
|
||||
return dataobj;
|
||||
}
|
||||
|
||||
static HRESULT shellex_run_context_menu_default( IShellExtInit *obj,
|
||||
LPSHELLEXECUTEINFOW sei )
|
||||
{
|
||||
IContextMenu *cm = NULL;
|
||||
CMINVOKECOMMANDINFOEX ici;
|
||||
MENUITEMINFOW info;
|
||||
WCHAR string[0x80];
|
||||
INT i, n, def = -1;
|
||||
HMENU hmenu = 0;
|
||||
HRESULT r;
|
||||
|
||||
TRACE("%p %p\n", obj, sei );
|
||||
|
||||
r = IShellExtInit_QueryInterface( obj, &IID_IContextMenu, (LPVOID*) &cm );
|
||||
if ( FAILED( r ) )
|
||||
return r;
|
||||
|
||||
hmenu = CreateMenu();
|
||||
if ( !hmenu )
|
||||
goto end;
|
||||
|
||||
/* the number of the last menu added is returned in r */
|
||||
r = IContextMenu_QueryContextMenu( cm, hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY );
|
||||
if ( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
n = GetMenuItemCount( hmenu );
|
||||
for ( i = 0; i < n; i++ )
|
||||
{
|
||||
memset( &info, 0, sizeof info );
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
|
||||
info.dwTypeData = string;
|
||||
info.cch = sizeof string;
|
||||
string[0] = 0;
|
||||
GetMenuItemInfoW( hmenu, i, TRUE, &info );
|
||||
|
||||
TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string),
|
||||
info.fState, info.dwItemData, info.fType, info.wID );
|
||||
if ( ( !sei->lpVerb && (info.fState & MFS_DEFAULT) ) ||
|
||||
( sei->lpVerb && !lstrcmpiW( sei->lpVerb, string ) ) )
|
||||
{
|
||||
def = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
r = E_FAIL;
|
||||
if ( def == -1 )
|
||||
goto end;
|
||||
|
||||
memset( &ici, 0, sizeof ici );
|
||||
ici.cbSize = sizeof ici;
|
||||
ici.fMask = CMIC_MASK_UNICODE;
|
||||
ici.nShow = sei->nShow;
|
||||
ici.lpVerb = MAKEINTRESOURCEA( def );
|
||||
ici.hwnd = sei->hwnd;
|
||||
ici.lpParametersW = sei->lpParameters;
|
||||
|
||||
r = IContextMenu_InvokeCommand( cm, (LPCMINVOKECOMMANDINFO) &ici );
|
||||
|
||||
TRACE("invoke command returned %08lx\n", r );
|
||||
|
||||
end:
|
||||
if ( hmenu )
|
||||
DestroyMenu( hmenu );
|
||||
if ( cm )
|
||||
IContextMenu_Release( cm );
|
||||
return r;
|
||||
}
|
||||
|
||||
static HRESULT shellex_load_object_and_run( HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei )
|
||||
{
|
||||
IDataObject *dataobj = NULL;
|
||||
IObjectWithSite *ows = NULL;
|
||||
IShellExtInit *obj = NULL;
|
||||
HRESULT r;
|
||||
|
||||
TRACE("%p %s %p\n", hkey, debugstr_guid( guid ), sei );
|
||||
|
||||
r = CoInitialize( NULL );
|
||||
if ( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
r = CoCreateInstance( guid, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IShellExtInit, (LPVOID*)&obj );
|
||||
if ( FAILED( r ) )
|
||||
{
|
||||
ERR("failed %08lx\n", r );
|
||||
goto end;
|
||||
}
|
||||
|
||||
dataobj = shellex_get_dataobj( sei );
|
||||
if ( !dataobj )
|
||||
{
|
||||
ERR("failed to get data object\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = IShellExtInit_Initialize( obj, NULL, dataobj, hkey );
|
||||
if ( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
r = IShellExtInit_QueryInterface( obj, &IID_IObjectWithSite, (LPVOID*) &ows );
|
||||
if ( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
IObjectWithSite_SetSite( ows, NULL );
|
||||
|
||||
r = shellex_run_context_menu_default( obj, sei );
|
||||
|
||||
end:
|
||||
if ( ows )
|
||||
IObjectWithSite_Release( ows );
|
||||
if ( dataobj )
|
||||
IDataObject_Release( dataobj );
|
||||
if ( obj )
|
||||
IShellExtInit_Release( obj );
|
||||
CoUninitialize();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* ShellExecute_FromContextMenu [Internal]
|
||||
*/
|
||||
static LONG ShellExecute_FromContextMenu( LPSHELLEXECUTEINFOW sei )
|
||||
{
|
||||
static const WCHAR szcm[] = { 's','h','e','l','l','e','x','\\',
|
||||
'C','o','n','t','e','x','t','M','e','n','u','H','a','n','d','l','e','r','s',0 };
|
||||
HKEY hkey, hkeycm = 0;
|
||||
WCHAR szguid[39];
|
||||
HRESULT hr;
|
||||
GUID guid;
|
||||
DWORD i;
|
||||
LONG r;
|
||||
|
||||
TRACE("%s\n", debugstr_w(sei->lpFile) );
|
||||
|
||||
hkey = ShellExecute_GetClassKey( sei );
|
||||
if ( !hkey )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = RegOpenKeyW( hkey, szcm, &hkeycm );
|
||||
if ( r == ERROR_SUCCESS )
|
||||
{
|
||||
i = 0;
|
||||
while ( 1 )
|
||||
{
|
||||
r = RegEnumKeyW( hkeycm, i++, szguid, 39 );
|
||||
if ( r != ERROR_SUCCESS )
|
||||
break;
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
hr = CLSIDFromString( szguid, &guid );
|
||||
if ( FAILED( hr ) )
|
||||
break;
|
||||
r = ERROR_SUCCESS;
|
||||
/* stop at the first one that succeeds in running */
|
||||
hr = shellex_load_object_and_run( hkey, &guid, sei );
|
||||
if ( SUCCEEDED( hr ) )
|
||||
break;
|
||||
}
|
||||
RegCloseKey( hkeycm );
|
||||
}
|
||||
|
||||
if ( hkey != sei->hkeyClass )
|
||||
RegCloseKey( hkey );
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* SHELL_execute [Internal]
|
||||
*/
|
||||
|
@ -993,7 +1185,6 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc, BOOL uni
|
|||
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};
|
||||
static const WCHAR wExtLnk[] = {'.','l','n','k',0};
|
||||
static const WCHAR wExplorer[] = {'e','x','p','l','o','r','e','r','.','e','x','e',0};
|
||||
static const DWORD unsupportedFlags =
|
||||
SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY |
|
||||
|
@ -1010,7 +1201,6 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc, BOOL uni
|
|||
UINT_PTR retval = 31;
|
||||
WCHAR wcmd[1024];
|
||||
WCHAR buffer[MAX_PATH];
|
||||
const WCHAR* ext;
|
||||
BOOL done;
|
||||
|
||||
/* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */
|
||||
|
@ -1083,6 +1273,12 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc, BOOL uni
|
|||
TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
|
||||
}
|
||||
|
||||
if ( ERROR_SUCCESS == ShellExecute_FromContextMenu( &sei_tmp ) )
|
||||
{
|
||||
sei->hInstApp = (HINSTANCE) 33;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (sei_tmp.fMask & SEE_MASK_CLASSALL)
|
||||
{
|
||||
/* launch a document by fileclass like 'WordPad.Document.1' */
|
||||
|
@ -1111,78 +1307,6 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc, BOOL uni
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* resolve shell shortcuts */
|
||||
ext = PathFindExtensionW(sei_tmp.lpFile);
|
||||
|
||||
if (ext && !strncmpiW(ext, wExtLnk, sizeof(wExtLnk) / sizeof(WCHAR) - 1) &&
|
||||
(ext[sizeof(wExtLnk) / sizeof(WCHAR) - 1] == '\0' ||
|
||||
(sei_tmp.lpFile[0] == '"' && ext[sizeof(wExtLnk) / sizeof(WCHAR) - 1] == '"'))) /* or check for: shell_attribs & SFGAO_LINK */
|
||||
{
|
||||
HRESULT hr;
|
||||
BOOL Quoted;
|
||||
|
||||
if (wszApplicationName[0] == '"')
|
||||
{
|
||||
if (wszApplicationName[strlenW(wszApplicationName) - 1] == '"')
|
||||
{
|
||||
wszApplicationName[strlenW(wszApplicationName) - 1] = '\0';
|
||||
Quoted = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Quoted = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Quoted = FALSE;
|
||||
}
|
||||
/* expand paths before reading shell link */
|
||||
if (ExpandEnvironmentStringsW(Quoted ? sei_tmp.lpFile + 1 : sei_tmp.lpFile, buffer, MAX_PATH))
|
||||
lstrcpyW(Quoted ? wszApplicationName + 1 : wszApplicationName/*sei_tmp.lpFile*/, buffer);
|
||||
|
||||
if (*sei_tmp.lpParameters)
|
||||
if (ExpandEnvironmentStringsW(sei_tmp.lpParameters, buffer, MAX_PATH))
|
||||
lstrcpyW(wszParameters/*sei_tmp.lpParameters*/, buffer);
|
||||
|
||||
hr = SHELL_ResolveShortCutW((LPWSTR)(Quoted ? sei_tmp.lpFile + 1 : sei_tmp.lpFile),
|
||||
(LPWSTR)sei_tmp.lpParameters, (LPWSTR)sei_tmp.lpDirectory,
|
||||
sei_tmp.hwnd, sei_tmp.lpVerb?sei_tmp.lpVerb:wszEmpty, &sei_tmp.nShow, (LPITEMIDLIST*)&sei_tmp.lpIDList);
|
||||
if (Quoted)
|
||||
{
|
||||
wszApplicationName[strlenW(wszApplicationName) + 1] = '\0';
|
||||
wszApplicationName[strlenW(wszApplicationName)] = '"';
|
||||
}
|
||||
|
||||
if (sei->lpIDList)
|
||||
sei->fMask |= SEE_MASK_IDLIST;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
/* repeat IDList processing if needed */
|
||||
if (sei_tmp.fMask & SEE_MASK_IDLIST)
|
||||
{
|
||||
IShellExecuteHookW* pSEH;
|
||||
|
||||
HRESULT hr = SHBindToParent(sei_tmp.lpIDList, &IID_IShellExecuteHookW, (LPVOID*)&pSEH, NULL);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IShellExecuteHookW_Execute(pSEH, &sei_tmp);
|
||||
|
||||
IShellExecuteHookW_Release(pSEH);
|
||||
|
||||
if (hr == S_OK)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TRACE("-- idlist=%p (%s)\n", debugstr_w(sei_tmp.lpIDList), debugstr_w(sei_tmp.lpFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Has the IDList not yet been translated? */
|
||||
if (sei_tmp.fMask & SEE_MASK_IDLIST)
|
||||
{
|
||||
|
|
|
@ -761,7 +761,7 @@ static void test_lnks(void)
|
|||
{
|
||||
okChildInt("argcA", 5);
|
||||
}
|
||||
else todo_wine
|
||||
else
|
||||
{
|
||||
okChildInt("argcA", 5);
|
||||
}
|
||||
|
@ -778,7 +778,7 @@ static void test_lnks(void)
|
|||
{
|
||||
okChildPath("argvA4", params);
|
||||
}
|
||||
else todo_wine
|
||||
else
|
||||
{
|
||||
okChildPath("argvA4", params);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue