//+--------------------------------------------------------------------------- // // 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 #include #include #include // ADO CLSID and IID definitions #include // 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 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 STDMETHODIMP CixssoQuery::OnStartPage (IUnknown* pUnk) { // 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(); 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 &apstr, unsigned i ) { SCODE sc = S_OK; if (bstr) { CTranslateSystemExceptions translate; TRY { unsigned cch = SysStringLen( bstr )+1; if (cch > 1) { XArray 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 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 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 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 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 & aNum ) { while (pwszValue) { LONG lNum = _wtoi( pwszValue ); aNum[aNum.Count()] = lNum; pwszValue = wcschr(pwszValue, L','); if (pwszValue) pwszValue++; } } void FormatLongVector( SAFEARRAY * psa, XGrowable & 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 & 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 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 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