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.

3836 lines
100 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. // ATLDBCLI.H : ATL consumer code for OLEDB
  11. #ifndef __ATLDBCLI_H_
  12. #define __ATLDBCLI_H_
  13. #ifndef __cplusplus
  14. #error ATL requires C++ compilation (use a .cpp suffix)
  15. #endif
  16. #ifndef _ATLBASE_H
  17. #include <atlbase.h>
  18. #endif
  19. #ifndef __oledb_h__
  20. #include <oledb.h>
  21. #endif // __oledb_h__
  22. #include <msdaguid.h>
  23. #include <msdasc.h>
  24. namespace ATL
  25. {
  26. #define DEFINE_OLEDB_TYPE_FUNCTION(ctype, oledbtype) \
  27. inline DBTYPE _GetOleDBType(ctype&) \
  28. { \
  29. return oledbtype; \
  30. }
  31. inline DBTYPE _GetOleDBType(BYTE[])
  32. {
  33. return DBTYPE_BYTES;
  34. }
  35. inline DBTYPE _GetOleDBType(CHAR[])
  36. {
  37. return DBTYPE_STR;
  38. }
  39. inline DBTYPE _GetOleDBType(WCHAR[])
  40. {
  41. return DBTYPE_WSTR;
  42. }
  43. DEFINE_OLEDB_TYPE_FUNCTION(signed char ,DBTYPE_I1)
  44. DEFINE_OLEDB_TYPE_FUNCTION(SHORT ,DBTYPE_I2) // DBTYPE_BOOL
  45. DEFINE_OLEDB_TYPE_FUNCTION(int ,DBTYPE_I4)
  46. DEFINE_OLEDB_TYPE_FUNCTION(LONG ,DBTYPE_I4) // DBTYPE_ERROR (SCODE)
  47. DEFINE_OLEDB_TYPE_FUNCTION(LARGE_INTEGER ,DBTYPE_I8) // DBTYPE_CY
  48. DEFINE_OLEDB_TYPE_FUNCTION(BYTE ,DBTYPE_UI1)
  49. DEFINE_OLEDB_TYPE_FUNCTION(unsigned short ,DBTYPE_UI2)
  50. DEFINE_OLEDB_TYPE_FUNCTION(unsigned int ,DBTYPE_UI4)
  51. DEFINE_OLEDB_TYPE_FUNCTION(unsigned long ,DBTYPE_UI4)
  52. DEFINE_OLEDB_TYPE_FUNCTION(ULARGE_INTEGER ,DBTYPE_UI8)
  53. DEFINE_OLEDB_TYPE_FUNCTION(float ,DBTYPE_R4)
  54. DEFINE_OLEDB_TYPE_FUNCTION(double ,DBTYPE_R8) // DBTYPE_DATE
  55. DEFINE_OLEDB_TYPE_FUNCTION(DECIMAL ,DBTYPE_DECIMAL)
  56. DEFINE_OLEDB_TYPE_FUNCTION(DB_NUMERIC ,DBTYPE_NUMERIC)
  57. DEFINE_OLEDB_TYPE_FUNCTION(VARIANT ,DBTYPE_VARIANT)
  58. DEFINE_OLEDB_TYPE_FUNCTION(IDispatch* ,DBTYPE_IDISPATCH)
  59. DEFINE_OLEDB_TYPE_FUNCTION(IUnknown* ,DBTYPE_IUNKNOWN)
  60. DEFINE_OLEDB_TYPE_FUNCTION(GUID ,DBTYPE_GUID)
  61. DEFINE_OLEDB_TYPE_FUNCTION(SAFEARRAY* ,DBTYPE_ARRAY)
  62. DEFINE_OLEDB_TYPE_FUNCTION(DBVECTOR ,DBTYPE_VECTOR)
  63. DEFINE_OLEDB_TYPE_FUNCTION(DBDATE ,DBTYPE_DBDATE)
  64. DEFINE_OLEDB_TYPE_FUNCTION(DBTIME ,DBTYPE_DBTIME)
  65. DEFINE_OLEDB_TYPE_FUNCTION(DBTIMESTAMP ,DBTYPE_DBTIMESTAMP)
  66. DEFINE_OLEDB_TYPE_FUNCTION(FILETIME ,DBTYPE_FILETIME)
  67. DEFINE_OLEDB_TYPE_FUNCTION(PROPVARIANT ,DBTYPE_PROPVARIANT)
  68. DEFINE_OLEDB_TYPE_FUNCTION(DB_VARNUMERIC ,DBTYPE_VARNUMERIC)
  69. // Internal structure containing the accessor handle and a flag
  70. // indicating whether the data for the accessor is automatically
  71. // retrieved
  72. struct _ATL_ACCESSOR_INFO
  73. {
  74. HACCESSOR hAccessor;
  75. bool bAutoAccessor;
  76. };
  77. class _CNoOutputColumns
  78. {
  79. public:
  80. static bool HasOutputColumns()
  81. {
  82. return false;
  83. }
  84. static ULONG _GetNumAccessors()
  85. {
  86. return 0;
  87. }
  88. static HRESULT _GetBindEntries(ULONG*, DBBINDING*, ULONG, bool*, BYTE* pBuffer = NULL)
  89. {
  90. pBuffer;
  91. return E_FAIL;
  92. }
  93. };
  94. class _CNoParameters
  95. {
  96. public:
  97. static bool HasParameters()
  98. {
  99. return false;
  100. }
  101. static HRESULT _GetParamEntries(ULONG*, DBBINDING*, BYTE* pBuffer = NULL)
  102. {
  103. pBuffer;
  104. return E_FAIL;
  105. }
  106. };
  107. class _CNoCommand
  108. {
  109. public:
  110. static HRESULT GetDefaultCommand(LPCTSTR* /*ppszCommand*/)
  111. {
  112. return S_OK;
  113. }
  114. };
  115. typedef _CNoOutputColumns _OutputColumnsClass;
  116. typedef _CNoParameters _ParamClass;
  117. typedef _CNoCommand _CommandClass;
  118. #define BEGIN_ACCESSOR_MAP(x, num) \
  119. public: \
  120. typedef x _classtype; \
  121. typedef x _OutputColumnsClass; \
  122. static ULONG _GetNumAccessors() { return num; } \
  123. static bool HasOutputColumns() { return true; } \
  124. /* If pBindings == NULL means we only return the column number */ \
  125. /* If pBuffer != NULL then it points to the accessor buffer and */ \
  126. /* we release any appropriate memory e.g. BSTR's or interface pointers */ \
  127. inline static HRESULT _GetBindEntries(ULONG* pColumns, DBBINDING *pBinding, ULONG nAccessor, bool* pAuto, BYTE* pBuffer = NULL) \
  128. { \
  129. ATLASSERT(pColumns != NULL); \
  130. DBPARAMIO eParamIO = DBPARAMIO_NOTPARAM; \
  131. ULONG nColumns = 0; \
  132. pBuffer;
  133. #define BEGIN_ACCESSOR(num, bAuto) \
  134. if (nAccessor == num) \
  135. { \
  136. if (pBinding != NULL) \
  137. *pAuto = bAuto;
  138. #define END_ACCESSOR() \
  139. } \
  140. else
  141. #define END_ACCESSOR_MAP() \
  142. ; \
  143. *pColumns = nColumns; \
  144. return S_OK; \
  145. }
  146. #define BEGIN_COLUMN_MAP(x) \
  147. BEGIN_ACCESSOR_MAP(x, 1) \
  148. BEGIN_ACCESSOR(0, true)
  149. #define END_COLUMN_MAP() \
  150. END_ACCESSOR() \
  151. END_ACCESSOR_MAP()
  152. #define offsetbuf(m) offsetof(_classtype, m)
  153. #define _OLEDB_TYPE(data) _GetOleDBType(((_classtype*)0)->data)
  154. #define _SIZE_TYPE(data) sizeof(((_classtype*)0)->data)
  155. #define _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, nPrecision, nScale, dataOffset, lengthOffset, statusOffset) \
  156. if (pBuffer != NULL) \
  157. { \
  158. CAccessorBase::FreeType(wType, pBuffer + dataOffset); \
  159. } \
  160. else if (pBinding != NULL) \
  161. { \
  162. CAccessorBase::Bind(pBinding, nOrdinal, wType, nLength, nPrecision, nScale, eParamIO, \
  163. dataOffset, lengthOffset, statusOffset); \
  164. pBinding++; \
  165. } \
  166. nColumns++;
  167. #define COLUMN_ENTRY_EX(nOrdinal, wType, nLength, nPrecision, nScale, data, length, status) \
  168. _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  169. #define COLUMN_ENTRY_TYPE(nOrdinal, wType, data) \
  170. COLUMN_ENTRY_TYPE_SIZE(nOrdinal, wType, _SIZE_TYPE(data), data)
  171. #define COLUMN_ENTRY_TYPE_SIZE(nOrdinal, wType, nLength, data) \
  172. _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, 0, 0, offsetbuf(data), 0, 0)
  173. // Standard macros where type and size is worked out
  174. #define COLUMN_ENTRY(nOrdinal, data) \
  175. COLUMN_ENTRY_TYPE(nOrdinal, _OLEDB_TYPE(data), data)
  176. #define COLUMN_ENTRY_LENGTH(nOrdinal, data, length) \
  177. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), 0)
  178. #define COLUMN_ENTRY_STATUS(nOrdinal, data, status) \
  179. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), 0, offsetbuf(status))
  180. #define COLUMN_ENTRY_LENGTH_STATUS(nOrdinal, data, length, status) \
  181. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  182. // Follow macros are used if precision and scale need to be specified
  183. #define COLUMN_ENTRY_PS(nOrdinal, nPrecision, nScale, data) \
  184. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, 0)
  185. #define COLUMN_ENTRY_PS_LENGTH(nOrdinal, nPrecision, nScale, data, length) \
  186. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), 0)
  187. #define COLUMN_ENTRY_PS_STATUS(nOrdinal, nPrecision, nScale, data, status) \
  188. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, offsetbuf(status))
  189. #define COLUMN_ENTRY_PS_LENGTH_STATUS(nOrdinal, nPrecision, nScale, data, length, status) \
  190. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  191. #define BOOKMARK_ENTRY(variable) \
  192. COLUMN_ENTRY_TYPE_SIZE(0, DBTYPE_BYTES, _SIZE_TYPE(variable##.m_rgBuffer), variable##.m_rgBuffer)
  193. #define _BLOB_ENTRY_CODE(nOrdinal, IID, flags, dataOffset, statusOffset) \
  194. if (pBuffer != NULL) \
  195. { \
  196. CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
  197. } \
  198. else if (pBinding != NULL) \
  199. { \
  200. DBOBJECT* pObject = NULL; \
  201. ATLTRY(pObject = new DBOBJECT); \
  202. if (pObject == NULL) \
  203. return E_OUTOFMEMORY; \
  204. pObject->dwFlags = flags; \
  205. pObject->iid = IID; \
  206. CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN, sizeof(IUnknown*), 0, 0, eParamIO, \
  207. dataOffset, 0, statusOffset, pObject); \
  208. pBinding++; \
  209. } \
  210. nColumns++;
  211. #define BLOB_ENTRY(nOrdinal, IID, flags, data) \
  212. _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), 0);
  213. #define BLOB_ENTRY_STATUS(nOrdinal, IID, flags, data, status) \
  214. _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), offsetbuf(status));
  215. #define BEGIN_PARAM_MAP(x) \
  216. public: \
  217. typedef x _classtype; \
  218. typedef x _ParamClass; \
  219. static bool HasParameters() { return true; } \
  220. static HRESULT _GetParamEntries(ULONG* pColumns, DBBINDING *pBinding, BYTE* pBuffer = NULL) \
  221. { \
  222. ATLASSERT(pColumns != NULL); \
  223. DBPARAMIO eParamIO = DBPARAMIO_INPUT; \
  224. int nColumns = 0; \
  225. pBuffer;
  226. #define END_PARAM_MAP() \
  227. *pColumns = nColumns; \
  228. return S_OK; \
  229. }
  230. #define SET_PARAM_TYPE(type) \
  231. eParamIO = type;
  232. #define DEFINE_COMMAND(x, szCommand) \
  233. typedef x _CommandClass; \
  234. static HRESULT GetDefaultCommand(LPCTSTR* ppszCommand) \
  235. { \
  236. *ppszCommand = szCommand; \
  237. return S_OK; \
  238. }
  239. ///////////////////////////////////////////////////////////////////////////
  240. // class CDBErrorInfo
  241. class CDBErrorInfo
  242. {
  243. public:
  244. // Use to get the number of error record when you want to explicitly check that
  245. // the passed interface set the error information
  246. HRESULT GetErrorRecords(IUnknown* pUnk, const IID& iid, ULONG* pcRecords)
  247. {
  248. CComPtr<ISupportErrorInfo> spSupportErrorInfo;
  249. HRESULT hr = pUnk->QueryInterface(&spSupportErrorInfo);
  250. if (FAILED(hr))
  251. return hr;
  252. hr = spSupportErrorInfo->InterfaceSupportsErrorInfo(iid);
  253. if (FAILED(hr))
  254. return hr;
  255. return GetErrorRecords(pcRecords);
  256. }
  257. // Use to get the number of error records
  258. HRESULT GetErrorRecords(ULONG* pcRecords)
  259. {
  260. ATLASSERT(pcRecords != NULL);
  261. HRESULT hr;
  262. m_spErrorInfo.Release();
  263. m_spErrorRecords.Release();
  264. hr = ::GetErrorInfo(0, &m_spErrorInfo);
  265. if (hr == S_FALSE)
  266. return E_FAIL;
  267. hr = m_spErrorInfo->QueryInterface(IID_IErrorRecords, (void**)&m_spErrorRecords);
  268. if (FAILED(hr))
  269. {
  270. // Well we got the IErrorInfo so we'll just treat that as
  271. // the one record
  272. *pcRecords = 1;
  273. return S_OK;
  274. }
  275. return m_spErrorRecords->GetRecordCount(pcRecords);
  276. }
  277. // Get the error information for the passed record number. GetErrorRecords must
  278. // be called before this function is called.
  279. HRESULT GetAllErrorInfo(ULONG ulRecordNum, LCID lcid, BSTR* pbstrDescription,
  280. BSTR* pbstrSource = NULL, GUID* pguid = NULL, DWORD* pdwHelpContext = NULL,
  281. BSTR* pbstrHelpFile = NULL) const
  282. {
  283. CComPtr<IErrorInfo> spErrorInfo;
  284. // If we have the IErrorRecords interface pointer then use it, otherwise
  285. // we'll just default to the IErrorInfo we have already retrieved in the call
  286. // to GetErrorRecords
  287. if (m_spErrorRecords != NULL)
  288. {
  289. HRESULT hr = m_spErrorRecords->GetErrorInfo(ulRecordNum, lcid, &spErrorInfo);
  290. if (FAILED(hr))
  291. return hr;
  292. }
  293. else
  294. {
  295. ATLASSERT(m_spErrorInfo != NULL);
  296. spErrorInfo = m_spErrorInfo;
  297. }
  298. if (pbstrDescription != NULL)
  299. spErrorInfo->GetDescription(pbstrDescription);
  300. if (pguid != NULL)
  301. spErrorInfo->GetGUID(pguid);
  302. if (pdwHelpContext != NULL)
  303. spErrorInfo->GetHelpContext(pdwHelpContext);
  304. if (pbstrHelpFile != NULL)
  305. spErrorInfo->GetHelpFile(pbstrHelpFile);
  306. if (pbstrSource != NULL)
  307. spErrorInfo->GetSource(pbstrSource);
  308. return S_OK;
  309. }
  310. // Get the error information for the passed record number
  311. HRESULT GetBasicErrorInfo(ULONG ulRecordNum, ERRORINFO* pErrorInfo) const
  312. {
  313. return m_spErrorRecords->GetBasicErrorInfo(ulRecordNum, pErrorInfo);
  314. }
  315. // Get the custom error object for the passed record number
  316. HRESULT GetCustomErrorObject(ULONG ulRecordNum, REFIID riid, IUnknown** ppObject) const
  317. {
  318. return m_spErrorRecords->GetCustomErrorObject(ulRecordNum, riid, ppObject);
  319. }
  320. // Get the IErrorInfo interface for the passed record number
  321. HRESULT GetErrorInfo(ULONG ulRecordNum, LCID lcid, IErrorInfo** ppErrorInfo) const
  322. {
  323. return m_spErrorRecords->GetErrorInfo(ulRecordNum, lcid, ppErrorInfo);
  324. }
  325. // Get the error parameters for the passed record number
  326. HRESULT GetErrorParameters(ULONG ulRecordNum, DISPPARAMS* pdispparams) const
  327. {
  328. return m_spErrorRecords->GetErrorParameters(ulRecordNum, pdispparams);
  329. }
  330. // Implementation
  331. CComPtr<IErrorInfo> m_spErrorInfo;
  332. CComPtr<IErrorRecords> m_spErrorRecords;
  333. };
  334. #ifdef _DEBUG
  335. inline void AtlTraceErrorRecords(HRESULT hrErr = S_OK)
  336. {
  337. CDBErrorInfo ErrorInfo;
  338. ULONG cRecords;
  339. HRESULT hr;
  340. ULONG i;
  341. CComBSTR bstrDesc, bstrHelpFile, bstrSource;
  342. GUID guid;
  343. DWORD dwHelpContext;
  344. WCHAR wszGuid[40];
  345. USES_CONVERSION;
  346. // If the user passed in an HRESULT then trace it
  347. if (hrErr != S_OK)
  348. ATLTRACE2(atlTraceDBClient, 0, _T("OLE DB Error Record dump for hr = 0x%x\n"), hrErr);
  349. LCID lcLocale = GetSystemDefaultLCID();
  350. hr = ErrorInfo.GetErrorRecords(&cRecords);
  351. if (FAILED(hr) && ErrorInfo.m_spErrorInfo == NULL)
  352. {
  353. ATLTRACE2(atlTraceDBClient, 0, _T("No OLE DB Error Information found: hr = 0x%x\n"), hr);
  354. }
  355. else
  356. {
  357. for (i = 0; i < cRecords; i++)
  358. {
  359. hr = ErrorInfo.GetAllErrorInfo(i, lcLocale, &bstrDesc, &bstrSource, &guid,
  360. &dwHelpContext, &bstrHelpFile);
  361. if (FAILED(hr))
  362. {
  363. ATLTRACE2(atlTraceDBClient, 0,
  364. _T("OLE DB Error Record dump retrieval failed: hr = 0x%x\n"), hr);
  365. return;
  366. }
  367. StringFromGUID2(guid, wszGuid, sizeof(wszGuid) / sizeof(WCHAR));
  368. ATLTRACE2(atlTraceDBClient, 0,
  369. _T("Row #: %4d Source: \"%s\" Description: \"%s\" Help File: \"%s\" Help Context: %4d GUID: %s\n"),
  370. i, OLE2T(bstrSource), OLE2T(bstrDesc), OLE2T(bstrHelpFile), dwHelpContext, OLE2T(wszGuid));
  371. bstrSource.Empty();
  372. bstrDesc.Empty();
  373. bstrHelpFile.Empty();
  374. }
  375. ATLTRACE2(atlTraceDBClient, 0, _T("OLE DB Error Record dump end\n"));
  376. }
  377. }
  378. #else
  379. inline void AtlTraceErrorRecords(HRESULT hrErr = S_OK) { hrErr; }
  380. #endif
  381. ///////////////////////////////////////////////////////////////////////////
  382. // class CDBPropSet
  383. class CDBPropSet : public tagDBPROPSET
  384. {
  385. public:
  386. CDBPropSet()
  387. {
  388. rgProperties = NULL;
  389. cProperties = 0;
  390. }
  391. CDBPropSet(const GUID& guid)
  392. {
  393. rgProperties = NULL;
  394. cProperties = 0;
  395. guidPropertySet = guid;
  396. }
  397. CDBPropSet(const CDBPropSet& propset)
  398. {
  399. InternalCopy(propset);
  400. }
  401. ~CDBPropSet()
  402. {
  403. for (ULONG i = 0; i < cProperties; i++)
  404. VariantClear(&rgProperties[i].vValue);
  405. CoTaskMemFree(rgProperties);
  406. }
  407. CDBPropSet& operator=(CDBPropSet& propset)
  408. {
  409. this->~CDBPropSet();
  410. InternalCopy(propset);
  411. return *this;
  412. }
  413. // Set the GUID of the property set this class represents.
  414. // Use if you didn't pass the GUID to the constructor.
  415. void SetGUID(const GUID& guid)
  416. {
  417. guidPropertySet = guid;
  418. }
  419. // Add the passed property to the property set
  420. bool AddProperty(DWORD dwPropertyID, const VARIANT& var)
  421. {
  422. HRESULT hr;
  423. if (!Add())
  424. return false;
  425. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  426. hr = ::VariantCopy(&(rgProperties[cProperties].vValue), const_cast<VARIANT*>(&var));
  427. if (FAILED(hr))
  428. return false;
  429. cProperties++;
  430. return true;
  431. }
  432. // Add the passed property to the property set
  433. bool AddProperty(DWORD dwPropertyID, LPCSTR szValue)
  434. {
  435. USES_CONVERSION;
  436. if (!Add())
  437. return false;
  438. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  439. rgProperties[cProperties].vValue.vt = VT_BSTR;
  440. rgProperties[cProperties].vValue.bstrVal = SysAllocString(A2COLE(szValue));
  441. if (rgProperties[cProperties].vValue.bstrVal == NULL)
  442. return false;
  443. cProperties++;
  444. return true;
  445. }
  446. // Add the passed property to the property set
  447. bool AddProperty(DWORD dwPropertyID, LPCWSTR szValue)
  448. {
  449. USES_CONVERSION;
  450. if (!Add())
  451. return false;
  452. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  453. rgProperties[cProperties].vValue.vt = VT_BSTR;
  454. rgProperties[cProperties].vValue.bstrVal = SysAllocString(W2COLE(szValue));
  455. if (rgProperties[cProperties].vValue.bstrVal == NULL)
  456. return false;
  457. cProperties++;
  458. return true;
  459. }
  460. // Add the passed property to the property set
  461. bool AddProperty(DWORD dwPropertyID, bool bValue)
  462. {
  463. if (!Add())
  464. return false;
  465. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  466. rgProperties[cProperties].vValue.vt = VT_BOOL;
  467. #pragma warning(disable: 4310) // cast truncates constant value
  468. rgProperties[cProperties].vValue.boolVal = (bValue) ? VARIANT_TRUE : VARIANT_FALSE;
  469. #pragma warning(default: 4310)
  470. cProperties++;
  471. return true;
  472. }
  473. // Add the passed property to the property set
  474. bool AddProperty(DWORD dwPropertyID, BYTE bValue)
  475. {
  476. if (!Add())
  477. return false;
  478. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  479. rgProperties[cProperties].vValue.vt = VT_UI1;
  480. rgProperties[cProperties].vValue.bVal = bValue;
  481. cProperties++;
  482. return true;
  483. }
  484. // Add the passed property to the property set
  485. bool AddProperty(DWORD dwPropertyID, short nValue)
  486. {
  487. if (!Add())
  488. return false;
  489. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  490. rgProperties[cProperties].vValue.vt = VT_I2;
  491. rgProperties[cProperties].vValue.iVal = nValue;
  492. cProperties++;
  493. return true;
  494. }
  495. // Add the passed property to the property set
  496. bool AddProperty(DWORD dwPropertyID, long nValue)
  497. {
  498. if (!Add())
  499. return false;
  500. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  501. rgProperties[cProperties].vValue.vt = VT_I4;
  502. rgProperties[cProperties].vValue.lVal = nValue;
  503. cProperties++;
  504. return true;
  505. }
  506. // Add the passed property to the property set
  507. bool AddProperty(DWORD dwPropertyID, float fltValue)
  508. {
  509. if (!Add())
  510. return false;
  511. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  512. rgProperties[cProperties].vValue.vt = VT_R4;
  513. rgProperties[cProperties].vValue.fltVal = fltValue;
  514. cProperties++;
  515. return true;
  516. }
  517. // Add the passed property to the property set
  518. bool AddProperty(DWORD dwPropertyID, double dblValue)
  519. {
  520. if (!Add())
  521. return false;
  522. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  523. rgProperties[cProperties].vValue.vt = VT_R8;
  524. rgProperties[cProperties].vValue.dblVal = dblValue;
  525. cProperties++;
  526. return true;
  527. }
  528. // Add the passed property to the property set
  529. bool AddProperty(DWORD dwPropertyID, CY cyValue)
  530. {
  531. if (!Add())
  532. return false;
  533. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  534. rgProperties[cProperties].vValue.vt = VT_CY;
  535. rgProperties[cProperties].vValue.cyVal = cyValue;
  536. cProperties++;
  537. return true;
  538. }
  539. // Implementation
  540. // Create memory to add a new property
  541. bool Add()
  542. {
  543. DBPROP* rgNewProperties;
  544. rgNewProperties = (DBPROP*)CoTaskMemRealloc(rgProperties, (cProperties + 1) * sizeof(DBPROP));
  545. if (rgNewProperties != NULL)
  546. {
  547. rgProperties = rgNewProperties;
  548. rgProperties[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED;
  549. rgProperties[cProperties].colid = DB_NULLID;
  550. rgProperties[cProperties].vValue.vt = VT_EMPTY;
  551. return true;
  552. }
  553. else
  554. return false;
  555. }
  556. // Copies in the passed value now it this value been cleared
  557. void InternalCopy(const CDBPropSet& propset)
  558. {
  559. cProperties = propset.cProperties;
  560. guidPropertySet = propset.guidPropertySet;
  561. rgProperties = (DBPROP*)CoTaskMemAlloc(cProperties * sizeof(DBPROP));
  562. if (rgProperties != NULL)
  563. {
  564. for (ULONG i = 0; i < cProperties; i++)
  565. {
  566. rgProperties[i].dwPropertyID = propset.rgProperties[i].dwPropertyID;
  567. rgProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
  568. rgProperties[i].colid = DB_NULLID;
  569. rgProperties[i].vValue.vt = VT_EMPTY;
  570. VariantCopy(&rgProperties[i].vValue, &propset.rgProperties[i].vValue);
  571. }
  572. }
  573. else
  574. {
  575. // The memory allocation failed so set the count
  576. // of properties to zero
  577. cProperties = 0;
  578. }
  579. }
  580. };
  581. ///////////////////////////////////////////////////////////////////////////
  582. // class CDBPropIDSet
  583. class CDBPropIDSet : public tagDBPROPIDSET
  584. {
  585. // Constructors and Destructors
  586. public:
  587. CDBPropIDSet()
  588. {
  589. rgPropertyIDs = NULL;
  590. cPropertyIDs = 0;
  591. }
  592. CDBPropIDSet(const GUID& guid)
  593. {
  594. rgPropertyIDs = NULL;
  595. cPropertyIDs = 0;
  596. guidPropertySet = guid;
  597. }
  598. CDBPropIDSet(const CDBPropIDSet& propidset)
  599. {
  600. InternalCopy(propidset);
  601. }
  602. ~CDBPropIDSet()
  603. {
  604. if (rgPropertyIDs != NULL)
  605. free(rgPropertyIDs);
  606. }
  607. CDBPropIDSet& operator=(CDBPropIDSet& propset)
  608. {
  609. this->~CDBPropIDSet();
  610. InternalCopy(propset);
  611. return *this;
  612. }
  613. // Set the GUID of the property ID set
  614. void SetGUID(const GUID& guid)
  615. {
  616. guidPropertySet = guid;
  617. }
  618. // Add a property ID to the set
  619. bool AddPropertyID(DBPROPID propid)
  620. {
  621. if (!Add())
  622. return false;
  623. rgPropertyIDs[cPropertyIDs] = propid;
  624. cPropertyIDs++;
  625. return true;
  626. }
  627. // Implementation
  628. bool Add()
  629. {
  630. DBPROPID* rgNewPropertyIDs;
  631. rgNewPropertyIDs = (DBPROPID*)realloc(rgPropertyIDs, (cPropertyIDs + 1) * sizeof(DBPROPID));
  632. if (rgNewPropertyIDs == NULL)
  633. return false;
  634. else
  635. {
  636. rgPropertyIDs = rgNewPropertyIDs;
  637. return true;
  638. }
  639. }
  640. void InternalCopy(const CDBPropIDSet& propidset)
  641. {
  642. cPropertyIDs = propidset.cPropertyIDs;
  643. guidPropertySet = propidset.guidPropertySet;
  644. rgPropertyIDs = (DBPROPID*)malloc(cPropertyIDs * sizeof(DBPROPID));
  645. if (rgPropertyIDs != NULL)
  646. {
  647. for (ULONG i = 0; i < cPropertyIDs; i++)
  648. rgPropertyIDs[i] = propidset.rgPropertyIDs[i];
  649. }
  650. else
  651. {
  652. // The memory allocation failed so set the count
  653. // of properties to zero
  654. cPropertyIDs = 0;
  655. }
  656. }
  657. };
  658. ///////////////////////////////////////////////////////////////////////////
  659. // class CBookmarkBase
  660. class ATL_NO_VTABLE CBookmarkBase
  661. {
  662. public:
  663. virtual ULONG_PTR GetSize() const = 0;
  664. virtual BYTE* GetBuffer() const = 0;
  665. };
  666. ///////////////////////////////////////////////////////////////////////////
  667. // class CBookmark
  668. template <ULONG_PTR nSize = 0>
  669. class CBookmark : public CBookmarkBase
  670. {
  671. public:
  672. virtual ULONG_PTR GetSize() const { return nSize; }
  673. virtual BYTE* GetBuffer() const { return (BYTE*)m_rgBuffer; }
  674. // Implementation
  675. BYTE m_rgBuffer[nSize];
  676. };
  677. // Size of 0 means that the memory for the bookmark will be allocated
  678. // at run time.
  679. template <>
  680. class CBookmark<0> : public CBookmarkBase
  681. {
  682. public:
  683. CBookmark()
  684. {
  685. m_nSize = 0;
  686. m_pBuffer = NULL;
  687. }
  688. CBookmark(ULONG_PTR nSize)
  689. {
  690. m_pBuffer = NULL;
  691. ATLTRY(m_pBuffer = new BYTE[(size_t)nSize]); //REVIEW
  692. m_nSize = (m_pBuffer == NULL) ? 0 : nSize;
  693. }
  694. ~CBookmark()
  695. {
  696. delete [] m_pBuffer;
  697. }
  698. CBookmark& operator=(const CBookmark& bookmark)
  699. {
  700. SetBookmark(bookmark.GetSize(), bookmark.GetBuffer());
  701. return *this;
  702. }
  703. virtual ULONG_PTR GetSize() const { return m_nSize; }
  704. virtual BYTE* GetBuffer() const { return m_pBuffer; }
  705. // Sets the bookmark to the passed value
  706. HRESULT SetBookmark(ULONG_PTR nSize, BYTE* pBuffer)
  707. {
  708. ATLASSERT(pBuffer != NULL);
  709. delete [] m_pBuffer;
  710. m_pBuffer = NULL;
  711. ATLTRY(m_pBuffer = new BYTE[(size_t)nSize]); //REVIEW
  712. if (m_pBuffer != NULL)
  713. {
  714. memcpy(m_pBuffer, pBuffer, (size_t)nSize); //REVIEW
  715. m_nSize = nSize;
  716. return S_OK;
  717. }
  718. else
  719. {
  720. m_nSize = 0;
  721. return E_OUTOFMEMORY;
  722. }
  723. }
  724. ULONG_PTR m_nSize;
  725. BYTE* m_pBuffer;
  726. };
  727. ///////////////////////////////////////////////////////////////////////////
  728. // class CAccessorBase
  729. class CAccessorBase
  730. {
  731. public:
  732. CAccessorBase()
  733. {
  734. m_pAccessorInfo = NULL;
  735. m_nAccessors = 0;
  736. m_pBuffer = NULL;
  737. }
  738. void Close()
  739. {
  740. // If Close is called then ReleaseAccessors must have been
  741. // called first
  742. ATLASSERT(m_nAccessors == 0);
  743. ATLASSERT(m_pAccessorInfo == NULL);
  744. }
  745. // Get the number of accessors that have been created
  746. ULONG GetNumAccessors() const { return m_nAccessors; }
  747. // Get the handle of the passed accessor (offset from 0)
  748. HACCESSOR GetHAccessor(ULONG nAccessor) const
  749. {
  750. ATLASSERT(nAccessor<m_nAccessors);
  751. return m_pAccessorInfo[nAccessor].hAccessor;
  752. };
  753. // Called during Close to release the accessor information
  754. HRESULT ReleaseAccessors(IUnknown* pUnk)
  755. {
  756. ATLASSERT(pUnk != NULL);
  757. HRESULT hr = S_OK;
  758. if (m_nAccessors > 0)
  759. {
  760. CComPtr<IAccessor> spAccessor;
  761. hr = pUnk->QueryInterface(IID_IAccessor, (void**)&spAccessor);
  762. if (SUCCEEDED(hr))
  763. {
  764. ATLASSERT(m_pAccessorInfo != NULL);
  765. for (ULONG i = 0; i < m_nAccessors; i++)
  766. spAccessor->ReleaseAccessor(m_pAccessorInfo[i].hAccessor, NULL);
  767. }
  768. m_nAccessors = 0;
  769. delete [] m_pAccessorInfo;
  770. m_pAccessorInfo = NULL;
  771. }
  772. return hr;
  773. }
  774. // Returns true or false depending upon whether data should be
  775. // automatically retrieved for the passed accessor.
  776. bool IsAutoAccessor(ULONG nAccessor) const
  777. {
  778. ATLASSERT(nAccessor < m_nAccessors);
  779. ATLASSERT(m_pAccessorInfo != NULL);
  780. return m_pAccessorInfo[nAccessor].bAutoAccessor;
  781. }
  782. // Implementation
  783. // Used by the rowset class to find out where to place the data
  784. BYTE* GetBuffer() const
  785. {
  786. return m_pBuffer;
  787. }
  788. // Set the buffer that is used to retrieve the data
  789. void SetBuffer(BYTE* pBuffer)
  790. {
  791. m_pBuffer = pBuffer;
  792. }
  793. // Allocate internal memory for the passed number of accessors
  794. HRESULT AllocateAccessorMemory(int nAccessors)
  795. {
  796. // Can't be called twice without calling ReleaseAccessors first
  797. ATLASSERT(m_pAccessorInfo == NULL);
  798. m_nAccessors = nAccessors;
  799. m_pAccessorInfo = NULL;
  800. ATLTRY(m_pAccessorInfo = new _ATL_ACCESSOR_INFO[nAccessors]);
  801. if (m_pAccessorInfo == NULL)
  802. return E_OUTOFMEMORY;
  803. else
  804. return S_OK;
  805. }
  806. // BindParameters will be overriden if parameters are used
  807. HRESULT BindParameters(HACCESSOR*, ICommand*, void**) { return S_OK; }
  808. // Create an accessor for the passed binding information. The created accessor is
  809. // returned through the pHAccessor parameter.
  810. static HRESULT BindEntries(DBBINDING* pBindings, DBCOUNTITEM nColumns, HACCESSOR* pHAccessor,
  811. ULONG_PTR nSize, IAccessor* pAccessor)
  812. {
  813. ATLASSERT(pBindings != NULL);
  814. ATLASSERT(pHAccessor != NULL);
  815. ATLASSERT(pAccessor != NULL);
  816. HRESULT hr;
  817. DBCOUNTITEM i;
  818. DWORD dwAccessorFlags = (pBindings->eParamIO == DBPARAMIO_NOTPARAM) ?
  819. DBACCESSOR_ROWDATA : DBACCESSOR_PARAMETERDATA;
  820. #ifdef _DEBUG
  821. // In debug builds we will retrieve the status flags and trace out
  822. // any errors that may occur.
  823. DBBINDSTATUS* pStatus = NULL;
  824. ATLTRY(pStatus = new DBBINDSTATUS[(size_t)nColumns]); //REVIEW
  825. hr = pAccessor->CreateAccessor(dwAccessorFlags, nColumns,
  826. pBindings, nSize, pHAccessor, pStatus);
  827. if (FAILED(hr) && pStatus != NULL)
  828. {
  829. for (i=0; i<nColumns; i++)
  830. {
  831. if (pStatus[i] != DBBINDSTATUS_OK)
  832. ATLTRACE2(atlTraceDBClient, 0, _T("Binding entry %d failed. Status: %d\n"), i, pStatus[i]);
  833. }
  834. }
  835. delete [] pStatus;
  836. #else
  837. hr = pAccessor->CreateAccessor(dwAccessorFlags, nColumns,
  838. pBindings, nSize, pHAccessor, NULL);
  839. #endif
  840. for (i=0; i<nColumns; i++)
  841. delete pBindings[i].pObject;
  842. return hr;
  843. }
  844. // Set up the binding structure pointed to by pBindings based upon
  845. // the other passed parameters.
  846. static void Bind(DBBINDING* pBinding, ULONG_PTR nOrdinal, DBTYPE wType,
  847. ULONG_PTR nLength, BYTE nPrecision, BYTE nScale, DBPARAMIO eParamIO,
  848. ULONG_PTR nDataOffset, ULONG_PTR nLengthOffset = NULL, ULONG_PTR nStatusOffset = NULL,
  849. DBOBJECT* pdbobject = NULL)
  850. {
  851. ATLASSERT(pBinding != NULL);
  852. // If we are getting a pointer to the data then let the provider
  853. // own the memory
  854. if (wType & DBTYPE_BYREF)
  855. pBinding->dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
  856. else
  857. pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  858. pBinding->pObject = pdbobject;
  859. pBinding->eParamIO = eParamIO;
  860. pBinding->iOrdinal = nOrdinal;
  861. pBinding->wType = wType;
  862. pBinding->bPrecision = nPrecision;
  863. pBinding->bScale = nScale;
  864. pBinding->dwFlags = 0;
  865. pBinding->obValue = nDataOffset;
  866. pBinding->obLength = 0;
  867. pBinding->obStatus = 0;
  868. pBinding->pTypeInfo = NULL;
  869. pBinding->pBindExt = NULL;
  870. pBinding->cbMaxLen = nLength;
  871. pBinding->dwPart = DBPART_VALUE;
  872. if (nLengthOffset != NULL)
  873. {
  874. pBinding->dwPart |= DBPART_LENGTH;
  875. pBinding->obLength = nLengthOffset;
  876. }
  877. if (nStatusOffset != NULL)
  878. {
  879. pBinding->dwPart |= DBPART_STATUS;
  880. pBinding->obStatus = nStatusOffset;
  881. }
  882. }
  883. // Free memory if appropriate
  884. static inline void FreeType(DBTYPE wType, BYTE* pValue, IRowset* pRowset = NULL)
  885. {
  886. switch (wType)
  887. {
  888. case DBTYPE_BSTR:
  889. SysFreeString(*((BSTR*)pValue));
  890. break;
  891. case DBTYPE_VARIANT:
  892. VariantClear((VARIANT*)pValue);
  893. break;
  894. case DBTYPE_IUNKNOWN:
  895. case DBTYPE_IDISPATCH:
  896. (*(IUnknown**)pValue)->Release();
  897. break;
  898. case DBTYPE_ARRAY:
  899. SafeArrayDestroy((SAFEARRAY*)pValue);
  900. break;
  901. case DBTYPE_HCHAPTER:
  902. CComQIPtr<IChapteredRowset> spChapteredRowset = pRowset;
  903. if (spChapteredRowset != NULL)
  904. spChapteredRowset->ReleaseChapter(*(HCHAPTER*)pValue, NULL);
  905. break;
  906. }
  907. if ((wType & DBTYPE_VECTOR) && ~(wType & DBTYPE_BYREF))
  908. CoTaskMemFree(((DBVECTOR*)pValue)->ptr);
  909. }
  910. _ATL_ACCESSOR_INFO* m_pAccessorInfo;
  911. ULONG m_nAccessors;
  912. BYTE* m_pBuffer;
  913. };
  914. ///////////////////////////////////////////////////////////////////////////
  915. // class CRowset
  916. class CRowset
  917. {
  918. // Constructors and Destructors
  919. public:
  920. CRowset()
  921. {
  922. m_pAccessor = NULL;
  923. m_hRow = NULL;
  924. }
  925. CRowset(IRowset* pRowset)
  926. {
  927. m_spRowset = pRowset;
  928. CRowset();
  929. }
  930. ~CRowset()
  931. {
  932. Close();
  933. }
  934. // Release any retrieved row handles and then release the rowset
  935. void Close()
  936. {
  937. if (m_spRowset != NULL)
  938. {
  939. ReleaseRows();
  940. m_spRowset.Release();
  941. m_spRowsetChange.Release();
  942. }
  943. }
  944. // Addref the current row
  945. HRESULT AddRefRows()
  946. {
  947. ATLASSERT(m_spRowset != NULL);
  948. return m_spRowset->AddRefRows(1, &m_hRow, NULL, NULL);
  949. }
  950. // Release the current row
  951. HRESULT ReleaseRows()
  952. {
  953. ATLASSERT(m_spRowset != NULL);
  954. HRESULT hr = S_OK;
  955. if (m_hRow != NULL)
  956. {
  957. hr = m_spRowset->ReleaseRows(1, &m_hRow, NULL, NULL, NULL);
  958. m_hRow = NULL;
  959. }
  960. return hr;
  961. }
  962. // Compare two bookmarks with each other
  963. HRESULT Compare(const CBookmarkBase& bookmark1, const CBookmarkBase& bookmark2,
  964. DBCOMPARE* pComparison) const
  965. {
  966. ATLASSERT(m_spRowset != NULL);
  967. CComPtr<IRowsetLocate> spLocate;
  968. HRESULT hr = m_spRowset.QueryInterface(&spLocate);
  969. if (FAILED(hr))
  970. return hr;
  971. return spLocate->Compare(NULL, bookmark1.GetSize(), bookmark1.GetBuffer(),
  972. bookmark2.GetSize(), bookmark2.GetBuffer(), pComparison);
  973. }
  974. // Compare the passed hRow with the current row
  975. HRESULT IsSameRow(HROW hRow) const
  976. {
  977. ATLASSERT(m_spRowset != NULL);
  978. CComPtr<IRowsetIdentity> spRowsetIdentity;
  979. HRESULT hr = m_spRowset.QueryInterface(&spRowsetIdentity);
  980. if (FAILED(hr))
  981. return hr;
  982. return spRowsetIdentity->IsSameRow(m_hRow, hRow);
  983. }
  984. // Move to the previous record
  985. HRESULT MovePrev()
  986. {
  987. return MoveNext(-2, true);
  988. }
  989. // Move to the next record
  990. HRESULT MoveNext()
  991. {
  992. return MoveNext(0, true);
  993. }
  994. // Move lSkip records forward or backward
  995. HRESULT MoveNext(LONG lSkip, bool bForward)
  996. {
  997. HRESULT hr;
  998. DBCOUNTITEM ulRowsFetched = 0;
  999. // Check the data was opened successfully and the accessor
  1000. // has been set.
  1001. ATLASSERT(m_spRowset != NULL);
  1002. ATLASSERT(m_pAccessor != NULL);
  1003. // Release a row if one is already around
  1004. ReleaseRows();
  1005. // Get the row handle
  1006. HROW* phRow = &m_hRow;
  1007. hr = m_spRowset->GetNextRows(NULL, lSkip, (bForward) ? 1 : -1, &ulRowsFetched, &phRow);
  1008. if (hr != S_OK)
  1009. return hr;
  1010. // Get the data
  1011. hr = GetData();
  1012. if (FAILED(hr))
  1013. {
  1014. ATLTRACE2(atlTraceDBClient, 0, _T("GetData failed - HRESULT = 0x%X\n"),hr);
  1015. ReleaseRows();
  1016. }
  1017. return hr;
  1018. }
  1019. // Move to the first record
  1020. HRESULT MoveFirst()
  1021. {
  1022. HRESULT hr;
  1023. // Check the data was opened successfully and the accessor
  1024. // has been set.
  1025. ATLASSERT(m_spRowset != NULL);
  1026. ATLASSERT(m_pAccessor != NULL);
  1027. // Release a row if one is already around
  1028. ReleaseRows();
  1029. hr = m_spRowset->RestartPosition(NULL);
  1030. if (FAILED(hr))
  1031. return hr;
  1032. // Get the data
  1033. return MoveNext();
  1034. }
  1035. // Move to the last record
  1036. HRESULT MoveLast()
  1037. {
  1038. // Check the data was opened successfully and the accessor
  1039. // has been set.
  1040. ATLASSERT(m_spRowset != NULL);
  1041. ATLASSERT(m_pAccessor != NULL);
  1042. // Release a row if one is already around
  1043. ReleaseRows();
  1044. HRESULT hr;
  1045. DBCOUNTITEM ulRowsFetched = 0;
  1046. HROW* phRow = &m_hRow;
  1047. // Restart the rowset position and then move backwards
  1048. m_spRowset->RestartPosition(NULL);
  1049. hr = m_spRowset->GetNextRows(NULL, -1, 1, &ulRowsFetched, &phRow);
  1050. if (hr != S_OK)
  1051. return hr;
  1052. // Get the data
  1053. hr = GetData();
  1054. if (FAILED(hr))
  1055. {
  1056. ATLTRACE2(atlTraceDBClient, 0, _T("GetData from MoveLast failed - HRESULT = 0x%X\n"),hr);
  1057. ReleaseRows();
  1058. }
  1059. return S_OK;
  1060. }
  1061. // Move to the passed bookmark
  1062. HRESULT MoveToBookmark(const CBookmarkBase& bookmark, LONG lSkip = 0)
  1063. {
  1064. // Check the data was opened successfully and the accessor
  1065. // has been set.
  1066. ATLASSERT(m_spRowset != NULL);
  1067. ATLASSERT(m_pAccessor != NULL);
  1068. CComPtr<IRowsetLocate> spLocate;
  1069. HRESULT hr = m_spRowset.QueryInterface(&spLocate);
  1070. if (FAILED(hr))
  1071. return hr;
  1072. // Release a row if one is already around
  1073. ReleaseRows();
  1074. DBCOUNTITEM ulRowsFetched = 0;
  1075. HROW* phRow = &m_hRow;
  1076. hr = spLocate->GetRowsAt(NULL, NULL, bookmark.GetSize(), bookmark.GetBuffer(),
  1077. lSkip, 1, &ulRowsFetched, &phRow);
  1078. // Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
  1079. if (hr != S_OK)
  1080. return hr;
  1081. // Get the data
  1082. hr = GetData();
  1083. if (FAILED(hr))
  1084. {
  1085. ATLTRACE2(atlTraceDBClient, 0, _T("GetData from Bookmark failed - HRESULT = 0x%X\n"),hr);
  1086. ReleaseRows();
  1087. }
  1088. return S_OK;
  1089. }
  1090. // Get the data for the current record
  1091. HRESULT GetData()
  1092. {
  1093. HRESULT hr = S_OK;
  1094. ATLASSERT(m_pAccessor != NULL);
  1095. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1096. for (ULONG i=0; i<nAccessors; i++)
  1097. {
  1098. if (m_pAccessor->IsAutoAccessor(i))
  1099. {
  1100. hr = GetData(i);
  1101. if (FAILED(hr))
  1102. return hr;
  1103. }
  1104. }
  1105. return hr;
  1106. }
  1107. // Get the data for the passed accessor. Use for a non-auto accessor
  1108. HRESULT GetData(int nAccessor)
  1109. {
  1110. ATLASSERT(m_spRowset != NULL);
  1111. ATLASSERT(m_pAccessor != NULL);
  1112. ATLASSERT(m_hRow != NULL);
  1113. // Note that we are using the specified buffer if it has been set,
  1114. // otherwise we use the accessor for the data.
  1115. return m_spRowset->GetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor), m_pAccessor->GetBuffer());
  1116. }
  1117. // Get the data for the passed accessor. Use for a non-auto accessor
  1118. HRESULT GetDataHere(int nAccessor, void* pBuffer)
  1119. {
  1120. ATLASSERT(m_spRowset != NULL);
  1121. ATLASSERT(m_pAccessor != NULL);
  1122. ATLASSERT(m_hRow != NULL);
  1123. // Note that we are using the specified buffer if it has been set,
  1124. // otherwise we use the accessor for the data.
  1125. return m_spRowset->GetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor), pBuffer);
  1126. }
  1127. HRESULT GetDataHere(void* pBuffer)
  1128. {
  1129. HRESULT hr = S_OK;
  1130. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1131. for (ULONG i=0; i<nAccessors; i++)
  1132. {
  1133. hr = GetDataHere(i, pBuffer);
  1134. if (FAILED(hr))
  1135. return hr;
  1136. }
  1137. return hr;
  1138. }
  1139. // Insert the current record
  1140. HRESULT Insert(int nAccessor = 0, bool bGetHRow = false)
  1141. {
  1142. ATLASSERT(m_pAccessor != NULL);
  1143. HRESULT hr;
  1144. if (m_spRowsetChange != NULL)
  1145. {
  1146. HROW* pHRow;
  1147. if (bGetHRow)
  1148. {
  1149. ReleaseRows();
  1150. pHRow = &m_hRow;
  1151. }
  1152. else
  1153. pHRow = NULL;
  1154. hr = m_spRowsetChange->InsertRow(NULL, m_pAccessor->GetHAccessor(nAccessor),
  1155. m_pAccessor->GetBuffer(), pHRow);
  1156. }
  1157. else
  1158. hr = E_NOINTERFACE;
  1159. return hr;
  1160. }
  1161. // Delete the current record
  1162. HRESULT Delete() const
  1163. {
  1164. ATLASSERT(m_pAccessor != NULL);
  1165. HRESULT hr;
  1166. if (m_spRowsetChange != NULL)
  1167. hr = m_spRowsetChange->DeleteRows(NULL, 1, &m_hRow, NULL);
  1168. else
  1169. hr = E_NOINTERFACE;
  1170. return hr;
  1171. }
  1172. // Update the current record
  1173. HRESULT SetData() const
  1174. {
  1175. ATLASSERT(m_pAccessor != NULL);
  1176. HRESULT hr = S_OK;
  1177. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1178. for (ULONG i=0; i<nAccessors; i++)
  1179. {
  1180. hr = SetData(i);
  1181. if (FAILED(hr))
  1182. return hr;
  1183. }
  1184. return hr;
  1185. }
  1186. // Update the current record with the data in the passed accessor
  1187. HRESULT SetData(int nAccessor) const
  1188. {
  1189. ATLASSERT(m_pAccessor != NULL);
  1190. HRESULT hr;
  1191. if (m_spRowsetChange != NULL)
  1192. {
  1193. hr = m_spRowsetChange->SetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor),
  1194. m_pAccessor->GetBuffer());
  1195. }
  1196. else
  1197. hr = E_NOINTERFACE;
  1198. return hr;
  1199. }
  1200. // Get the data most recently fetched from or transmitted to the data source.
  1201. // Does not get values based on pending changes.
  1202. HRESULT GetOriginalData()
  1203. {
  1204. ATLASSERT(m_spRowset != NULL);
  1205. ATLASSERT(m_pAccessor != NULL);
  1206. HRESULT hr = S_OK;
  1207. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1208. hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1209. if (FAILED(hr))
  1210. return hr;
  1211. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1212. for (ULONG i = 0; i < nAccessors; i++)
  1213. {
  1214. hr = spRowsetUpdate->GetOriginalData(m_hRow, m_pAccessor->GetHAccessor(i), m_pAccessor->GetBuffer());
  1215. if (FAILED(hr))
  1216. return hr;
  1217. }
  1218. return hr;
  1219. }
  1220. // Get the status of the current row
  1221. HRESULT GetRowStatus(DBPENDINGSTATUS* pStatus) const
  1222. {
  1223. ATLASSERT(m_spRowset != NULL);
  1224. ATLASSERT(pStatus != NULL);
  1225. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1226. HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1227. if (FAILED(hr))
  1228. return hr;
  1229. return spRowsetUpdate->GetRowStatus(NULL, 1, &m_hRow, pStatus);
  1230. }
  1231. // Undo any changes made to the current row since it was last fetched or Update
  1232. // was called for it
  1233. HRESULT Undo(DBCOUNTITEM* pcRows = NULL, HROW* phRow = NULL, DBROWSTATUS* pStatus = NULL)
  1234. {
  1235. ATLASSERT(m_spRowset != NULL);
  1236. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1237. HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1238. if (FAILED(hr))
  1239. return hr;
  1240. HROW* prgRows;
  1241. DBROWSTATUS* pRowStatus;
  1242. if (phRow != NULL)
  1243. hr = spRowsetUpdate->Undo(NULL, 1, &m_hRow, pcRows, &prgRows, &pRowStatus);
  1244. else
  1245. hr = spRowsetUpdate->Undo(NULL, 1, &m_hRow, pcRows, NULL, &pRowStatus);
  1246. if (FAILED(hr))
  1247. return hr;
  1248. if (phRow != NULL)
  1249. {
  1250. *phRow = *prgRows;
  1251. CoTaskMemFree(prgRows);
  1252. }
  1253. if (pStatus != NULL)
  1254. *pStatus = *pRowStatus;
  1255. CoTaskMemFree(pRowStatus);
  1256. return hr;
  1257. }
  1258. // Transmits any pending changes made to a row since it was last fetched or Update was
  1259. // called for it. Also see SetData.
  1260. HRESULT Update(DBCOUNTITEM* pcRows = NULL, HROW* phRow = NULL, DBROWSTATUS* pStatus = NULL)
  1261. {
  1262. ATLASSERT(m_spRowset != NULL);
  1263. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1264. HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1265. if (FAILED(hr))
  1266. return hr;
  1267. HROW* prgRows;
  1268. DBROWSTATUS* pRowStatus;
  1269. if (phRow != NULL)
  1270. hr = spRowsetUpdate->Update(NULL, 1, &m_hRow, pcRows, &prgRows, &pRowStatus);
  1271. else
  1272. hr = spRowsetUpdate->Update(NULL, 1, &m_hRow, pcRows, NULL, &pRowStatus);
  1273. if (FAILED(hr))
  1274. return hr;
  1275. if (phRow != NULL)
  1276. {
  1277. *phRow = *prgRows;
  1278. CoTaskMemFree(prgRows);
  1279. }
  1280. if (pStatus != NULL)
  1281. *pStatus = *pRowStatus;
  1282. CoTaskMemFree(pRowStatus);
  1283. return hr;
  1284. }
  1285. // Get the approximate position of the row corresponding to the passed bookmark
  1286. HRESULT GetApproximatePosition(const CBookmarkBase* pBookmark, DBCOUNTITEM* pPosition, DBCOUNTITEM* pcRows)
  1287. {
  1288. ATLASSERT(m_spRowset != NULL);
  1289. CComPtr<IRowsetScroll> spRowsetScroll;
  1290. HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
  1291. if (SUCCEEDED(hr))
  1292. {
  1293. if (pBookmark != NULL)
  1294. hr = spRowsetScroll->GetApproximatePosition(NULL, pBookmark->GetSize(), pBookmark->GetBuffer(),
  1295. pPosition, pcRows);
  1296. else
  1297. hr = spRowsetScroll->GetApproximatePosition(NULL, 0, NULL, pPosition, pcRows);
  1298. }
  1299. return hr;
  1300. }
  1301. // Move to a fractional position in the rowset
  1302. HRESULT MoveToRatio(ULONG nNumerator, ULONG nDenominator, bool bForward = true)
  1303. {
  1304. ATLASSERT(m_spRowset != NULL);
  1305. DBCOUNTITEM nRowsFetched;
  1306. CComPtr<IRowsetScroll> spRowsetScroll;
  1307. HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
  1308. if (FAILED(hr))
  1309. return hr;
  1310. ReleaseRows();
  1311. HROW* phRow = &m_hRow;
  1312. hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, (bForward) ? 1 : -1,
  1313. &nRowsFetched, &phRow);
  1314. // Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
  1315. if (hr == S_OK)
  1316. hr = GetData();
  1317. return hr;
  1318. }
  1319. // Implementation
  1320. static const IID& GetIID()
  1321. {
  1322. return IID_IRowset;
  1323. }
  1324. IRowset* GetInterface() const
  1325. {
  1326. return m_spRowset;
  1327. }
  1328. IRowset** GetInterfacePtr()
  1329. {
  1330. return &m_spRowset;
  1331. }
  1332. void SetupOptionalRowsetInterfaces()
  1333. {
  1334. // Cache IRowsetChange if available
  1335. if (m_spRowset != NULL)
  1336. m_spRowset->QueryInterface(&m_spRowsetChange);
  1337. }
  1338. HRESULT BindFinished() const { return S_OK; }
  1339. void SetAccessor(CAccessorBase* pAccessor)
  1340. {
  1341. m_pAccessor = pAccessor;
  1342. }
  1343. CComPtr<IRowset> m_spRowset;
  1344. CComPtr<IRowsetChange> m_spRowsetChange;
  1345. CAccessorBase* m_pAccessor;
  1346. HROW m_hRow;
  1347. };
  1348. ///////////////////////////////////////////////////////////////////////////
  1349. // class CBulkRowset
  1350. class CBulkRowset : public CRowset
  1351. {
  1352. public:
  1353. CBulkRowset()
  1354. {
  1355. // Default the number of rows to bulk fetch to 10
  1356. m_nRows = 10;
  1357. m_hr = S_OK;
  1358. m_phRow = NULL;
  1359. }
  1360. CBulkRowset::~CBulkRowset()
  1361. {
  1362. Close();
  1363. delete [] m_phRow;
  1364. }
  1365. // Set the number of row handles that will be retrieved in each
  1366. // bulk row fetch. The default is 10 and this function must be called
  1367. // before Open if you wish to change it.
  1368. void SetRows(ULONG nRows)
  1369. {
  1370. // This function must be called before the memory is allocated
  1371. // during binding
  1372. ATLASSERT(m_phRow == NULL);
  1373. m_nRows = nRows;
  1374. }
  1375. // AddRef all the currently retrieved row handles
  1376. HRESULT AddRefRows()
  1377. {
  1378. ATLASSERT(m_spRowset != NULL);
  1379. return m_spRowset->AddRefRows(m_nCurrentRows, m_phRow, NULL, NULL);
  1380. }
  1381. // Release all the currently retrieved row handles
  1382. HRESULT ReleaseRows()
  1383. {
  1384. ATLASSERT(m_spRowset != NULL);
  1385. // We're going to Release the rows so reset the current row position
  1386. m_nCurrentRow = 0;
  1387. m_hRow = NULL;
  1388. return m_spRowset->ReleaseRows(m_nCurrentRows, m_phRow, NULL, NULL, NULL);
  1389. }
  1390. // Move to the first record
  1391. HRESULT MoveFirst()
  1392. {
  1393. ATLASSERT(m_spRowset != NULL);
  1394. ReleaseRows();
  1395. // Cause MoveNext to perform a new bulk fetch
  1396. m_nCurrentRow = m_nRows;
  1397. HRESULT hr = m_spRowset->RestartPosition(NULL);
  1398. if (FAILED(hr))
  1399. return hr;
  1400. // Get the data
  1401. return MoveNext();
  1402. }
  1403. // Move to the next record
  1404. HRESULT MoveNext()
  1405. {
  1406. ATLASSERT(m_spRowset != NULL);
  1407. ATLASSERT(m_phRow != NULL);
  1408. // Move to the next record in the buffer
  1409. m_nCurrentRow++;
  1410. // Have we reached the end of the buffer?
  1411. if (m_nCurrentRow >= m_nCurrentRows)
  1412. {
  1413. // If we've reached the end of the buffer and we had a non S_OK HRESULT from
  1414. // the last call to GetNextRows then return that HRESULT now.
  1415. if (m_hr != S_OK)
  1416. return m_hr;
  1417. // We've finished with these rows so we need some more
  1418. // First release any HROWs that we have
  1419. ReleaseRows();
  1420. m_hr = m_spRowset->GetNextRows(NULL, 0, m_nRows, &m_nCurrentRows, &m_phRow);
  1421. // If we have an error HRESULT or we haven't retrieved any rows then return
  1422. // the HRESULT now.
  1423. if (FAILED(m_hr) || m_nCurrentRows == 0)
  1424. return m_hr;
  1425. }
  1426. // Get the data for the current row
  1427. m_hRow = m_phRow[m_nCurrentRow];
  1428. return GetData();
  1429. }
  1430. // Move to the previous record
  1431. HRESULT MovePrev()
  1432. {
  1433. ATLASSERT(m_spRowset != NULL);
  1434. ATLASSERT(m_phRow != NULL);
  1435. // Check if we're at the start of the block
  1436. if (m_nCurrentRow == 0)
  1437. {
  1438. ReleaseRows();
  1439. // Go back the amount of rows in the block - 1 and fetch forward
  1440. m_hr = m_spRowset->GetNextRows(NULL, -(LONG)m_nRows-1, m_nRows, &m_nCurrentRows, &m_phRow);
  1441. // Set the current record to the end of the new block
  1442. m_nCurrentRow = m_nCurrentRows - 1;
  1443. // If we have an error HRESULT or we haven't retrieved any rows then return
  1444. // the HRESULT now.
  1445. if (FAILED(m_hr) || m_nCurrentRows == 0)
  1446. return m_hr;
  1447. }
  1448. else
  1449. {
  1450. // Move back a row in the block
  1451. m_nCurrentRow--;
  1452. }
  1453. // Get the data for the current row
  1454. m_hRow = m_phRow[m_nCurrentRow];
  1455. return GetData();
  1456. }
  1457. // Move to the last record
  1458. HRESULT MoveLast()
  1459. {
  1460. ReleaseRows();
  1461. return CRowset::MoveLast();
  1462. }
  1463. // Move to the passed bookmark
  1464. HRESULT MoveToBookmark(const CBookmarkBase& bookmark, LONG lSkip = 0)
  1465. {
  1466. ATLASSERT(m_spRowset != NULL);
  1467. CComPtr<IRowsetLocate> spLocate;
  1468. HRESULT hr = m_spRowset->QueryInterface(&spLocate);
  1469. if (FAILED(hr))
  1470. return hr;
  1471. ReleaseRows();
  1472. m_hr = spLocate->GetRowsAt(NULL, NULL, bookmark.GetSize(), bookmark.GetBuffer(),
  1473. lSkip, m_nRows, &m_nCurrentRows, &m_phRow);
  1474. if (m_hr != S_OK || m_nCurrentRows == 0)
  1475. return m_hr;
  1476. // Get the data
  1477. m_hRow = m_phRow[m_nCurrentRow];
  1478. return GetData();
  1479. }
  1480. // Move to a fractional position in the rowset
  1481. HRESULT MoveToRatio(ULONG nNumerator, ULONG nDenominator)
  1482. {
  1483. ATLASSERT(m_spRowset != NULL);
  1484. CComPtr<IRowsetScroll> spRowsetScroll;
  1485. HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
  1486. if (FAILED(hr))
  1487. return hr;
  1488. ReleaseRows();
  1489. m_hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, m_nRows, &m_nCurrentRows, &m_phRow);
  1490. if (m_hr != S_OK || m_nCurrentRows == 0)
  1491. return m_hr;
  1492. // Get the data
  1493. m_hRow = m_phRow[m_nCurrentRow];
  1494. return GetData();
  1495. }
  1496. // Insert the current record
  1497. HRESULT Insert(int nAccessor = 0, bool bGetHRow = false)
  1498. {
  1499. ReleaseRows();
  1500. return CRowset::Insert(nAccessor, bGetHRow);
  1501. }
  1502. // Implementation
  1503. HRESULT BindFinished()
  1504. {
  1505. // No rows in the buffer yet
  1506. m_nCurrentRows = 0;
  1507. // Cause MoveNext to automatically perform a new bulk fetch the first time
  1508. m_nCurrentRow = m_nRows;
  1509. m_phRow = NULL;
  1510. ATLTRY(m_phRow = new HROW[(size_t)m_nRows]); //REVIEW
  1511. if (m_phRow == NULL)
  1512. return E_OUTOFMEMORY;
  1513. return S_OK;
  1514. }
  1515. HRESULT m_hr; // HRESULT to return from MoveNext at end of buffer
  1516. HROW* m_phRow; // Pointer to array of HROWs for each row in buffer
  1517. ULONG_PTR m_nRows; // Number of rows that will fit in the buffer
  1518. ULONG_PTR m_nCurrentRows; // Number of rows currently in the buffer
  1519. ULONG_PTR m_nCurrentRow;
  1520. };
  1521. ///////////////////////////////////////////////////////////////////////////
  1522. // class CArrayRowset
  1523. //
  1524. // Allows you to access a rowset with an array syntax
  1525. template <class T, class TRowset = CRowset>
  1526. class CArrayRowset :
  1527. public CVirtualBuffer<T>,
  1528. public TRowset
  1529. {
  1530. public:
  1531. CArrayRowset(int nMax = 100000) : CVirtualBuffer<T>(nMax)
  1532. {
  1533. m_nRowsRead = 0;
  1534. }
  1535. T& operator[](int nRow)
  1536. {
  1537. ATLASSERT(nRow >= 0);
  1538. HRESULT hr = S_OK;
  1539. T* m_pCurrent = m_pBase + m_nRowsRead;
  1540. // Retrieve the row if we haven't retrieved it already
  1541. while ((ULONG)nRow >= m_nRowsRead)
  1542. {
  1543. m_pAccessor->SetBuffer((BYTE*)m_pCurrent);
  1544. __try
  1545. {
  1546. // Get the row
  1547. hr = MoveNext();
  1548. if (hr != S_OK)
  1549. break;
  1550. }
  1551. __except(Except(GetExceptionInformation()))
  1552. {
  1553. }
  1554. m_nRowsRead++;
  1555. m_pCurrent++;
  1556. }
  1557. if (hr != S_OK)
  1558. *((char*)0) = 0; // Force exception
  1559. return *(m_pBase + nRow);
  1560. }
  1561. HRESULT Snapshot()
  1562. {
  1563. ATLASSERT(m_nRowsRead == 0);
  1564. ATLASSERT(m_spRowset != NULL);
  1565. HRESULT hr = MoveFirst();
  1566. if (FAILED(hr))
  1567. return hr;
  1568. do
  1569. {
  1570. Write(*(T*)m_pAccessor->GetBuffer());
  1571. m_nRowsRead++;
  1572. hr = MoveNext();
  1573. } while (SUCCEEDED(hr) && hr != DB_S_ENDOFROWSET);
  1574. return (hr == DB_S_ENDOFROWSET) ? S_OK : hr;
  1575. }
  1576. // Implementation
  1577. ULONG m_nRowsRead;
  1578. };
  1579. // Used when you don't need any parameters or output columns
  1580. class CNoAccessor
  1581. {
  1582. public:
  1583. // We don't need any typedef's here as the default
  1584. // global typedef is not to have any parameters and
  1585. // output columns.
  1586. HRESULT BindColumns(IUnknown*) { return S_OK; }
  1587. HRESULT BindParameters(HACCESSOR*, ICommand*, void**) { return S_OK; }
  1588. void Close() { }
  1589. HRESULT ReleaseAccessors(IUnknown*) { return S_OK; }
  1590. };
  1591. // Used when a rowset will not be returned from the command
  1592. class CNoRowset
  1593. {
  1594. public:
  1595. HRESULT BindFinished() { return S_OK; }
  1596. void Close() { }
  1597. static const IID& GetIID() { return IID_NULL; }
  1598. IRowset* GetInterface() const { return NULL; }
  1599. IRowset** GetInterfacePtr() { return NULL; }
  1600. void SetAccessor(void*) { }
  1601. void SetupOptionalRowsetInterfaces() { }
  1602. };
  1603. ///////////////////////////////////////////////////////////////////////////
  1604. // class CAccessor
  1605. // T is the class that contains the data that will be accessed.
  1606. template <class T>
  1607. class CAccessor :
  1608. public T,
  1609. public CAccessorBase
  1610. {
  1611. public:
  1612. // Implementation
  1613. // Free's any columns in the current record that need to be freed.
  1614. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  1615. void FreeRecordMemory(IRowset* /* pRowset */)
  1616. {
  1617. ULONG nColumns;
  1618. ULONG i;
  1619. for (i = 0; i < GetNumAccessors(); i++)
  1620. {
  1621. // Passing in m_pBuffer tells the column entry maps to free the
  1622. // memory for the types if appropriate
  1623. _GetBindEntries(&nColumns, NULL, i, NULL, m_pBuffer);
  1624. }
  1625. }
  1626. HRESULT BindColumns(IUnknown* pUnk)
  1627. {
  1628. HRESULT hr;
  1629. ULONG nAccessors;
  1630. ULONG nSize;
  1631. nAccessors = _OutputColumnsClass::_GetNumAccessors();
  1632. SetBuffer((BYTE*)this);
  1633. nSize = sizeof(T);
  1634. hr = BindAccessors(nAccessors, nSize, pUnk);
  1635. return hr;
  1636. }
  1637. HRESULT BindAccessors(ULONG nAccessors, ULONG nSize, IUnknown* pUnk)
  1638. {
  1639. ATLASSERT(pUnk != NULL);
  1640. HRESULT hr;
  1641. CComPtr<IAccessor> spAccessor;
  1642. hr = pUnk->QueryInterface(&spAccessor);
  1643. if (SUCCEEDED(hr))
  1644. {
  1645. // Allocate the accessor memory if we haven't done so yet
  1646. if (m_pAccessorInfo == NULL)
  1647. {
  1648. hr = AllocateAccessorMemory(nAccessors);
  1649. if (FAILED(hr))
  1650. return hr;
  1651. }
  1652. for (ULONG i=0; i<nAccessors && SUCCEEDED(hr); i++)
  1653. hr = BindAccessor(spAccessor, i, nSize);
  1654. }
  1655. return hr;
  1656. }
  1657. HRESULT BindAccessor(IAccessor* pAccessor, ULONG nAccessor, ULONG nSize)
  1658. {
  1659. DBBINDING* pBindings = NULL;
  1660. ULONG nColumns;
  1661. bool bAuto;
  1662. HRESULT hr;
  1663. // First time just get the number of entries by passing in &nColumns
  1664. _OutputColumnsClass::_GetBindEntries(&nColumns, NULL, nAccessor, NULL);
  1665. // Now allocate the binding structures
  1666. ATLTRY(pBindings = new DBBINDING[nColumns]);
  1667. if (pBindings == NULL)
  1668. return E_OUTOFMEMORY;
  1669. // Now get the bind entries
  1670. hr = _OutputColumnsClass::_GetBindEntries(&nColumns, pBindings, nAccessor, &bAuto);
  1671. if (FAILED(hr))
  1672. return hr;
  1673. m_pAccessorInfo[nAccessor].bAutoAccessor = bAuto;
  1674. hr = BindEntries(pBindings, nColumns, &m_pAccessorInfo[nAccessor].hAccessor, nSize, pAccessor);
  1675. delete [] pBindings;
  1676. return hr;
  1677. }
  1678. HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer)
  1679. {
  1680. HRESULT hr = S_OK;
  1681. // In the static accessor case, the parameter buffer will be T
  1682. *ppParameterBuffer = this;
  1683. // Only bind the parameters if we haven't already done it
  1684. if (*pHAccessor == NULL)
  1685. {
  1686. ULONG nColumns = 0;
  1687. _ParamClass::_GetParamEntries(&nColumns, NULL);
  1688. DBBINDING* pBinding = NULL;
  1689. ATLTRY(pBinding = new DBBINDING[nColumns]);
  1690. if (pBinding == NULL)
  1691. return E_OUTOFMEMORY;
  1692. hr = _ParamClass::_GetParamEntries(&nColumns, pBinding);
  1693. if (SUCCEEDED(hr))
  1694. {
  1695. // Get the IAccessor from the passed IUnknown
  1696. CComPtr<IAccessor> spAccessor;
  1697. hr = pCommand->QueryInterface(&spAccessor);
  1698. if (SUCCEEDED(hr))
  1699. {
  1700. hr = BindEntries(pBinding, nColumns, pHAccessor, sizeof(T),
  1701. spAccessor);
  1702. }
  1703. }
  1704. delete [] pBinding;
  1705. }
  1706. return hr;
  1707. }
  1708. };
  1709. ///////////////////////////////////////////////////////////////////////////
  1710. // CDynamicAccessor
  1711. class CDynamicAccessor :
  1712. public CAccessorBase
  1713. {
  1714. public:
  1715. CDynamicAccessor()
  1716. {
  1717. m_nColumns = 0;
  1718. m_pColumnInfo = NULL;
  1719. m_pStringsBuffer = NULL;
  1720. };
  1721. ~CDynamicAccessor()
  1722. {
  1723. Close();
  1724. }
  1725. void Close()
  1726. {
  1727. if (m_pColumnInfo != NULL)
  1728. {
  1729. CoTaskMemFree(m_pColumnInfo);
  1730. m_pColumnInfo = NULL;
  1731. }
  1732. // Free the memory for the string buffer returned by IColumnsInfo::GetColumnInfo,
  1733. // if necessary
  1734. if (m_pStringsBuffer != NULL)
  1735. {
  1736. CoTaskMemFree(m_pStringsBuffer);
  1737. m_pStringsBuffer = NULL;
  1738. }
  1739. delete [] m_pBuffer;
  1740. m_pBuffer = NULL;
  1741. m_nColumns = 0;
  1742. CAccessorBase::Close();
  1743. }
  1744. bool GetColumnType(ULONG_PTR nColumn, DBTYPE* pType) const
  1745. {
  1746. if (TranslateColumnNo(nColumn))
  1747. {
  1748. *pType = m_pColumnInfo[nColumn].wType;
  1749. return true;
  1750. }
  1751. else
  1752. return false;
  1753. }
  1754. bool GetColumnFlags(ULONG_PTR nColumn, DBCOLUMNFLAGS* pFlags) const
  1755. {
  1756. if (TranslateColumnNo(nColumn))
  1757. {
  1758. *pFlags = m_pColumnInfo[nColumn].dwFlags;
  1759. return true;
  1760. }
  1761. else
  1762. return false;
  1763. }
  1764. bool GetOrdinal(TCHAR* pColumnName, DBORDINAL* pOrdinal) const
  1765. {
  1766. ATLASSERT(pColumnName != NULL);
  1767. ULONG_PTR nColumn;
  1768. if (GetInternalColumnNo(pColumnName, &nColumn))
  1769. {
  1770. *pOrdinal = m_pColumnInfo[nColumn].iOrdinal;
  1771. return true;
  1772. }
  1773. else
  1774. return false;
  1775. }
  1776. void* GetValue(ULONG_PTR nColumn) const
  1777. {
  1778. if (TranslateColumnNo(nColumn))
  1779. return _GetDataPtr(nColumn);
  1780. else
  1781. return NULL;
  1782. }
  1783. void* GetValue(TCHAR* pColumnName) const
  1784. {
  1785. ATLASSERT(pColumnName != NULL);
  1786. ULONG_PTR nColumn;
  1787. if (GetInternalColumnNo(pColumnName, &nColumn))
  1788. return _GetDataPtr(nColumn);
  1789. else
  1790. return NULL; // Not Found
  1791. }
  1792. template <class ctype>
  1793. void _GetValue(ULONG_PTR nColumn, ctype* pData) const
  1794. {
  1795. ATLASSERT(pData != NULL);
  1796. ATLASSERT(m_pColumnInfo[nColumn].ulColumnSize == sizeof(ctype));
  1797. ctype* pBuffer = (ctype*)_GetDataPtr(nColumn);
  1798. *pData = *pBuffer;
  1799. }
  1800. template <class ctype>
  1801. void _SetValue(ULONG_PTR nColumn, const ctype& data)
  1802. {
  1803. ATLASSERT(m_pColumnInfo[nColumn].ulColumnSize == sizeof(ctype));
  1804. ctype* pBuffer = (ctype*)_GetDataPtr(nColumn);
  1805. *pBuffer = (ctype)data;
  1806. }
  1807. template <class ctype>
  1808. bool GetValue(ULONG_PTR nColumn, ctype* pData) const
  1809. {
  1810. if (TranslateColumnNo(nColumn))
  1811. {
  1812. _GetValue(nColumn, pData);
  1813. return true;
  1814. }
  1815. return false;
  1816. }
  1817. template <class ctype>
  1818. bool SetValue(ULONG_PTR nColumn, const ctype& data)
  1819. {
  1820. if (TranslateColumnNo(nColumn))
  1821. {
  1822. _SetValue(nColumn, data);
  1823. return true;
  1824. }
  1825. return false;
  1826. }
  1827. template <class ctype>
  1828. bool GetValue(TCHAR *pColumnName, ctype* pData) const
  1829. {
  1830. ATLASSERT(pColumnName != NULL);
  1831. ULONG_PTR nColumn;
  1832. if (GetInternalColumnNo(pColumnName, &nColumn))
  1833. {
  1834. _GetValue(nColumn, pData);
  1835. return true;
  1836. }
  1837. return false;
  1838. }
  1839. template <class ctype>
  1840. bool SetValue(TCHAR *pColumnName, const ctype& data)
  1841. {
  1842. ATLASSERT(pColumnName != NULL);
  1843. ULONG_PTR nColumn;
  1844. if (GetInternalColumnNo(pColumnName, &nColumn))
  1845. {
  1846. _SetValue(nColumn, data);
  1847. return true;
  1848. }
  1849. return false;
  1850. }
  1851. bool GetLength(ULONG_PTR nColumn, ULONG_PTR* pLength) const
  1852. {
  1853. ATLASSERT(pLength != NULL);
  1854. if (TranslateColumnNo(nColumn))
  1855. {
  1856. *pLength = *(ULONG_PTR*)(AddOffset((ULONG_PTR)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize));
  1857. return true;
  1858. }
  1859. else
  1860. return false;
  1861. }
  1862. bool SetLength(ULONG_PTR nColumn, ULONG_PTR nLength)
  1863. {
  1864. if (TranslateColumnNo(nColumn))
  1865. {
  1866. *(ULONG_PTR*)(AddOffset((ULONG_PTR)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize)) = nLength;
  1867. return true;
  1868. }
  1869. else
  1870. return false;
  1871. }
  1872. bool GetLength(TCHAR* pColumnName, ULONG_PTR* pLength) const
  1873. {
  1874. ATLASSERT(pColumnName != NULL);
  1875. ATLASSERT(pLength != NULL);
  1876. ULONG_PTR nColumn;
  1877. if (GetInternalColumnNo(pColumnName, &nColumn))
  1878. {
  1879. *pLength = *(ULONG_PTR*)(AddOffset((ULONG_PTR)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize));
  1880. return true;
  1881. }
  1882. else
  1883. return false;
  1884. }
  1885. bool SetLength(TCHAR* pColumnName, ULONG_PTR nLength)
  1886. {
  1887. ATLASSERT(pColumnName != NULL);
  1888. ULONG_PTR nColumn;
  1889. if (GetInternalColumnNo(pColumnName, &nColumn))
  1890. {
  1891. *(ULONG_PTR*)(AddOffset((ULONG_PTR)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize)) = nLength;
  1892. return true;
  1893. }
  1894. else
  1895. return false;
  1896. }
  1897. bool GetStatus(ULONG_PTR nColumn, DBSTATUS* pStatus) const
  1898. {
  1899. ATLASSERT(pStatus != NULL);
  1900. if (TranslateColumnNo(nColumn))
  1901. {
  1902. *pStatus = *(DBSTATUS*)(AddOffset(AddOffset((ULONG_PTR)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG)));
  1903. return true;
  1904. }
  1905. else
  1906. return false;
  1907. }
  1908. bool SetStatus(ULONG_PTR nColumn, DBSTATUS status)
  1909. {
  1910. if (TranslateColumnNo(nColumn))
  1911. {
  1912. *(DBSTATUS*)(AddOffset(AddOffset((ULONG_PTR)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG))) = status;
  1913. return true;
  1914. }
  1915. else
  1916. return false;
  1917. }
  1918. bool GetStatus(TCHAR* pColumnName, DBSTATUS* pStatus) const
  1919. {
  1920. ATLASSERT(pColumnName != NULL);
  1921. ATLASSERT(pStatus != NULL);
  1922. ULONG_PTR nColumn;
  1923. if (GetInternalColumnNo(pColumnName, &nColumn))
  1924. {
  1925. *pStatus = *(DBSTATUS*)((BYTE*)_GetDataPtr(nColumn) + m_pColumnInfo[nColumn].ulColumnSize + sizeof(ULONG));
  1926. return true;
  1927. }
  1928. else
  1929. return false;
  1930. }
  1931. bool SetStatus(TCHAR* pColumnName, DBSTATUS status)
  1932. {
  1933. ATLASSERT(pColumnName != NULL);
  1934. ULONG_PTR nColumn;
  1935. if (GetInternalColumnNo(pColumnName, &nColumn))
  1936. {
  1937. *(DBSTATUS*)((BYTE*)_GetDataPtr(nColumn) + m_pColumnInfo[nColumn].ulColumnSize + sizeof(ULONG)) = status;
  1938. return true;
  1939. }
  1940. else
  1941. return false;
  1942. }
  1943. // Returns true if a bookmark is available
  1944. HRESULT GetBookmark(CBookmark<>* pBookmark) const
  1945. {
  1946. HRESULT hr;
  1947. if (m_pColumnInfo->iOrdinal == 0)
  1948. hr = pBookmark->SetBookmark(m_pColumnInfo->ulColumnSize, (BYTE*)_GetDataPtr(0));
  1949. else
  1950. hr = E_FAIL;
  1951. return hr;
  1952. }
  1953. ULONG_PTR GetColumnCount() const
  1954. {
  1955. return m_nColumns;
  1956. }
  1957. LPOLESTR GetColumnName(ULONG_PTR nColumn) const
  1958. {
  1959. if (TranslateColumnNo(nColumn))
  1960. return m_pColumnInfo[nColumn].pwszName;
  1961. else
  1962. return NULL;
  1963. }
  1964. HRESULT GetColumnInfo(IRowset* pRowset, DBORDINAL* pColumns, DBCOLUMNINFO** ppColumnInfo)
  1965. {
  1966. CComPtr<IColumnsInfo> spColumnsInfo;
  1967. HRESULT hr = pRowset->QueryInterface(&spColumnsInfo);
  1968. if (SUCCEEDED(hr))
  1969. hr = spColumnsInfo->GetColumnInfo(pColumns, ppColumnInfo, &m_pStringsBuffer);
  1970. return hr;
  1971. }
  1972. HRESULT AddBindEntry(const DBCOLUMNINFO& info)
  1973. {
  1974. DBCOLUMNINFO* pColumnInfo;
  1975. pColumnInfo = (DBCOLUMNINFO*)CoTaskMemRealloc(m_pColumnInfo, (ULONG)(m_nColumns + 1) * sizeof(DBCOLUMNINFO)); //REVIEW: size_t
  1976. if (pColumnInfo == NULL)
  1977. return E_OUTOFMEMORY;
  1978. m_pColumnInfo = pColumnInfo;
  1979. m_pColumnInfo[m_nColumns] = info;
  1980. m_nColumns++;
  1981. return S_OK;
  1982. }
  1983. // Implementation
  1984. // Free's any columns in the current record that need to be freed.
  1985. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  1986. void FreeRecordMemory(IRowset* pRowset)
  1987. {
  1988. ULONG_PTR i;
  1989. for (i = 0; i < m_nColumns; i++)
  1990. CAccessorBase::FreeType(m_pColumnInfo[i].wType, (BYTE*)_GetDataPtr(i), pRowset);
  1991. }
  1992. void* _GetDataPtr(ULONG_PTR nColumn) const
  1993. {
  1994. return m_pBuffer + (ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  1995. }
  1996. bool GetInternalColumnNo(TCHAR* pColumnName, ULONG_PTR* pColumn) const
  1997. {
  1998. ATLASSERT(pColumnName != NULL);
  1999. ATLASSERT(pColumn != NULL);
  2000. USES_CONVERSION;
  2001. ULONG_PTR i;
  2002. ULONG nSize = (lstrlen(pColumnName) + 1) * sizeof(OLECHAR);
  2003. OLECHAR* pOleColumnName = T2OLE(pColumnName);
  2004. // Search through the columns trying to find a match
  2005. for (i = 0; i < m_nColumns; i++)
  2006. {
  2007. if (m_pColumnInfo[i].pwszName != NULL &&
  2008. memcmp(m_pColumnInfo[i].pwszName, pOleColumnName, nSize) == 0)
  2009. break;
  2010. }
  2011. if (i < m_nColumns)
  2012. {
  2013. *pColumn = i;
  2014. return true;
  2015. }
  2016. else
  2017. return false; // Not Found
  2018. }
  2019. HRESULT BindColumns(IUnknown* pUnk)
  2020. {
  2021. ATLASSERT(pUnk != NULL);
  2022. CComPtr<IAccessor> spAccessor;
  2023. HRESULT hr = pUnk->QueryInterface(&spAccessor);
  2024. if (FAILED(hr))
  2025. return hr;
  2026. ULONG_PTR i;
  2027. ULONG_PTR nOffset = 0, nLengthOffset, nStatusOffset;
  2028. // If the user hasn't specifed the column information to bind by calling AddBindEntry then
  2029. // we get it ourselves
  2030. if (m_pColumnInfo == NULL)
  2031. {
  2032. CComPtr<IColumnsInfo> spColumnsInfo;
  2033. hr = pUnk->QueryInterface(&spColumnsInfo);
  2034. if (FAILED(hr))
  2035. return hr;
  2036. hr = spColumnsInfo->GetColumnInfo(&m_nColumns, &m_pColumnInfo, &m_pStringsBuffer);
  2037. if (FAILED(hr))
  2038. return hr;
  2039. m_bOverride = false;
  2040. }
  2041. else
  2042. m_bOverride = true;
  2043. DBBINDING* pBinding = NULL;
  2044. ATLTRY(pBinding= new DBBINDING[(size_t)m_nColumns]); //REVIEW
  2045. if (pBinding == NULL)
  2046. return E_OUTOFMEMORY;
  2047. DBBINDING* pCurrent = pBinding;
  2048. DBOBJECT* pObject;
  2049. for (i = 0; i < m_nColumns; i++)
  2050. {
  2051. // If it's a BLOB or the column size is large enough for us to treat it as
  2052. // a BLOB then we also need to set up the DBOBJECT structure.
  2053. if (m_pColumnInfo[i].ulColumnSize > 1024 || m_pColumnInfo[i].wType == DBTYPE_IUNKNOWN)
  2054. {
  2055. pObject = NULL;
  2056. ATLTRY(pObject = new DBOBJECT);
  2057. if (pObject == NULL)
  2058. return E_OUTOFMEMORY;
  2059. pObject->dwFlags = STGM_READ;
  2060. pObject->iid = IID_ISequentialStream;
  2061. m_pColumnInfo[i].wType = DBTYPE_IUNKNOWN;
  2062. m_pColumnInfo[i].ulColumnSize = sizeof(IUnknown*);
  2063. }
  2064. else
  2065. pObject = NULL;
  2066. // If column is of type STR or WSTR increase length by 1
  2067. // to accommodate the NULL terminator.
  2068. if (m_pColumnInfo[i].wType == DBTYPE_STR ||
  2069. m_pColumnInfo[i].wType == DBTYPE_WSTR)
  2070. m_pColumnInfo[i].ulColumnSize += 1;
  2071. nLengthOffset = AddOffset(nOffset, m_pColumnInfo[i].ulColumnSize);
  2072. nStatusOffset = AddOffset(nLengthOffset, sizeof(ULONG));
  2073. Bind(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
  2074. m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  2075. DBPARAMIO_NOTPARAM, nOffset,
  2076. nLengthOffset, nStatusOffset, pObject);
  2077. pCurrent++;
  2078. // Note that, as we're not using this for anything else, we're using the
  2079. // pTypeInfo element to store the offset to our data.
  2080. m_pColumnInfo[i].pTypeInfo = (ITypeInfo*)(DWORD_PTR)nOffset;
  2081. nOffset = AddOffset(nStatusOffset, sizeof(DBSTATUS));
  2082. }
  2083. // Allocate the accessor memory if we haven't done so yet
  2084. if (m_pAccessorInfo == NULL)
  2085. {
  2086. hr = AllocateAccessorMemory(1); // We only have one accessor
  2087. if (FAILED(hr))
  2088. {
  2089. delete [] pBinding;
  2090. return hr;
  2091. }
  2092. m_pAccessorInfo->bAutoAccessor = TRUE;
  2093. }
  2094. // Allocate enough memory for the data buffer and tell the rowset
  2095. // Note that the rowset will free the memory in its destructor.
  2096. m_pBuffer = NULL;
  2097. ATLTRY(m_pBuffer = new BYTE[(size_t)nOffset]); //REVIEW
  2098. if (m_pBuffer == NULL)
  2099. {
  2100. delete [] pBinding;
  2101. return E_OUTOFMEMORY;
  2102. }
  2103. hr = BindEntries(pBinding, m_nColumns, &m_pAccessorInfo->hAccessor,
  2104. nOffset, spAccessor);
  2105. delete [] pBinding;
  2106. return hr;
  2107. }
  2108. static ULONG_PTR AddOffset(ULONG_PTR nCurrent, ULONG_PTR nAdd)
  2109. {
  2110. struct foobar
  2111. {
  2112. char foo;
  2113. LONG_PTR bar;
  2114. };
  2115. ULONG_PTR nAlign = offsetof(foobar, bar);
  2116. return nCurrent + nAdd + (nAlign - (nAdd % nAlign));
  2117. }
  2118. // Translate the column number to the index into the column info array
  2119. bool TranslateColumnNo(ULONG_PTR& nColumn) const
  2120. {
  2121. ATLASSERT(m_pColumnInfo != NULL);
  2122. // If the user has overriden the binding then we need to search
  2123. // through the column info for the ordinal number
  2124. if (m_bOverride)
  2125. {
  2126. for (ULONG_PTR i = 0; i < m_nColumns; i++)
  2127. {
  2128. if (m_pColumnInfo[i].iOrdinal == nColumn)
  2129. {
  2130. nColumn = i;
  2131. return true;
  2132. }
  2133. }
  2134. return false;
  2135. }
  2136. else
  2137. {
  2138. // Note that m_pColumnInfo->iOrdinal will be zero if have bound
  2139. // a bookmark as the first entry, otherwise it will be 1.
  2140. // If the column is out of range then return false
  2141. if (nColumn > (m_nColumns - 1 + m_pColumnInfo->iOrdinal))
  2142. return false;
  2143. // otherwise translate the column to an index into our internal
  2144. // binding entries array
  2145. nColumn -= m_pColumnInfo->iOrdinal;
  2146. return true;
  2147. }
  2148. }
  2149. typedef CDynamicAccessor _OutputColumnsClass;
  2150. static bool HasOutputColumns() { return true; }
  2151. ULONG_PTR m_nColumns;
  2152. DBCOLUMNINFO* m_pColumnInfo;
  2153. OLECHAR* m_pStringsBuffer;
  2154. bool m_bOverride;
  2155. };
  2156. ///////////////////////////////////////////////////////////////////////////
  2157. // class CDynamicParameterAccessor
  2158. class CDynamicParameterAccessor : public CDynamicAccessor
  2159. {
  2160. // Constructors and Destructors
  2161. public:
  2162. typedef CDynamicParameterAccessor _ParamClass;
  2163. CDynamicParameterAccessor()
  2164. {
  2165. m_pParameterEntry = NULL;
  2166. m_pParameterBuffer = NULL;
  2167. m_ppParamName = NULL;
  2168. m_nParameterBufferSize = 0;
  2169. m_nParams = 0;
  2170. };
  2171. ~CDynamicParameterAccessor()
  2172. {
  2173. delete [] m_pParameterEntry;
  2174. if (m_ppParamName != NULL)
  2175. {
  2176. if (*m_ppParamName != NULL)
  2177. CoTaskMemFree(*m_ppParamName);
  2178. delete [] m_ppParamName;
  2179. }
  2180. delete m_pParameterBuffer;
  2181. };
  2182. // nParam is the parameter number (offset from 1)
  2183. bool GetParamType(ULONG_PTR nParam, DBTYPE* pType) const
  2184. {
  2185. ATLASSERT(pType != NULL);
  2186. if (nParam == 0 || nParam > m_nParams)
  2187. return false;
  2188. *pType = m_pParameterEntry[nParam-1].wType;
  2189. return true;
  2190. }
  2191. template <class ctype>
  2192. bool GetParam(ULONG_PTR nParam, ctype* pData) const
  2193. {
  2194. ATLASSERT(pData != NULL);
  2195. ctype* pBuffer = (ctype*)GetParam(nParam);
  2196. if (pBuffer == NULL)
  2197. return false;
  2198. *pData = *pBuffer;
  2199. return true;
  2200. }
  2201. template <class ctype>
  2202. bool SetParam(ULONG_PTR nParam, ctype* pData)
  2203. {
  2204. ATLASSERT(pData != NULL);
  2205. ctype* pBuffer = (ctype*)GetParam(nParam);
  2206. if (pBuffer == NULL)
  2207. return false;
  2208. *pBuffer = *pData;
  2209. return true;
  2210. }
  2211. template <class ctype>
  2212. bool GetParam(TCHAR* pParamName, ctype* pData) const
  2213. {
  2214. ATLASSERT(pData != NULL);
  2215. ctype* pBuffer = (ctype*)GetParam(pParamName);
  2216. if (pBuffer == NULL)
  2217. return false;
  2218. *pData = *pBuffer;
  2219. return true;
  2220. }
  2221. template <class ctype>
  2222. bool SetParam(TCHAR* pParamName, ctype* pData)
  2223. {
  2224. ATLASSERT(pData != NULL);
  2225. ctype* pBuffer = (ctype*)GetParam(pParamName);
  2226. if (pBuffer == NULL)
  2227. return false;
  2228. *pBuffer = *pData;
  2229. return true;
  2230. }
  2231. void* GetParam(ULONG_PTR nParam) const
  2232. {
  2233. if (nParam == 0 || nParam > m_nParams)
  2234. return NULL;
  2235. else
  2236. return m_pParameterBuffer + m_pParameterEntry[nParam-1].obValue;
  2237. }
  2238. void* GetParam(TCHAR* pParamName) const
  2239. {
  2240. USES_CONVERSION;
  2241. ULONG_PTR i;
  2242. ULONG nSize = (lstrlen(pParamName) + 1) * sizeof(OLECHAR);
  2243. OLECHAR* pOleParamName = T2OLE(pParamName);
  2244. for (i=0; i<m_nParams; i++)
  2245. {
  2246. if (memcmp(m_ppParamName[i], pOleParamName, nSize) == 0)
  2247. break;
  2248. }
  2249. if (i < m_nParams)
  2250. return (m_pParameterBuffer + m_pParameterEntry[i].obValue);
  2251. else
  2252. return NULL; // Not Found
  2253. }
  2254. // Get the number of parameters
  2255. ULONG_PTR GetParamCount() const
  2256. {
  2257. return m_nParams;
  2258. }
  2259. // Get the parameter name for the passed parameter number
  2260. LPOLESTR GetParamName(ULONG_PTR ulParam) const
  2261. {
  2262. ATLASSERT(ulParam<m_nParams);
  2263. return m_ppParamName[ulParam];
  2264. }
  2265. // Implementation
  2266. HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand,
  2267. void** ppParameterBuffer)
  2268. {
  2269. // If we have already bound the parameters then just return
  2270. // the pointer to the parameter buffer
  2271. if (*pHAccessor != NULL)
  2272. {
  2273. *ppParameterBuffer = m_pParameterBuffer;
  2274. return S_OK;
  2275. }
  2276. CComPtr<IAccessor> spAccessor;
  2277. HRESULT hr = pCommand->QueryInterface(&spAccessor);
  2278. if (FAILED(hr))
  2279. return hr;
  2280. // Try to bind parameters if available
  2281. CComPtr<ICommandWithParameters> spCommandParameters;
  2282. hr = pCommand->QueryInterface(&spCommandParameters);
  2283. if (FAILED(hr))
  2284. return hr;
  2285. DB_UPARAMS ulParams = 0;
  2286. DBPARAMINFO* pParamInfo = NULL;
  2287. LPOLESTR pNamesBuffer = NULL;
  2288. // Get Parameter Information
  2289. hr = spCommandParameters->GetParameterInfo(&ulParams, &pParamInfo,
  2290. &pNamesBuffer);
  2291. if (FAILED(hr))
  2292. return hr;
  2293. // Create the parameter information for binding
  2294. hr = AllocateParameterInfo(ulParams);
  2295. if (FAILED(hr))
  2296. {
  2297. CoTaskMemFree(pParamInfo);
  2298. CoTaskMemFree(pNamesBuffer);
  2299. return hr;
  2300. }
  2301. ULONG_PTR nOffset = 0;
  2302. DBBINDING* pCurrent = m_pParameterEntry;
  2303. for (ULONG l=0; l<ulParams; l++)
  2304. {
  2305. m_pParameterEntry[l].eParamIO = 0;
  2306. if (pParamInfo[l].dwFlags & DBPARAMFLAGS_ISINPUT)
  2307. m_pParameterEntry[l].eParamIO |= DBPARAMIO_INPUT;
  2308. if (pParamInfo[l].dwFlags & DBPARAMFLAGS_ISOUTPUT)
  2309. m_pParameterEntry[l].eParamIO |= DBPARAMIO_OUTPUT;
  2310. Bind(pCurrent, pParamInfo[l].iOrdinal, pParamInfo[l].wType,
  2311. pParamInfo[l].ulParamSize, pParamInfo[l].bPrecision, pParamInfo[l].bScale,
  2312. m_pParameterEntry[l].eParamIO, nOffset);
  2313. pCurrent++;
  2314. m_ppParamName[l] = pNamesBuffer;
  2315. if (pNamesBuffer && *pNamesBuffer)
  2316. {
  2317. // Search for the NULL termination character
  2318. while (*pNamesBuffer++)
  2319. ;
  2320. }
  2321. nOffset += pParamInfo[l].ulParamSize;
  2322. }
  2323. // Allocate memory for the new buffer
  2324. m_pParameterBuffer = NULL;
  2325. ATLTRY(m_pParameterBuffer = new BYTE[(size_t)nOffset]); //REVIEW
  2326. if (m_pParameterBuffer == NULL)
  2327. {
  2328. // Note that pNamesBuffer will be freed in the destructor
  2329. // by freeing *m_ppParamName
  2330. CoTaskMemFree(pParamInfo);
  2331. return E_OUTOFMEMORY;
  2332. }
  2333. *ppParameterBuffer = m_pParameterBuffer;
  2334. m_nParameterBufferSize = nOffset;
  2335. m_nParams = ulParams;
  2336. BindEntries(m_pParameterEntry, ulParams, pHAccessor, nOffset, spAccessor);
  2337. CoTaskMemFree(pParamInfo);
  2338. return S_OK;
  2339. }
  2340. bool HasParameters() const
  2341. {
  2342. return true;
  2343. }
  2344. HRESULT AllocateParameterInfo(ULONG_PTR nParamEntries)
  2345. {
  2346. // Allocate memory for the bind structures
  2347. m_pParameterEntry = NULL;
  2348. ATLTRY(m_pParameterEntry = new DBBINDING[(size_t)nParamEntries]); //REVIEW
  2349. if (m_pParameterEntry == NULL)
  2350. return E_OUTOFMEMORY;
  2351. // Allocate memory to store the field names
  2352. m_ppParamName = NULL;
  2353. ATLTRY(m_ppParamName = new OLECHAR*[(size_t)nParamEntries]); //REVIEW
  2354. if (m_ppParamName == NULL)
  2355. return E_OUTOFMEMORY;
  2356. return S_OK;
  2357. }
  2358. // Data Members
  2359. // Number of parameters
  2360. ULONG_PTR m_nParams;
  2361. // A pointer to the entry structures for each parameter
  2362. DBBINDING* m_pParameterEntry;
  2363. // String names for the parameters
  2364. OLECHAR** m_ppParamName;
  2365. // The size of the buffer where the parameters are stored
  2366. ULONG_PTR m_nParameterBufferSize;
  2367. // A pointer to the buffer where the parameters are stored
  2368. BYTE* m_pParameterBuffer;
  2369. };
  2370. ///////////////////////////////////////////////////////////////////////////
  2371. // class CManualAccessor
  2372. class CManualAccessor :
  2373. public CAccessorBase
  2374. {
  2375. public:
  2376. CManualAccessor()
  2377. {
  2378. // By default we don't have any parameters unless CreateParameterAccessor is called
  2379. m_pEntry = NULL;
  2380. m_nParameters = 0;
  2381. m_pParameterEntry = NULL;
  2382. m_nColumns = 0;
  2383. }
  2384. ~CManualAccessor()
  2385. {
  2386. delete [] m_pEntry;
  2387. delete [] m_pParameterEntry;
  2388. }
  2389. HRESULT CreateAccessor(ULONG_PTR nBindEntries, void* pBuffer, ULONG_PTR nBufferSize)
  2390. {
  2391. m_pBuffer = (BYTE*)pBuffer;
  2392. m_nBufferSize = nBufferSize;
  2393. m_nColumns = nBindEntries;
  2394. m_nEntry = 0;
  2395. // If they've previously created some entries then free them
  2396. delete [] m_pEntry;
  2397. m_pEntry = NULL;
  2398. // Allocate memory for the bind structures
  2399. ATLTRY(m_pEntry = new DBBINDING[(size_t)nBindEntries]); //REVIEW
  2400. if (m_pEntry == NULL)
  2401. return E_OUTOFMEMORY;
  2402. else
  2403. return S_OK;
  2404. }
  2405. HRESULT CreateParameterAccessor(ULONG_PTR nBindEntries, void* pBuffer, ULONG_PTR nBufferSize)
  2406. {
  2407. m_pParameterBuffer = (BYTE*)pBuffer;
  2408. m_nParameterBufferSize = nBufferSize;
  2409. m_nParameters = nBindEntries;
  2410. m_nCurrentParameter = 0;
  2411. // Allocate memory for the bind structures
  2412. m_pParameterEntry = NULL;
  2413. ATLTRY(m_pParameterEntry = new DBBINDING[(size_t)nBindEntries]); //REVIEW
  2414. if (m_pParameterEntry == NULL)
  2415. return E_OUTOFMEMORY;
  2416. else
  2417. return S_OK;
  2418. }
  2419. void AddBindEntry(ULONG_PTR nOrdinal, DBTYPE wType, ULONG_PTR nColumnSize,
  2420. void* pData, void* pLength = NULL, void* pStatus = NULL)
  2421. {
  2422. ATLASSERT(m_nEntry < m_nColumns);
  2423. ULONG_PTR nLengthOffset, nStatusOffset;
  2424. if (pStatus != NULL)
  2425. nStatusOffset = (BYTE*)pStatus - m_pBuffer;
  2426. else
  2427. nStatusOffset = 0;
  2428. if (pLength != NULL)
  2429. nLengthOffset = (BYTE*)pLength - m_pBuffer;
  2430. else
  2431. nLengthOffset = 0;
  2432. Bind(m_pEntry+m_nEntry, nOrdinal, wType, nColumnSize, 0, 0, DBPARAMIO_NOTPARAM,
  2433. (BYTE*)pData - m_pBuffer, nLengthOffset, nStatusOffset);
  2434. m_nEntry++;
  2435. }
  2436. void AddParameterEntry(ULONG_PTR nOrdinal, DBTYPE wType, ULONG_PTR nColumnSize,
  2437. void* pData, void* pLength = NULL, void* pStatus = NULL,
  2438. DBPARAMIO eParamIO = DBPARAMIO_INPUT)
  2439. {
  2440. ATLASSERT(m_nCurrentParameter < m_nParameters);
  2441. ULONG_PTR nLengthOffset, nStatusOffset;
  2442. if (pStatus != NULL)
  2443. nStatusOffset = (BYTE*)pStatus - m_pParameterBuffer;
  2444. else
  2445. nStatusOffset = 0;
  2446. if (pLength != NULL)
  2447. nLengthOffset = (BYTE*)pLength - m_pBuffer;
  2448. else
  2449. nLengthOffset = 0;
  2450. Bind(m_pParameterEntry + m_nCurrentParameter, nOrdinal, wType, nColumnSize, 0, 0,
  2451. eParamIO, (BYTE*)pData - m_pParameterBuffer, nLengthOffset, nStatusOffset);
  2452. m_nCurrentParameter++;
  2453. }
  2454. // Implementation
  2455. // Free's any columns in the current record that need to be freed.
  2456. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  2457. void FreeRecordMemory(IRowset* pRowset)
  2458. {
  2459. ULONG_PTR i;
  2460. for (i = 0; i < m_nColumns; i++)
  2461. CAccessorBase::FreeType(m_pEntry[i].wType, m_pBuffer + m_pEntry[i].obValue, pRowset);
  2462. }
  2463. HRESULT BindColumns(IUnknown* pUnk)
  2464. {
  2465. ATLASSERT(pUnk != NULL);
  2466. CComPtr<IAccessor> spAccessor;
  2467. HRESULT hr = pUnk->QueryInterface(&spAccessor);
  2468. if (FAILED(hr))
  2469. return hr;
  2470. // Allocate the accessor memory if we haven't done so yet
  2471. if (m_pAccessorInfo == NULL)
  2472. {
  2473. hr = AllocateAccessorMemory(1); // We only have one accessor
  2474. if (FAILED(hr))
  2475. return hr;
  2476. m_pAccessorInfo->bAutoAccessor = TRUE;
  2477. }
  2478. return BindEntries(m_pEntry, m_nColumns, &m_pAccessorInfo->hAccessor, m_nBufferSize, spAccessor);
  2479. }
  2480. HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer)
  2481. {
  2482. HRESULT hr;
  2483. *ppParameterBuffer = m_pParameterBuffer;
  2484. // Only bind the parameter if we haven't done so yet
  2485. if (*pHAccessor == NULL)
  2486. {
  2487. // Get the IAccessor from the passed IUnknown
  2488. CComPtr<IAccessor> spAccessor;
  2489. hr = pCommand->QueryInterface(&spAccessor);
  2490. if (SUCCEEDED(hr))
  2491. {
  2492. hr = BindEntries(m_pParameterEntry, m_nParameters, pHAccessor,
  2493. m_nParameterBufferSize, spAccessor);
  2494. }
  2495. }
  2496. else
  2497. hr = S_OK;
  2498. return hr;
  2499. }
  2500. typedef CManualAccessor _ParamClass;
  2501. bool HasParameters() { return (m_nParameters > 0); }
  2502. typedef CManualAccessor _OutputColumnsClass;
  2503. static bool HasOutputColumns() { return true; }
  2504. ULONG_PTR GetColumnCount() const
  2505. {
  2506. return m_nColumns;
  2507. }
  2508. // The binding structure for the output columns
  2509. DBBINDING* m_pEntry;
  2510. // The number of output columns
  2511. ULONG_PTR m_nColumns;
  2512. // The number of the current entry for the output columns
  2513. ULONG_PTR m_nEntry;
  2514. // The size of the data buffer for the output columns
  2515. ULONG_PTR m_nBufferSize;
  2516. // The number of parameters columns
  2517. ULONG_PTR m_nParameters;
  2518. // The number of the parameter column to bind next
  2519. ULONG_PTR m_nCurrentParameter;
  2520. // A pointer to the entry structures for each parameter
  2521. DBBINDING* m_pParameterEntry;
  2522. // The size of the buffer where the parameters are stored
  2523. ULONG_PTR m_nParameterBufferSize;
  2524. // A pointer to the buffer where the parameters are stored
  2525. BYTE* m_pParameterBuffer;
  2526. };
  2527. ///////////////////////////////////////////////////////////////////////////
  2528. // CAccessorRowset
  2529. template <class TAccessor = CNoAccessor, class TRowset = CRowset>
  2530. class CAccessorRowset :
  2531. public TAccessor,
  2532. public TRowset
  2533. {
  2534. public:
  2535. CAccessorRowset()
  2536. {
  2537. // Give the rowset a pointer to the accessor
  2538. SetAccessor(this);
  2539. }
  2540. ~CAccessorRowset()
  2541. {
  2542. Close();
  2543. }
  2544. // Used to get the column information from the opened rowset. The user is responsible
  2545. // for freeing the returned column information and string buffer.
  2546. HRESULT GetColumnInfo(ULONG_PTR* pulColumns,
  2547. DBCOLUMNINFO** ppColumnInfo, LPOLESTR* ppStrings) const
  2548. {
  2549. ATLASSERT(GetInterface() != NULL);
  2550. if (ppColumnInfo == NULL || pulColumns == NULL || ppStrings == NULL)
  2551. return E_POINTER;
  2552. CComPtr<IColumnsInfo> spColumns;
  2553. HRESULT hr = GetInterface()->QueryInterface(&spColumns);
  2554. if (SUCCEEDED(hr))
  2555. hr = spColumns->GetColumnInfo(pulColumns, ppColumnInfo, ppStrings);
  2556. return hr;
  2557. }
  2558. // Used to get the column information when overriding the bindings using CDynamicAccessor
  2559. // The user should CoTaskMemFree the column information pointer that is returned.
  2560. HRESULT GetColumnInfo(ULONG_PTR* pColumns, DBCOLUMNINFO** ppColumnInfo)
  2561. {
  2562. // If you get a compilation here, then you are most likely calling this function
  2563. // from a class that is not using CDynamicAccessor.
  2564. ATLASSERT(GetInterface() != NULL);
  2565. return TAccessor::GetColumnInfo(GetInterface(), pColumns, ppColumnInfo);
  2566. }
  2567. // Call to bind the output columns
  2568. HRESULT Bind()
  2569. {
  2570. // Bind should only be called when we've successfully opened the rowset
  2571. ATLASSERT(GetInterface() != NULL);
  2572. HRESULT hr = TAccessor::BindColumns(GetInterface());
  2573. if (SUCCEEDED(hr))
  2574. hr = BindFinished();
  2575. return hr;
  2576. }
  2577. // Close the opened rowset and release the created accessors for the output columns
  2578. void Close()
  2579. {
  2580. if (GetInterface() != NULL)
  2581. {
  2582. ReleaseAccessors(GetInterface());
  2583. TAccessor::Close();
  2584. TRowset::Close();
  2585. }
  2586. }
  2587. // Free's any columns in the current record that need to be freed.
  2588. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  2589. void FreeRecordMemory()
  2590. {
  2591. TAccessor::FreeRecordMemory(m_spRowset);
  2592. }
  2593. };
  2594. ///////////////////////////////////////////////////////////////////////////
  2595. // class CEnumeratorAccessor
  2596. class CEnumeratorAccessor
  2597. {
  2598. public:
  2599. WCHAR m_szName[129];
  2600. WCHAR m_szParseName[129];
  2601. WCHAR m_szDescription[129];
  2602. USHORT m_nType;
  2603. VARIANT_BOOL m_bIsParent;
  2604. // Binding Maps
  2605. BEGIN_COLUMN_MAP(CEnumeratorAccessor)
  2606. COLUMN_ENTRY(1, m_szName)
  2607. COLUMN_ENTRY(2, m_szParseName)
  2608. COLUMN_ENTRY(3, m_szDescription)
  2609. COLUMN_ENTRY(4, m_nType)
  2610. COLUMN_ENTRY(5, m_bIsParent)
  2611. END_COLUMN_MAP()
  2612. };
  2613. ///////////////////////////////////////////////////////////////////////////
  2614. // class CEnumerator
  2615. class CEnumerator : public CAccessorRowset<CAccessor<CEnumeratorAccessor> >
  2616. {
  2617. public:
  2618. HRESULT Open(LPMONIKER pMoniker)
  2619. {
  2620. if (pMoniker == NULL)
  2621. return E_FAIL;
  2622. // Bind the moniker for the sources rowset
  2623. if (FAILED(BindMoniker(pMoniker, 0, IID_ISourcesRowset,
  2624. (void**)&m_spSourcesRowset)))
  2625. return E_FAIL;
  2626. // Enumerate the data sources
  2627. if (FAILED(m_spSourcesRowset->GetSourcesRowset(NULL, IID_IRowset, 0,
  2628. NULL, (IUnknown**)&m_spRowset)))
  2629. return E_FAIL;
  2630. return Bind();
  2631. }
  2632. HRESULT Open(const CEnumerator& enumerator)
  2633. {
  2634. HRESULT hr;
  2635. CComPtr<IMoniker> spMoniker;
  2636. hr = enumerator.GetMoniker(&spMoniker);
  2637. if (FAILED(hr))
  2638. return hr;
  2639. return Open(spMoniker);
  2640. }
  2641. HRESULT Open(const CLSID* pClsid = &CLSID_OLEDB_ENUMERATOR)
  2642. {
  2643. if (pClsid == NULL)
  2644. return E_FAIL;
  2645. HRESULT hr;
  2646. // Create the enumerator
  2647. hr = CoCreateInstance(*pClsid, NULL, CLSCTX_INPROC_SERVER,
  2648. IID_ISourcesRowset, (LPVOID*)&m_spSourcesRowset);
  2649. if (FAILED(hr))
  2650. return hr;
  2651. // Get the rowset so we can enumerate the data sources
  2652. hr = m_spSourcesRowset->GetSourcesRowset(NULL, IID_IRowset, 0,
  2653. NULL, (IUnknown**)&m_spRowset);
  2654. if (FAILED(hr))
  2655. return hr;
  2656. return Bind();
  2657. }
  2658. HRESULT GetMoniker(LPMONIKER* ppMoniker) const
  2659. {
  2660. CComPtr<IParseDisplayName> spParse;
  2661. HRESULT hr;
  2662. ULONG chEaten;
  2663. if (ppMoniker == NULL)
  2664. return E_POINTER;
  2665. if (m_spSourcesRowset == NULL)
  2666. return E_FAIL;
  2667. hr = m_spSourcesRowset->QueryInterface(IID_IParseDisplayName, (void**)&spParse);
  2668. if (FAILED(hr))
  2669. return hr;
  2670. hr = spParse->ParseDisplayName(NULL, (LPOLESTR)m_szParseName,
  2671. &chEaten, ppMoniker);
  2672. return hr;
  2673. }
  2674. HRESULT GetMoniker(LPMONIKER* ppMoniker, LPCTSTR lpszDisplayName) const
  2675. {
  2676. USES_CONVERSION;
  2677. CComPtr<IParseDisplayName> spParse;
  2678. HRESULT hr;
  2679. ULONG chEaten;
  2680. if (ppMoniker == NULL || lpszDisplayName == NULL)
  2681. return E_POINTER;
  2682. if (m_spSourcesRowset == NULL)
  2683. return E_FAIL;
  2684. hr = m_spSourcesRowset->QueryInterface(IID_IParseDisplayName, (void**)&spParse);
  2685. if (FAILED(hr))
  2686. return hr;
  2687. hr = spParse->ParseDisplayName(NULL, (LPOLESTR)T2COLE(lpszDisplayName),
  2688. &chEaten, ppMoniker);
  2689. return hr;
  2690. }
  2691. bool Find(TCHAR* szSearchName)
  2692. {
  2693. USES_CONVERSION;
  2694. // Loop through the providers looking for the passed name
  2695. while (MoveNext()==S_OK && lstrcmp(W2T(m_szName), szSearchName))
  2696. ATLTRACE2(atlTraceDBClient, 0, _T("%s, %s, %d\n"), W2T(m_szName), W2T(m_szParseName), m_nType);
  2697. if (lstrcmp(W2T(m_szName), szSearchName))
  2698. return false;
  2699. else
  2700. return true;
  2701. }
  2702. CComPtr<ISourcesRowset> m_spSourcesRowset;
  2703. };
  2704. ///////////////////////////////////////////////////////////////////////////
  2705. // CDataSource
  2706. class CDataSource
  2707. {
  2708. public:
  2709. HRESULT Open(const CLSID& clsid, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
  2710. {
  2711. HRESULT hr;
  2712. m_spInit.Release();
  2713. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize,
  2714. (void**)&m_spInit);
  2715. if (FAILED(hr))
  2716. return hr;
  2717. // Initialize the provider
  2718. return OpenWithProperties(pPropSet, nPropertySets);
  2719. }
  2720. HRESULT Open(const CLSID& clsid, LPCTSTR pName, LPCTSTR pUserName = NULL,
  2721. LPCTSTR pPassword = NULL, long nInitMode = 0)
  2722. {
  2723. HRESULT hr;
  2724. m_spInit.Release();
  2725. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize,
  2726. (void**)&m_spInit);
  2727. if (FAILED(hr))
  2728. return hr;
  2729. return OpenWithNameUserPassword(pName, pUserName, pPassword, nInitMode);
  2730. }
  2731. HRESULT Open(LPCTSTR szProgID, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
  2732. {
  2733. USES_CONVERSION;
  2734. HRESULT hr;
  2735. CLSID clsid;
  2736. hr = CLSIDFromProgID(T2COLE(szProgID), &clsid);
  2737. if (FAILED(hr))
  2738. return hr;
  2739. return Open(clsid, pPropSet, nPropertySets);
  2740. }
  2741. HRESULT Open(LPCTSTR szProgID, LPCTSTR pName, LPCTSTR pUserName = NULL,
  2742. LPCTSTR pPassword = NULL, long nInitMode = 0)
  2743. {
  2744. USES_CONVERSION;
  2745. HRESULT hr;
  2746. CLSID clsid;
  2747. hr = CLSIDFromProgID(T2COLE(szProgID), &clsid);
  2748. if (FAILED(hr))
  2749. return hr;
  2750. return Open(clsid, pName, pUserName, pPassword, nInitMode);
  2751. }
  2752. HRESULT Open(const CEnumerator& enumerator, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
  2753. {
  2754. CComPtr<IMoniker> spMoniker;
  2755. HRESULT hr;
  2756. hr = enumerator.GetMoniker(&spMoniker);
  2757. if (FAILED(hr))
  2758. return hr;
  2759. m_spInit.Release();
  2760. // Now bind the moniker
  2761. hr = BindMoniker(spMoniker, 0, IID_IDBInitialize, (void**)&m_spInit);
  2762. if (FAILED(hr))
  2763. return hr;
  2764. return OpenWithProperties(pPropSet, nPropertySets);
  2765. }
  2766. HRESULT Open(const CEnumerator& enumerator, LPCTSTR pName, LPCTSTR pUserName = NULL,
  2767. LPCTSTR pPassword = NULL, long nInitMode = 0)
  2768. {
  2769. CComPtr<IMoniker> spMoniker;
  2770. HRESULT hr;
  2771. hr = enumerator.GetMoniker(&spMoniker);
  2772. if (FAILED(hr))
  2773. return hr;
  2774. m_spInit.Release();
  2775. // Now bind the moniker
  2776. hr = BindMoniker(spMoniker, 0, IID_IDBInitialize, (void**)&m_spInit);
  2777. if (FAILED(hr))
  2778. return hr;
  2779. return OpenWithNameUserPassword(pName, pUserName, pPassword, nInitMode);
  2780. }
  2781. // Invoke the data links dialog and open the selected database
  2782. HRESULT Open(HWND hWnd = GetActiveWindow(), DBPROMPTOPTIONS dwPromptOptions = DBPROMPTOPTIONS_WIZARDSHEET)
  2783. {
  2784. CComPtr<IDBPromptInitialize> spDBInit;
  2785. HRESULT hr = CoCreateInstance(CLSID_DataLinks, NULL, CLSCTX_INPROC_SERVER,
  2786. IID_IDBPromptInitialize, (void**) &spDBInit);
  2787. if (FAILED(hr))
  2788. return hr;
  2789. CComPtr<IDBProperties> spIDBProperties;
  2790. hr = spDBInit->PromptDataSource(NULL, hWnd, dwPromptOptions, 0, NULL, NULL,
  2791. IID_IDBProperties, (IUnknown**)&spIDBProperties);
  2792. if (hr == S_OK)
  2793. {
  2794. hr = spIDBProperties->QueryInterface(&m_spInit);
  2795. if (SUCCEEDED(hr))
  2796. hr = m_spInit->Initialize();
  2797. }
  2798. else if (hr == S_FALSE)
  2799. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CANCELLED); // The user clicked cancel
  2800. return hr;
  2801. }
  2802. // Opens a data source using the service components
  2803. HRESULT OpenWithServiceComponents(const CLSID& clsid, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
  2804. {
  2805. CComPtr<IDataInitialize> spDataInit;
  2806. HRESULT hr;
  2807. hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
  2808. IID_IDataInitialize, (void**)&spDataInit);
  2809. if (FAILED(hr))
  2810. return hr;
  2811. m_spInit.Release();
  2812. hr = spDataInit->CreateDBInstance(clsid, NULL, CLSCTX_INPROC_SERVER, NULL,
  2813. IID_IDBInitialize, (IUnknown**)&m_spInit);
  2814. if (FAILED(hr))
  2815. return hr;
  2816. // Initialize the provider
  2817. return OpenWithProperties(pPropSet, nPropertySets);
  2818. }
  2819. // Opens a data source using the service components
  2820. HRESULT OpenWithServiceComponents(LPCTSTR szProgID, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
  2821. {
  2822. USES_CONVERSION;
  2823. HRESULT hr;
  2824. CLSID clsid;
  2825. hr = CLSIDFromProgID(T2COLE(szProgID), &clsid);
  2826. if (FAILED(hr))
  2827. return hr;
  2828. return OpenWithServiceComponents(clsid, pPropSet, nPropertySets);
  2829. }
  2830. // Bring up the "Organize Dialog" which allows the user to select a previously created data link
  2831. // file (.UDL file). The selected file will be used to open the datbase.
  2832. HRESULT OpenWithPromptFileName(HWND hWnd = GetActiveWindow(), DBPROMPTOPTIONS dwPromptOptions = DBPROMPTOPTIONS_NONE,
  2833. LPCOLESTR szInitialDirectory = NULL)
  2834. {
  2835. USES_CONVERSION;
  2836. CComPtr<IDBPromptInitialize> spDBInit;
  2837. HRESULT hr = CoCreateInstance(CLSID_DataLinks, NULL, CLSCTX_INPROC_SERVER,
  2838. IID_IDBPromptInitialize, (void**) &spDBInit);
  2839. if (FAILED(hr))
  2840. return hr;
  2841. CComPtr<IDBProperties> spIDBProperties;
  2842. LPOLESTR szSelected;
  2843. hr = spDBInit->PromptFileName(hWnd, dwPromptOptions, szInitialDirectory, L"*.udl", &szSelected);
  2844. if (hr == S_OK)
  2845. hr = OpenFromFileName(szSelected);
  2846. else if (hr == S_FALSE)
  2847. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CANCELLED); // The user clicked cancel
  2848. return hr;
  2849. }
  2850. // Open the datasource specified by the passed filename, typically a .UDL file
  2851. HRESULT OpenFromFileName(LPCOLESTR szFileName)
  2852. {
  2853. CComPtr<IDataInitialize> spDataInit;
  2854. LPOLESTR szInitString;
  2855. HRESULT hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
  2856. IID_IDataInitialize, (void**)&spDataInit);
  2857. if (FAILED(hr))
  2858. return hr;
  2859. hr = spDataInit->LoadStringFromStorage(szFileName, &szInitString);
  2860. if (FAILED(hr))
  2861. return hr;
  2862. return OpenFromInitializationString(szInitString);
  2863. }
  2864. // Open the datasource specified by the passed initialization string
  2865. HRESULT OpenFromInitializationString(LPCOLESTR szInitializationString)
  2866. {
  2867. CComPtr<IDataInitialize> spDataInit;
  2868. HRESULT hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
  2869. IID_IDataInitialize, (void**)&spDataInit);
  2870. if (FAILED(hr))
  2871. return hr;
  2872. CComPtr<IDBProperties> spIDBProperties;
  2873. hr = spDataInit->GetDataSource(NULL, CLSCTX_INPROC_SERVER, szInitializationString,
  2874. IID_IDBInitialize, (IUnknown**)&m_spInit);
  2875. if (FAILED(hr))
  2876. return hr;
  2877. return m_spInit->Initialize();
  2878. }
  2879. // Get the initialization string from the currently open data source. The returned string
  2880. // must be CoTaskMemFree'd when finished with.
  2881. HRESULT GetInitializationString(BSTR* pInitializationString, bool bIncludePassword=false)
  2882. {
  2883. // If the datasource isn't open then we're not going to get an init string
  2884. _ASSERTE(m_spInit != NULL);
  2885. CComPtr<IDataInitialize> spDataInit;
  2886. LPOLESTR szInitString;
  2887. HRESULT hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
  2888. IID_IDataInitialize, (void**)&spDataInit);
  2889. if (FAILED(hr))
  2890. return hr;
  2891. hr = spDataInit->GetInitializationString(m_spInit, bIncludePassword, &szInitString);
  2892. if (SUCCEEDED(hr))
  2893. *pInitializationString = ::SysAllocString(szInitString);
  2894. return hr;
  2895. }
  2896. HRESULT GetProperties(ULONG ulPropIDSets, const DBPROPIDSET* pPropIDSet,
  2897. ULONG* pulPropertySets, DBPROPSET** ppPropsets) const
  2898. {
  2899. CComPtr<IDBProperties> spProperties;
  2900. // Check that we are connected
  2901. ATLASSERT(m_spInit != NULL);
  2902. HRESULT hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
  2903. if (FAILED(hr))
  2904. return hr;
  2905. hr = spProperties->GetProperties(ulPropIDSets, pPropIDSet, pulPropertySets,
  2906. ppPropsets);
  2907. return hr;
  2908. }
  2909. HRESULT GetProperty(const GUID& guid, DBPROPID propid, VARIANT* pVariant) const
  2910. {
  2911. ATLASSERT(pVariant != NULL);
  2912. CComPtr<IDBProperties> spProperties;
  2913. // Check that we are connected
  2914. ATLASSERT(m_spInit != NULL);
  2915. HRESULT hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
  2916. if (FAILED(hr))
  2917. return hr;
  2918. CDBPropIDSet set(guid);
  2919. set.AddPropertyID(propid);
  2920. DBPROPSET* pPropSet = NULL;
  2921. ULONG ulPropSet = 0;
  2922. hr = spProperties->GetProperties(1, &set, &ulPropSet, &pPropSet);
  2923. if (FAILED(hr))
  2924. return hr;
  2925. ATLASSERT(ulPropSet == 1);
  2926. VariantCopy(pVariant, &pPropSet->rgProperties[0].vValue);
  2927. CoTaskMemFree(pPropSet->rgProperties);
  2928. CoTaskMemFree(pPropSet);
  2929. return S_OK;
  2930. }
  2931. void Close()
  2932. {
  2933. m_spInit.Release();
  2934. }
  2935. // Implementation
  2936. HRESULT OpenFromIDBProperties(IDBProperties* pIDBProperties)
  2937. {
  2938. CComPtr<IPersist> spPersist;
  2939. CLSID clsid;
  2940. HRESULT hr;
  2941. hr = pIDBProperties->QueryInterface(IID_IPersist, (void**)&spPersist);
  2942. if (FAILED(hr))
  2943. return hr;
  2944. spPersist->GetClassID(&clsid);
  2945. ULONG ulPropSets=0;
  2946. CDBPropSet* pPropSets=NULL;
  2947. pIDBProperties->GetProperties(0, NULL, &ulPropSets, (DBPROPSET**)&pPropSets);
  2948. hr = Open(clsid, &pPropSets[0], ulPropSets);
  2949. for (ULONG i=0; i < ulPropSets; i++)
  2950. (pPropSets+i)->~CDBPropSet();
  2951. CoTaskMemFree(pPropSets);
  2952. return hr;
  2953. }
  2954. HRESULT OpenWithNameUserPassword(LPCTSTR pName, LPCTSTR pUserName, LPCTSTR pPassword, long nInitMode = 0)
  2955. {
  2956. ATLASSERT(m_spInit != NULL);
  2957. CComPtr<IDBProperties> spProperties;
  2958. HRESULT hr;
  2959. hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
  2960. if (FAILED(hr))
  2961. return hr;
  2962. // Set connection properties
  2963. CDBPropSet propSet(DBPROPSET_DBINIT);
  2964. // Add Datbase name, User name and Password
  2965. if (pName != NULL)
  2966. propSet.AddProperty(DBPROP_INIT_DATASOURCE, pName);
  2967. if (pUserName != NULL)
  2968. propSet.AddProperty(DBPROP_AUTH_USERID, pUserName);
  2969. if (pPassword != NULL)
  2970. propSet.AddProperty(DBPROP_AUTH_PASSWORD, pPassword);
  2971. if (nInitMode)
  2972. propSet.AddProperty(DBPROP_INIT_MODE, nInitMode);
  2973. hr = spProperties->SetProperties(1, &propSet);
  2974. if (FAILED(hr))
  2975. return hr;
  2976. // Initialize the provider
  2977. return m_spInit->Initialize();
  2978. }
  2979. HRESULT OpenWithProperties(DBPROPSET* pPropSet, ULONG nPropertySets=1)
  2980. {
  2981. ATLASSERT(m_spInit != NULL);
  2982. // Set the properties if there are some to set
  2983. if (pPropSet != NULL)
  2984. {
  2985. CComPtr<IDBProperties> spProperties;
  2986. HRESULT hr;
  2987. hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
  2988. if (FAILED(hr))
  2989. return hr;
  2990. hr = spProperties->SetProperties(nPropertySets, pPropSet);
  2991. if (FAILED(hr))
  2992. return hr;
  2993. }
  2994. // Initialize the provider
  2995. return m_spInit->Initialize();
  2996. }
  2997. CComPtr<IDBInitialize> m_spInit;
  2998. };
  2999. ///////////////////////////////////////////////////////////////////////////
  3000. // class CSession
  3001. class CSession
  3002. {
  3003. public:
  3004. // Create a session on the passed datasource
  3005. HRESULT Open(const CDataSource& ds)
  3006. {
  3007. CComPtr<IDBCreateSession> spSession;
  3008. // Check we have connected to the database
  3009. ATLASSERT(ds.m_spInit != NULL);
  3010. HRESULT hr = ds.m_spInit->QueryInterface(IID_IDBCreateSession, (void**)&spSession);
  3011. if (FAILED(hr))
  3012. return hr;
  3013. hr = spSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown**)&m_spOpenRowset);
  3014. return hr;
  3015. }
  3016. // Close the session
  3017. void Close()
  3018. {
  3019. m_spOpenRowset.Release();
  3020. }
  3021. // Start a transaction
  3022. HRESULT StartTransaction(ISOLEVEL isoLevel = ISOLATIONLEVEL_READCOMMITTED, ULONG isoFlags = 0,
  3023. ITransactionOptions* pOtherOptions = NULL, ULONG* pulTransactionLevel = NULL) const
  3024. {
  3025. ATLASSERT(m_spOpenRowset != NULL);
  3026. CComPtr<ITransactionLocal> spTransactionLocal;
  3027. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransactionLocal);
  3028. if (SUCCEEDED(hr))
  3029. hr = spTransactionLocal->StartTransaction(isoLevel, isoFlags, pOtherOptions, pulTransactionLevel);
  3030. return hr;
  3031. }
  3032. // Abort the current transaction
  3033. HRESULT Abort(BOID* pboidReason = NULL, BOOL bRetaining = FALSE, BOOL bAsync = FALSE) const
  3034. {
  3035. ATLASSERT(m_spOpenRowset != NULL);
  3036. CComPtr<ITransaction> spTransaction;
  3037. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
  3038. if (SUCCEEDED(hr))
  3039. hr = spTransaction->Abort(pboidReason, bRetaining, bAsync);
  3040. return hr;
  3041. }
  3042. // Commit the current transaction
  3043. HRESULT Commit(BOOL bRetaining = FALSE, DWORD grfTC = XACTTC_SYNC, DWORD grfRM = 0) const
  3044. {
  3045. ATLASSERT(m_spOpenRowset != NULL);
  3046. CComPtr<ITransaction> spTransaction;
  3047. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
  3048. if (SUCCEEDED(hr))
  3049. hr = spTransaction->Commit(bRetaining, grfTC, grfRM);
  3050. return hr;
  3051. }
  3052. // Get information for the current transaction
  3053. HRESULT GetTransactionInfo(XACTTRANSINFO* pInfo) const
  3054. {
  3055. ATLASSERT(m_spOpenRowset != NULL);
  3056. CComPtr<ITransaction> spTransaction;
  3057. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
  3058. if (SUCCEEDED(hr))
  3059. hr = spTransaction->GetTransactionInfo(pInfo);
  3060. return hr;
  3061. }
  3062. // Implementation
  3063. CComPtr<IOpenRowset> m_spOpenRowset;
  3064. };
  3065. ///////////////////////////////////////////////////////////////////////////
  3066. // CTable
  3067. template <class TAccessor = CNoAccessor, class TRowset = CRowset>
  3068. class CTable :
  3069. public CAccessorRowset<TAccessor, TRowset>
  3070. {
  3071. public:
  3072. // Open a rowset on the passed name
  3073. HRESULT Open(const CSession& session, LPCTSTR szTableName, DBPROPSET* pPropSet = NULL)
  3074. {
  3075. USES_CONVERSION;
  3076. DBID idTable;
  3077. idTable.eKind = DBKIND_NAME;
  3078. idTable.uName.pwszName = (LPOLESTR)T2COLE(szTableName);
  3079. return Open(session, idTable, pPropSet);
  3080. }
  3081. // Open the a rowset on the passed DBID
  3082. HRESULT Open(const CSession& session, DBID& dbid, DBPROPSET* pPropSet = NULL)
  3083. {
  3084. // Check the session is valid
  3085. ATLASSERT(session.m_spOpenRowset != NULL);
  3086. HRESULT hr;
  3087. hr = session.m_spOpenRowset->OpenRowset(NULL, &dbid, NULL, GetIID(),
  3088. (pPropSet) ? 1 : 0, pPropSet, (IUnknown**)GetInterfacePtr());
  3089. if (SUCCEEDED(hr))
  3090. {
  3091. SetupOptionalRowsetInterfaces();
  3092. // If we have output columns then bind
  3093. if (_OutputColumnsClass::HasOutputColumns())
  3094. hr = Bind();
  3095. }
  3096. return hr;
  3097. }
  3098. };
  3099. #if (OLEDBVER < 0x0150)
  3100. #define DBGUID_DEFAULT DBGUID_DBSQL
  3101. #endif
  3102. ///////////////////////////////////////////////////////////////////////////
  3103. // CCommandBase
  3104. class CCommandBase
  3105. {
  3106. public:
  3107. CCommandBase()
  3108. {
  3109. m_hParameterAccessor = NULL;
  3110. }
  3111. ~CCommandBase()
  3112. {
  3113. ReleaseCommand();
  3114. }
  3115. // Create the command
  3116. HRESULT CreateCommand(const CSession& session)
  3117. {
  3118. // Before creating the command, release the old one if necessary.
  3119. ReleaseCommand();
  3120. // Check the session is valid
  3121. ATLASSERT(session.m_spOpenRowset != NULL);
  3122. CComPtr<IDBCreateCommand> spCreateCommand;
  3123. HRESULT hr = session.m_spOpenRowset->QueryInterface(IID_IDBCreateCommand, (void**)&spCreateCommand);
  3124. if (FAILED(hr))
  3125. return hr;
  3126. return spCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown**)&m_spCommand);
  3127. }
  3128. // Prepare the command
  3129. HRESULT Prepare(ULONG cExpectedRuns = 0)
  3130. {
  3131. CComPtr<ICommandPrepare> spCommandPrepare;
  3132. HRESULT hr = m_spCommand->QueryInterface(&spCommandPrepare);
  3133. if (SUCCEEDED(hr))
  3134. hr = spCommandPrepare->Prepare(cExpectedRuns);
  3135. return hr;
  3136. }
  3137. // Unprepare the command
  3138. HRESULT Unprepare()
  3139. {
  3140. CComPtr<ICommandPrepare> spCommandPrepare;
  3141. HRESULT hr = m_spCommand->QueryInterface(&spCommandPrepare);
  3142. if (SUCCEEDED(hr))
  3143. hr = spCommandPrepare->Unprepare();
  3144. return hr;
  3145. }
  3146. // Create the command and set the command text
  3147. HRESULT Create(const CSession& session, LPCTSTR szCommand,
  3148. REFGUID guidCommand = DBGUID_DEFAULT)
  3149. {
  3150. USES_CONVERSION;
  3151. HRESULT hr;
  3152. hr = CreateCommand(session);
  3153. if (SUCCEEDED(hr))
  3154. {
  3155. CComPtr<ICommandText> spCommandText;
  3156. hr = m_spCommand->QueryInterface(&spCommandText);
  3157. if (SUCCEEDED(hr))
  3158. hr = spCommandText->SetCommandText(guidCommand, T2COLE(szCommand));
  3159. }
  3160. return hr;
  3161. }
  3162. // Release the command
  3163. void ReleaseCommand()
  3164. {
  3165. // Release the parameter accessor if necessary, before releasing the command
  3166. if (m_hParameterAccessor != NULL)
  3167. {
  3168. CComPtr<IAccessor> spAccessor;
  3169. HRESULT hr = m_spCommand->QueryInterface(&spAccessor);
  3170. if (SUCCEEDED(hr))
  3171. {
  3172. spAccessor->ReleaseAccessor(m_hParameterAccessor, NULL); \
  3173. m_hParameterAccessor = NULL;
  3174. }
  3175. }
  3176. m_spCommand.Release();
  3177. }
  3178. // Get the parameter information from the command
  3179. HRESULT GetParameterInfo(ULONG_PTR* pParams, DBPARAMINFO** ppParamInfo,
  3180. OLECHAR** ppNamesBuffer)
  3181. {
  3182. CComPtr<ICommandWithParameters> spCommandParameters;
  3183. HRESULT hr = m_spCommand->QueryInterface(&spCommandParameters);
  3184. if (SUCCEEDED(hr))
  3185. {
  3186. // Get the parameter information
  3187. hr = spCommandParameters->GetParameterInfo(pParams, ppParamInfo,
  3188. ppNamesBuffer);
  3189. }
  3190. return hr;
  3191. }
  3192. // Set the parameter information for the command
  3193. HRESULT SetParameterInfo(ULONG_PTR ulParams, const ULONG_PTR* pOrdinals,
  3194. const DBPARAMBINDINFO* pParamInfo)
  3195. {
  3196. CComPtr<ICommandWithParameters> spCommandParameters;
  3197. HRESULT hr = m_spCommand->QueryInterface(&spCommandParameters);
  3198. if (SUCCEEDED(hr))
  3199. {
  3200. // Set the parameter information
  3201. hr = spCommandParameters->SetParameterInfo(ulParams, pOrdinals,
  3202. pParamInfo);
  3203. }
  3204. return hr;
  3205. }
  3206. CComPtr<ICommand> m_spCommand;
  3207. HACCESSOR m_hParameterAccessor;
  3208. };
  3209. // Used to turn on multiple result set support in CCommand
  3210. class CMultipleResults
  3211. {
  3212. public:
  3213. bool UseMultipleResults() { return true; }
  3214. IMultipleResults** GetMultiplePtrAddress() { return &m_spMultipleResults.p; }
  3215. IMultipleResults* GetMultiplePtr() { return m_spMultipleResults; }
  3216. CComPtr<IMultipleResults> m_spMultipleResults;
  3217. };
  3218. // Used to turn off multiple result set support in CCommand
  3219. class CNoMultipleResults
  3220. {
  3221. public:
  3222. bool UseMultipleResults() { return false; }
  3223. IMultipleResults** GetMultiplePtrAddress() { return NULL; }
  3224. IMultipleResults* GetMultiplePtr() { return NULL; }
  3225. };
  3226. ///////////////////////////////////////////////////////////////////////////
  3227. // CCommand
  3228. template <class TAccessor = CNoAccessor, class TRowset = CRowset, class TMultiple = CNoMultipleResults>
  3229. class CCommand :
  3230. public CAccessorRowset<TAccessor, TRowset>,
  3231. public CCommandBase,
  3232. public TMultiple
  3233. {
  3234. public:
  3235. // Create a command on the session and execute it
  3236. HRESULT Open(const CSession& session, LPCTSTR szCommand = NULL,
  3237. DBPROPSET *pPropSet = NULL, LONG_PTR* pRowsAffected = NULL,
  3238. REFGUID guidCommand = DBGUID_DEFAULT, bool bBind = true)
  3239. {
  3240. HRESULT hr;
  3241. if (szCommand == NULL)
  3242. {
  3243. hr = _CommandClass::GetDefaultCommand(&szCommand);
  3244. if (FAILED(hr))
  3245. return hr;
  3246. }
  3247. hr = Create(session, szCommand, guidCommand);
  3248. if (FAILED(hr))
  3249. return hr;
  3250. return Open(pPropSet, pRowsAffected, bBind);
  3251. }
  3252. // Used if you have previously created the command
  3253. HRESULT Open(DBPROPSET *pPropSet = NULL, LONG_PTR* pRowsAffected = NULL, bool bBind = true)
  3254. {
  3255. HRESULT hr;
  3256. DBPARAMS params;
  3257. DBPARAMS *pParams;
  3258. // Bind the parameters if we have some
  3259. if (_ParamClass::HasParameters())
  3260. {
  3261. // Bind the parameters in the accessor if they haven't already been bound
  3262. hr = BindParameters(&m_hParameterAccessor, m_spCommand, &params.pData);
  3263. if (FAILED(hr))
  3264. return hr;
  3265. // Setup the DBPARAMS structure
  3266. params.cParamSets = 1;
  3267. params.hAccessor = m_hParameterAccessor;
  3268. pParams = &params;
  3269. }
  3270. else
  3271. pParams = NULL;
  3272. hr = Execute(GetInterfacePtr(), pParams, pPropSet, pRowsAffected);
  3273. if (FAILED(hr))
  3274. return hr;
  3275. // Only bind if we have been asked to and we have output columns
  3276. if (bBind && _OutputColumnsClass::HasOutputColumns())
  3277. return Bind();
  3278. else
  3279. return hr;
  3280. }
  3281. // Get the next rowset when using multiple result sets
  3282. HRESULT GetNextResult(LONG_PTR* pulRowsAffected, bool bBind = true)
  3283. {
  3284. // This function should only be called if CMultipleResults is being
  3285. // used as the third template parameter
  3286. ATLASSERT(GetMultiplePtrAddress() != NULL);
  3287. // If user calls GetNextResult but the interface is not available
  3288. // return E_FAIL.
  3289. if (GetMultiplePtr() == NULL)
  3290. return E_FAIL;
  3291. // Close the existing rowset in preparation for opening the next one
  3292. Close();
  3293. HRESULT hr = GetMultiplePtr()->GetResult(NULL, 0, IID_IRowset,
  3294. pulRowsAffected, (IUnknown**)GetInterfacePtr());
  3295. if (FAILED(hr))
  3296. return hr;
  3297. if (bBind && GetInterface() != NULL)
  3298. return Bind();
  3299. else
  3300. return hr;
  3301. }
  3302. // Implementation
  3303. HRESULT Execute(IRowset** ppRowset, DBPARAMS* pParams, DBPROPSET *pPropSet, LONG_PTR* pRowsAffected)
  3304. {
  3305. HRESULT hr;
  3306. // Specify the properties if we have some
  3307. if (pPropSet)
  3308. {
  3309. CComPtr<ICommandProperties> spCommandProperties;
  3310. hr = m_spCommand->QueryInterface(&spCommandProperties);
  3311. if (FAILED(hr))
  3312. return hr;
  3313. hr = spCommandProperties->SetProperties(1, pPropSet);
  3314. if (FAILED(hr))
  3315. return hr;
  3316. }
  3317. // If the user want the rows affected then return it back, otherwise
  3318. // just point to our local variable here.
  3319. LONG_PTR nAffected, *pAffected;
  3320. if (pRowsAffected)
  3321. pAffected = pRowsAffected;
  3322. else
  3323. pAffected = &nAffected;
  3324. if (UseMultipleResults())
  3325. {
  3326. hr = m_spCommand->Execute(NULL, IID_IMultipleResults, pParams,
  3327. pAffected, (IUnknown**)GetMultiplePtrAddress());
  3328. if (SUCCEEDED(hr))
  3329. {
  3330. hr = GetNextResult(pAffected, false);
  3331. }
  3332. else
  3333. {
  3334. // If we can't get IMultipleResults then just try to get IRowset
  3335. hr = m_spCommand->Execute(NULL, IID_IRowset, pParams, pAffected,
  3336. (IUnknown**)GetInterfacePtr());
  3337. }
  3338. }
  3339. else
  3340. {
  3341. hr = m_spCommand->Execute(NULL, GetIID(), pParams, pAffected,
  3342. (IUnknown**)ppRowset);
  3343. if (SUCCEEDED(hr))
  3344. SetupOptionalRowsetInterfaces();
  3345. }
  3346. return hr;
  3347. }
  3348. };
  3349. // This class can be used to implement the IRowsetNotify interface.
  3350. // It is supplied so that if you only want to implement one of the
  3351. // notifications you don't have to supply empty functions for the
  3352. // other methods.
  3353. class ATL_NO_VTABLE IRowsetNotifyImpl : public IRowsetNotify
  3354. {
  3355. public:
  3356. STDMETHOD(OnFieldChange)(
  3357. /* [in] */ IRowset* /* pRowset */,
  3358. /* [in] */ HROW /* hRow */,
  3359. /* [in] */ DBORDINAL /* cColumns */,
  3360. /* [size_is][in] */ DBORDINAL /* rgColumns*/ [] ,
  3361. /* [in] */ DBREASON /* eReason */,
  3362. /* [in] */ DBEVENTPHASE /* ePhase */,
  3363. /* [in] */ BOOL /* fCantDeny */)
  3364. {
  3365. ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnFieldChange"));
  3366. }
  3367. STDMETHOD(OnRowChange)(
  3368. /* [in] */ IRowset* /* pRowset */,
  3369. /* [in] */ DBCOUNTITEM /* cRows */,
  3370. /* [size_is][in] */ const HROW /* rghRows*/ [] ,
  3371. /* [in] */ DBREASON /* eReason */,
  3372. /* [in] */ DBEVENTPHASE /* ePhase */,
  3373. /* [in] */ BOOL /* fCantDeny */)
  3374. {
  3375. ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnRowChange"));
  3376. }
  3377. STDMETHOD(OnRowsetChange)(
  3378. /* [in] */ IRowset* /* pRowset */,
  3379. /* [in] */ DBREASON /* eReason */,
  3380. /* [in] */ DBEVENTPHASE /* ePhase */,
  3381. /* [in] */ BOOL /* fCantDeny*/)
  3382. {
  3383. ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnRowsetChange"));
  3384. }
  3385. };
  3386. }; //namespace ATL
  3387. #endif // __ATLDBCLI_H_