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.

1622 lines
45 KiB

  1. //---------------------------------------------------------------------------
  2. // CursorPosition.cpp : CursorPosition implementation
  3. //
  4. // Copyright (c) 1996 Microsoft Corporation, All Rights Reserved
  5. // Developed by Sheridan Software Systems, Inc.
  6. //---------------------------------------------------------------------------
  7. #include "stdafx.h"
  8. #include "Notifier.h"
  9. #include "RSColumn.h"
  10. #include "RSSource.h"
  11. #include "CursMain.h"
  12. #include "ColUpdat.h"
  13. #include "CursPos.h"
  14. #include "fastguid.h"
  15. #include "MSR2C.h"
  16. #include "resource.h"
  17. SZTHISFILE
  18. //=--------------------------------------------------------------------------=
  19. // CVDCursorPosition - Constructor
  20. //
  21. CVDCursorPosition::CVDCursorPosition()
  22. {
  23. m_pCursorMain = NULL;
  24. m_pRowPosition = NULL;
  25. m_pSameRowClone = NULL;
  26. m_dwEditMode = CURSOR_DBEDITMODE_NONE;
  27. m_ppColumnUpdates = NULL;
  28. m_fTempEditMode = FALSE;
  29. m_fConnected = FALSE;
  30. m_dwAdviseCookie = 0;
  31. m_fPassivated = FALSE;
  32. m_fInternalSetRow = FALSE;
  33. #ifdef _DEBUG
  34. g_cVDCursorPositionCreated++;
  35. #endif
  36. }
  37. //=--------------------------------------------------------------------------=
  38. // ~CVDCursorPosition - Destructor
  39. //
  40. CVDCursorPosition::~CVDCursorPosition()
  41. {
  42. Passivate();
  43. #ifdef _DEBUG
  44. g_cVDCursorPositionDestroyed++;
  45. #endif
  46. }
  47. //=--------------------------------------------------------------------------=
  48. // Pasivate when external ref count gets to zero
  49. //
  50. void CVDCursorPosition::Passivate()
  51. {
  52. if (m_fPassivated)
  53. return;
  54. m_fPassivated = TRUE;
  55. DestroyColumnUpdates();
  56. ReleaseCurrentRow();
  57. ReleaseAddRow();
  58. LeaveFamily(); // remove myself from pCursorMain's notification family
  59. if (m_pCursorMain)
  60. m_pCursorMain->Release(); // release associated cursor main object
  61. if (m_fConnected)
  62. DisconnectIRowPositionChange(); // disconnect IRowPosition change
  63. if (m_pRowPosition)
  64. m_pRowPosition->Release(); // release associated row position
  65. }
  66. //=--------------------------------------------------------------------------=
  67. // Create - Create cursor position object
  68. //=--------------------------------------------------------------------------=
  69. // This function creates and initializes a new cursor position object
  70. //
  71. // Parameters:
  72. // pRowPosition - [in] IRowPosition provider (may be NULL)
  73. // pCursorMain - [in] backwards pointer to CVDCursorMain object
  74. // ppCursorPosition - [out] a pointer in which to return pointer to cursor position object
  75. //
  76. // Output:
  77. // HRESULT - S_OK if successful
  78. // E_INVALIDARG bad parameter
  79. // E_OUTOFMEMORY not enough memory to create object
  80. //
  81. // Notes:
  82. //
  83. HRESULT CVDCursorPosition::Create(IRowPosition * pRowPosition,
  84. CVDCursorMain * pCursorMain,
  85. CVDCursorPosition ** ppCursorPosition,
  86. CVDResourceDLL * pResourceDLL)
  87. {
  88. ASSERT_POINTER(pCursorMain, CVDCursorMain)
  89. ASSERT_POINTER(ppCursorPosition, CVDCursorPosition*)
  90. if (!pCursorMain || !ppCursorPosition)
  91. {
  92. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorMove, pResourceDLL);
  93. return E_INVALIDARG;
  94. }
  95. *ppCursorPosition = NULL;
  96. CVDCursorPosition * pCursorPosition = new CVDCursorPosition();
  97. if (!pCursorPosition)
  98. {
  99. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursorMove, pResourceDLL);
  100. return E_OUTOFMEMORY;
  101. }
  102. pCursorPosition->m_pResourceDLL = pResourceDLL;
  103. pCursorPosition->m_pCursorMain = pCursorMain;
  104. pCursorPosition->m_pRowPosition = pRowPosition;
  105. pCursorMain->AddRef(); // add reference to associated cursor main object
  106. if (pRowPosition) // add reference to associated row position (if needed)
  107. {
  108. pRowPosition->AddRef();
  109. // connect IRowPositionChange
  110. HRESULT hr = pCursorPosition->ConnectIRowPositionChange();
  111. if (SUCCEEDED(hr))
  112. pCursorPosition->m_fConnected = TRUE;
  113. }
  114. // add to pCursorMain's notification family
  115. pCursorPosition->JoinFamily(pCursorMain);
  116. pCursorPosition->PositionToFirstRow();
  117. *ppCursorPosition = pCursorPosition;
  118. return S_OK;
  119. }
  120. //=--------------------------------------------------------------------------=
  121. // CreateColumnUpdates - Create array of column update pointers
  122. //
  123. HRESULT CVDCursorPosition::CreateColumnUpdates()
  124. {
  125. const ULONG ulColumns = m_pCursorMain->GetColumnsCount();
  126. m_ppColumnUpdates = new CVDColumnUpdate*[ulColumns];
  127. if (!m_ppColumnUpdates)
  128. {
  129. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursorUpdateARow, m_pResourceDLL);
  130. return E_OUTOFMEMORY;
  131. }
  132. // set all column update pointers to NULL
  133. memset(m_ppColumnUpdates, 0, ulColumns * sizeof(CVDColumnUpdate*));
  134. return S_OK;
  135. }
  136. //=--------------------------------------------------------------------------=
  137. // ResetColumnUpdates - Reset column updates array
  138. //
  139. HRESULT CVDCursorPosition::ResetColumnUpdates()
  140. {
  141. HRESULT hr = S_OK;
  142. if (m_ppColumnUpdates)
  143. {
  144. const ULONG ulColumns = m_pCursorMain->GetColumnsCount();
  145. // set all column update pointers to NULL
  146. for (ULONG ulCol = 0; ulCol < ulColumns; ulCol++)
  147. SetColumnUpdate(ulCol, NULL);
  148. }
  149. else
  150. {
  151. // create array of column update pointers
  152. hr = CreateColumnUpdates();
  153. }
  154. return hr;
  155. }
  156. //=--------------------------------------------------------------------------=
  157. // DestroyColumnUpdates - Destroy column updates and array of update pointers
  158. //
  159. void CVDCursorPosition::DestroyColumnUpdates()
  160. {
  161. if (m_ppColumnUpdates)
  162. {
  163. // set all column update pointers to NULL
  164. ResetColumnUpdates();
  165. // destroy array of column update pointers
  166. delete [] m_ppColumnUpdates;
  167. m_ppColumnUpdates = NULL;
  168. }
  169. }
  170. //=--------------------------------------------------------------------------=
  171. // GetColumnUpdate - Get column update
  172. //
  173. CVDColumnUpdate * CVDCursorPosition::GetColumnUpdate(ULONG ulColumn) const
  174. {
  175. CVDColumnUpdate * pColumnUpdate = NULL;
  176. const ULONG ulColumns = m_pCursorMain->GetColumnsCount();
  177. // make sure column index is in range
  178. if (ulColumn < ulColumns)
  179. pColumnUpdate = m_ppColumnUpdates[ulColumn];
  180. return pColumnUpdate;
  181. }
  182. //=--------------------------------------------------------------------------=
  183. // SetColumnUpdate - Set column update
  184. //
  185. void CVDCursorPosition::SetColumnUpdate(ULONG ulColumn, CVDColumnUpdate * pColumnUpdate)
  186. {
  187. const ULONG ulColumns = m_pCursorMain->GetColumnsCount();
  188. // make sure column index is in range
  189. if (ulColumn < ulColumns)
  190. {
  191. // release update if it already exists
  192. if (m_ppColumnUpdates[ulColumn])
  193. m_ppColumnUpdates[ulColumn]->Release();
  194. // store new column update
  195. m_ppColumnUpdates[ulColumn] = pColumnUpdate;
  196. }
  197. }
  198. //=--------------------------------------------------------------------------=
  199. // PositionToFirstRow
  200. //=--------------------------------------------------------------------------=
  201. // Positions to the first row in the rowset
  202. //
  203. void CVDCursorPosition::PositionToFirstRow()
  204. {
  205. m_bmCurrent.Reset();
  206. ULONG cRowsObtained = 0;
  207. HROW * rghRows = NULL;
  208. BYTE bSpecialBM;
  209. bSpecialBM = DBBMK_FIRST;
  210. HRESULT hr = GetRowsetSource()->GetRowsetLocate()->GetRowsAt(0, 0, sizeof(BYTE), &bSpecialBM, 0,
  211. 1, &cRowsObtained, &rghRows);
  212. if (cRowsObtained)
  213. {
  214. // set current row to first row
  215. SetCurrentHRow(rghRows[0]);
  216. // release hRows and associated memory
  217. GetRowsetSource()->GetRowset()->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL);
  218. g_pMalloc->Free(rghRows);
  219. }
  220. }
  221. //=--------------------------------------------------------------------------=
  222. // ReleaseCurrentRow
  223. //=--------------------------------------------------------------------------=
  224. // Releases old current row
  225. //
  226. void CVDCursorPosition::ReleaseCurrentRow()
  227. {
  228. if (!GetRowsetSource()->IsRowsetValid() ||
  229. m_bmCurrent.GetStatus() != VDBOOKMARKSTATUS_CURRENT)
  230. return;
  231. if (m_bmCurrent.m_hRow)
  232. {
  233. GetRowsetSource()->GetRowset()->ReleaseRows(1, &m_bmCurrent.m_hRow, NULL, NULL, NULL);
  234. m_bmCurrent.m_hRow = NULL;
  235. }
  236. }
  237. //=--------------------------------------------------------------------------=
  238. // ReleaseAddRow
  239. //=--------------------------------------------------------------------------=
  240. // Releases temporary add row
  241. //
  242. void CVDCursorPosition::ReleaseAddRow()
  243. {
  244. if (!GetRowsetSource()->IsRowsetValid())
  245. return;
  246. if (m_bmAddRow.m_hRow)
  247. {
  248. GetRowsetSource()->GetRowset()->ReleaseRows(1, &m_bmAddRow.m_hRow, NULL, NULL, NULL);
  249. m_bmAddRow.m_hRow = NULL;
  250. }
  251. }
  252. //=--------------------------------------------------------------------------=
  253. // SetCurrentRowStatus
  254. //=--------------------------------------------------------------------------=
  255. // Sets status to beginning or end (releasing current hrow)
  256. //
  257. void CVDCursorPosition::SetCurrentRowStatus(WORD wStatus)
  258. {
  259. if (VDBOOKMARKSTATUS_BEGINNING == wStatus ||
  260. VDBOOKMARKSTATUS_END == wStatus)
  261. {
  262. ReleaseCurrentRow();
  263. m_bmCurrent.SetBookmark(wStatus);
  264. }
  265. }
  266. //=--------------------------------------------------------------------------=
  267. // SetCurrentHRow
  268. //=--------------------------------------------------------------------------=
  269. // Reads the bookmark from the hrow and sets the m_bmCurrent
  270. //
  271. // Parameters:
  272. // hRowNew - [in] hrow of new current row
  273. //
  274. // Output:
  275. // HRESULT - S_OK if successful
  276. //
  277. // Notes:
  278. //
  279. HRESULT CVDCursorPosition::SetCurrentHRow(HROW hRowNew)
  280. {
  281. if (!GetRowsetSource()->IsRowsetValid())
  282. {
  283. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  284. return E_FAIL;
  285. }
  286. IRowset * pRowset = GetRowsetSource()->GetRowset();
  287. // allocate buffer for bookmark plus length indicator
  288. BYTE * pBuff = new BYTE[GetCursorMain()->GetMaxBookmarkLen() + sizeof(ULONG)];
  289. if (!pBuff)
  290. {
  291. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  292. return E_OUTOFMEMORY;
  293. }
  294. // get the bookmark data
  295. HRESULT hr = pRowset->GetData(hRowNew,
  296. GetCursorMain()->GetBookmarkAccessor(),
  297. pBuff);
  298. if (S_OK == hr)
  299. {
  300. ReleaseCurrentRow();
  301. pRowset->AddRefRows(1, &hRowNew, NULL, NULL);
  302. ULONG * pulLen = (ULONG*)pBuff;
  303. BYTE * pbmdata = pBuff + sizeof(ULONG);
  304. m_bmCurrent.SetBookmark(VDBOOKMARKSTATUS_CURRENT, hRowNew, pbmdata, *pulLen);
  305. }
  306. else
  307. {
  308. ASSERT_(FALSE);
  309. hr = VDMapRowsetHRtoCursorHR(hr,
  310. IDS_ERR_GETDATAFAILED,
  311. IID_ICursorMove,
  312. pRowset,
  313. IID_IRowset,
  314. m_pResourceDLL);
  315. }
  316. delete [] pBuff;
  317. return hr;
  318. }
  319. //=--------------------------------------------------------------------------=
  320. // IsSameRowAsCurrent - Compares current bookmark to supplied hrow
  321. //=--------------------------------------------------------------------------=
  322. //
  323. // Parameters:
  324. // hRow - [in] hrow to check
  325. // fCacheIfNotSame - [in] If TRUE same hrow in cached CVDBookmark
  326. //
  327. // Output:
  328. // HRESULT - S_OK if both hrows correspond to the same logical row
  329. // S_FALSE if not same row
  330. // E_INVALIDARG
  331. // E_UNEXPECTED
  332. // DB_E_BADROWHANDLE
  333. // DB_E_DELETEDROW
  334. // DB_E_NEWLYINSERTED
  335. //
  336. // Notes:
  337. //
  338. HRESULT CVDCursorPosition::IsSameRowAsCurrent(HROW hRow, BOOL fCacheIfNotSame)
  339. {
  340. if (!GetRowsetSource()->IsRowsetValid())
  341. {
  342. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  343. return E_FAIL;
  344. }
  345. if (m_bmCurrent.IsSameHRow(hRow))
  346. return S_OK;
  347. HRESULT hrSame = S_FALSE;
  348. IRowsetIdentity * pRowsetIdentity = GetRowsetSource()->GetRowsetIdentity();
  349. if (pRowsetIdentity)
  350. {
  351. hrSame = pRowsetIdentity->IsSameRow(hRow, m_bmCurrent.GetHRow());
  352. // return if hrow matches or not cache flag set
  353. if (S_OK == hrSame || !fCacheIfNotSame)
  354. return hrSame;
  355. }
  356. else
  357. if (fCacheIfNotSame)
  358. {
  359. // check if hRow matches cache
  360. if (m_bmCache.IsSameHRow(hRow))
  361. {
  362. // return TRUE if bookmark matches cache
  363. return m_bmCurrent.IsSameBookmark(&m_bmCache) ? S_OK : S_FALSE;
  364. }
  365. }
  366. // allocate buffer for bookmark plus length indicator
  367. BYTE * pBuff = new BYTE[GetCursorMain()->GetMaxBookmarkLen() + sizeof(ULONG)];
  368. if (!pBuff)
  369. {
  370. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  371. return E_OUTOFMEMORY;
  372. }
  373. // get the bookmark data
  374. HRESULT hrWork = GetRowsetSource()->GetRowset()->GetData(hRow, GetCursorMain()->GetBookmarkAccessor(), pBuff);
  375. if (S_OK == hrWork)
  376. {
  377. ULONG * pulLen = (ULONG*)pBuff;
  378. BYTE * pbmdata = pBuff + sizeof(ULONG);
  379. // if IRowsetIdentity isn't supported, compare bookmarks
  380. if (!pRowsetIdentity)
  381. {
  382. DBCOMPARE dbcompare;
  383. hrWork = GetRowsetSource()->GetRowsetLocate()->Compare(0,
  384. m_bmCurrent.GetBookmarkLen(),
  385. m_bmCurrent.GetBookmark(),
  386. *pulLen,
  387. pbmdata,
  388. &dbcompare);
  389. if (SUCCEEDED(hrWork))
  390. {
  391. if (DBCOMPARE_EQ == dbcompare)
  392. hrSame = S_OK;
  393. else
  394. hrSame = S_FALSE;
  395. }
  396. }
  397. if (fCacheIfNotSame && S_OK != hrSame)
  398. m_bmCache.SetBookmark(VDBOOKMARKSTATUS_CURRENT, hRow, pbmdata, *pulLen);
  399. }
  400. else
  401. hrSame = hrWork;
  402. delete [] pBuff;
  403. return hrSame;
  404. }
  405. //=--------------------------------------------------------------------------=
  406. // IsSameRowAsAddRow - Compares addrow bookmark to supplied hrow
  407. //=--------------------------------------------------------------------------=
  408. //
  409. // Parameters:
  410. // hRow - [in] hrow to check
  411. //
  412. // Output:
  413. // HRESULT - S_OK if both hrows correspond to the same logical row
  414. // S_FALSE if not same row
  415. // E_INVALIDARG
  416. // E_UNEXPECTED
  417. // DB_E_BADROWHANDLE
  418. // DB_E_DELETEDROW
  419. // DB_E_NEWLYINSERTED
  420. //
  421. // Notes:
  422. //
  423. HRESULT CVDCursorPosition::IsSameRowAsNew(HROW hRow)
  424. {
  425. if (!GetRowsetSource()->IsRowsetValid())
  426. {
  427. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  428. return E_FAIL;
  429. }
  430. if (m_bmAddRow.IsSameHRow(hRow))
  431. return S_OK;
  432. if (m_bmAddRow.m_hRow == NULL)
  433. return S_FALSE;
  434. HRESULT hrSame = S_FALSE;
  435. IRowsetIdentity * pRowsetIdentity = GetRowsetSource()->GetRowsetIdentity();
  436. if (pRowsetIdentity)
  437. {
  438. hrSame = pRowsetIdentity->IsSameRow(hRow, m_bmAddRow.GetHRow());
  439. // return result
  440. return hrSame;
  441. }
  442. // allocate buffer for bookmark plus length indicator
  443. BYTE * pBuff = new BYTE[GetCursorMain()->GetMaxBookmarkLen() + sizeof(ULONG)];
  444. if (!pBuff)
  445. {
  446. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  447. return E_OUTOFMEMORY;
  448. }
  449. // get the bookmark data
  450. HRESULT hrWork = GetRowsetSource()->GetRowset()->GetData(hRow, GetCursorMain()->GetBookmarkAccessor(), pBuff);
  451. if (S_OK == hrWork)
  452. {
  453. ULONG * pulLen = (ULONG*)pBuff;
  454. BYTE * pbmdata = pBuff + sizeof(ULONG);
  455. // since IRowsetIdentity isn't supported, compare bookmarks
  456. DBCOMPARE dbcompare;
  457. hrWork = GetRowsetSource()->GetRowsetLocate()->Compare(0,
  458. m_bmAddRow.GetBookmarkLen(),
  459. m_bmAddRow.GetBookmark(),
  460. *pulLen,
  461. pbmdata,
  462. &dbcompare);
  463. if (SUCCEEDED(hrWork))
  464. {
  465. if (DBCOMPARE_EQ == dbcompare)
  466. hrSame = S_OK;
  467. else
  468. hrSame = S_FALSE;
  469. }
  470. }
  471. else
  472. hrSame = hrWork;
  473. delete [] pBuff;
  474. return hrSame;
  475. }
  476. //=--------------------------------------------------------------------------=
  477. // SetAddHRow
  478. //=--------------------------------------------------------------------------=
  479. // Reads the bookmark from the hrow and sets the m_bmAddRow
  480. //
  481. // Parameters:
  482. // hRowNew - [in] hrow of new add row
  483. //
  484. // Output:
  485. // HRESULT - S_OK if successful
  486. //
  487. // Notes:
  488. //
  489. HRESULT CVDCursorPosition::SetAddHRow(HROW hRowNew)
  490. {
  491. if (!GetRowsetSource()->IsRowsetValid())
  492. {
  493. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  494. return E_FAIL;
  495. }
  496. IRowset * pRowset = GetRowsetSource()->GetRowset();
  497. // allocate buffer for bookmark plus length indicator
  498. BYTE * pBuff = new BYTE[GetCursorMain()->GetMaxBookmarkLen() + sizeof(ULONG)];
  499. if (!pBuff)
  500. {
  501. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  502. return E_OUTOFMEMORY;
  503. }
  504. // get the bookmark data
  505. HRESULT hr = pRowset->GetData(hRowNew,
  506. GetCursorMain()->GetBookmarkAccessor(),
  507. pBuff);
  508. if (S_OK == hr)
  509. {
  510. ReleaseAddRow();
  511. pRowset->AddRefRows(1, &hRowNew, NULL, NULL);
  512. ULONG * pulLen = (ULONG*)pBuff;
  513. BYTE * pbmdata = pBuff + sizeof(ULONG);
  514. m_bmAddRow.SetBookmark(VDBOOKMARKSTATUS_CURRENT, hRowNew, pbmdata, *pulLen);
  515. }
  516. else
  517. {
  518. ASSERT_(FALSE);
  519. hr = VDMapRowsetHRtoCursorHR(hr,
  520. IDS_ERR_GETDATAFAILED,
  521. IID_ICursorMove,
  522. pRowset,
  523. IID_IRowset,
  524. m_pResourceDLL);
  525. }
  526. delete [] pBuff;
  527. return hr;
  528. }
  529. //=--------------------------------------------------------------------------=
  530. // GetEditRow - Get hRow of the row currently being edited
  531. //
  532. HROW CVDCursorPosition::GetEditRow() const
  533. {
  534. HROW hRow = NULL;
  535. switch (m_dwEditMode)
  536. {
  537. case CURSOR_DBEDITMODE_UPDATE:
  538. hRow = m_bmCurrent.m_hRow;
  539. break;
  540. case CURSOR_DBEDITMODE_ADD:
  541. hRow = m_bmAddRow.m_hRow;
  542. break;
  543. }
  544. return hRow;
  545. }
  546. //=--------------------------------------------------------------------------=
  547. // SetRowPosition - Set new current hRow
  548. //
  549. HRESULT CVDCursorPosition::SetRowPosition(HROW hRow)
  550. {
  551. if (!m_pRowPosition)
  552. return S_OK;
  553. // set new current row (set/clear internal set row flag)
  554. m_fInternalSetRow = TRUE;
  555. HRESULT hr = m_pRowPosition->ClearRowPosition();
  556. if (SUCCEEDED(hr))
  557. hr = m_pRowPosition->SetRowPosition(NULL, hRow, DBPOSITION_OK);
  558. m_fInternalSetRow = FALSE;
  559. return hr;
  560. }
  561. #ifndef VD_DONT_IMPLEMENT_ISTREAM
  562. //=--------------------------------------------------------------------------=
  563. // UpdateEntryIDStream - Update entry identifier from stream
  564. //=--------------------------------------------------------------------------=
  565. // This function updates the entry identifier's data from stream
  566. //
  567. // Parameters:
  568. // pColumn - [in] rowset column pointer
  569. // hRow - [in] the row handle
  570. // pStream - [in] stream pointer
  571. //
  572. // Output:
  573. // HRESULT - S_OK if successful
  574. // E_INVALIDARG bad parameter
  575. // E_OUTOFMEMORY not enough memory
  576. //
  577. HRESULT CVDCursorPosition::UpdateEntryIDStream(CVDRowsetColumn * pColumn, HROW hRow, IStream * pStream)
  578. {
  579. ASSERT_POINTER(pStream, IStream)
  580. IAccessor * pAccessor = GetCursorMain()->GetAccessor();
  581. IRowsetChange * pRowsetChange = GetCursorMain()->GetRowsetChange();
  582. // make sure we have valid accessor and change pointers
  583. if (!pAccessor || !pRowsetChange || !GetCursorMain()->IsRowsetValid())
  584. {
  585. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_IEntryID, m_pResourceDLL);
  586. return E_FAIL;
  587. }
  588. // make sure we have all necessary pointers
  589. if (!pColumn || !pStream)
  590. {
  591. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_IEntryID, m_pResourceDLL);
  592. return E_INVALIDARG;
  593. }
  594. STATSTG statstg;
  595. // retrieve status structure
  596. HRESULT hr = pStream->Stat(&statstg, STATFLAG_NONAME);
  597. if (FAILED(hr))
  598. {
  599. VDSetErrorInfo(IDS_ERR_STATFAILED, IID_IEntryID, m_pResourceDLL);
  600. return E_FAIL;
  601. }
  602. // determine length of data
  603. ULONG cbData = statstg.cbSize.LowPart;
  604. HGLOBAL hData;
  605. // get handle to data
  606. hr = GetHGlobalFromStream(pStream, &hData);
  607. if (FAILED(hr))
  608. return hr;
  609. // get pointer to data
  610. BYTE * pData = (BYTE*)GlobalLock(hData);
  611. DBBINDING binding;
  612. // clear out binding
  613. memset(&binding, 0, sizeof(DBBINDING));
  614. // create value binding
  615. binding.iOrdinal = pColumn->GetOrdinal();
  616. binding.obValue = sizeof(DBSTATUS) + sizeof(ULONG);
  617. binding.obLength = sizeof(DBSTATUS);
  618. binding.obStatus = 0;
  619. binding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  620. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  621. binding.cbMaxLen = cbData;
  622. binding.wType = DBTYPE_BYREF | DBTYPE_BYTES;
  623. HACCESSOR hAccessor;
  624. // create update accessor
  625. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &binding, 0, &hAccessor, NULL);
  626. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_IEntryID, pAccessor, IID_IAccessor, m_pResourceDLL);
  627. if (FAILED(hr))
  628. {
  629. // release pointer to data
  630. GlobalUnlock(hData);
  631. return hr;
  632. }
  633. // create update buffer
  634. BYTE * pBuffer = new BYTE[sizeof(DBSTATUS) + sizeof(ULONG) + sizeof(LPBYTE)];
  635. if (!pBuffer)
  636. {
  637. // release pointer to data
  638. GlobalUnlock(hData);
  639. // release update accessor
  640. pAccessor->ReleaseAccessor(hAccessor, NULL);
  641. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_IEntryID, m_pResourceDLL);
  642. return E_OUTOFMEMORY;
  643. }
  644. // set status, length and value
  645. *(DBSTATUS*)pBuffer = DBSTATUS_S_OK;
  646. *(ULONG*)(pBuffer + sizeof(DBSTATUS)) = cbData;
  647. *(LPBYTE*)(pBuffer + sizeof(DBSTATUS) + sizeof(ULONG)) = pData;
  648. // modify column
  649. hr = pRowsetChange->SetData(hRow, hAccessor, pBuffer);
  650. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_SETDATAFAILED, IID_IEntryID, pRowsetChange, IID_IRowsetChange,
  651. m_pResourceDLL);
  652. // release pointer to data
  653. GlobalUnlock(hData);
  654. // release update accessor
  655. pAccessor->ReleaseAccessor(hAccessor, NULL);
  656. // destroy update buffer
  657. delete [] pBuffer;
  658. return hr;
  659. }
  660. #endif //VD_DONT_IMPLEMENT_ISTREAM
  661. //=--------------------------------------------------------------------------=
  662. // ReleaseSameRowClone - Release same-row clone, if we still have one
  663. //
  664. void CVDCursorPosition::ReleaseSameRowClone()
  665. {
  666. if (m_pSameRowClone)
  667. {
  668. // must be set to NULL before release
  669. ICursor * pSameRowClone = m_pSameRowClone;
  670. m_pSameRowClone = NULL;
  671. pSameRowClone->Release();
  672. }
  673. }
  674. //=--------------------------------------------------------------------------=
  675. // IRowsetNotify Methods
  676. //=--------------------------------------------------------------------------=
  677. //=--------------------------------------------------------------------------=
  678. // IRowsetNotify OnFieldChange
  679. //=--------------------------------------------------------------------------=
  680. // This function is called on any change to the value of a field
  681. //
  682. // Parameters:
  683. // pRowset - [in] the IRowset that is generating the notification
  684. // (we can ignore this since we are only ever dealing
  685. // with a single rowset).
  686. // hRow - [in] the HROW of the row in which the field value has
  687. // changed
  688. // cColumns - [in] the count of columns in rgColumns
  689. // rgColumns - [in] an array of column (ordinal positions) in the row
  690. // for which the value has changed
  691. // eReason - [in] the kind of action which caused this change
  692. // ePhase - [in] the phase of this notification
  693. // fCantDeny - [in] when this flag is set to TRUE, the consumer cannot
  694. // veto the event (by returning S_FALSE)
  695. //
  696. // Output:
  697. // HRESULT - S_OK if successful
  698. // S_FALSE the event/phase is vetoed
  699. // DB_S_UNWANTEDPHASE
  700. // DB_S_UNWANTEDREASON
  701. //
  702. // Notes:
  703. //
  704. HRESULT CVDCursorPosition::OnFieldChange(IUnknown *pRowset,
  705. HROW hRow,
  706. ULONG cColumns,
  707. ULONG rgColumns[],
  708. DBREASON eReason,
  709. DBEVENTPHASE ePhase,
  710. BOOL fCantDeny)
  711. {
  712. // make sure rowset is valid
  713. if (!GetRowsetSource()->IsRowsetValid())
  714. return S_OK;
  715. // check for columns
  716. if (0 == cColumns)
  717. return S_OK;
  718. // check for known reasons
  719. if (eReason != DBREASON_COLUMN_SET && eReason != DBREASON_COLUMN_RECALCULATED)
  720. return S_OK;
  721. HRESULT hr = S_OK;
  722. // send edit mode notification if needed
  723. if (ePhase == DBEVENTPHASE_OKTODO && m_dwEditMode == CURSOR_DBEDITMODE_NONE)
  724. {
  725. // setup notification structures
  726. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  727. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  728. CURSOR_DBNOTIFYREASON rgReasons[1];
  729. VariantInit((VARIANT*)&rgReasons[0].arg1);
  730. VariantInit((VARIANT*)&rgReasons[0].arg2);
  731. rgReasons[0].dwReason = CURSOR_DBREASON_EDIT;
  732. // notify other interested parties of action
  733. hr = NotifyBefore(dwEventWhat, 1, rgReasons);
  734. if (hr == S_OK)
  735. {
  736. // notify other interested parties of success
  737. NotifyAfter(dwEventWhat, 1, rgReasons);
  738. // temporarily place cursor into edit mode
  739. m_fTempEditMode = TRUE;
  740. }
  741. else
  742. {
  743. // notify other interested parties of failure
  744. NotifyFail(dwEventWhat, 1, rgReasons);
  745. }
  746. }
  747. // sent set column notifications
  748. if (hr == S_OK && (ePhase == DBEVENTPHASE_OKTODO ||
  749. ePhase == DBEVENTPHASE_DIDEVENT ||
  750. ePhase == DBEVENTPHASE_FAILEDTODO))
  751. {
  752. // setup notification structures
  753. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED;
  754. CURSOR_DBNOTIFYREASON rgReasons[1];
  755. VariantInit((VARIANT*)&rgReasons[0].arg1);
  756. VariantInit((VARIANT*)&rgReasons[0].arg2);
  757. switch (eReason)
  758. {
  759. case DBREASON_COLUMN_SET:
  760. rgReasons[0].dwReason = CURSOR_DBREASON_SETCOLUMN;
  761. break;
  762. case DBREASON_COLUMN_RECALCULATED:
  763. rgReasons[0].dwReason = CURSOR_DBREASON_RECALC;
  764. break;
  765. }
  766. // get internal column pointers
  767. ULONG ulColumns = m_pCursorMain->GetColumnsCount();
  768. CVDRowsetColumn * pColumn = m_pCursorMain->InternalGetColumns();
  769. for (ULONG ulCol = 0; ulCol < cColumns; ulCol++)
  770. {
  771. // determine which column is changing
  772. for (ULONG ulRSCol = 0; ulRSCol < ulColumns; ulRSCol++)
  773. {
  774. if (pColumn[ulRSCol].GetOrdinal() == rgColumns[ulCol])
  775. {
  776. rgReasons[0].arg1.vt = VT_I4;
  777. rgReasons[0].arg1.lVal = ulRSCol;
  778. }
  779. }
  780. HRESULT hrNotify = S_OK;
  781. // notify other interested parties
  782. switch (ePhase)
  783. {
  784. case DBEVENTPHASE_OKTODO:
  785. hrNotify = NotifyBefore(dwEventWhat, 1, rgReasons);
  786. break;
  787. case DBEVENTPHASE_DIDEVENT:
  788. NotifyAfter(dwEventWhat, 1, rgReasons);
  789. break;
  790. case DBEVENTPHASE_FAILEDTODO:
  791. NotifyFail(dwEventWhat, 1, rgReasons);
  792. break;
  793. }
  794. if (hrNotify != S_OK)
  795. hr = S_FALSE;
  796. }
  797. }
  798. // take cursor out of edit mode if we placed it into that mode (success)
  799. if (ePhase == DBEVENTPHASE_DIDEVENT && m_fTempEditMode)
  800. {
  801. // setup notification structures
  802. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  803. CURSOR_DBEVENT_NONCURRENT_ROW_DATA_CHANGED |
  804. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  805. CURSOR_DBNOTIFYREASON rgReasons[1];
  806. VariantInit((VARIANT*)&rgReasons[0].arg1);
  807. VariantInit((VARIANT*)&rgReasons[0].arg2);
  808. rgReasons[0].dwReason = CURSOR_DBREASON_MODIFIED;
  809. // notify other interested parties of action
  810. NotifyBefore(dwEventWhat, 1, rgReasons);
  811. NotifyAfter(dwEventWhat, 1, rgReasons);
  812. // take out of edit mode
  813. m_fTempEditMode = FALSE;
  814. }
  815. // take cursor out of edit mode if we placed it into that mode (failure)
  816. if (ePhase == DBEVENTPHASE_FAILEDTODO && m_fTempEditMode)
  817. {
  818. // setup notification structures
  819. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED;
  820. CURSOR_DBNOTIFYREASON rgReasons[1];
  821. VariantInit((VARIANT*)&rgReasons[0].arg1);
  822. VariantInit((VARIANT*)&rgReasons[0].arg2);
  823. rgReasons[0].dwReason = CURSOR_DBREASON_CANCELUPDATE;
  824. // notify other interested parties of action
  825. NotifyBefore(dwEventWhat, 1, rgReasons);
  826. NotifyAfter(dwEventWhat, 1, rgReasons);
  827. // take out of edit mode
  828. m_fTempEditMode = FALSE;
  829. }
  830. // reset cache on ending phase
  831. if (DBEVENTPHASE_FAILEDTODO == ePhase ||
  832. DBEVENTPHASE_DIDEVENT == ePhase)
  833. m_bmCache.Reset();
  834. return hr;
  835. }
  836. //=--------------------------------------------------------------------------=
  837. // IRowsetNotify OnRowChange
  838. //=--------------------------------------------------------------------------=
  839. // This function is called on the first change to a row, or any whole-row change
  840. //
  841. // Parameters:
  842. // pRowset - [in] the IRowset that is generating the notification
  843. // (we can ignore this since we are only ever dealing
  844. // with a single rowset).
  845. // cRows - [in] the count of HROWs in rghRows
  846. // rghRows - [in] an array of HROWs which are changing
  847. // eReason - [in] the kind of action which caused this change
  848. // ePhase - [in] the phase of this notification
  849. // fCantDeny - [in] when this flag is set to TRUE, the consumer cannot
  850. // veto the event (by returning S_FALSE)
  851. //
  852. // Output:
  853. // HRESULT - S_OK if successful
  854. // S_FALSE the event/phase is vetoed
  855. // DB_S_UNWANTEDPHASE
  856. // DB_S_UNWANTEDREASON
  857. //
  858. // Notes:
  859. //
  860. HRESULT CVDCursorPosition::OnRowChange(IUnknown *pRowset,
  861. ULONG cRows,
  862. const HROW rghRows[],
  863. DBREASON eReason,
  864. DBEVENTPHASE ePhase,
  865. BOOL fCantDeny)
  866. {
  867. // make sure we still have a valid rowset
  868. if (!(GetRowsetSource()->IsRowsetValid()))
  869. return S_OK;
  870. // check for rows
  871. if (0 == cRows)
  872. return S_OK;
  873. // filter notifications
  874. switch (eReason)
  875. {
  876. case DBREASON_ROW_DELETE:
  877. case DBREASON_ROW_INSERT:
  878. case DBREASON_ROW_RESYNCH:
  879. case DBREASON_ROW_UPDATE:
  880. case DBREASON_ROW_UNDOCHANGE:
  881. case DBREASON_ROW_UNDOINSERT:
  882. break;
  883. // the following do not generate notifications
  884. //
  885. // case DBREASON_ROW_ACTIVATE:
  886. // case DBREASON_ROW_RELEASE:
  887. // case DBREASON_ROW_FIRSTCHANGE:
  888. // case DBREASON_ROW_UNDODELETE:
  889. default:
  890. return S_OK;
  891. }
  892. // create variables
  893. DWORD dwEventWhat = 0;
  894. CURSOR_DBNOTIFYREASON * pReasons = (CURSOR_DBNOTIFYREASON *)g_pMalloc->Alloc(cRows * sizeof(CURSOR_DBNOTIFYREASON));
  895. if (!pReasons)
  896. return S_OK;
  897. memset(pReasons, 0, cRows * sizeof(CURSOR_DBNOTIFYREASON));
  898. HRESULT hr;
  899. BOOL fCurrentRow;
  900. // iterate through supplied rows
  901. for (ULONG ul = 0; ul < cRows; ul++)
  902. {
  903. if (eReason != DBREASON_ROW_UNDOINSERT)
  904. {
  905. // check to see if this row is current
  906. hr = IsSameRowAsCurrent(rghRows[ul], TRUE);
  907. switch (hr)
  908. {
  909. case S_OK:
  910. fCurrentRow = TRUE;
  911. pReasons[ul].arg1 = m_bmCurrent.GetBookmarkVariant();
  912. break;
  913. case S_FALSE:
  914. fCurrentRow = FALSE;
  915. pReasons[ul].arg1 = m_bmCache.GetBookmarkVariant();
  916. break;
  917. default:
  918. hr = S_OK;
  919. goto cleanup;
  920. }
  921. }
  922. else
  923. {
  924. // check to see of this row is current add-row
  925. if (m_dwEditMode == CURSOR_DBEDITMODE_ADD)
  926. hr = IsSameRowAsNew(rghRows[ul]);
  927. else
  928. hr = E_FAIL;
  929. switch (hr)
  930. {
  931. case S_OK:
  932. fCurrentRow = TRUE;
  933. pReasons[ul].arg1 = m_bmAddRow.GetBookmarkVariant();
  934. break;
  935. default:
  936. hr = S_OK;
  937. goto cleanup;
  938. }
  939. }
  940. // setup variables
  941. switch (eReason)
  942. {
  943. case DBREASON_ROW_DELETE:
  944. if (fCurrentRow)
  945. dwEventWhat |= CURSOR_DBEVENT_CURRENT_ROW_CHANGED |
  946. CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  947. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  948. else
  949. dwEventWhat |= CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  950. pReasons[ul].dwReason = CURSOR_DBREASON_DELETED;
  951. break;
  952. case DBREASON_ROW_INSERT:
  953. if (fCurrentRow)
  954. dwEventWhat |= CURSOR_DBEVENT_CURRENT_ROW_CHANGED |
  955. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  956. else
  957. dwEventWhat |= CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  958. pReasons[ul].dwReason = CURSOR_DBREASON_INSERTED;
  959. break;
  960. case DBREASON_ROW_RESYNCH:
  961. if (fCurrentRow)
  962. dwEventWhat |= CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED;
  963. else
  964. dwEventWhat |= CURSOR_DBEVENT_NONCURRENT_ROW_DATA_CHANGED;
  965. pReasons[ul].dwReason = CURSOR_DBREASON_REFRESH;
  966. break;
  967. case DBREASON_ROW_UPDATE:
  968. if (fCurrentRow)
  969. dwEventWhat |= CURSOR_DBEVENT_CURRENT_ROW_CHANGED |
  970. CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  971. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  972. else
  973. dwEventWhat |= CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  974. pReasons[ul].dwReason = CURSOR_DBREASON_MODIFIED;
  975. break;
  976. case DBREASON_ROW_UNDOCHANGE:
  977. if (fCurrentRow)
  978. dwEventWhat |= CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  979. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  980. else
  981. dwEventWhat |= CURSOR_DBEVENT_NONCURRENT_ROW_DATA_CHANGED |
  982. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  983. pReasons[ul].dwReason = CURSOR_DBREASON_MODIFIED;
  984. break;
  985. case DBREASON_ROW_UNDOINSERT:
  986. if (fCurrentRow)
  987. dwEventWhat |= CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED;
  988. pReasons[ul].dwReason = CURSOR_DBREASON_CANCELUPDATE;
  989. break;
  990. }
  991. }
  992. // notify interested cursor listeners
  993. hr = SendNotification(ePhase, dwEventWhat, cRows, pReasons);
  994. // take cursor out of add-mode if we received UNDOINSERT on current add-row
  995. if (eReason == DBREASON_ROW_UNDOINSERT && ePhase == DBEVENTPHASE_DIDEVENT && hr == S_OK)
  996. {
  997. // if acquired, release same-row clone
  998. if (GetSameRowClone())
  999. ReleaseSameRowClone();
  1000. // also, release add row if we have one
  1001. if (m_bmAddRow.GetHRow())
  1002. ReleaseAddRow();
  1003. // reset edit mode
  1004. SetEditMode(CURSOR_DBEDITMODE_NONE);
  1005. // reset column updates
  1006. ResetColumnUpdates();
  1007. }
  1008. cleanup:
  1009. g_pMalloc->Free(pReasons);
  1010. // reset cache on ending phase
  1011. if (DBEVENTPHASE_FAILEDTODO == ePhase ||
  1012. DBEVENTPHASE_DIDEVENT == ePhase)
  1013. m_bmCache.Reset();
  1014. return hr;
  1015. }
  1016. //=--------------------------------------------------------------------------=
  1017. // IRowsetNotify OnRowsetChange
  1018. //=--------------------------------------------------------------------------=
  1019. // This function is called on any change affecting the entire rowset
  1020. //
  1021. // Parameters:
  1022. // pRowset - [in] the IRowset that is generating the notification
  1023. // (we can ignore this since we are only ever dealing
  1024. // with a single rowset).
  1025. // eReason - [in] the kind of action which caused this change
  1026. // ePhase - [in] the phase of this notification
  1027. // fCantDeny - [in] when this flag is set to TRUE, the consumer cannot
  1028. // veto the event (by returning S_FALSE)
  1029. //
  1030. // Output:
  1031. // HRESULT - S_OK if successful
  1032. // S_FALSE the event/phase is vetoed
  1033. // DB_S_UNWANTEDPHASE
  1034. // DB_S_UNWANTEDREASON
  1035. //
  1036. // Notes:
  1037. //
  1038. HRESULT CVDCursorPosition::OnRowsetChange(IUnknown *pRowset,
  1039. DBREASON eReason,
  1040. DBEVENTPHASE ePhase,
  1041. BOOL fCantDeny)
  1042. {
  1043. if (!(GetRowsetSource()->IsRowsetValid()))
  1044. return S_OK;
  1045. switch (eReason)
  1046. {
  1047. case DBREASON_ROWSET_RELEASE:
  1048. GetRowsetSource()->SetRowsetReleasedFlag();
  1049. break;
  1050. case DBREASON_ROWSET_FETCHPOSITIONCHANGE:
  1051. {
  1052. /*
  1053. What do we do here
  1054. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_CHANGED;
  1055. CURSOR_DBNOTIFYREASON reason;
  1056. memset(&reason, 0, sizeof(CURSOR_DBNOTIFYREASON));
  1057. reason.dwReason = CURSOR_DBREASON_MOVE;
  1058. reason.arg1 = m_bmCurrent.GetBookmarkVariant();
  1059. VariantInit((VARIANT*)&reason.arg2);
  1060. reason.arg2.vt = VT_I4;
  1061. // the ICursor spec states that this is the value of dlOffset in
  1062. // iCursorMove::Move. Since we can't get that from the Rowset spec
  1063. // we are setting the value to an arbitrary 1
  1064. reason.arg2.lVal = 1;
  1065. return SendNotification(ePhase, CURSOR_DBEVENT_CURRENT_ROW_CHANGED, 1, &reason);
  1066. */
  1067. break;
  1068. }
  1069. }
  1070. return S_OK;
  1071. }
  1072. //=--------------------------------------------------------------------------=
  1073. // ConnectIRowPositionChange - Connect IRowPositionChange interface
  1074. //
  1075. HRESULT CVDCursorPosition::ConnectIRowPositionChange()
  1076. {
  1077. IConnectionPointContainer * pConnectionPointContainer;
  1078. HRESULT hr = m_pRowPosition->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
  1079. if (FAILED(hr))
  1080. return VD_E_CANNOTCONNECTIROWPOSITIONCHANGE;
  1081. IConnectionPoint * pConnectionPoint;
  1082. hr = pConnectionPointContainer->FindConnectionPoint(IID_IRowPositionChange, &pConnectionPoint);
  1083. if (FAILED(hr))
  1084. {
  1085. pConnectionPointContainer->Release();
  1086. return VD_E_CANNOTCONNECTIROWPOSITIONCHANGE;
  1087. }
  1088. hr = pConnectionPoint->Advise(&m_RowPositionChange, &m_dwAdviseCookie);
  1089. pConnectionPointContainer->Release();
  1090. pConnectionPoint->Release();
  1091. return hr;
  1092. }
  1093. //=--------------------------------------------------------------------------=
  1094. // DisconnectIRowPositionChange - Disconnect IRowPositionChange interface
  1095. //
  1096. void CVDCursorPosition::DisconnectIRowPositionChange()
  1097. {
  1098. IConnectionPointContainer * pConnectionPointContainer;
  1099. HRESULT hr = m_pRowPosition->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
  1100. if (FAILED(hr))
  1101. return;
  1102. IConnectionPoint * pConnectionPoint;
  1103. hr = pConnectionPointContainer->FindConnectionPoint(IID_IRowPositionChange, &pConnectionPoint);
  1104. if (FAILED(hr))
  1105. {
  1106. pConnectionPointContainer->Release();
  1107. return;
  1108. }
  1109. hr = pConnectionPoint->Unadvise(m_dwAdviseCookie);
  1110. if (SUCCEEDED(hr))
  1111. m_dwAdviseCookie = 0; // clear connection point identifier
  1112. pConnectionPointContainer->Release();
  1113. pConnectionPoint->Release();
  1114. }
  1115. //=--------------------------------------------------------------------------=
  1116. // SendNotification maps the event phases to the corresponding INotifyDBEvents
  1117. // methods
  1118. //
  1119. HRESULT CVDCursorPosition::SendNotification(DBEVENTPHASE ePhase,
  1120. DWORD dwEventWhat,
  1121. ULONG cReasons,
  1122. CURSOR_DBNOTIFYREASON rgReasons[])
  1123. {
  1124. HRESULT hr = S_OK;
  1125. switch (ePhase)
  1126. {
  1127. case DBEVENTPHASE_OKTODO:
  1128. hr = NotifyOKToDo(dwEventWhat, cReasons, rgReasons);
  1129. break;
  1130. case DBEVENTPHASE_ABOUTTODO:
  1131. hr = NotifyAboutToDo(dwEventWhat, cReasons, rgReasons);
  1132. if (S_OK == hr)
  1133. hr = NotifySyncBefore(dwEventWhat, cReasons, rgReasons);
  1134. break;
  1135. case DBEVENTPHASE_SYNCHAFTER:
  1136. // SyncAfter fired from DidEvent for reentrant safety
  1137. break;
  1138. case DBEVENTPHASE_FAILEDTODO:
  1139. NotifyCancel(dwEventWhat, cReasons, rgReasons);
  1140. NotifyFail(dwEventWhat, cReasons, rgReasons);
  1141. break;
  1142. case DBEVENTPHASE_DIDEVENT:
  1143. hr = NotifySyncAfter(dwEventWhat, cReasons, rgReasons);
  1144. if (S_OK == hr)
  1145. hr = NotifyDidEvent(dwEventWhat, cReasons, rgReasons);
  1146. break;
  1147. }
  1148. if (CURSOR_DB_S_CANCEL == hr)
  1149. hr = S_FALSE;
  1150. return hr;
  1151. }
  1152. //=--------------------------------------------------------------------------=
  1153. // IUnknown QueryInterface
  1154. //
  1155. HRESULT CVDCursorPosition::QueryInterface(REFIID riid, void **ppvObjOut)
  1156. {
  1157. ASSERT_POINTER(ppvObjOut, IUnknown*)
  1158. if (!ppvObjOut)
  1159. return E_INVALIDARG;
  1160. *ppvObjOut = NULL;
  1161. if (DO_GUIDS_MATCH(riid, IID_IUnknown))
  1162. {
  1163. *ppvObjOut = this;
  1164. AddRef();
  1165. return S_OK;
  1166. }
  1167. return E_NOINTERFACE;
  1168. }
  1169. //=--------------------------------------------------------------------------=
  1170. // IUnknown AddRef (needed to resolve ambiguity)
  1171. //
  1172. ULONG CVDCursorPosition::AddRef(void)
  1173. {
  1174. return CVDNotifier::AddRef();
  1175. }
  1176. //=--------------------------------------------------------------------------=
  1177. // IUnknown Release (needed to resolve ambiguity)
  1178. //
  1179. ULONG CVDCursorPosition::Release(void)
  1180. {
  1181. if (1 == m_dwRefCount)
  1182. Passivate(); // unhook everything including notification sink
  1183. if (1 > --m_dwRefCount)
  1184. {
  1185. if (0 == m_RowPositionChange.GetRefCount())
  1186. delete this;
  1187. return 0;
  1188. }
  1189. return m_dwRefCount;
  1190. }
  1191. //=--------------------------------------------------------------------------=
  1192. // IRowPositionChange methods implemented
  1193. //=--------------------------------------------------------------------------=
  1194. //=--------------------------------------------------------------------------=
  1195. // IRowPositionChange OnRowPositionChange
  1196. //=--------------------------------------------------------------------------=
  1197. // This function is called on any change affecting the current row
  1198. //
  1199. // Parameters:
  1200. // eReason - [in] the kind of action which caused this change
  1201. // ePhase - [in] the phase of this notification
  1202. // fCantDeny - [in] when this flag is set to TRUE, the consumer cannot
  1203. // veto the event (by returning S_FALSE)
  1204. //
  1205. // Output:
  1206. // HRESULT - S_OK if successful
  1207. // S_FALSE the event/phase is vetoed
  1208. // DB_S_UNWANTEDPHASE
  1209. // DB_S_UNWANTEDREASON
  1210. //
  1211. // Notes:
  1212. //
  1213. HRESULT CVDCursorPosition::OnRowPositionChange(DBREASON eReason, DBEVENTPHASE ePhase, BOOL fCantDeny)
  1214. {
  1215. // return if notification caused by internal set row call
  1216. if (m_fInternalSetRow)
  1217. return S_OK;
  1218. // return if reason has anything to do with chapter changes
  1219. if (eReason == DBREASON_ROWPOSITION_CHAPTERCHANGED)
  1220. return S_OK;
  1221. IRowset * pRowset = GetRowsetSource()->GetRowset();
  1222. // make sure we have valid row position and rowset pointers
  1223. if (!m_pRowPosition || !pRowset || !GetRowsetSource()->IsRowsetValid())
  1224. return S_OK;
  1225. // synchronize hRow after event occurs
  1226. if (ePhase == DBEVENTPHASE_SYNCHAFTER)
  1227. {
  1228. HROW hRow = NULL;
  1229. HCHAPTER hChapterDummy = NULL;
  1230. DBPOSITIONFLAGS dwPositionFlags = NULL;
  1231. // get new current hRow and position flags from row position object
  1232. HRESULT hr = m_pRowPosition->GetRowPosition(&hChapterDummy, &hRow, &dwPositionFlags);
  1233. if (FAILED(hr))
  1234. return hr;
  1235. if (hRow)
  1236. {
  1237. // set new hRow
  1238. SetCurrentHRow(hRow);
  1239. pRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
  1240. }
  1241. else
  1242. {
  1243. // set row status to beginning or end
  1244. if (dwPositionFlags == DBPOSITION_BOF)
  1245. SetCurrentRowStatus(VDBOOKMARKSTATUS_BEGINNING);
  1246. else if (dwPositionFlags == DBPOSITION_EOF)
  1247. SetCurrentRowStatus(VDBOOKMARKSTATUS_END);
  1248. }
  1249. }
  1250. CURSOR_DBNOTIFYREASON rgReasons[1];
  1251. rgReasons[0].dwReason = CURSOR_DBREASON_MOVE;
  1252. rgReasons[0].arg1 = m_bmCurrent.GetBookmarkVariant();
  1253. VariantInit((VARIANT*)&rgReasons[0].arg2);
  1254. // notify other interested parties
  1255. return SendNotification(ePhase, CURSOR_DBEVENT_CURRENT_ROW_CHANGED, 1, rgReasons);
  1256. }
  1257. //=--------------------------------------------------------------------------=
  1258. // CVDCursorPosition::CVDRowPositionChange::m_pMainUnknown
  1259. //=--------------------------------------------------------------------------=
  1260. // this method is used when we're sitting in the private unknown object,
  1261. // and we need to get at the pointer for the main unknown. basically, it's
  1262. // a little better to do this pointer arithmetic than have to store a pointer
  1263. // to the parent, etc.
  1264. //
  1265. inline CVDCursorPosition *CVDCursorPosition::CVDRowPositionChange::m_pMainUnknown
  1266. (
  1267. void
  1268. )
  1269. {
  1270. return (CVDCursorPosition *)((LPBYTE)this - offsetof(CVDCursorPosition, m_RowPositionChange));
  1271. }
  1272. //=--------------------------------------------------------------------------=
  1273. // CVDCursorPosition::CVDRowPositionChange::QueryInterface
  1274. //=--------------------------------------------------------------------------=
  1275. // this is the non-delegating internal QI routine.
  1276. //
  1277. // Parameters:
  1278. // REFIID - [in] interface they want
  1279. // void ** - [out] where they want to put the resulting object ptr.
  1280. //
  1281. // Output:
  1282. // HRESULT - S_OK, E_NOINTERFACE
  1283. //
  1284. // Notes:
  1285. //
  1286. STDMETHODIMP CVDCursorPosition::CVDRowPositionChange::QueryInterface
  1287. (
  1288. REFIID riid,
  1289. void **ppvObjOut
  1290. )
  1291. {
  1292. if (!ppvObjOut)
  1293. return E_INVALIDARG;
  1294. *ppvObjOut = NULL;
  1295. if (DO_GUIDS_MATCH(riid, IID_IUnknown))
  1296. *ppvObjOut = (IUnknown *)this;
  1297. else
  1298. if (DO_GUIDS_MATCH(riid, IID_IRowPositionChange))
  1299. *ppvObjOut = (IUnknown *)this;
  1300. if (*ppvObjOut)
  1301. {
  1302. m_cRef++;
  1303. return S_OK;
  1304. }
  1305. return E_NOINTERFACE;
  1306. }
  1307. //=--------------------------------------------------------------------------=
  1308. // CVDCursorPosition::CVDRowPositionChange::AddRef
  1309. //=--------------------------------------------------------------------------=
  1310. // adds a tick to the current reference count.
  1311. //
  1312. // Output:
  1313. // ULONG - the new reference count
  1314. //
  1315. // Notes:
  1316. //
  1317. ULONG CVDCursorPosition::CVDRowPositionChange::AddRef
  1318. (
  1319. void
  1320. )
  1321. {
  1322. return ++m_cRef;
  1323. }
  1324. //=--------------------------------------------------------------------------=
  1325. // CVDCursorPosition::CVDRowPositionChange::Release
  1326. //=--------------------------------------------------------------------------=
  1327. // removes a tick from the count, and delets the object if necessary
  1328. //
  1329. // Output:
  1330. // ULONG - remaining refs
  1331. //
  1332. // Notes:
  1333. //
  1334. ULONG CVDCursorPosition::CVDRowPositionChange::Release
  1335. (
  1336. void
  1337. )
  1338. {
  1339. ULONG cRef = --m_cRef;
  1340. if (!m_cRef && !m_pMainUnknown()->m_dwRefCount)
  1341. delete m_pMainUnknown();
  1342. return cRef;
  1343. }
  1344. //=--------------------------------------------------------------------------=
  1345. // IRowPositionChange OnRowPositionChange
  1346. //=--------------------------------------------------------------------------=
  1347. // Forward to all CVDCursor objects in our family
  1348. //
  1349. HRESULT CVDCursorPosition::CVDRowPositionChange::OnRowPositionChange(DBREASON eReason,
  1350. DBEVENTPHASE ePhase,
  1351. BOOL fCantDeny)
  1352. {
  1353. return m_pMainUnknown()->OnRowPositionChange(eReason, ePhase, fCantDeny);
  1354. }