1032 lines
20 KiB
C++
1032 lines
20 KiB
C++
|
|
#ifndef _TAPI_OBJECT_WITH_SITE_H_
|
|
#define _TAPI_OBJECT_WITH_SITE_H_
|
|
|
|
|
|
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ObjectWithSite.h
|
|
|
|
Abstract:
|
|
|
|
The implementation of IObjectWithSite interface that allows
|
|
for per-page persistent data to be stored in registry or as
|
|
a cookie.
|
|
|
|
--*/
|
|
|
|
|
|
#include <Mshtml.h>
|
|
#include <Wininet.h>
|
|
|
|
|
|
//
|
|
// this url is used to construct the URL for cookies -- a security measure
|
|
// so a script applet cannot drop a cookie with the same name and data
|
|
// and fool us into thinking it is our cookie
|
|
//
|
|
|
|
static const TCHAR gszHardCodedURL[] = _T("http://www.microsoft.com/");
|
|
|
|
//
|
|
// the expiration date is needed to make the cookie persistent
|
|
//
|
|
|
|
static const TCHAR gszCookieData[] =
|
|
_T("6; expires = Sat, 12-Sep-2099 00:00:00 GMT");
|
|
|
|
|
|
|
|
//
|
|
// dummy suffix to be appended to the url string
|
|
//
|
|
|
|
static const TCHAR gszURLSuffix[] =
|
|
_T("/url");
|
|
|
|
class CObjectWithSite : public IObjectWithSite
|
|
{
|
|
|
|
public:
|
|
|
|
//
|
|
// current validation level. used to determine whether the page is safe,
|
|
// unsafe, or whether information from the user is needed
|
|
//
|
|
|
|
enum EnValidation { VALIDATED_SAFE, VALIDATED_SAFE_PERMANENT, VALIDATED_UNSAFE, UNVALIDATED };
|
|
|
|
|
|
public:
|
|
|
|
|
|
//
|
|
// store type
|
|
//
|
|
|
|
enum EnMechanism { COOKIES, REGISTRY };
|
|
|
|
|
|
CObjectWithSite(TCHAR const *pszStorageName)
|
|
:m_pszURL(NULL),
|
|
m_dwSecurityZone(URLZONE_UNTRUSTED),
|
|
m_pUnkSite(NULL),
|
|
m_pszStorageName(NULL)
|
|
{
|
|
SetStorageName(pszStorageName);
|
|
}
|
|
|
|
|
|
~CObjectWithSite()
|
|
{
|
|
|
|
if (m_pszURL)
|
|
{
|
|
delete m_pszURL;
|
|
|
|
m_pszURL = NULL;
|
|
}
|
|
|
|
|
|
if (m_pUnkSite)
|
|
{
|
|
m_pUnkSite->Release();
|
|
|
|
m_pUnkSite = NULL;
|
|
}
|
|
|
|
|
|
if (m_pszStorageName)
|
|
{
|
|
|
|
delete m_pszStorageName;
|
|
|
|
m_pszStorageName = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
////////////////////////////
|
|
//
|
|
// IObjectWithSite methods
|
|
|
|
|
|
STDMETHOD(SetSite)(IUnknown *pUnkSite)
|
|
{
|
|
|
|
|
|
if ((NULL != pUnkSite) && IsBadCodePtr((FARPROC)pUnkSite))
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
s_ObjectWithSiteCritSection.Lock();
|
|
|
|
//
|
|
// we are moving away from a page. this is the new page, as far as
|
|
// validation logic is concerned, so invalidate the current page
|
|
//
|
|
|
|
if (NULL == pUnkSite)
|
|
{
|
|
Validate(UNVALIDATED);
|
|
}
|
|
|
|
//
|
|
// Get URL and zone information for this site
|
|
//
|
|
|
|
//
|
|
// Note: we could delay this until we are actually asked for
|
|
// zone or URL, but this should not be a performance bottlneck
|
|
// in our case, so do this now to keep the code simple.
|
|
|
|
StoreURLAndZone(pUnkSite);
|
|
|
|
|
|
//
|
|
// replace the current site pointer with the new one
|
|
//
|
|
|
|
if (m_pUnkSite)
|
|
{
|
|
m_pUnkSite->Release();
|
|
}
|
|
|
|
|
|
m_pUnkSite = pUnkSite;
|
|
|
|
if (m_pUnkSite)
|
|
{
|
|
m_pUnkSite->AddRef();
|
|
}
|
|
|
|
s_ObjectWithSiteCritSection.Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHOD(GetSite)(REFIID riid, void **ppSite)
|
|
{
|
|
|
|
HRESULT hr = E_POINTER;
|
|
|
|
if (!IsBadWritePtr(ppSite, sizeof(void*)))
|
|
{
|
|
|
|
s_ObjectWithSiteCritSection.Lock();
|
|
|
|
*ppSite = NULL;
|
|
|
|
if (m_pUnkSite)
|
|
{
|
|
hr = m_pUnkSite->QueryInterface(riid, ppSite);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
s_ObjectWithSiteCritSection.Unlock();
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// has this page been validated?
|
|
//
|
|
|
|
EnValidation GetValidation()
|
|
{
|
|
|
|
//
|
|
// if the page has not been validated, see if it is marked as safe
|
|
//
|
|
|
|
s_ObjectWithSiteCritSection.Lock();
|
|
|
|
|
|
if (UNVALIDATED == s_enValidation)
|
|
{
|
|
if (IsPageSafe())
|
|
{
|
|
s_enValidation = VALIDATED_SAFE;
|
|
}
|
|
}
|
|
|
|
EnValidation enValidation = s_enValidation;
|
|
|
|
s_ObjectWithSiteCritSection.Unlock();
|
|
|
|
return enValidation;
|
|
}
|
|
|
|
|
|
//
|
|
// validate page as safe, unsafe, or reset validation
|
|
//
|
|
|
|
EnValidation Validate(EnValidation enNewValidation)
|
|
{
|
|
|
|
s_ObjectWithSiteCritSection.Lock();
|
|
|
|
|
|
//
|
|
// keep the validation before the change
|
|
//
|
|
|
|
EnValidation enOldValidation = s_enValidation;
|
|
|
|
|
|
//
|
|
// safe permanent is a special case:
|
|
//
|
|
|
|
if (VALIDATED_SAFE_PERMANENT == enNewValidation)
|
|
{
|
|
|
|
//
|
|
// set persistent safety flag and
|
|
// validate page as safe
|
|
//
|
|
|
|
MarkPageAsSafe();
|
|
enNewValidation = VALIDATED_SAFE;
|
|
}
|
|
|
|
|
|
//
|
|
// change our validation level for this page
|
|
//
|
|
|
|
s_enValidation = enNewValidation;
|
|
|
|
s_ObjectWithSiteCritSection.Unlock();
|
|
|
|
return enOldValidation;
|
|
}
|
|
|
|
|
|
|
|
BOOL IsIntranet()
|
|
{
|
|
|
|
//
|
|
// if anything other that intranet assume internet -- a less secure zone
|
|
//
|
|
|
|
s_ObjectWithSiteCritSection.Lock();
|
|
|
|
BOOL bIntranet = ( m_dwSecurityZone == URLZONE_INTRANET );
|
|
|
|
s_ObjectWithSiteCritSection.Unlock();
|
|
|
|
return bIntranet;
|
|
|
|
}
|
|
|
|
|
|
////////////////////
|
|
//
|
|
// HaveSite()
|
|
//
|
|
// return true if we have a site pointer
|
|
//
|
|
|
|
BOOL HaveSite()
|
|
{
|
|
|
|
s_ObjectWithSiteCritSection.Lock();
|
|
|
|
|
|
BOOL bHaveSite = FALSE;
|
|
|
|
if (NULL != m_pUnkSite)
|
|
{
|
|
bHaveSite = TRUE;
|
|
}
|
|
|
|
|
|
s_ObjectWithSiteCritSection.Unlock();
|
|
|
|
return bHaveSite;
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
////////////////////////////
|
|
//
|
|
// store the current url in the "safe" list
|
|
//
|
|
//
|
|
// not thread safe, called from inside a lock
|
|
//
|
|
|
|
HRESULT MarkPageAsSafe(EnMechanism enMechanism = COOKIES)
|
|
{
|
|
|
|
//
|
|
// if storage is invalid, the object has not been properly initialized
|
|
//
|
|
|
|
if (IsBadStringPtr(m_pszStorageName, -1))
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
//
|
|
// is we don't have the url, can't do what we are asked
|
|
//
|
|
|
|
if (NULL == m_pszURL)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// if url is garbage, we have a problem
|
|
//
|
|
|
|
if ( IsBadStringPtr(m_pszURL, -1) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
switch (enMechanism)
|
|
{
|
|
|
|
case REGISTRY:
|
|
|
|
hr = MarkPageSafeInRegistry(m_pszStorageName);
|
|
break;
|
|
|
|
case COOKIES:
|
|
|
|
hr = MarkPageSafeCookie(m_pszStorageName);
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Returns TRUE if the current page is in the safe list
|
|
//
|
|
|
|
//
|
|
// not thread safe, called from inside a lock
|
|
//
|
|
|
|
BOOL IsPageSafe( EnMechanism enMechanism = COOKIES )
|
|
{
|
|
|
|
//
|
|
// if we cannot get safety marking for whatever reason,
|
|
// return false
|
|
//
|
|
|
|
_ASSERTE(NULL != m_pszStorageName);
|
|
|
|
if ( IsBadStringPtr(m_pszURL, -1) ||
|
|
IsBadStringPtr(m_pszStorageName, -1))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bSafe = FALSE;
|
|
|
|
switch (enMechanism)
|
|
{
|
|
|
|
case REGISTRY:
|
|
|
|
bSafe = IsPageSafeRegistry(m_pszStorageName);
|
|
break;
|
|
|
|
case COOKIES:
|
|
|
|
bSafe = IsPageSafeCookie(m_pszStorageName);
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
return bSafe;
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
//
|
|
// this method is only called from the constructor. not thread safe.
|
|
//
|
|
|
|
HRESULT SetStorageName(TCHAR const *pszStorageName)
|
|
{
|
|
//
|
|
// calling this method invalidates the old storage name
|
|
// so deallocate it before doing anything else
|
|
//
|
|
|
|
if (NULL != m_pszStorageName)
|
|
{
|
|
delete m_pszStorageName;
|
|
m_pszStorageName = NULL;
|
|
}
|
|
|
|
//
|
|
// argument must be valid
|
|
//
|
|
|
|
if (IsBadStringPtr(pszStorageName, -1))
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// allocate buffer for the new storage name
|
|
//
|
|
|
|
size_t nSize = _tcsclen(pszStorageName) + 1;
|
|
|
|
m_pszStorageName = new TCHAR[nSize];
|
|
|
|
if (NULL == m_pszStorageName)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
_tcscpy(m_pszStorageName, pszStorageName);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// cache the url string and security zone id
|
|
// not thread safe must be called from inside a lock
|
|
//
|
|
|
|
HRESULT StoreURLAndZone(IUnknown *pUnkSite)
|
|
{
|
|
|
|
//
|
|
// reset zone and deallocate URL, if it exists
|
|
//
|
|
|
|
m_dwSecurityZone = URLZONE_UNTRUSTED;
|
|
|
|
if (m_pszURL)
|
|
{
|
|
delete m_pszURL;
|
|
m_pszURL = NULL;
|
|
}
|
|
|
|
if (pUnkSite == NULL)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// use pUnkSite to get to IHTMLDocument2, which will give us the URL
|
|
//
|
|
|
|
//
|
|
// these interfaces need to be released on exit.
|
|
// smart pointers will do exactly what we need
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
CComPtr<IOleClientSite> pSite;
|
|
|
|
if (FAILED(hr = pUnkSite->QueryInterface(IID_IOleClientSite, (LPVOID *) &pSite)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
|
|
CComPtr<IOleContainer> pOleCtr;
|
|
|
|
if (FAILED(hr = pSite->GetContainer(&pOleCtr)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
|
|
CComPtr<IHTMLDocument2> pDoc;
|
|
|
|
if (FAILED(hr = pOleCtr->QueryInterface(IID_IHTMLDocument2, (LPVOID *) &pDoc)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// get and keep the url
|
|
//
|
|
|
|
BSTR bstrURL;
|
|
|
|
if (FAILED(hr = pDoc->get_URL(&bstrURL)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
UINT nURLLength = SysStringLen(bstrURL) + 1;
|
|
|
|
_ASSERTE(NULL == m_pszURL);
|
|
|
|
m_pszURL = new TCHAR[nURLLength];
|
|
|
|
if (NULL == m_pszURL)
|
|
{
|
|
SysFreeString(bstrURL);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
|
|
#ifdef _UNICODE
|
|
|
|
_tcscpy(m_pszURL, bstrURL);
|
|
|
|
#else
|
|
int r = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
bstrURL,
|
|
nURLLength,
|
|
m_pszURL,
|
|
nURLLength,
|
|
NULL,
|
|
NULL );
|
|
|
|
if (0 == r)
|
|
{
|
|
SysFreeString(bstrURL);
|
|
|
|
delete m_pszURL;
|
|
m_pszURL = NULL;
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
//
|
|
// whatever follows '#' and '?' is "extra info" and is not considered
|
|
// to be a part of the actual URL by Internet(Set/Get)Coookie. Extra
|
|
// Info has no value for us -- so throw it out
|
|
//
|
|
|
|
TCHAR *psDelimiter = _tcsstr(m_pszURL, _T("#"));
|
|
|
|
if (NULL != psDelimiter)
|
|
{
|
|
*psDelimiter = _T('\0');
|
|
}
|
|
|
|
|
|
psDelimiter = _tcsstr(m_pszURL, _T("?"));
|
|
|
|
if (NULL != psDelimiter)
|
|
{
|
|
*psDelimiter = _T('\0');
|
|
}
|
|
|
|
|
|
//
|
|
// at this point we cached the URL
|
|
// now attempt to get the security zone. if we fail getting zone
|
|
// information still keep the url.
|
|
//
|
|
|
|
//
|
|
// Get security zone
|
|
//
|
|
|
|
CComPtr<IInternetSecurityManager> pSecMgr;
|
|
|
|
|
|
hr = CoCreateInstance(CLSID_InternetSecurityManager,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IInternetSecurityManager,
|
|
(LPVOID *) &pSecMgr);
|
|
|
|
if (pSecMgr == NULL)
|
|
{
|
|
SysFreeString(bstrURL);
|
|
return hr;
|
|
}
|
|
|
|
hr = pSecMgr->MapUrlToZone(bstrURL, &m_dwSecurityZone, 0);
|
|
|
|
|
|
//
|
|
// if failed, reset url to untrusted, just in case
|
|
//
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
m_dwSecurityZone = URLZONE_UNTRUSTED;
|
|
}
|
|
|
|
|
|
SysFreeString(bstrURL);
|
|
|
|
//
|
|
// we should have at least the URL at this point
|
|
//
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// drop a cookie for this page as an indicator that this page is safe
|
|
//
|
|
|
|
HRESULT MarkPageSafeCookie(TCHAR const *pszCookieName)
|
|
{
|
|
|
|
TCHAR *pszURL = NULL;
|
|
|
|
//
|
|
// generate the url for the cookie
|
|
// remember to delete the returned string
|
|
//
|
|
|
|
GenerateURLString(&pszURL);
|
|
|
|
if (NULL == pszURL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
BOOL bReturn = InternetSetCookie(pszURL, pszCookieName, gszCookieData);
|
|
|
|
delete pszURL;
|
|
|
|
return (bReturn)?S_OK:E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// presence of a cookie for this page is an indicator that it's safe
|
|
// returns TRUE if the cookie exists. FALSE otherwise
|
|
//
|
|
|
|
BOOL IsPageSafeCookie(TCHAR const *pszCookieName)
|
|
{
|
|
|
|
//
|
|
// m_pszURL was checked by the calling function and the object
|
|
// is protected. m_pszURL should never be null here.
|
|
//
|
|
|
|
_ASSERTE(m_pszURL);
|
|
|
|
//
|
|
// same goes for pszCookieName
|
|
//
|
|
|
|
_ASSERTE(pszCookieName);
|
|
|
|
|
|
BOOL bReturn = FALSE;
|
|
|
|
BOOL bFinalReturn = FALSE;
|
|
|
|
|
|
TCHAR *pszURL = NULL;
|
|
|
|
// remember to delete the returned string
|
|
|
|
GenerateURLString(&pszURL);
|
|
|
|
if (NULL == pszURL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// see how much data the cookie contains
|
|
//
|
|
|
|
DWORD dwCookieDataSize = 0;
|
|
|
|
//
|
|
// assuming the return code is TRUE if the method succeeds in getting
|
|
// get the buffer size. the current documentation is not 100% clear
|
|
//
|
|
|
|
bReturn = InternetGetCookie(pszURL, pszCookieName, NULL, &dwCookieDataSize);
|
|
|
|
|
|
//
|
|
// dwCookieDataSize has the length of cookie data
|
|
//
|
|
|
|
if ( bReturn && dwCookieDataSize )
|
|
{
|
|
|
|
//
|
|
// allocate the buffer for cookie data
|
|
//
|
|
|
|
TCHAR *pCookieDataBuffer = new TCHAR[dwCookieDataSize];
|
|
|
|
if (NULL != pCookieDataBuffer)
|
|
{
|
|
//
|
|
// all cookies for this page are returned in cookie data,
|
|
// the name argument is ignored
|
|
//
|
|
|
|
bReturn = InternetGetCookie(pszURL,
|
|
pszCookieName,
|
|
pCookieDataBuffer,
|
|
&dwCookieDataSize);
|
|
|
|
|
|
//
|
|
// is succeeded, parse cookie data buffer to see if the
|
|
// cookie we are looking for is there
|
|
//
|
|
|
|
if ( bReturn && ( NULL != _tcsstr(pCookieDataBuffer, pszCookieName) ) )
|
|
{
|
|
|
|
bFinalReturn = TRUE;
|
|
}
|
|
|
|
|
|
delete pCookieDataBuffer;
|
|
pCookieDataBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
delete pszURL;
|
|
pszURL = NULL;
|
|
|
|
return bFinalReturn;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// add a registry entry for this page as an indicator that the page is safe
|
|
// returns TRUE if the registry entry exists
|
|
//
|
|
|
|
HRESULT MarkPageSafeInRegistry(TCHAR const *szRegistryKeyName)
|
|
{
|
|
|
|
_ASSERTE(m_pszURL);
|
|
|
|
//
|
|
// open the registry key. create if not there
|
|
//
|
|
|
|
DWORD dwDisposition = 0;
|
|
HKEY hKey = 0;
|
|
|
|
LONG rc = RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
szRegistryKeyName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition);
|
|
|
|
if ( rc == ERROR_SUCCESS )
|
|
{
|
|
DWORD dwData = 0;
|
|
|
|
//
|
|
// add the current URL to the registry
|
|
//
|
|
|
|
rc = RegSetValueEx(hKey,
|
|
m_pszURL,
|
|
0,
|
|
REG_DWORD,
|
|
(BYTE*)&dwData,
|
|
sizeof(DWORD));
|
|
|
|
}
|
|
|
|
if (hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
hKey = NULL;
|
|
|
|
if (rc == ERROR_SUCCESS )
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// presence of a registry entry for this page indicates that the
|
|
// page is safe
|
|
//
|
|
|
|
BOOL IsPageSafeRegistry(TCHAR const *szRegistryKeyName)
|
|
{
|
|
|
|
DWORD dwDisposition = 0;
|
|
HKEY hKey = 0;
|
|
|
|
//
|
|
// the default is not safe
|
|
//
|
|
|
|
if (NULL == m_pszURL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// open the registry key where the page information is kept.
|
|
// create if not there
|
|
//
|
|
|
|
LONG rc = RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
szRegistryKeyName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_CREATE_SUB_KEY | KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition);
|
|
|
|
if ( rc == ERROR_SUCCESS )
|
|
{
|
|
|
|
|
|
DWORD dwDataType = 0;
|
|
DWORD dwDataSize = 0;
|
|
|
|
//
|
|
// read the setting for the current page.
|
|
// Note: we don't need the actual data, we just
|
|
// want to see if the value exists
|
|
//
|
|
|
|
rc = RegQueryValueEx(hKey,
|
|
m_pszURL,
|
|
0,
|
|
&dwDataType,
|
|
NULL,
|
|
&dwDataSize
|
|
);
|
|
}
|
|
|
|
if (hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
hKey = NULL;
|
|
|
|
return (rc == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
//
|
|
// build the URL string based on the hardcoded URL and
|
|
// the actual URL for this page.
|
|
// we are hoping that the striing will be unique (per page) and no
|
|
// mischevious scripting app can drop a cookie corresponding to
|
|
// this URL
|
|
//
|
|
// Note: if the implementation of of Internet(Set/Get)Cookie changes
|
|
// to have stricter validation for the URL string, this technique will
|
|
// not work
|
|
//
|
|
|
|
void GenerateURLString(TCHAR **ppszURL)
|
|
{
|
|
|
|
//
|
|
// the precondition is that m_pszURL exists
|
|
//
|
|
|
|
_ASSERT(NULL != m_pszURL);
|
|
|
|
*ppszURL = NULL;
|
|
|
|
//
|
|
// alias the char pointer pointer to by *pszURL.
|
|
// so it is easier to refer to.
|
|
//
|
|
|
|
TCHAR* &pszURL = *ppszURL;
|
|
|
|
//
|
|
// allocate memory for concatenated string
|
|
//
|
|
|
|
pszURL = new TCHAR[_tcslen(gszHardCodedURL) +
|
|
_tcslen(m_pszURL) +
|
|
_tcslen(gszURLSuffix) + 1];
|
|
|
|
// concatenate
|
|
|
|
if (pszURL)
|
|
{
|
|
*pszURL = _T('\0');
|
|
|
|
_tcscat(pszURL, gszHardCodedURL);
|
|
_tcscat(pszURL, m_pszURL);
|
|
_tcscat(pszURL, gszURLSuffix);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
//
|
|
// cached URL string
|
|
//
|
|
|
|
TCHAR *m_pszURL;
|
|
|
|
|
|
//
|
|
// cached security zone
|
|
//
|
|
|
|
DWORD m_dwSecurityZone;
|
|
|
|
|
|
//
|
|
// site for IObjectWithSite
|
|
//
|
|
|
|
IUnknown *m_pUnkSite;
|
|
|
|
//
|
|
// thread safety
|
|
//
|
|
|
|
static CComAutoCriticalSection s_ObjectWithSiteCritSection;
|
|
|
|
//
|
|
// the status of the current page
|
|
//
|
|
|
|
static EnValidation s_enValidation;
|
|
|
|
//
|
|
// name of the persistent cookie or registry key
|
|
//
|
|
|
|
TCHAR *m_pszStorageName;
|
|
|
|
};
|
|
|
|
#endif // _TAPI_OBJECT_WITH_SITE_H_
|