/*=================================================================== Microsoft Denali Microsoft Confidential. Copyright 1996 Microsoft Corporation. All Rights Reserved. Component: Server object File: Server.cpp Owner: CGrant This file contains the code for the implementation of the Server object. ===================================================================*/ #include "denpre.h" #pragma hdrstop #include "Server.h" #include "tlbcache.h" #include "memchk.h" /* * * C S e r v e r * */ /*=================================================================== CServer::CServer Constructor Parameters: punkOuter object to ref count (can be NULL) Returns: ===================================================================*/ CServer::CServer(IUnknown *punkOuter) : m_fInited(FALSE), m_fDiagnostics(FALSE), m_pData(NULL) { CDispatch::Init(IID_IServer); if (punkOuter) { m_punkOuter = punkOuter; m_fOuterUnknown = TRUE; } else { m_cRefs = 1; m_fOuterUnknown = FALSE; } #ifdef DBG m_fDiagnostics = TRUE; #endif // DBG } /*=================================================================== CServer::~CServer Destructor Parameters: Returns: ===================================================================*/ CServer::~CServer() { Assert(!m_fInited); Assert(m_fOuterUnknown || m_cRefs == 0); // must have 0 ref count } /*=================================================================== CServer::Init Allocates m_pData. Performs any intiailization of a CServer that's prone to failure that we also use internally before exposing the object outside. Parameters: None Returns: S_OK on success. ===================================================================*/ HRESULT CServer::Init() { if (m_fInited) return S_OK; // already inited Assert(!m_pData); m_pData = new CServerData; if (!m_pData) return E_OUTOFMEMORY; m_pData->m_pIReq = NULL; m_pData->m_pHitObj = NULL; m_pData->m_ISupportErrImp.Init(static_cast(this), static_cast(this), IID_IServer); m_fInited = TRUE; return S_OK; } /*=================================================================== CServer::UnInit Remove m_pData. Make tombstone (UnInited state). Parameters: Returns: HRESULT (S_OK) ===================================================================*/ HRESULT CServer::UnInit() { if (!m_fInited) return S_OK; // already uninited Assert(m_pData); delete m_pData; m_pData = NULL; m_fInited = FALSE; return S_OK; } /*=================================================================== CServer::ReInit The only need for a re-init here is to update the CIsapiReqInfo for this request, the CIsapiReqInfo is required to access the MapPath Method. Ideally this method should be part of the Request object Parameters: CIsapiReqInfo * CHitObj * Returns: S_OK on success. ===================================================================*/ HRESULT CServer::ReInit ( CIsapiReqInfo * pIReq, CHitObj *pHitObj ) { Assert(m_fInited); Assert(m_pData); m_pData->m_pIReq = pIReq; m_pData->m_pHitObj = pHitObj; return S_OK; } /*=================================================================== CServer::MapPathInternal Map virtual path BSTR into single char buffer Used by MapPath(), Execute(), Transfer() Parameters: dwContextId for error messages wszVirtPath path to translate szPhysPath [out] translate into this buffer (MAX_PATH sized) szVirtPath [out, optional] mb virtual path buffer (MAX_PATH sized) Returns: S_OK on success. ===================================================================*/ HRESULT CServer::MapPathInternal ( DWORD dwContextId, WCHAR *wszVirtPath, TCHAR *szPhysPath, TCHAR *szVirtPath ) { // increment the pointer past leading white spaces wchar_t *wszLogicalPath = wszVirtPath; while (iswspace(*wszLogicalPath)) ++wszLogicalPath; unsigned cchLogicalPath = wcslen(wszLogicalPath); if (cchLogicalPath > MAX_PATH-1) { if (dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH); return E_FAIL; } else if (cchLogicalPath == 0) { if (dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_STR); return E_FAIL; } // Is this a physical path? if (iswalpha(wszLogicalPath[0]) && wszLogicalPath[1] == L':') { if (dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_PHY_STR); return E_FAIL; } // simple validation: look for invalid characters in string [*?<>,;:'"] // and multiple slash characters ie "//" or "\\" // BOOL fParentPath = FALSE; BOOL fEnableParentPaths = m_pData->m_pHitObj->QueryAppConfig()->fEnableParentPaths(); BOOL fAnyBackslashes = FALSE; wchar_t *pwchT = wszLogicalPath; while (*pwchT != L'\0') { switch (*pwchT) { case L'*': case L':': case L'?': case L'<': case L'>': case L',': case L'"': if (dwContextId) ExceptionId( IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR); return E_FAIL; case L'.': if (*++pwchT == L'.') { if (!fEnableParentPaths) { if (dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR3); return E_FAIL; } else { fParentPath = TRUE; ++pwchT; } } break; case L'\\': fAnyBackslashes = TRUE; case L'/': ++pwchT; if (*pwchT == '/' || *pwchT == '\\') { if (dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR2); return E_FAIL; } break; default: ++pwchT; } } // whew! Error handling done! // Convert wszLogicalPath to multi-byte TCHAR szLogicalPath[MAX_PATH]; #if UNICODE wcscpy(szLogicalPath, wszLogicalPath); #else HRESULT hr; CWCharToMBCS convStr; if (hr = convStr.Init(wszLogicalPath)) { if ((hr == E_OUTOFMEMORY) && dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_OOM); return hr; } if (convStr.GetStringLen() > (MAX_PATH-1)) { if (dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH); return E_FAIL; } strcpy(szLogicalPath,convStr.GetString()); #endif // change all backslashes to forward slashes if (fAnyBackslashes) { TCHAR *pbBackslash = szLogicalPath; while (pbBackslash = _tcschr(pbBackslash, _T('\\'))) *pbBackslash = _T('/'); } // is this a Relative path request. I.E. no leading slash // if so prepend the path_info string to szLogicalPath BOOL fPathAlreadyIsMapped = FALSE; // Some cases map the path earlier if (szLogicalPath[0] != _T('/')) { TCHAR szParentPath[MAX_PATH]; _tcscpy(szParentPath, m_pData->m_pIReq->QueryPszPathInfo()); // Trim off the ASP file name from the PATH_INFO TCHAR *pchT = _tcsrchr(szParentPath, _T('/')); if (pchT != NULL) *pchT = '\0'; // If there were parent paths, map the parent now, then append the relative path // the relative path to the parent path if (fParentPath) { Assert (fEnableParentPaths); // Errors should have been flagged upstairs DWORD dwPathSize = sizeof(szParentPath); if (! m_pData->m_pIReq->MapUrlToPath(szParentPath, &dwPathSize)) { if (dwContextId) ExceptionId(IID_IServer, dwContextId, ::GetLastError() == ERROR_INSUFFICIENT_BUFFER? IDE_SERVER_EXCEDED_MAX_PATH : IDE_SERVER_MAPPATH_FAILED); return E_FAIL; } fPathAlreadyIsMapped = TRUE; } // Resolve relative paths if (! DotPathToPath(szLogicalPath, szLogicalPath, szParentPath)) { if (dwContextId) ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_FAILED); return E_FAIL; } } // return virtual path if requested if (szVirtPath) _tcscpy(szVirtPath, szLogicalPath); // Map this to a physical file name (if required) if (!fPathAlreadyIsMapped) { DWORD dwPathSize = sizeof(szLogicalPath); if (! m_pData->m_pIReq->MapUrlToPath(szLogicalPath, &dwPathSize)) { if (dwContextId) ExceptionId(IID_IServer, dwContextId, ::GetLastError() == ERROR_INSUFFICIENT_BUFFER? IDE_SERVER_EXCEDED_MAX_PATH : IDE_SERVER_MAPPATH_FAILED); return E_FAIL; } } // remove any ending delimiters (unless it's the root directory. The root always starts with drive letter) TCHAR *pchT = CharPrev(szLogicalPath, szLogicalPath + _tcslen(szLogicalPath)); if ((*pchT == _T('/') || *pchT == _T('\\')) && pchT[-1] != _T(':')) { *pchT = _T('\0'); } // Replace forward slash with back slash for (pchT = szLogicalPath; *pchT != _T('\0'); ++pchT) { if (*pchT == _T('/')) *pchT = _T('\\'); } _tcscpy(szPhysPath, szLogicalPath); return S_OK; } /*=================================================================== CServer::QueryInterface CServer::AddRef CServer::Release IUnknown members for CServer object. ===================================================================*/ STDMETHODIMP CServer::QueryInterface ( REFIID riid, PPVOID ppv ) { *ppv = NULL; /* * The only calls for IUnknown are either in a nonaggregated * case or when created in an aggregation, so in either case * always return our IUnknown for IID_IUnknown. */ // BUG FIX 683 added IID_IDenaliIntrinsic to prevent the user from // storing intrinsic objects in the application and session object if (IID_IUnknown == riid || IID_IDispatch == riid || IID_IServer == riid || IID_IDenaliIntrinsic == riid) *ppv = static_cast(this); //Indicate that we support error information if (IID_ISupportErrorInfo == riid) { if (m_pData) *ppv = & (m_pData->m_ISupportErrImp); } if (IID_IMarshal == riid) { *ppv = static_cast(this); } //AddRef any interface we'll return. if (NULL != *ppv) { ((LPUNKNOWN)*ppv)->AddRef(); return S_OK; } return E_NOINTERFACE; } STDMETHODIMP_(ULONG) CServer::AddRef() { if (m_fOuterUnknown) return m_punkOuter->AddRef(); return InterlockedIncrement((LPLONG)&m_cRefs); } STDMETHODIMP_(ULONG) CServer::Release() { if (m_fOuterUnknown) return m_punkOuter->Release(); DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs); if (cRefs) return cRefs; delete this; return 0; } /*=================================================================== CServer::GetIDsOfNames Special-case implementation for CreateObject, Execute, Transfer Parameters: riid REFIID reserved. Must be IID_NULL. rgszNames OLECHAR ** pointing to the array of names to be mapped. cNames UINT number of names to be mapped. lcid LCID of the locale. rgDispID DISPID * caller allocated array containing IDs corresponging to those names in rgszNames. Return Value: HRESULT S_OK or a general error code. ===================================================================*/ STDMETHODIMP CServer::GetIDsOfNames ( REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID ) { const DISPID dispidCreateObject = 0x60020002; const DISPID dispidExecute = 0x60020007; const DISPID dispidTransfer = 0x60020008; if (cNames == 1) { switch (rgszNames[0][0]) { case L'C': case L'c': if (wcsicmp(rgszNames[0]+1, L"reateobject") == 0) { *rgDispID = dispidCreateObject; return S_OK; } break; case L'E': case L'e': if (wcsicmp(rgszNames[0]+1, L"xecute") == 0) { *rgDispID = dispidExecute; return S_OK; } break; case L'T': case L't': if (wcsicmp(rgszNames[0]+1, L"ransfer") == 0) { *rgDispID = dispidTransfer; return S_OK; } break; } } // default to CDispatch's implementation return CDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispID); } /*=================================================================== CServer::CheckForTombstone Tombstone stub for IServer methods. If the object is tombstone, does ExceptionId and fails. Parameters: Returns: HRESULT E_FAIL if Tombstone S_OK if not ===================================================================*/ HRESULT CServer::CheckForTombstone() { if (m_fInited) { // inited - good object Assert(m_pData); // must be present for inited objects return S_OK; } ExceptionId ( IID_IServer, IDE_SERVER, IDE_INTRINSIC_OUT_OF_SCOPE ); return E_FAIL; } /*=================================================================== CServer::CreateObject Parameters: BSTR containing ProgID Variant to fillin with IUknown pointer Returns: S_OK if successful E_FAIL otherwise Side effects: Creates an instance of an ole automation object ===================================================================*/ STDMETHODIMP CServer::CreateObject(BSTR bstrProgID, IDispatch **ppDispObj) { if (FAILED(CheckForTombstone())) return E_FAIL; if (bstrProgID == NULL) { ExceptionId(IID_IServer, IDE_SERVER, IDE_EXPECTING_STR); return E_FAIL; } Assert(m_pData->m_pHitObj); *ppDispObj = NULL; HRESULT hr; CLSID clsid; if (Glob(fEnableTypelibCache)) { // Use typelib cache to create the component hr = g_TypelibCache.CreateComponent ( bstrProgID, m_pData->m_pHitObj, ppDispObj, &clsid ); if (FAILED(hr) && clsid == CLSID_NULL) { // bad prog id or something ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr); return hr; } } else { // Don't use typelib cache hr = CLSIDFromProgID((LPCOLESTR)bstrProgID, &clsid); if (FAILED(hr)) { ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr); return hr; } hr = m_pData->m_pHitObj->CreateComponent(clsid, ppDispObj); } if (SUCCEEDED(hr)) return S_OK; // Check if a custom error was already posted IErrorInfo *pErrInfo = NULL; if (GetErrorInfo(0, &pErrInfo) == S_OK && pErrInfo) { SetErrorInfo(0, pErrInfo); pErrInfo->Release(); } // Standard errors else if (hr == E_ACCESSDENIED) ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_DENIED); else { if (hr == REGDB_E_CLASSNOTREG) { BOOL fInProc; if (SUCCEEDED(CompModelFromCLSID(clsid, NULL, &fInProc)) && !fInProc) { ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_NOTINPROC); } } else ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr); } return hr; } /*=================================================================== CServer::MapPath Return the physical path translated from a logical path Parameters: BSTR bstrLogicalPath BSTR FAR * pbstrPhysicalPath Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::MapPath(BSTR bstrLogicalPath, BSTR FAR * pbstrPhysicalPath) { if (FAILED(CheckForTombstone())) return E_FAIL; // Bug 1361: error if no CIsapiReqInfo (presumably called during // Application_OnEnd or Session_OnEnd) if (m_pData->m_pIReq == NULL) { ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL); return E_FAIL; } AssertValid(); Assert (pbstrPhysicalPath != NULL); *pbstrPhysicalPath = NULL; // use MapPathInternal() to do the mapping TCHAR szLogicalPath[MAX_PATH]; HRESULT hr = MapPathInternal(IDE_SERVER_MAPPATH, bstrLogicalPath, szLogicalPath); if (FAILED(hr)) return hr; #if UNICODE *pbstrPhysicalPath = SysAllocString(szLogicalPath); if (*pbstrPhysicalPath == NULL) { ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_OOM); return E_FAIL; } #else // Convert the path to wide character if (FAILED(SysAllocStringFromSz(szLogicalPath, 0, pbstrPhysicalPath, CP_ACP))) { ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_OOM); return E_FAIL; } #endif return S_OK; } /*=================================================================== CServer::HTMLEncode Encodes a string to HTML standards Parameters: BSTR bstrIn value: string to be encoded BSTR FAR * pbstrEncoded value: pointer to HTML encoded version of string Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::HTMLEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded ) { if (FAILED(CheckForTombstone())) return E_FAIL; char* pszstrIn = NULL; char* pszEncodedstr = NULL; char* pszStartEncodestr = NULL; int nbstrLen = 0; int nstrLen = 0; HRESULT hr = S_OK; UINT uCodePage = m_pData->m_pHitObj->GetCodePage(); CWCharToMBCS convIn; STACK_BUFFER( tempHTML, 2048 ); if (bstrIn) nbstrLen = wcslen(bstrIn); else nbstrLen = 0; if (nbstrLen <= 0) return S_OK; if (FAILED(hr = convIn.Init(bstrIn, uCodePage))) { if (hr == E_OUTOFMEMORY) ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); goto L_Exit; } pszstrIn = convIn.GetString(); nstrLen = HTMLEncodeLen(pszstrIn, uCodePage, bstrIn); if (nstrLen > 0) { //Encode string , NOTE this function returns a pointer to the // NULL so you need to keep a pointer to the start of the string // if (!tempHTML.Resize(nstrLen + 2)) { ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); hr = E_FAIL; goto L_Exit; } pszEncodedstr = (char*)tempHTML.QueryPtr(); pszStartEncodestr = pszEncodedstr; pszEncodedstr = ::HTMLEncode( pszEncodedstr, pszstrIn, uCodePage, bstrIn); // convert result to bstr // if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded, uCodePage))) { ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); hr = E_FAIL; goto L_Exit; } } L_Exit: return hr; } /*=================================================================== CServer::URLEncode Encodes a query string to URL standards Parameters: BSTR bstrIn value: string to be URL encoded BSTR FAR * pbstrEncoded value: pointer to URL encoded version of string Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::URLEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded ) { if (FAILED(CheckForTombstone())) return E_FAIL; char* pszstrIn = NULL; char* pszEncodedstr = NULL; char* pszStartEncodestr = NULL; int nbstrLen = 0; int nstrLen = 0; HRESULT hr = S_OK; CWCharToMBCS convIn; STACK_BUFFER( tempURL, 256 ); if (bstrIn) nbstrLen = wcslen(bstrIn); else nbstrLen = 0; if (nbstrLen <= 0) return S_OK; if (FAILED(hr = convIn.Init(bstrIn, m_pData->m_pHitObj->GetCodePage()))) { if (hr == E_OUTOFMEMORY) ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); goto L_Exit; } pszstrIn = convIn.GetString(); nstrLen = URLEncodeLen(pszstrIn); if (nstrLen > 0) { //Encode string , NOTE this function returns a pointer to the // NULL so you need to keep a pointer to the start of the string // if (!tempURL.Resize(nstrLen + 2)) { ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); hr = E_FAIL; goto L_Exit; } pszEncodedstr = (char *)tempURL.QueryPtr(); pszStartEncodestr = pszEncodedstr; pszEncodedstr = ::URLEncode( pszEncodedstr, pszstrIn ); // convert result to bstr // if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded))) { ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); hr = E_FAIL; goto L_Exit; } } L_Exit: return hr; } /*=================================================================== CServer::URLPathEncode Encodes the path portion of a URL or a full URL. All characters up to the first '?' are encoded with the following rules: o Charcters that are needed to parse the URL are left alone o RFC 1630 safe characters are left alone o Non-foreign alphanumberic characters are left alone o Anything else is escape encoded Everything after the '?' is not encoded. Parameters: BSTR bstrIn value: string to be URL path encoded BSTR FAR * pbstrEncoded value: pointer to URL path encoded version of string Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::URLPathEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded ) { if (FAILED(CheckForTombstone())) return E_FAIL; char* pszstrIn = NULL; char* pszEncodedstr = NULL; char* pszStartEncodestr = NULL; int nbstrLen = 0; int nstrLen = 0; HRESULT hr = S_OK; CWCharToMBCS convIn; STACK_BUFFER( tempPath, 256 ); if (bstrIn) nbstrLen = wcslen(bstrIn); else nbstrLen = 0; if (nbstrLen <= 0) return S_OK; if (FAILED(hr = convIn.Init(bstrIn, m_pData->m_pHitObj->GetCodePage()))) { if (hr == E_OUTOFMEMORY) ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); goto L_Exit; } pszstrIn = convIn.GetString(); nstrLen = URLPathEncodeLen(pszstrIn); if (nstrLen > 0) { //Encode string , NOTE this function returns a pointer to the // NULL so you need to keep a pointer to the start of the string // if (!tempPath.Resize(nstrLen+2)) { ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); hr = E_FAIL; goto L_Exit; } pszEncodedstr = (char *)tempPath.QueryPtr(); pszStartEncodestr = pszEncodedstr; pszEncodedstr = ::URLPathEncode( pszEncodedstr, pszstrIn ); // convert result to bstr // if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded))) { ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM); hr = E_FAIL; goto L_Exit; } } L_Exit: return hr; } /*=================================================================== CServer::get_ScriptTimeout Will return the script timeout interval (in seconds) Parameters: long *plTimeoutSeconds Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::get_ScriptTimeout( long * plTimeoutSeconds ) { if (FAILED(CheckForTombstone())) return E_FAIL; if (m_pData->m_pHitObj == NULL) { ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL); return(E_FAIL); } *plTimeoutSeconds = m_pData->m_pHitObj->GetScriptTimeout(); return S_OK; } /*=================================================================== CServer::put_ScriptTimeout Allows the user to set the timeout interval for a script (in seconds) Parameters: long lTimeoutSeconds Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::put_ScriptTimeout( long lTimeoutSeconds ) { if (FAILED(CheckForTombstone())) return E_FAIL; if ( lTimeoutSeconds < 0 ) { ExceptionId( IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_TIMEOUT ); return E_FAIL; } else { if (m_pData->m_pHitObj == NULL) { ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL); return(E_FAIL); } m_pData->m_pHitObj->SetScriptTimeout(lTimeoutSeconds); return S_OK; } } /*=================================================================== CServer::Execute Execute an ASP Parameters: bstrURL URL to execute Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::Execute(BSTR bstrURL) { if (FAILED(CheckForTombstone())) return E_FAIL; if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL) { ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_CALL); return E_FAIL; } TCHAR szTemplate[MAX_PATH], szVirtTemp[MAX_PATH]; HRESULT hr = MapPathInternal(IDE_SERVER, bstrURL, szTemplate, szVirtTemp); if (FAILED(hr)) { ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_EXECUTE_INVALID_PATH); return hr; } Normalize(szTemplate); hr = m_pData->m_pHitObj->ExecuteChildRequest(FALSE, szTemplate, szVirtTemp); if (FAILED(hr)) { if (m_pData->m_pHitObj->FHasASPError()) // error already reported return hr; ExceptionId(IID_IServer, IDE_SERVER, (hr == E_COULDNT_OPEN_SOURCE_FILE) ? IDE_SERVER_EXECUTE_CANTLOAD : IDE_SERVER_EXECUTE_FAILED); return E_FAIL; } return S_OK; } /*=================================================================== CServer::Transfer Transfer execution an ASP Parameters: bstrURL URL to execute Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::Transfer(BSTR bstrURL) { if (FAILED(CheckForTombstone())) return E_FAIL; if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL) { ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL); return E_FAIL; } TCHAR szTemplate[MAX_PATH], szVirtTemp[MAX_PATH]; HRESULT hr = MapPathInternal(IDE_SERVER, bstrURL, szTemplate, szVirtTemp); if (FAILED(hr)) { ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_TRANSFER_INVALID_PATH); return hr; } Normalize(szTemplate); hr = m_pData->m_pHitObj->ExecuteChildRequest(TRUE, szTemplate, szVirtTemp); if (FAILED(hr)) { if (m_pData->m_pHitObj->FHasASPError()) // error already reported return hr; ExceptionId(IID_IServer, IDE_SERVER, (hr == E_COULDNT_OPEN_SOURCE_FILE) ? IDE_SERVER_TRANSFER_CANTLOAD : IDE_SERVER_TRANSFER_FAILED); return E_FAIL; } return S_OK; } /*=================================================================== CServer::GetLastError Get ASPError object for the last error Parameters: ppASPErrorObject [out] the error object Returns: HRESULT S_OK on success ===================================================================*/ STDMETHODIMP CServer::GetLastError(IASPError **ppASPErrorObject) { *ppASPErrorObject = NULL; if (FAILED(CheckForTombstone())) return E_FAIL; if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL) { ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_CALL); return E_FAIL; } HRESULT hr = m_pData->m_pHitObj->GetASPError(ppASPErrorObject); if (FAILED(hr)) { ExceptionId(IID_IServer, IDE_SERVER, IDE_UNEXPECTED); return hr; } return S_OK; } #ifdef DBG /*=================================================================== CServer::AssertValid Test to make sure that the CServer object is currently correctly formed and assert if it is not. Returns: Side effects: None. ===================================================================*/ void CServer::AssertValid() const { Assert(m_fInited); Assert(m_pData); Assert(m_pData->m_pIReq); } #endif DBG