bindcb.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 31k
Category:

Windows Kernel

Development Platform:

Visual C++

  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.     
  175.     return S_OK;
  176. }
  177. //+---------------------------------------------------------------------------
  178. //
  179. //  Method:     CStubBindStatusCallback::_CanMarshalIID
  180. //
  181. //  Synopsis:   Checks whether this object supports marshalling this IID.
  182. //
  183. //  Arguments:  [riid] --
  184. //
  185. //  Returns:
  186. //
  187. //  History:    1-19-96   JohannP (Johann Posch)   Created
  188. //
  189. //  Notes:
  190. //
  191. //----------------------------------------------------------------------------
  192. inline BOOL CStubBindStatusCallback::_CanMarshalIID(REFIID riid)
  193. {
  194.     // keep this in sync with the QueryInterface
  195.     return (BOOL) (IsEqualIID(riid,IID_IBindStatusCallback) || 
  196.                    IsEqualIID(riid,IID_IUnknown) ||
  197.                    IsEqualIID(riid, IID_IHttpNegotiate));
  198. }
  199. //+---------------------------------------------------------------------------
  200. //
  201. //  Method:     CStubBindStatusCallback::_ValidateMarshalParams
  202. //
  203. //  Synopsis:   Validates the standard set parameters that are passed into most
  204. //              of the IMarshal methods
  205. //
  206. //  Arguments:  [riid] --
  207. //              [pvInterface] --
  208. //              [dwDestContext] --
  209. //              [pvDestContext] --
  210. //              [mshlflags] --
  211. //
  212. //  Returns:
  213. //
  214. //  History:    1-19-96   JohannP (Johann Posch)   Created
  215. //
  216. //  Notes:
  217. //
  218. //----------------------------------------------------------------------------
  219. HRESULT CStubBindStatusCallback::_ValidateMarshalParams(REFIID riid,void *pvInterface,
  220.                     DWORD dwDestContext,void *pvDestContext,DWORD mshlflags)
  221. {
  222.     HRESULT hr = NOERROR;
  223.  
  224.     if (_CanMarshalIID(riid))
  225.     {
  226.         // BUGBUG 10/02/96 chrisfra: ask johannp, should we be supporting future contexts
  227.         // via CoGetStandardMarshal?
  228.         ASSERT((dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_LOCAL || dwDestContext == MSHCTX_NOSHAREDMEM));
  229.         ASSERT((mshlflags == MSHLFLAGS_NORMAL || mshlflags == MSHLFLAGS_TABLESTRONG));
  230.         if (   (dwDestContext != MSHCTX_INPROC && dwDestContext != MSHCTX_LOCAL && dwDestContext != MSHCTX_NOSHAREDMEM)
  231.             || (mshlflags != MSHLFLAGS_NORMAL && mshlflags != MSHLFLAGS_TABLESTRONG))
  232.         {
  233.             hr = E_INVALIDARG;
  234.         }
  235.     }
  236.     else
  237.     {
  238.         hr = E_NOINTERFACE;
  239.     }
  240.     return hr;
  241. }
  242. //+---------------------------------------------------------------------------
  243. //
  244. // IMarshal methods
  245. //
  246. //+---------------------------------------------------------------------------
  247. //
  248. //  Method:     CStubBindStatusCallback::GetUnmarshalClass
  249. //
  250. //  Synopsis:
  251. //
  252. //  Arguments:  [riid] --
  253. //              [pvInterface] --
  254. //              [dwDestContext] --
  255. //              [pvDestContext] --
  256. //              [mshlflags] --
  257. //              [pCid] --
  258. //
  259. //  Returns:
  260. //
  261. //  History:    1-19-96   JohannP (Johann Posch)   Created
  262. //
  263. //  Notes:
  264. //
  265. //----------------------------------------------------------------------------
  266. STDMETHODIMP CStubBindStatusCallback::GetUnmarshalClass(REFIID riid,void *pvInterface,
  267.         DWORD dwDestContext,void *pvDestContext,DWORD mshlflags,CLSID *pCid)
  268. {
  269.     HRESULT hr;
  270.     hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
  271.     if (hr == NOERROR)
  272.     {
  273.         *pCid = (CLSID) CLSID_CStubBindStatusCallback;
  274.     }
  275.     return hr;
  276. }
  277. //+---------------------------------------------------------------------------
  278. //
  279. //  Method:     CStubBindStatusCallback::GetMarshalSizeMax
  280. //
  281. //  Synopsis:
  282. //
  283. //  Arguments:  [void] --
  284. //              [pvInterface] --
  285. //              [dwDestContext] --
  286. //              [pvDestContext] --
  287. //              [mshlflags] --
  288. //              [pSize] --
  289. //
  290. //  Returns:
  291. //
  292. //  History:    1-19-96   JohannP (Johann Posch)   Created
  293. //
  294. //  Notes:
  295. //
  296. //----------------------------------------------------------------------------
  297. STDMETHODIMP CStubBindStatusCallback::GetMarshalSizeMax(REFIID riid,void *pvInterface,
  298.         DWORD dwDestContext,void *pvDestContext,DWORD mshlflags,DWORD *pSize)
  299. {
  300.     HRESULT hr;
  301.     if (pSize == NULL)
  302.     {
  303.         hr = E_INVALIDARG;
  304.     }
  305.     else
  306.     {
  307.         hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
  308.         if (hr == NOERROR)
  309.         {
  310.             // size of fBSCBFlags, grBindFlags, postdata, headers.
  311.             *pSize = (sizeof(DWORD) + 3 * sizeof(DWORD)) + _cbPostData ;
  312.             if (_pszHeaders)
  313.                 *pSize += lstrlen(_pszHeaders) + 1;
  314.         }
  315.     }
  316.     return hr;
  317. }
  318. //+---------------------------------------------------------------------------
  319. //
  320. //  Method:     CStubBindStatusCallback::MarshalInterface
  321. //
  322. //  Synopsis:
  323. //
  324. //  Arguments:  [REFIID] --
  325. //              [riid] --
  326. //              [DWORD] --
  327. //              [void] --
  328. //              [DWORD] --
  329. //              [mshlflags] --
  330. //
  331. //  Returns:
  332. //
  333. //  History:    1-19-96   JohannP (Johann Posch)   Created
  334. //
  335. //  Notes:
  336. //
  337. //----------------------------------------------------------------------------
  338. STDMETHODIMP CStubBindStatusCallback::MarshalInterface(IStream *pistm,REFIID riid,
  339.                                 void *pvInterface,DWORD dwDestContext,
  340.                                 void *pvDestContext,DWORD mshlflags)
  341. {
  342.     HRESULT hr;
  343.     DWORD cbLen;
  344.     DWORD fBSCBFlags;
  345.     hr = _ValidateMarshalParams(riid, pvInterface, dwDestContext,pvDestContext, mshlflags);
  346.     if (hr != NOERROR) goto exitPoint;
  347.     //  Write _grBindFlags
  348.     hr = pistm->Write(&_grBindFlags, sizeof(DWORD), NULL);
  349.     if (hr != NOERROR) goto exitPoint;
  350.     //  Write fBSCBFlags
  351.     fBSCBFlags = (_bFrameIsOffline ? 1 : 0) + (_bFrameIsSilent ? 2 : 0) ;
  352.     hr = pistm->Write(&fBSCBFlags, sizeof(DWORD), NULL);
  353.     if (hr != NOERROR) goto exitPoint;
  354.     //  Write headers
  355.     cbLen = (_pszHeaders ? (lstrlen(_pszHeaders) + 1) * sizeof(TCHAR) : 0);
  356.     hr = pistm->Write(&cbLen, sizeof(DWORD), NULL);
  357.     if (hr != NOERROR) goto exitPoint;
  358.     if (cbLen != 0)
  359.     {
  360.         hr = pistm->Write(_pszHeaders, cbLen, NULL);
  361.         if (hr != NOERROR) goto exitPoint;
  362.     }
  363.     //  Write PostData
  364.     hr = pistm->Write(&_cbPostData, sizeof(DWORD), NULL);
  365.     if (hr != NOERROR) goto exitPoint;
  366.     if (_cbPostData != 0)
  367.     {
  368.         hr = pistm->Write(_hszPostData, _cbPostData, NULL);
  369.         if (hr != NOERROR) goto exitPoint;
  370.     }
  371. exitPoint:
  372.     return hr;
  373. }
  374. //+---------------------------------------------------------------------------
  375. //
  376. //  Method:     CStubBindStatusCallback::UnmarshalInterface
  377. //
  378. //  Synopsis:   Unmarshals an Urlmon interface out of a stream
  379. //
  380. //  Arguments:  [REFIID] --
  381. //              [void] --
  382. //              [ppvObj] --
  383. //
  384. //  Returns:
  385. //
  386. //  History:    1-19-96   JohannP (Johann Posch)   Created
  387. //
  388. //  Notes:
  389. //
  390. //----------------------------------------------------------------------------
  391. STDMETHODIMP CStubBindStatusCallback::UnmarshalInterface(IStream *pistm,REFIID riid,void ** ppvObj)
  392. {
  393.     HRESULT hr = NOERROR;
  394.     DWORD fBSCBFlags;
  395.     if (ppvObj == NULL)
  396.     {
  397.         hr = E_INVALIDARG;
  398.     }
  399.     else if (! _CanMarshalIID(riid))
  400.     {
  401.         *ppvObj = NULL;
  402.         hr = E_NOINTERFACE;
  403.     }
  404.     else
  405.     {
  406.         *ppvObj = NULL;
  407.         DWORD cbLen;
  408.         //  Free old values, if any
  409.         _FreeHeadersAndPostData();
  410.         //  Read _grBindFlags
  411.         hr = pistm->Read(&fBSCBFlags, sizeof(DWORD), NULL);
  412.         if (hr != NOERROR) goto exitPoint;
  413.         _grBindFlags = fBSCBFlags;
  414.         //  Read m_fBSCBFlags
  415.         hr = pistm->Read(&fBSCBFlags, sizeof(DWORD), NULL);
  416.         if (hr != NOERROR) goto exitPoint;
  417.         _bFrameIsOffline = fBSCBFlags & 1 ? 1:0;
  418.         _bFrameIsSilent = fBSCBFlags & 2 ? 1:0;
  419.         //  Read headers
  420.         hr = pistm->Read(&cbLen, sizeof(DWORD), NULL);
  421.         if (hr != NOERROR) goto exitPoint;
  422.         if (cbLen != 0)
  423.         {
  424.             LPTSTR pszData;
  425.             pszData = (LPTSTR) LocalAlloc(LPTR, cbLen);
  426.             if (pszData == NULL)
  427.             {
  428.                 hr = E_OUTOFMEMORY;
  429.                 goto exitPoint;
  430.             }
  431.             hr = pistm->Read(pszData, cbLen, 0);
  432.             if (hr != NOERROR)
  433.             {
  434.                 LocalFree(pszData);
  435.                 goto exitPoint;
  436.             }
  437.             _pszHeaders = pszData;
  438.         }
  439.         //  Read PostData
  440.         hr = pistm->Read(&cbLen, sizeof(DWORD), NULL);
  441.         if (hr != NOERROR) goto exitPoint;
  442.         if (cbLen != 0)
  443.         {
  444.             HGLOBAL hszData;
  445.             // POST data must be HGLOBAL because the StgMedium requires it
  446.             // see bindcb.cpp ::GetBindInfo()
  447.             // This will be freed by the Moniker when it's done with it.
  448.             hszData = GlobalAlloc(GPTR,cbLen);
  449.             if (hszData == NULL)
  450.             {
  451.                 hr = E_OUTOFMEMORY;
  452.                 goto exitPoint;
  453.             }
  454.             hr = pistm->Read(hszData, cbLen, 0);
  455.             if (hr != NOERROR)
  456.             {
  457.                 GlobalFree(hszData);
  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.     //  BUGBUG:  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.         
  509.         // We want to set the offline bindf flag if the ambient flag is set
  510.         // and we're currently not connected.
  511.         //
  512.         // If either of these conditions is not true, clear the offline flag
  513.         // as mshtml may have previously set it.
  514.         if(FALSE == InternetGetConnectedState(&dwConnectedStateFlags, 0))
  515.         {
  516.             *grfBINDF |= BINDF_OFFLINEOPERATION;
  517.             *grfBINDF &= ~BINDF_GETFROMCACHE_IF_NET_FAIL;
  518.         }
  519.         else
  520.         {
  521.             *grfBINDF |= BINDF_GETFROMCACHE_IF_NET_FAIL;
  522.             *grfBINDF &= ~BINDF_OFFLINEOPERATION;   
  523.         }
  524.     }
  525.     else
  526.     {
  527.         *grfBINDF &= ~BINDF_OFFLINEOPERATION;
  528.     }
  529. }
  530. /*******************************************************************
  531.     NAME:       BuildBindInfo
  532.     SYNOPSIS:   Fills out a BINDINFO structure for a URL moniker
  533.     NOTES:      The point of having this in a global helper function is
  534.                 so we don't have to duplicate this code in multiple
  535.                 implementations of IBindStatusCallback.
  536.                 The caller must pass in an IUnknown to be used as the
  537.                 pUnkForRelease in the STGMEDIUM for post data.  If there
  538.                 is post data, this function will AddRef the passed-in
  539.                 IUnknown and return it in the STGMEDIUM structure.  The
  540.                 caller (or someone else, if the caller hands it off) must
  541.                 ultimately call Release on pbindinfo->stgmediumData.pUnkForRelease.
  542. ********************************************************************/
  543. HRESULT BuildBindInfo(DWORD *grfBINDF,BINDINFO *pbindinfo,HGLOBAL hszPostData,
  544.     DWORD cbPostData, BOOL bFrameIsOffline, BOOL bFrameIsSilent, BOOL bHyperlink, LPUNKNOWN pUnkForRelease)
  545. {
  546.     DWORD dwConnectedStateFlags = 0;
  547.     ASSERT(grfBINDF);
  548.     ASSERT(pbindinfo);
  549.     ASSERT(pUnkForRelease);
  550.     HRESULT hres=S_OK;
  551.     if ( !grfBINDF || !pbindinfo || !pbindinfo->cbSize )
  552.         return E_INVALIDARG;
  553.     // clear BINDINFO except cbSize
  554.     ASSERT(sizeof(*pbindinfo) == pbindinfo->cbSize);
  555.     DWORD cbSize = pbindinfo->cbSize;
  556.     ZeroMemory( pbindinfo, cbSize );
  557.     pbindinfo->cbSize = cbSize;
  558.     *grfBINDF |= BINDF_ASYNCHRONOUS;
  559.     if (bHyperlink)
  560.         *grfBINDF |= BINDF_HYPERLINK;
  561.    
  562.     SetBindfFlagsBasedOnAmbient(bFrameIsOffline, grfBINDF);
  563.     
  564.     if(bFrameIsSilent)
  565.         *grfBINDF |= BINDF_NO_UI;   
  566.     // default method is GET.  Valid ones are _GET, _PUT, _POST, _CUSTOM
  567.     pbindinfo->dwBindVerb = BINDVERB_GET;
  568.     // get IE-wide UTF-8 policy by calling urlmon
  569.     DWORD dwIE = URL_ENCODING_NONE;
  570.     DWORD dwOutLen = sizeof(DWORD);
  571.     if( S_OK == UrlMkGetSessionOption(
  572.         URLMON_OPTION_URL_ENCODING,
  573.         &dwIE, 
  574.         sizeof(DWORD),
  575.         &dwOutLen,
  576.         NULL )  )
  577.     {
  578.         if( dwIE == URL_ENCODING_ENABLE_UTF8 )
  579.         {
  580.             pbindinfo->dwOptions |= BINDINFO_OPTIONS_ENABLE_UTF8;
  581.         }
  582.         else 
  583.         if( dwIE == URL_ENCODING_DISABLE_UTF8 )
  584.         {
  585.             pbindinfo->dwOptions |= BINDINFO_OPTIONS_DISABLE_UTF8;
  586.         }
  587.     }
  588.     // if we have postdata set, then we assume this is a POST verb
  589.     if (hszPostData)
  590.     {
  591.         pbindinfo->dwBindVerb = BINDVERB_POST;
  592.         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
  593.         pbindinfo->stgmedData.hGlobal = hszPostData;
  594.         //  this count should *NOT* include the terminating NULL
  595.         pbindinfo->cbstgmedData = cbPostData;
  596.         pbindinfo->stgmedData.pUnkForRelease = pUnkForRelease;
  597.         // addref on the IUnknown that's holding onto this data so
  598.         // it knows to stick around; caller must call Release
  599.         // on the pUnkForRelease when done.
  600.         pUnkForRelease->AddRef(); 
  601.         // We will still cache the response, but we do not want to
  602.         // read from cache for a POST transaction.  This will keep us
  603.         // from reading from the cache.
  604.         *grfBINDF |= BINDF_GETNEWESTVERSION | BINDF_CONTAINER_NOWRITECACHE;
  605.     } else {
  606.         ASSERT(pbindinfo->stgmedData.tymed == TYMED_NULL);
  607.         ASSERT(pbindinfo->stgmedData.hGlobal == NULL);
  608.         ASSERT(pbindinfo->stgmedData.pUnkForRelease == NULL);
  609.     }
  610.     return hres;
  611. }
  612. #define HDR_LANGUAGE     TEXT("Accept-Language:")
  613. #define CRLF             TEXT("x0Dx0A")
  614. #define HDR_LANGUAGE_CRLF     TEXT("Accept-Language: %sx0Dx0A")
  615. /*******************************************************************
  616.     NAME:       BuildAdditionalHeaders
  617.     SYNOPSIS:   Builds HTTP headers to be given to URL moniker
  618.     ENTRY:      pszOurExtraHeaders - headers that we explicitly want to add
  619.                 *ppwzCombinedHeadersOut - on exit, filled in with
  620.                    buffer of default headers plus pszOurExtraHeaders.
  621.     NOTES:      The point of having this in a global helper function is
  622.                 so we don't have to duplicate this code in multiple
  623.                 implementations of IBindStatusCallback.
  624.                 The caller must free *ppwzCombinedHeaders by passing
  625.                 to URLMON, or calling OleFree
  626. ********************************************************************/
  627. HRESULT BuildAdditionalHeaders(LPCTSTR pszOurExtraHeaders,LPCWSTR * ppwzCombinedHeadersOut)
  628. {
  629.     TCHAR   szLanguage[80];   // BUGBUG: what limit on language?
  630.     DWORD   dwLanguage = ARRAYSIZE(szLanguage);
  631.     static const TCHAR hdr_language[] = HDR_LANGUAGE_CRLF;
  632.     TCHAR szHeader[ARRAYSIZE(hdr_language) + ARRAYSIZE(szLanguage)]; // NOTE format string length > wnsprintf length
  633.     int cchHeaders = 0;
  634.     int cchAddedHeaders = 1;  // implied ''
  635.     HRESULT hres = NOERROR;
  636.     if (!ppwzCombinedHeadersOut)
  637.         return E_FAIL;
  638.     *ppwzCombinedHeadersOut = NULL;
  639.     // If there is no language in the registry, *WE DO NOT SEND THIS HEADER*
  640.     // S_OK means szLanguage filled in and returned
  641.     // S_FALSE means call succeeded, but there was no language set
  642.     // E_* is an error
  643.     // We treat S_FALSE and E_* the same, no language header sent.
  644.     if (GetAcceptLanguages(szLanguage, &dwLanguage) == S_OK)
  645.     {
  646.         wnsprintf(szHeader, ARRAYSIZE(szHeader), hdr_language, szLanguage);
  647.         cchHeaders = lstrlen(szHeader) + 1;
  648.     }
  649.     if (pszOurExtraHeaders)
  650.     {
  651.         cchAddedHeaders = lstrlen(pszOurExtraHeaders) + 1;
  652.     }
  653.     // If we have headers we added or were sent in, we need to Wide 'em and
  654.     // give 'em back
  655.     if (cchAddedHeaders > 1 || cchHeaders > 0)
  656.     {
  657.         WCHAR *pwzHeadersForUrlmon = (WCHAR *)CoTaskMemAlloc(sizeof(WCHAR) * (cchHeaders  + cchAddedHeaders - 1));
  658.         if (pwzHeadersForUrlmon)
  659.         {
  660.             if (cchHeaders)
  661.             {
  662.                 StrCpyN(pwzHeadersForUrlmon, szHeader, cchHeaders);
  663.             }
  664.             if (pszOurExtraHeaders)
  665.             {
  666.                 if (cchHeaders)
  667.                 {
  668.                     StrCpyN(pwzHeadersForUrlmon + cchHeaders - 1,
  669.                             pszOurExtraHeaders, cchAddedHeaders);
  670.                 }
  671.                 else
  672.                 {
  673.                     StrCpyN(pwzHeadersForUrlmon, pszOurExtraHeaders, cchAddedHeaders - 1);
  674.                 }
  675.             }
  676.             if (cchHeaders || pszOurExtraHeaders)
  677.                 *ppwzCombinedHeadersOut = pwzHeadersForUrlmon;
  678.         }
  679.         else
  680.             hres = E_OUTOFMEMORY;
  681.     }
  682.     else
  683.         hres = pszOurExtraHeaders == NULL ? S_OK : E_FAIL;
  684.     return hres;
  685. }
  686. /*******************************************************************
  687.     NAME:       GetHeadersAndPostData
  688.     SYNOPSIS:   Gets HTTP headers and post data from an IBindStatusCallback
  689.     ENTRY:      IBindStatusCallback - object to ask for headers and post data
  690.                 ppszHeaders - on exit, filled in with pointer to headers,
  691.                     or NULL if none
  692.                 pstgPostData - pointer to a STGMEDIUM to be filled in with post
  693.                     data, if any.
  694.     NOTES:      The caller is responsible for:
  695.                     - calling LocalFree on *ppszHeaders when done with them
  696.                     - calling ReleaseStgMedium on pstgPostData when done
  697.                       with it
  698. ********************************************************************/
  699. HRESULT GetHeadersAndPostData(IBindStatusCallback * pBindStatusCallback,
  700.     LPTSTR * ppszHeaders, STGMEDIUM * pstgPostData, DWORD * pdwPostData, BOOL* pfIsPost)
  701. {
  702.     HRESULT hr = S_OK;
  703.     ASSERT(pBindStatusCallback);
  704.     ASSERT(ppszHeaders);
  705.     ASSERT(pstgPostData);
  706.     ASSERT(pdwPostData);
  707.     // clear the out parameters
  708.     *ppszHeaders = NULL;
  709.     DWORD grfBINDF;
  710.     IHttpNegotiate *pinegotiate;
  711.     BINDINFO binfo;
  712.     binfo.cbSize = sizeof(binfo);
  713.     ZeroMemory(pstgPostData,sizeof(*pstgPostData));
  714.     *pdwPostData = 0;
  715.     hr=pBindStatusCallback->GetBindInfo(&grfBINDF, &binfo);
  716.     if (SUCCEEDED(hr)) {
  717.         // copy STGMEDIUM with post data to caller
  718.         *pstgPostData = binfo.stgmedData;
  719.         *pdwPostData = binfo.cbstgmedData;
  720.         // clear these so ReleaseBindInfo won't wack it since we are giving it to the caller
  721.         ZeroMemory(&binfo.stgmedData, sizeof(STGMEDIUM));
  722.         binfo.cbstgmedData = 0;
  723.         if (pfIsPost)
  724.         {
  725.             if(*pdwPostData)
  726.                 *pfIsPost = TRUE;
  727.             else
  728.                 *pfIsPost = FALSE;
  729.         }
  730.  
  731.         hr = pBindStatusCallback->QueryInterface(IID_IHttpNegotiate, (LPVOID *)&pinegotiate);
  732.         if (SUCCEEDED(hr))
  733.         {
  734.             WCHAR *pwzAdditionalHeaders = NULL;
  735.             WCHAR wzNull[1];
  736.             wzNull[0] = 0;
  737.             hr=pinegotiate->BeginningTransaction(wzNull, wzNull, 0, &pwzAdditionalHeaders);
  738.             if (SUCCEEDED(hr) && pwzAdditionalHeaders)
  739.             {
  740.                 DWORD cchHeaders;
  741.                 cchHeaders = lstrlen(pwzAdditionalHeaders) + 1;
  742.                 //  they should *NEVER* be specifying more than a few hundred
  743.                 //  bytes or they're going to fail with a number of HTTP servers!
  744.                 LPTSTR pszHeaders = (TCHAR *)LocalAlloc(LPTR, cchHeaders*sizeof(TCHAR));
  745.                 if (pszHeaders)
  746.                 {
  747.                     LPTSTR pszNext;
  748.                     LPTSTR pszLine;
  749.                     LPTSTR pszLast;
  750.                     StrCpyN(pszHeaders, pwzAdditionalHeaders, cchHeaders);
  751.                     pszLine = pszHeaders;
  752.                     pszLast = pszHeaders + lstrlen(pszHeaders);
  753.                     while (pszLine < pszLast)
  754.                     {
  755.                         pszNext = StrStrI(pszLine, CRLF);
  756.                         if (pszNext == NULL)
  757.                         {
  758.                             // All Headers must be terminated in CRLF!
  759.                             pszLine[0] = '';
  760.                             break;
  761.                         }
  762.                         pszNext += 2;
  763.                         if (!StrCmpNI(pszLine,HDR_LANGUAGE,16))
  764.                         {
  765.                             MoveMemory(pszLine, pszNext, ((pszLast - pszNext) + 1)*sizeof(TCHAR));
  766.                             break;
  767.                         }
  768.                         pszLine = pszNext;
  769.                     }
  770.                     // Don't include empty headers
  771.                     if (pszHeaders[0] == '')
  772.                     {
  773.                         LocalFree(pszHeaders);
  774.                         pszHeaders = NULL;
  775.                     }
  776.                 }
  777.                 OleFree(pwzAdditionalHeaders);
  778.                 *ppszHeaders = pszHeaders;
  779.             }
  780.             pinegotiate->Release();
  781.         }
  782.         ReleaseBindInfo(&binfo);
  783.     }
  784.     return hr;
  785. }
  786. /*******************************************************************
  787.     NAME:       GetTopLevelBindStatusCallback
  788.     ENTRY:      psp - IServiceProvider of ShellBrowser container to query
  789.                 ppBindStatusCallback - if successful, filled in with
  790.                    an IBindStatusCallback on exit
  791.     SYNOPSIS:   Gets the IBindStatusCallback associated with this top
  792.                 level browser.  This works from within nested frames.
  793. ********************************************************************/
  794. HRESULT GetTopLevelBindStatusCallback(IServiceProvider * psp,
  795.     IBindStatusCallback ** ppBindStatusCallback)
  796. {
  797.     HRESULT hr;
  798.     IHlinkFrame *phf;
  799.     hr = psp->QueryService(SID_SHlinkFrame, IID_IHlinkFrame, (LPVOID*)&phf);
  800.     if (SUCCEEDED(hr)) {
  801.         hr = IUnknown_QueryService(phf, IID_IHlinkFrame, IID_IBindStatusCallback, (LPVOID*)ppBindStatusCallback);
  802.         phf->Release();
  803.     }
  804.     return hr;
  805. }
  806. /*******************************************************************
  807.     NAME:       GetTopLevelPendingBindStatusCallback
  808.     ENTRY:      psp - IServiceProvider of ShellBrowser container to query
  809.                 ppBindStatusCallback - if successful, filled in with
  810.                    an IBindStatusCallback on exit
  811.     SYNOPSIS:   Gets the IBindStatusCallback associated with this top
  812.                 level browser.  This works from within nested frames.
  813. ********************************************************************/
  814. HRESULT GetTopLevelPendingBindStatusCallback(IServiceProvider * psp,
  815.     IBindStatusCallback ** ppBindStatusCallback)
  816. {
  817.     HRESULT hr;
  818.     IHlinkFrame *phf;
  819.     hr = psp->QueryService(SID_SHlinkFrame, IID_IHlinkFrame, (LPVOID*)&phf);
  820.     if (SUCCEEDED(hr)) {
  821.         hr = IUnknown_QueryService(phf, SID_PendingBindStatusCallback, IID_IBindStatusCallback, (LPVOID*)ppBindStatusCallback);
  822.         phf->Release();
  823.     }
  824.     return hr;
  825. }
  826. // Global helper function to create a CStubBindStatusCallback
  827. HRESULT CStubBindStatusCallback_Create(LPCWSTR pwzHeaders, LPCBYTE pPostData,
  828.     DWORD cbPostData, VARIANT_BOOL bFrameIsOffline, VARIANT_BOOL bFrameIsSilent, BOOL bHyperlink, 
  829.     DWORD grBindFlags,
  830.     CStubBindStatusCallback ** ppBindStatusCallback)
  831. {
  832.     ASSERT(ppBindStatusCallback);
  833.     *ppBindStatusCallback = new CStubBindStatusCallback(pwzHeaders,pPostData,
  834.         cbPostData, bFrameIsOffline, bFrameIsSilent, bHyperlink, grBindFlags);
  835.     return (*ppBindStatusCallback ? S_OK : E_OUTOFMEMORY);
  836. }