urlexec.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 12k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*
  2.  * urlexec.cpp - IUnknown implementation for Intshcut class.
  3.  */
  4. #include "shellprv.h"
  5. #include <shstr.h>
  6. #include <intshcut.h>
  7. // URL Exec Hook
  8. class CURLExec : public IShellExecuteHook
  9. {
  10. private:
  11.     ULONG       m_cRef;
  12.     ~CURLExec(void);    // Prevent this class from being allocated on the stack or it will fault.
  13. public:
  14.     CURLExec(void);
  15.    // IShellExecuteHook methods
  16.     STDMETHODIMP Execute(LPSHELLEXECUTEINFO pei);
  17.     // IUnknown methods
  18.     
  19.     STDMETHODIMP  QueryInterface(REFIID riid, PVOID *ppvObj);
  20.     STDMETHODIMP_(ULONG) AddRef(void);
  21.     STDMETHODIMP_(ULONG) Release(void);
  22.     
  23. #ifdef DEBUG
  24.     friend BOOL IsValidPCURLExec(const CURLExec * pue);
  25. #endif
  26. };
  27. #ifdef DEBUG
  28. BOOL IsValidPCURLExec(CURLExec * pue)
  29. {
  30.     return (IS_VALID_READ_PTR(pue, CURLExec));
  31. }
  32. #endif
  33. /*----------------------------------------------------------
  34. Purpose: This function qualifies a string as a URL.  Strings
  35.          such as "www.foo.com" would have the scheme guessed
  36.          if the correct flags are given.  Local paths are 
  37.          converted to "file:" URLs.
  38.          pszTranslatedURL may point to the same buffer as 
  39.          pcszURL.
  40.          NOTE:  This is identical to shdocvw's IURLQualify,
  41.          except it doesn't have the search hook.
  42. Returns: S_OK or S_FALSE means we filled in pszTranslatedURL.
  43.          S_OK means we altered the URL to qualify it too.
  44.          various failure codes too
  45. Cond:    --
  46. */
  47. STDAPI
  48. MyIURLQualify(
  49.     IN  LPCTSTR pcszURL, 
  50.     IN  DWORD  dwFlags,         // UQF_*
  51.     OUT LPTSTR  pszTranslatedURL)
  52. {
  53.     HRESULT hres = S_FALSE;
  54.     SHSTR strOut;
  55.     ASSERT(IS_VALID_STRING_PTR(pcszURL, -1));
  56.     ASSERT(IS_VALID_STRING_PTR(pszTranslatedURL, -1));
  57.     // Special cases: URLs of the form <drive>:<filename>
  58.     //                URLs of the form <filename>
  59.     // we'll assume that if the second character is a : or |, this is an url of
  60.     // that form, and we will guess "file://" for the prefix.
  61.     // we'll assume any url that begins with a single  is a file: url
  62.  
  63.     // NOTE: We do this here because these are cases where the protocol is 
  64.     // left off, and is likely to be incorrectly guessed, such as a 
  65.     // relative path dataftpdocs, would wrongly be turned 
  66.     // into "ftp://dataftpdocs".
  67.  
  68.     if (PathIsURL(pcszURL))
  69.     {
  70.         //  BUGBUG multiple exit points for expediency
  71.         //  of common case
  72.         if (pszTranslatedURL != pcszURL)
  73.             lstrcpy(pszTranslatedURL, pcszURL);
  74.         return S_OK;
  75.     }
  76.     //  look for file paths
  77.     else if (IsFlagClear(dwFlags, UQF_IGNORE_FILEPATHS) &&
  78.         (pcszURL[1] == ':' || pcszURL[1] == '|' || pcszURL[0] == '\'))
  79.     {
  80.         hres = strOut.SetSize(MAX_PATH);
  81.         if(SUCCEEDED(hres))
  82.         {
  83.             //  SHSTRs have a size granularity, so the size
  84.             //  will be equal to or greater than what was set.
  85.             //  this means we need to get it our self.
  86.             DWORD cchOut = strOut.GetSize();
  87.             TCHAR szCurrentDir[MAX_PATH];
  88.             //
  89.             //  BUGBUG - IE30 compatibility - zekel 8-Jan-97
  90.             //  we need to GetCurrentDirectory() in order to
  91.             //  put a default drive letter on the path
  92.             //  if necessary.  
  93.             //
  94.             if(GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir))
  95.                 PathCombine((LPTSTR)strOut, szCurrentDir, pcszURL);
  96.             else
  97.                 hres = strOut.SetStr(pcszURL);
  98.             if(SUCCEEDED(hres))
  99.             {
  100.                 hres = UrlCreateFromPath((LPTSTR) strOut, (LPTSTR) strOut, &cchOut, 0);
  101.                 if (E_POINTER == hres && SUCCEEDED(hres = strOut.SetSize(cchOut)))
  102.                 {
  103.                     cchOut = strOut.GetSize();
  104.                     hres = UrlCreateFromPath((LPTSTR) strOut, (LPTSTR) strOut, &cchOut, 0);
  105.                 }
  106.             }
  107.         }
  108.     }
  109.     else if (SUCCEEDED(hres = strOut.SetSize(INTERNET_MAX_URL_LENGTH)))
  110.     {
  111.         // No; begin processing general-case URLs.  Try to guess the
  112.         // protocol or resort to the default protocol.
  113.         DWORD cchOut = strOut.GetSize();
  114.         if (IsFlagSet(dwFlags, UQF_GUESS_PROTOCOL))
  115.             hres = UrlApplyScheme(pcszURL, (LPTSTR) strOut, &cchOut, URL_APPLY_GUESSSCHEME);
  116.         if (hres == S_FALSE &&
  117.             IsFlagSet(dwFlags, UQF_USE_DEFAULT_PROTOCOL)) 
  118.         {
  119.             cchOut = strOut.GetSize();
  120.             hres = UrlApplyScheme(pcszURL, (LPTSTR) strOut, &cchOut, URL_APPLY_DEFAULT);
  121.         }
  122.         // Did the above fail?
  123.         if (S_FALSE == hres)
  124.         {
  125.             // Yes; return the real reason why the URL is bad
  126.             hres = URL_E_INVALID_SYNTAX;
  127.         }
  128.     }
  129.     if (SUCCEEDED(hres))
  130.     {
  131.         lstrcpy(pszTranslatedURL, (LPTSTR)strOut);
  132.     }
  133.     return hres;
  134. }
  135. STDAPI
  136. MyURLQualify(
  137.     LPCTSTR pszURL, 
  138.     DWORD  dwFlags,         // UQF_*
  139.     LPTSTR *ppszOut)
  140. {
  141.     HRESULT hres;
  142.     ASSERT(IS_VALID_STRING_PTR(pszURL, -1));
  143.     ASSERT(IS_VALID_WRITE_PTR(ppszOut, LPTSTR));
  144.     *ppszOut = NULL;
  145.     TCHAR szTempTranslatedURL[INTERNET_MAX_URL_LENGTH];
  146.     hres = MyIURLQualify(pszURL, dwFlags, szTempTranslatedURL);
  147.     if (SUCCEEDED(hres))
  148.     {
  149.         *ppszOut = StrDup(szTempTranslatedURL);
  150.         if (!*ppszOut)
  151.             hres = E_OUTOFMEMORY;
  152.     } 
  153.     return hres;
  154. }
  155. //-----------------------------------------------------------------------
  156. CURLExec::CURLExec(void) : m_cRef(1)
  157. {
  158.     // CURLExec objects should always be allocated
  159.     ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
  160.     return;
  161. }
  162. CURLExec::~CURLExec(void)
  163. {
  164.     ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
  165.     
  166.     return;
  167. }
  168. /*----------------------------------------------------------
  169. Purpose: IUnknown::QueryInterface handler for CURLExec
  170. */
  171. STDMETHODIMP CURLExec::QueryInterface(REFIID riid, PVOID *ppvObj)
  172. {
  173.     if (IsEqualIID(riid, IID_IUnknown) ||
  174.         IsEqualIID(riid, IID_IShellExecuteHook))
  175.     {
  176.         *ppvObj = SAFECAST(this, IShellExecuteHook *);
  177.     }
  178.     else
  179.     {
  180.         *ppvObj = NULL;
  181.         return E_NOINTERFACE;
  182.     }
  183.     AddRef();
  184.     return NOERROR;
  185. }
  186. STDMETHODIMP_(ULONG) CURLExec::AddRef()
  187. {
  188.     return ++m_cRef;
  189. }
  190. STDMETHODIMP_(ULONG) CURLExec::Release()
  191. {
  192.     m_cRef--;
  193.     if (m_cRef > 0)
  194.         return m_cRef;
  195.     delete this;
  196.     return 0;
  197. }
  198. /*----------------------------------------------------------
  199. Purpose: IShellExecuteHook::Execute handler for CURLExec
  200. */
  201. STDMETHODIMP CURLExec::Execute(LPSHELLEXECUTEINFO pei)
  202. {
  203.     HRESULT hres;
  204.     
  205.     ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
  206.     ASSERT(IS_VALID_STRUCT_PTR(pei, SHELLEXECUTEINFO));
  207.     
  208.     if (! pei->lpVerb ||
  209.         ! lstrcmpi(pei->lpVerb, TEXT("open")))
  210.     {
  211.         if (pei->lpFile && !UrlIs(pei->lpFile, URLIS_FILEURL))
  212.         {
  213.             LPTSTR pszURL;
  214.             // This should succeed only for real URLs.  We should fail
  215.             // for file paths and let the shell handle those.
  216.             // WARNING: since this hook is called in any process that
  217.             // calls ShellExecuteEx, we must be careful about calling
  218.             // into shdocvw (it is delay-loaded), since it loads OLE.
  219.             // Very piggy.
  220.             //
  221.             // If shdocvw isn't already loaded, defer to the local 
  222.             // MyURLQualify.  Otherwise, call shdocvw's URLQualify.
  223.             //
  224.             // URLQualify offers more features (e.g., search) than the 
  225.             // local MyURLQualify.  We'd like to take advantage of this
  226.             // in the explorer process (say, for the Run dialog).
  227.             
  228.             if (GetModuleHandle(TEXT("shdocvw.dll")))
  229.             {
  230.                 // Call the full-featured API
  231.                 hres = URLQualify(pei->lpFile, UQF_GUESS_PROTOCOL | UQF_IGNORE_FILEPATHS,
  232.                                   &pszURL);
  233.             }
  234.             else
  235.             {
  236.                 // Use the local function
  237.                 hres = MyURLQualify(pei->lpFile, UQF_GUESS_PROTOCOL | UQF_IGNORE_FILEPATHS,
  238.                                   &pszURL);
  239.             }
  240.             
  241.             if (SUCCEEDED(hres))
  242.             {
  243.                 IUniformResourceLocator * purl;
  244.                 hres = SHCoCreateInstance(NULL, &CLSID_InternetShortcut, NULL, IID_IUniformResourceLocator, (void **)&purl);
  245.                 if (SUCCEEDED(hres))
  246.                 {
  247.                     hres = purl->SetURL(pszURL, 0);
  248.                     if (hres == S_OK)
  249.                     {
  250.                         IShellLink * psl;
  251.                         hres = purl->QueryInterface(IID_IShellLink, (void **)&psl);
  252.                         if (SUCCEEDED(hres))
  253.                         {
  254.                             URLINVOKECOMMANDINFO urlici;
  255.                             EVAL(psl->SetShowCmd(pei->nShow) == S_OK);
  256.                             
  257.                             urlici.dwcbSize = SIZEOF(urlici);
  258.                             urlici.hwndParent = pei->hwnd;
  259.                             urlici.pcszVerb = NULL;
  260.                             
  261.                             urlici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
  262.                             
  263.                             if (IsFlagClear(pei->fMask, SEE_MASK_FLAG_NO_UI))
  264.                                 SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI);
  265.                             if (pei->fMask & SEE_MASK_FLAG_DDEWAIT)
  266.                                 SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_DDEWAIT);
  267.                                 
  268.                             hres = purl->InvokeCommand(&urlici);
  269.                             
  270.                             if (hres != S_OK)
  271.                                 SetFlag(pei->fMask, SEE_MASK_FLAG_NO_UI);
  272.                             psl->Release();
  273.                         }
  274.                     }
  275.                     purl->Release();
  276.                 }
  277.                 LocalFree(pszURL);
  278.             }
  279.         }
  280.         else
  281.             // BUGBUG (scotth): This hook only handles execution of file string, not IDList.
  282.             hres = S_FALSE;
  283.     }
  284.     else
  285.         // Unrecognized verb.
  286.         hres = S_FALSE;
  287.     
  288.     if (hres == S_OK)
  289.         pei->hInstApp = (HINSTANCE)42;  // BUGBUG (scotth): huh??
  290.     else if (FAILED(hres))
  291.     {
  292.         switch (hres)
  293.         {
  294.         case URL_E_INVALID_SYNTAX:
  295.         case URL_E_UNREGISTERED_PROTOCOL:
  296.             hres = S_FALSE;
  297.             break;
  298.             
  299.         case E_OUTOFMEMORY:
  300.             pei->hInstApp = (HINSTANCE)SE_ERR_OOM;
  301.             hres = E_FAIL;
  302.             break;
  303.             
  304.         case IS_E_EXEC_FAILED:
  305.             // Translate execution failure into "file not found".
  306.             pei->hInstApp = (HINSTANCE)SE_ERR_FNF;
  307.             hres = E_FAIL;
  308.             break;
  309.             
  310.         default:
  311.             // pei->lpFile is bogus.  Treat as file not found.
  312.             pei->hInstApp = (HINSTANCE)SE_ERR_FNF;
  313.             hres = E_FAIL;
  314.             break;
  315.         }
  316.     }
  317.     else
  318.         ASSERT(hres == S_FALSE);
  319.     
  320.     ASSERT(hres == S_OK ||
  321.         hres == S_FALSE ||
  322.         hres == E_FAIL);
  323.     
  324.     return hres;
  325. }
  326. STDAPI CURLExec_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
  327. {
  328.     HRESULT hres;
  329.     
  330.     CURLExec *pue = new CURLExec;
  331.     if (pue)
  332.     {
  333.         hres = pue->QueryInterface(riid, ppvOut);
  334.         pue->Release();
  335.     }
  336.     else
  337.     {
  338.         *ppvOut = NULL;
  339.         hres = E_OUTOFMEMORY;
  340.     }
  341.     return hres;
  342. }