//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995. // // File: cdlprot.cxx // // Contents: // // Classes: // // Functions: // // History: 02-06-1997 t-alans (Alan Shi) Created // //---------------------------------------------------------------------------- #include #include #ifdef unix #include "../download/cdl.h" #else #include "..\download\cdl.h" #endif /* !unix */ // From shlwapip.h LWSTDAPI_(HRESULT) CLSIDFromStringWrap(LPOLESTR lpsz, LPCLSID pclsid); #define VALUE_EQUAL_CHAR '=' #define VALUE_SEPARATOR_CHAR ';' //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::CCdlProtocol // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- CCdlProtocol::CCdlProtocol(REFCLSID rclsid, IUnknown *pUnkOuter, IUnknown **ppUnkInner) : CBaseProtocol(rclsid, pUnkOuter, ppUnkInner) { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::CCdlProtocol \n", this)); DllAddRef(); _clsidReport = CLSID_NULL; _pCodeDLBSC = NULL; _fDataPending = TRUE; _fNotStarted = TRUE; _iid = IID_IUnknown; _pbc = NULL; _fGetClassObject = FALSE; EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::CCdlProtocol \n", this)); } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::~CCdlProtocol // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- CCdlProtocol::~CCdlProtocol() { if (_pbc) { _pbc->Release(); } DllRelease(); EProtDebugOut((DEB_PLUGPROT, "%p _IN/OUT CCdlProtocol::~CCdlProtocol \n", this)); } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::Start // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- #ifdef _WIN64 LWSTDAPI_(BOOL) StrToInt64ExW(LPCWSTR pszString, DWORD dwFlags, LONGLONG * pllRet); #endif STDMETHODIMP CCdlProtocol::Start(LPCWSTR pwzUrl, IOInetProtocolSink *pIOInetProtocolSink, IOInetBindInfo *pIOInetBindInfo, DWORD grfSTI, DWORD_PTR dwReserved) { DWORD cElFetched = 0; LPOLESTR pwzIID = NULL; BINDINFO bindinfo; DWORD grfBINDF = 0; EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::Start\n", this)); HRESULT hr = NOERROR; WCHAR wzURL[MAX_URL_SIZE]; EProtAssert((!_pProtSink && pIOInetBindInfo && pIOInetProtocolSink)); EProtAssert((_pwzUrl == NULL)); bindinfo.cbSize = sizeof(BINDINFO); pIOInetBindInfo->GetBindInfo(&grfBINDF, &bindinfo); if (grfBINDF & BINDF_GETCLASSOBJECT) { LPWSTR pwzBC = NULL; DWORD cElFetched = 0; hr = pIOInetBindInfo->GetBindString(BINDSTRING_PTR_BIND_CONTEXT, &pwzBC, 0, &cElFetched); if (SUCCEEDED(hr)) { #ifdef _WIN64 StrToInt64ExW(pwzBC, 0, (LONGLONG *)&_pbc); #else _pbc = (IBindCtx *)StrToIntW(pwzBC); #endif EProtAssert(_pbc); delete [] pwzBC; pwzBC = NULL; } else { hr = E_UNEXPECTED; goto Exit; } _fGetClassObject = TRUE; } grfSTI |= PI_FORCE_ASYNC; hr = CBaseProtocol::Start(pwzUrl, pIOInetProtocolSink, pIOInetBindInfo, grfSTI, dwReserved); if (SUCCEEDED(hr)) { hr = pIOInetBindInfo->GetBindString(BINDSTRING_IID, &pwzIID, 0, &cElFetched); } if (hr == S_OK) { hr = CLSIDFromString(pwzIID, &_iid); delete [] pwzIID; } if (SUCCEEDED(hr)) { hr = ParseURL(); } Exit: EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::Start (hr:%lx)\n",this, hr)); return hr; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::Continue // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::Continue(PROTOCOLDATA *pStateInfoIn) { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::Continue\n", this)); HRESULT hr = E_FAIL; if (_fNotStarted && pStateInfoIn->dwState == CDL_STATE_BIND) { _fNotStarted = FALSE; hr = ParseURL(); } EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::Continue (hr:%lx)\n",this, hr)); return hr; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::Read // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::Read(void *pv,ULONG cb,ULONG *pcbRead) { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::Read\n", this)); HRESULT hr; hr = (_fDataPending) ? (E_PENDING) : (S_FALSE); *pcbRead = (_fDataPending) ? (0x0) : (0x100); EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::Read\n", this)); return hr; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::Abort // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::Abort(HRESULT hrReason, DWORD dwOptions) { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::Abort\n", this)); HRESULT hr = E_UNEXPECTED; EProtAssert( _pCodeDLBSC != NULL ); if (_pCodeDLBSC != NULL) { hr = _pCodeDLBSC->Abort(); } #if 0 if (_pProtSink) { hr = CBaseProtocol::Abort(hrReason, dwOptions); } #endif EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::Abort\n", this)); return hr; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::Seek // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::Seek\n", this)); EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::Seek\n", this)); return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::LockRequest // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::LockRequest(DWORD dwOptions) { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::LockRequest\n", this)); EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::LockRequest\n", this)); return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::UnlockRequest // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::UnlockRequest() { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::UnlockRequest\n", this)); EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::UnlockRequest\n", this)); return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::ParseURL // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::ParseURL() { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::ParseURL\n", this)); HRESULT hr = MK_E_SYNTAX; WCHAR wzlURL[MAX_URL_SIZE]; LPWSTR pwz = NULL; LPWSTR pwzValue = NULL; LPWSTR pwzTag = NULL; LPWSTR pwzPound = NULL; BOOL fGotRequiredField = FALSE; CodeDownloadData cdldata; CHAR szValue[MAX_PATH]; cdldata.szDistUnit = NULL; cdldata.szClassString = NULL; cdldata.szURL = NULL; cdldata.szMimeType = NULL; cdldata.szExtension = NULL; cdldata.szDll = NULL; cdldata.dwFileVersionMS = 0; cdldata.dwFileVersionLS = 0; cdldata.dwFlags = 0; // URL is of the form: // (1) cdl://[unused]?[clsid=xxx|codebase=xxx|mimetype=xxx|extension=xxx]; // [clsid=xxx|codebase=xxx|mimetype=xxx|extension=xxx]; // [clsid=xxx|codebase=xxx|mimetype=xxx|extension=xxx];... // // OR // // (2) cdl:[clsid=xxx|codebase=xxx|mimetype=xxx|extension=xxx]; // [clsid=xxx|codebase=xxx|mimetype=xxx|extension=xxx];... // // // NOTE: [distunit=xxx] added to support AsyncInstallDistributionUnit // [flags=xxx] added flags (as an integer so that we can dictate // silent mode, async. etc. wcscpy(wzlURL, _wzFullURL); // ensure correct format: "cdl://[stuff]?" pwz = wcschr(wzlURL, ':'); pwz++; if (!(wcsnicmp(pwz, L"//", 2) && wcsnicmp(pwz, L"\\\\", 2))) { // URL is of form (1) pwz = wcschr(pwz, '?'); if( pwz == NULL ) { // error, no '?' found hr = MK_E_SYNTAX; goto Exit; } pwz++; // pwz now points to the start of the param list (start boundry) } pwzValue = pwz + wcslen( pwz ); // points to NULL // If there is a pound, NULL terminate there instead pwzPound = pwzValue - 1; while (pwzPound >= pwz) { if (*pwzPound == VALUE_POUND_CHAR) { *pwzPound = NULL; pwzValue = pwzPound; break; } pwzPound--; } for ( ;; ) { while (pwzValue >= pwz && *pwzValue != VALUE_EQUAL_CHAR && *pwzValue != VALUE_SEPARATOR_CHAR) { pwzValue--; } if (pwzValue < pwz || *pwzValue == VALUE_SEPARATOR_CHAR) { // error, expected '=' hr = MK_E_SYNTAX; goto Exit; } // pwzValue now points to '=' *pwzValue = NULL; pwzTag = pwzValue; pwzValue++; while (pwzTag >= pwz && *pwzTag != VALUE_EQUAL_CHAR && *pwzTag != VALUE_SEPARATOR_CHAR) { pwzTag--; } if (*pwzTag == VALUE_EQUAL_CHAR) { // error, expected either a separator, or the beginning hr = MK_E_SYNTAX; goto Exit; } pwzTag++; if (!wcsicmp(L"codebase", pwzTag)) { cdldata.szURL = pwzValue; } else if (!wcsicmp(L"clsid", pwzTag)) { cdldata.szClassString = pwzValue; fGotRequiredField = TRUE; } else if (!wcsicmp(L"mimetype", pwzTag)) { cdldata.szMimeType = pwzValue; fGotRequiredField = TRUE; } else if (!wcsicmp(L"extension", pwzTag)) { cdldata.szExtension = pwzValue; fGotRequiredField = TRUE; } else if (!wcsicmp(L"verMS", pwzTag)) { //cdldata.dwFileVersionMS = _wtol(pwzValue); W2A(pwzValue, szValue, MAX_PATH); cdldata.dwFileVersionMS = atol(szValue); } else if (!wcsicmp(L"verLS", pwzTag)) { //cdldata.dwFileVersionLS = _wtol(pwzValue); W2A(pwzValue, szValue, MAX_PATH); cdldata.dwFileVersionLS = atol(szValue); } else if (!wcsicmp(L"distunit", pwzTag)) { cdldata.szDistUnit = pwzValue; fGotRequiredField = TRUE; } else if (!wcsicmp(L"flags", pwzTag)) { cdldata.dwFlags = StrToIntW(pwzValue); } else if (!wcsicmp(L"version", pwzTag)) { W2A(pwzValue, szValue, MAX_PATH); GetVersionFromString(szValue, &(cdldata.dwFileVersionMS), &(cdldata.dwFileVersionLS)); } else if (!wcsicmp(L"dllname",pwzTag)) { cdldata.szDll = pwzValue; } if (pwzTag <= pwz) { break; // we are done } else { pwzValue = pwzTag; pwzValue--; *pwzValue = NULL; pwzTag = NULL; } } // backwards compatability with clsid can be dist unit if(cdldata.szClassString && ! cdldata.szDistUnit) { cdldata.szDistUnit = cdldata.szClassString; } if(cdldata.szDistUnit && ! cdldata.szClassString) { cdldata.szClassString = cdldata.szDistUnit; } if (fGotRequiredField) { // The client must provide a host security manager for // CDL:// protocol bindings. Otherwise, a file:// URL codebase // will be executed without WVT UI. IInternetHostSecurityManager *phsm = NULL; IServiceProvider *psp = NULL; hr = _pProtSink->QueryInterface(IID_IServiceProvider, (void **)&psp); if (FAILED(hr)) { hr = TRUST_E_FAIL; goto Exit; } hr = psp->QueryService(IID_IInternetHostSecurityManager, IID_IInternetHostSecurityManager, (void **)&phsm); if (FAILED(hr)) { hr = TRUST_E_FAIL; goto Exit; } psp->Release(); phsm->Release(); if (IsEqualGUID(_clsidReport , CLSID_NULL)) CLSIDFromString((LPOLESTR)cdldata.szClassString, &_clsidReport); hr = StartDownload(cdldata); } else { hr = MK_E_SYNTAX; } Exit: // if we error for any reason here, then CodeDL BSC was never initiated and we will // never get an BSC::OSB to shut up sink. if (hr != E_PENDING) { _fDataPending = FALSE; if (_pProtSink) { if (!IsEqualGUID(_clsidReport, CLSID_NULL)) { LPOLESTR pwzStrClsId; StringFromCLSID(_clsidReport, &pwzStrClsId); _pProtSink->ReportProgress(BINDSTATUS_CLSIDCANINSTANTIATE, pwzStrClsId); delete [] pwzStrClsId; } _pProtSink->ReportResult(hr, 0, 0); } } EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::ParseURL\n", this)); return hr; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::StartDownload // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CCdlProtocol::StartDownload(CodeDownloadData &cdldata) { EProtDebugOut((DEB_PLUGPROT, "%p _IN CCdlProtocol::StartDownload\n", this)); HRESULT hr = S_OK; IBindCtx *pbc = NULL; IUnknown *pUnk = NULL; // Kick off the download _pCodeDLBSC = new CCodeDLBSC(_pProtSink, _pOIBindInfo, this, _fGetClassObject); if (_pCodeDLBSC == NULL) { hr = E_OUTOFMEMORY; goto Exit; } hr = CreateBindCtx(0, &pbc); if (SUCCEEDED(hr)) { hr = RegisterBindStatusCallback(pbc, _pCodeDLBSC, NULL, 0); if (_pCodeDLBSC != NULL) { _pCodeDLBSC->Release(); } if (FAILED(hr)) { goto Exit; } } cdldata.dwFlags = (_fGetClassObject) ? (CD_FLAGS_NEED_CLASSFACTORY) : (0); hr = AsyncInstallDistributionUnitEx(&cdldata, pbc, _iid, &pUnk, NULL); if (hr == MK_S_ASYNCHRONOUS) { hr = E_PENDING; } else { if (_fGetClassObject) { if (pUnk && SUCCEEDED(hr)) { hr = RegisterIUnknown(pUnk); pUnk->Release(); if (SUCCEEDED(hr)) { hr = _pProtSink->ReportProgress(BINDSTATUS_IUNKNOWNAVAILABLE, NULL); } } _pProtSink->ReportResult(hr, 0, 0); } } Exit: if (pbc != NULL) { // NOTE: This instruction can cause deletion of this object, // referencing "this" afterwords may be a bad idea. pbc->Release(); } EProtDebugOut((DEB_PLUGPROT, "%p OUT CCdlProtocol::StartDownload\n", this)); return hr; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::SetDataPending // // Synopsis: // // Arguments: // // // // Returns: // // History: 02-06-1997 t-alans (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- void CCdlProtocol::SetDataPending(BOOL fPending) { _fDataPending = fPending; } //+--------------------------------------------------------------------------- // // Method: CCdlProtocol::RegisterIUnknown // // Synopsis: // // Arguments: // // // // Returns: // // History: 11-12-1998 AlanShi (Alan Shi) Created // // Notes: // //---------------------------------------------------------------------------- HRESULT CCdlProtocol::RegisterIUnknown(IUnknown *pUnk) { EProtAssert(_pbc); return _pbc->RegisterObjectParam(SZ_IUNKNOWN_PTR, pUnk); }