Leaked source code of windows server 2003
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.

1011 lines
31 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1996 **
  4. //*********************************************************************
  5. // the CStubBindStatusCallback implements IBindStatusCallback,
  6. // IHttpNegotiate. We use it to make a "fake" bind status callback
  7. // object when we have headers and post data we would like to apply
  8. // to a navigation. We supply this IBindStatusCallback object, and
  9. // the URL moniker asks us for headers and post data and use those in
  10. // the transaction.
  11. #include "priv.h"
  12. #include "sccls.h"
  13. #include "bindcb.h"
  14. CStubBindStatusCallback::CStubBindStatusCallback(LPCWSTR pwzHeaders,LPCBYTE pPostData,
  15. DWORD cbPostData, VARIANT_BOOL bOfflineProperty, VARIANT_BOOL bSilentProperty, BOOL bHyperlink,
  16. DWORD grBindFlags) : _cRef(1)
  17. // _pszHeaders(NULL), _hszPostData(NULL), _cbPostData(0) (don't need to zero-init)
  18. {
  19. // this is a standalone COM object; need to maintain ref count on our
  20. // DLL to ensure it doesn't unload
  21. DllAddRef();
  22. if (pwzHeaders) {
  23. _pszHeaders = StrDup(pwzHeaders); // allocate for a permanent copy
  24. }
  25. if (pPostData && cbPostData) {
  26. // make a copy of post data and store it
  27. _hszPostData = GlobalAlloc(GPTR,cbPostData);
  28. if (_hszPostData) {
  29. memcpy((LPVOID) _hszPostData,pPostData,cbPostData);
  30. _cbPostData = cbPostData;
  31. }
  32. }
  33. _bFrameIsOffline = bOfflineProperty ? TRUE : FALSE;
  34. _bFrameIsSilent = bSilentProperty ? TRUE : FALSE;
  35. _bHyperlink = bHyperlink ? TRUE : FALSE;
  36. _grBindFlags = grBindFlags;
  37. TraceMsg(TF_SHDLIFE, "ctor CStubBindStatusCallback %x", this);
  38. }
  39. HRESULT CStubBSC_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  40. {
  41. // aggregation checking is handled in class factory
  42. CStubBindStatusCallback * pbsc = new CStubBindStatusCallback(NULL, NULL, 0, FALSE, FALSE, TRUE, 0);
  43. if (pbsc) {
  44. *ppunk = (IBindStatusCallback *)pbsc;
  45. return S_OK;
  46. }
  47. return E_OUTOFMEMORY;
  48. }
  49. CStubBindStatusCallback::~CStubBindStatusCallback()
  50. {
  51. TraceMsg(TF_SHDLIFE, "dtor CBindStatusCallback %x", this);
  52. _FreeHeadersAndPostData(); // free any data we still have in this object
  53. // release ref count on DLL
  54. DllRelease();
  55. }
  56. STDMETHODIMP CStubBindStatusCallback::QueryInterface(REFIID riid,
  57. LPVOID * ppvObj)
  58. {
  59. if (IsEqualIID(riid, IID_IUnknown) ||
  60. IsEqualIID(riid, IID_IBindStatusCallback)) {
  61. *ppvObj = SAFECAST(this, IBindStatusCallback*);
  62. } else if (IsEqualIID(riid, IID_IHttpNegotiate)) {
  63. *ppvObj = SAFECAST(this, IHttpNegotiate*);
  64. } else if (IsEqualIID(riid, IID_IMarshal)) {
  65. *ppvObj = SAFECAST(this, IMarshal*);
  66. }
  67. else
  68. {
  69. *ppvObj = NULL;
  70. return E_NOINTERFACE;
  71. }
  72. AddRef(); // handing out an interface on ourselves; bump up ref count
  73. return S_OK;
  74. }
  75. STDMETHODIMP_(ULONG) CStubBindStatusCallback::AddRef(void)
  76. {
  77. _cRef++;
  78. TraceMsg(TF_SHDREF, "CStubBindStatusCallback(%x)::AddRef called, new _cRef=%d", this, _cRef);
  79. return _cRef;
  80. }
  81. STDMETHODIMP_(ULONG) CStubBindStatusCallback::Release(void)
  82. {
  83. _cRef--;
  84. TraceMsg(TF_SHDREF, "CStubBindStatusCallback(%x)::Release called, new _cRef=%d", this, _cRef);
  85. if (_cRef > 0)
  86. return _cRef;
  87. delete this;
  88. return 0;
  89. }
  90. //
  91. // Implementation of IBindStatusCallback begins here
  92. //
  93. // implements IBindStatusCallback::OnStartBinding
  94. STDMETHODIMP CStubBindStatusCallback::OnStartBinding(DWORD grfBSCOption,IBinding *pib)
  95. {
  96. return S_OK; // we don't care
  97. }
  98. // implements IBindStatusCallback::GetPriority
  99. STDMETHODIMP CStubBindStatusCallback::GetPriority(LONG *pnPriority)
  100. {
  101. *pnPriority = NORMAL_PRIORITY_CLASS;
  102. return S_OK;
  103. }
  104. // implements IBindStatusCallback::OnLowResource
  105. STDMETHODIMP CStubBindStatusCallback::OnLowResource(DWORD reserved)
  106. {
  107. return S_OK; // we don't care
  108. }
  109. // implements IBindStatusCallback::OnProgress
  110. STDMETHODIMP CStubBindStatusCallback::OnProgress(ULONG ulProgress,ULONG ulProgressMax,
  111. ULONG ulStatusCode,LPCWSTR szStatusText)
  112. {
  113. return S_OK; // we don't care
  114. }
  115. // implements IBindStatusCallback::OnStopBinding
  116. STDMETHODIMP CStubBindStatusCallback::OnStopBinding(HRESULT hresult,LPCWSTR szError)
  117. {
  118. return S_OK; // we don't care
  119. }
  120. // implements IBindStatusCallback::GetBindInfo
  121. STDMETHODIMP CStubBindStatusCallback::GetBindInfo(DWORD *grfBINDF,BINDINFO *pbindinfo)
  122. {
  123. HRESULT hr;
  124. if (!grfBINDF || !pbindinfo || !pbindinfo->cbSize)
  125. return E_INVALIDARG;
  126. // call helper function to do fill in BINDINFO struct with appropriate
  127. // binding data
  128. *grfBINDF = _grBindFlags;
  129. hr = BuildBindInfo(grfBINDF,pbindinfo,_hszPostData,_cbPostData, _bFrameIsOffline, _bFrameIsSilent, _bHyperlink,
  130. (IBindStatusCallback *) this);
  131. return hr;
  132. }
  133. // implements IBindStatusCallback::OnDataAvailable
  134. STDMETHODIMP CStubBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
  135. FORMATETC *pformatetc, STGMEDIUM *pstgmed)
  136. {
  137. ASSERT(FALSE); // should never get called here!
  138. return S_OK;
  139. }
  140. STDMETHODIMP CStubBindStatusCallback::OnObjectAvailable(REFIID riid,IUnknown *punk)
  141. {
  142. return S_OK;
  143. }
  144. //
  145. // Implementation of IHttpNegotiate begins here
  146. //
  147. // implements IHttpNegotiate::BeginningTransaction
  148. STDMETHODIMP CStubBindStatusCallback::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders,
  149. DWORD dwReserved, LPWSTR *ppwzAdditionalHeaders)
  150. {
  151. // call helper function
  152. return BuildAdditionalHeaders(_pszHeaders,(LPCWSTR *) ppwzAdditionalHeaders);
  153. }
  154. // implements IHttpNegotiate::OnResponse
  155. STDMETHODIMP CStubBindStatusCallback::OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders,
  156. LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
  157. {
  158. return S_OK;
  159. }
  160. //
  161. // Additional methods on our class begin here
  162. //
  163. STDMETHODIMP CStubBindStatusCallback::_FreeHeadersAndPostData()
  164. {
  165. if (_pszHeaders) {
  166. LocalFree((HGLOBAL) _pszHeaders);
  167. _pszHeaders = NULL;
  168. }
  169. if (_hszPostData) {
  170. GlobalFree(_hszPostData);
  171. _hszPostData = NULL;
  172. _cbPostData = 0;
  173. }
  174. return S_OK;
  175. }
  176. //+---------------------------------------------------------------------------
  177. //
  178. // Method: CStubBindStatusCallback::_CanMarshalIID
  179. //
  180. // Synopsis: Checks whether this object supports marshalling this IID.
  181. //
  182. // Arguments: [riid] --
  183. //
  184. // Returns:
  185. //
  186. // History: 1-19-96 JohannP (Johann Posch) Created
  187. //
  188. // Notes:
  189. //
  190. //----------------------------------------------------------------------------
  191. inline BOOL CStubBindStatusCallback::_CanMarshalIID(REFIID riid)
  192. {
  193. // keep this in sync with the QueryInterface
  194. return (BOOL) (IsEqualIID(riid,IID_IBindStatusCallback) ||
  195. IsEqualIID(riid,IID_IUnknown) ||
  196. IsEqualIID(riid, IID_IHttpNegotiate));
  197. }
  198. //+---------------------------------------------------------------------------
  199. //
  200. // Method: CStubBindStatusCallback::_ValidateMarshalParams
  201. //
  202. // Synopsis: Validates the standard set parameters that are passed into most
  203. // of the IMarshal methods
  204. //
  205. // Arguments: [riid] --
  206. // [pvInterface] --
  207. // [dwDestContext] --
  208. // [pvDestContext] --
  209. // [mshlflags] --
  210. //
  211. // Returns:
  212. //
  213. // History: 1-19-96 JohannP (Johann Posch) Created
  214. //
  215. // Notes:
  216. //
  217. //----------------------------------------------------------------------------
  218. HRESULT CStubBindStatusCallback::_ValidateMarshalParams(REFIID riid,void *pvInterface,
  219. DWORD dwDestContext,void *pvDestContext,DWORD mshlflags)
  220. {
  221. HRESULT hr = NOERROR;
  222. if (_CanMarshalIID(riid))
  223. {
  224. // 10/02/96 chrisfra: ask johannp, should we be supporting future contexts
  225. // via CoGetStandardMarshal?
  226. ASSERT((dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_LOCAL || dwDestContext == MSHCTX_NOSHAREDMEM));
  227. ASSERT((mshlflags == MSHLFLAGS_NORMAL || mshlflags == MSHLFLAGS_TABLESTRONG));
  228. if ( (dwDestContext != MSHCTX_INPROC && dwDestContext != MSHCTX_LOCAL && dwDestContext != MSHCTX_NOSHAREDMEM)
  229. || (mshlflags != MSHLFLAGS_NORMAL && mshlflags != MSHLFLAGS_TABLESTRONG))
  230. {
  231. hr = E_INVALIDARG;
  232. }
  233. }
  234. else
  235. {
  236. hr = E_NOINTERFACE;
  237. }
  238. return hr;
  239. }
  240. //+---------------------------------------------------------------------------
  241. //
  242. // IMarshal methods
  243. //
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Method: CStubBindStatusCallback::GetUnmarshalClass
  247. //
  248. // Synopsis:
  249. //
  250. // Arguments: [riid] --
  251. // [pvInterface] --
  252. // [dwDestContext] --
  253. // [pvDestContext] --
  254. // [mshlflags] --
  255. // [pCid] --
  256. //
  257. // Returns:
  258. //
  259. // History: 1-19-96 JohannP (Johann Posch) Created
  260. //
  261. // Notes:
  262. //
  263. //----------------------------------------------------------------------------
  264. STDMETHODIMP CStubBindStatusCallback::GetUnmarshalClass(REFIID riid,void *pvInterface,
  265. DWORD dwDestContext,void *pvDestContext,DWORD mshlflags,CLSID *pCid)
  266. {
  267. HRESULT hr;
  268. hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
  269. if (hr == NOERROR)
  270. {
  271. *pCid = (CLSID) CLSID_CStubBindStatusCallback;
  272. }
  273. return hr;
  274. }
  275. //+---------------------------------------------------------------------------
  276. //
  277. // Method: CStubBindStatusCallback::GetMarshalSizeMax
  278. //
  279. // Synopsis:
  280. //
  281. // Arguments: [void] --
  282. // [pvInterface] --
  283. // [dwDestContext] --
  284. // [pvDestContext] --
  285. // [mshlflags] --
  286. // [pSize] --
  287. //
  288. // Returns:
  289. //
  290. // History: 1-19-96 JohannP (Johann Posch) Created
  291. //
  292. // Notes:
  293. //
  294. //----------------------------------------------------------------------------
  295. STDMETHODIMP CStubBindStatusCallback::GetMarshalSizeMax(REFIID riid,void *pvInterface,
  296. DWORD dwDestContext,void *pvDestContext,DWORD mshlflags,DWORD *pSize)
  297. {
  298. HRESULT hr;
  299. if (pSize == NULL)
  300. {
  301. hr = E_INVALIDARG;
  302. }
  303. else
  304. {
  305. hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
  306. if (hr == NOERROR)
  307. {
  308. // size of fBSCBFlags, grBindFlags, postdata, headers.
  309. *pSize = (sizeof(DWORD) + 3 * sizeof(DWORD)) + _cbPostData ;
  310. if (_pszHeaders)
  311. *pSize += ((lstrlen(_pszHeaders) + 1) * sizeof(*_pszHeaders));
  312. }
  313. }
  314. return hr;
  315. }
  316. //+---------------------------------------------------------------------------
  317. //
  318. // Method: CStubBindStatusCallback::MarshalInterface
  319. //
  320. // Synopsis:
  321. //
  322. // Arguments: [REFIID] --
  323. // [riid] --
  324. // [DWORD] --
  325. // [void] --
  326. // [DWORD] --
  327. // [mshlflags] --
  328. //
  329. // Returns:
  330. //
  331. // History: 1-19-96 JohannP (Johann Posch) Created
  332. //
  333. // Notes:
  334. //
  335. //----------------------------------------------------------------------------
  336. STDMETHODIMP CStubBindStatusCallback::MarshalInterface(IStream *pistm,REFIID riid,
  337. void *pvInterface,DWORD dwDestContext,
  338. void *pvDestContext,DWORD mshlflags)
  339. {
  340. HRESULT hr;
  341. DWORD cbLen;
  342. DWORD fBSCBFlags;
  343. hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
  344. if (hr != NOERROR) goto exitPoint;
  345. // Write _grBindFlags
  346. hr = pistm->Write(&_grBindFlags, sizeof(DWORD), NULL);
  347. if (hr != NOERROR) goto exitPoint;
  348. // Write fBSCBFlags
  349. fBSCBFlags = (_bFrameIsOffline ? 1 : 0) + (_bFrameIsSilent ? 2 : 0) ;
  350. hr = pistm->Write(&fBSCBFlags, sizeof(DWORD), NULL);
  351. if (hr != NOERROR) goto exitPoint;
  352. // Write headers
  353. cbLen = (_pszHeaders ? (lstrlen(_pszHeaders) + 1) * sizeof(TCHAR) : 0);
  354. hr = pistm->Write(&cbLen, sizeof(DWORD), NULL);
  355. if (hr != NOERROR) goto exitPoint;
  356. if (cbLen != 0)
  357. {
  358. hr = pistm->Write(_pszHeaders, cbLen, NULL);
  359. if (hr != NOERROR) goto exitPoint;
  360. }
  361. // Write PostData
  362. hr = pistm->Write(&_cbPostData, sizeof(DWORD), NULL);
  363. if (hr != NOERROR) goto exitPoint;
  364. if (_cbPostData != 0)
  365. {
  366. hr = pistm->Write(_hszPostData, _cbPostData, NULL);
  367. if (hr != NOERROR) goto exitPoint;
  368. }
  369. exitPoint:
  370. return hr;
  371. }
  372. //+---------------------------------------------------------------------------
  373. //
  374. // Method: CStubBindStatusCallback::UnmarshalInterface
  375. //
  376. // Synopsis: Unmarshals an Urlmon interface out of a stream
  377. //
  378. // Arguments: [REFIID] --
  379. // [void] --
  380. // [ppvObj] --
  381. //
  382. // Returns:
  383. //
  384. // History: 1-19-96 JohannP (Johann Posch) Created
  385. //
  386. // Notes:
  387. //
  388. //----------------------------------------------------------------------------
  389. STDMETHODIMP CStubBindStatusCallback::UnmarshalInterface(IStream *pistm, REFIID riid, void ** ppvObj)
  390. {
  391. HRESULT hr = NOERROR;
  392. DWORD fBSCBFlags;
  393. if (ppvObj == NULL)
  394. {
  395. hr = E_INVALIDARG;
  396. }
  397. else if (! _CanMarshalIID(riid))
  398. {
  399. *ppvObj = NULL;
  400. hr = E_NOINTERFACE;
  401. }
  402. else
  403. {
  404. *ppvObj = NULL;
  405. DWORD cbLen;
  406. // Free old values, if any
  407. _FreeHeadersAndPostData();
  408. // Read _grBindFlags
  409. hr = pistm->Read(&fBSCBFlags, sizeof(DWORD), NULL);
  410. if (hr != NOERROR) goto exitPoint;
  411. _grBindFlags = fBSCBFlags;
  412. // Read m_fBSCBFlags
  413. hr = pistm->Read(&fBSCBFlags, sizeof(DWORD), NULL);
  414. if (hr != NOERROR) goto exitPoint;
  415. _bFrameIsOffline = fBSCBFlags & 1 ? 1:0;
  416. _bFrameIsSilent = fBSCBFlags & 2 ? 1:0;
  417. // Read headers
  418. hr = pistm->Read(&cbLen, sizeof(DWORD), NULL);
  419. if (hr != NOERROR) goto exitPoint;
  420. if (cbLen != 0)
  421. {
  422. LPTSTR pszData;
  423. pszData = (LPTSTR) LocalAlloc(LPTR, cbLen);
  424. if (pszData == NULL)
  425. {
  426. hr = E_OUTOFMEMORY;
  427. goto exitPoint;
  428. }
  429. hr = pistm->Read(pszData, cbLen, 0);
  430. if (hr != NOERROR)
  431. {
  432. LocalFree(pszData);
  433. pszData = NULL;
  434. goto exitPoint;
  435. }
  436. _pszHeaders = pszData;
  437. }
  438. // Read PostData
  439. hr = pistm->Read(&cbLen, sizeof(DWORD), NULL);
  440. if (hr != NOERROR) goto exitPoint;
  441. if (cbLen != 0)
  442. {
  443. HGLOBAL hszData;
  444. // POST data must be HGLOBAL because the StgMedium requires it
  445. // see bindcb.cpp ::GetBindInfo()
  446. // This will be freed by the Moniker when it's done with it.
  447. hszData = GlobalAlloc(GPTR,cbLen);
  448. if (hszData == NULL)
  449. {
  450. hr = E_OUTOFMEMORY;
  451. goto exitPoint;
  452. }
  453. hr = pistm->Read(hszData, cbLen, 0);
  454. if (hr != NOERROR)
  455. {
  456. GlobalFree(hszData);
  457. hszData = NULL;
  458. goto exitPoint;
  459. }
  460. _hszPostData = hszData;
  461. _cbPostData = cbLen;
  462. }
  463. // call QI to get the requested interface
  464. hr = QueryInterface(riid, ppvObj);
  465. }
  466. exitPoint:
  467. return hr;
  468. }
  469. STDMETHODIMP CStubBindStatusCallback::ReleaseMarshalData(IStream *pStm)
  470. {
  471. // 10/02/96 chrisfra: ask Johannp if this should be seeking past EOD
  472. return NOERROR;
  473. }
  474. STDMETHODIMP CStubBindStatusCallback::DisconnectObject(DWORD dwReserved)
  475. {
  476. return NOERROR;
  477. }
  478. //
  479. // Global helper functions
  480. //
  481. /*******************************************************************
  482. NAME: fOnProxy
  483. SYNOPSIS: returns TRUE if we are have proxy enabled
  484. ********************************************************************/
  485. BOOL fOnProxy()
  486. {
  487. // are we on a proxy?
  488. BOOL fRetOnProxy = FALSE;
  489. DWORD dwValue;
  490. DWORD dwSize = SIZEOF(dwValue);
  491. BOOL fDefault = FALSE;
  492. SHRegGetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
  493. TEXT("ProxyEnable"), NULL, (LPBYTE)&dwValue, &dwSize, FALSE, (LPVOID) &fDefault, SIZEOF(fDefault));
  494. fRetOnProxy = dwValue;
  495. return fRetOnProxy;
  496. }
  497. /*******************************************************************
  498. NAME: SetBindfFlagsBasedOnAmbient
  499. SYNOPSIS: sets BINDF_OFFLINE if ambient offline and
  500. not-connected and sets BINDF_GETFROMCACHE_IF_NET_FAIL
  501. if ambient offline and connected
  502. ********************************************************************/
  503. void SetBindfFlagsBasedOnAmbient(BOOL fAmbientOffline, DWORD *grfBINDF)
  504. {
  505. if (fAmbientOffline)
  506. {
  507. DWORD dwConnectedStateFlags;
  508. // We want to set the offline bindf flag if the ambient flag is set
  509. // and we're currently not connected.
  510. //
  511. // If either of these conditions is not true, clear the offline flag
  512. // as mshtml may have previously set it.
  513. if (FALSE == InternetGetConnectedState(&dwConnectedStateFlags, 0))
  514. {
  515. *grfBINDF |= BINDF_OFFLINEOPERATION;
  516. *grfBINDF &= ~BINDF_GETFROMCACHE_IF_NET_FAIL;
  517. }
  518. else
  519. {
  520. *grfBINDF |= BINDF_GETFROMCACHE_IF_NET_FAIL;
  521. *grfBINDF &= ~BINDF_OFFLINEOPERATION;
  522. }
  523. }
  524. else
  525. {
  526. *grfBINDF &= ~BINDF_OFFLINEOPERATION;
  527. }
  528. }
  529. /*******************************************************************
  530. NAME: BuildBindInfo
  531. SYNOPSIS: Fills out a BINDINFO structure for a URL moniker
  532. NOTES: The point of having this in a global helper function is
  533. so we don't have to duplicate this code in multiple
  534. implementations of IBindStatusCallback.
  535. The caller must pass in an IUnknown to be used as the
  536. pUnkForRelease in the STGMEDIUM for post data. If there
  537. is post data, this function will AddRef the passed-in
  538. IUnknown and return it in the STGMEDIUM structure. The
  539. caller (or someone else, if the caller hands it off) must
  540. ultimately call Release on pbindinfo->stgmediumData.pUnkForRelease.
  541. ********************************************************************/
  542. HRESULT BuildBindInfo(DWORD *grfBINDF,BINDINFO *pbindinfo,HGLOBAL hszPostData,
  543. DWORD cbPostData, BOOL bFrameIsOffline, BOOL bFrameIsSilent, BOOL bHyperlink, LPUNKNOWN pUnkForRelease)
  544. {
  545. DWORD dwConnectedStateFlags = 0;
  546. ASSERT(grfBINDF);
  547. ASSERT(pbindinfo);
  548. ASSERT(pUnkForRelease);
  549. HRESULT hres=S_OK;
  550. if (!grfBINDF || !pbindinfo || !pbindinfo->cbSize)
  551. return E_INVALIDARG;
  552. // clear BINDINFO except cbSize
  553. ASSERT(sizeof(*pbindinfo) == pbindinfo->cbSize);
  554. DWORD cbSize = pbindinfo->cbSize;
  555. ZeroMemory(pbindinfo, cbSize);
  556. pbindinfo->cbSize = cbSize;
  557. *grfBINDF |= BINDF_ASYNCHRONOUS;
  558. if (bHyperlink)
  559. *grfBINDF |= BINDF_HYPERLINK;
  560. SetBindfFlagsBasedOnAmbient(bFrameIsOffline, grfBINDF);
  561. if (bFrameIsSilent)
  562. *grfBINDF |= BINDF_NO_UI;
  563. // default method is GET. Valid ones are _GET, _PUT, _POST, _CUSTOM
  564. pbindinfo->dwBindVerb = BINDVERB_GET;
  565. // get IE-wide UTF-8 policy by calling urlmon
  566. DWORD dwIE = URL_ENCODING_NONE;
  567. DWORD dwOutLen = sizeof(DWORD);
  568. if (S_OK == UrlMkGetSessionOption(
  569. URLMON_OPTION_URL_ENCODING,
  570. &dwIE,
  571. sizeof(DWORD),
  572. &dwOutLen,
  573. NULL))
  574. {
  575. if (dwIE == URL_ENCODING_ENABLE_UTF8)
  576. {
  577. pbindinfo->dwOptions |= BINDINFO_OPTIONS_ENABLE_UTF8;
  578. }
  579. else if (dwIE == URL_ENCODING_DISABLE_UTF8)
  580. {
  581. pbindinfo->dwOptions |= BINDINFO_OPTIONS_DISABLE_UTF8;
  582. }
  583. }
  584. // if we have postdata set, then we assume this is a POST verb
  585. if (hszPostData)
  586. {
  587. pbindinfo->dwBindVerb = BINDVERB_POST;
  588. pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
  589. pbindinfo->stgmedData.hGlobal = hszPostData;
  590. // this count should *NOT* include the terminating NULL
  591. pbindinfo->cbstgmedData = cbPostData;
  592. pbindinfo->stgmedData.pUnkForRelease = pUnkForRelease;
  593. // addref on the IUnknown that's holding onto this data so
  594. // it knows to stick around; caller must call Release
  595. // on the pUnkForRelease when done.
  596. pUnkForRelease->AddRef();
  597. // We will still cache the response, but we do not want to
  598. // read from cache for a POST transaction. This will keep us
  599. // from reading from the cache.
  600. *grfBINDF |= BINDF_GETNEWESTVERSION | BINDF_CONTAINER_NOWRITECACHE;
  601. } else {
  602. ASSERT(pbindinfo->stgmedData.tymed == TYMED_NULL);
  603. ASSERT(pbindinfo->stgmedData.hGlobal == NULL);
  604. ASSERT(pbindinfo->stgmedData.pUnkForRelease == NULL);
  605. }
  606. return hres;
  607. }
  608. #define HDR_LANGUAGE TEXT("Accept-Language:")
  609. #define CRLF TEXT("\x0D\x0A")
  610. #define HDR_LANGUAGE_CRLF TEXT("Accept-Language: %s\x0D\x0A")
  611. /*******************************************************************
  612. NAME: BuildAdditionalHeaders
  613. SYNOPSIS: Builds HTTP headers to be given to URL moniker
  614. ENTRY: pszOurExtraHeaders - headers that we explicitly want to add
  615. *ppwzCombinedHeadersOut - on exit, filled in with
  616. buffer of default headers plus pszOurExtraHeaders.
  617. NOTES: The point of having this in a global helper function is
  618. so we don't have to duplicate this code in multiple
  619. implementations of IBindStatusCallback.
  620. The caller must free *ppwzCombinedHeaders by passing
  621. to URLMON, or calling OleFree
  622. ********************************************************************/
  623. HRESULT BuildAdditionalHeaders(LPCTSTR pszOurExtraHeaders,LPCWSTR * ppwzCombinedHeadersOut)
  624. {
  625. TCHAR szLanguage[80]; // what limit on language?
  626. DWORD dwLanguage = ARRAYSIZE(szLanguage);
  627. static const TCHAR hdr_language[] = HDR_LANGUAGE_CRLF;
  628. TCHAR szHeader[ARRAYSIZE(hdr_language) + ARRAYSIZE(szLanguage)]; // NOTE format string length > wnsprintf length
  629. int cchHeaders = 0;
  630. int cchAddedHeaders = 1; // implied '\0'
  631. HRESULT hres = NOERROR;
  632. if (!ppwzCombinedHeadersOut)
  633. return E_FAIL;
  634. *ppwzCombinedHeadersOut = NULL;
  635. // If there is no language in the registry, *WE DO NOT SEND THIS HEADER*
  636. // S_OK means szLanguage filled in and returned
  637. // S_FALSE means call succeeded, but there was no language set
  638. // E_* is an error
  639. // We treat S_FALSE and E_* the same, no language header sent.
  640. if (GetAcceptLanguages(szLanguage, &dwLanguage) == S_OK)
  641. {
  642. StringCchPrintf(szHeader, ARRAYSIZE(szHeader), hdr_language, szLanguage);
  643. cchHeaders = lstrlen(szHeader) + 1;
  644. }
  645. if (pszOurExtraHeaders)
  646. {
  647. cchAddedHeaders = lstrlen(pszOurExtraHeaders) + 1;
  648. }
  649. // If we have headers we added or were sent in, we need to Wide 'em and
  650. // give 'em back
  651. if (cchAddedHeaders > 1 || cchHeaders > 0)
  652. {
  653. WCHAR *pwzHeadersForUrlmon = (WCHAR *)CoTaskMemAlloc(sizeof(WCHAR) * (cchHeaders + cchAddedHeaders - 1));
  654. if (pwzHeadersForUrlmon)
  655. {
  656. if (cchHeaders)
  657. {
  658. StrCpyN(pwzHeadersForUrlmon, szHeader, cchHeaders);
  659. }
  660. if (pszOurExtraHeaders)
  661. {
  662. if (cchHeaders)
  663. {
  664. StrCpyN(pwzHeadersForUrlmon + cchHeaders - 1,
  665. pszOurExtraHeaders, cchAddedHeaders);
  666. }
  667. else
  668. {
  669. StrCpyN(pwzHeadersForUrlmon, pszOurExtraHeaders, cchAddedHeaders - 1);
  670. }
  671. }
  672. if (cchHeaders || pszOurExtraHeaders)
  673. *ppwzCombinedHeadersOut = pwzHeadersForUrlmon;
  674. }
  675. else
  676. hres = E_OUTOFMEMORY;
  677. }
  678. else
  679. hres = pszOurExtraHeaders == NULL ? S_OK : E_FAIL;
  680. return hres;
  681. }
  682. /*******************************************************************
  683. NAME: GetHeadersAndPostData
  684. SYNOPSIS: Gets HTTP headers and post data from an IBindStatusCallback
  685. ENTRY: IBindStatusCallback - object to ask for headers and post data
  686. ppszHeaders - on exit, filled in with pointer to headers,
  687. or NULL if none
  688. pstgPostData - pointer to a STGMEDIUM to be filled in with post
  689. data, if any.
  690. NOTES: The caller is responsible for:
  691. - calling LocalFree on *ppszHeaders when done with them
  692. - calling ReleaseStgMedium on pstgPostData when done
  693. with it
  694. ********************************************************************/
  695. HRESULT GetHeadersAndPostData(IBindStatusCallback * pBindStatusCallback,
  696. LPTSTR * ppszHeaders, STGMEDIUM * pstgPostData, DWORD * pdwPostData, BOOL* pfIsPost)
  697. {
  698. HRESULT hr = S_OK;
  699. ASSERT(pBindStatusCallback);
  700. ASSERT(ppszHeaders);
  701. ASSERT(pstgPostData);
  702. ASSERT(pdwPostData);
  703. // clear the out parameters
  704. *ppszHeaders = NULL;
  705. DWORD grfBINDF;
  706. IHttpNegotiate *pinegotiate;
  707. BINDINFO binfo;
  708. binfo.cbSize = sizeof(binfo);
  709. ZeroMemory(pstgPostData, sizeof(*pstgPostData));
  710. *pdwPostData = 0;
  711. hr=pBindStatusCallback->GetBindInfo(&grfBINDF, &binfo);
  712. if (SUCCEEDED(hr)) {
  713. // copy STGMEDIUM with post data to caller
  714. *pstgPostData = binfo.stgmedData;
  715. *pdwPostData = binfo.cbstgmedData;
  716. // clear these so ReleaseBindInfo won't wack it since we are giving it to the caller
  717. ZeroMemory(&binfo.stgmedData, sizeof(STGMEDIUM));
  718. binfo.cbstgmedData = 0;
  719. if (pfIsPost)
  720. {
  721. if (*pdwPostData)
  722. *pfIsPost = TRUE;
  723. else
  724. *pfIsPost = FALSE;
  725. }
  726. hr = pBindStatusCallback->QueryInterface(IID_IHttpNegotiate, (LPVOID *)&pinegotiate);
  727. if (SUCCEEDED(hr))
  728. {
  729. WCHAR *pwzAdditionalHeaders = NULL;
  730. WCHAR wzNull[1];
  731. wzNull[0] = 0;
  732. hr=pinegotiate->BeginningTransaction(wzNull, wzNull, 0, &pwzAdditionalHeaders);
  733. if (SUCCEEDED(hr) && pwzAdditionalHeaders)
  734. {
  735. DWORD cchHeaders;
  736. cchHeaders = lstrlen(pwzAdditionalHeaders) + 1;
  737. // they should *NEVER* be specifying more than a few hundred
  738. // bytes or they're going to fail with a number of HTTP servers!
  739. LPTSTR pszHeaders = (TCHAR *)LocalAlloc(LPTR, cchHeaders*sizeof(TCHAR));
  740. if (pszHeaders)
  741. {
  742. LPTSTR pszNext;
  743. LPTSTR pszLine;
  744. LPTSTR pszLast;
  745. StrCpyN(pszHeaders, pwzAdditionalHeaders, cchHeaders);
  746. pszLine = pszHeaders;
  747. pszLast = pszHeaders + lstrlen(pszHeaders);
  748. while (pszLine < pszLast)
  749. {
  750. pszNext = StrStrI(pszLine, CRLF);
  751. if (pszNext == NULL)
  752. {
  753. // All Headers must be terminated in CRLF!
  754. pszLine[0] = '\0';
  755. break;
  756. }
  757. pszNext += 2;
  758. if (!StrCmpNI(pszLine,HDR_LANGUAGE,16))
  759. {
  760. MoveMemory(pszLine, pszNext, ((pszLast - pszNext) + 1)*sizeof(TCHAR));
  761. break;
  762. }
  763. pszLine = pszNext;
  764. }
  765. // Don't include empty headers
  766. if (pszHeaders[0] == '\0')
  767. {
  768. LocalFree(pszHeaders);
  769. pszHeaders = NULL;
  770. }
  771. }
  772. OleFree(pwzAdditionalHeaders);
  773. *ppszHeaders = pszHeaders;
  774. }
  775. pinegotiate->Release();
  776. }
  777. ReleaseBindInfo(&binfo);
  778. }
  779. return hr;
  780. }
  781. /*******************************************************************
  782. NAME: GetTopLevelBindStatusCallback
  783. ENTRY: psp - IServiceProvider of ShellBrowser container to query
  784. ppBindStatusCallback - if successful, filled in with
  785. an IBindStatusCallback on exit
  786. SYNOPSIS: Gets the IBindStatusCallback associated with this top
  787. level browser. This works from within nested frames.
  788. ********************************************************************/
  789. HRESULT GetTopLevelBindStatusCallback(IServiceProvider *psp, IBindStatusCallback **ppBindStatusCallback)
  790. {
  791. IHlinkFrame *phf;
  792. HRESULT hr = psp->QueryService(SID_SHlinkFrame, IID_PPV_ARG(IHlinkFrame, &phf));
  793. if (SUCCEEDED(hr))
  794. {
  795. hr = IUnknown_QueryService(phf, IID_IHlinkFrame, IID_PPV_ARG(IBindStatusCallback, ppBindStatusCallback));
  796. phf->Release();
  797. }
  798. return hr;
  799. }
  800. /*******************************************************************
  801. NAME: GetTopLevelPendingBindStatusCallback
  802. ENTRY: psp - IServiceProvider of ShellBrowser container to query
  803. ppBindStatusCallback - if successful, filled in with
  804. an IBindStatusCallback on exit
  805. SYNOPSIS: Gets the IBindStatusCallback associated with this top
  806. level browser. This works from within nested frames.
  807. ********************************************************************/
  808. HRESULT GetTopLevelPendingBindStatusCallback(IServiceProvider *psp, IBindStatusCallback **ppBindStatusCallback)
  809. {
  810. IHlinkFrame *phf;
  811. HRESULT hr = psp->QueryService(SID_SHlinkFrame, IID_PPV_ARG(IHlinkFrame, &phf));
  812. if (SUCCEEDED(hr))
  813. {
  814. hr = IUnknown_QueryService(phf, SID_PendingBindStatusCallback, IID_PPV_ARG(IBindStatusCallback, ppBindStatusCallback));
  815. phf->Release();
  816. }
  817. return hr;
  818. }
  819. // Global helper function to create a CStubBindStatusCallback
  820. HRESULT CStubBindStatusCallback_Create(LPCWSTR pwzHeaders, LPCBYTE pPostData,
  821. DWORD cbPostData, VARIANT_BOOL bFrameIsOffline, VARIANT_BOOL bFrameIsSilent, BOOL bHyperlink,
  822. DWORD grBindFlags,
  823. CStubBindStatusCallback ** ppBindStatusCallback)
  824. {
  825. ASSERT(ppBindStatusCallback);
  826. *ppBindStatusCallback = new CStubBindStatusCallback(pwzHeaders,pPostData,
  827. cbPostData, bFrameIsOffline, bFrameIsSilent, bHyperlink, grBindFlags);
  828. return (*ppBindStatusCallback ? S_OK : E_OUTOFMEMORY);
  829. }