|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: hlinkez.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History:
// 5-15-96 Ramesh G - Major modifications
// 5-17-96 Ramesh G - Added Frames support
// Ramesh G - Modified variable names to Hungarian Notation
// 6-19-96 Ramesh G - Modifications
// 7-25-96 Ramesh G - Modifications
// 8-05-96 Ramesh G - Merged HlinkSimple...String() and Moniker()
// HlinkSimpleNavigateToString() creates the moniker
// and calls HlinkSimpleNavigateToMoniker()
//----------------------------------------------------------------------------
#define USE_SYSTEM_URL_MONIKER
#define INITGUID
#define STR_SIZE 20
#include "hlink.h"
#include "ocidl.h"
#include "docobj.h"
#include "exdisp.h"
#include "shellapi.h"
#include "servprov.h"
#include "urlhlink.h"
#include "htiface.h"
#include "wininet.h"
#include <shlwapi.h>
#include <shlwapip.h>
#include <mshtml.h>
#include "mshtmdid.h"
#include <delaydll.h>
#include "sdll.hxx"
#ifndef GUID_NULL
struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) GUID_NULL; #define GUID_NULL __uuidof(struct GUID_NULL)
#endif
class HLinkDll { public: HLinkDll(); HRESULT HlinkCreateFromMoniker( IMoniker* pmkSource, LPCWSTR szLocation, LPCWSTR szFriendlyName, IHlinkSite* phlSite, DWORD dwSiteData, IUnknown* punkOuter, REFIID riid, void** ppv); private:
BOOL LoadFunc( LPCSTR lpProcName, FARPROC & fp ); typedef HRESULT (STDAPICALLTYPE * LPFNHlinkCreateFromMoniker)( IMoniker* pmkSource, LPCWSTR szLocation, LPCWSTR szFriendlyName, IHlinkSite* phlSite, DWORD dwSiteData, IUnknown* punkOuter, REFIID riid, void** ppv); LPFNHlinkCreateFromMoniker m_lpfnHlinkCreateFromMoniker;
HMODULE m_hmodule; BOOL m_error;
};
inline HRESULT HLinkDll::HlinkCreateFromMoniker( IMoniker* pmkSource, LPCWSTR szLocation, LPCWSTR szFriendlyName, IHlinkSite* phlSite, DWORD dwSiteData, IUnknown* punkOuter, REFIID riid, void** ppv) {
if( !LoadFunc("HlinkCreateFromMoniker",*(FARPROC*)&m_lpfnHlinkCreateFromMoniker) ) return(E_FAIL);
return m_lpfnHlinkCreateFromMoniker( pmkSource, szLocation, szFriendlyName, phlSite, dwSiteData, punkOuter, riid, ppv); }
HLinkDll::HLinkDll() { m_hmodule = 0; m_error = 0; m_lpfnHlinkCreateFromMoniker = 0; }
#if 0
HLinkDll::~HLinkDll() { if( m_hmodule ) ::FreeLibrary( m_hmodule ); } #endif
BOOL HLinkDll::LoadFunc( LPCSTR lpProcName, FARPROC & fp ) { if( m_error ) return(0);
if( fp ) return(1);
if( !m_hmodule ) { m_hmodule = ::LoadLibrary( "HLINK.DLL" );
if( !m_hmodule ) { m_error = 1; return(0); }
}
fp = ::GetProcAddress( m_hmodule, lpProcName );
return( fp != 0 ); }
static HLinkDll hlink;
//////////////////
static int wclen(LPCWSTR szStr) { int cbStr=0; if(szStr!=NULL) while(szStr[cbStr]!=NULL) ++cbStr;
return cbStr; }
////////////////////////////
static HRESULT GetAnInterface ( IUnknown * punk, const IID & riid, void ** pout,
BOOL bCheckServiceProvider, const IID & siid, const IID & siid_riid, void ** sout ) { IOleObject * oleObj = 0; IOleClientSite * oleSite = 0; IOleContainer * container = 0; IUnknown * service = 0;
HRESULT hr = E_FAIL;
// Initialize passed in interface pointers: calling code assumes NULL for failure
if(pout) *pout = NULL; if(sout) *sout = NULL;
if(punk) hr = punk->QueryInterface( IID_IOleObject, (void **)&oleObj );
// BUBUG: I think this returns a wrong hr if QS fails but the QI passes - jp
while( SUCCEEDED(hr) && oleObj ) { if( oleSite ) { //oleSite->Release();
oleSite = 0; }
hr = oleObj->GetClientSite(&oleSite);
if( FAILED(hr) || !oleSite) break;
if( bCheckServiceProvider) { IServiceProvider * servProv;
hr = oleSite->QueryInterface( IID_IServiceProvider, (void**)&servProv);
if( SUCCEEDED(hr) ) { hr = servProv->QueryService ( siid, siid_riid, (void **)&service );
servProv->Release(); }
if( SUCCEEDED(hr) ) { bCheckServiceProvider = FALSE;
hr = service->QueryInterface( riid, pout ); }
if( SUCCEEDED(hr) ) break;
}
if( container ) { container->Release(); container = 0; }
hr = oleSite->GetContainer( &container );
if( FAILED(hr) ) break;
hr = container->QueryInterface( riid, pout );
if( SUCCEEDED(hr) ) break;
oleObj->Release(); oleObj = 0;
hr = container->QueryInterface( IID_IOleObject, (void**)&oleObj );
}
if( oleSite ) { oleSite->Release(); oleSite = 0; }
if( oleObj ) oleObj->Release();
if( container ) container->Release();
if( service ) { if (sout) *sout = service; else service->Release(); }
return( hr ); }
//
// GetUrlScheme() returns one of the URL_SCHEME_* constants as
// defined in shlwapip.h
// example "http://foo" returns URL_SCHEME_HTTP
//
static DWORD GetUrlSchemeW(IN LPCWSTR pcszUrl) { if(pcszUrl) { PARSEDURLW pu; pu.cbSize = sizeof(pu); if(SUCCEEDED(ParseURLW(pcszUrl, &pu))) return pu.nScheme; } return URL_SCHEME_INVALID; }
//
// GetUrlScheme() returns one of the URL_SCHEME_* constants as
// defined in shlwapip.h
// example "http://foo" returns URL_SCHEME_HTTP
//
static DWORD GetUrlSchemeA(IN LPCSTR pcszUrl) { if(pcszUrl) { PARSEDURLA pu; pu.cbSize = sizeof(pu); if(SUCCEEDED(ParseURLA(pcszUrl, &pu))) return pu.nScheme; } return URL_SCHEME_INVALID; }
HRESULT DoUrlShellExecuteA(LPCSTR pszUrl) { CShellDll sdll; HINSTANCE hInst = NULL;
if(S_OK == sdll.Init()) { UINT uProt = GetUrlSchemeA(pszUrl);
switch (uProt) { case URL_SCHEME_HTTP: case URL_SCHEME_HTTPS: case URL_SCHEME_FTP: case URL_SCHEME_FILE: hInst = sdll.ShellExecute( NULL, NULL, pszUrl, NULL, NULL, SW_SHOWNORMAL ); break;
// Non-standard protocols go here:
default: hInst = sdll.ShellExecute( NULL, "open", "iexplore.exe", pszUrl, NULL, SW_SHOWNORMAL ); } }
return ((ULONG_PTR)hInst > 32) ? S_OK : E_FAIL; }
BOOL IsSpecialUrl(WCHAR *pchURL) { UINT uProt; uProt = GetUrlSchemeW(pchURL); return (URL_SCHEME_JAVASCRIPT == uProt || URL_SCHEME_VBSCRIPT == uProt || URL_SCHEME_ABOUT == uProt); }
HRESULT WrapSpecialUrlFlat(LPWSTR pszUrl, DWORD cchUrl) { HRESULT hr = S_OK;
if (IsSpecialUrl(pszUrl)) { //
// If this is javascript:, vbscript: or about:, append the
// url of this document so that on the other side we can
// decide whether or not to allow script execution.
//
// QFE 2735 (Georgi XDomain): [alanau]
//
// If the special URL contains an %00 sequence, then it will be converted to a Null char when
// encoded. This will effectively truncate the Security ID. For now, simply disallow this
// sequence, and display a "Permission Denied" script error.
//
if (StrStrW(pszUrl, L"%00")) { hr = E_ACCESSDENIED; } else { // munge the url in place
//
// someone could put in a string like this:
// %2501 OR %252501 OR %25252501
// which, depending on the number of decoding steps, will bypass security
// so, just keep decoding while there are %s and the string is getting shorter
int nPreviousLen = 0; while ( (nPreviousLen != lstrlenW(pszUrl)) && (StrChrW(pszUrl, L'%'))) { nPreviousLen = lstrlenW(pszUrl); int nNumPercents; int nNumPrevPercents = 0;
// Reduce the URL
//
for (;;) { // Count the % signs.
//
nNumPercents = 0;
WCHAR *pch = pszUrl; while (pch = StrChrW(pch, L'%')) { pch++; nNumPercents++; }
// If the number of % signs has changed, we've reduced the URL one iteration.
//
if (nNumPercents != nNumPrevPercents) { WCHAR szBuf[INTERNET_MAX_URL_LENGTH]; DWORD dwSize;
// Encode the URL
hr = CoInternetParseUrl(pszUrl, PARSE_ENCODE, 0, szBuf, INTERNET_MAX_URL_LENGTH, &dwSize, 0);
StrCpyNW(pszUrl, szBuf, cchUrl);
nNumPrevPercents = nNumPercents; } else { // The URL is fully reduced. Break out of loop.
//
break; } } }
// Now scan for '\1' characters.
//
if (StrChrW(pszUrl, L'\1')) { // If there are '\1' characters, we can't guarantee the safety. Put up "Permission Denied".
//
hr = E_ACCESSDENIED; } } }
return hr; }
static HRESULT GetAMoniker ( IUnknown * pUnk, LPCWSTR szTarget, IMoniker * * ppMoniker ) { HRESULT hr; IBindHost * pBindHost = 0;
hr = GetAnInterface ( pUnk, IID_IBindHost, (void**)&pBindHost, TRUE, IID_IBindHost, IID_IBindHost, NULL );
if( pBindHost ) { hr = pBindHost->CreateMoniker((LPWSTR)szTarget,NULL,ppMoniker,0); pBindHost->Release(); } else hr = ::CreateURLMoniker(0,szTarget,ppMoniker);
return(hr); }
STDAPI HlinkSimpleNavigateToString ( /* [in] */ LPCWSTR szTarget, // required - target document - null if local jump w/in doc
/* [in] */ LPCWSTR szLocation, // optional, for navigation into middle of a doc
/* [in] */ LPCWSTR szTargetFrame, // optional, for targeting frame-sets
/* [in] */ IUnknown *pUnk, // required - we'll search this for other necessary interfaces
/* [in] */ IBindCtx *pBndctx, // optional. caller may register an IBSC in this
/* [in] */ IBindStatusCallback * pBscb, /* [in] */ DWORD grfHLNF, // flags (TBD - HadiP needs to define this correctly?)
/* [in] */ DWORD dwReserved // for future use, must be NULL
) { IWebBrowserApp *pExplorer = 0; IHlinkFrame *pHlframe = 0; ITargetFrame *pTargetFrame = 0; IMoniker *pMoniker = 0;
HRESULT hr = S_OK;
if ( szTarget && *szTarget ) hr = GetAMoniker( pUnk, szTarget, &pMoniker );
if ( SUCCEEDED(hr) ) hr = HlinkSimpleNavigateToMoniker ( pMoniker, szLocation, szTargetFrame, pUnk, pBndctx, pBscb, grfHLNF, dwReserved );
if ( pMoniker ) pMoniker->Release();
return( hr );
}
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
BOOL AccessAllowed(LPCWSTR pwszURL1, LPCWSTR pwszURL2) { BOOL fRet = FALSE; IInternetSecurityManager *pSecMgr = NULL;
if (pwszURL1 && pwszURL2) { if (StrCmpW(pwszURL1, pwszURL2) == 0) { // No need to check if URLs are the same
fRet = TRUE; } else if (SUCCEEDED(CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER, IID_IInternetSecurityManager, (void **)&pSecMgr))) { BYTE reqSid[MAX_SIZE_SECURITY_ID], docSid[MAX_SIZE_SECURITY_ID]; DWORD cbReqSid = ARRAYSIZE(reqSid); DWORD cbDocSid = ARRAYSIZE(docSid);
if ( SUCCEEDED(pSecMgr->GetSecurityId(pwszURL1, reqSid, &cbReqSid, 0)) && SUCCEEDED(pSecMgr->GetSecurityId(pwszURL2, docSid, &cbDocSid, 0)) && (cbReqSid == cbDocSid) && (memcmp(reqSid, docSid, cbReqSid) == 0)) { fRet = TRUE; } pSecMgr->Release(); } } return fRet; }
BOOL AccessAllowed(ITargetFrame* pSrcFrame, IHlinkFrame* pTargetFrame) { IDispatch* pdisp[2] = {0}; IServiceProvider* pIsp[2] = {0}; DISPPARAMS dp; VARIANT VarUrl[2]; UINT uiErr; BOOL fRet = FALSE; HRESULT hr; int idx;
if(!pTargetFrame || !pSrcFrame) { goto cleanup; }
hr = pTargetFrame->QueryInterface(IID_IServiceProvider, (LPVOID *)&pIsp[0]);
if(hr) goto cleanup;
hr = pSrcFrame->QueryInterface(IID_IServiceProvider, (LPVOID *)&pIsp[1]);
if(hr) goto cleanup;
VariantInit(&VarUrl[0]); VariantInit(&VarUrl[1]);
for (idx = 0; idx < 2; idx++) { hr = pIsp[idx]->QueryService(IID_IHTMLWindow2, IID_IDispatch, (LPVOID *)&pdisp[idx]);
if(hr) { hr = pIsp[idx]->QueryService(IID_IWebBrowserApp, IID_IDispatch, (LPVOID *)&pdisp[idx]); }
if(hr) goto cleanup;
ZeroMemory((PVOID)&dp, sizeof(dp));
hr = pdisp[idx]->Invoke( DISPID_SECURITYCTX, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dp, &VarUrl[idx], NULL, &uiErr); if(hr) goto cleanup;
if (V_VT(&VarUrl[idx]) != VT_BSTR || !V_BSTR(&VarUrl[idx])) { goto cleanup; }
if (hr) goto cleanup; }
fRet = AccessAllowed(V_BSTR(&VarUrl[0]), V_BSTR(&VarUrl[1]));
cleanup: for (idx = 0; idx < 2; idx++) { if(pdisp[idx]) pdisp[idx]->Release(); if(pIsp[idx]) pIsp[idx]->Release();
VariantClear(&VarUrl[idx]); } return fRet; }
STDAPI HlinkSimpleNavigateToMoniker ( /* [in] */ IMoniker *pmkTarget, // required - target document - (may be null if local jump w/in doc)
/* [in] */ LPCWSTR szLocation, // optional, for navigation into middle of a doc
/* [in] */ LPCWSTR szTargetFrame, // optional, for targeting frame-sets
/* [in] */ IUnknown *pUnk, // required - we'll search this for other necessary interfaces
/* [in] */ IBindCtx *pBndctx, // optional. caller may register an IBSC in this
/* [in] */ IBindStatusCallback * pBscb, /* [in] */ DWORD grfHLNF, // flags
/* [in] */ DWORD dwReserved // for future use, must be NULL
) { IWebBrowserApp * pExplorer = 0; IHlinkFrame * pHlframe = 0; ITargetFrame * pTargetFrameSrc = 0; CShellDll sdll; LPWSTR pszUrl = NULL;
HRESULT hr, htemp;
if (pmkTarget == NULL) { if (szLocation && *szLocation) { grfHLNF |= HLNF_INTERNALJUMP; hr = S_OK; } else return E_INVALIDARG; //no location specified for internal jump
} else { DWORD dwId;
if (SUCCEEDED(pmkTarget->IsSystemMoniker(&dwId)) && MKSYS_URLMONIKER == dwId) {
if (SUCCEEDED(pmkTarget->GetDisplayName(NULL, NULL, &pszUrl))) { HRESULT hrSecure = WrapSpecialUrlFlat(pszUrl, lstrlenW(pszUrl) + 1);
if (FAILED(hrSecure)) { CoTaskMemFree(pszUrl); return hrSecure; } } } }
if (pUnk) hr = GetAnInterface ( pUnk, IID_IWebBrowserApp, (void**)&pExplorer, TRUE, IID_IHlinkFrame, IID_IHlinkFrame, (void**)&pHlframe );
IHlink * pLink = 0;
hr = hlink.HlinkCreateFromMoniker ( pmkTarget, szLocation, L"TheName", 0, // hlsite,
0, NULL, IID_IHlink, (void**)&pLink );
if (SUCCEEDED(hr) && pHlframe) { BOOL fAccessAllowed = TRUE;
if (szTargetFrame && *szTargetFrame) { long len = (lstrlenW(szTargetFrame) + 1) * sizeof(char); char szTargetFrameName[STR_SIZE+1]; len = (len > STR_SIZE) ? STR_SIZE : len; WideCharToMultiByte(CP_ACP, 0, szTargetFrame, -1, (LPSTR)szTargetFrameName, len, NULL, NULL); if (lstrcmpi(szTargetFrameName,"_blank") == 0) grfHLNF |= HLNF_OPENINNEWWINDOW; else { htemp = GetAnInterface ( pUnk, IID_ITargetFrame, (void**)&pTargetFrameSrc, TRUE, IID_ITargetFrame, IID_ITargetFrame, NULL ); IUnknown *punkTargetFrame = 0; if (SUCCEEDED(htemp)) htemp = pTargetFrameSrc->FindFrame(szTargetFrame, pHlframe, FINDFRAME_JUSTTESTEXISTENCE, &punkTargetFrame); IHlinkFrame *pTargetHlinkFrame = 0; if (punkTargetFrame) { IServiceProvider *pIsp = 0;
// Get the IHlinkFrame for the target'ed frame and the source.
htemp = punkTargetFrame->QueryInterface(IID_IServiceProvider, (LPVOID *)&pIsp); if (pIsp != NULL) { // NOTE: SID_SHLinkFrame should be the guidService
htemp = pIsp->QueryService(IID_IWebBrowserApp, IID_IHlinkFrame, (LPVOID*) &pTargetHlinkFrame); pIsp->Release(); }
fAccessAllowed = (!IsSpecialUrl(pszUrl) || AccessAllowed(pTargetFrameSrc, pTargetHlinkFrame)); } else { grfHLNF |= HLNF_OPENINNEWWINDOW; } if (punkTargetFrame) punkTargetFrame->Release();
if (pTargetFrameSrc) pTargetFrameSrc->Release();
if (pTargetHlinkFrame) { pHlframe->Release(); pHlframe = pTargetHlinkFrame; } } }
if(!fAccessAllowed) { hr = E_ACCESSDENIED; goto exit; }
hr = pHlframe->Navigate(grfHLNF, pBndctx, pBscb, pLink); } else hr = E_FAIL;
if ( FAILED(hr) && pHlframe) { // Navigation through pHlframe failed, we will retrieve the
// corresponding IWebBrowserApp interface and try navigation.
if (pExplorer) { pExplorer->Release(); pExplorer = 0; } pHlframe->QueryInterface(IID_IWebBrowserApp, (void **)&pExplorer); }
if (FAILED(hr) && pExplorer && pmkTarget) { LPOLESTR szTarget; hr = pmkTarget->GetDisplayName(pBndctx,NULL,&szTarget);
if (SUCCEEDED(hr)) hr = pExplorer->Navigate( szTarget, 0, 0, 0, 0);
CoTaskMemFree(szTarget); }
// pExplorer->Navigate ShellExecute's
// We need not ShellExecute when pExplorer is not NULL
if (FAILED(hr) && !pExplorer && pmkTarget) { // Our container does not support hyperlinking. We need to shell execute
// explorer and go to the link.
// We need to translate the string to ANSI
CHAR szPath[MAX_PATH]; DWORD cchPath = MAX_PATH; LPOLESTR szTarget; pmkTarget->GetDisplayName(pBndctx,NULL,&szTarget); int cbStr = 2 * wclen(szTarget + 1); char *pszAnsiTarget = new char[cbStr]; if( !pszAnsiTarget ) goto cleanup;
// ASSERT(pszAnsiTarget)
WideCharToMultiByte(CP_ACP, 0, szTarget, -1, pszAnsiTarget, cbStr, 0, 0); pszAnsiTarget[cbStr-1] = '\0';
if(SUCCEEDED(PathCreateFromUrl(pszAnsiTarget, szPath, &cchPath, 0))) { HANDLE hFile = CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hFile) { CloseHandle(hFile); hr = DoUrlShellExecuteA(szPath); } else hr = E_FAIL; } else { hr = DoUrlShellExecuteA((LPCTSTR)pszAnsiTarget); } cleanup: if( pszAnsiTarget ) delete[] pszAnsiTarget;
CoTaskMemFree(szTarget); }
exit:
if (pExplorer) pExplorer->Release(); if (pHlframe) pHlframe->Release(); if (pLink) pLink->Release(); if(pszUrl) CoTaskMemFree(pszUrl);
return( hr ); }
//////////////////////////////////////////////////////////////////////////
//
// HlinkGoBack
//
STDAPI HlinkGoBack(IUnknown *pUnk) { IWebBrowserApp * pExplorer = 0; IHlinkFrame * pHlframe = 0; HRESULT hr;
hr = GetAnInterface ( pUnk, IID_IWebBrowserApp, (void**)&pExplorer, TRUE, IID_IHlinkFrame, IID_IHlinkFrame, (void**)&pHlframe );
if ( SUCCEEDED(hr) ) hr = pHlframe->Navigate(HLNF_NAVIGATINGBACK, 0, 0, 0);
if ( FAILED(hr) && pExplorer ) hr = pExplorer->GoBack();
if ( pExplorer ) pExplorer->Release();
if ( pHlframe ) pHlframe->Release();
return (hr); }
//////////////////////////////////////////////////////////////////////////
//
// HlinkGoForward
//
//////////////////////////////////////////////////////////////////////////
STDAPI HlinkGoForward(IUnknown *pUnk) { IWebBrowserApp * pExplorer = 0; IHlinkFrame * pHlframe = 0; HRESULT hr;
hr = GetAnInterface ( pUnk, IID_IWebBrowserApp, (void**)&pExplorer, TRUE, IID_IHlinkFrame, IID_IHlinkFrame, (void**)&pHlframe );
if (SUCCEEDED(hr)) hr = pHlframe->Navigate(HLNF_NAVIGATINGFORWARD, 0, 0, 0);
if ( FAILED(hr) && pExplorer ) hr = pExplorer->GoForward();
if ( pExplorer ) pExplorer->Release();
if ( pHlframe ) pHlframe->Release();
return (hr); }
//////////////////////////////////////////////////////////////////////////
//
// HlinkNavigateString
//
//////////////////////////////////////////////////////////////////////////
STDAPI HlinkNavigateString(IUnknown *pUnk, LPCWSTR szTarget) { HRESULT hr;
hr = HlinkSimpleNavigateToString(szTarget, NULL, NULL, pUnk, NULL, 0, 0, 0);
return (hr); }
//////////////////////////////////////////////////////////////////////////
//
// HlinkNavigateMoniker
//
//////////////////////////////////////////////////////////////////////////
STDAPI HlinkNavigateMoniker(IUnknown *pUnk, IMoniker *pmkTarget) { HRESULT hr;
hr = HlinkSimpleNavigateToMoniker(pmkTarget, NULL, NULL, pUnk, NULL,NULL, 0, 0);
return (hr); }
|