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.

787 lines
26 KiB

  1. //---------------------------------------------------------------------------
  2. // CursorBase.cpp : CursorBase 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 "CursBase.h"
  13. #include "fastguid.h"
  14. #include "resource.h"
  15. SZTHISFILE
  16. //=--------------------------------------------------------------------------=
  17. // CVDCursorBase - Constructor
  18. //
  19. CVDCursorBase::CVDCursorBase()
  20. {
  21. m_ulCursorBindings = 0;
  22. m_pCursorBindings = NULL;
  23. m_fNeedVarData = FALSE;
  24. m_cbRowLength = 0;
  25. m_cbVarRowLength = 0;
  26. #ifdef _DEBUG
  27. g_cVDCursorBaseCreated++;
  28. #endif
  29. }
  30. //=--------------------------------------------------------------------------=
  31. // ~CVDCursorBase - Destructor
  32. //
  33. CVDCursorBase::~CVDCursorBase()
  34. {
  35. DestroyCursorBindings(&m_pCursorBindings, &m_ulCursorBindings);
  36. #ifdef _DEBUG
  37. g_cVDCursorBaseDestroyed++;
  38. #endif
  39. }
  40. //=--------------------------------------------------------------------------=
  41. // DestroyCursorBindings - Destroy cursor bindings and column identifer names
  42. //
  43. void CVDCursorBase::DestroyCursorBindings(CURSOR_DBCOLUMNBINDING** ppCursorBindings,
  44. ULONG* pcBindings)
  45. {
  46. for (ULONG ulBind = 0; ulBind < *pcBindings; ulBind++)
  47. {
  48. CURSOR_DBCOLUMNID * pCursorColumnID = &(*ppCursorBindings)[ulBind].columnID;
  49. if (pCursorColumnID->dwKind == CURSOR_DBCOLKIND_GUID_NAME || pCursorColumnID->dwKind == CURSOR_DBCOLKIND_NAME)
  50. delete [] pCursorColumnID->lpdbsz;
  51. }
  52. delete [] *ppCursorBindings;
  53. *ppCursorBindings = NULL;
  54. *pcBindings = 0;
  55. }
  56. //=--------------------------------------------------------------------------=
  57. // IsValidCursorType - Return TRUE if specified cursor data type is valid
  58. //
  59. BOOL CVDCursorBase::IsValidCursorType(DWORD dwCursorType)
  60. {
  61. BOOL fValid = FALSE;
  62. switch (dwCursorType)
  63. {
  64. case CURSOR_DBTYPE_I2:
  65. case CURSOR_DBTYPE_I4:
  66. case CURSOR_DBTYPE_I8:
  67. case CURSOR_DBTYPE_R4:
  68. case CURSOR_DBTYPE_R8:
  69. case CURSOR_DBTYPE_CY:
  70. case CURSOR_DBTYPE_DATE:
  71. case CURSOR_DBTYPE_FILETIME:
  72. case CURSOR_DBTYPE_BOOL:
  73. case CURSOR_DBTYPE_LPSTR:
  74. case CURSOR_DBTYPE_LPWSTR:
  75. case CURSOR_DBTYPE_BLOB:
  76. case CURSOR_DBTYPE_UI2:
  77. case CURSOR_DBTYPE_UI4:
  78. case CURSOR_DBTYPE_UI8:
  79. case CURSOR_DBTYPE_COLUMNID:
  80. case CURSOR_DBTYPE_BYTES:
  81. case CURSOR_DBTYPE_CHARS:
  82. case CURSOR_DBTYPE_WCHARS:
  83. case CURSOR_DBTYPE_ANYVARIANT:
  84. case VT_VARIANT:
  85. case VT_BSTR:
  86. case VT_UI1:
  87. case VT_I1:
  88. fValid = TRUE;
  89. break;
  90. }
  91. return fValid;
  92. }
  93. //=--------------------------------------------------------------------------=
  94. // DoesCursorTypeNeedVarData - Return TRUE if specified cursor type needs
  95. // variable length buffer
  96. //
  97. BOOL CVDCursorBase::DoesCursorTypeNeedVarData(DWORD dwCursorType)
  98. {
  99. BOOL fNeedsVarData = FALSE;
  100. switch (dwCursorType)
  101. {
  102. case CURSOR_DBTYPE_BLOB:
  103. case CURSOR_DBTYPE_LPSTR:
  104. case CURSOR_DBTYPE_LPWSTR:
  105. fNeedsVarData = TRUE;
  106. break;
  107. }
  108. return fNeedsVarData;
  109. }
  110. //=--------------------------------------------------------------------------=
  111. // GetCursorTypeLength - Get the size in bytes required by cursor data type
  112. //
  113. ULONG CVDCursorBase::GetCursorTypeLength(DWORD dwCursorType, ULONG cbMaxLen)
  114. {
  115. ULONG cbRequired = 0;
  116. switch (dwCursorType)
  117. {
  118. case CURSOR_DBTYPE_I2:
  119. case CURSOR_DBTYPE_UI2:
  120. cbRequired = sizeof(short);
  121. break;
  122. case CURSOR_DBTYPE_I4:
  123. case CURSOR_DBTYPE_UI4:
  124. cbRequired = sizeof(long);
  125. break;
  126. case CURSOR_DBTYPE_I8:
  127. case CURSOR_DBTYPE_UI8:
  128. cbRequired = sizeof(LARGE_INTEGER);
  129. break;
  130. case CURSOR_DBTYPE_R4:
  131. cbRequired = sizeof(float);
  132. break;
  133. case CURSOR_DBTYPE_R8:
  134. cbRequired = sizeof(double);
  135. break;
  136. case CURSOR_DBTYPE_CY:
  137. cbRequired = sizeof(CY);
  138. break;
  139. case CURSOR_DBTYPE_DATE:
  140. cbRequired = sizeof(DATE);
  141. break;
  142. case CURSOR_DBTYPE_FILETIME:
  143. cbRequired = sizeof(FILETIME);
  144. break;
  145. case CURSOR_DBTYPE_BOOL:
  146. cbRequired = sizeof(VARIANT_BOOL);
  147. break;
  148. case CURSOR_DBTYPE_LPSTR:
  149. cbRequired = sizeof(LPSTR);
  150. break;
  151. case CURSOR_DBTYPE_LPWSTR:
  152. cbRequired = sizeof(LPWSTR);
  153. break;
  154. case CURSOR_DBTYPE_BLOB:
  155. cbRequired = sizeof(BLOB);
  156. break;
  157. case CURSOR_DBTYPE_COLUMNID:
  158. cbRequired = sizeof(CURSOR_DBCOLUMNID);
  159. break;
  160. case CURSOR_DBTYPE_BYTES:
  161. cbRequired = cbMaxLen;
  162. break;
  163. case CURSOR_DBTYPE_CHARS:
  164. cbRequired = cbMaxLen;
  165. break;
  166. case CURSOR_DBTYPE_WCHARS:
  167. cbRequired = cbMaxLen;
  168. break;
  169. case CURSOR_DBTYPE_ANYVARIANT:
  170. cbRequired = sizeof(CURSOR_DBVARIANT);
  171. break;
  172. case VT_VARIANT:
  173. cbRequired = sizeof(VARIANT);
  174. break;
  175. case VT_I1:
  176. case VT_UI1:
  177. cbRequired = sizeof(BYTE);
  178. break;
  179. }
  180. return cbRequired;
  181. }
  182. //=--------------------------------------------------------------------------=
  183. // IsEqualCursorColumnID - Return TRUE if cursor column identifier are the same
  184. //
  185. BOOL CVDCursorBase::IsEqualCursorColumnID(const CURSOR_DBCOLUMNID& cursorColumnID1, const CURSOR_DBCOLUMNID& cursorColumnID2)
  186. {
  187. // first check to see if column identifers are the same kind
  188. if (cursorColumnID1.dwKind != cursorColumnID1.dwKind)
  189. return FALSE;
  190. // then, check to see if they are equal
  191. BOOL bResult = TRUE;
  192. switch (cursorColumnID1.dwKind)
  193. {
  194. case CURSOR_DBCOLKIND_GUID_NAME:
  195. if (!IsEqualGUID(cursorColumnID1.guid, cursorColumnID2.guid))
  196. bResult = FALSE;
  197. else if (lstrcmpW(cursorColumnID1.lpdbsz, cursorColumnID2.lpdbsz))
  198. bResult = FALSE;
  199. break;
  200. case CURSOR_DBCOLKIND_GUID_NUMBER:
  201. if (!IsEqualGUID(cursorColumnID1.guid, cursorColumnID2.guid))
  202. bResult = FALSE;
  203. else if (cursorColumnID1.lNumber != cursorColumnID2.lNumber)
  204. bResult = FALSE;
  205. break;
  206. case CURSOR_DBCOLKIND_NAME:
  207. if (lstrcmpW(cursorColumnID1.lpdbsz, cursorColumnID2.lpdbsz))
  208. bResult = FALSE;
  209. break;
  210. }
  211. return bResult;
  212. }
  213. //=--------------------------------------------------------------------------=
  214. // GetCursorColumnIDNameLength - Get the size in bytes of possible name attached
  215. // to the specified cursor column identifier
  216. //
  217. ULONG CVDCursorBase::GetCursorColumnIDNameLength(const CURSOR_DBCOLUMNID& cursorColumnID)
  218. {
  219. ULONG cbName = 0;
  220. if (cursorColumnID.dwKind == CURSOR_DBCOLKIND_GUID_NAME || cursorColumnID.dwKind == CURSOR_DBCOLKIND_NAME)
  221. cbName = (lstrlenW(cursorColumnID.lpdbsz) + 1) * sizeof(WCHAR);
  222. return cbName;
  223. }
  224. //=--------------------------------------------------------------------------=
  225. // ValidateCursorBindings - Validate cursor column bindings
  226. //=--------------------------------------------------------------------------=
  227. // This function makes sure the specified column bindings are acceptable
  228. //
  229. // Parameters:
  230. // ulColumns - [in] the number available columns
  231. // pColumns - [in] an array of available columns
  232. // ulBindings - [in] the number of cursor column bindings
  233. // pCursorBindings - [in] an array of cursor column bindings
  234. // cbRequestedRowLength - [in] the requested number of bytes of inline
  235. // memory in a single row of data
  236. // dwFlags - [in] a flag that specifies whether to replace the
  237. // existing column bindings or add to them
  238. // pcbNewRowLength - [out] a pointer to memory in which to return
  239. // the new number of bytes of inline memory
  240. // in a single row of data for all bindings
  241. // pcbNewRowLength - [out] a pointer to memory in which to return
  242. // the new number of bytes of out-of-line memory
  243. // in a single row of data for all bindings
  244. //
  245. // Output:
  246. // HRESULT - S_OK if successful
  247. // CURSOR_DB_E_BADBINDINFO bad binding information
  248. // CURSOR_DB_E_COLUMNUNAVAILABLE columnID is not available
  249. // CURSOR_DB_E_ROWTOOSHORT cbRequestedRowLength was less than the minumum (and not zero)
  250. //
  251. // Notes:
  252. // This function also computes and returns the new fixed and variable buffer row length required
  253. // by all the cursor bindings.
  254. //
  255. HRESULT CVDCursorBase::ValidateCursorBindings(ULONG ulColumns,
  256. CVDRowsetColumn * pColumns,
  257. ULONG ulBindings,
  258. CURSOR_DBCOLUMNBINDING * pCursorBindings,
  259. ULONG cbRequestedRowLength,
  260. DWORD dwFlags,
  261. ULONG * pcbNewRowLength,
  262. ULONG * pcbNewVarRowLength)
  263. {
  264. DWORD cbMaxLength;
  265. DWORD dwCursorType;
  266. BOOL fColumnIDAvailable;
  267. CVDRowsetColumn * pColumn;
  268. ULONG cbRequiredRowLength = 0;
  269. ULONG cbRequiredVarRowLength = 0;
  270. CURSOR_DBCOLUMNBINDING * pBinding = pCursorBindings;
  271. // iterate through bindings
  272. for (ULONG ulBind = 0; ulBind < ulBindings; ulBind++)
  273. {
  274. // make sure column identifier is available
  275. fColumnIDAvailable = FALSE;
  276. pColumn = pColumns;
  277. for (ULONG ulCol = 0; ulCol < ulColumns && !fColumnIDAvailable; ulCol++)
  278. {
  279. if (IsEqualCursorColumnID(pBinding->columnID, pColumn->GetCursorColumnID()))
  280. {
  281. cbMaxLength = pColumn->GetMaxLength();
  282. dwCursorType = pColumn->GetCursorType();
  283. fColumnIDAvailable = TRUE;
  284. }
  285. pColumn++;
  286. }
  287. if (!fColumnIDAvailable)
  288. {
  289. VDSetErrorInfo(IDS_ERR_COLUMNUNAVAILABLE, IID_ICursor, m_pResourceDLL);
  290. return CURSOR_DB_E_COLUMNUNAVAILABLE;
  291. }
  292. // make sure caller supplied a maximum length if a default binding was specified
  293. // for the cursor types CURSOR_DBTYPE_CHARS, CURSOR_DBTYPE_WCHARS or CURSOR_DBTYPE_BYTES
  294. if (pBinding->cbMaxLen == CURSOR_DB_NOMAXLENGTH &&
  295. pBinding->dwBinding == CURSOR_DBBINDING_DEFAULT)
  296. {
  297. if (pBinding->dwDataType == CURSOR_DBTYPE_CHARS ||
  298. pBinding->dwDataType == CURSOR_DBTYPE_WCHARS ||
  299. pBinding->dwDataType == CURSOR_DBTYPE_BYTES)
  300. {
  301. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
  302. return CURSOR_DB_E_BADBINDINFO;
  303. }
  304. }
  305. // check binding bit mask for possible values
  306. if (pBinding->dwBinding != CURSOR_DBBINDING_DEFAULT &&
  307. pBinding->dwBinding != CURSOR_DBBINDING_VARIANT &&
  308. pBinding->dwBinding != CURSOR_DBBINDING_ENTRYID &&
  309. pBinding->dwBinding != (CURSOR_DBBINDING_VARIANT | CURSOR_DBBINDING_ENTRYID))
  310. {
  311. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
  312. return CURSOR_DB_E_BADBINDINFO;
  313. }
  314. // check for valid cursor type
  315. if (!IsValidCursorType(pBinding->dwDataType))
  316. {
  317. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
  318. return CURSOR_DB_E_BADBINDINFO;
  319. }
  320. // if a variant binding was specified make sure the cursor type is not CURSOR_DBTYPE_CHARS,
  321. // CURSOR_DBTYPE_WCHARS or CURSOR_DBTYPE_BYTES
  322. if (pBinding->dwBinding & CURSOR_DBBINDING_VARIANT)
  323. {
  324. if (pBinding->dwDataType == CURSOR_DBTYPE_CHARS ||
  325. pBinding->dwDataType == CURSOR_DBTYPE_WCHARS ||
  326. pBinding->dwDataType == CURSOR_DBTYPE_BYTES)
  327. {
  328. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
  329. return CURSOR_DB_E_BADBINDINFO;
  330. }
  331. }
  332. // if its not a variant binding make sure the cursor type is not CURSOR_DBTYPE_ANYVARIANT
  333. if (!(pBinding->dwBinding & CURSOR_DBBINDING_VARIANT) && pBinding->dwDataType == CURSOR_DBTYPE_ANYVARIANT)
  334. {
  335. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
  336. return CURSOR_DB_E_BADBINDINFO;
  337. }
  338. // calulate row length required by data field
  339. if (!(pBinding->dwBinding & CURSOR_DBBINDING_VARIANT))
  340. cbRequiredRowLength += GetCursorTypeLength(pBinding->dwDataType, pBinding->cbMaxLen);
  341. else
  342. cbRequiredRowLength += sizeof(CURSOR_DBVARIANT);
  343. // calulate row length required by variable data length field
  344. if (pBinding->obVarDataLen != CURSOR_DB_NOVALUE)
  345. cbRequiredRowLength += sizeof(ULONG);
  346. // calulate row length required by information field
  347. if (pBinding->obInfo != CURSOR_DB_NOVALUE)
  348. cbRequiredRowLength += sizeof(DWORD);
  349. // calulate variable row length required by data field
  350. if (!(pBinding->dwBinding & CURSOR_DBBINDING_VARIANT))
  351. {
  352. if (DoesCursorTypeNeedVarData(pBinding->dwDataType))
  353. {
  354. if (pBinding->cbMaxLen != CURSOR_DB_NOMAXLENGTH)
  355. cbRequiredVarRowLength += pBinding->cbMaxLen;
  356. else
  357. cbRequiredVarRowLength += cbMaxLength;
  358. }
  359. }
  360. else // variant binding
  361. {
  362. if (DoesCursorTypeNeedVarData(pBinding->dwDataType))
  363. {
  364. if (pBinding->cbMaxLen != CURSOR_DB_NOMAXLENGTH)
  365. cbRequiredVarRowLength += pBinding->cbMaxLen;
  366. else
  367. cbRequiredVarRowLength += cbMaxLength;
  368. }
  369. if (pBinding->dwDataType == CURSOR_DBTYPE_COLUMNID)
  370. cbRequiredVarRowLength += sizeof(CURSOR_DBCOLUMNID);
  371. }
  372. pBinding++;
  373. }
  374. // if we're replacing bindings reset row lengths
  375. if (dwFlags == CURSOR_DBCOLUMNBINDOPTS_REPLACE)
  376. {
  377. *pcbNewRowLength = 0;
  378. *pcbNewVarRowLength = 0;
  379. }
  380. else // if we're adding bindings set to current row lengths
  381. {
  382. *pcbNewRowLength = m_cbRowLength;
  383. *pcbNewVarRowLength = m_cbVarRowLength;
  384. }
  385. // if no row length was requested, use required row length
  386. if (!cbRequestedRowLength)
  387. {
  388. *pcbNewRowLength += cbRequiredRowLength;
  389. }
  390. else // make sure row length is large enough
  391. {
  392. if (cbRequestedRowLength < *pcbNewRowLength + cbRequiredRowLength)
  393. {
  394. VDSetErrorInfo(IDS_ERR_ROWTOOSHORT, IID_ICursor, m_pResourceDLL);
  395. return CURSOR_DB_E_ROWTOOSHORT;
  396. }
  397. // use requested row length
  398. *pcbNewRowLength += cbRequestedRowLength;
  399. }
  400. // calculate required variable row length
  401. *pcbNewVarRowLength += cbRequiredVarRowLength;
  402. return S_OK;
  403. }
  404. //=--------------------------------------------------------------------------=
  405. // DoCursorBindingsNeedVarData - Return TRUE if current cursor column bindings
  406. // need variable length buffer
  407. //
  408. BOOL CVDCursorBase::DoCursorBindingsNeedVarData()
  409. {
  410. BOOL fNeedVarData = FALSE;
  411. CURSOR_DBCOLUMNBINDING * pCursorBinding = m_pCursorBindings;
  412. for (ULONG ulBind = 0; ulBind < m_ulCursorBindings && !fNeedVarData; ulBind++)
  413. {
  414. if (DoesCursorTypeNeedVarData(pCursorBinding->dwDataType))
  415. fNeedVarData = TRUE;
  416. pCursorBinding++;
  417. }
  418. return fNeedVarData;
  419. }
  420. //=--------------------------------------------------------------------------=
  421. // Validate fetch params
  422. //=--------------------------------------------------------------------------=
  423. //
  424. // Parameters:
  425. // pFetchParams - [in] ptr to the CURSOR_DBFETCHROWS structure
  426. // riid - [in] guid of calling interface (used for error generation)
  427. //
  428. // Output:
  429. // HRESULT - S_OK if pFetchParams valid
  430. // CURSOR_DB_E_BADFETCHINFO if pFetchParams invalid
  431. //
  432. //
  433. HRESULT CVDCursorBase::ValidateFetchParams(CURSOR_DBFETCHROWS *pFetchParams, REFIID riid)
  434. {
  435. if (!pFetchParams)
  436. {
  437. VDSetErrorInfo(IDS_ERR_INVALIDARG, riid, m_pResourceDLL);
  438. return E_INVALIDARG;
  439. }
  440. // init out parameter
  441. pFetchParams->cRowsReturned = 0;
  442. // return if caller didn't ask for any rows
  443. if (!pFetchParams->cRowsRequested)
  444. return S_OK;
  445. HRESULT hr = S_OK;
  446. // make sure fetch flags has only valid values
  447. if (pFetchParams->dwFlags != CURSOR_DBROWFETCH_DEFAULT &&
  448. pFetchParams->dwFlags != CURSOR_DBROWFETCH_CALLEEALLOCATES &&
  449. pFetchParams->dwFlags != CURSOR_DBROWFETCH_FORCEREFRESH &&
  450. pFetchParams->dwFlags != (CURSOR_DBROWFETCH_CALLEEALLOCATES | CURSOR_DBROWFETCH_FORCEREFRESH))
  451. hr = CURSOR_DB_E_BADFETCHINFO;
  452. // if memory was caller allocated, make sure caller supplied data pointer
  453. if (!(pFetchParams->dwFlags & CURSOR_DBROWFETCH_CALLEEALLOCATES) && !pFetchParams->pData)
  454. hr = CURSOR_DB_E_BADFETCHINFO;
  455. // if memory was caller allocated, make sure caller supplied var-data pointer and size if needed
  456. if (!(pFetchParams->dwFlags & CURSOR_DBROWFETCH_CALLEEALLOCATES) && m_fNeedVarData &&
  457. (!pFetchParams->pVarData || !pFetchParams->cbVarData))
  458. hr = CURSOR_DB_E_BADFETCHINFO;
  459. if (FAILED(hr))
  460. VDSetErrorInfo(IDS_ERR_BADFETCHINFO, riid, m_pResourceDLL);
  461. return hr;
  462. }
  463. //=--------------------------------------------------------------------------=
  464. // IUnknown methods implemented
  465. //=--------------------------------------------------------------------------=
  466. //=--------------------------------------------------------------------------=
  467. // IUnknown QueryInterface
  468. //
  469. HRESULT CVDCursorBase::QueryInterface(REFIID riid, void **ppvObjOut)
  470. {
  471. ASSERT_POINTER(ppvObjOut, IUnknown*)
  472. if (!ppvObjOut)
  473. return E_INVALIDARG;
  474. *ppvObjOut = NULL;
  475. switch (riid.Data1)
  476. {
  477. QI_INTERFACE_SUPPORTED((ICursor*)this, IUnknown);
  478. QI_INTERFACE_SUPPORTED(this, ICursor);
  479. QI_INTERFACE_SUPPORTED(this, ICursorMove);
  480. QI_INTERFACE_SUPPORTED_IF(this, ICursorScroll, SupportsScroll());
  481. QI_INTERFACE_SUPPORTED(this, ISupportErrorInfo);
  482. }
  483. if (NULL == *ppvObjOut)
  484. return E_NOINTERFACE;
  485. AddRef();
  486. return S_OK;
  487. }
  488. //=--------------------------------------------------------------------------=
  489. // IUnknown AddRef (Notifier and MetadataCursor maintain reference count)
  490. //
  491. ULONG CVDCursorBase::AddRef(void)
  492. {
  493. return (ULONG)E_NOTIMPL;
  494. }
  495. //=--------------------------------------------------------------------------=
  496. // IUnknown Release (Notifier and MetadataCursor maintain reference count)
  497. //
  498. ULONG CVDCursorBase::Release(void)
  499. {
  500. return (ULONG)E_NOTIMPL;
  501. }
  502. //=--------------------------------------------------------------------------=
  503. // ICursor methods implemented
  504. //=--------------------------------------------------------------------------=
  505. // ICursor SetBindings
  506. //=--------------------------------------------------------------------------=
  507. // Replaces the existing column bindings or adds new column bindings to the
  508. // existing ones
  509. //
  510. // Parameters:
  511. // cCol - [in] the number of columns to bind
  512. // rgBoundColumns - [in] an array of column bindings, one for each
  513. // column for which data is to be returned
  514. // cbRowLength - [in] the number of bytes of inline memory in a
  515. // single row of data
  516. // dwFlags - [in] a flag that specifies whether to replace the
  517. // existing column bindings or add to them
  518. //
  519. // Output:
  520. // HRESULT - S_OK if successful
  521. // E_OUTOFMEMORY not enough memory
  522. //
  523. // Notes:
  524. // Parameter validation is performed by derived classes
  525. //
  526. HRESULT CVDCursorBase::SetBindings(ULONG cCol, CURSOR_DBCOLUMNBINDING rgBoundColumns[], ULONG cbRowLength, DWORD dwFlags)
  527. {
  528. // reset flag
  529. m_fNeedVarData = FALSE;
  530. // if we should replace, then first destroy existing bindings
  531. if (dwFlags == CURSOR_DBCOLUMNBINDOPTS_REPLACE)
  532. DestroyCursorBindings(&m_pCursorBindings, &m_ulCursorBindings);
  533. // if no new bindings are supplied, we're done
  534. if (!cCol)
  535. return S_OK;
  536. // create new storage
  537. CURSOR_DBCOLUMNBINDING * pCursorBindings = new CURSOR_DBCOLUMNBINDING[m_ulCursorBindings + cCol];
  538. if (!pCursorBindings)
  539. {
  540. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  541. return E_OUTOFMEMORY;
  542. }
  543. // if we have exsiting bindings, then copy them over
  544. if (m_pCursorBindings)
  545. memcpy(pCursorBindings, m_pCursorBindings, m_ulCursorBindings * sizeof(CURSOR_DBCOLUMNBINDING));
  546. // then append new bindings directly,
  547. memcpy(pCursorBindings + m_ulCursorBindings, rgBoundColumns, cCol * sizeof(CURSOR_DBCOLUMNBINDING));
  548. // and adjust possible cursor column identifier names in new bindings
  549. for (ULONG ulBind = m_ulCursorBindings; ulBind < m_ulCursorBindings + cCol; ulBind++)
  550. {
  551. CURSOR_DBCOLUMNID * pCursorColumnID = &pCursorBindings[ulBind].columnID;
  552. if (pCursorColumnID->dwKind == CURSOR_DBCOLKIND_GUID_NAME || pCursorColumnID->dwKind == CURSOR_DBCOLKIND_NAME)
  553. {
  554. const int nLength = lstrlenW(pCursorColumnID->lpdbsz);
  555. WCHAR * pwszName = new WCHAR[nLength + 1];
  556. if (!pwszName)
  557. {
  558. DestroyCursorBindings(&pCursorBindings, &ulBind);
  559. delete [] m_pCursorBindings;
  560. m_ulCursorBindings = 0;
  561. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  562. return E_OUTOFMEMORY;
  563. }
  564. memcpy(pwszName, pCursorColumnID->lpdbsz, (nLength + 1) * sizeof(WCHAR));
  565. pCursorColumnID->lpdbsz = pwszName;
  566. }
  567. }
  568. m_ulCursorBindings += cCol;
  569. // delete previous storage
  570. // any existing bindings will have been copied over into
  571. delete [] m_pCursorBindings;
  572. m_pCursorBindings = pCursorBindings;
  573. // determine if new bindings need variable length buffer
  574. m_fNeedVarData = DoCursorBindingsNeedVarData();
  575. return S_OK;
  576. }
  577. //=--------------------------------------------------------------------------=
  578. // ICursor GetBindings
  579. //=--------------------------------------------------------------------------=
  580. // Returns the current column bindings
  581. //
  582. // Parameters:
  583. // pcCol - [out] a pointer to memory in which to return the
  584. // number of bound columns
  585. // prgBoundColumns - [out] a pointer to memory in which to return a
  586. // pointer to an array containing the current
  587. // column bindings (callee allocated)
  588. // pcbRowLength - [out] a pointer to memory in which to return the
  589. // number of bytes of inline memory in a single
  590. // row
  591. //
  592. // Output:
  593. // HRESULT - S_OK if successful
  594. // E_OUTOFMEMORY not enough memory
  595. //
  596. // Notes:
  597. //
  598. HRESULT CVDCursorBase::GetBindings(ULONG *pcCol,
  599. CURSOR_DBCOLUMNBINDING *prgBoundColumns[],
  600. ULONG *pcbRowLength)
  601. {
  602. ASSERT_NULL_OR_POINTER(pcCol, ULONG)
  603. ASSERT_NULL_OR_POINTER(prgBoundColumns, CURSOR_DBCOLUMNBINDING)
  604. ASSERT_NULL_OR_POINTER(pcbRowLength, ULONG)
  605. // init out parameters
  606. if (pcCol)
  607. *pcCol = 0;
  608. if (prgBoundColumns)
  609. *prgBoundColumns = NULL;
  610. if (pcbRowLength)
  611. *pcbRowLength = 0;
  612. // return column bindings
  613. if (prgBoundColumns && m_ulCursorBindings)
  614. {
  615. // calculate size of bindings
  616. ULONG cbBindings = m_ulCursorBindings * sizeof(CURSOR_DBCOLUMNBINDING);
  617. // calculate extra space needed for names in column identifers
  618. ULONG cbNames = 0;
  619. for (ULONG ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  620. cbNames += GetCursorColumnIDNameLength(m_pCursorBindings[ulBind].columnID);
  621. // allocate memory for bindings and names
  622. CURSOR_DBCOLUMNBINDING * pCursorBindings = (CURSOR_DBCOLUMNBINDING*)g_pMalloc->Alloc(cbBindings + cbNames);
  623. if (!pCursorBindings)
  624. {
  625. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  626. return E_OUTOFMEMORY;
  627. }
  628. // copy bindings directly
  629. memcpy(pCursorBindings, m_pCursorBindings, cbBindings);
  630. // adjust column identifier names
  631. WCHAR * pwszName = (WCHAR*)(pCursorBindings + m_ulCursorBindings);
  632. for (ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  633. {
  634. CURSOR_DBCOLUMNID * pCursorColumnID = &pCursorBindings[ulBind].columnID;
  635. if (pCursorColumnID->dwKind == CURSOR_DBCOLKIND_GUID_NAME || pCursorColumnID->dwKind == CURSOR_DBCOLKIND_NAME)
  636. {
  637. const int nLength = lstrlenW(pCursorColumnID->lpdbsz);
  638. memcpy(pwszName, pCursorColumnID->lpdbsz, (nLength + 1) * sizeof(WCHAR));
  639. pCursorColumnID->lpdbsz = pwszName;
  640. pwszName += nLength + 1;
  641. }
  642. }
  643. *prgBoundColumns = pCursorBindings;
  644. // sanity check
  645. ASSERT_((BYTE*)pwszName == ((BYTE*)pCursorBindings) + cbBindings + cbNames);
  646. }
  647. // return bound column count
  648. if (pcCol)
  649. *pcCol = m_ulCursorBindings;
  650. // return row length
  651. if (pcbRowLength)
  652. *pcbRowLength = m_cbRowLength;
  653. return S_OK;
  654. }