You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2133 lines
55 KiB
2133 lines
55 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 2002.
|
|
//
|
|
// File: ixsso.cxx
|
|
//
|
|
// Contents: Query SSO class
|
|
//
|
|
// History: 25 Oct 1996 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.cxx"
|
|
#pragma hdrstop
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Include Files
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// debugging macros
|
|
#include "ssodebug.hxx"
|
|
|
|
DECLARE_INFOLEVEL( ixsso )
|
|
|
|
// class declaration
|
|
#include "stdcf.hxx"
|
|
#include "ixsso.hxx"
|
|
#include <string.hxx>
|
|
#include <codepage.hxx>
|
|
|
|
#include <initguid.h>
|
|
#include <adoid.h> // ADO CLSID and IID definitions
|
|
#include <adoint.h> // ADO interface definition
|
|
|
|
const WCHAR * pwcDefaultDialect = L"2";
|
|
|
|
extern WCHAR * g_pwszProgIdQuery;
|
|
|
|
#if CIDBG
|
|
extern ULONG g_ulObjCount;
|
|
extern LONG g_lQryCount;
|
|
#endif // CIDBG
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::CixssoQuery - public
|
|
//
|
|
// Synopsis: Constructor of CixssoQuery
|
|
//
|
|
// Arguments: [pitlb] - pointer to ITypeLib for ixsso
|
|
// [pIAdoRecordsetCF] - pointer to the class factory for ADO
|
|
// recordsets
|
|
//
|
|
// History: 06 Nov 1996 Alanw Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CixssoQuery::CixssoQuery( ITypeLib * pitlb,
|
|
IClassFactory * pIAdoRecordsetCF,
|
|
BOOL fAdoV15,
|
|
const CLSID & ssoClsid) :
|
|
_pwszRestriction( 0 ),
|
|
_pwszSort( 0 ),
|
|
_pwszGroup( 0 ),
|
|
_pwszColumns( 0 ),
|
|
_pwszCatalog( 0 ),
|
|
_pwszDialect( 0 ),
|
|
_cScopes( 0 ),
|
|
_apwszScope( 0 ),
|
|
_aulDepth( 0 ),
|
|
|
|
_fAllowEnumeration( FALSE ),
|
|
_dwOptimizeFlags( eOptHitCount | eOptRecall ),
|
|
_maxResults( 0 ),
|
|
_cFirstRows( 0 ),
|
|
_iResourceFactor( 0 ),
|
|
|
|
_StartHit( 0 ),
|
|
|
|
_lcid( GetSystemDefaultLCID() ),
|
|
_ulCodepage( CP_ACP ),
|
|
_err( IID_IixssoQuery ),
|
|
_pIAdoRecordsetCF( pIAdoRecordsetCF ),
|
|
_fAdoV15( fAdoV15 ),
|
|
_pIRowset( 0 ),
|
|
_pIRowsetQueryStatus( 0 ),
|
|
_fSequential( FALSE ),
|
|
_PropertyList( _ulCodepage )
|
|
{
|
|
_cRef = 1;
|
|
Win4Assert(g_pTheGlobalIXSSOVariables);
|
|
|
|
|
|
SCODE sc;
|
|
|
|
if ( CLSID_CissoQueryEx == ssoClsid )
|
|
{
|
|
_err = IID_IixssoQueryEx;
|
|
sc = pitlb->GetTypeInfoOfGuid( IID_IixssoQueryEx, &_ptinfo );
|
|
}
|
|
else if ( CLSID_CissoQuery == ssoClsid )
|
|
{
|
|
sc = pitlb->GetTypeInfoOfGuid( IID_IixssoQuery, &_ptinfo );
|
|
}
|
|
else
|
|
THROW( CException(E_INVALIDARG));
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
ixssoDebugOut(( DEB_ERROR, "GetTypeInfoOfGuid failed (%x)\n", sc ));
|
|
Win4Assert(SUCCEEDED(sc));
|
|
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
#if CIDBG
|
|
LONG cAdoRecordsetRefs =
|
|
#endif // CIDBG
|
|
_pIAdoRecordsetCF->AddRef();
|
|
|
|
XInterface<IColumnMapper> xColumnMapper;
|
|
ISimpleCommandCreator *pCmdCreator = 0;
|
|
|
|
pCmdCreator = g_pTheGlobalIXSSOVariables->xCmdCreator.GetPointer();
|
|
g_pTheGlobalIXSSOVariables->xColumnMapperCreator->GetColumnMapper(
|
|
LOCAL_MACHINE,
|
|
INDEX_SERVER_DEFAULT_CAT,
|
|
(IColumnMapper **)xColumnMapper.GetQIPointer());
|
|
|
|
if (0 == pCmdCreator)
|
|
THROW(CException(REGDB_E_CLASSNOTREG));
|
|
|
|
_xCmdCreator.Set(pCmdCreator);
|
|
#if CIDBG
|
|
LONG cCmdCreatorRefs =
|
|
#endif // CIDBG
|
|
pCmdCreator->AddRef();
|
|
Win4Assert(xColumnMapper.GetPointer());
|
|
_PropertyList.SetDefaultList(xColumnMapper.GetPointer());
|
|
|
|
INC_OBJECT_COUNT();
|
|
|
|
ixssoDebugOut((DEB_REFCOUNTS, "[DLL]: Create query: refcounts: glob %d qry %d AdoRSCF %d CmdCtor %d\n",
|
|
g_ulObjCount,
|
|
g_lQryCount,
|
|
cAdoRecordsetRefs,
|
|
cCmdCreatorRefs ));
|
|
|
|
}
|
|
|
|
CixssoQuery::~CixssoQuery( )
|
|
{
|
|
Reset();
|
|
|
|
if (_ptinfo)
|
|
_ptinfo->Release();
|
|
|
|
#if CIDBG
|
|
LONG cAdoRecordsetRefs = -2;
|
|
#endif // CIDBG
|
|
if (_pIAdoRecordsetCF)
|
|
#if CIDBG
|
|
cAdoRecordsetRefs =
|
|
#endif // CIDBG
|
|
_pIAdoRecordsetCF->Release();
|
|
|
|
DEC_OBJECT_COUNT();
|
|
|
|
#if CIDBG
|
|
LONG l = InterlockedDecrement( &g_lQryCount );
|
|
Win4Assert( l >= 0 );
|
|
#endif //CIDBG
|
|
|
|
ixssoDebugOut((DEB_REFCOUNTS, "[DLL]: Delete query: refcounts: glob %d qry %d AdoRSCF %d\n",
|
|
g_ulObjCount,
|
|
g_lQryCount,
|
|
cAdoRecordsetRefs ));
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::Reset - public
|
|
//
|
|
// Synopsis: Clear any internal state in the object
|
|
//
|
|
// Arguments: - none -
|
|
//
|
|
// Notes: Doesn't currently clear lcid or property list.
|
|
//
|
|
// History: 05 Mar 1997 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CixssoQuery::Reset(void)
|
|
{
|
|
_maxResults = 0;
|
|
_cFirstRows = 0;
|
|
_cScopes = 0;
|
|
_fAllowEnumeration = FALSE;
|
|
_dwOptimizeFlags = eOptHitCount | eOptRecall;
|
|
|
|
if (_pIRowset)
|
|
{
|
|
_pIRowset->Release();
|
|
_pIRowset = 0;
|
|
}
|
|
|
|
if (_pIRowsetQueryStatus)
|
|
{
|
|
_pIRowsetQueryStatus->Release();
|
|
_pIRowsetQueryStatus = 0;
|
|
}
|
|
|
|
delete _pwszRestriction;
|
|
_pwszRestriction = 0;
|
|
|
|
delete _pwszSort;
|
|
_pwszSort = 0;
|
|
|
|
delete _pwszGroup;
|
|
_pwszGroup = 0;
|
|
|
|
delete _pwszColumns;
|
|
_pwszColumns = 0;
|
|
|
|
delete _pwszCatalog;
|
|
_pwszCatalog = 0;
|
|
|
|
delete _pwszDialect;
|
|
_pwszDialect = 0;
|
|
|
|
// Unneeded since cScopes is set to zero.
|
|
// _apwszScope.Clear();
|
|
|
|
_StartHit.Destroy();
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// ASP Methods
|
|
//
|
|
|
|
#include <asp/asptlb.h>
|
|
|
|
STDMETHODIMP CixssoQuery::OnStartPage (IUnknown* pUnk)
|
|
{
|
|
if ( 0 == pUnk )
|
|
return E_INVALIDARG;
|
|
|
|
SCODE sc = S_OK;
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
// reset the error structure
|
|
_err.Reset();
|
|
|
|
SCODE sc;
|
|
IScriptingContext *piContext = 0;
|
|
IRequest* piRequest = 0;
|
|
IRequestDictionary *piRequestDict = 0;
|
|
|
|
ISessionObject* piSession = 0;
|
|
|
|
do
|
|
{
|
|
//Get IScriptingContext Interface
|
|
sc = pUnk->QueryInterface(IID_IScriptingContext, (void**)&piContext);
|
|
if (FAILED(sc))
|
|
break;
|
|
|
|
//Get Request Object Pointer
|
|
sc = piContext->get_Request(&piRequest);
|
|
if (FAILED(sc))
|
|
break;
|
|
|
|
//Get ServerVariables Pointer
|
|
sc = piRequest->get_ServerVariables(&piRequestDict);
|
|
if (FAILED(sc))
|
|
break;
|
|
|
|
VARIANT vtOut;
|
|
VariantInit(&vtOut);
|
|
|
|
//
|
|
// Get the HTTP_ACCEPT_LANGUAGE Item. Don't need to check the
|
|
// return code; use a default value for the locale ID
|
|
//
|
|
piRequestDict->get_Item(g_vtAcceptLanguageHeader, &vtOut);
|
|
|
|
//
|
|
//vtOut Contains an IDispatch Pointer. To fetch the value
|
|
//for HTTP_ACCEPT_LANGUAGE you must get the Default Value for the
|
|
//Object stored in vtOut using VariantChangeType.
|
|
//
|
|
if (V_VT(&vtOut) != VT_BSTR)
|
|
VariantChangeType(&vtOut, &vtOut, 0, VT_BSTR);
|
|
|
|
if (V_VT(&vtOut) == VT_BSTR)
|
|
{
|
|
ixssoDebugOut((DEB_TRACE, "OnStartPage: HTTP_ACCEPT_LANGUAGE = %ws\n",
|
|
V_BSTR(&vtOut) ));
|
|
SetLocaleString(V_BSTR(&vtOut));
|
|
}
|
|
else
|
|
{
|
|
ixssoDebugOut(( DEB_TRACE,
|
|
"OnStartPage: HTTP_ACCEPT_LANGAUGE was not set in ServerVariables; using lcid=0x%x\n",
|
|
GetSystemDefaultLCID() ));
|
|
|
|
put_LocaleID( GetSystemDefaultLCID() );
|
|
}
|
|
VariantClear(&vtOut);
|
|
|
|
_ulCodepage = LocaleToCodepage( _lcid );
|
|
|
|
//Get Session Object Pointer
|
|
sc = piContext->get_Session(&piSession);
|
|
if (FAILED(sc))
|
|
{
|
|
// Don't fail request if sessions are not enabled. This specific
|
|
// error is given when AspAllowSessionState is zero.
|
|
if (TYPE_E_ELEMENTNOTFOUND == sc)
|
|
sc = S_OK;
|
|
|
|
break;
|
|
}
|
|
|
|
LONG cp = CP_ACP;
|
|
sc = piSession->get_CodePage( &cp );
|
|
if (FAILED(sc))
|
|
{
|
|
// sc = S_OK;
|
|
break;
|
|
}
|
|
|
|
if (cp != CP_ACP)
|
|
_ulCodepage = cp;
|
|
|
|
} while (FALSE);
|
|
|
|
if (piSession)
|
|
piSession->Release();
|
|
|
|
if (piRequestDict)
|
|
piRequestDict->Release();
|
|
if (piRequest)
|
|
piRequest->Release();
|
|
if (piContext)
|
|
piContext->Release();
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
}
|
|
END_CATCH
|
|
|
|
return sc;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CixssoQuery IUnknown Methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::QueryInterface(REFIID iid, void * * ppv)
|
|
{
|
|
*ppv = 0;
|
|
|
|
if (iid == IID_IUnknown || iid == IID_IDispatch)
|
|
*ppv = (IDispatch *) this;
|
|
else if (iid == IID_ISupportErrorInfo )
|
|
*ppv = (ISupportErrorInfo *) this;
|
|
else if (iid == IID_IixssoQuery )
|
|
*ppv = (IixssoQuery *) this;
|
|
else if (iid == IID_IixssoQueryPrivate )
|
|
*ppv = (IixssoQueryPrivate *) this;
|
|
else if ( iid == IID_IixssoQueryEx )
|
|
*ppv = (IixssoQueryEx *) this;
|
|
#if 0
|
|
else if ( iid == IID_IObjectSafety )
|
|
*ppv = (IObjectSafety *) this;
|
|
#endif
|
|
else if ( iid == IID_IObjectWithSite )
|
|
*ppv = (IObjectWithSite *) this;
|
|
else
|
|
return E_NOINTERFACE;
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CixssoQuery::AddRef(void)
|
|
{
|
|
return InterlockedIncrement((long *)&_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CixssoQuery::Release(void)
|
|
{
|
|
ULONG uTmp = InterlockedDecrement((long *)&_cRef);
|
|
if (uTmp == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return uTmp;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CixssoQuery IDispatch Methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::GetTypeInfoCount(UINT * pctinfo)
|
|
{
|
|
*pctinfo = 1;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::GetTypeInfo(
|
|
UINT itinfo,
|
|
LCID lcid,
|
|
ITypeInfo * * pptinfo)
|
|
{
|
|
_ptinfo->AddRef();
|
|
*pptinfo = _ptinfo;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::GetIDsOfNames(
|
|
REFIID riid,
|
|
OLECHAR * * rgszNames,
|
|
UINT cNames,
|
|
LCID lcid,
|
|
DISPID * rgdispid)
|
|
{
|
|
return DispGetIDsOfNames(_ptinfo, rgszNames, cNames, rgdispid);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::Invoke(
|
|
DISPID dispidMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
WORD wFlags,
|
|
DISPPARAMS * pParams,
|
|
VARIANT * pvarResult,
|
|
EXCEPINFO * pexcepinfo,
|
|
UINT * puArgErr)
|
|
{
|
|
ixssoDebugOut((DEB_IDISPATCH, "Invoking method dispid=%d wFlags=%d\n",
|
|
dispidMember, wFlags ));
|
|
|
|
_err.Reset();
|
|
|
|
SCODE sc = DispInvoke( this, _ptinfo,
|
|
dispidMember, wFlags, pParams,
|
|
pvarResult, pexcepinfo, puArgErr );
|
|
|
|
if ( _err.IsError() )
|
|
sc = DISP_E_EXCEPTION;
|
|
|
|
return sc;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::InterfaceSupportsErrorInfo(
|
|
REFIID riid)
|
|
{
|
|
if (IID_IixssoQueryEx == riid || IID_IixssoQuery == riid )
|
|
return S_OK;
|
|
else
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CixssoQuery property Methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::CopyWstrToBstr - private inline
|
|
//
|
|
// Synopsis: Copies a Unicode string to a BSTR
|
|
//
|
|
// Arguments: [pbstr] - destination BSTR
|
|
// [pwstr] - string to be copied
|
|
//
|
|
// Returns: SCODE - status return
|
|
//
|
|
// History: 25 Oct 1996 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline
|
|
SCODE CixssoQuery::CopyWstrToBstr( BSTR * pbstr, WCHAR const * pwstr )
|
|
{
|
|
*pbstr = 0;
|
|
if (pwstr)
|
|
{
|
|
*pbstr = SysAllocString( pwstr );
|
|
if (0 == *pbstr)
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::CopyBstrToWstr - private inline
|
|
//
|
|
// Synopsis: Copies a BSTR to a Unicode string
|
|
//
|
|
// Arguments: [bstr] - string to be copied
|
|
// [rwstr] - destination string
|
|
//
|
|
// Returns: SCODE - status return
|
|
//
|
|
// History: 25 Oct 1996 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline
|
|
SCODE CixssoQuery::CopyBstrToWstr( BSTR bstr, LPWSTR & rwstr )
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
if (rwstr)
|
|
{
|
|
delete rwstr;
|
|
rwstr = 0;
|
|
}
|
|
|
|
if (bstr)
|
|
{
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
unsigned cch = SysStringLen( bstr )+1;
|
|
if (cch > 1)
|
|
{
|
|
rwstr = new WCHAR[ cch ];
|
|
RtlCopyMemory( rwstr, bstr, cch*sizeof (WCHAR) );
|
|
}
|
|
}
|
|
CATCH (CException, e)
|
|
{
|
|
if (e.GetErrorCode() == STATUS_ACCESS_VIOLATION)
|
|
sc = E_FAIL;
|
|
else
|
|
sc = E_OUTOFMEMORY;
|
|
|
|
SetError( sc, OLESTR("PutProperty") );
|
|
}
|
|
END_CATCH
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::CopyBstrToWstr - private inline
|
|
//
|
|
// Synopsis: Copies a BSTR to a Unicode string
|
|
//
|
|
// Arguments: [bstr] - string to be copied
|
|
// [apstr] - destination string array
|
|
// [i] - string array index
|
|
//
|
|
// Returns: SCODE - status return
|
|
//
|
|
// History: 25 Oct 1996 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline
|
|
SCODE CixssoQuery::CopyBstrToWstrArray( BSTR bstr,
|
|
CDynArray<WCHAR> &apstr,
|
|
unsigned i )
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
if (bstr)
|
|
{
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
unsigned cch = SysStringLen( bstr )+1;
|
|
if (cch > 1)
|
|
{
|
|
XArray<WCHAR> wstr( cch );
|
|
|
|
RtlCopyMemory( wstr.GetPointer(), bstr, cch*sizeof (WCHAR) );
|
|
delete apstr.Acquire( i );
|
|
apstr.Add( wstr.GetPointer(), i );
|
|
wstr.Acquire();
|
|
}
|
|
else
|
|
apstr.Add( 0, i );
|
|
}
|
|
CATCH (CException, e)
|
|
{
|
|
if (e.GetErrorCode() == STATUS_ACCESS_VIOLATION)
|
|
sc = E_FAIL;
|
|
else
|
|
sc = E_OUTOFMEMORY;
|
|
|
|
SetError( sc, OLESTR("CopyBstrToWstrArray") );
|
|
}
|
|
END_CATCH
|
|
}
|
|
else
|
|
apstr.Add( 0, i );
|
|
|
|
return sc;
|
|
}
|
|
|
|
inline
|
|
SCODE CixssoQuery::GetBoolProperty( VARIANT_BOOL * pfVal, BOOL fMemberVal )
|
|
{
|
|
*pfVal = fMemberVal ? VARIANT_TRUE : VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
inline
|
|
SCODE CixssoQuery::PutBoolProperty( VARIANT_BOOL fInputVal, BOOL & fMemberVal )
|
|
{
|
|
fMemberVal = (fInputVal == VARIANT_TRUE) ? TRUE : FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CixssoQuery read-write properties
|
|
//-----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_Query(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
return CopyWstrToBstr( pstr, _pwszRestriction );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_Query(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
return CopyBstrToWstr( str, _pwszRestriction );
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_GroupBy(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
#if IXSSO_CATEGORIZE == 1
|
|
return CopyWstrToBstr( pstr, _pwszGroup );
|
|
#else // IXSSO_CATEGORIZE
|
|
return E_NOTIMPL;
|
|
#endif // IXSSO_CATEGORIZE
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_GroupBy(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
#if IXSSO_CATEGORIZE == 1
|
|
return CopyBstrToWstr( str, _pwszGroup );
|
|
#else // IXSSO_CATEGORIZE
|
|
return E_NOTIMPL;
|
|
#endif // IXSSO_CATEGORIZE
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_Columns(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
return CopyWstrToBstr( pstr, _pwszColumns );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_Columns(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
return CopyBstrToWstr( str, _pwszColumns );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_LocaleID(LONG * plVal)
|
|
{
|
|
_err.Reset();
|
|
*plVal = _lcid;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_LocaleID(LONG lVal)
|
|
{
|
|
_err.Reset();
|
|
_lcid = lVal;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_CodePage(LONG * plVal)
|
|
{
|
|
_err.Reset();
|
|
*plVal = _ulCodepage;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_CodePage(LONG lVal)
|
|
{
|
|
_err.Reset();
|
|
if (0 == IsValidCodePage( lVal ) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
_ulCodepage = lVal;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_SortBy(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
return CopyWstrToBstr( pstr, _pwszSort );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_SortBy(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
return CopyBstrToWstr( str, _pwszSort );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_CiScope(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
if (_cScopes > 1)
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("get CiScope") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
return CopyWstrToBstr( pstr, _apwszScope.Get(0) );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_CiScope(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
if (_cScopes > 1)
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("set CiScope") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
SCODE sc = CopyBstrToWstrArray( str, _apwszScope, 0 );
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
_cScopes = (_apwszScope[0] == 0) ? 0 : 1;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_CiFlags(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
if (_cScopes > 1)
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("get CiFlags") );
|
|
return _err.GetError();
|
|
}
|
|
ULONG ulDepth = QUERY_DEEP;
|
|
if (_aulDepth.Count() > 0)
|
|
ulDepth = _aulDepth[0];
|
|
WCHAR * pwszDepth = ulDepth & QUERY_DEEP ? L"DEEP" : L"SHALLOW";
|
|
|
|
return CopyWstrToBstr( pstr, pwszDepth );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_CiFlags(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
SCODE sc = S_OK;
|
|
|
|
if (_cScopes > 1)
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("set CiFlags") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
ULONG ulDepth = ParseCiDepthFlag( str );
|
|
_aulDepth[0] = ulDepth;
|
|
}
|
|
CATCH( CIxssoException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
SetError( sc, OLESTR("set CiFlags"), eIxssoError );
|
|
}
|
|
AND_CATCH( CException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
SetError( sc, OLESTR("set CiFlags") );
|
|
}
|
|
END_CATCH
|
|
|
|
return sc;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_Catalog(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
return CopyWstrToBstr( pstr, _pwszCatalog );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_Catalog(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
return CopyBstrToWstr( str, _pwszCatalog );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_Dialect(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
return CopyWstrToBstr( pstr,
|
|
_pwszDialect ? _pwszDialect : pwcDefaultDialect );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_Dialect(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
//
|
|
// Do some validation first
|
|
//
|
|
|
|
ULONG ulDialect = (ULONG) _wtoi( str );
|
|
if ( ulDialect < ISQLANG_V1 ||
|
|
ulDialect > ISQLANG_V2 )
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("set Dialect") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
return CopyBstrToWstr( str, _pwszDialect );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_OptimizeFor(BSTR * pstr)
|
|
{
|
|
_err.Reset();
|
|
|
|
WCHAR * pwszChoice = L"recall";
|
|
|
|
switch (_dwOptimizeFlags)
|
|
{
|
|
case 0:
|
|
pwszChoice = L"nohitcount";
|
|
break;
|
|
case eOptPerformance:
|
|
pwszChoice = L"performance,nohitcount";
|
|
break;
|
|
case eOptRecall:
|
|
pwszChoice = L"recall,nohitcount";
|
|
break;
|
|
case eOptPerformance|eOptHitCount:
|
|
pwszChoice = L"performance,hitcount";
|
|
break;
|
|
case eOptRecall|eOptHitCount:
|
|
pwszChoice = L"recall,hitcount";
|
|
break;
|
|
case eOptHitCount:
|
|
pwszChoice = L"hitcount";
|
|
break;
|
|
default:
|
|
Win4Assert( !"Invalid value in _dwOptimizeFlags!" );
|
|
}
|
|
|
|
return CopyWstrToBstr( pstr, pwszChoice );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_OptimizeFor(BSTR str)
|
|
{
|
|
_err.Reset();
|
|
|
|
DWORD eChoice;
|
|
SCODE sc = ParseOptimizeFor( str, eChoice );
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
_dwOptimizeFlags = eChoice;
|
|
return sc;
|
|
}
|
|
else
|
|
{
|
|
SetError( sc, OLESTR("set OptimizeFor") );
|
|
return _err.GetError();
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_AllowEnumeration(VARIANT_BOOL * pfFlag)
|
|
{
|
|
_err.Reset();
|
|
return GetBoolProperty( pfFlag, _fAllowEnumeration );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_AllowEnumeration(VARIANT_BOOL fFlag)
|
|
{
|
|
_err.Reset();
|
|
return PutBoolProperty( fFlag, _fAllowEnumeration );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_MaxRecords(LONG * plVal)
|
|
{
|
|
_err.Reset();
|
|
*plVal = _maxResults;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_MaxRecords(LONG lVal)
|
|
{
|
|
_err.Reset();
|
|
if (lVal < 0)
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("set MaxRecords") );
|
|
return _err.GetError();
|
|
}
|
|
else if (IsQueryActive())
|
|
{
|
|
SetError( MSG_IXSSO_QUERY_ACTIVE, OLESTR("set MaxRecords") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
_maxResults = lVal;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_FirstRows(LONG * plVal)
|
|
{
|
|
_err.Reset();
|
|
*plVal = _cFirstRows;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_FirstRows(LONG lVal)
|
|
{
|
|
_err.Reset();
|
|
if (lVal < 0)
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("set FirstRows") );
|
|
return _err.GetError();
|
|
}
|
|
else if (IsQueryActive())
|
|
{
|
|
SetError( MSG_IXSSO_QUERY_ACTIVE, OLESTR("set FirstRows") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
_cFirstRows = lVal;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_StartHit(VARIANT * pvar)
|
|
{
|
|
_err.Reset();
|
|
if (_StartHit.Get() != 0)
|
|
{
|
|
XGrowable<WCHAR> awchBuf;
|
|
|
|
FormatLongVector( _StartHit.Get(), awchBuf );
|
|
|
|
VariantInit( pvar );
|
|
V_BSTR(pvar) = SysAllocString( awchBuf.Get() );
|
|
if ( V_BSTR(pvar) != 0 )
|
|
{
|
|
V_VT(pvar) = VT_BSTR;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
V_VT(pvar) = VT_EMPTY;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_StartHit(VARIANT* pvar)
|
|
{
|
|
_err.Reset();
|
|
//
|
|
// NOTE: StartHit is not read-only with an active query so it can
|
|
// be set from the recordset prior to calling QueryToURL.
|
|
//
|
|
SCODE sc;
|
|
|
|
SAFEARRAY* psa;
|
|
XSafeArray xsa;
|
|
|
|
switch( V_VT(pvar) )
|
|
{
|
|
|
|
case VT_DISPATCH:
|
|
//
|
|
//pvar Contains an IDispatch Pointer. To fetch the value
|
|
//you must get the Default Value for the
|
|
//Object stored in pvar using VariantChangeType.
|
|
//
|
|
VariantChangeType(pvar, pvar, 0, VT_BSTR);
|
|
|
|
if (V_VT(pvar) != VT_BSTR)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
// NOTE: fall through
|
|
|
|
case VT_BSTR:
|
|
{
|
|
CDynArrayInPlace<LONG> aStartHit( 0 );
|
|
|
|
ParseNumberVectorString( V_BSTR(pvar), aStartHit );
|
|
unsigned cHits = aStartHit.Count();
|
|
|
|
psa = SafeArrayCreateVector(VT_I4, 1, cHits);
|
|
if ( ! psa )
|
|
return E_OUTOFMEMORY;
|
|
|
|
xsa.Set(psa);
|
|
|
|
for (unsigned i=1; i<=cHits; i++)
|
|
{
|
|
long rgIx[1];
|
|
LONG lVal = aStartHit.Get(i-1);
|
|
rgIx[0] = (long)i;
|
|
sc = SafeArrayPutElement( xsa.Get(), rgIx, &lVal );
|
|
if ( FAILED(sc) )
|
|
break;
|
|
}
|
|
if ( FAILED(sc) )
|
|
return sc;
|
|
}
|
|
break;
|
|
|
|
case VT_ARRAY | VT_I4:
|
|
sc = SafeArrayCopy(V_ARRAY(pvar),&psa);
|
|
if ( FAILED(sc) )
|
|
return sc;
|
|
|
|
xsa.Set(psa);
|
|
if (SafeArrayGetDim(psa) != 1)
|
|
return E_INVALIDARG;
|
|
break;
|
|
|
|
case VT_I4:
|
|
case VT_I2:
|
|
psa = SafeArrayCreateVector(VT_I4,1,1);
|
|
if ( ! psa )
|
|
return E_OUTOFMEMORY;
|
|
|
|
xsa.Set(psa);
|
|
{
|
|
long rgIx[1];
|
|
rgIx[0] = 1;
|
|
long lVal = (V_VT(pvar) == VT_I4) ? V_I4(pvar) : V_I2(pvar);
|
|
sc = SafeArrayPutElement( xsa.Get(), rgIx, &lVal );
|
|
|
|
if ( FAILED( sc ) )
|
|
return sc;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
SetError( E_INVALIDARG, OLESTR("set StartHit") );
|
|
return _err.GetError();
|
|
|
|
}
|
|
|
|
_StartHit.Destroy();
|
|
_StartHit.Set( xsa.Acquire() );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_ResourceUseFactor(LONG * plVal)
|
|
{
|
|
_err.Reset();
|
|
*plVal = _iResourceFactor;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::put_ResourceUseFactor(LONG lVal)
|
|
{
|
|
_err.Reset();
|
|
|
|
if (IsQueryActive())
|
|
{
|
|
SetError( MSG_IXSSO_QUERY_ACTIVE, OLESTR("set ResourceUseFactor") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
_iResourceFactor = lVal;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CixssoQuery read-only properties
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::CheckQueryStatusBit - private inline
|
|
//
|
|
// Synopsis: Check a specific query status bit, set variant bool accordingly
|
|
//
|
|
// Arguments: [pfVal] - VARIANT_BOOL to be set
|
|
// [dwBit] - bit(s) in query status to be tested
|
|
//
|
|
// Returns: SCODE - status return
|
|
//
|
|
// History: 03 Jan 1997 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline
|
|
SCODE CixssoQuery::CheckQueryStatusBit( VARIANT_BOOL * pfVal, DWORD dwBit )
|
|
{
|
|
SCODE sc = S_OK;
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
DWORD dwStatus = GetQueryStatus( );
|
|
*pfVal = (dwStatus & dwBit) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
}
|
|
CATCH( CIxssoException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
SetError( sc, OLESTR("CheckQueryStatus"), eIxssoError );
|
|
}
|
|
AND_CATCH( CException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
SetError( sc, OLESTR("CheckQueryStatus") );
|
|
}
|
|
END_CATCH
|
|
|
|
return sc;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_QueryTimedOut(VARIANT_BOOL * pfFlag)
|
|
{
|
|
_err.Reset();
|
|
return CheckQueryStatusBit( pfFlag, STAT_TIME_LIMIT_EXCEEDED );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_QueryIncomplete(VARIANT_BOOL * pfFlag)
|
|
{
|
|
_err.Reset();
|
|
return CheckQueryStatusBit( pfFlag, STAT_CONTENT_QUERY_INCOMPLETE );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::get_OutOfDate(VARIANT_BOOL * pfFlag)
|
|
{
|
|
_err.Reset();
|
|
return CheckQueryStatusBit( pfFlag,
|
|
(STAT_CONTENT_OUT_OF_DATE | STAT_REFRESH_INCOMPLETE) );
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CixssoQuery Methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::AddScopeToQuery( BSTR bstrScope,
|
|
BSTR bstrDepth)
|
|
{
|
|
//
|
|
// This is an internally used method, so don't need to reset error object here.
|
|
//
|
|
|
|
if (0 == bstrScope || 0 == SysStringLen(bstrScope) )
|
|
{
|
|
THROW( CException(E_INVALIDARG) );
|
|
}
|
|
|
|
SCODE sc = CopyBstrToWstrArray( bstrScope, _apwszScope, _cScopes );
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
ULONG ulDepth = ParseCiDepthFlag( bstrDepth );
|
|
_aulDepth[_cScopes] = ulDepth;
|
|
|
|
_cScopes++;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::DefineColumn( BSTR bstrColDefinition)
|
|
{
|
|
_err.Reset();
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
CQueryScanner scanner( bstrColDefinition, FALSE );
|
|
XPtr<CPropEntry> xpropentry;
|
|
CPropertyList::ParseOneLine( scanner, 0, xpropentry );
|
|
|
|
if (xpropentry.GetPointer())
|
|
sc = _PropertyList.AddEntry( xpropentry, 0 );
|
|
}
|
|
CATCH( CPListException, e )
|
|
{
|
|
sc = e.GetPListError();
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
SetError( sc, OLESTR("DefineColumn"), ePlistError );
|
|
}
|
|
AND_CATCH( CException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
SetError( sc, OLESTR("DefineColumn") );
|
|
}
|
|
END_CATCH
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::CreateRecordset - public
|
|
//
|
|
// Synopsis: Executes the query and returns a recordset
|
|
//
|
|
// Arguments: [bstrSequential] - one of "SEQUENTIAL" or "NONSEQUENTIAL",
|
|
// selects whether a nonsequential query is used.
|
|
// [ppDisp] - recordset is returned here.
|
|
//
|
|
// History: 06 Nov 1996 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CixssoQuery::CreateRecordset( BSTR bstrSequential,
|
|
IDispatch * * ppDisp)
|
|
{
|
|
_err.Reset();
|
|
|
|
unsigned eErrorClass = 0;
|
|
BOOL fSetErrorNeeded = TRUE;
|
|
|
|
if (IsQueryActive())
|
|
{
|
|
SetError( MSG_IXSSO_QUERY_ACTIVE, OLESTR("CreateRecordset") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
IsSafeForScripting();
|
|
|
|
*ppDisp = 0;
|
|
|
|
if ( bstrSequential && 0 == _wcsicmp(bstrSequential, L"SEQUENTIAL") )
|
|
_fSequential = TRUE;
|
|
else if ( bstrSequential &&
|
|
(0 == _wcsicmp(bstrSequential, L"NONSEQUENTIAL") ||
|
|
0 == _wcsicmp(bstrSequential, L"NON-SEQUENTIAL")) )
|
|
_fSequential = FALSE;
|
|
else
|
|
{
|
|
SetError( E_INVALIDARG, OLESTR("CreateRecordset") );
|
|
return _err.GetError();
|
|
}
|
|
|
|
ExecuteQuery();
|
|
Win4Assert( _pIRowset != 0 );
|
|
Win4Assert( _pIRowsetQueryStatus != 0 );
|
|
|
|
//
|
|
// Create an empty recordset, and put our rowset in it.
|
|
//
|
|
|
|
IDispatch * pRecordset = 0;
|
|
sc = _pIAdoRecordsetCF->CreateInstance( 0,
|
|
IID_IDispatch,
|
|
(void **)&pRecordset );
|
|
|
|
ADORecordsetConstruction * pRecordsetConstruction = 0;
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
sc = pRecordset->QueryInterface( IID_IADORecordsetConstruction,
|
|
(void **)&pRecordsetConstruction );
|
|
}
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
sc = pRecordsetConstruction->put_Rowset( _pIRowset );
|
|
pRecordsetConstruction->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
*ppDisp = pRecordset;
|
|
}
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
if (pRecordset)
|
|
pRecordset->Release();
|
|
pRecordset = 0;
|
|
|
|
_pIRowset->Release();
|
|
_pIRowset = 0;
|
|
|
|
_pIRowsetQueryStatus->Release();
|
|
_pIRowsetQueryStatus = 0;
|
|
}
|
|
|
|
fSetErrorNeeded = FAILED(sc);
|
|
}
|
|
CATCH( CPListException, e )
|
|
{
|
|
sc = e.GetPListError();
|
|
eErrorClass = ePlistError;
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
}
|
|
AND_CATCH( CIxssoException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
eErrorClass = eIxssoError;
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
}
|
|
AND_CATCH( CParserException, e )
|
|
{
|
|
sc = e.GetParseError();
|
|
eErrorClass = eParseError;
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
}
|
|
AND_CATCH( CPostedOleDBException, e )
|
|
{
|
|
//
|
|
// When the execution error was detected, the Ole DB error
|
|
// info was retrieved and stored in the exception object.
|
|
// We retrieve that here and compose the error message.
|
|
//
|
|
|
|
sc = e.GetErrorCode();
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
|
|
XInterface <IErrorInfo> xErrorInfo(e.AcquireErrorInfo());
|
|
|
|
if (xErrorInfo.GetPointer())
|
|
{
|
|
BSTR bstrErrorDescription = 0;
|
|
xErrorInfo->GetDescription(&bstrErrorDescription);
|
|
if (bstrErrorDescription)
|
|
{
|
|
SetError( sc, OLESTR("CreateRecordset"), (WCHAR const *)bstrErrorDescription);
|
|
SysFreeString(bstrErrorDescription);
|
|
fSetErrorNeeded = FALSE;
|
|
}
|
|
else
|
|
eErrorClass = eDefaultError;
|
|
}
|
|
}
|
|
AND_CATCH( CException, e )
|
|
{
|
|
sc = e.GetErrorCode();
|
|
eErrorClass = eDefaultError;
|
|
Win4Assert( !SUCCEEDED(sc) );
|
|
}
|
|
END_CATCH
|
|
|
|
if (! SUCCEEDED(sc) && fSetErrorNeeded)
|
|
SetError( sc, OLESTR("CreateRecordset"), eErrorClass );
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::ParseOptimizeFor - private static
|
|
//
|
|
// Synopsis: Parse the input string for the OptimizeFor property
|
|
//
|
|
// Arguments: [wcsOptString] - input string
|
|
// [eChoice] - OptimizeFor choice expressed in wcsOptString
|
|
//
|
|
// Returns: SCODE - status return
|
|
//
|
|
// History: 05 Mar 1997 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CixssoQuery::ParseOptimizeFor( WCHAR const * wcsOptString,
|
|
DWORD & eChoice )
|
|
{
|
|
eChoice = eOptHitCount;
|
|
|
|
while (wcsOptString && *wcsOptString)
|
|
{
|
|
WCHAR * wcsNext = wcschr( wcsOptString, ',' );
|
|
ULONG cch = (wcsNext) ? CiPtrToUlong( wcsNext - wcsOptString ) :
|
|
wcslen( wcsOptString );
|
|
|
|
|
|
if ( 11 == cch && _wcsnicmp(wcsOptString, L"performance", 11) == 0)
|
|
{
|
|
eChoice |= eOptPerformance;
|
|
}
|
|
else if ( 6 == cch && _wcsnicmp(wcsOptString, L"recall", 6) == 0)
|
|
{
|
|
eChoice |= eOptRecall;
|
|
}
|
|
else if ( 8 == cch && _wcsnicmp(wcsOptString, L"hitcount", 8) == 0)
|
|
{
|
|
eChoice |= eOptHitCount;
|
|
}
|
|
else if ( 10 == cch && _wcsnicmp(wcsOptString, L"nohitcount", 10) == 0)
|
|
{
|
|
eChoice &= ~eOptHitCount;
|
|
}
|
|
else
|
|
return E_INVALIDARG;
|
|
|
|
wcsOptString = wcsNext;
|
|
if (wcsOptString)
|
|
{
|
|
wcsOptString++;
|
|
|
|
while (iswspace( *wcsOptString ))
|
|
wcsOptString++;
|
|
}
|
|
}
|
|
|
|
// 'performance' and 'recall' are mutually exclusive. Check if both
|
|
// were set.
|
|
if ( (eChoice & (eOptRecall | eOptPerformance)) ==
|
|
(eOptRecall | eOptPerformance) )
|
|
return E_INVALIDARG;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::ParseCiDepthFlag, private
|
|
//
|
|
// Synopsis: Parses the flags attribute
|
|
//
|
|
// Arguments: [bstrFlags] -- flags
|
|
//
|
|
// Returns: ULONG - query scope flags
|
|
//
|
|
// History: 96/Jan/03 DwightKr created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
ULONG CixssoQuery::ParseCiDepthFlag( BSTR bstrFlags )
|
|
{
|
|
if ( 0 == bstrFlags || 0 == SysStringLen(bstrFlags) )
|
|
{
|
|
return QUERY_DEEP;
|
|
}
|
|
|
|
ULONG ulFlags;
|
|
|
|
if ( _wcsicmp(bstrFlags, L"SHALLOW") == 0 )
|
|
{
|
|
ulFlags = QUERY_SHALLOW;
|
|
}
|
|
else if ( _wcsicmp(bstrFlags, L"DEEP") == 0 )
|
|
{
|
|
ulFlags = QUERY_DEEP;
|
|
}
|
|
else
|
|
{
|
|
THROW( CIxssoException(MSG_IXSSO_EXPECTING_SHALLOWDEEP, 0) );
|
|
}
|
|
|
|
return ulFlags;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::SetLocaleString - private
|
|
//
|
|
// Synopsis: Parse the input string for a recognizable locale name
|
|
//
|
|
// Arguments: [bstrLocale] - input string
|
|
//
|
|
// Returns: SCODE - status return
|
|
//
|
|
// History: 13 Mar 1997 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CixssoQuery::SetLocaleString(BSTR str)
|
|
{
|
|
LCID lcidTemp = GetLCIDFromString( str );
|
|
if (lcidTemp == -1)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
_lcid = lcidTemp;
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ParseNumberVectorString - public
|
|
//
|
|
// Synopsis: Parses a string consisting of ',' separated numeric values
|
|
// into an array.
|
|
//
|
|
// Arguments: [pwszValue] - input string
|
|
// [aNum] - dynamic array where numbers are placed.
|
|
//
|
|
// History: 10 Jun 1997 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void ParseNumberVectorString( WCHAR * pwszValue, CDynArrayInPlace<LONG> & aNum )
|
|
{
|
|
while (pwszValue)
|
|
{
|
|
LONG lNum = _wtoi( pwszValue );
|
|
aNum[aNum.Count()] = lNum;
|
|
pwszValue = wcschr(pwszValue, L',');
|
|
if (pwszValue)
|
|
pwszValue++;
|
|
}
|
|
}
|
|
|
|
void FormatLongVector( SAFEARRAY * psa, XGrowable<WCHAR> & awchBuf )
|
|
{
|
|
Win4Assert( SafeArrayGetDim( psa ) == 1 &&
|
|
SafeArrayGetElemsize( psa ) == sizeof (LONG) );
|
|
|
|
LONG iLBound = 0;
|
|
LONG iUBound = 0;
|
|
SCODE sc = SafeArrayGetLBound( psa, 1, &iLBound );
|
|
if (SUCCEEDED(sc))
|
|
sc = SafeArrayGetUBound( psa, 1, &iUBound );
|
|
|
|
unsigned cch = 0;
|
|
for (int i=iLBound; i<= iUBound; i++)
|
|
{
|
|
LONG lValue;
|
|
LONG ix[1];
|
|
ix[0] = i;
|
|
sc = SafeArrayGetElement( psa, ix, &lValue );
|
|
|
|
awchBuf.SetSize(cch + 20);
|
|
if (i != iLBound)
|
|
{
|
|
awchBuf[cch] = L',';
|
|
cch++;
|
|
}
|
|
_itow( lValue, &awchBuf[cch], 10 );
|
|
cch += wcslen( &awchBuf[cch] );
|
|
}
|
|
|
|
}
|
|
|
|
// CIXSSOPropertyList methods
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::CIXSSOPropertyList, public
|
|
//
|
|
// Synopsis: Constructs a property mapper for the ixsso's use.
|
|
//
|
|
// Parameters: [pDefaultList] -- The default column mapper.
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
CIXSSOPropertyList::CIXSSOPropertyList(ULONG ulCodePage)
|
|
: _cRefs( 1 ),
|
|
_ulCodePage( ulCodePage ),
|
|
_xDefaultList(0)
|
|
{
|
|
// default list is not known. Use SetDefaultList to set that
|
|
}
|
|
|
|
// Set the defualt list
|
|
void CIXSSOPropertyList::SetDefaultList(IColumnMapper *pDefaultList)
|
|
{
|
|
Win4Assert(pDefaultList);
|
|
|
|
_xDefaultList.Set(pDefaultList);
|
|
_xDefaultList->AddRef();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::QueryInterface, public
|
|
//
|
|
// Arguments: [ifid] -- Interface id
|
|
// [ppiuk] -- Interface return pointer
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CIXSSOPropertyList::QueryInterface( REFIID ifid, void ** ppiuk )
|
|
{
|
|
if (0 == ppiuk)
|
|
return E_INVALIDARG;
|
|
|
|
if ( IID_IUnknown == ifid )
|
|
{
|
|
AddRef();
|
|
*ppiuk = (void *)((IUnknown *)this);
|
|
return S_OK;
|
|
}
|
|
else if (IID_IColumnMapper == ifid )
|
|
{
|
|
AddRef();
|
|
*ppiuk = (void *)((IColumnMapper *)this);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppiuk = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::AddRef, public
|
|
//
|
|
// Synopsis: Reference the virtual table.
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CIXSSOPropertyList::AddRef(void)
|
|
{
|
|
InterlockedIncrement( &_cRefs );
|
|
return( _cRefs );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::Release, public
|
|
//
|
|
// Synopsis: De-Reference the virtual table.
|
|
//
|
|
// Effects: If the ref count goes to 0 then the table is deleted.
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CIXSSOPropertyList::Release(void)
|
|
{
|
|
unsigned long uTmp = InterlockedDecrement( &_cRefs );
|
|
if (0 == uTmp)
|
|
{
|
|
delete this;
|
|
}
|
|
return(uTmp);
|
|
}
|
|
|
|
//
|
|
// IColumnMapper methods
|
|
//
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::GetPropInfoFromName, public
|
|
//
|
|
// Synopsis: Get property info. from name.
|
|
//
|
|
// Parameters: [wcsPropName] -- Property name to look up.
|
|
// [ppPropId] -- Ptr to return Id of the property.
|
|
// [pPropType] -- Ptr to return type of the property.
|
|
// [puiWidth] -- Ptr to return property width.
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CIXSSOPropertyList::GetPropInfoFromName(const WCHAR *wcsPropName,
|
|
DBID * *ppPropId,
|
|
DBTYPE *pPropType,
|
|
unsigned int *puiWidth)
|
|
{
|
|
//
|
|
// Callers can pass in 0 for pPropType and puiWidth if they
|
|
// don't care about them.
|
|
//
|
|
|
|
if (0 == wcsPropName || 0 == ppPropId)
|
|
return E_INVALIDARG;
|
|
|
|
Win4Assert(_xDefaultList.GetPointer());
|
|
|
|
//
|
|
// First check in the default list, then in the override list.
|
|
//
|
|
|
|
SCODE sc = _xDefaultList->GetPropInfoFromName(wcsPropName,
|
|
ppPropId,
|
|
pPropType,
|
|
puiWidth);
|
|
|
|
if (FAILED(sc) && 0 != _xOverrideList.GetPointer())
|
|
{
|
|
sc = _xOverrideList->GetPropInfoFromName(wcsPropName,
|
|
ppPropId,
|
|
pPropType,
|
|
puiWidth);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::GetPropInfoFromId, public
|
|
//
|
|
// Synopsis: Get property info. from dbid.
|
|
//
|
|
// Parameters: [pPropId] -- Ptr to prop to look up.
|
|
// [pwcsName] -- Ptr to return property name.
|
|
// [pPropType] -- Ptr to return type of the property.
|
|
// [puiWidth] -- Ptr to return property width.
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CIXSSOPropertyList::GetPropInfoFromId(const DBID *pPropId,
|
|
WCHAR * *pwcsName,
|
|
DBTYPE *pPropType,
|
|
unsigned int *puiWidth)
|
|
{
|
|
Win4Assert(!"Not available!");
|
|
return E_NOTIMPL;
|
|
|
|
#if 0 // complete, working implementation, but not needed.
|
|
//
|
|
// Callers can pass in 0 for pPropType and puiWidth if they
|
|
// don't care about them.
|
|
//
|
|
if (0 == pwcsName || 0 == pPropId)
|
|
return E_INVALIDARG;
|
|
|
|
//
|
|
// First check in the default list, then in the override list.
|
|
//
|
|
|
|
SCODE sc = _xDefaultList->GetPropInfoFromId(pPropId,
|
|
pwcsName,
|
|
pPropType,
|
|
puiWidth);
|
|
|
|
if (FAILED(sc) && 0 != _xOverrideList.GetPointer())
|
|
{
|
|
sc = _xOverrideList->GetPropInfoFromId(pPropId,
|
|
pwcsName,
|
|
pPropType,
|
|
puiWidth);
|
|
}
|
|
|
|
return sc;
|
|
#endif // 0
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::EnumPropInfo, public
|
|
//
|
|
// Synopsis: Gets the i-th entry from the list of properties.
|
|
//
|
|
// Parameters: [iEntry] -- i-th entry to retrieve (0-based).
|
|
// [pwcsName] -- Ptr to return property name.
|
|
// [ppPropId] -- Ptr to return Id of the property.
|
|
// [pPropType] -- Ptr to return type of the property.
|
|
// [puiWidth] -- Ptr to return property width.
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CIXSSOPropertyList::EnumPropInfo(ULONG iEntry,
|
|
const WCHAR * *pwcsName,
|
|
DBID * *ppPropId,
|
|
DBTYPE *pPropType,
|
|
unsigned int *puiWidth)
|
|
{
|
|
Win4Assert(!"Not available!");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::IsMapUpToDate, public
|
|
//
|
|
// Synopsis: Indicates if the column map is up to date.
|
|
//
|
|
// History: 26-Aug-97 KrishnaN Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CIXSSOPropertyList::IsMapUpToDate()
|
|
{
|
|
Win4Assert(_xDefaultList.GetPointer());
|
|
|
|
// return the IsMapUpToDate of the default list.
|
|
// the override list is always considered to be
|
|
// upto date.
|
|
|
|
return _xDefaultList->IsMapUpToDate();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CIXSSOPropertyList::AddEntry, private
|
|
//
|
|
// Synopsis: Adds a CPropEntry to the overriding list. Verifies that the name
|
|
// isn't already in the default list or the overriding list.
|
|
//
|
|
// Arguments: [xPropEntry] -- CPropEntry to add. Acquired on success
|
|
// [iLine] -- line number we're parsing
|
|
//
|
|
// Returns: S_OK on success or S_
|
|
//
|
|
// History: 11-Sep-97 KrishnaN Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CIXSSOPropertyList::AddEntry( XPtr<CPropEntry> & xPropEntry, int iLine )
|
|
{
|
|
Win4Assert(_xDefaultList.GetPointer());
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
// protect _xOverrideList
|
|
|
|
CLock lock(_mtxAdd);
|
|
|
|
//
|
|
// We do not allow entries in the override list that have the same name
|
|
// as the default list.
|
|
//
|
|
|
|
DBID *pPropId;
|
|
DBTYPE PropType;
|
|
unsigned uWidth;
|
|
|
|
if ( S_OK == GetPropInfoFromName( xPropEntry->GetName(),
|
|
&pPropId,
|
|
&PropType,
|
|
&uWidth ))
|
|
{
|
|
if ( PropType != xPropEntry->GetPropType() ||
|
|
( uWidth != xPropEntry->GetWidth() &&
|
|
xPropEntry->GetWidth() != PLIST_DEFAULT_WIDTH ) )
|
|
{
|
|
THROW( CPListException( QPLIST_E_DUPLICATE, iLine ) );
|
|
}
|
|
else
|
|
sc = QPLIST_S_DUPLICATE;
|
|
}
|
|
|
|
if ( S_OK == sc )
|
|
{
|
|
if (0 == _xOverrideList.GetPointer())
|
|
_xOverrideList.Set(new CPropertyList(_ulCodePage));
|
|
|
|
_xOverrideList->AddEntry( xPropEntry.GetPointer(), iLine);
|
|
|
|
xPropEntry.Acquire();
|
|
}
|
|
|
|
return sc;
|
|
} //AddEntry
|
|
|
|
#if 0
|
|
|
|
HRESULT CixssoQuery::GetInterfaceSafetyOptions(
|
|
REFIID riid,
|
|
DWORD * pdwSupportedOptions,
|
|
DWORD * pdwEnabledOptions )
|
|
{
|
|
if ( 0 == pdwSupportedOptions ||
|
|
0 == pdwEnabledOptions )
|
|
return E_POINTER;
|
|
|
|
ixssoDebugOut(( DEB_ITRACE, "get safety options called...\n" ));
|
|
|
|
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
|
|
*pdwEnabledOptions = 0;
|
|
|
|
return S_OK;
|
|
} //GetInterfaceSafetyOptions
|
|
|
|
HRESULT CixssoQuery::SetInterfaceSafetyOptions(
|
|
REFIID riid,
|
|
DWORD dwOptionSetMask,
|
|
DWORD dwEnabledOptions )
|
|
{
|
|
ixssoDebugOut(( DEB_ITRACE, "set setmask: %#x\n", dwOptionSetMask ));
|
|
ixssoDebugOut(( DEB_ITRACE, "set enabled: %#x\n", dwEnabledOptions ));
|
|
|
|
_dwSafetyOptions = (dwEnabledOptions & dwOptionSetMask);
|
|
|
|
return S_OK;
|
|
} //SetInterfaceSafetyOptions
|
|
|
|
#endif
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::SetSite, public
|
|
//
|
|
// Synopsis: Sets the current site (if any). Called by containers of
|
|
// CixssoQuery like IE. Not called by other containers like
|
|
// ASP and CScript.
|
|
//
|
|
// Arguments: [pSite] -- The container of this query object
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// History: 09-Nov-00 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT CixssoQuery::SetSite( IUnknown * pSite )
|
|
{
|
|
_xSite.Free();
|
|
|
|
if ( 0 != pSite )
|
|
{
|
|
pSite->AddRef();
|
|
|
|
_xSite.Set( pSite );
|
|
}
|
|
|
|
ixssoDebugOut(( DEB_ITRACE, "setting site: %#x\n", pSite ));
|
|
|
|
return S_OK;
|
|
} //SetSite
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::GetSite, public
|
|
//
|
|
// Synopsis: Retrieves the current site (if any)
|
|
//
|
|
// Arguments: [riid] -- IID requested
|
|
// [ppvSite] -- Where the interface pointer is returned
|
|
//
|
|
// Returns: HRESULT like a QueryInterface()
|
|
//
|
|
// History: 09-Nov-00 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT CixssoQuery::GetSite(
|
|
REFIID riid,
|
|
void ** ppvSite )
|
|
{
|
|
ixssoDebugOut(( DEB_ITRACE, "getsite\n" ));
|
|
|
|
if ( 0 == ppvSite )
|
|
return E_POINTER;
|
|
|
|
*ppvSite = 0;
|
|
|
|
if ( _xSite.IsNull() )
|
|
return E_NOINTERFACE;
|
|
|
|
return _xSite->QueryInterface( riid, ppvSite );
|
|
} //GetSite
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CixssoQuery::IsSafeForScripting, private
|
|
//
|
|
// Synopsis: Checks if it's ok to execute in the current context. Throws
|
|
// an exception if it's not safe or on error. It's not safe
|
|
// to execute script off a remote machine.
|
|
//
|
|
// History: 09-Nov-00 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CixssoQuery::IsSafeForScripting()
|
|
{
|
|
XInterface<IServiceProvider> xServiceProvider;
|
|
SCODE sc = GetSite( IID_IServiceProvider,
|
|
xServiceProvider.GetQIPointer() );
|
|
|
|
//
|
|
// When queries are run in IIS the container does not call
|
|
// SetSite, so there is no site and we'll have E_NOINTERFACE
|
|
// at this point. Same for cscript.exe queries.
|
|
// If that ever changes, the check below for file:// URLs will
|
|
// fail and no IIS queries will ever work.
|
|
//
|
|
|
|
if ( E_NOINTERFACE == sc )
|
|
return;
|
|
|
|
if ( FAILED( sc ) )
|
|
THROW( CException( sc ) );
|
|
|
|
XInterface<IWebBrowser2> xWebBrowser;
|
|
sc = xServiceProvider->QueryService( SID_SWebBrowserApp,
|
|
IID_IWebBrowser2,
|
|
xWebBrowser.GetQIPointer() );
|
|
if ( E_NOINTERFACE == sc )
|
|
return;
|
|
|
|
if ( FAILED( sc ) )
|
|
THROW( CException( sc ) );
|
|
|
|
BSTR bstrURL;
|
|
sc = xWebBrowser->get_LocationURL( &bstrURL );
|
|
if ( FAILED( sc ) )
|
|
THROW( CException( sc ) );
|
|
|
|
XBStr xURL( bstrURL );
|
|
ixssoDebugOut(( DEB_ITRACE, "url: %ws\n", bstrURL ));
|
|
|
|
WCHAR buf[32];
|
|
URL_COMPONENTS uc;
|
|
RtlZeroMemory( &uc, sizeof uc );
|
|
uc.dwStructSize = sizeof uc;
|
|
uc.lpszScheme = buf;
|
|
uc.dwSchemeLength = sizeof buf / sizeof WCHAR;
|
|
|
|
INTERNET_SCHEME scheme = INTERNET_SCHEME_UNKNOWN;
|
|
|
|
if ( InternetCrackUrl( bstrURL, wcslen( bstrURL ), ICU_DECODE, &uc ) )
|
|
scheme = uc.nScheme;
|
|
|
|
// The URL has to be a file:/// URL or we won't allow it.
|
|
|
|
if ( INTERNET_SCHEME_FILE != scheme )
|
|
THROW( CException( E_ACCESSDENIED ) );
|
|
|
|
// OK, now it can't be a UNC path. Look for a drive letter and a colon
|
|
|
|
// file:///c: the length should at least be 10
|
|
if ( wcslen( bstrURL ) <= 9 )
|
|
THROW( CException( E_ACCESSDENIED ) );
|
|
|
|
WCHAR const * pwcPath = bstrURL + 8;
|
|
WCHAR const * pwcColon = wcschr( pwcPath, L':' );
|
|
|
|
ixssoDebugOut(( DEB_ITRACE, "Path is: %ws\n", pwcPath ));
|
|
|
|
if ( ( 0 == pwcColon ) ||
|
|
( pwcColon > ( pwcPath + 1 ) ) )
|
|
THROW( CException( E_ACCESSDENIED ) );
|
|
|
|
WCHAR wcDrive = * ( pwcColon - 1 );
|
|
|
|
ixssoDebugOut(( DEB_ITRACE, "wcDrive is: %wc\n", wcDrive ));
|
|
wcDrive = towupper( wcDrive );
|
|
|
|
if ( ( wcDrive < L'A' ) || ( wcDrive > L'Z' ) )
|
|
THROW( CException( E_ACCESSDENIED ) );
|
|
} //IsSafeForScripting
|
|
|