📄 shlexec.c
字号:
return ret;
}
/*************************************************************************
* execute_from_key [Internal]
*/
static UINT_PTR execute_from_key(LPWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWSTR szCommandline,
SHELL_ExecuteW32 execfunc,
LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
{
WCHAR cmd[1024];
LONG cmdlen = sizeof(cmd);
UINT_PTR retval = 31;
cmd[0] = '\0';
/* Get the application for the registry */
if (RegQueryValueW(HKEY_CLASSES_ROOT, key, cmd, &cmdlen) == ERROR_SUCCESS)
{
static const WCHAR wCommand[] = {'c','o','m','m','a','n','d',0};
static const WCHAR wDdeexec[] = {'d','d','e','e','x','e','c',0};
LPWSTR tmp;
WCHAR param[256];
LONG paramlen = sizeof(param);
param[0] = '\0';
/* Get the parameters needed by the application
from the associated ddeexec key */
tmp = strstrW(key, wCommand);
assert(tmp);
strcpyW(tmp, wDdeexec);
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, szCommandline, psei->lpIDList, execfunc, psei, psei_out);
}
else
{
/* Is there a replace() function anywhere? */
cmdlen /= sizeof(WCHAR);
cmd[cmdlen] = '\0';
SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, psei->lpIDList, szCommandline);
retval = execfunc(param, env, FALSE, psei, psei_out);
}
}
else TRACE("ooch\n");
return retval;
}
/*************************************************************************
* FindExecutableA [SHELL32.@]
*/
HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
{
HINSTANCE retval;
WCHAR *wFile = NULL, *wDirectory = NULL;
WCHAR wResult[MAX_PATH];
if (lpFile) __SHCloneStrAtoW(&wFile, lpFile);
if (lpDirectory) __SHCloneStrAtoW(&wDirectory, lpDirectory);
retval = FindExecutableW(wFile, wDirectory, wResult);
WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL);
if (wFile) SHFree( wFile );
if (wDirectory) SHFree( wDirectory );
TRACE("returning %s\n", lpResult);
return retval;
}
/*************************************************************************
* FindExecutableW [SHELL32.@]
*/
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
{
UINT_PTR retval = 31; /* default - 'No association was found' */
WCHAR old_dir[1024];
TRACE("File %s, Dir %s\n",
(lpFile != NULL ? debugstr_w(lpFile) : "-"), (lpDirectory != NULL ? debugstr_w(lpDirectory) : "-"));
lpResult[0] = '\0'; /* Start off with an empty return string */
/* trap NULL parameters on entry */
if ((lpFile == NULL) || (lpResult == NULL))
{
/* FIXME - should throw a warning, perhaps! */
return (HINSTANCE)2; /* File not found. Close enough, I guess. */
}
if (lpDirectory)
{
GetCurrentDirectoryW(sizeof(old_dir)/sizeof(WCHAR), old_dir);
SetCurrentDirectoryW(lpDirectory);
}
retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, lpResult, MAX_PATH, NULL, NULL, NULL, NULL);
TRACE("returning %s\n", debugstr_w(lpResult));
if (lpDirectory)
SetCurrentDirectoryW(old_dir);
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;
hr = CLSIDFromString( szguid, &guid );
if (SUCCEEDED(hr))
{
/* 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]
*/
BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
{
static const WCHAR wQuote[] = {'"',0};
static const WCHAR wSpace[] = {' ',0};
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 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 |
SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI |
SEE_MASK_UNICODE | SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK |
SEE_MASK_HMONITOR;
WCHAR wszApplicationName[MAX_PATH+2], wszParameters[1024], wszDir[MAX_PATH];
SHELLEXECUTEINFOW sei_tmp; /* modifiable copy of SHELLEXECUTEINFO struct */
WCHAR wfileName[MAX_PATH];
WCHAR *env;
WCHAR lpstrProtocol[256];
LPCWSTR lpFile;
UINT_PTR retval = 31;
WCHAR wcmd[1024];
WCHAR buffer[MAX_PATH];
WCHAR target[MAX_PATH];
BOOL done;
DWORD attribs;
/* 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_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_CLASSALL) == SEE_MASK_CLASSNAME) ?
debugstr_w(sei_tmp.lpClass) : "not used");
sei->hProcess = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -