windows-nt/Source/XPSP1/NT/shell/ext/url/urlexec.cpp
2020-09-26 16:20:57 +08:00

368 lines
10 KiB
C++

/*
* urlexec.cpp - IUnknown implementation for Intshcut class.
*/
#include "project.hpp"
#include "urlshell.h"
#include "clsfact.h"
#include "resource.h"
#include <mluisupp.h>
// URL Exec Hook
class CURLExec : public IShellExecuteHookA, public IShellExecuteHookW
{
private:
ULONG m_cRef;
~CURLExec(void); // Prevent this class from being allocated on the stack or it will fault.
public:
CURLExec(void);
// IShellExecuteHook methods
// Ansi
STDMETHODIMP Execute(LPSHELLEXECUTEINFOA pei);
// Unicode
STDMETHODIMP Execute(LPSHELLEXECUTEINFOW pei);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppvObj);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
#ifdef DEBUG
friend BOOL IsValidPCURLExec(const CURLExec * pue);
#endif
};
#ifdef DEBUG
BOOL IsValidPCURLExec(CURLExec * pue)
{
return (IS_VALID_READ_PTR(pue, CURLExec));
}
#endif
CURLExec::CURLExec(void) : m_cRef(1)
{
// CURLExec objects should always be allocated
ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
DLLAddRef();
}
CURLExec::~CURLExec(void)
{
ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
DLLRelease();
}
/*----------------------------------------------------------
Purpose: IUnknown::QueryInterface handler for CURLExec
*/
STDMETHODIMP CURLExec::QueryInterface(REFIID riid, PVOID *ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IShellExecuteHookA))
{
*ppvObj = SAFECAST(this, IShellExecuteHookA *);
}
else if (IsEqualIID(riid, IID_IShellExecuteHookW))
{
*ppvObj = SAFECAST(this, IShellExecuteHookW *);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
STDMETHODIMP_(ULONG) CURLExec::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CURLExec::Release()
{
m_cRef--;
if (m_cRef > 0)
return m_cRef;
delete this;
return 0;
}
// from shlexec.c
#define SEE_MASK_CLASS (SEE_MASK_CLASSNAME|SEE_MASK_CLASSKEY)
/*----------------------------------------------------------
Purpose: IShellExecuteHook::Execute handler for CURLExec
*/
STDMETHODIMP CURLExec::Execute(LPSHELLEXECUTEINFOA pei)
{
HRESULT hres;
ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
ASSERT(IS_VALID_READ_PTR(pei, SHELLEXECUTEINFO));
if (! pei->lpVerb ||
! lstrcmpi(pei->lpVerb, TEXT("open")))
{
if (pei->lpFile)
{
LPTSTR pszURL;
// This should succeed only for real URLs. We should fail
// for file paths and let the shell handle those.
hres = TranslateURL(pei->lpFile,
TRANSLATEURL_FL_GUESS_PROTOCOL | TRANSLATEURL_FL_CANONICALIZE,
&pszURL);
if (SUCCEEDED(hres))
{
LPCTSTR pszURLToUse;
pszURLToUse = (hres == S_OK) ? pszURL : pei->lpFile;
hres = ValidateURL(pszURLToUse);
if (SUCCEEDED(hres))
{
IUniformResourceLocator * purl;
hres = SHCoCreateInstance(NULL, &CLSID_InternetShortcut, NULL, IID_IUniformResourceLocator, (void **)&purl);
if (SUCCEEDED(hres))
{
hres = purl->SetURL(pszURLToUse, 0);
if (hres == S_OK)
{
IShellLink * psl;
hres = purl->QueryInterface(IID_IShellLink, (void **)&psl);
if (SUCCEEDED(hres))
{
URLINVOKECOMMANDINFO urlici;
EVAL(psl->SetShowCmd(pei->nShow) == S_OK);
urlici.dwcbSize = SIZEOF(urlici);
urlici.hwndParent = pei->hwnd;
urlici.pcszVerb = NULL;
urlici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
if (IsFlagClear(pei->fMask, SEE_MASK_FLAG_NO_UI))
SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI);
hres = purl->InvokeCommand(&urlici);
if (hres != S_OK)
SetFlag(pei->fMask, SEE_MASK_FLAG_NO_UI);
psl->Release();
}
}
purl->Release();
}
}
if (pszURL)
LocalFree(pszURL);
}
}
else
// (scotth): This hook only handles execution of file string, not IDList.
hres = S_FALSE;
}
else
// Unrecognized verb.
hres = S_FALSE;
if (hres == S_OK)
pei->hInstApp = (HINSTANCE)42; // huh??
else if (FAILED(hres))
{
switch (hres)
{
case URL_E_INVALID_SYNTAX:
case URL_E_UNREGISTERED_PROTOCOL:
hres = S_FALSE;
break;
case E_OUTOFMEMORY:
pei->hInstApp = (HINSTANCE)SE_ERR_OOM;
hres = E_FAIL;
break;
case IS_E_EXEC_FAILED:
// Translate execution failure into "file not found".
pei->hInstApp = (HINSTANCE)SE_ERR_FNF;
hres = E_FAIL;
break;
default:
// pei->lpFile is bogus. Treat as file not found.
ASSERT(hres == E_POINTER);
pei->hInstApp = (HINSTANCE)SE_ERR_FNF;
hres = E_FAIL;
break;
}
}
else
ASSERT(hres == S_FALSE);
ASSERT(hres == S_OK ||
hres == S_FALSE ||
hres == E_FAIL);
return hres;
}
STDMETHODIMP CURLExec::Execute(LPSHELLEXECUTEINFOW pei)
{
// thunk stuff copied from shlexec.c InvokeShellExecuteHook
SHELLEXECUTEINFOA seia;
UINT cchVerb = 0;
UINT cchFile = 0;
UINT cchParameters = 0;
UINT cchDirectory = 0;
UINT cchClass = 0;
LPSTR lpszBuffer;
HRESULT hres = E_FAIL;
seia = *(SHELLEXECUTEINFOA*)pei; // Copy all of the binary data
if (pei->lpVerb)
{
cchVerb = WideCharToMultiByte(CP_ACP,0,
pei->lpVerb, -1,
NULL, 0,
NULL, NULL)+1;
}
if (pei->lpFile)
cchFile = WideCharToMultiByte(CP_ACP,0,
pei->lpFile, -1,
NULL, 0,
NULL, NULL)+1;
if (pei->lpParameters)
cchParameters = WideCharToMultiByte(CP_ACP,0,
pei->lpParameters, -1,
NULL, 0,
NULL, NULL)+1;
if (pei->lpDirectory)
cchDirectory = WideCharToMultiByte(CP_ACP,0,
pei->lpDirectory, -1,
NULL, 0,
NULL, NULL)+1;
if (((pei->fMask & SEE_MASK_CLASS) == SEE_MASK_CLASSNAME) && pei->lpClass)
cchClass = WideCharToMultiByte(CP_ACP,0,
pei->lpClass, -1,
NULL, 0,
NULL, NULL)+1;
// what is this (alloca)? InvokeShellExecuteHook is not freeing lpszBuffer
//lpszBuffer = alloca(cchVerb+cchFile+cchParameters+cchDirectory+cchClass);
lpszBuffer = (LPSTR)LocalAlloc(LPTR, cchVerb+cchFile+cchParameters+cchDirectory+cchClass);
if (lpszBuffer)
{
LPSTR lpsz = lpszBuffer;
seia.lpVerb = NULL;
seia.lpFile = NULL;
seia.lpParameters = NULL;
seia.lpDirectory = NULL;
seia.lpClass = NULL;
//
// Convert all of the strings to ANSI
//
if (pei->lpVerb)
{
WideCharToMultiByte(CP_ACP, 0, pei->lpVerb, -1,
lpszBuffer, cchVerb, NULL, NULL);
seia.lpVerb = lpszBuffer;
lpszBuffer += cchVerb;
}
if (pei->lpFile)
{
WideCharToMultiByte(CP_ACP, 0, pei->lpFile, -1,
lpszBuffer, cchFile, NULL, NULL);
seia.lpFile = lpszBuffer;
lpszBuffer += cchFile;
}
if (pei->lpParameters)
{
WideCharToMultiByte(CP_ACP, 0,
pei->lpParameters, -1,
lpszBuffer, cchParameters, NULL, NULL);
seia.lpParameters = lpszBuffer;
lpszBuffer += cchParameters;
}
if (pei->lpDirectory)
{
WideCharToMultiByte(CP_ACP, 0,
pei->lpDirectory, -1,
lpszBuffer, cchDirectory, NULL, NULL);
seia.lpDirectory = lpszBuffer;
lpszBuffer += cchDirectory;
}
if (((pei->fMask & SEE_MASK_CLASS) == SEE_MASK_CLASSNAME) && pei->lpClass)
{
WideCharToMultiByte(CP_ACP, 0,
pei->lpClass, -1,
lpszBuffer, cchClass, NULL, NULL);
seia.lpClass = lpszBuffer;
}
hres = Execute(&seia);
// now thunk the possible new stuff back
pei->hInstApp = seia.hInstApp;
if (pei->fMask & SEE_MASK_NOCLOSEPROCESS)
pei->hProcess = seia.hProcess;
LocalFree(lpsz);
}
return hres;
}
STDAPI CreateInstance_URLExec(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
{
*ppvOut = NULL;
if (punkOuter)
return CLASS_E_NOAGGREGATION;
CURLExec *pue = new(CURLExec);
if (!pue)
return E_OUTOFMEMORY;
HRESULT hres = pue->QueryInterface(riid, ppvOut);
pue->Release();
return hres;
}