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.

2147 lines
53 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: URLOSTRM.CXX
  7. //
  8. // Contents: Public interface and implementation of the URL
  9. // Open Stream APIs
  10. //
  11. // Classes: many (see below)
  12. //
  13. // Functions:
  14. //
  15. // History: 04-22-96 VictorS Created
  16. // 05-16-96 Jobi Modified
  17. // 06-06-96 Jobi Modified
  18. // 07-05-96 Ramesh Modified
  19. //----------------------------------------------------------------------------
  20. #ifndef unix
  21. // For some reaon on unix this causes NOERROR compile errors
  22. #include "winerror.h"
  23. #endif /* unix */
  24. #include "ocidl.h"
  25. #include "servprov.h"
  26. #include "tchar.h"
  27. #include "wininet.h"
  28. #include "urlmki.h"
  29. #include "urlhlink.h"
  30. #include <shlwapi.h>
  31. #include <shlwapip.h>
  32. #define URLOSTRM_DONOT_NOTIFY_ONDATA 0xFF
  33. #define URLOSTRM_NOTIFY_ONDATA 0x00
  34. //----------------------------------------------------------//
  35. // //
  36. // This file can never be compiled with the _UNICODE or //
  37. // UNICODE macros defined. //
  38. // //
  39. //----------------------------------------------------------//
  40. //----------------------------------------------------------//
  41. // MACROS
  42. //----------------------------------------------------------//
  43. // These macros can go away when macros and implementation of
  44. // the InetSDK has settled down...
  45. #define IS_E_PENDING(x) (x == E_PENDING)
  46. #define LPUOSCALLBACK LPBINDSTATUSCALLBACK
  47. #define PUMPREAD(strm) \
  48. { \
  49. DWORD dwSize = 0; \
  50. char * x = new char[20]; \
  51. hr = strm->Read(x, 20, &dwSize ); \
  52. if( !IS_E_PENDING(hr) && (dwSize != 0) ) \
  53. { \
  54. DPRINTF( ("Data on the over read! %d\n", dwSize) ); \
  55. } \
  56. delete x; \
  57. }
  58. #define HANDLE_ABORT(hr) \
  59. { if( hr == E_ABORT) \
  60. { m_bInAbort = 1; \
  61. if( m_binding ) \
  62. m_binding->Abort(); \
  63. return(E_ABORT); \
  64. } \
  65. }
  66. #define CHECK_MEMORY(ptr) \
  67. { if( !ptr ) \
  68. { DPRINTF( ("Failed to alloc memory") ); \
  69. m_bInAbort = 1; \
  70. if( m_binding ) \
  71. m_binding->Abort(); \
  72. return(E_OUTOFMEMORY); \
  73. } \
  74. }
  75. //
  76. // Refcount helper
  77. //
  78. // Standardized COM Ref counting. ASSUMES that class has a ULONG
  79. // data member called 'm_ref'.
  80. #define IMPLEMENT_REFCOUNT(clsname) \
  81. STDMETHOD_(ULONG, AddRef)() \
  82. { CHECK_INTERFACE(this); \
  83. DPRINTF( ("(%#08x) " #clsname "::Addref %d\n", this, m_ref+1) );\
  84. return(++m_ref); }\
  85. STDMETHOD_(ULONG, Release)()\
  86. { CHECK_INTERFACE(this); \
  87. DPRINTF( ( "(%#08x) " #clsname "::Release : %d\n", this, m_ref-1) );\
  88. if( !--m_ref )\
  89. { delete this; return 0; }\
  90. return m_ref;\
  91. }
  92. //----------------------------------------------------------
  93. //
  94. // DEBUG MACROS
  95. //
  96. //----------------------------------------------------------
  97. #ifdef _DEBUG
  98. // Check the validity of a pointer - use this for all allocated memory
  99. #define CHECK_POINTER(val) \
  100. if (!(val) || IsBadWritePtr((void *)(val), sizeof(void *))) \
  101. { DPRINTF( ("BAD POINTER: %s!\n", #val ) ); \
  102. return E_POINTER; }
  103. // Check the validity of an interface pointer. Use this for all pointers
  104. // to C++ objects that are supposed to have vtables.
  105. #define CHECK_INTERFACE(val) \
  106. if (!(val) || IsBadWritePtr((void *)(val), sizeof(void *)) \
  107. || IsBadCodePtr( FARPROC( *((DWORD **)val)) ) ) \
  108. { DPRINTF( ("BAD INTERFACE: %s!\n", #val ) ); \
  109. return E_POINTER; }
  110. // Simple assert. Map this to whatever general
  111. // framework assert you want.
  112. #define UOSASSERT(x) { if(!(x)) dprintf( "Assert in URLOSTRM API: %s\n", #x ); }
  113. #define DUOS OutputDebugString( "URLOSTRM API: " );
  114. #define DPRINTF(x) DUOS dprintf x ;
  115. #ifndef CHECK_METHOD
  116. #define CHECK_METHOD( m, args ) DUOS dprintf( "(%#08x) %s(", this, #m ); dprintf args ; dprintf(")\n");
  117. #endif
  118. #ifndef MEMPRINTF
  119. #define MEMPRINTF(x) DPRINTF(x)
  120. #endif
  121. void dprintf( char * format, ... )
  122. {
  123. char out[1024];
  124. va_list marker;
  125. va_start(marker, format);
  126. wvsprintf(out, format, marker);
  127. va_end(marker);
  128. OutputDebugString( out );
  129. }
  130. #else
  131. #define CHECK_POINTER(x)
  132. #define CHECK_INTERFACE(x)
  133. #define CHECK_METHOD( m, args )
  134. #define UOSASSERT(x)
  135. #define DPRINTF(x)
  136. #define MEMPRINTF(x)
  137. #endif
  138. //----------------------------------------------------------
  139. //
  140. // Local heap stuff
  141. //
  142. //----------------------------------------------------------
  143. // Keeping this here makes this code portable to any .dll
  144. static HANDLE g_hHeap;
  145. #ifdef _DEBUG
  146. // Uncomment the line below for Debug spew of memory stuff
  147. //#define MONITER_MEMALLOC 1
  148. #endif
  149. #ifdef _DEBUG
  150. static void * _cdecl
  151. operator new( size_t size )
  152. {
  153. if( !g_hHeap )
  154. g_hHeap = ::GetProcessHeap();
  155. // Heap alloc is the fastest gun in the west
  156. // for the type of allocations we do here.
  157. void * p = HeapAlloc(g_hHeap, 0, size);
  158. MEMPRINTF( ("operator new(%d) returns(%#08X)\n",size, DWORD(p)) );
  159. return(p);
  160. }
  161. static void _cdecl
  162. operator delete ( void *ptr)
  163. {
  164. MEMPRINTF( ("operator delete(%#08X)\n", DWORD(ptr) ) );
  165. HeapFree(g_hHeap, 0, ptr);
  166. }
  167. #endif
  168. //----------------------------------------------------------
  169. //
  170. // class CBuffer
  171. //
  172. //----------------------------------------------------------
  173. // Generic CBuffer class for quick and dirty mem allocs.
  174. // Caller must check return results.
  175. class CBuffer
  176. {
  177. public:
  178. CBuffer(ULONG cBytes);
  179. ~CBuffer();
  180. void *GetBuffer();
  181. private:
  182. void * m_pBuf;
  183. // we'll use this temp buffer for small cases.
  184. //
  185. char m_szTmpBuf[120];
  186. unsigned m_fHeapAlloc:1;
  187. };
  188. inline
  189. CBuffer::CBuffer(ULONG cBytes)
  190. {
  191. if( !g_hHeap )
  192. g_hHeap = ::GetProcessHeap();
  193. m_pBuf = (cBytes <= 120) ? m_szTmpBuf : HeapAlloc(g_hHeap, 0, cBytes);
  194. m_fHeapAlloc = (cBytes > 120);
  195. }
  196. inline
  197. CBuffer::~CBuffer()
  198. {
  199. if (m_pBuf && m_fHeapAlloc) HeapFree(g_hHeap, 0, m_pBuf);
  200. }
  201. inline
  202. void * CBuffer::GetBuffer()
  203. {
  204. return m_pBuf;
  205. }
  206. //=--------------------------------------------------------------------------=
  207. //
  208. // String ANSI <-> WIDE helper macros
  209. //
  210. // This stuff stolen from marcwan...
  211. //
  212. // allocates a temporary buffer that will disappear when it goes out of scope
  213. // NOTE: be careful of that -- make sure you use the string in the same or
  214. // nested scope in which you created this buffer. people should not use this
  215. // class directly. use the macro(s) below.
  216. //
  217. //=--------------------------------------------------------------------------=
  218. #define MAKE_WIDE(ptrname) \
  219. long __l##ptrname = (lstrlen(ptrname) + 1) * sizeof(WCHAR); \
  220. CBuffer __CBuffer##ptrname(__l##ptrname); \
  221. CHECK_POINTER(__CBuffer##ptrname.GetBuffer()); \
  222. if( !__CBuffer##ptrname.GetBuffer()) \
  223. return( E_OUTOFMEMORY ); \
  224. MultiByteToWideChar(CP_ACP, 0, ptrname, -1, \
  225. (LPWSTR)__CBuffer##ptrname.GetBuffer(), __l##ptrname); \
  226. LPWSTR __w##ptrname = (LPWSTR)__CBuffer##ptrname.GetBuffer()
  227. #define WIDE_NAME(ptrname) __w##ptrname
  228. #define MAKE_ANSI(ptrname) \
  229. long __l##ptrname = (lstrlenW(ptrname)*2 + 1) * sizeof(char); \
  230. CBuffer __CBuffer##ptrname(__l##ptrname); \
  231. CHECK_POINTER(__CBuffer##ptrname.GetBuffer()); \
  232. if( !__CBuffer##ptrname.GetBuffer()) \
  233. return( E_OUTOFMEMORY ); \
  234. WideCharToMultiByte(CP_ACP, 0, ptrname, -1, \
  235. (LPSTR)__CBuffer##ptrname.GetBuffer(), __l##ptrname, NULL, NULL); \
  236. LPSTR __a##ptrname = (LPSTR)__CBuffer##ptrname.GetBuffer()
  237. #define ANSI_NAME(ptrname) __a##ptrname
  238. //----------------------------------------------------------
  239. //
  240. // Misc helper functions
  241. //
  242. //----------------------------------------------------------
  243. // These registry functions are here for support of backdoor
  244. // flags and screamer features.
  245. static HRESULT
  246. GetRegDword( HKEY mainkey, LPCTSTR subkey, LPCTSTR valueName, DWORD * result )
  247. {
  248. HKEY hkey = 0;
  249. DWORD dwDisposition;
  250. LONG dwResult = RegCreateKeyEx(
  251. mainkey, subkey,
  252. 0, // DWORD Reserved, // reserved
  253. 0, // LPTSTR lpClass, // address of class string
  254. REG_OPTION_NON_VOLATILE, // DWORD dwOptions, // special options flag
  255. KEY_ALL_ACCESS, // REGSAM samDesired, // desired security access
  256. 0, // LPSECURITY_ATTRIBUTES lpSecurityAttributes, // address of key security structure
  257. &hkey, // PHKEY phkResult, // address of buffer for opened handle
  258. &dwDisposition // LPDWORD lpdwDisposition // address of disposition value buffer
  259. );
  260. HRESULT hr = dwResult == ERROR_SUCCESS ? NOERROR : E_FAIL;
  261. if( SUCCEEDED(hr) )
  262. {
  263. DWORD dwType;
  264. DWORD dwSize = sizeof(DWORD);
  265. DWORD dwSavedResult = *result;
  266. dwResult = RegQueryValueEx(
  267. hkey, // handle of key to query
  268. valueName,
  269. 0, // LPDWORD lpReserved, // reserved
  270. &dwType, // LPDWORD lpType, // address of buffer for value type
  271. (LPBYTE)result, // LPBYTE lpData, // address of data buffer
  272. &dwSize // LPDWORD lpcbData // address of data buffer size
  273. );
  274. hr = dwResult == ERROR_SUCCESS ? NOERROR : E_FAIL;
  275. if( FAILED(hr) )
  276. *result = dwSavedResult;
  277. }
  278. if( hkey )
  279. RegCloseKey(hkey);
  280. return(hr);
  281. }
  282. static HRESULT
  283. GetDLMRegDWord( LPCTSTR valueName, DWORD * result )
  284. {
  285. return(GetRegDword( HKEY_LOCAL_MACHINE,
  286. _TEXT("Software\\Microsoft\\DownloadManager"),
  287. valueName,
  288. result ) );
  289. }
  290. static HRESULT
  291. MyCreateFile( LPCWSTR filename, HANDLE & hfile )
  292. {
  293. // BUGBUG: in retrospect this should be a ansi function
  294. // not a wide string one.
  295. HRESULT hr = NOERROR;
  296. /**********
  297. MAKE_ANSI( filename );
  298. hfile = ::CreateFileA(
  299. ANSI_NAME(filename), // LPCTSTR lpFileName, // pointer to name of the file
  300. GENERIC_WRITE, // DWORD dwDesiredAccess, // access (read-write) mode
  301. 0, // DWORD dwShareMode, // share mode
  302. 0, // LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security descriptor
  303. CREATE_ALWAYS, // DWORD dwCreationDistribution, // how to create
  304. FILE_ATTRIBUTE_NORMAL, //DWORD dwFlagsAndAttributes, // file attributes
  305. 0 // HANDLE hTemplateFile // handle to file with attributes to copy
  306. );
  307. *************/
  308. hfile = CreateFileWrapW(
  309. filename,
  310. GENERIC_WRITE,
  311. 0,
  312. 0,
  313. CREATE_ALWAYS,
  314. FILE_ATTRIBUTE_NORMAL,
  315. 0
  316. );
  317. // Our code likes HRESULT style error handling
  318. if( hfile == INVALID_HANDLE_VALUE )
  319. hr = MK_E_CANTOPENFILE;
  320. return(hr);
  321. }
  322. //----------------------------------------------------------
  323. //
  324. // BindStatusCallback base class
  325. //
  326. //----------------------------------------------------------
  327. //
  328. // This is the base class for the download objects. It implements
  329. // the url mon callback interface (IBindStatusCallback) and
  330. // IServiceProvider -- which it delegates to the caller's IBSCB.
  331. //
  332. // State flags
  333. class CBaseBSCB : public IBindStatusCallbackMsg,
  334. public IServiceProvider
  335. {
  336. public:
  337. CBaseBSCB( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback );
  338. virtual ~CBaseBSCB();
  339. STDMETHOD(KickOffDownload)( LPCWSTR szURL );
  340. // IUnknown
  341. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObjOut);
  342. IMPLEMENT_REFCOUNT(CBaseBSCB);
  343. // IBindStatusCallback
  344. STDMETHODIMP OnStartBinding(
  345. DWORD grfBSCOption,
  346. IBinding *pib);
  347. STDMETHODIMP GetPriority(
  348. LONG *pnPriority);
  349. STDMETHODIMP OnLowResource(
  350. DWORD reserved);
  351. STDMETHODIMP OnProgress(
  352. ULONG ulProgress,
  353. ULONG ulProgressMax,
  354. ULONG ulStatusCode,
  355. LPCWSTR szStatusText);
  356. STDMETHODIMP OnDataAvailable(
  357. DWORD grfBSCF,
  358. DWORD dwSize,
  359. FORMATETC *pformatetc,
  360. STGMEDIUM *pstgmed);
  361. STDMETHODIMP OnStopBinding(
  362. HRESULT hresult,
  363. LPCWSTR szError);
  364. STDMETHODIMP GetBindInfo(
  365. DWORD *grfBINDF,
  366. BINDINFO *pbindinfo);
  367. STDMETHODIMP OnObjectAvailable(
  368. REFIID riid,
  369. IUnknown *punk);
  370. STDMETHODIMP MessagePending(
  371. DWORD dwPendingType,
  372. DWORD dwPendingRecursion,
  373. DWORD dwReserved);
  374. // IServiceProvider
  375. STDMETHODIMP QueryService(
  376. REFGUID rsid,
  377. REFIID iid,
  378. void **ppvObj);
  379. // Local methods
  380. void Abort();
  381. BOOL IsAborted();
  382. BOOL DownloadDone();
  383. HRESULT FinalResult();
  384. void SetEncodingFlags( ULONG flags );
  385. IUnknown * Caller();
  386. // I guess at one point I thought it would be cool
  387. // to make all of these inlines and isolated from
  388. // the core functionality.
  389. HRESULT SignalOnData( DWORD flags, ULONG size, FORMATETC *pformatetc);
  390. HRESULT SignalOnProgress( ULONG status, ULONG size, ULONG maxSize, LPCWSTR msg );
  391. HRESULT SignalOnStopBinding( HRESULT hr, LPCWSTR msg );
  392. HRESULT SignalOnStartBinding( DWORD grfBSCOption, IBinding *pib);
  393. HRESULT SignalOnGetPriority(LONG*);
  394. HRESULT SignalOnLowResource(DWORD);
  395. HRESULT SignalGetBindInfo(DWORD *grfBINDF,BINDINFO *pbindinfo);
  396. virtual void Neutralize();
  397. ULONG m_ref;
  398. LPUOSCALLBACK m_callback;
  399. IUnknown * m_caller;
  400. IBinding * m_binding;
  401. IServiceProvider * m_callbackServiceProvider;
  402. IBindStatusCallbackMsg *_pBSCBMsg;
  403. BOOL m_bInAbort : 1;
  404. BOOL m_bInCache : 1;
  405. BOOL m_bCheckedForServiceProvider : 1;
  406. DWORD m_readSoFar;
  407. HRESULT m_finalResult;
  408. // See notes above about IStream usage
  409. IStream * m_UserStream;
  410. ULONG m_maxSize;
  411. DWORD m_bscoFlags;
  412. UINT m_encoding;
  413. char m_szCacheFileName[MAX_PATH];
  414. };
  415. /*---------------------*/
  416. /* INLINES */
  417. /*---------------------*/
  418. inline void CBaseBSCB::Abort() { m_bInAbort = 1; }
  419. inline BOOL CBaseBSCB::IsAborted() { return(m_bInAbort); }
  420. inline HRESULT CBaseBSCB::FinalResult(){ return( m_finalResult ); }
  421. inline IUnknown*CBaseBSCB::Caller() { return( m_caller ); }
  422. inline void CBaseBSCB::SetEncodingFlags( ULONG flags ) { m_encoding = flags; }
  423. inline HRESULT
  424. CBaseBSCB::SignalOnData( DWORD flags, ULONG size, FORMATETC *pformatetc )
  425. {
  426. HRESULT hr=NOERROR;
  427. if(m_bscoFlags!=URLOSTRM_NOTIFY_ONDATA)
  428. return(hr);
  429. STGMEDIUM stg;
  430. stg.tymed = TYMED_ISTREAM;
  431. stg.pstm = m_UserStream;
  432. stg.pUnkForRelease = NULL;
  433. if(m_callback)
  434. hr=m_callback->OnDataAvailable(flags,size,pformatetc,&stg);
  435. return(hr);
  436. }
  437. inline HRESULT
  438. CBaseBSCB::SignalOnProgress( ULONG status, ULONG size, ULONG maxSize, LPCWSTR msg )
  439. {
  440. if( !m_callback )
  441. return(NOERROR);
  442. if( size && !maxSize )
  443. maxSize = size;
  444. if( maxSize > m_maxSize )
  445. m_maxSize = maxSize;
  446. HRESULT hr = m_callback->OnProgress( size, m_maxSize, status, msg );
  447. return(hr);
  448. }
  449. inline HRESULT
  450. CBaseBSCB::SignalOnStopBinding( HRESULT hres, LPCWSTR msg )
  451. {
  452. if( !m_callback )
  453. return(NOERROR);
  454. HRESULT hr = m_callback->OnStopBinding( hres, msg );
  455. return(hr);
  456. }
  457. inline HRESULT
  458. CBaseBSCB::SignalOnStartBinding( DWORD grfBSCOption, IBinding *pib)
  459. {
  460. if( !m_callback )
  461. return(NOERROR);
  462. return( m_callback->OnStartBinding(grfBSCOption,pib) );
  463. }
  464. inline HRESULT
  465. CBaseBSCB:: SignalOnGetPriority(LONG* lng)
  466. {
  467. if( !m_callback )
  468. return(E_NOTIMPL);
  469. return(m_callback->GetPriority(lng));
  470. }
  471. inline HRESULT
  472. CBaseBSCB:: SignalOnLowResource(DWORD dw)
  473. {
  474. if( !m_callback )
  475. return( NOERROR );
  476. return( m_callback->OnLowResource(dw) );
  477. }
  478. inline HRESULT
  479. CBaseBSCB::SignalGetBindInfo(DWORD *grfBINDF, BINDINFO * pbindinfo)
  480. {
  481. if( !m_callback )
  482. return(E_NOTIMPL);
  483. return( m_callback->GetBindInfo(grfBINDF, pbindinfo) );
  484. }
  485. /*---------------------*/
  486. /* OUT-OF-LINES */
  487. /*---------------------*/
  488. // Do nothing CTOR
  489. CBaseBSCB::CBaseBSCB
  490. (
  491. IUnknown * caller,
  492. DWORD bscof,
  493. LPUOSCALLBACK callback
  494. )
  495. {
  496. m_binding = 0;
  497. m_ref = 0;
  498. m_bInAbort = 0;
  499. m_bCheckedForServiceProvider = 0;
  500. m_bInCache = 0;
  501. m_readSoFar = 0;
  502. m_UserStream = 0;
  503. m_encoding = 0;
  504. m_bscoFlags = bscof;
  505. m_callbackServiceProvider = 0;
  506. m_szCacheFileName[0] = NULL;
  507. m_finalResult = S_OK;
  508. _pBSCBMsg = 0;
  509. if( (m_callback = callback) != 0 )
  510. m_callback->AddRef();
  511. if( (m_caller = caller) != 0 )
  512. caller->AddRef();
  513. }
  514. // Cleanup just call Neutralize();
  515. CBaseBSCB::~CBaseBSCB()
  516. {
  517. Neutralize();
  518. }
  519. void
  520. CBaseBSCB::Neutralize()
  521. {
  522. if( m_binding )
  523. {
  524. m_binding->Release();
  525. m_binding = 0;
  526. }
  527. if( m_caller )
  528. {
  529. m_caller->Release();
  530. m_caller = 0;
  531. }
  532. if( m_callback )
  533. {
  534. m_callback->Release();
  535. m_callback = 0;
  536. }
  537. if( m_callbackServiceProvider )
  538. {
  539. m_callbackServiceProvider->Release();
  540. m_callbackServiceProvider = 0;
  541. }
  542. if( m_UserStream )
  543. {
  544. m_UserStream->Release();
  545. m_UserStream = 0;
  546. }
  547. if (_pBSCBMsg)
  548. {
  549. _pBSCBMsg->Release();
  550. }
  551. }
  552. // IUnknown::QueryInterface
  553. STDMETHODIMP
  554. CBaseBSCB::QueryInterface
  555. (
  556. const GUID &iid,
  557. void ** ppv
  558. )
  559. {
  560. CHECK_METHOD(CBaseBSCB::QueryInterface, ("") );
  561. if (iid==IID_IUnknown || iid==IID_IBindStatusCallback)
  562. {
  563. *ppv =(IBindStatusCallback*)this;
  564. AddRef();
  565. return(NOERROR);
  566. }
  567. if( iid==IID_IServiceProvider)
  568. {
  569. *ppv =(IServiceProvider*)this;
  570. AddRef();
  571. return(NOERROR);
  572. }
  573. if (iid==IID_IBindStatusCallbackMsg)
  574. {
  575. *ppv =(IBindStatusCallbackMsg*)this;
  576. AddRef();
  577. return(NOERROR);
  578. }
  579. return( E_NOINTERFACE );
  580. }
  581. // IServiceProvider::QueryService
  582. STDMETHODIMP
  583. CBaseBSCB::QueryService
  584. (
  585. REFGUID rsid,
  586. REFIID iid,
  587. void **ppvObj
  588. )
  589. {
  590. CHECK_METHOD(CBaseBSCB::QueryService, ("") );
  591. HRESULT hr = E_NOINTERFACE;
  592. if (iid==IID_IBindStatusCallback)
  593. {
  594. *ppvObj =(IBindStatusCallbackMsg*)this;
  595. AddRef();
  596. return(NOERROR);
  597. }
  598. if( m_callback )
  599. hr = m_callback->QueryInterface( iid, ppvObj );
  600. if( FAILED(hr) && !m_callbackServiceProvider && !m_bCheckedForServiceProvider )
  601. {
  602. m_bCheckedForServiceProvider = 1;
  603. if( m_callback )
  604. {
  605. hr = m_callback->QueryInterface
  606. (
  607. IID_IServiceProvider,
  608. (void**)&m_callbackServiceProvider
  609. );
  610. }
  611. if( SUCCEEDED(hr) && m_callbackServiceProvider )
  612. hr = m_callbackServiceProvider->QueryService(rsid,iid,ppvObj);
  613. else
  614. hr = E_NOINTERFACE; // BUGBUG: what's that error code again?
  615. }
  616. HANDLE_ABORT(hr);
  617. return( hr );
  618. }
  619. // IBindStatusCallback::OnStartBinding
  620. STDMETHODIMP
  621. CBaseBSCB::OnStartBinding
  622. (
  623. DWORD grfBSCOption,
  624. IBinding *pib
  625. )
  626. {
  627. CHECK_METHOD(CBaseBSCB::OnStartBinding, ("flags: %#08x, IBinding: %#08x",grfBSCOption,pib) );
  628. CHECK_INTERFACE(pib);
  629. HRESULT hr = SignalOnStartBinding(grfBSCOption,pib);
  630. // smooth over user's e_not_implemented for when we
  631. // return to urlmon
  632. if( hr == E_NOTIMPL )
  633. hr = NOERROR;
  634. else
  635. HANDLE_ABORT(hr);
  636. if( SUCCEEDED(hr) )
  637. {
  638. pib->AddRef();
  639. m_binding = pib;
  640. }
  641. return( hr );
  642. }
  643. // IBindStatusCallback::GetPriority
  644. STDMETHODIMP
  645. CBaseBSCB::GetPriority
  646. (
  647. LONG *pnPriority
  648. )
  649. {
  650. CHECK_METHOD(CBaseBSCB::GetPriority, ("pnPriority: %#08x", pnPriority) );
  651. CHECK_POINTER(pnPriority);
  652. if (!pnPriority)
  653. return E_POINTER;
  654. HRESULT hr = SignalOnGetPriority(pnPriority);
  655. if( hr == E_NOTIMPL )
  656. {
  657. // only override if caller doesn't implement.
  658. *pnPriority = NORMAL_PRIORITY_CLASS;
  659. hr = NOERROR;
  660. }
  661. else
  662. {
  663. HANDLE_ABORT(hr);
  664. }
  665. return( hr );
  666. }
  667. // IBindStatusCallback::OnLowResource
  668. STDMETHODIMP
  669. CBaseBSCB::OnLowResource( DWORD rsv)
  670. {
  671. CHECK_METHOD(CBaseBSCB::OnLowResource, ("resv: %#08x",rsv) );
  672. HRESULT hr = SignalOnLowResource(rsv);
  673. // Keep downloading...
  674. if( hr == E_NOTIMPL )
  675. hr = NOERROR;
  676. else
  677. HANDLE_ABORT(hr);
  678. return( hr );
  679. }
  680. // IBindStatusCallback::OnStopBinding
  681. STDMETHODIMP
  682. CBaseBSCB::OnStopBinding
  683. (
  684. HRESULT hresult,
  685. LPCWSTR szError
  686. )
  687. {
  688. CHECK_METHOD(CBaseBSCB::OnStopBinding, ("%#08X %ws", hresult, szError ? szError : L"[no error]" ) );
  689. // Store the hresult so we can return it to caller in the
  690. // blocking/sync case.
  691. HRESULT hr = SignalOnStopBinding( m_finalResult = hresult, szError );
  692. if( m_binding )
  693. {
  694. m_binding->Release();
  695. m_binding = 0;
  696. }
  697. if( hr == E_NOTIMPL )
  698. hr = NOERROR;
  699. else
  700. HANDLE_ABORT(hr);
  701. return( hr );
  702. }
  703. // IBindStatusCallback::GetBindInfo
  704. STDMETHODIMP
  705. CBaseBSCB::GetBindInfo
  706. (
  707. DWORD * grfBINDF,
  708. BINDINFO* pbindinfo
  709. )
  710. {
  711. CHECK_METHOD(CBaseBSCB::GetBindInfo, ("grfBINDF: %#08x, pbinfinfo ",grfBINDF) );
  712. CHECK_POINTER(grfBINDF);
  713. CHECK_POINTER(pbindinfo);
  714. *grfBINDF = 0;
  715. HRESULT hr = SignalGetBindInfo(grfBINDF,pbindinfo);
  716. if( SUCCEEDED(hr) || (hr == E_NOTIMPL) )
  717. {
  718. // Let the derived class choose the bind flags
  719. if(m_encoding)
  720. {
  721. *grfBINDF |= m_encoding;
  722. pbindinfo->grfBindInfoF |= m_encoding;
  723. }
  724. hr = NOERROR;
  725. }
  726. HANDLE_ABORT(hr);
  727. return( hr );
  728. }
  729. // IBindStatusCallback::OnObjectAvailable
  730. STDMETHODIMP
  731. CBaseBSCB::OnObjectAvailable
  732. (
  733. REFIID riid,
  734. IUnknown *punk
  735. )
  736. {
  737. // This should never be called
  738. CHECK_METHOD(CBaseBSCB::OnObjectAvailable, ("!") );
  739. UOSASSERT(0 && "This should never be called");
  740. return(NOERROR);
  741. }
  742. STDMETHODIMP
  743. CBaseBSCB::OnProgress
  744. (
  745. ULONG ulProgress,
  746. ULONG ulProgressMax,
  747. ULONG ulStatusCode,
  748. LPCWSTR szStatusText
  749. )
  750. {
  751. CHECK_METHOD(CBaseBSCB::OnProgress, ("!") );
  752. // URL moniker has a habit of passing ZERO
  753. // into ulProgressMax. So.. let's at least
  754. // pass in the amount we have so far...
  755. m_maxSize = ulProgressMax ? ulProgressMax : ulProgress;
  756. // This is useful information for the IStream implementation
  757. if( ulStatusCode == BINDSTATUS_USINGCACHEDCOPY )
  758. m_bInCache = TRUE;
  759. HRESULT hr;
  760. hr = SignalOnProgress( ulStatusCode, ulProgress, ulProgressMax, szStatusText );
  761. if( hr == E_NOTIMPL )
  762. hr = NOERROR;
  763. else
  764. HANDLE_ABORT(hr);
  765. return( hr );
  766. }
  767. // IBindStatusCallback::OnDataAvailable.
  768. STDMETHODIMP
  769. CBaseBSCB::OnDataAvailable
  770. (
  771. DWORD grfBSCF,
  772. DWORD dwSize,
  773. FORMATETC *pformatetc,
  774. STGMEDIUM *pstgmed
  775. )
  776. {
  777. CHECK_METHOD(CBaseBSCB::OnDataAvailable,
  778. ("Flags: %x, dwSize: %d", grfBSCF, dwSize) );
  779. HRESULT hr = NOERROR;
  780. // N.B Assumption here is that the pstgmed->pstm will always be the same
  781. if( !m_UserStream )
  782. {
  783. // We need to bump the refcount every time we
  784. // copy and store the pointer.
  785. m_UserStream = pstgmed->pstm;
  786. m_UserStream->AddRef();
  787. }
  788. if (*m_szCacheFileName == NULL)
  789. {
  790. STATSTG statstg;
  791. DWORD dwVal = 0;
  792. if (m_UserStream->Stat(&statstg,dwVal) == S_OK)
  793. {
  794. if (0==WideCharToMultiByte( CP_ACP, 0, statstg.pwcsName, lstrlenW(statstg.pwcsName)+1, m_szCacheFileName,
  795. MAX_PATH, NULL, NULL))
  796. {
  797. m_szCacheFileName[0] = NULL;
  798. }
  799. if (statstg.pwcsName)
  800. {
  801. CoTaskMemFree(statstg.pwcsName);
  802. statstg.pwcsName = NULL;
  803. }
  804. }
  805. else
  806. m_szCacheFileName[0] = NULL;
  807. }
  808. hr = SignalOnData( grfBSCF, dwSize, pformatetc );
  809. // Tell the blocking state machine we are have data.
  810. // ClearState( WAITING_FOR_DATA );
  811. if( hr == E_NOTIMPL )
  812. hr = NOERROR;
  813. else
  814. HANDLE_ABORT(hr);
  815. return( hr );
  816. }
  817. // IBindStatusCallback::MessagePending.
  818. STDMETHODIMP CBaseBSCB::MessagePending(DWORD dwPendingType, DWORD dwPendingRecursion, DWORD dwReserved)
  819. {
  820. MSG msg;
  821. HRESULT hr = NOERROR;
  822. if (m_callback && !_pBSCBMsg)
  823. {
  824. hr = m_callback->QueryInterface(IID_IBindStatusCallbackMsg, (void **) &_pBSCBMsg);
  825. }
  826. if (_pBSCBMsg && hr == NOERROR )
  827. {
  828. hr = _pBSCBMsg->MessagePending(dwPendingType, dwPendingRecursion, dwReserved );
  829. }
  830. return hr;
  831. }
  832. HRESULT
  833. CBaseBSCB::KickOffDownload( LPCWSTR szURL )
  834. {
  835. HRESULT hr;
  836. IOleObject * pOleObject = 0;
  837. IServiceProvider * pServiceProvider = 0;
  838. BOOL bUseCaller = (Caller() != 0);
  839. IMoniker * pmkr = 0;
  840. IBindCtx * pBndCtx = 0;
  841. CHECK_POINTER(szURL);
  842. UOSASSERT(*szURL);
  843. IStream * pstrm = 0;
  844. // Don't bother if we don't have a caller...
  845. if( bUseCaller )
  846. {
  847. // By convention the we give the caller first crack at service
  848. // provider. The assumption here is that if they implement it
  849. // they have the decency to forward QS's to their container.
  850. hr = Caller()->QueryInterface( IID_IServiceProvider,
  851. (void**)&pServiceProvider );
  852. if( FAILED(hr) )
  853. {
  854. // Ok, now try the 'slow way' : maybe the object is an 'OLE' object
  855. // that knows about it's client site:
  856. hr = Caller()->QueryInterface( IID_IOleObject, (void**)&pOleObject );
  857. if( SUCCEEDED(hr) )
  858. {
  859. IOleClientSite * pClientSite = 0;
  860. hr = pOleObject->GetClientSite(&pClientSite);
  861. if( SUCCEEDED(hr) )
  862. {
  863. // Now see if we have a service provider at that site
  864. hr = pClientSite->QueryInterface
  865. ( IID_IServiceProvider,
  866. (void**)&pServiceProvider );
  867. }
  868. if( pClientSite )
  869. pClientSite->Release();
  870. }
  871. else
  872. {
  873. // Ok, it's not an OLE object, maybe it's one of these
  874. // new fangled 'ObjectWithSites':
  875. IObjectWithSite * pObjWithSite = 0;
  876. hr = Caller()->QueryInterface( IID_IObjectWithSite,
  877. (void**)&pObjWithSite );
  878. if( SUCCEEDED(hr) )
  879. {
  880. // Now see if we have a service provider at that site
  881. hr = pObjWithSite->GetSite(IID_IServiceProvider,
  882. (void**)&pServiceProvider);
  883. }
  884. if( pObjWithSite )
  885. pObjWithSite->Release();
  886. }
  887. if( pOleObject )
  888. pOleObject->Release();
  889. }
  890. // BUGBUG: In the code above we stop looking at one level up --
  891. // this may be too harsh and we should loop on client sites
  892. // until we get to the top...
  893. if( !pServiceProvider )
  894. hr = E_UNEXPECTED;
  895. IBindHost * pBindHost = 0;
  896. // Ok, we have a service provider, let's see if BindHost is
  897. // available. (Here there is some upward delegation going on
  898. // via service provider).
  899. if( SUCCEEDED(hr) )
  900. hr = pServiceProvider->QueryService( SID_SBindHost, IID_IBindHost,
  901. (void**)&pBindHost );
  902. if( pServiceProvider )
  903. pServiceProvider->Release();
  904. pmkr = 0;
  905. if( pBindHost )
  906. {
  907. // This allows the container to actually drive the download
  908. // by creating it's own moniker.
  909. hr = pBindHost->CreateMoniker( LPOLESTR(szURL),NULL, &pmkr,0 );
  910. if( SUCCEEDED(hr) )
  911. {
  912. // This allows containers to hook the download for
  913. // doing progress and aborting
  914. hr = pBindHost->MonikerBindToStorage(pmkr, NULL, this, IID_IStream,(void**)&pstrm);
  915. }
  916. pBindHost->Release();
  917. }
  918. else
  919. {
  920. bUseCaller = 0;
  921. }
  922. }
  923. if( !bUseCaller )
  924. {
  925. // If you are here, then either the caller didn't pass
  926. // a 'caller' pointer or the caller is not in a BindHost
  927. // friendly environment.
  928. hr = ::CreateURLMoniker( 0, szURL, &pmkr );
  929. if( SUCCEEDED(hr) )
  930. hr = ::CreateBindCtx( 0, &pBndCtx );
  931. if( SUCCEEDED(hr) )
  932. {
  933. // Register US (not the caller) as the callback. This allows
  934. // us to hook all notfiications from URL moniker and filter
  935. // and manipulate to our satifisfaction.
  936. hr = ::RegisterBindStatusCallback( pBndCtx, this, 0, 0L );
  937. }
  938. if( SUCCEEDED(hr) )
  939. {
  940. hr = pmkr->BindToStorage( pBndCtx, NULL, IID_IStream, (void**)&pstrm );
  941. // Smooth out the error code
  942. if( IS_E_PENDING(hr) )
  943. hr = S_OK;
  944. }
  945. }
  946. if( pstrm )
  947. pstrm->Release();
  948. if( pmkr )
  949. pmkr->Release();
  950. if( pBndCtx )
  951. pBndCtx->Release();
  952. return(hr);
  953. }
  954. //----------------------------------------------------------
  955. //
  956. // CPullDownload
  957. //
  958. //----------------------------------------------------------
  959. // placeholder for covering the URL moniker anomolies
  960. class CPullDownload : public CBaseBSCB
  961. {
  962. public:
  963. CPullDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback );
  964. STDMETHODIMP GetBindInfo(
  965. DWORD *grfBINDF,
  966. BINDINFO *pbindinfo);
  967. };
  968. inline
  969. CPullDownload::CPullDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback )
  970. : CBaseBSCB(caller,bscof,callback)
  971. {
  972. }
  973. STDMETHODIMP
  974. CPullDownload::GetBindInfo
  975. (
  976. DWORD * grfBINDF,
  977. BINDINFO * pbindinfo
  978. )
  979. {
  980. // pointers are validated in base class
  981. HRESULT hr = CBaseBSCB::GetBindInfo( grfBINDF, pbindinfo );
  982. if( SUCCEEDED(hr))
  983. {
  984. if (*grfBINDF & BINDF_ENFORCERESTRICTED)
  985. *grfBINDF = BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_ASYNCHRONOUS | BINDF_ENFORCERESTRICTED;
  986. else
  987. *grfBINDF = BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_ASYNCHRONOUS;
  988. }
  989. return(hr);
  990. }
  991. //----------------------------------------------------------
  992. //
  993. // Push Stream API
  994. //
  995. //----------------------------------------------------------
  996. //
  997. // Class used for implementing push model downloading when used
  998. // in combination with the CStream object.
  999. //
  1000. // The general design for is this class pumps a
  1001. // CBitBucket object with bits and the CStream object makes
  1002. // those bits available to the caller for reading.
  1003. //
  1004. class CPushDownload : public CBaseBSCB
  1005. {
  1006. public:
  1007. CPushDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback );
  1008. ~CPushDownload();
  1009. STDMETHODIMP GetBindInfo(
  1010. DWORD *grfBINDF,
  1011. BINDINFO *pbindinfo);
  1012. protected:
  1013. // CBaseBSCB
  1014. virtual void Neutralize();
  1015. // IBindStatusCallback
  1016. STDMETHODIMP OnDataAvailable
  1017. (
  1018. DWORD grfBSCF,
  1019. DWORD dwSize,
  1020. FORMATETC * pFmtetc,
  1021. STGMEDIUM * pstgmed
  1022. ) ;
  1023. private:
  1024. HRESULT CleanupPush();
  1025. };
  1026. CPushDownload::CPushDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback )
  1027. : CBaseBSCB(caller,bscof, callback)
  1028. {
  1029. }
  1030. CPushDownload::~CPushDownload()
  1031. {
  1032. CleanupPush();
  1033. }
  1034. void
  1035. CPushDownload::Neutralize()
  1036. {
  1037. // We have to do special cleanup.
  1038. CleanupPush();
  1039. CBaseBSCB::Neutralize();
  1040. }
  1041. HRESULT
  1042. CPushDownload::CleanupPush()
  1043. {
  1044. return(NOERROR);
  1045. }
  1046. STDMETHODIMP
  1047. CPushDownload::OnDataAvailable
  1048. (
  1049. DWORD grfBSCF,
  1050. DWORD dwSize,
  1051. FORMATETC * pFmtetc,
  1052. STGMEDIUM * pstgmed
  1053. )
  1054. {
  1055. HRESULT hr = NOERROR;
  1056. if( SUCCEEDED(hr) && pstgmed->pstm )
  1057. {
  1058. m_UserStream = pstgmed->pstm;
  1059. // Add ref again because we are copying and storing the ptr
  1060. m_UserStream->AddRef();
  1061. }
  1062. if( SUCCEEDED(hr) || IS_E_PENDING(hr) )
  1063. hr = CBaseBSCB::OnDataAvailable(grfBSCF,dwSize,pFmtetc,pstgmed);
  1064. return(hr);
  1065. }
  1066. STDMETHODIMP
  1067. CPushDownload::GetBindInfo
  1068. (
  1069. DWORD * grfBINDF,
  1070. BINDINFO * pbindinfo
  1071. )
  1072. {
  1073. HRESULT hr = CBaseBSCB::GetBindInfo( grfBINDF, pbindinfo );
  1074. // PushDownload can not be ASYNC
  1075. if (*grfBINDF & BINDF_ENFORCERESTRICTED)
  1076. *grfBINDF = BINDF_ENFORCERESTRICTED;
  1077. else
  1078. *grfBINDF = 0;
  1079. return(hr);
  1080. }
  1081. //----------------------------------------------------------
  1082. //
  1083. // Block Stream API
  1084. //
  1085. //----------------------------------------------------------
  1086. class CBlockDownload : public CPushDownload
  1087. {
  1088. public:
  1089. CBlockDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback );
  1090. ~CBlockDownload();
  1091. STDMETHODIMP GetBindInfo(
  1092. DWORD *grfBINDF,
  1093. BINDINFO *pbindinfo);
  1094. HRESULT GetStream( IStream ** ppStream );
  1095. };
  1096. inline
  1097. CBlockDownload::CBlockDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback )
  1098. : CPushDownload(caller,bscof, callback)
  1099. {
  1100. }
  1101. template <class T> inline
  1102. HRESULT CheckThis( T * AThisPtr )
  1103. {
  1104. CHECK_INTERFACE(AThisPtr);
  1105. return(NOERROR);
  1106. }
  1107. CBlockDownload::~CBlockDownload()
  1108. {
  1109. CheckThis(this);
  1110. }
  1111. HRESULT
  1112. CBlockDownload::GetStream( IStream ** ppStream )
  1113. {
  1114. // REMEMBER: If you get this pointer and return it
  1115. // to caller YOU MUST add ref it before handing
  1116. // it back via an API
  1117. HRESULT hr = E_FAIL;
  1118. if( m_UserStream )
  1119. {
  1120. *ppStream = m_UserStream;
  1121. hr = S_OK;
  1122. }
  1123. return( hr );
  1124. }
  1125. STDMETHODIMP
  1126. CBlockDownload::GetBindInfo
  1127. (
  1128. DWORD * grfBINDF,
  1129. BINDINFO * pbindinfo
  1130. )
  1131. {
  1132. HRESULT hr = CBaseBSCB::GetBindInfo( grfBINDF, pbindinfo );
  1133. return(hr);
  1134. }
  1135. //----------------------------------------------------------
  1136. //
  1137. // Download to file
  1138. //
  1139. //----------------------------------------------------------
  1140. //
  1141. // This class implements the File downloading code. It reads from the
  1142. // stream from urlmon and writes every buffer directly to disk.
  1143. //
  1144. class CFileDownload : public CBaseBSCB
  1145. {
  1146. public:
  1147. CFileDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback, LPCWSTR szFileName=0);
  1148. ~CFileDownload();
  1149. void SetFileName(LPCWSTR);
  1150. STDMETHODIMP OnDataAvailable(
  1151. DWORD grfBSCF,
  1152. DWORD dwSize,
  1153. FORMATETC *pformatetc,
  1154. STGMEDIUM *pstgmed);
  1155. STDMETHODIMP GetBindInfo(
  1156. DWORD *grfBINDF,
  1157. BINDINFO *pbindinfo);
  1158. STDMETHOD(KickOffDownload)( LPCWSTR szURL );
  1159. virtual void Neutralize();
  1160. private:
  1161. HRESULT Cleanup();
  1162. unsigned char * m_buffer;
  1163. unsigned long m_bufsize;
  1164. HANDLE m_file;
  1165. LPCWSTR m_filename;
  1166. ULONG m_okFromCache;
  1167. };
  1168. inline void
  1169. CFileDownload::SetFileName(LPCWSTR newFileName)
  1170. {
  1171. // ASSUMES Calls to this class are synchronous
  1172. m_filename = newFileName;
  1173. }
  1174. CFileDownload::CFileDownload
  1175. (
  1176. IUnknown * caller,
  1177. DWORD bscof,
  1178. LPUOSCALLBACK callback,
  1179. LPCWSTR szFileName
  1180. )
  1181. : CBaseBSCB(caller, bscof, callback)
  1182. {
  1183. m_buffer = 0;
  1184. m_bufsize = 0;
  1185. m_file = INVALID_HANDLE_VALUE;
  1186. m_filename = szFileName;
  1187. m_okFromCache = 0;
  1188. }
  1189. CFileDownload::~CFileDownload()
  1190. {
  1191. Cleanup();
  1192. }
  1193. STDMETHODIMP
  1194. CFileDownload::KickOffDownload( LPCWSTR szURL )
  1195. {
  1196. // MAGIC: registry flag determines whether we
  1197. // nuke this guy from the cache or not
  1198. GetDLMRegDWord( _TEXT("CacheOk"), &m_okFromCache );
  1199. return( CBaseBSCB::KickOffDownload(szURL) );
  1200. }
  1201. HRESULT CFileDownload::Cleanup()
  1202. {
  1203. if( m_buffer )
  1204. {
  1205. delete m_buffer;
  1206. m_buffer = 0;
  1207. }
  1208. if( m_file != INVALID_HANDLE_VALUE )
  1209. {
  1210. CloseHandle(m_file);
  1211. m_file = INVALID_HANDLE_VALUE;
  1212. }
  1213. return(NOERROR);
  1214. }
  1215. STDMETHODIMP
  1216. CFileDownload::GetBindInfo
  1217. (
  1218. DWORD * grfBINDF,
  1219. BINDINFO * pbindinfo
  1220. )
  1221. {
  1222. HRESULT hr = CBaseBSCB::GetBindInfo( grfBINDF, pbindinfo );
  1223. if( SUCCEEDED(hr) && !m_okFromCache )
  1224. {
  1225. if (*grfBINDF & BINDF_ENFORCERESTRICTED)
  1226. *grfBINDF = BINDF_ENFORCERESTRICTED | BINDF_PULLDATA;
  1227. else
  1228. *grfBINDF = BINDF_PULLDATA;
  1229. }
  1230. return(hr);
  1231. }
  1232. STDMETHODIMP
  1233. CFileDownload::OnDataAvailable
  1234. (
  1235. DWORD grfBSCF,
  1236. DWORD dwSize,
  1237. FORMATETC *pformatetc,
  1238. STGMEDIUM *pstgmed
  1239. )
  1240. {
  1241. // Pointers are validated in base class
  1242. HRESULT hr = CBaseBSCB::OnDataAvailable(grfBSCF,dwSize,pformatetc,pstgmed);
  1243. if( FAILED(hr) || (dwSize == m_readSoFar) )
  1244. return(hr);
  1245. if( (m_file == INVALID_HANDLE_VALUE) && dwSize )
  1246. {
  1247. CHECK_POINTER(m_filename);
  1248. hr = MyCreateFile(m_filename,m_file);
  1249. if( FAILED(hr) )
  1250. hr = E_ABORT;
  1251. }
  1252. HANDLE_ABORT(hr);
  1253. UOSASSERT( (m_file != INVALID_HANDLE_VALUE) );
  1254. // Only allocate a read buffer if the one we have is not
  1255. // big enough.
  1256. if( m_buffer && (m_bufsize < (dwSize- m_readSoFar+1)) )
  1257. {
  1258. delete m_buffer;
  1259. m_buffer = 0;
  1260. m_bufsize=0;
  1261. }
  1262. if( !m_buffer )
  1263. {
  1264. m_bufsize=dwSize- m_readSoFar+1;
  1265. DPRINTF( ("Allocating read buffer %d\n",m_bufsize) );
  1266. m_buffer = new unsigned char [(dwSize- m_readSoFar+1)];
  1267. }
  1268. CHECK_MEMORY(m_buffer);
  1269. DWORD dwReadThisMuch = dwSize - m_readSoFar;
  1270. DWORD dwActual = 0;
  1271. DWORD dwCurrentRead = 0;
  1272. unsigned char * temp = m_buffer;
  1273. do
  1274. {
  1275. hr = m_UserStream->Read(temp,dwReadThisMuch,&dwActual);
  1276. dwCurrentRead += dwActual;
  1277. dwReadThisMuch -= dwActual;
  1278. temp += dwActual;
  1279. }
  1280. while (!(hr == S_FALSE || hr == E_PENDING) && SUCCEEDED(hr));
  1281. if( dwCurrentRead )
  1282. {
  1283. m_readSoFar += (dwReadThisMuch = dwCurrentRead);
  1284. BOOL bWriteOk = ::WriteFile(
  1285. m_file, // HANDLE hFile, // handle to file to write to
  1286. m_buffer, // LPCVOID lpBuffer, // pointer to data to write to file
  1287. dwReadThisMuch, // DWORD nNumberOfBytesToWrite, // number of bytes to write
  1288. &dwActual, // pointer to number of bytes written
  1289. 0 ); // LPOVERLAPPED lpOverlapped // addr. of structure needed for overlapped
  1290. if( !bWriteOk )
  1291. hr = E_FAIL;
  1292. }
  1293. // PUMPREAD(pstgmed->pstm);
  1294. if (grfBSCF & BSCF_LASTDATANOTIFICATION)
  1295. {
  1296. CloseHandle(m_file);
  1297. m_file = INVALID_HANDLE_VALUE;
  1298. }
  1299. return( hr );
  1300. }
  1301. void
  1302. CFileDownload::Neutralize()
  1303. {
  1304. // We have to do special cleanup.
  1305. Cleanup();
  1306. CBaseBSCB::Neutralize();
  1307. }
  1308. //----------------------------------------------------------
  1309. //
  1310. // Download to Cache file
  1311. // Implementation of the CCacheFileDownload
  1312. //
  1313. //----------------------------------------------------------
  1314. // This class downloads the file to the cache and returns the cache file name
  1315. class CCacheFileDownload : public CBaseBSCB
  1316. {
  1317. public:
  1318. CCacheFileDownload( IUnknown * caller, DWORD bscof, LPUOSCALLBACK callback, LPCWSTR szFileName=0);
  1319. ~CCacheFileDownload();
  1320. STDMETHODIMP OnDataAvailable(
  1321. DWORD grfBSCF,
  1322. DWORD dwSize,
  1323. FORMATETC *pformatetc,
  1324. STGMEDIUM *pstgmed);
  1325. STDMETHODIMP GetBindInfo(
  1326. DWORD *grfBINDF,
  1327. BINDINFO *pbindinfo);
  1328. STDMETHOD(KickOffDownload)( LPCWSTR szURL );
  1329. private:
  1330. DWORD m_readSoFar;
  1331. };
  1332. CCacheFileDownload::CCacheFileDownload
  1333. (
  1334. IUnknown * caller,
  1335. DWORD bscof,
  1336. LPUOSCALLBACK callback,
  1337. LPCWSTR szFileName
  1338. )
  1339. : CBaseBSCB(caller, bscof, callback)
  1340. {
  1341. m_readSoFar=0;
  1342. }
  1343. CCacheFileDownload::~CCacheFileDownload()
  1344. {
  1345. // Cleanup();
  1346. }
  1347. STDMETHODIMP
  1348. CCacheFileDownload::KickOffDownload( LPCWSTR szURL )
  1349. {
  1350. return( CBaseBSCB::KickOffDownload(szURL) );
  1351. }
  1352. STDMETHODIMP
  1353. CCacheFileDownload::GetBindInfo
  1354. (
  1355. DWORD * grfBINDF,
  1356. BINDINFO * pbindinfo
  1357. )
  1358. {
  1359. HRESULT hr = CBaseBSCB::GetBindInfo( grfBINDF, pbindinfo );
  1360. *grfBINDF &= ~BINDF_ASYNCHRONOUS; //to fix MSN 5.0 bug 103719.
  1361. return(hr);
  1362. }
  1363. #define READBLOCKSIZE 8192
  1364. STDMETHODIMP
  1365. CCacheFileDownload::OnDataAvailable
  1366. (
  1367. DWORD grfBSCF,
  1368. DWORD dwSize,
  1369. FORMATETC *pformatetc,
  1370. STGMEDIUM *pstgmed
  1371. )
  1372. {
  1373. // Pointers are validated in base class
  1374. HRESULT hr = CBaseBSCB::OnDataAvailable(grfBSCF,dwSize,pformatetc,pstgmed);
  1375. if( FAILED(hr) || (dwSize == m_readSoFar) )
  1376. return(hr);
  1377. IStream * pstm = pstgmed->pstm;
  1378. if (pstm && dwSize > m_readSoFar)
  1379. {
  1380. DWORD dwToRead = dwSize - m_readSoFar;
  1381. DWORD dwActuallyRead = 1; //initialize to force it into loop
  1382. char* lp = NULL;
  1383. lp = new char[READBLOCKSIZE+1];
  1384. CHECK_MEMORY(lp);
  1385. while (dwActuallyRead)
  1386. {
  1387. dwActuallyRead=0;
  1388. hr = pstm->Read(lp, READBLOCKSIZE, &dwActuallyRead);
  1389. if(hr!=S_OK && hr!=E_PENDING) // If Read Fails then return Error
  1390. break;
  1391. m_readSoFar += dwActuallyRead;
  1392. }
  1393. delete lp;
  1394. }
  1395. return (hr);
  1396. }
  1397. STDAPI
  1398. URLOpenPullStreamW
  1399. (
  1400. LPUNKNOWN caller,
  1401. LPCWSTR szURL,
  1402. DWORD dwReserved,
  1403. LPUOSCALLBACK callback
  1404. )
  1405. {
  1406. CHECK_POINTER(szURL);
  1407. HRESULT hr;
  1408. CPullDownload * download = new CPullDownload(caller,URLOSTRM_NOTIFY_ONDATA,callback);
  1409. CHECK_POINTER(download);
  1410. if( !download )
  1411. hr = E_OUTOFMEMORY;
  1412. else
  1413. {
  1414. download->SetEncodingFlags(dwReserved);
  1415. hr = download->KickOffDownload(szURL);
  1416. }
  1417. return(hr);
  1418. }
  1419. STDAPI
  1420. URLDownloadToFileW
  1421. (
  1422. LPUNKNOWN caller,
  1423. LPCWSTR szURL,
  1424. LPCWSTR szFileName,
  1425. DWORD dwReserved,
  1426. LPUOSCALLBACK callback
  1427. )
  1428. {
  1429. CHECK_POINTER(szURL);
  1430. HRESULT hr;
  1431. CFileDownload * strm = new CFileDownload(caller,URLOSTRM_DONOT_NOTIFY_ONDATA,callback,szFileName);
  1432. CHECK_POINTER(strm);
  1433. if( !strm )
  1434. hr = E_OUTOFMEMORY;
  1435. else
  1436. {
  1437. strm->AddRef(); // So that we have valid handle even after OnStopBinding()
  1438. strm->SetEncodingFlags(dwReserved);
  1439. hr = strm->KickOffDownload(szURL);
  1440. }
  1441. if (strm)
  1442. strm->Release();
  1443. return(hr);
  1444. }
  1445. extern void DoThreadCleanup(BOOL bInThreadDetach);
  1446. extern BOOL g_bNT5OrGreater;
  1447. STDAPI
  1448. URLDownloadToCacheFileW
  1449. (
  1450. LPUNKNOWN caller,
  1451. LPCWSTR szURL,
  1452. LPWSTR szFileName,
  1453. DWORD dwBufLength,
  1454. DWORD dwReserved,
  1455. LPUOSCALLBACK callback
  1456. )
  1457. {
  1458. CHECK_POINTER(szURL);
  1459. HRESULT hr=S_OK;
  1460. BOOL fFileURL = FALSE;
  1461. if (dwBufLength <= 0)
  1462. {
  1463. hr = E_OUTOFMEMORY; // Buffer length invalid
  1464. return hr;
  1465. }
  1466. //
  1467. // 1,2, and 3 are reserved for the constants
  1468. // URLOSTRM_USECACHE, CACHEONLY and GETNEWESTVERSION constants
  1469. // For Compatibility with previous versions
  1470. //
  1471. dwBufLength = (dwBufLength < 4) ? MAX_PATH : dwBufLength;
  1472. szFileName[0] = NULL;
  1473. // For Cache calls
  1474. MAKE_ANSI(szURL);
  1475. CCacheFileDownload * strm = new CCacheFileDownload(caller,dwBufLength,callback,szFileName);
  1476. CHECK_POINTER(strm);
  1477. if( !strm )
  1478. {
  1479. hr = E_OUTOFMEMORY;
  1480. }
  1481. else
  1482. {
  1483. strm->AddRef(); // So that we have valid handle even after OnStopBinding()
  1484. strm->SetEncodingFlags(dwReserved);
  1485. hr = strm->KickOffDownload(szURL);
  1486. }
  1487. if(SUCCEEDED(hr))
  1488. {
  1489. if (*strm->m_szCacheFileName)
  1490. {
  1491. // If it is a file URL we have to convert it to WIN32 file
  1492. CHAR szPath[MAX_PATH];
  1493. DWORD cchPath = MAX_PATH;
  1494. if(SUCCEEDED(PathCreateFromUrl(strm->m_szCacheFileName, szPath, &cchPath, 0)))
  1495. {
  1496. fFileURL = TRUE;
  1497. // url should now look like a DOS path
  1498. if (0==MultiByteToWideChar(CP_ACP, 0,
  1499. szPath,-1,
  1500. szFileName, dwBufLength))
  1501. {
  1502. hr = E_OUTOFMEMORY;
  1503. szFileName[0] = NULL;
  1504. }
  1505. else
  1506. hr=S_OK;
  1507. }
  1508. if (!fFileURL)
  1509. {
  1510. if (0==MultiByteToWideChar(CP_ACP, 0, strm->m_szCacheFileName,
  1511. lstrlen(strm->m_szCacheFileName)+1,
  1512. szFileName, dwBufLength))
  1513. {
  1514. hr = E_OUTOFMEMORY;
  1515. szFileName[0] = NULL;
  1516. }
  1517. else
  1518. hr=S_OK;
  1519. }
  1520. }
  1521. else
  1522. hr = E_FAIL;
  1523. }
  1524. if (strm)
  1525. strm->Release();
  1526. // WinSE QFE #3411
  1527. // At a minimum, we may need to cleanup the notification hwnd created
  1528. // because this thread can become unresponsive if a broadcast message
  1529. // is sent and the client app isn't pumping messages on this thread.
  1530. // We'll go ahead an do a full tls cleanup.
  1531. // If this is NOT NT5 or greater, then our notification window is not a message window.
  1532. // Clean up our thread data if no other activity on this thread.
  1533. //
  1534. if (!g_bNT5OrGreater)
  1535. {
  1536. DoThreadCleanup(FALSE);
  1537. }
  1538. return(hr);
  1539. }
  1540. STDAPI
  1541. URLOpenBlockingStreamW
  1542. (
  1543. LPUNKNOWN caller,
  1544. LPCWSTR szURL,
  1545. LPSTREAM* ppStream,
  1546. DWORD dwReserved,
  1547. LPUOSCALLBACK callback
  1548. )
  1549. {
  1550. CHECK_POINTER(szURL);
  1551. CHECK_POINTER(ppStream);
  1552. HRESULT hr;
  1553. if (!ppStream)
  1554. return E_INVALIDARG;
  1555. CBlockDownload * strm = new CBlockDownload(caller,URLOSTRM_DONOT_NOTIFY_ONDATA,callback);
  1556. CHECK_POINTER(strm);
  1557. if( !strm )
  1558. hr = E_OUTOFMEMORY;
  1559. else
  1560. {
  1561. strm->AddRef();
  1562. strm->SetEncodingFlags(dwReserved);
  1563. hr = strm->KickOffDownload(szURL);
  1564. }
  1565. if( SUCCEEDED(hr) )
  1566. {
  1567. hr = strm->GetStream(ppStream);
  1568. // We add ref this pointer because we are handing
  1569. // it back to the user
  1570. if( SUCCEEDED(hr) )
  1571. (*ppStream)->AddRef();
  1572. }
  1573. if (strm)
  1574. strm->Release();
  1575. return(hr);
  1576. }
  1577. STDAPI
  1578. URLOpenStreamW
  1579. (
  1580. LPUNKNOWN caller,
  1581. LPCWSTR szURL,
  1582. DWORD dwReserved,
  1583. LPUOSCALLBACK callback
  1584. )
  1585. {
  1586. CHECK_POINTER(szURL);
  1587. HRESULT hr;
  1588. CPushDownload * strm = new CPushDownload(caller,URLOSTRM_NOTIFY_ONDATA,callback);
  1589. CHECK_POINTER(strm);
  1590. if( !strm )
  1591. hr = E_OUTOFMEMORY;
  1592. else
  1593. {
  1594. strm->SetEncodingFlags(dwReserved);
  1595. hr = strm->KickOffDownload(szURL);
  1596. }
  1597. return(hr);
  1598. }
  1599. //
  1600. // ANSI VERSION OF PUBLIC API
  1601. //
  1602. STDAPI
  1603. URLOpenPullStreamA
  1604. (
  1605. LPUNKNOWN caller,
  1606. LPCSTR szURL,
  1607. DWORD dwReserved,
  1608. LPUOSCALLBACK callback
  1609. )
  1610. {
  1611. MAKE_WIDE(szURL);
  1612. return( URLOpenPullStreamW(caller, WIDE_NAME(szURL), dwReserved, callback) );
  1613. }
  1614. STDAPI
  1615. URLDownloadToFileA
  1616. (
  1617. LPUNKNOWN caller,
  1618. LPCSTR szURL,
  1619. LPCSTR szFileName,
  1620. DWORD dwReserved,
  1621. LPUOSCALLBACK callback
  1622. )
  1623. {
  1624. MAKE_WIDE(szURL);
  1625. MAKE_WIDE(szFileName);
  1626. return( URLDownloadToFileW( caller, WIDE_NAME(szURL), WIDE_NAME(szFileName),dwReserved, callback ) );
  1627. }
  1628. STDAPI
  1629. URLDownloadToCacheFileA
  1630. (
  1631. LPUNKNOWN caller,
  1632. LPCSTR szURL,
  1633. LPSTR szFileName,
  1634. DWORD dwBufLength,
  1635. DWORD dwReserved,
  1636. LPUOSCALLBACK callback
  1637. )
  1638. {
  1639. HRESULT hr=E_OUTOFMEMORY;
  1640. if (dwBufLength <= 0)
  1641. return hr;
  1642. MAKE_WIDE(szURL);
  1643. LPWSTR lpwszfilename= new WCHAR[MAX_PATH];
  1644. if (lpwszfilename!=NULL)
  1645. {
  1646. hr=URLDownloadToCacheFileW( caller, WIDE_NAME(szURL), lpwszfilename, MAX_PATH, dwReserved, callback );
  1647. if (SUCCEEDED(hr))
  1648. {
  1649. // Convert to ANSI.
  1650. dwBufLength = (dwBufLength < 4) ? MAX_PATH : dwBufLength;
  1651. if (0==WideCharToMultiByte( CP_ACP, 0, lpwszfilename, lstrlenW(lpwszfilename)+1,szFileName,
  1652. dwBufLength, NULL, NULL))
  1653. {
  1654. hr = E_OUTOFMEMORY;
  1655. szFileName[0] = NULL;
  1656. }
  1657. }
  1658. else
  1659. szFileName[0] = NULL;
  1660. delete[] lpwszfilename;
  1661. }
  1662. return(hr);
  1663. }
  1664. STDAPI
  1665. URLOpenBlockingStreamA
  1666. (
  1667. LPUNKNOWN caller,
  1668. LPCSTR szURL,
  1669. LPSTREAM* ppStream,
  1670. DWORD dwReserved,
  1671. LPUOSCALLBACK callback
  1672. )
  1673. {
  1674. MAKE_WIDE(szURL);
  1675. return( URLOpenBlockingStreamW(caller,WIDE_NAME(szURL),ppStream,dwReserved,callback) );
  1676. }
  1677. STDAPI
  1678. URLOpenStreamA
  1679. (
  1680. LPUNKNOWN caller,
  1681. LPCSTR szURL,
  1682. DWORD dwReserved,
  1683. LPUOSCALLBACK callback
  1684. )
  1685. {
  1686. MAKE_WIDE(szURL);
  1687. return( URLOpenStreamW(caller,WIDE_NAME(szURL),dwReserved,callback) );
  1688. }