Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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