Source code of Windows XP (NT5)
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.

685 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: stgconn.cxx
  7. //
  8. // Contents: Connection points for Async Storage/Stream Wrappers
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 19-Dec-95 SusiA Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "astghead.cxx"
  18. #pragma hdrstop
  19. #include <sinklist.hxx>
  20. #include <utils.hxx>
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Member: CConnectionPoint::CConnectionPoint, public
  24. //
  25. // Synopsis: Constructor
  26. //
  27. // Arguments:
  28. //
  29. // History: 28-Dec-95 SusiA Created
  30. //
  31. //----------------------------------------------------------------------------
  32. CConnectionPoint::CConnectionPoint()
  33. {
  34. astgDebugOut((DEB_ITRACE, "In CConnectionPoint::CConnectionPoint:%p()\n", this));
  35. _cReferences = 1;
  36. _dwCookie = 0;
  37. _pSinkHead = NULL;
  38. _pParentCP = NULL;
  39. _fCSInitialized = FALSE;
  40. astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::CConnectionPoint\n"));
  41. }
  42. CConnectionPoint::~CConnectionPoint()
  43. {
  44. astgDebugOut((DEB_ITRACE, "In CConnectionPoint::~CConnectionPoint:%p()\n", this));
  45. TakeCS();
  46. if (_pParentCP)
  47. _pParentCP->Release();
  48. // clean up the advise list
  49. CSinkList *psltemp = _pSinkHead;
  50. CSinkList *pslprev = NULL;
  51. while (psltemp)
  52. {
  53. pslprev = psltemp;
  54. psltemp = psltemp->GetNext();
  55. pslprev->GetProgressNotify()->Release();
  56. delete pslprev;
  57. }
  58. if (_fCSInitialized)
  59. {
  60. ReleaseCS();
  61. DeleteCriticalSection(&_csSinkList);
  62. }
  63. astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::~CConnectionPoint\n"));
  64. }
  65. SCODE CConnectionPoint::Init()
  66. {
  67. if (FALSE == _fCSInitialized)
  68. {
  69. __try
  70. {
  71. InitializeCriticalSection(&_csSinkList);
  72. _fCSInitialized = TRUE;
  73. }
  74. __except( EXCEPTION_EXECUTE_HANDLER )
  75. {
  76. return HRESULT_FROM_WIN32( GetExceptionCode() );
  77. }
  78. }
  79. return S_OK;
  80. }
  81. #ifndef ASYNC
  82. void CConnectionPoint::Init(IConnectionPointContainer *pCPC)
  83. {
  84. _pCPC = pCPC;
  85. }
  86. //+---------------------------------------------------------------------------
  87. //
  88. // Member: CConnectionPoint::Notify, public
  89. //
  90. // Synopsis:
  91. //
  92. // Returns: Appropriate status code
  93. //
  94. // History: 14-Jan-96 SusiA Created
  95. // 27-Feb-96 SusiA Moved from Async wrappers
  96. //
  97. //----------------------------------------------------------------------------
  98. SCODE CConnectionPoint::Notify(SCODE scFailure,
  99. IFillLockBytes *piflb,
  100. BOOL fDefaultLockBytes)
  101. {
  102. SCODE sc = S_OK;
  103. BOOL fAccurate = (scFailure == E_PENDING);
  104. ULONG ulWaterMark;
  105. ULONG ulFailurePoint;
  106. HANDLE hNotifyEvent;
  107. if (fDefaultLockBytes)
  108. {
  109. CFillLockBytes *pflb = (CFillLockBytes *)piflb;
  110. pflb->GetFailureInfo(&ulWaterMark,
  111. &ulFailurePoint);
  112. pflb->ReleaseCriticalSection();
  113. while (((sc = NotifySinks(ulWaterMark,
  114. ulFailurePoint,
  115. fAccurate,
  116. STG_S_MONITORING)) == STG_S_BLOCK) ||
  117. (sc == STG_S_MONITORING) ||
  118. // S_OK is a synonym for STG_S_MONITORING
  119. (sc == S_OK))
  120. {
  121. DWORD dwFlags;
  122. // wait for an event to signal
  123. hNotifyEvent = pflb->GetNotificationEvent();
  124. WaitForSingleObject(hNotifyEvent, INFINITE);
  125. pflb->GetTerminationStatus(&dwFlags);
  126. // client terminated call?
  127. if (dwFlags == TERMINATED_ABNORMAL)
  128. return STG_E_INCOMPLETE;
  129. // download is complete
  130. else if (dwFlags == TERMINATED_NORMAL)
  131. return S_OK;
  132. else
  133. {
  134. //Note: Don't overwrite the failure point we recorded
  135. // before, since it may have been changed by some
  136. // other thread.
  137. //Don't need to take the critical section here, since
  138. //we don't care about the current failure point.
  139. ULONG ulFailurePointCurrent;
  140. pflb->GetFailureInfo(&ulWaterMark,
  141. &ulFailurePointCurrent);
  142. // all the data is available now
  143. if (ulWaterMark >= ulFailurePoint)
  144. {
  145. // we won't care what the return value is, so send STG_S_BLOCK,
  146. // and all sinks are will have fOwner == FALSE
  147. NotifySinks(ulWaterMark, ulFailurePoint, fAccurate, STG_S_BLOCK);
  148. break;
  149. }
  150. }
  151. }
  152. }
  153. if ((sc == STG_S_RETRYNOW) || (sc == STG_S_BLOCK) || (sc == STG_S_MONITORING))
  154. return S_OK;
  155. else return sc;
  156. }
  157. #endif
  158. //+---------------------------------------------------------------------------
  159. //
  160. // Member: CConnectionPoint::NotifySinks, public
  161. //
  162. // Synopsis:
  163. //
  164. // Returns: Appropriate status code
  165. //
  166. // History: 23-Feb-96 SusiA Created
  167. //
  168. //----------------------------------------------------------------------------
  169. SCODE CConnectionPoint::NotifySinks(ULONG ulProgressCurrent,
  170. ULONG ulProgressMaximum,
  171. BOOL fAccurate,
  172. SCODE sc)
  173. {
  174. CSinkList *pslTemp;
  175. TakeCS();
  176. // closest node with a connection point that wants to determine
  177. // behavior does
  178. // priority first to last on this Connection Point, then the
  179. // parent connection point.
  180. pslTemp = GetHead();
  181. while (((sc == S_OK) ||(sc == STG_S_MONITORING))
  182. &&(pslTemp!=NULL))
  183. {
  184. sc = pslTemp->GetProgressNotify()
  185. ->OnProgress(ulProgressCurrent, ulProgressMaximum, fAccurate, TRUE);
  186. pslTemp = pslTemp->GetNext();
  187. }
  188. // notify the rest of the connections
  189. while (pslTemp !=NULL)
  190. {
  191. pslTemp->GetProgressNotify()
  192. ->OnProgress(ulProgressCurrent, ulProgressMaximum, fAccurate, FALSE);
  193. pslTemp = pslTemp->GetNext();
  194. }
  195. //call parent storage advise list next
  196. if (_pParentCP)
  197. sc = _pParentCP->NotifySinks(ulProgressCurrent,
  198. ulProgressMaximum,
  199. fAccurate,
  200. sc);
  201. ReleaseCS();
  202. return sc;
  203. }
  204. //+---------------------------------------------------------------------------
  205. //
  206. // Member: CConnectionPoint::QueryInterface, public
  207. //
  208. // Synopsis:
  209. //
  210. // Arguments:
  211. //
  212. // Returns: Appropriate status code
  213. //
  214. // Modifies:
  215. //
  216. // History: 01-Jan-96 SusiA Created
  217. //
  218. // Notes:
  219. //
  220. //----------------------------------------------------------------------------
  221. STDMETHODIMP CConnectionPoint::QueryInterface(REFIID iid, void **ppvObj)
  222. {
  223. SCODE sc = S_OK;
  224. astgDebugOut((DEB_TRACE,
  225. "In CConnectionPoint::QueryInterface:%p()\n",
  226. this));
  227. *ppvObj = NULL;
  228. if ((IsEqualIID(iid, IID_IUnknown)) ||
  229. (IsEqualIID(iid, IID_IDocfileAsyncConnectionPoint)))
  230. {
  231. *ppvObj = (IDocfileAsyncConnectionPoint *)this;
  232. CConnectionPoint::AddRef();
  233. }
  234. else
  235. {
  236. return E_NOINTERFACE;
  237. }
  238. astgDebugOut((DEB_TRACE, "Out CConnectionPoint::QueryInterface\n"));
  239. return ResultFromScode(sc);
  240. }
  241. //+---------------------------------------------------------------------------
  242. //
  243. // Member: CConnectionPoint::AddRef, public
  244. //
  245. // Synopsis:
  246. //
  247. // Arguments:
  248. //
  249. // Returns: Appropriate status code
  250. //
  251. // Modifies:
  252. //
  253. // History: 29-Dec-95 SusiA Created
  254. //
  255. // Notes:
  256. //
  257. //----------------------------------------------------------------------------
  258. STDMETHODIMP_(ULONG) CConnectionPoint::AddRef(void)
  259. {
  260. ULONG ulRet;
  261. astgDebugOut((DEB_TRACE,
  262. "In CConnectionPoint::AddRef:%p()\n",
  263. this));
  264. InterlockedIncrement(&_cReferences);
  265. ulRet = _cReferences;
  266. astgDebugOut((DEB_TRACE, "Out CConnectionPoint::AddRef\n"));
  267. return ulRet;
  268. }
  269. //+---------------------------------------------------------------------------
  270. //
  271. // Member: CConnectionPoint::Release, public
  272. //
  273. // Synopsis:
  274. //
  275. // Arguments:
  276. //
  277. // Returns: Appropriate status code
  278. //
  279. // Modifies:
  280. //
  281. // History: 30-Dec-95 SusiA Created
  282. //
  283. // Notes:
  284. //
  285. //----------------------------------------------------------------------------
  286. STDMETHODIMP_(ULONG) CConnectionPoint::Release(void)
  287. {
  288. LONG lRet;
  289. astgDebugOut((DEB_TRACE,
  290. "In CConnectionPoint::Release:%p()\n",
  291. this));
  292. astgAssert(_cReferences > 0);
  293. lRet = InterlockedDecrement(&_cReferences);
  294. if (lRet == 0)
  295. {
  296. delete this;
  297. }
  298. else if (lRet < 0)
  299. {
  300. astgAssert((lRet > 0) && "Connection point released too many times.");
  301. lRet = 0;
  302. }
  303. astgDebugOut((DEB_TRACE, "Out CConnectionPoint::Release\n"));
  304. return (ULONG)lRet;
  305. }
  306. #ifndef ASYNC
  307. //+---------------------------------------------------------------------------
  308. //
  309. // Member: CConnectionPoint::GetConnectionInterface, public
  310. //
  311. // Synopsis:
  312. //
  313. // Arguments:
  314. //
  315. // Returns: Appropriate status code
  316. //
  317. // Modifies:
  318. //
  319. // History: 30-Dec-95 SusiA Created
  320. //
  321. // Notes:
  322. //
  323. //----------------------------------------------------------------------------
  324. STDMETHODIMP CConnectionPoint::GetConnectionInterface(IID *pIID)
  325. {
  326. astgDebugOut((DEB_ITRACE,
  327. "In CConnectionPoint::GetConnectionInterface:%p()\n",
  328. this));
  329. *pIID = IID_IProgressNotify;
  330. astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::GetConnectionInterface\n"));
  331. return S_OK;
  332. }
  333. //+---------------------------------------------------------------------------
  334. //
  335. // Member: CConnectionPoint::GetConnectionPointContainer, public
  336. //
  337. // Synopsis:
  338. //
  339. // Arguments:
  340. //
  341. // Returns: Appropriate status code
  342. //
  343. // Modifies:
  344. //
  345. // History: 30-Dec-95 SusiA Created
  346. //
  347. // Notes:
  348. //
  349. //----------------------------------------------------------------------------
  350. STDMETHODIMP CConnectionPoint::GetConnectionPointContainer(
  351. IConnectionPointContainer ** ppCPC)
  352. {
  353. astgDebugOut((DEB_ITRACE,
  354. "In CConnectionPoint::GetConnectionPointContainer:%p()\n",
  355. this));
  356. *ppCPC = _pCPC;
  357. _pCPC->AddRef();
  358. astgDebugOut((DEB_ITRACE,
  359. "Out CConnectionPoint::GetConnectionPointContainer\n"));
  360. return S_OK;
  361. }
  362. #endif
  363. //+---------------------------------------------------------------------------
  364. //
  365. // Member: CConnectionPoint::Clone, public
  366. //
  367. // Synopsis:
  368. //
  369. // Arguments:
  370. //
  371. // Returns: Appropriate status code
  372. //
  373. // Modifies:
  374. //
  375. // History: 26-Feb-96 SusiA Created
  376. //
  377. // Notes:
  378. //
  379. //----------------------------------------------------------------------------
  380. SCODE CConnectionPoint::Clone( CConnectionPoint *pcp)
  381. {
  382. SCODE sc = S_OK;
  383. void *pv = NULL;
  384. astgDebugOut((DEB_ITRACE,"In CConnectionPoint::Clone:%p()\n", this));
  385. TakeCS();
  386. pcp->TakeCS();
  387. CSinkList *pslNew = NULL;
  388. CSinkList *pslPrev = NULL;
  389. CSinkList *pslOld = pcp->GetHead();
  390. while (pslOld != NULL)
  391. {
  392. astgMem(pslNew = new CSinkList);
  393. pslNew->SetNext(NULL);
  394. if (pslPrev)
  395. pslPrev->SetNext(pslNew);
  396. else
  397. _pSinkHead = pslNew;
  398. pslPrev = pslNew;
  399. pslNew->SetCookie(pslOld->GetCookie());
  400. //Note: The QueryInterface will give us a reference to hold on to.
  401. astgChk(pslOld->GetProgressNotify()->QueryInterface(IID_IProgressNotify, &pv));
  402. pslNew->SetProgressNotify((IProgressNotify *)pv);
  403. pslOld= pslOld->GetNext();
  404. }
  405. _dwCookie = pcp->GetCookie();
  406. astgDebugOut((DEB_ITRACE,"Out CConnectionPoint::Clone\n"));
  407. Err:
  408. while (_pSinkHead != NULL)
  409. {
  410. CSinkList *pSinkNext = _pSinkHead;
  411. delete _pSinkHead;
  412. _pSinkHead = pSinkNext;
  413. }
  414. pcp->ReleaseCS();
  415. ReleaseCS();
  416. return sc;
  417. }
  418. //+---------------------------------------------------------------------------
  419. //
  420. // Member: CConnectionPoint:: Advise, public
  421. //
  422. // Synopsis:
  423. //
  424. // Arguments:
  425. //
  426. // Returns: Appropriate status code
  427. //
  428. // Modifies:
  429. //
  430. // History: 29-Dec-95 SusiA Created
  431. //
  432. // Notes:
  433. //
  434. //----------------------------------------------------------------------------
  435. #ifdef ASYNC
  436. STDMETHODIMP CConnectionPoint::AddConnection(IProgressNotify *pSink,
  437. DWORD *pdwCookie)
  438. #else
  439. STDMETHODIMP CConnectionPoint::Advise(IUnknown *pUnkSink,
  440. DWORD *pdwCookie)
  441. #endif
  442. {
  443. SCODE sc = S_OK;
  444. CSinkList *pslNew = NULL;
  445. CSinkList *pslTemp = _pSinkHead;
  446. astgDebugOut((DEB_ITRACE, "In CConnectionPoint::Advise:%p()\n", this));
  447. TakeCS();
  448. IProgressNotify *ppn;
  449. astgMem(pslNew = new CSinkList);
  450. *pdwCookie = ++_dwCookie;
  451. pslNew->SetCookie(*pdwCookie);
  452. #ifdef ASYNC
  453. pSink->AddRef();
  454. pslNew->SetProgressNotify(pSink);
  455. #else
  456. void *pv;
  457. //Note: The QueryInterface will give us a reference to hold on to.
  458. astgChk(pUnkSink->QueryInterface(IID_IProgressNotify, &pv));
  459. pslNew->SetProgressNotify((IProgressNotify *)pv);
  460. #endif
  461. //Add new node to end of list
  462. if (pslTemp == NULL)
  463. _pSinkHead = pslNew;
  464. else
  465. {
  466. while(pslTemp->GetNext() != NULL)
  467. pslTemp = pslTemp->GetNext();
  468. pslTemp->SetNext(pslNew);
  469. }
  470. ReleaseCS();
  471. astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::Advise\n"));
  472. return sc;
  473. Err:
  474. ReleaseCS();
  475. delete pslNew;
  476. return sc;
  477. }
  478. //+---------------------------------------------------------------------------
  479. //
  480. // Member: CConnectionPoint::Unadvise, public
  481. //
  482. // Synopsis:
  483. //
  484. // Arguments:
  485. //
  486. // Returns: Appropriate status code
  487. //
  488. // Modifies:
  489. //
  490. // History: 30-Dec-95 SusiA Created
  491. //
  492. // Notes:
  493. //
  494. //----------------------------------------------------------------------------
  495. #ifdef ASYNC
  496. STDMETHODIMP CConnectionPoint::RemoveConnection(DWORD dwCookie)
  497. #else
  498. STDMETHODIMP CConnectionPoint::Unadvise(DWORD dwCookie)
  499. #endif
  500. {
  501. CSinkList *pslTemp;
  502. CSinkList *pslPrev;
  503. astgDebugOut((DEB_ITRACE, "In CConnectionPoint::Unadvise:%p()\n", this));
  504. TakeCS();
  505. pslTemp = _pSinkHead;
  506. pslPrev = NULL;
  507. while ((pslTemp != NULL) && (pslTemp->GetCookie() != dwCookie))
  508. {
  509. pslPrev = pslTemp;
  510. pslTemp = pslTemp->GetNext();
  511. }
  512. if (pslTemp != NULL)
  513. {
  514. //Found the sink. Delete it from the list.
  515. if (pslPrev != NULL)
  516. {
  517. pslPrev->SetNext(pslTemp->GetNext());
  518. }
  519. else
  520. {
  521. _pSinkHead = pslTemp->GetNext();
  522. }
  523. pslTemp->GetProgressNotify()->Release();
  524. delete pslTemp;
  525. }
  526. else
  527. { //Client passed in unknown cookie.
  528. ReleaseCS();
  529. return E_UNEXPECTED;
  530. }
  531. ReleaseCS();
  532. astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::Unadvise\n"));
  533. return S_OK;
  534. }
  535. #ifndef ASYNC
  536. //+---------------------------------------------------------------------------
  537. //
  538. // Member: CConnectionPoint::EnumConnections, public
  539. //
  540. // Synopsis:
  541. //
  542. // Arguments:
  543. //
  544. // Returns: Appropriate status code
  545. //
  546. // Modifies:
  547. //
  548. // History: 30-Dec-95 SusiA Created
  549. //
  550. // Notes:
  551. //
  552. //----------------------------------------------------------------------------
  553. STDMETHODIMP CConnectionPoint::EnumConnections(
  554. IEnumConnections **ppEnum)
  555. {
  556. astgDebugOut((DEB_ITRACE, "In CConnectionPoint::EnumConnections:%p()\n", this));
  557. astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::EnumConnections\n"));
  558. return E_NOTIMPL;
  559. }
  560. #endif
  561. #ifdef ASYNC
  562. STDMETHODIMP CConnectionPoint::GetParent(IDocfileAsyncConnectionPoint **ppdacp)
  563. {
  564. *ppdacp = _pParentCP;
  565. return S_OK;
  566. }
  567. #endif
  568. void CConnectionPoint::TakeCS(void)
  569. {
  570. astgAssert (_fCSInitialized);
  571. EnterCriticalSection(&_csSinkList);
  572. }
  573. void CConnectionPoint::ReleaseCS(void)
  574. {
  575. astgAssert (_fCSInitialized);
  576. LeaveCriticalSection(&_csSinkList);
  577. }