Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6431 lines
191 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. #ifndef __ATLDB_H
  11. #define __ATLDB_H
  12. // OLE DB Provider Support
  13. // Interface Impl Classes
  14. //
  15. // Data Source Object
  16. //
  17. // -Mandatory Interfaces:
  18. // IDBCreateSession
  19. // IDBInitialize
  20. // IDBProperties
  21. // IPersist
  22. //
  23. // Session Object
  24. //
  25. // -Mandatory Interfaces:
  26. // IGetDataSource
  27. // IOpenRowset
  28. // ISessionProperties
  29. //
  30. // -Optional Interfaces:
  31. // IDBCreateCommand
  32. // IDBSchemaRowset
  33. //
  34. // Rowset Object
  35. //
  36. // -Mandatory Interfaces:
  37. // IAccessor
  38. // IColumnsInfo
  39. // IConvertType
  40. // IRowset
  41. // IRowsetInfo
  42. //
  43. // -Optional Interfaces:
  44. // IRowsetIdentity
  45. //
  46. // Command Object
  47. //
  48. // -Mandatory Interfaces:
  49. // ICommand)
  50. // IAccessor)
  51. // ICommandProperties
  52. // ICommandText - derives from ICommand
  53. // IColumnsInfo
  54. // IConvertType
  55. #include <oledb.h>
  56. #include <limits.h>
  57. #include <oledberr.h>
  58. #include <msdadc.h>
  59. #include <atldbcli.h>
  60. //Forwards
  61. template <class T> class CUtlPropInfo;
  62. class CColumnIds;
  63. // Additional Property Flag needed internally
  64. const int DBPROPFLAGS_CHANGE = 0x40000000;
  65. // ------------- STRUCTURE DEFINITIONS --------------------------------
  66. struct UPROPVAL
  67. {
  68. DBPROPOPTIONS dwOption;
  69. CColumnIds* pCColumnIds;
  70. DWORD dwFlags;
  71. VARIANT vValue;
  72. };
  73. struct UPROPINFO
  74. {
  75. DBPROPID dwPropId;
  76. ULONG ulIDS;
  77. VARTYPE VarType;
  78. DBPROPFLAGS dwFlags;
  79. union
  80. {
  81. DWORD_PTR dwVal;
  82. LPOLESTR szVal;
  83. };
  84. DBPROPOPTIONS dwOption;
  85. };
  86. struct UPROP
  87. {
  88. ULONG cPropIds;
  89. UPROPINFO** rgpUPropInfo;
  90. UPROPVAL* pUPropVal;
  91. };
  92. struct PROPCOLID
  93. {
  94. DBID dbidProperty; // The column id information
  95. DBPROPOPTIONS dwOption;
  96. VARIANT vValue;
  97. };
  98. typedef PROPCOLID* PPROPCOLID;
  99. struct UPROPSET
  100. {
  101. const GUID* pPropSet;
  102. ULONG cUPropInfo;
  103. UPROPINFO* pUPropInfo;
  104. DWORD dwFlags;
  105. };
  106. struct ATLBINDINGS
  107. {
  108. DBBINDING* pBindings;
  109. DWORD dwRef;
  110. DBCOUNTITEM cBindings;
  111. DBACCESSORFLAGS dwAccessorFlags;
  112. };
  113. struct ATLCOLUMNINFO
  114. {
  115. LPOLESTR pwszName;
  116. ITypeInfo *pTypeInfo;
  117. DBORDINAL iOrdinal;
  118. DBCOLUMNFLAGS dwFlags;
  119. DBLENGTH ulColumnSize;
  120. DBTYPE wType;
  121. BYTE bPrecision;
  122. BYTE bScale;
  123. DBID columnid;
  124. DBBYTEOFFSET cbOffset;
  125. };
  126. //
  127. // The following very large sections of defines are to implement auto determination
  128. // of Preoperty map constants based on a stringized prop name. There is one set for
  129. // Type (VT_), one for Init Value, and one for Property flags.
  130. //
  131. #define ABORTPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  132. #define ACTIVESESSIONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  133. #define APPENDONLY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  134. #define ASYNCTXNABORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  135. #define ASYNCTXNCOMMIT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  136. #define AUTH_CACHE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  137. #define AUTH_ENCRYPT_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  138. #define AUTH_INTEGRATED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  139. #define AUTH_MASK_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  140. #define AUTH_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  141. #define AUTH_PERSIST_ENCRYPTED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  142. #define AUTH_PERSIST_SENSITIVE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  143. #define AUTH_USERID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  144. #define BLOCKINGSTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  145. #define BOOKMARKS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  146. #define BOOKMARKSKIPPED_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  147. #define BOOKMARKTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  148. #define BYREFACCESSORS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  149. #define CACHEDEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  150. #define CANFETCHBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  151. #define CANHOLDROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  152. #define CANSCROLLBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  153. #define CATALOGLOCATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  154. #define CATALOGTERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  155. #define CATALOGUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  156. #define CHANGEINSERTEDROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE )
  157. #define COL_AUTOINCREMENT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  158. #define COL_DEFAULT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  159. #define COL_DESCRIPTION_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  160. #define COL_FIXEDLENGTH_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  161. #define COL_NULLABLE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  162. #define COL_PRIMARYKEY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  163. #define COL_UNIQUE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  164. #define COLUMNDEFINITION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  165. #define COLUMNRESTRICT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  166. #define COMMANDTIMEOUT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  167. #define COMMITPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  168. #define CONCATNULLBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  169. #define CURRENTCATALOG_Flags ( DBPROPFLAGS_DATASOURCE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  170. #define DATASOURCENAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  171. #define DATASOURCEREADONLY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  172. #define DBMSNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  173. #define DBMSVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  174. #define DEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  175. #define DELAYSTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  176. #define DSOTHREADMODEL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  177. #define GROUPBY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  178. #define HETEROGENEOUSTABLES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  179. #define IAccessor_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  180. #define IColumnsInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  181. #define IColumnsRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  182. #define IConnectionPointContainer_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  183. #define IConvertType_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  184. #define IRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  185. #define IRowsetChange_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  186. #define IRowsetIdentity_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  187. #define IRowsetIndex_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  188. #define IRowsetInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  189. #define IRowsetLocate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  190. #define IRowsetResynch_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  191. #define IRowsetScroll_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  192. #define IRowsetUpdate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  193. #define ISupportErrorInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  194. #define ILockBytes_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  195. #define ISequentialStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  196. #define IStorage_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  197. #define IStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  198. #define IDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  199. #define IMMOBILEROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  200. #define INDEX_AUTOUPDATE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  201. #define INDEX_CLUSTERED_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  202. #define INDEX_FILLFACTOR_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  203. #define INDEX_INITIALSIZE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  204. #define INDEX_NULLCOLLATION_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  205. #define INDEX_NULLS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  206. #define INDEX_PRIMARYKEY_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  207. #define INDEX_SORTBOOKMARKS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  208. #define INDEX_TEMPINDEX_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  209. #define INDEX_TYPE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  210. #define INDEX_UNIQUE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  211. #define INIT_DATASOURCE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  212. #define INIT_HWND_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  213. #define INIT_IMPERSONATION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  214. #define INIT_LCID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  215. #define INIT_LOCATION_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  216. #define INIT_MODE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  217. #define INIT_PROMPT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  218. #define INIT_PROTECTION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  219. #define INIT_PROVIDERSTRING_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  220. #define INIT_TIMEOUT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  221. #define LITERALBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  222. #define LITERALIDENTITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  223. #define MAXINDEXSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  224. #define MAXOPENROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  225. #define MAXPENDINGROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  226. #define MAXROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  227. #define MAXROWSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  228. #define MAXROWSIZEINCLUDESBLOB_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  229. #define MAXTABLESINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  230. #define MAYWRITECOLUMN_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  231. #define MEMORYUSAGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  232. #define MULTIPLEPARAMSETS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  233. #define MULTIPLERESULTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  234. #define MULTIPLESTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  235. #define MULTITABLEUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  236. #define NOTIFICATIONPHASES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  237. #define NOTIFYCOLUMNSET_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  238. #define NOTIFYROWDELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  239. #define NOTIFYROWFIRSTCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  240. #define NOTIFYROWINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  241. #define NOTIFYROWRESYNCH_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  242. #define NOTIFYROWSETRELEASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  243. #define NOTIFYROWSETFETCHPOSITIONCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  244. #define NOTIFYROWUNDOCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  245. #define NOTIFYROWUNDODELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  246. #define NOTIFYROWUNDOINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  247. #define NOTIFYROWUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  248. #define NULLCOLLATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  249. #define OLEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  250. #define ORDERBYCOLUMNSINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  251. #define ORDEREDBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  252. #define OTHERINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  253. #define OTHERUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  254. #define OUTPUTPARAMETERAVAILABILITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  255. #define OWNINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  256. #define OWNUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  257. #define PERSISTENTIDTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  258. #define PREPAREABORTBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  259. #define PREPARECOMMITBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  260. #define PROCEDURETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  261. #define PROVIDERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  262. #define PROVIDEROLEDBVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  263. #define PROVIDERVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  264. #define QUICKRESTART_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  265. #define QUOTEDIDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  266. #define REENTRANTEVENTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  267. #define REMOVEDELETED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  268. #define REPORTMULTIPLECHANGES_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE )
  269. #define RETURNPENDINGINSERTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  270. #define ROWRESTRICT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  271. #define ROWSETCONVERSIONSONCOMMAND_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  272. #define ROWTHREADMODEL_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  273. #define SCHEMATERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  274. #define SCHEMAUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  275. #define SERVERCURSOR_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  276. #define SESS_AUTOCOMMITISOLEVELS_Flags ( DBPROPFLAGS_SESSION | DBPROPFLAGS_READ )
  277. #define SQLSUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  278. #define STRONGIDENTITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  279. #define STRUCTUREDSTORAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  280. #define SUBQUERIES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  281. #define SUPPORTEDTXNDDL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  282. #define SUPPORTEDTXNISOLEVELS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  283. #define SUPPORTEDTXNISORETAIN_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  284. #define TABLETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  285. #define TBL_TEMPTABLE_Flags ( DBPROPFLAGS_TABLE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  286. #define TRANSACTEDOBJECT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  287. #define UPDATABILITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  288. #define USERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  289. #define ABORTPRESERVE_Type VT_BOOL
  290. #define ACTIVESESSIONS_Type VT_I4
  291. #define APPENDONLY_Type VT_BOOL
  292. #define ASYNCTXNABORT_Type VT_BOOL
  293. #define ASYNCTXNCOMMIT_Type VT_BOOL
  294. #define AUTH_CACHE_AUTHINFO_Type VT_BOOL
  295. #define AUTH_ENCRYPT_PASSWORD_Type VT_BOOL
  296. #define AUTH_INTEGRATED_Type VT_BSTR
  297. #define AUTH_MASK_PASSWORD_Type VT_BOOL
  298. #define AUTH_PASSWORD_Type VT_BSTR
  299. #define AUTH_PERSIST_ENCRYPTED_Type VT_BOOL
  300. #define AUTH_PERSIST_SENSITIVE_AUTHINFO_Type VT_BOOL
  301. #define AUTH_USERID_Type VT_BSTR
  302. #define BLOCKINGSTORAGEOBJECTS_Type VT_BOOL
  303. #define BOOKMARKS_Type VT_BOOL
  304. #define BOOKMARKSKIPPED_Type VT_BOOL
  305. #define BOOKMARKTYPE_Type VT_I4
  306. #define BYREFACCESSORS_Type VT_BOOL
  307. #define CACHEDEFERRED_Type VT_BOOL
  308. #define CANFETCHBACKWARDS_Type VT_BOOL
  309. #define CANHOLDROWS_Type VT_BOOL
  310. #define CANSCROLLBACKWARDS_Type VT_BOOL
  311. #define CATALOGLOCATION_Type VT_I4
  312. #define CATALOGTERM_Type VT_BSTR
  313. #define CATALOGUSAGE_Type VT_I4
  314. #define CHANGEINSERTEDROWS_Type VT_BOOL
  315. #define COL_AUTOINCREMENT_Type VT_BOOL
  316. #define COL_DEFAULT_Type VT_BSTR
  317. #define COL_DESCRIPTION_Type VT_BSTR
  318. #define COL_FIXEDLENGTH_Type VT_BOOL
  319. #define COL_NULLABLE_Type VT_BOOL
  320. #define COL_PRIMARYKEY_Type VT_BOOL
  321. #define COL_UNIQUE_Type VT_BOOL
  322. #define COLUMNDEFINITION_Type VT_I4
  323. #define COLUMNRESTRICT_Type VT_BOOL
  324. #define COMMANDTIMEOUT_Type VT_I4
  325. #define COMMITPRESERVE_Type VT_BOOL
  326. #define CONCATNULLBEHAVIOR_Type VT_I4
  327. #define CURRENTCATALOG_Type VT_BSTR
  328. #define DATASOURCENAME_Type VT_BSTR
  329. #define DATASOURCEREADONLY_Type VT_BOOL
  330. #define DBMSNAME_Type VT_BSTR
  331. #define DBMSVER_Type VT_BSTR
  332. #define DEFERRED_Type VT_BOOL
  333. #define DELAYSTORAGEOBJECTS_Type VT_BOOL
  334. #define DSOTHREADMODEL_Type VT_I4
  335. #define GROUPBY_Type VT_I4
  336. #define HETEROGENEOUSTABLES_Type VT_I4
  337. #define IAccessor_Type VT_BOOL
  338. #define IColumnsInfo_Type VT_BOOL
  339. #define IColumnsRowset_Type VT_BOOL
  340. #define IConnectionPointContainer_Type VT_BOOL
  341. #define IConvertType_Type VT_BOOL
  342. #define IRowset_Type VT_BOOL
  343. #define IRowsetChange_Type VT_BOOL
  344. #define IRowsetIdentity_Type VT_BOOL
  345. #define IRowsetIndex_Type VT_BOOL
  346. #define IRowsetInfo_Type VT_BOOL
  347. #define IRowsetLocate_Type VT_BOOL
  348. #define IRowsetResynch_Type VT_BOOL
  349. #define IRowsetScroll_Type VT_BOOL
  350. #define IRowsetUpdate_Type VT_BOOL
  351. #define ISupportErrorInfo_Type VT_BOOL
  352. #define ILockBytes_Type VT_BOOL
  353. #define ISequentialStream_Type VT_BOOL
  354. #define IStorage_Type VT_BOOL
  355. #define IStream_Type VT_BOOL
  356. #define IDENTIFIERCASE_Type VT_I4
  357. #define IMMOBILEROWS_Type VT_BOOL
  358. #define INDEX_AUTOUPDATE_Type VT_BOOL
  359. #define INDEX_CLUSTERED_Type VT_BOOL
  360. #define INDEX_FILLFACTOR_Type VT_I4
  361. #define INDEX_INITIALSIZE_Type VT_I4
  362. #define INDEX_NULLCOLLATION_Type VT_I4
  363. #define INDEX_NULLS_Type VT_I4
  364. #define INDEX_PRIMARYKEY_Type VT_BOOL
  365. #define INDEX_SORTBOOKMARKS_Type VT_BOOL
  366. #define INDEX_TEMPINDEX_Type VT_BOOL
  367. #define INDEX_TYPE_Type VT_I4
  368. #define INDEX_UNIQUE_Type VT_BOOL
  369. #define INIT_DATASOURCE_Type VT_BSTR
  370. #define INIT_HWND_Type VT_I4
  371. #define INIT_IMPERSONATION_LEVEL_Type VT_I4
  372. #define INIT_LCID_Type VT_I4
  373. #define INIT_LOCATION_Type VT_BSTR
  374. #define INIT_MODE_Type VT_I4
  375. #define INIT_PROMPT_Type VT_I2
  376. #define INIT_PROTECTION_LEVEL_Type VT_I4
  377. #define INIT_PROVIDERSTRING_Type VT_BSTR
  378. #define INIT_TIMEOUT_Type VT_I4
  379. #define LITERALBOOKMARKS_Type VT_BOOL
  380. #define LITERALIDENTITY_Type VT_BOOL
  381. #define MAXINDEXSIZE_Type VT_I4
  382. #define MAXOPENROWS_Type VT_I4
  383. #define MAXPENDINGROWS_Type VT_I4
  384. #define MAXROWS_Type VT_I4
  385. #define MAXROWSIZE_Type VT_I4
  386. #define MAXROWSIZEINCLUDESBLOB_Type VT_BOOL
  387. #define MAXTABLESINSELECT_Type VT_I4
  388. #define MAYWRITECOLUMN_Type VT_BOOL
  389. #define MEMORYUSAGE_Type VT_I4
  390. #define MULTIPLEPARAMSETS_Type VT_BOOL
  391. #define MULTIPLERESULTS_Type VT_I4
  392. #define MULTIPLESTORAGEOBJECTS_Type VT_BOOL
  393. #define MULTITABLEUPDATE_Type VT_BOOL
  394. #define NOTIFICATIONPHASES_Type VT_I4
  395. #define NOTIFYCOLUMNSET_Type VT_I4
  396. #define NOTIFYROWDELETE_Type VT_I4
  397. #define NOTIFYROWFIRSTCHANGE_Type VT_I4
  398. #define NOTIFYROWINSERT_Type VT_I4
  399. #define NOTIFYROWRESYNCH_Type VT_I4
  400. #define NOTIFYROWSETRELEASE_Type VT_I4
  401. #define NOTIFYROWSETFETCHPOSITIONCHANGE_Type VT_I4
  402. #define NOTIFYROWUNDOCHANGE_Type VT_I4
  403. #define NOTIFYROWUNDODELETE_Type VT_I4
  404. #define NOTIFYROWUNDOINSERT_Type VT_I4
  405. #define NOTIFYROWUPDATE_Type VT_I4
  406. #define NULLCOLLATION_Type VT_I4
  407. #define OLEOBJECTS_Type VT_I4
  408. #define ORDERBYCOLUMNSINSELECT_Type VT_BOOL
  409. #define ORDEREDBOOKMARKS_Type VT_BOOL
  410. #define OTHERINSERT_Type VT_BOOL
  411. #define OTHERUPDATEDELETE_Type VT_BOOL
  412. #define OUTPUTPARAMETERAVAILABILITY_Type VT_I4
  413. #define OWNINSERT_Type VT_BOOL
  414. #define OWNUPDATEDELETE_Type VT_BOOL
  415. #define PERSISTENTIDTYPE_Type VT_I4
  416. #define PREPAREABORTBEHAVIOR_Type VT_I4
  417. #define PREPARECOMMITBEHAVIOR_Type VT_I4
  418. #define PROCEDURETERM_Type VT_BSTR
  419. #define PROVIDERNAME_Type VT_BSTR
  420. #define PROVIDEROLEDBVER_Type VT_BSTR
  421. #define PROVIDERVER_Type VT_BSTR
  422. #define QUICKRESTART_Type VT_BOOL
  423. #define QUOTEDIDENTIFIERCASE_Type VT_I4
  424. #define REENTRANTEVENTS_Type VT_BOOL
  425. #define REMOVEDELETED_Type VT_BOOL
  426. #define REPORTMULTIPLECHANGES_Type VT_BOOL
  427. #define RETURNPENDINGINSERTS_Type VT_BOOL
  428. #define ROWRESTRICT_Type VT_BOOL
  429. #define ROWSETCONVERSIONSONCOMMAND_Type VT_BOOL
  430. #define ROWTHREADMODEL_Type VT_I4
  431. #define SCHEMATERM_Type VT_BSTR
  432. #define SCHEMAUSAGE_Type VT_I4
  433. #define SERVERCURSOR_Type VT_BOOL
  434. #define SESS_AUTOCOMMITISOLEVELS_Type VT_I4
  435. #define SQLSUPPORT_Type VT_I4
  436. #define STRONGIDENTITY_Type VT_BOOL
  437. #define STRUCTUREDSTORAGE_Type VT_I4
  438. #define SUBQUERIES_Type VT_I4
  439. #define SUPPORTEDTXNDDL_Type VT_I4
  440. #define SUPPORTEDTXNISOLEVELS_Type VT_I4
  441. #define SUPPORTEDTXNISORETAIN_Type VT_I4
  442. #define TABLETERM_Type VT_BSTR
  443. #define TBL_TEMPTABLE_Type VT_BOOL
  444. #define TRANSACTEDOBJECT_Type VT_BOOL
  445. #define UPDATABILITY_Type VT_I4
  446. #define USERNAME_Type VT_BSTR
  447. #define ABORTPRESERVE_Value VARIANT_FALSE
  448. #define ACTIVESESSIONS_Value 0
  449. #define APPENDONLY_Value VARIANT_FALSE
  450. #define ASYNCTXNABORT_Value VARIANT_FALSE
  451. #define ASYNCTXNCOMMIT_Value VARIANT_FALSE
  452. #define AUTH_CACHE_AUTHINFO_Value VARIANT_FALSE
  453. #define AUTH_ENCRYPT_PASSWORD_Value VARIANT_FALSE
  454. #define AUTH_INTEGRATED_Value OLESTR("")
  455. #define AUTH_MASK_PASSWORD_Value VARIANT_FALSE
  456. #define AUTH_PASSWORD_Value OLESTR("")
  457. #define AUTH_PERSIST_ENCRYPTED_Value VARIANT_FALSE
  458. #define AUTH_PERSIST_SENSITIVE_AUTHINFO_Value VARIANT_FALSE
  459. #define AUTH_USERID_Value OLESTR("")
  460. #define BLOCKINGSTORAGEOBJECTS_Value VARIANT_FALSE
  461. #define BOOKMARKS_Value VARIANT_FALSE
  462. #define BOOKMARKSKIPPED_Value VARIANT_FALSE
  463. #define BOOKMARKTYPE_Value 0
  464. #define BYREFACCESSORS_Value VARIANT_FALSE
  465. #define CACHEDEFERRED_Value VARIANT_FALSE
  466. #define CANFETCHBACKWARDS_Value VARIANT_TRUE
  467. #define CANHOLDROWS_Value VARIANT_TRUE
  468. #define CANSCROLLBACKWARDS_Value VARIANT_TRUE
  469. #define CATALOGLOCATION_Value 0
  470. #define CATALOGTERM_Value OLESTR("")
  471. #define CATALOGUSAGE_Value 0
  472. #define CHANGEINSERTEDROWS_Value VARIANT_FALSE
  473. #define COL_AUTOINCREMENT_Value VARIANT_FALSE
  474. #define COL_DEFAULT_Value OLESTR("")
  475. #define COL_DESCRIPTION_Value OLESTR("")
  476. #define COL_FIXEDLENGTH_Value VARIANT_FALSE
  477. #define COL_NULLABLE_Value VARIANT_FALSE
  478. #define COL_PRIMARYKEY_Value VARIANT_FALSE
  479. #define COL_UNIQUE_Value VARIANT_FALSE
  480. #define COLUMNDEFINITION_Value 0
  481. #define COLUMNRESTRICT_Value VARIANT_FALSE
  482. #define COMMANDTIMEOUT_Value 0
  483. #define COMMITPRESERVE_Value VARIANT_FALSE
  484. #define CONCATNULLBEHAVIOR_Value 0
  485. #define CURRENTCATALOG_Value OLESTR("")
  486. #define DATASOURCENAME_Value OLESTR("")
  487. #define DATASOURCEREADONLY_Value VARIANT_TRUE
  488. #define DBMSNAME_Value OLESTR("")
  489. #define DBMSVER_Value OLESTR("")
  490. #define DEFERRED_Value VARIANT_FALSE
  491. #define DELAYSTORAGEOBJECTS_Value VARIANT_FALSE
  492. #define DSOTHREADMODEL_Value DBPROPVAL_RT_APTMTTHREAD
  493. #define GROUPBY_Value 0
  494. #define HETEROGENEOUSTABLES_Value 0
  495. #define IAccessor_Value VARIANT_TRUE
  496. #define IColumnsInfo_Value VARIANT_TRUE
  497. #define IColumnsRowset_Value VARIANT_FALSE
  498. #define IConnectionPointContainer_Value VARIANT_FALSE
  499. #define IConvertType_Value VARIANT_TRUE
  500. #define IRowset_Value VARIANT_TRUE
  501. #define IRowsetChange_Value VARIANT_FALSE
  502. #define IRowsetIdentity_Value VARIANT_TRUE
  503. #define IRowsetIndex_Value VARIANT_FALSE
  504. #define IRowsetInfo_Value VARIANT_TRUE
  505. #define IRowsetLocate_Value VARIANT_FALSE
  506. #define IRowsetResynch_Value VARIANT_FALSE
  507. #define IRowsetScroll_Value VARIANT_FALSE
  508. #define IRowsetUpdate_Value VARIANT_FALSE
  509. #define ISupportErrorInfo_Value VARIANT_FALSE
  510. #define ILockBytes_Value VARIANT_FALSE
  511. #define ISequentialStream_Value VARIANT_FALSE
  512. #define IStorage_Value VARIANT_FALSE
  513. #define IStream_Value VARIANT_FALSE
  514. #define IDENTIFIERCASE_Value 0
  515. #define IMMOBILEROWS_Value VARIANT_FALSE
  516. #define INDEX_AUTOUPDATE_Value VARIANT_FALSE
  517. #define INDEX_CLUSTERED_Value VARIANT_FALSE
  518. #define INDEX_FILLFACTOR_Value 0
  519. #define INDEX_INITIALSIZE_Value 0
  520. #define INDEX_NULLCOLLATION_Value 0
  521. #define INDEX_NULLS_Value 0
  522. #define INDEX_PRIMARYKEY_Value VARIANT_FALSE
  523. #define INDEX_SORTBOOKMARKS_Value VARIANT_FALSE
  524. #define INDEX_TEMPINDEX_Value VARIANT_FALSE
  525. #define INDEX_TYPE_Value 0
  526. #define INDEX_UNIQUE_Value VARIANT_FALSE
  527. #define INIT_DATASOURCE_Value OLESTR("")
  528. #define INIT_HWND_Value 0
  529. #define INIT_IMPERSONATION_LEVEL_Value 0
  530. #define INIT_LCID_Value 0
  531. #define INIT_LOCATION_Value OLESTR("")
  532. #define INIT_MODE_Value 0
  533. #define INIT_PROMPT_Value VT_I2
  534. #define INIT_PROTECTION_LEVEL_Value 0
  535. #define INIT_PROVIDERSTRING_Value OLESTR("")
  536. #define INIT_TIMEOUT_Value 0
  537. #define LITERALBOOKMARKS_Value VARIANT_FALSE
  538. #define LITERALIDENTITY_Value VARIANT_FALSE
  539. #define MAXINDEXSIZE_Value 0
  540. #define MAXOPENROWS_Value 0
  541. #define MAXPENDINGROWS_Value 0
  542. #define MAXROWS_Value 0
  543. #define MAXROWSIZE_Value 0
  544. #define MAXROWSIZEINCLUDESBLOB_Value VARIANT_FALSE
  545. #define MAXTABLESINSELECT_Value 0
  546. #define MAYWRITECOLUMN_Value VARIANT_FALSE
  547. #define MEMORYUSAGE_Value 0
  548. #define MULTIPLEPARAMSETS_Value VARIANT_FALSE
  549. #define MULTIPLERESULTS_Value 0
  550. #define MULTIPLESTORAGEOBJECTS_Value VARIANT_FALSE
  551. #define MULTITABLEUPDATE_Value VARIANT_FALSE
  552. #define NOTIFICATIONPHASES_Value 0
  553. #define NOTIFYCOLUMNSET_Value 0
  554. #define NOTIFYROWDELETE_Value 0
  555. #define NOTIFYROWFIRSTCHANGE_Value 0
  556. #define NOTIFYROWINSERT_Value 0
  557. #define NOTIFYROWRESYNCH_Value 0
  558. #define NOTIFYROWSETRELEASE_Value 0
  559. #define NOTIFYROWSETFETCHPOSITIONCHANGE_Value 0
  560. #define NOTIFYROWUNDOCHANGE_Value 0
  561. #define NOTIFYROWUNDODELETE_Value 0
  562. #define NOTIFYROWUNDOINSERT_Value 0
  563. #define NOTIFYROWUPDATE_Value 0
  564. #define NULLCOLLATION_Value 0
  565. #define OLEOBJECTS_Value 0
  566. #define ORDERBYCOLUMNSINSELECT_Value VARIANT_FALSE
  567. #define ORDEREDBOOKMARKS_Value VARIANT_FALSE
  568. #define OTHERINSERT_Value VARIANT_FALSE
  569. #define OTHERUPDATEDELETE_Value VARIANT_FALSE
  570. #define OUTPUTPARAMETERAVAILABILITY_Value 0
  571. #define OWNINSERT_Value VARIANT_FALSE
  572. #define OWNUPDATEDELETE_Value VARIANT_FALSE
  573. #define PERSISTENTIDTYPE_Value 0
  574. #define PREPAREABORTBEHAVIOR_Value 0
  575. #define PREPARECOMMITBEHAVIOR_Value 0
  576. #define PROCEDURETERM_Value OLESTR("")
  577. #define PROVIDERNAME_Value OLESTR("")
  578. #define PROVIDEROLEDBVER_Value OLESTR("2.0")
  579. #define PROVIDERVER_Value OLESTR("")
  580. #define QUICKRESTART_Value VARIANT_FALSE
  581. #define QUOTEDIDENTIFIERCASE_Value 0
  582. #define REENTRANTEVENTS_Value VARIANT_FALSE
  583. #define REMOVEDELETED_Value VARIANT_FALSE
  584. #define REPORTMULTIPLECHANGES_Value VARIANT_FALSE
  585. #define RETURNPENDINGINSERTS_Value VARIANT_FALSE
  586. #define ROWRESTRICT_Value VARIANT_FALSE
  587. #define ROWSETCONVERSIONSONCOMMAND_Value VARIANT_TRUE
  588. #define ROWTHREADMODEL_Value 0
  589. #define SCHEMATERM_Value OLESTR("")
  590. #define SCHEMAUSAGE_Value 0
  591. #define SERVERCURSOR_Value VARIANT_FALSE
  592. #define SESS_AUTOCOMMITISOLEVELS_Value 0
  593. #define SQLSUPPORT_Value 0
  594. #define STRONGIDENTITY_Value VARIANT_FALSE
  595. #define STRUCTUREDSTORAGE_Value 0
  596. #define SUBQUERIES_Value 0
  597. #define SUPPORTEDTXNDDL_Value 0
  598. #define SUPPORTEDTXNISOLEVELS_Value 0
  599. #define SUPPORTEDTXNISORETAIN_Value 0
  600. #define TABLETERM_Value OLESTR("")
  601. #define TBL_TEMPTABLE_Value VARIANT_FALSE
  602. #define TRANSACTEDOBJECT_Value VARIANT_FALSE
  603. #define UPDATABILITY_Value 0
  604. #define USERNAME_Value OLESTR("")
  605. #define OUT_OF_LINE virtual
  606. #define BEGIN_PROPSET_MAP(Class) \
  607. static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL)) \
  608. { \
  609. typedef Class _PropSetClass; \
  610. ULONG& cElemsMax = *pcElemPerSupported; \
  611. cElemsMax = 0; \
  612. int nCurProp = 0; \
  613. int cRemainder = 0; \
  614. cRemainder;
  615. #define BEGIN_PROPERTY_SET_EX(guid, flags) \
  616. if (pNumPropSets != NULL) \
  617. { \
  618. pSet[nCurProp].pPropSet = &guid; \
  619. pSet[nCurProp].dwFlags = flags; \
  620. } \
  621. static const UPROPINFO aProperty##guid[] = \
  622. {
  623. #define BEGIN_PROPERTY_SET(guid) BEGIN_PROPERTY_SET_EX(guid, 0)
  624. #define PROPERTY_INFO_ENTRY_EX(dwPropID, vt, dwFlags, value, options) DBPROP_##dwPropID, IDS_DBPROP_##dwPropID, vt, dwFlags, (DWORD_PTR)value, (DBPROPOPTIONS)options,
  625. #define PROPERTY_INFO_ENTRY_VALUE(dwPropID, value) PROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, ##dwPropID##_Flags, value, 0)
  626. #define PROPERTY_INFO_ENTRY(dwPropID) PROPERTY_INFO_ENTRY_VALUE(dwPropID, dwPropID##_Value)
  627. #define END_PROPERTY_SET(guid) \
  628. }; \
  629. if (pNumPropSets != NULL) \
  630. { \
  631. pSet[nCurProp].pUPropInfo = (UPROPINFO*)aProperty##guid; \
  632. pSet[nCurProp].cUPropInfo = sizeof(aProperty##guid) / sizeof(UPROPINFO); \
  633. cRemainder = (pSet[nCurProp].cUPropInfo % 32) ? 1 : 0; \
  634. if (cElemsMax < (pSet[nCurProp].cUPropInfo / 32 + cRemainder)) \
  635. { \
  636. cElemsMax = (pSet[nCurProp].cUPropInfo / 32 + cRemainder); \
  637. } \
  638. } \
  639. nCurProp++;
  640. #define CHAIN_PROPERTY_SET(ChainClass) \
  641. ULONG cPropSets##ChainClass, cElsSupported##ChainClass; \
  642. int cSets##ChainClass = (int)(DWORD_PTR)ChainClass::_GetPropSet(NULL, &cElsSupported##ChainClass); \
  643. if (pNumPropSets != NULL) \
  644. { \
  645. UPROPSET* pSetA = (UPROPSET*)_alloca(sizeof(UPROPSET)*cSets##ChainClass); \
  646. UPROPSET* pSetTemp = ChainClass::_GetPropSet(&cPropSets##ChainClass, &cElsSupported##ChainClass, pSetA); \
  647. cElemsMax = (cElemsMax < cElsSupported##ChainClass) ? cElsSupported##ChainClass : cElemsMax; \
  648. ATLASSERT(pSetTemp); \
  649. for (ULONG iSet = nCurProp; iSet < nCurProp+cPropSets##ChainClass; iSet++) \
  650. { \
  651. pSet[iSet].pPropSet = pSetTemp[iSet-nCurProp].pPropSet; \
  652. pSet[iSet].dwFlags = pSetTemp[iSet-nCurProp].dwFlags; \
  653. pSet[iSet].pUPropInfo = pSetTemp[iSet-nCurProp].pUPropInfo; \
  654. pSet[iSet].cUPropInfo = pSetTemp[iSet-nCurProp].cUPropInfo; \
  655. } \
  656. } \
  657. nCurProp += cSets##ChainClass;
  658. #define END_PROPSET_MAP() \
  659. if (pNumPropSets != NULL) \
  660. { \
  661. if (IsEqualGUID(*pguidSet, GUID_NULL)) \
  662. { \
  663. *pNumPropSets = nCurProp; \
  664. return pSet; \
  665. } \
  666. else \
  667. { \
  668. *pNumPropSets = 1; \
  669. UINT i = 0; \
  670. for (; i < sizeof(pSet)/sizeof(UPROPSET) && IsEqualGUID(*(pSet[i].pPropSet), *pguidSet); i++); \
  671. return (i == sizeof(pSet)/sizeof(UPROPSET)) ? &pSet[0] : &pSet[i]; \
  672. } \
  673. } \
  674. return (UPROPSET*)(DWORD_PTR)nCurProp; \
  675. }
  676. // For DataSource flags IDBInitialize::m_dwStatus
  677. enum DATASOURCE_FLAGS {
  678. DSF_MASK_INIT = 0xFFFFF00F, // Mask for stuff lasting over init/uninit.
  679. DSF_PERSIST_DIRTY = 0x00000001, // Set if init string changes.
  680. DSF_INITIALIZED = 0x00000010, // Have we been initialized.
  681. };
  682. #define DBID_USE_GUID_OR_PGUID(e) \
  683. ((1<<(e)) & \
  684. ( 1<<DBKIND_GUID \
  685. | 1<<DBKIND_GUID_NAME \
  686. | 1<<DBKIND_GUID_PROPID \
  687. | 1<<DBKIND_PGUID_NAME \
  688. | 1<<DBKIND_PGUID_PROPID ))
  689. #define DBID_USE_GUID(e) \
  690. ((1<<(e)) & \
  691. ( 1<<DBKIND_GUID \
  692. | 1<<DBKIND_GUID_NAME \
  693. | 1<<DBKIND_GUID_PROPID ))
  694. #define DBID_USE_PGUID(e) \
  695. ((1<<(e)) & \
  696. ( 1<<DBKIND_PGUID_NAME \
  697. | 1<<DBKIND_PGUID_PROPID ))
  698. #define DBID_USE_NAME(e) \
  699. ((1<<(e)) & \
  700. ( 1<<DBKIND_NAME \
  701. | 1<<DBKIND_GUID_NAME \
  702. | 1<<DBKIND_PGUID_NAME ))
  703. #define DBID_USE_PROPID(e) \
  704. ((1<<(e)) & \
  705. ( 1<<DBKIND_PROPID \
  706. | 1<<DBKIND_GUID_PROPID \
  707. | 1<<DBKIND_PGUID_PROPID ))
  708. // Bookmark can be either guid or pguid.
  709. #define DBID_IS_BOOKMARK(dbid) \
  710. ( DBID_USE_GUID(dbid.eKind) && dbid.uGuid.guid == DBCOL_SPECIALCOL \
  711. || DBID_USE_PGUID(dbid.eKind) && *dbid.uGuid.pguid == DBCOL_SPECIALCOL )
  712. #define DivDword(dw) (dw >> 5) // dw / 32 = dw / (sizeof(DWORD)*8)
  713. #define ModDword(dw) (dw & (32-1)) // dw % 32
  714. #define DwordSizeofBits(nBits) (nBits/32+1) // Use in array declarations
  715. #define CLEARBITARRAY( rgdwFlags ) memset( rgdwFlags, 0, sizeof(rgdwFlags) )
  716. template <class T>
  717. BOOL InRange(T& val, T& valMin, T& valMax)
  718. {
  719. return ( valMin <= val && val <= valMax );
  720. }
  721. // Implementation Class
  722. class CBitFieldOps
  723. {
  724. public:
  725. void SETBIT( DWORD rgdwFlags[], const DWORD dwBit )
  726. {
  727. rgdwFlags[DivDword(dwBit)] |= 1 << ModDword(dwBit);
  728. }
  729. void CLEARBIT( DWORD rgdwFlags[], const DWORD dwBit )
  730. {
  731. rgdwFlags[DivDword(dwBit)] &= ~( 1 << ModDword(dwBit) );
  732. }
  733. DWORD TESTBIT( const DWORD rgdwFlags[], const DWORD dwBit )
  734. {
  735. //old//Note: Not {0,1}, but from {0...2^32-1}.
  736. // Note: Now returns {0,1}.
  737. return ( rgdwFlags[DivDword(dwBit)] & ( 1 << ModDword(dwBit) ) ) != 0;
  738. }
  739. };
  740. // Implementation Class
  741. class CDBIDOps
  742. {
  743. public:
  744. HRESULT CompareDBIDs(const DBID* pdbid1, const DBID* pdbid2)
  745. {
  746. // Array of valid eKind matches, in addition to matching exactly.
  747. static BYTE s_rgbKind[] =
  748. {
  749. DBKIND_PGUID_NAME, // DBKIND_GUID_NAME
  750. DBKIND_PGUID_PROPID, // DBKIND_GUID_PROPID
  751. DBKIND_NAME, // DBKIND_NAME
  752. DBKIND_GUID_NAME, // DBKIND_PGUID_NAME
  753. DBKIND_GUID_PROPID, // DBKIND_PGUID_PROPID
  754. DBKIND_PROPID, // DBKIND_PROPID
  755. DBKIND_GUID // DBKIND_GUID
  756. };
  757. if( !pdbid1 || !pdbid2 )
  758. return S_FALSE;
  759. // Assume a match, and discard early if we can.
  760. if (!InRange(pdbid2->eKind, (DWORD)0, (DWORD)(sizeof(s_rgbKind)/sizeof(*s_rgbKind))))
  761. {
  762. ATLTRACE2(atlTraceDBProvider, 0, "Column ID out of Range\n");
  763. return E_FAIL;
  764. }
  765. if (pdbid1->eKind != pdbid2->eKind
  766. && pdbid1->eKind != s_rgbKind[pdbid2->eKind])
  767. return S_FALSE;
  768. if (DBID_USE_GUID_OR_PGUID(pdbid1->eKind))
  769. {
  770. if (!DBID_USE_GUID_OR_PGUID(pdbid2->eKind))
  771. return S_FALSE;
  772. // Compare GUIDs.
  773. // Note that _GUID_ is equivalent to _PGUID_.
  774. if (!InlineIsEqualGUID(
  775. DBID_USE_PGUID(pdbid1->eKind) ? *(pdbid1->uGuid.pguid) : pdbid1->uGuid.guid,
  776. DBID_USE_PGUID(pdbid2->eKind) ? *(pdbid2->uGuid.pguid) : pdbid2->uGuid.guid ))
  777. return S_FALSE;
  778. }
  779. if (DBID_USE_NAME(pdbid1->eKind))
  780. {
  781. if (!DBID_USE_NAME(pdbid2->eKind))
  782. return S_FALSE;
  783. // Compare names.
  784. // Need to check if 1 is null and the other is not.
  785. if ( ((pdbid1->uName.pwszName == NULL) &&
  786. (pdbid2->uName.pwszName != NULL)) ||
  787. ((pdbid1->uName.pwszName != NULL) &&
  788. (pdbid2->uName.pwszName == NULL)) )
  789. return S_FALSE;
  790. // Since the above check does not rule out both being null, which is
  791. // a valid comparison, and wcscmp will GPF if they were, we need
  792. // to check for valid pointers
  793. if( pdbid1->uName.pwszName && pdbid2->uName.pwszName )
  794. {
  795. // Assume null-terminated.
  796. // Assume LCID match is OK (note diff with lstrcmp(), CompareString().)
  797. if (wcscmp(pdbid1->uName.pwszName, pdbid2->uName.pwszName) != 0)
  798. return S_FALSE;
  799. }
  800. }
  801. if (DBID_USE_PROPID(pdbid1->eKind))
  802. {
  803. if (!DBID_USE_PROPID(pdbid2->eKind))
  804. return S_FALSE;
  805. // Compare PROPID.
  806. if (pdbid1->uName.ulPropid != pdbid2->uName.ulPropid)
  807. return S_FALSE;
  808. }
  809. // No reason to discard, so must have matched each field successfully.
  810. return S_OK;
  811. }
  812. static HRESULT IsValidDBID(const DBID* pdbid1)
  813. {
  814. ATLASSERT( pdbid1 );
  815. if( pdbid1 &&
  816. ((pdbid1->eKind == DBKIND_GUID_NAME) ||
  817. (pdbid1->eKind == DBKIND_GUID_PROPID) ||
  818. (pdbid1->eKind == DBKIND_NAME) ||
  819. (pdbid1->eKind == DBKIND_PGUID_NAME) ||
  820. (pdbid1->eKind == DBKIND_PGUID_PROPID) ||
  821. (pdbid1->eKind == DBKIND_PROPID) ||
  822. (pdbid1->eKind == DBKIND_GUID)) )
  823. return S_OK;
  824. else
  825. return S_FALSE;
  826. }
  827. HRESULT CopyDBIDs(DBID* pdbidDest, const DBID* pdbidSrc)
  828. {
  829. size_t cwchBuffer;
  830. ATLASSERT( pdbidDest || pdbidSrc );
  831. if( !pdbidDest || !pdbidSrc )
  832. return S_FALSE;
  833. // Save eKind
  834. pdbidDest->eKind = pdbidSrc->eKind;
  835. switch( pdbidSrc->eKind )
  836. {
  837. case DBKIND_GUID_NAME:
  838. pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
  839. cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
  840. cwchBuffer++;
  841. pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
  842. if( pdbidDest->uName.pwszName )
  843. memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
  844. else
  845. return E_OUTOFMEMORY;
  846. break;
  847. case DBKIND_GUID_PROPID:
  848. pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
  849. pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
  850. break;
  851. case DBKIND_NAME:
  852. cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
  853. cwchBuffer++;
  854. pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
  855. if( pdbidDest->uName.pwszName )
  856. memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
  857. else
  858. return E_OUTOFMEMORY;
  859. break;
  860. case DBKIND_PGUID_NAME:
  861. pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID));
  862. if( pdbidDest->uGuid.pguid )
  863. {
  864. *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid);
  865. cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
  866. cwchBuffer++;
  867. pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
  868. if( pdbidDest->uName.pwszName )
  869. {
  870. memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
  871. break;
  872. }
  873. else
  874. {
  875. CoTaskMemFree(pdbidDest->uGuid.pguid);
  876. pdbidDest->uGuid.pguid = NULL;
  877. }
  878. }
  879. return E_OUTOFMEMORY;
  880. case DBKIND_PGUID_PROPID:
  881. pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID));
  882. if( pdbidDest->uGuid.pguid )
  883. *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid);
  884. else
  885. return E_OUTOFMEMORY;
  886. pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
  887. break;
  888. case DBKIND_PROPID:
  889. pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
  890. break;
  891. case DBKIND_GUID:
  892. pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
  893. break;
  894. default:
  895. ATLASSERT(L"Unhandled dbid1.ekind");
  896. return S_FALSE;
  897. }
  898. return S_OK;
  899. }
  900. static GUID* GetDBIDpGuid(DBID& dbid)
  901. {
  902. GUID* pGuid;
  903. switch (dbid.eKind)
  904. {
  905. case DBKIND_PGUID_NAME:
  906. case DBKIND_PGUID_PROPID:
  907. pGuid = dbid.uGuid.pguid;
  908. break;
  909. case DBKIND_GUID_NAME:
  910. case DBKIND_GUID_PROPID:
  911. case DBKIND_GUID:
  912. pGuid = &(dbid.uGuid.guid);
  913. break;
  914. default:
  915. pGuid = NULL;
  916. }
  917. return pGuid;
  918. }
  919. static ULONG GetPropIDFromDBID(DBID& dbid)
  920. {
  921. switch (dbid.eKind)
  922. {
  923. case DBKIND_GUID_PROPID:
  924. case DBKIND_PGUID_PROPID:
  925. case DBKIND_PROPID:
  926. return dbid.uName.ulPropid;
  927. default:
  928. return 0;
  929. }
  930. }
  931. void FreeDBIDs(DBID* pdbidSrc)
  932. {
  933. switch( pdbidSrc->eKind )
  934. {
  935. case DBKIND_GUID_NAME:
  936. CoTaskMemFree(pdbidSrc->uName.pwszName);
  937. break;
  938. case DBKIND_NAME:
  939. CoTaskMemFree(pdbidSrc->uName.pwszName);
  940. break;
  941. case DBKIND_PGUID_NAME:
  942. CoTaskMemFree(pdbidSrc->uGuid.pguid);
  943. CoTaskMemFree(pdbidSrc->uName.pwszName);
  944. break;
  945. case DBKIND_PGUID_PROPID:
  946. CoTaskMemFree(pdbidSrc->uGuid.pguid);
  947. break;
  948. case DBKIND_GUID_PROPID:
  949. case DBKIND_PROPID:
  950. case DBKIND_GUID:
  951. break;
  952. default:
  953. ATLASSERT(L"Unhandled dbid1.ekind");
  954. break;
  955. }
  956. }
  957. };
  958. extern "C" const CLSID CLSID_DataConvert;
  959. class CConvertHelper
  960. {
  961. public:
  962. CConvertHelper() {}
  963. HRESULT FinalConstruct()
  964. {
  965. HRESULT hr = ::CoCreateInstance(CLSID_DataConvert, NULL, CLSCTX_INPROC_SERVER, IID_IDataConvert, (void**)&m_spConvert);
  966. if (FAILED(hr))
  967. return hr;
  968. // Check to see if the data conversion routine is 2.0 capable, if so. Initialize
  969. // the conversion routine to be 2.0.
  970. DCINFO rgInfo[] = {{DCINFOTYPE_VERSION, {VT_UI4, 0, 0, 0, 0x0}}};
  971. CComPtr<IDCInfo> spIDCInfo;
  972. hr = m_spConvert->QueryInterface(&spIDCInfo);
  973. if (hr == S_OK)
  974. {
  975. V_UI4(&rgInfo->vData) = 0x200; // OLEDB Version 02.00
  976. spIDCInfo->SetInfo(1, rgInfo);
  977. }
  978. return hr;
  979. }
  980. CComPtr<IDataConvert> m_spConvert;
  981. };
  982. // IDBCreateSessionImpl
  983. template <class T, class SessionClass>
  984. class ATL_NO_VTABLE IDBCreateSessionImpl : public IDBCreateSession
  985. {
  986. public:
  987. STDMETHOD(CreateSession)(IUnknown *pUnkOuter,
  988. REFIID riid,
  989. IUnknown **ppDBSession)
  990. {
  991. ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession\n");
  992. if (ppDBSession == NULL)
  993. return E_INVALIDARG;
  994. T* pT = (T*)this;
  995. if (!(pT->m_dwStatus & DSF_INITIALIZED))
  996. {
  997. ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession : Error not initialized\n");
  998. *ppDBSession = NULL;
  999. return E_UNEXPECTED;
  1000. }
  1001. CComPolyObject<SessionClass> *pSession;
  1002. // You can't QI for an interface other than IUnknown when aggregating
  1003. // and creating the object. You might ask for your own interface,
  1004. // which would be bad. Note, we return DB_E_NOAGGREGATION instead of
  1005. // CLASS_E_NOAGGREGATION due to OLE DB constraints.
  1006. if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid))
  1007. return DB_E_NOAGGREGATION;
  1008. HRESULT hr = CComPolyObject<SessionClass>::CreateInstance(pUnkOuter, &pSession);
  1009. if (SUCCEEDED(hr))
  1010. {
  1011. CComPtr<IObjectWithSite> spCreator;
  1012. hr = pSession->QueryInterface(IID_IObjectWithSite, (void**)&spCreator);
  1013. if (SUCCEEDED(hr))
  1014. {
  1015. spCreator->SetSite(this);
  1016. hr = pSession->QueryInterface(riid, (void**)ppDBSession);
  1017. }
  1018. else
  1019. delete pSession;
  1020. }
  1021. return hr;
  1022. }
  1023. };
  1024. // IDBInitializeImpl
  1025. template <class T>
  1026. class ATL_NO_VTABLE IDBInitializeImpl : public IDBInitialize
  1027. {
  1028. public:
  1029. IDBInitializeImpl()
  1030. {
  1031. m_dwStatus = 0;
  1032. m_pCUtlPropInfo = NULL;
  1033. m_cSessionsOpen = 0;
  1034. }
  1035. ~IDBInitializeImpl()
  1036. {
  1037. delete m_pCUtlPropInfo;
  1038. }
  1039. STDMETHOD(Uninitialize)(void)
  1040. {
  1041. ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Uninitialize\n");
  1042. T* pT = (T*)this;
  1043. pT->Lock();
  1044. if (pT->m_cSessionsOpen != 0)
  1045. {
  1046. ATLTRACE2(atlTraceDBProvider, 0, "Uninitialized called with Open Sessions\n");
  1047. return DB_E_OBJECTOPEN;
  1048. }
  1049. delete m_pCUtlPropInfo;
  1050. m_pCUtlPropInfo = NULL;
  1051. pT->m_dwStatus |= DSF_PERSIST_DIRTY;
  1052. pT->m_dwStatus &= DSF_MASK_INIT; // Clear all non-init flags.
  1053. pT->Unlock();
  1054. return S_OK;
  1055. }
  1056. LONG m_cSessionsOpen;
  1057. DWORD m_dwStatus;
  1058. CUtlPropInfo<T>* m_pCUtlPropInfo;
  1059. STDMETHOD(Initialize)(void)
  1060. {
  1061. ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize\n");
  1062. T *pT = (T*)(this);
  1063. T::ObjectLock lock(pT);
  1064. HRESULT hr;
  1065. if (pT->m_dwStatus & DSF_INITIALIZED)
  1066. {
  1067. ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : Already Initialized\n");
  1068. return DB_E_ALREADYINITIALIZED;
  1069. }
  1070. delete m_pCUtlPropInfo;
  1071. m_pCUtlPropInfo = NULL;
  1072. ATLTRY(m_pCUtlPropInfo = new CUtlPropInfo<T>())
  1073. if (m_pCUtlPropInfo == NULL)
  1074. {
  1075. ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : OOM\n");
  1076. return E_OUTOFMEMORY;
  1077. }
  1078. hr = m_pCUtlPropInfo->FInit();
  1079. if (hr == S_OK)
  1080. {
  1081. pT->m_dwStatus |= DSF_INITIALIZED;
  1082. }
  1083. else
  1084. {
  1085. delete m_pCUtlPropInfo;
  1086. m_pCUtlPropInfo = NULL;
  1087. }
  1088. return hr;
  1089. }
  1090. };
  1091. // Implementation Class
  1092. class CPropColID :
  1093. public PROPCOLID,
  1094. public CDBIDOps
  1095. {
  1096. public:
  1097. CPropColID()
  1098. {
  1099. VariantInit(&vValue);
  1100. }
  1101. ~CPropColID()
  1102. {
  1103. FreeDBIDs(&dbidProperty);
  1104. VariantClear(&vValue);
  1105. }
  1106. bool operator==(const CPropColID& colId)
  1107. {
  1108. return (CompareDBIDs(&dbidProperty, &(colId.dbidProperty)) == S_OK) ? true : false;
  1109. }
  1110. };
  1111. class CColumnIds :
  1112. public CDBIDOps,
  1113. public CSimpleArray<CPropColID>
  1114. {
  1115. public:
  1116. PPROPCOLID AddNode()
  1117. {
  1118. CPropColID colID;
  1119. if (Add(colID))
  1120. return &(m_aT[GetSize()]);
  1121. return NULL;
  1122. }
  1123. HRESULT RemoveColumnId(const DBID* pdbidProp)
  1124. {
  1125. for (int i = 0; i < GetSize(); i++)
  1126. {
  1127. if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
  1128. return (RemoveAt(i)) ? S_OK : E_FAIL;
  1129. }
  1130. return E_FAIL;
  1131. }
  1132. HRESULT AddColumnId(DBPROP* pProp)
  1133. {
  1134. CPropColID colID;
  1135. HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pProp->colid));
  1136. if(FAILED(hr))
  1137. return hr;
  1138. colID.dwOption = pProp->dwOptions;
  1139. hr = VariantCopy(&(colID.vValue),&(pProp->vValue));
  1140. if(FAILED(hr))
  1141. return hr;
  1142. return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
  1143. }
  1144. HRESULT AddColumnId(PPROPCOLID pPropNode)
  1145. {
  1146. CPropColID colID;
  1147. HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pPropNode->dbidProperty));
  1148. if(FAILED(hr))
  1149. return hr;
  1150. colID.dwOption = pPropNode->dwOption;
  1151. hr = VariantCopy(&(colID.vValue),&(pPropNode->vValue));
  1152. if(FAILED(hr))
  1153. return hr;
  1154. return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
  1155. }
  1156. ULONG GetCountOfPropColids(){ return (ULONG)GetSize();}
  1157. PPROPCOLID FindColumnId(const DBID* pdbidProp)
  1158. {
  1159. for (int i = 0; i < GetSize(); i++)
  1160. {
  1161. if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
  1162. return &(m_aT[i]);
  1163. }
  1164. return NULL;
  1165. }
  1166. HRESULT GetValue(int iColId, DWORD* pdwOptions, DBID* pColid, VARIANT* pvValue)
  1167. {
  1168. HRESULT hr;
  1169. ATLASSERT(pdwOptions && pColid && pvValue);
  1170. ATLASSERT(iColId >= 0 && iColId < m_nSize);
  1171. CPropColID& colId = m_aT[iColId];
  1172. *pdwOptions = colId.dwOption;
  1173. CopyDBIDs( pColid, &(colId.dbidProperty) );
  1174. if(FAILED(hr = VariantCopy(pvValue, &(colId.vValue))))
  1175. return hr;
  1176. return S_OK;
  1177. }
  1178. };
  1179. const ULONG cchDescBuffSize = 256;
  1180. const DWORD DBINTERNFLAGS_CHANGED = 0x00000001;
  1181. // Rules for GetPropertiesArgChk
  1182. const DWORD ARGCHK_PROPERTIESINERROR = 0x00000001;
  1183. // Implementation Class
  1184. template <class T>
  1185. class CUtlPropInfo : public CBitFieldOps, public CDBIDOps
  1186. {
  1187. public:
  1188. enum EnumGetPropInfo
  1189. {
  1190. GETPROPINFO_ALLPROPIDS = 0x0001,
  1191. GETPROPINFO_NOTSUPPORTED = 0x0002,
  1192. GETPROPINFO_ERRORSOCCURRED = 0x0004,
  1193. GETPROPINFO_VALIDPROP = 0x0008
  1194. };
  1195. CUtlPropInfo()
  1196. {
  1197. m_cUPropSet = 0;
  1198. m_pUPropSet = NULL;
  1199. m_cPropSetDex = 0;
  1200. m_rgiPropSetDex = NULL;
  1201. m_cElemPerSupported = 0;
  1202. m_rgdwSupported = NULL;
  1203. }
  1204. ~CUtlPropInfo()
  1205. {
  1206. delete[] m_rgiPropSetDex;
  1207. delete[] m_rgdwSupported;
  1208. if (m_pUPropSet != NULL)
  1209. CoTaskMemFree(m_pUPropSet);
  1210. }
  1211. //Determine the number of description buffers needed
  1212. ULONG CalcDescripBuffers(ULONG cPropInfoSet, DBPROPINFOSET* pPropInfoSet)
  1213. {
  1214. ULONG cBuffers = 0;
  1215. ATLASSERT(m_pUPropSet);
  1216. ATLASSERT(cPropInfoSet && pPropInfoSet);
  1217. for(ULONG ulSet=0; ulSet<cPropInfoSet; ulSet++)
  1218. {
  1219. if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
  1220. {
  1221. for(ULONG ul=0; ul<m_cPropSetDex; ul++)
  1222. {
  1223. cBuffers += m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo;
  1224. }
  1225. }
  1226. }
  1227. return cBuffers;
  1228. }
  1229. //Retrieve the property set indexes that match this property set.
  1230. HRESULT GetPropertySetIndex(const GUID* pPropertySet)
  1231. {
  1232. DWORD dwFlag = 0;
  1233. ULONG ulSet;
  1234. ATLASSERT(m_cUPropSet && m_pUPropSet);
  1235. ATLASSERT(m_rgiPropSetDex);
  1236. ATLASSERT(pPropertySet);
  1237. m_cPropSetDex = 0;
  1238. if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEALL))
  1239. {
  1240. dwFlag = DBPROPFLAGS_DATASOURCE;
  1241. }
  1242. else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEINFOALL))
  1243. {
  1244. dwFlag = DBPROPFLAGS_DATASOURCEINFO;
  1245. }
  1246. else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_ROWSETALL))
  1247. {
  1248. dwFlag = DBPROPFLAGS_ROWSET;
  1249. }
  1250. else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_DBINITALL))
  1251. {
  1252. dwFlag = DBPROPFLAGS_DBINIT;
  1253. }
  1254. else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_SESSIONALL))
  1255. {
  1256. dwFlag = DBPROPFLAGS_SESSION;
  1257. }
  1258. else // No scan required, just look for match.
  1259. {
  1260. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  1261. {
  1262. if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
  1263. {
  1264. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  1265. m_cPropSetDex++;
  1266. break;
  1267. }
  1268. }
  1269. goto EXIT;
  1270. }
  1271. // Scan through the property sets looking for matching attributes
  1272. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  1273. {
  1274. if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
  1275. {
  1276. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  1277. m_cPropSetDex++;
  1278. }
  1279. }
  1280. EXIT:
  1281. return (m_cPropSetDex) ? S_OK : S_FALSE;
  1282. }
  1283. //Retrieve the property id pointer
  1284. HRESULT GetUPropInfoPtr(ULONG iPropSetDex, DBPROPID dwPropertyId, UPROPINFO** ppUPropInfo)
  1285. {
  1286. // Scan through the property sets looking for matching attributes
  1287. for(ULONG ulProps=0; ulProps<m_pUPropSet[iPropSetDex].cUPropInfo; ulProps++)
  1288. {
  1289. if( m_pUPropSet[iPropSetDex].pUPropInfo[ulProps].dwPropId == dwPropertyId )
  1290. {
  1291. *ppUPropInfo = &(m_pUPropSet[iPropSetDex].pUPropInfo[ulProps]);
  1292. // Test to see if the property is supported for this
  1293. // instantiation
  1294. return (TESTBIT(&(m_rgdwSupported[iPropSetDex * m_cElemPerSupported]), ulProps)) ? S_OK : S_FALSE;
  1295. }
  1296. }
  1297. return S_FALSE;
  1298. }
  1299. HRESULT FInit(GUID* pguidSet = (GUID*)&GUID_NULL)
  1300. {
  1301. HRESULT hr;
  1302. hr = InitAvailUPropSets(&m_cUPropSet, &m_pUPropSet, &m_cElemPerSupported, pguidSet);
  1303. if (FAILED(hr))
  1304. return hr;
  1305. ATLASSERT((m_cUPropSet != 0) && (m_cElemPerSupported != 0));
  1306. if(!m_cUPropSet || !m_cElemPerSupported)
  1307. return E_FAIL;
  1308. ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  1309. if(m_rgdwSupported == NULL)
  1310. return E_OUTOFMEMORY;
  1311. if(FAILED(hr = InitUPropSetsSupported()))
  1312. {
  1313. delete[] m_rgdwSupported;
  1314. m_rgdwSupported = NULL;
  1315. return hr;
  1316. }
  1317. if(m_cUPropSet)
  1318. {
  1319. ATLTRY(m_rgiPropSetDex = new ULONG[m_cUPropSet])
  1320. if(m_rgiPropSetDex == NULL)
  1321. {
  1322. delete [] m_rgdwSupported;
  1323. return E_OUTOFMEMORY;
  1324. }
  1325. }
  1326. return S_OK;
  1327. }
  1328. HRESULT GetPropertyInfo(ULONG cPropertySets,
  1329. const DBPROPIDSET rgPropertySets[], ULONG* pcPropertyInfoSets,
  1330. DBPROPINFOSET** prgPropertyInfoSets,
  1331. WCHAR** ppDescBuffer, bool bInitialized = true,
  1332. const GUID* pGuid = NULL)
  1333. {
  1334. HRESULT hr = S_OK;
  1335. ULONG ul, ulSet, ulNext, ulEnd;
  1336. ULONG ulOutIndex;
  1337. ULONG cSets;
  1338. ULONG cPropInfos;
  1339. ULONG ulIndex = 0;
  1340. DWORD dwStatus = 0;
  1341. DBPROPINFO* pPropInfo = NULL;
  1342. DBPROPINFO* pCurPropInfo = NULL;
  1343. WCHAR* pDescBuffer = NULL;
  1344. DBPROPINFOSET* pPropInfoSet = NULL;
  1345. UPROPINFO* pUPropInfo = NULL;
  1346. WCHAR wszBuff[256];
  1347. int cch;
  1348. // If the consumer does not restrict the property sets
  1349. // by specify an array of property sets and a cPropertySets
  1350. // greater than 0, then we need to make sure we
  1351. // have some to return
  1352. if(cPropertySets == 0)
  1353. {
  1354. // Determine the number of property sets supported
  1355. // In this case, it usually the enumerator or data source asking for
  1356. // DBPROPSET_DBINIT information.
  1357. if (pGuid != NULL)
  1358. cSets = 1;
  1359. else
  1360. cSets = m_cUPropSet;
  1361. }
  1362. else
  1363. {
  1364. cSets = 0;
  1365. // Determine number of property sets required
  1366. // This is only required when any of the "special" property set GUIDs were specified
  1367. for(ulSet=0; ulSet<cPropertySets; ulSet++)
  1368. {
  1369. if (GetPropertySetIndex(&(rgPropertySets[ulSet].guidPropertySet)) == S_OK)
  1370. cSets += m_cPropSetDex;
  1371. else
  1372. cSets++;
  1373. }
  1374. }
  1375. ATLASSERT(cSets);
  1376. // Allocate the DBPROPINFOSET structures
  1377. pPropInfoSet = (DBPROPINFOSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPINFOSET));
  1378. if(pPropInfoSet == NULL)
  1379. {
  1380. ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
  1381. hr = E_OUTOFMEMORY;
  1382. goto EXIT;
  1383. }
  1384. memset(pPropInfoSet, 0, cSets * sizeof(DBPROPINFOSET));
  1385. ulOutIndex = 0;
  1386. // VC 6.0 ulEnd = cPropertySets == 0 ? cSets : cPropertySets;
  1387. ulEnd = cSets; // VC 6.0 SP3
  1388. // Fill in the output array
  1389. for(ulSet=0; ulSet<ulEnd; ulSet++)
  1390. {
  1391. // Depending of if Property sets are specified store the
  1392. // return property set.
  1393. if (cPropertySets == 0)
  1394. {
  1395. if (pGuid != NULL)
  1396. {
  1397. GUID const& guidSet = *pGuid;
  1398. if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) ||
  1399. InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) ||
  1400. InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) ||
  1401. InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) ||
  1402. InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) &&
  1403. GetPropertySetIndex(&guidSet) == S_OK )
  1404. {
  1405. for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++)
  1406. {
  1407. pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet);
  1408. pPropInfoSet[ulOutIndex].cPropertyInfos = 0;
  1409. ulIndex = m_rgiPropSetDex[ul];
  1410. }
  1411. }
  1412. else
  1413. {
  1414. for (ULONG l=0; l<m_cUPropSet; l++)
  1415. {
  1416. if (InlineIsEqualGUID(*m_pUPropSet[l].pPropSet, *pGuid))
  1417. ulIndex = l;
  1418. }
  1419. if (l == m_cUPropSet)
  1420. {
  1421. ATLTRACE2(atlTraceDBProvider, 0, "Property Info Set not supported");
  1422. ulIndex = 0;
  1423. }
  1424. pPropInfoSet[ulSet].guidPropertySet = *pGuid;
  1425. }
  1426. }
  1427. else
  1428. {
  1429. pPropInfoSet[ulSet].guidPropertySet = *(m_pUPropSet[ulSet].pPropSet);
  1430. }
  1431. }
  1432. else
  1433. {
  1434. GUID const& guidSet = rgPropertySets[ulSet].guidPropertySet;
  1435. if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) ||
  1436. InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) ||
  1437. InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) ||
  1438. InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) ||
  1439. InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) &&
  1440. GetPropertySetIndex(&guidSet) == S_OK )
  1441. {
  1442. for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++)
  1443. {
  1444. pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet);
  1445. pPropInfoSet[ulOutIndex].cPropertyInfos = 0;
  1446. }
  1447. }
  1448. else
  1449. {
  1450. // Handle non-category property sets
  1451. // Handle unknown property sets
  1452. pPropInfoSet[ulOutIndex].guidPropertySet = guidSet;
  1453. pPropInfoSet[ulOutIndex].cPropertyInfos = rgPropertySets[ulSet].cPropertyIDs;
  1454. ulOutIndex++;
  1455. }
  1456. }
  1457. }
  1458. // Allocate a Description Buffer if needed
  1459. if( ppDescBuffer )
  1460. {
  1461. ULONG cBuffers = CalcDescripBuffers(cSets, pPropInfoSet);
  1462. if( cBuffers != 0 )
  1463. {
  1464. pDescBuffer = (WCHAR*)CoTaskMemAlloc(cBuffers * cchDescBuffSize * sizeof(WCHAR));
  1465. if(pDescBuffer == NULL)
  1466. {
  1467. hr = E_OUTOFMEMORY;
  1468. goto EXIT;
  1469. }
  1470. *ppDescBuffer = pDescBuffer;
  1471. memset(pDescBuffer, 0, (cBuffers * cchDescBuffSize * sizeof(WCHAR)));
  1472. }
  1473. }
  1474. // Process requested or derived Property sets
  1475. dwStatus = 0;
  1476. for(ulSet=0; ulSet<cSets; ulSet++)
  1477. {
  1478. ulNext=0;
  1479. cPropInfos = 0;
  1480. pPropInfo = NULL;
  1481. dwStatus &= (GETPROPINFO_ERRORSOCCURRED | GETPROPINFO_VALIDPROP);
  1482. // Calculate the number of property nodes needed for this
  1483. // property set.
  1484. if( cPropertySets == 0 )
  1485. {
  1486. ULONG ulTempSet;
  1487. if (pGuid != NULL)
  1488. ulTempSet = ulIndex;
  1489. else
  1490. ulTempSet = ulSet;
  1491. cPropInfos = m_pUPropSet[ulTempSet].cUPropInfo;
  1492. dwStatus |= GETPROPINFO_ALLPROPIDS;
  1493. m_rgiPropSetDex[0] = ulTempSet;
  1494. m_cPropSetDex = 1;
  1495. }
  1496. else
  1497. {
  1498. // If the count of PROPIDs is 0 (NOTE: the above routine already determined
  1499. // if it belonged to a category and if so set the count of properties to 0 for
  1500. // each propset in that category.
  1501. if( pPropInfoSet[ulSet].cPropertyInfos == 0 )
  1502. {
  1503. dwStatus |= GETPROPINFO_ALLPROPIDS;
  1504. // We have to determine if the property set is supported and if so
  1505. // the count of properties in the set.
  1506. if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
  1507. {
  1508. ATLASSERT( m_cPropSetDex == 1 );
  1509. cPropInfos += m_pUPropSet[m_rgiPropSetDex[0]].cUPropInfo;
  1510. }
  1511. else
  1512. {
  1513. // Not Supported
  1514. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1515. goto NEXT_SET;
  1516. }
  1517. }
  1518. else
  1519. {
  1520. // We also handle the case here where the user has requested
  1521. // a non-initialization group property info set while the
  1522. // provider is not initialized. In this case, properties should
  1523. // not be set.
  1524. cPropInfos = pPropInfoSet[ulSet].cPropertyInfos;
  1525. if( (GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_FALSE)
  1526. || (!bInitialized &&
  1527. !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINIT)) &&
  1528. !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINITALL))))
  1529. {
  1530. dwStatus |= GETPROPINFO_NOTSUPPORTED;
  1531. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1532. }
  1533. }
  1534. }
  1535. // Allocate DBPROP array
  1536. ATLASSERT( cPropInfos != 0 );
  1537. pPropInfo = (DBPROPINFO*)CoTaskMemAlloc(cPropInfos * sizeof(DBPROPINFO));
  1538. if( pPropInfo )
  1539. {
  1540. // Initialize Buffer
  1541. memset(pPropInfo, 0, cPropInfos * sizeof(DBPROPINFO));
  1542. for(ULONG ulProp=0; ulProp<cPropInfos; ulProp++)
  1543. {
  1544. VariantInit(&(pPropInfo[ulProp].vValues));
  1545. if( dwStatus & GETPROPINFO_NOTSUPPORTED )
  1546. {
  1547. // Not supported, thus we need to mark all as NOT_SUPPORTED
  1548. pPropInfo[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  1549. pPropInfo[ulProp].dwFlags = DBPROPFLAGS_NOTSUPPORTED;
  1550. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1551. }
  1552. }
  1553. // Make sure we support the property set
  1554. if( dwStatus & GETPROPINFO_NOTSUPPORTED )
  1555. {
  1556. ulNext = cPropInfos;
  1557. goto NEXT_SET;
  1558. }
  1559. // Retrieve the property information for this property set
  1560. for(ul=0; ul<m_cPropSetDex; ul++)
  1561. {
  1562. pUPropInfo = (m_pUPropSet[m_rgiPropSetDex[ul]].pUPropInfo);
  1563. ATLASSERT( pUPropInfo );
  1564. // Retrieve current value of properties
  1565. if( dwStatus & GETPROPINFO_ALLPROPIDS )
  1566. {
  1567. for(ulProp=0; ulProp<m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo; ulProp++)
  1568. {
  1569. // Verify property is supported, if not do not return
  1570. if( !TESTBIT(&(m_rgdwSupported[m_rgiPropSetDex[ul] * m_cElemPerSupported]), ulProp) )
  1571. continue;
  1572. pCurPropInfo = &(pPropInfo[ulNext]);
  1573. // If the ppDescBuffer pointer was not NULL, then
  1574. // we need supply description of the properties
  1575. if( ppDescBuffer )
  1576. {
  1577. // Set Buffer pointer
  1578. pCurPropInfo->pwszDescription = pDescBuffer;
  1579. // Load the string into temp buffer
  1580. cch = LoadDescription(pUPropInfo[ulProp].ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
  1581. if( cch )
  1582. {
  1583. // Adjust for '\0'
  1584. cch++;
  1585. // Transfer to official buffer if room
  1586. memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
  1587. pDescBuffer += cch;
  1588. }
  1589. else
  1590. {
  1591. wcscpy(pDescBuffer, L"UNKNOWN");
  1592. pDescBuffer += (wcslen(L"UNKNOWN") + 1);
  1593. }
  1594. }
  1595. pCurPropInfo->dwPropertyID = pUPropInfo[ulProp].dwPropId;
  1596. pCurPropInfo->dwFlags = pUPropInfo[ulProp].dwFlags;
  1597. pCurPropInfo->vtType = pUPropInfo[ulProp].VarType;
  1598. pCurPropInfo->vValues.vt = VT_EMPTY;
  1599. dwStatus |= GETPROPINFO_VALIDPROP;
  1600. // Increment to next available buffer
  1601. ulNext++;
  1602. }
  1603. }
  1604. else
  1605. {
  1606. ATLASSERT( m_cPropSetDex == 1 );
  1607. for( ulProp = 0; ulProp < cPropInfos; ulProp++, ulNext++ )
  1608. {
  1609. pCurPropInfo = &(pPropInfo[ulNext]);
  1610. // Process Properties based on Restriction array.
  1611. pCurPropInfo->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  1612. if( GetUPropInfoPtr(m_rgiPropSetDex[ul], pCurPropInfo->dwPropertyID, &pUPropInfo)
  1613. == S_OK )
  1614. {
  1615. // If the ppDescBuffer pointer was not NULL, then
  1616. // we need supply description of the properties
  1617. if( ppDescBuffer )
  1618. {
  1619. // Set Buffer pointer
  1620. pCurPropInfo->pwszDescription = pDescBuffer;
  1621. // Load the string into temp buffer
  1622. cch = LoadDescription(pUPropInfo->ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
  1623. if( cch )
  1624. {
  1625. // Adjust for '\0'
  1626. cch++;
  1627. // Transfer to official buffer if room
  1628. memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
  1629. pDescBuffer += cch;
  1630. }
  1631. else
  1632. {
  1633. wcscpy(pDescBuffer, L"UNKNOWN");
  1634. pDescBuffer += (wcslen(L"UNKNOWN") + 1);
  1635. }
  1636. }
  1637. pCurPropInfo->dwPropertyID = pUPropInfo->dwPropId;
  1638. pCurPropInfo->dwFlags = pUPropInfo->dwFlags;
  1639. pCurPropInfo->vtType = pUPropInfo->VarType;
  1640. dwStatus |= GETPROPINFO_VALIDPROP;
  1641. }
  1642. else
  1643. {
  1644. // Not Supported
  1645. pCurPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED;
  1646. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1647. }
  1648. }
  1649. }
  1650. }
  1651. }
  1652. else
  1653. {
  1654. hr = E_OUTOFMEMORY;
  1655. goto EXIT;
  1656. }
  1657. NEXT_SET:
  1658. pPropInfoSet[ulSet].cPropertyInfos = ulNext;
  1659. pPropInfoSet[ulSet].rgPropertyInfos = pPropInfo;
  1660. }
  1661. // Success, set return values
  1662. *pcPropertyInfoSets = cSets;
  1663. *prgPropertyInfoSets = pPropInfoSet;
  1664. // At least one propid was marked as not S_OK
  1665. if( dwStatus & GETPROPINFO_ERRORSOCCURRED )
  1666. {
  1667. // If at least 1 property was set
  1668. if( dwStatus & GETPROPINFO_VALIDPROP )
  1669. return DB_S_ERRORSOCCURRED;
  1670. else
  1671. {
  1672. // Do not free any of the rgPropertyInfoSets, but
  1673. // do free the ppDescBuffer
  1674. if( pDescBuffer )
  1675. {
  1676. ATLASSERT( ppDescBuffer );
  1677. CoTaskMemFree(pDescBuffer);
  1678. *ppDescBuffer = NULL;
  1679. }
  1680. return DB_E_ERRORSOCCURRED;
  1681. }
  1682. }
  1683. return S_OK;
  1684. EXIT:
  1685. // Check if failure and clean up any allocated memory
  1686. if( FAILED(hr) &&
  1687. (hr != DB_E_ERRORSOCCURRED) )
  1688. {
  1689. // Free Description Buffer
  1690. if( pDescBuffer )
  1691. {
  1692. ATLASSERT( ppDescBuffer );
  1693. CoTaskMemFree(pDescBuffer);
  1694. *ppDescBuffer = NULL;
  1695. }
  1696. if( pPropInfoSet )
  1697. {
  1698. // Loop through Property Sets
  1699. for(ulSet=0; ulSet<cSets; ulSet++)
  1700. {
  1701. if( pPropInfoSet[ulSet].rgPropertyInfos )
  1702. CoTaskMemFree(pPropInfoSet[ulSet].rgPropertyInfos);
  1703. }
  1704. CoTaskMemFree(pPropInfoSet);
  1705. }
  1706. }
  1707. return hr;
  1708. }
  1709. ULONG m_cUPropSet; //count of UPropSet items
  1710. UPROPSET* m_pUPropSet; //Pointer to UPropset items
  1711. ULONG m_cPropSetDex; //count of UPropSet Indexes
  1712. ULONG* m_rgiPropSetDex;//array of UPropSet Index values
  1713. ULONG m_cElemPerSupported; //number of DWORDS per UPropSet to indicate supported UPropIds
  1714. DWORD* m_rgdwSupported;//array of DWORDs indicating supported UPropIds
  1715. HRESULT InitAvailUPropSets(ULONG* pcUPropSet, UPROPSET** ppUPropSet, ULONG* pcElemPerSupported, GUID* pguid)
  1716. {
  1717. ATLASSERT(pcUPropSet && ppUPropSet);
  1718. if (*ppUPropSet != NULL)
  1719. {
  1720. CoTaskMemFree(*ppUPropSet);
  1721. *ppUPropSet = NULL;
  1722. }
  1723. int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, pcElemPerSupported);
  1724. UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  1725. if (pSet == NULL)
  1726. return E_OUTOFMEMORY;
  1727. *ppUPropSet = T::_GetPropSet(pcUPropSet, pcElemPerSupported, pSet, pguid);
  1728. return S_OK;
  1729. }
  1730. virtual HRESULT InitUPropSetsSupported()
  1731. {
  1732. ULONG cPropSet = 0, cElemsPerSupported = 0;
  1733. int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, &cElemsPerSupported);
  1734. UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  1735. if (pSet == NULL)
  1736. return E_OUTOFMEMORY;
  1737. pSet = T::_GetPropSet(&cPropSet, &cElemsPerSupported, pSet);
  1738. memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
  1739. CoTaskMemFree(pSet);
  1740. return S_OK;
  1741. }
  1742. //Load a localized description
  1743. int LoadDescription(ULONG ids, PWSTR pwszBuff, ULONG cchBuff)
  1744. {
  1745. USES_CONVERSION;
  1746. TCHAR* pszBuf = (TCHAR*)_alloca(cchBuff * sizeof(TCHAR));
  1747. if (pszBuf == NULL)
  1748. return 0;
  1749. int nTemp = LoadString(_pModule->GetResourceInstance(), ids, pszBuf, cchBuff);
  1750. wcscpy(pwszBuff, T2W(pszBuf));
  1751. return nTemp;
  1752. }
  1753. };
  1754. class ATL_NO_VTABLE CUtlPropsBase : public CBitFieldOps, public CDBIDOps
  1755. {
  1756. public:
  1757. ULONG m_cUPropSet; //count of UPropSet items
  1758. UPROPSET* m_pUPropSet; //Pointer to UPropset items
  1759. UPROP* m_pUProp;
  1760. ULONG m_cUPropSetHidden; //Count of Hidden items
  1761. DWORD m_dwFlags; //Configuration flags
  1762. ULONG m_cPropSetDex; //count of UPropSet Indexes
  1763. ULONG* m_rgiPropSetDex; //pointer to Array of UPropSet Index values
  1764. ULONG m_cElemPerSupported;//number of DWORDS per UPropSet to indicate supported UPropIds
  1765. DWORD* m_rgdwSupported; //pointer to array of DWORDs indicating supported UPropIds
  1766. DWORD* m_rgdwPropsInError;//pointer to array of DWORDs indicating if property is in error
  1767. enum EnumUPropSetFlags
  1768. {
  1769. UPROPSET_HIDDEN = 0x00000001,
  1770. UPROPSET_PASSTHROUGH = 0x00000002
  1771. };
  1772. enum EnumGetProp
  1773. {
  1774. GETPROP_ALLPROPIDS = 0x0001,
  1775. GETPROP_NOTSUPPORTED = 0x0002,
  1776. GETPROP_ERRORSOCCURRED = 0x0004,
  1777. GETPROP_VALIDPROP = 0x0008,
  1778. GETPROP_PROPSINERROR = 0x0010
  1779. };
  1780. enum EnumSetProp
  1781. {
  1782. SETPROP_BADOPTION = 0x0001,
  1783. SETPROP_NOTSUPPORTED = 0x0002,
  1784. SETPROP_VALIDPROP = 0x0004,
  1785. SETPROP_ERRORS = 0x0008,
  1786. SETPROP_COLUMN_LEVEL = 0x0010,
  1787. SETPROP_WAS_REQUIRED = 0x0020
  1788. };
  1789. HRESULT SetPassThrough(const DBPROPSET* pPropSet)
  1790. {
  1791. ATLASSERT(pPropSet);
  1792. DBPROP* pProp = pPropSet->rgProperties;
  1793. //Default implementation just sets all properties as NOTSUPPORTED
  1794. for( ULONG ul=0; ul<pPropSet->cProperties; ul++, pProp++ )
  1795. pProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1796. return DB_E_ERRORSOCCURRED;
  1797. }
  1798. HRESULT GetIndexofPropIdinPropSet(ULONG iCurSet, DBPROPID dwPropertyId, ULONG* piCurPropId)
  1799. {
  1800. ATLASSERT(piCurPropId);
  1801. UPROPINFO* pUPropInfo = m_pUPropSet[iCurSet].pUPropInfo;
  1802. for(ULONG ul=0; ul<m_pUPropSet[iCurSet].cUPropInfo; ul++)
  1803. {
  1804. if( dwPropertyId == pUPropInfo[ul].dwPropId )
  1805. {
  1806. *piCurPropId = ul;
  1807. // Test to see if the property is supported for this
  1808. // instantiation
  1809. return (TESTBIT(&(m_rgdwSupported[iCurSet * m_cElemPerSupported]), ul)) ? S_OK : S_FALSE;
  1810. }
  1811. }
  1812. return S_FALSE;
  1813. }
  1814. virtual HRESULT IsValidValue(ULONG /*iCurSet*/, DBPROP* pDBProp)
  1815. {
  1816. ATLASSERT(pDBProp != NULL);
  1817. CComVariant var = pDBProp->vValue;
  1818. if (var.vt == VT_BOOL)
  1819. {
  1820. if (var.boolVal != VARIANT_TRUE && var.boolVal != VARIANT_FALSE)
  1821. return S_FALSE;
  1822. }
  1823. return S_OK;
  1824. }
  1825. virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/) = 0;
  1826. HRESULT SetProperty(ULONG iCurSet, ULONG iCurProp, DBPROP* pDBProp)
  1827. {
  1828. HRESULT hr = S_OK;
  1829. UPROP* pUProp;
  1830. UPROPVAL* pUPropVal;
  1831. UPROPINFO* pUPropInfo;
  1832. ULONG iUProp;
  1833. ATLASSERT( pDBProp );
  1834. // Set pointer to correct set
  1835. pUProp = &(m_pUProp[iCurSet]);
  1836. ATLASSERT( pUProp );
  1837. pUPropInfo = &(m_pUPropSet[iCurSet].pUPropInfo[iCurProp]);
  1838. ATLASSERT( pUPropInfo );
  1839. // Determine the index within m_pUProp
  1840. for(iUProp=0; iUProp<pUProp->cPropIds; iUProp++)
  1841. {
  1842. if( (pUProp->rgpUPropInfo[iUProp])->dwPropId == pDBProp->dwPropertyID )
  1843. break;
  1844. }
  1845. if( iUProp >= pUProp->cPropIds )
  1846. {
  1847. ATLASSERT( !"Should have found index of property to set" );
  1848. hr = E_FAIL;
  1849. pDBProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1850. goto EXIT;
  1851. }
  1852. //Get the UPROPVAL node pointer within that propset.
  1853. pUPropVal = &(pUProp->pUPropVal[iUProp]);
  1854. ATLASSERT( pUPropVal );
  1855. // Handle VT_EMPTY, which indicates to the provider to
  1856. // reset this property to the providers default
  1857. if( pDBProp->vValue.vt == VT_EMPTY )
  1858. {
  1859. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  1860. {
  1861. // Remove any nodes, because the default applies to
  1862. // all columns
  1863. delete pUPropVal->pCColumnIds;
  1864. pUPropVal->pCColumnIds = NULL;
  1865. }
  1866. // Should clear here, since previous values may already
  1867. // have been cached and need to be replaced.
  1868. VariantClear(&(pUPropVal->vValue));
  1869. pUPropVal->dwFlags &= ~DBINTERNFLAGS_CHANGED;
  1870. hr = GetDefaultValue(iCurSet, pDBProp->dwPropertyID,
  1871. &(pUPropVal->dwOption), &(pUPropVal->vValue));
  1872. goto EXIT;
  1873. }
  1874. // Column Level
  1875. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  1876. {
  1877. // Check to see if it applies to all
  1878. if( (CompareDBIDs(&(pDBProp->colid), &DB_NULLID) == S_OK) )
  1879. {
  1880. // Remove the Columns Storage object
  1881. delete pUPropVal->pCColumnIds;
  1882. pUPropVal->pCColumnIds = NULL;
  1883. pUPropVal->dwOption = pDBProp->dwOptions;
  1884. if( FAILED(hr = VariantCopy(&(pUPropVal->vValue),
  1885. &(pDBProp->vValue))) )
  1886. goto EXIT;
  1887. pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  1888. }
  1889. else // Does not apply to all columns
  1890. {
  1891. if( pUPropVal->pCColumnIds == NULL )
  1892. ATLTRY(pUPropVal->pCColumnIds = new CColumnIds)
  1893. if( pUPropVal->pCColumnIds )
  1894. {
  1895. if( FAILED(hr = (pUPropVal->pCColumnIds)->AddColumnId(pDBProp)) )
  1896. goto EXIT;
  1897. pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  1898. }
  1899. else
  1900. {
  1901. hr = E_OUTOFMEMORY;
  1902. goto EXIT;
  1903. }
  1904. }
  1905. }
  1906. else
  1907. {
  1908. // Set for non-column level properties
  1909. pUPropVal->dwOption = pDBProp->dwOptions;
  1910. if( FAILED(hr = VariantCopy(&(pUPropVal->vValue),
  1911. &(pDBProp->vValue))) )
  1912. goto EXIT;
  1913. OnPropertyChanged(iCurSet, pDBProp);
  1914. pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  1915. }
  1916. EXIT:
  1917. if( SUCCEEDED(hr) )
  1918. pDBProp->dwStatus = DBPROPSTATUS_OK;
  1919. return hr;
  1920. }
  1921. HRESULT SetProperties(const DWORD /*dwStatus*/, const ULONG cPropertySets,
  1922. const DBPROPSET rgPropertySets[], const ULONG cSelectProps = 1,
  1923. const GUID** ppGuid = NULL, bool bIsCreating = false)
  1924. {
  1925. DWORD dwState = 0;
  1926. ULONG ulCurSet, ulProp, ulCurProp = 0;
  1927. DBPROP* rgDBProp;
  1928. UPROPINFO* pUPropInfo;
  1929. VARIANT vDefaultValue;
  1930. DWORD dwOption;
  1931. // ppGuid specifies the property sets that the consumer can set based
  1932. // on the interface that called this function.
  1933. ATLASSERT(ppGuid != NULL);
  1934. if ((cPropertySets != 0) && (rgPropertySets == NULL))
  1935. return E_INVALIDARG;
  1936. // Initialize Variant
  1937. VariantInit(&vDefaultValue);
  1938. // Process property sets
  1939. for(ULONG ulSet=0; ulSet<cPropertySets; ulSet++)
  1940. {
  1941. if ((rgPropertySets[ulSet].cProperties != 0) && (rgPropertySets[ulSet].rgProperties == NULL))
  1942. return E_INVALIDARG;
  1943. bool bAvailable = false;
  1944. for (ULONG l=0; l<cSelectProps; l++)
  1945. {
  1946. if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  1947. bAvailable |= true;
  1948. }
  1949. // Make sure we support the property set
  1950. if( !bAvailable ||
  1951. (GetIndexofPropSet(&(rgPropertySets[ulSet].guidPropertySet), &ulCurSet) == S_FALSE ))
  1952. {
  1953. // Not supported, thus we need to mark all as NOT_SUPPORTED
  1954. rgDBProp = rgPropertySets[ulSet].rgProperties;
  1955. for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
  1956. {
  1957. dwState |= SETPROP_ERRORS;
  1958. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  1959. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1960. }
  1961. continue;
  1962. }
  1963. // Handle property sets marked as pass through
  1964. if( m_pUPropSet[ulCurSet].dwFlags & UPROPSET_PASSTHROUGH )
  1965. {
  1966. HRESULT hr = SetPassThrough(&rgPropertySets[ulSet]);
  1967. if( hr == DB_E_ERRORSOCCURRED )
  1968. {
  1969. dwState |= SETPROP_ERRORS;
  1970. dwState |= SETPROP_WAS_REQUIRED;
  1971. }
  1972. else if( hr == DB_S_ERRORSOCCURRED )
  1973. {
  1974. dwState |= SETPROP_ERRORS;
  1975. dwState |= SETPROP_VALIDPROP;
  1976. }
  1977. else
  1978. {
  1979. ATLASSERT( hr == S_OK );
  1980. dwState |= SETPROP_VALIDPROP;
  1981. }
  1982. continue;
  1983. }
  1984. // Handle properties of a supported property set
  1985. rgDBProp = rgPropertySets[ulSet].rgProperties;
  1986. for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
  1987. {
  1988. // Is this a supported PROPID for this property set
  1989. if( GetIndexofPropIdinPropSet(ulCurSet, rgDBProp[ulProp].dwPropertyID,
  1990. &ulCurProp) == S_FALSE)
  1991. {
  1992. dwState |= SETPROP_ERRORS;
  1993. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  1994. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1995. continue;
  1996. }
  1997. // Set the pUPropInfo pointer
  1998. pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
  1999. ATLASSERT( pUPropInfo );
  2000. // check dwOption for a valid option
  2001. if( (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_REQUIRED) &&
  2002. (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_SETIFCHEAP) )
  2003. {
  2004. ATLTRACE2(atlTraceDBProvider, 0, "SetProperties dwOptions Invalid: %u\n", rgDBProp[ulProp].dwOptions);
  2005. dwState |= SETPROP_ERRORS;
  2006. dwState |= SETPROP_WAS_REQUIRED;
  2007. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADOPTION;
  2008. continue;
  2009. }
  2010. // Check that the property is settable
  2011. // We do not check against DBPROPFLAGS_CHANGE here
  2012. if( (pUPropInfo->dwFlags & DBPROPFLAGS_WRITE) == 0 )
  2013. {
  2014. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_OK;
  2015. VariantClear(&vDefaultValue);
  2016. // VT_EMPTY against a read only property should be a no-op since
  2017. // the VT_EMPTY means the default.
  2018. if( V_VT(&rgDBProp[ulProp].vValue) == VT_EMPTY )
  2019. {
  2020. dwState |= SETPROP_VALIDPROP;
  2021. continue;
  2022. }
  2023. if( SUCCEEDED(GetDefaultValue(ulCurSet, rgDBProp[ulProp].dwPropertyID,
  2024. &dwOption, &(vDefaultValue))) )
  2025. {
  2026. if( V_VT(&rgDBProp[ulProp].vValue) == V_VT(&vDefaultValue) )
  2027. {
  2028. switch( V_VT(&vDefaultValue) )
  2029. {
  2030. case VT_BOOL:
  2031. if( V_BOOL(&rgDBProp[ulProp].vValue) == V_BOOL(&vDefaultValue) )
  2032. {
  2033. dwState |= SETPROP_VALIDPROP;
  2034. continue;
  2035. }
  2036. break;
  2037. case VT_I2:
  2038. if( V_I2(&rgDBProp[ulProp].vValue) == V_I2(&vDefaultValue) )
  2039. {
  2040. dwState |= SETPROP_VALIDPROP;
  2041. continue;
  2042. }
  2043. break;
  2044. case VT_I4:
  2045. if( V_I4(&rgDBProp[ulProp].vValue) == V_I4(&vDefaultValue) )
  2046. {
  2047. dwState |= SETPROP_VALIDPROP;
  2048. continue;
  2049. }
  2050. break;
  2051. case VT_BSTR:
  2052. if( wcscmp(V_BSTR(&rgDBProp[ulProp].vValue), V_BSTR(&vDefaultValue)) == 0 )
  2053. {
  2054. dwState |= SETPROP_VALIDPROP;
  2055. continue;
  2056. }
  2057. break;
  2058. }
  2059. }
  2060. }
  2061. dwState |= SETPROP_ERRORS;
  2062. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2063. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
  2064. continue;
  2065. }
  2066. // Check that the property is being set with the correct VARTYPE
  2067. if( (rgDBProp[ulProp].vValue.vt != pUPropInfo->VarType) &&
  2068. (rgDBProp[ulProp].vValue.vt != VT_EMPTY) )
  2069. {
  2070. dwState |= SETPROP_ERRORS;
  2071. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2072. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
  2073. continue;
  2074. }
  2075. // Check that the value is legal
  2076. if( (rgDBProp[ulProp].vValue.vt != VT_EMPTY) &&
  2077. IsValidValue(ulCurSet, &(rgDBProp[ulProp])) == S_FALSE )
  2078. {
  2079. dwState |= SETPROP_ERRORS;
  2080. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2081. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
  2082. continue;
  2083. }
  2084. // Check for a bad COLID, we only catch bad DBIDs
  2085. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2086. {
  2087. if( CDBIDOps::IsValidDBID(&(rgDBProp[ulProp].colid)) == S_FALSE )
  2088. {
  2089. dwState |= SETPROP_ERRORS;
  2090. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2091. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADCOLUMN;
  2092. continue;
  2093. }
  2094. dwState |= SETPROP_COLUMN_LEVEL;
  2095. }
  2096. if( SUCCEEDED(SetProperty(ulCurSet, ulCurProp, /*pUPropInfo,*/ &(rgDBProp[ulProp]))) )
  2097. {
  2098. dwState |= SETPROP_VALIDPROP;
  2099. }
  2100. }
  2101. }
  2102. VariantClear(&vDefaultValue);
  2103. // At least one propid was marked as not S_OK
  2104. if( dwState & SETPROP_ERRORS )
  2105. {
  2106. if (!bIsCreating)
  2107. {
  2108. return (dwState & SETPROP_VALIDPROP) ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED;
  2109. }
  2110. else
  2111. {
  2112. return (dwState & SETPROP_WAS_REQUIRED) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;
  2113. }
  2114. }
  2115. return S_OK;
  2116. }
  2117. OUT_OF_LINE HRESULT CopyUPropVal(ULONG iPropSet, UPROPVAL* rgUPropVal)
  2118. {
  2119. HRESULT hr = S_OK;
  2120. UPROP* pUProp;
  2121. UPROPVAL* pUPropVal;
  2122. DBPROP dbProp;
  2123. ATLASSERT(rgUPropVal);
  2124. ATLASSERT(iPropSet < m_cUPropSet);
  2125. VariantInit(&dbProp.vValue);
  2126. pUProp = &(m_pUProp[iPropSet]);
  2127. for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
  2128. {
  2129. pUPropVal = &(pUProp->pUPropVal[ul]);
  2130. // Transfer dwOptions
  2131. rgUPropVal[ul].dwOption = pUPropVal->dwOption;
  2132. // Transfer Flags
  2133. rgUPropVal[ul].dwFlags = pUPropVal->dwFlags;
  2134. // Transfer Column Properties
  2135. if( pUPropVal->pCColumnIds )
  2136. {
  2137. ATLTRY(rgUPropVal[ul].pCColumnIds = new CColumnIds)
  2138. if( rgUPropVal[ul].pCColumnIds )
  2139. {
  2140. CColumnIds* pColIds = pUPropVal->pCColumnIds;
  2141. for (int i = 0; i < pColIds->GetSize(); i++)
  2142. {
  2143. hr = (pUPropVal->pCColumnIds)->GetValue(i, &(dbProp.dwOptions),&(dbProp.colid), &(dbProp.vValue));
  2144. if( FAILED(hr) )
  2145. goto EXIT;
  2146. if( FAILED(hr = (rgUPropVal[ul].pCColumnIds)->AddColumnId(&dbProp)) )
  2147. goto EXIT;
  2148. }
  2149. }
  2150. else
  2151. {
  2152. hr = E_OUTOFMEMORY;
  2153. goto EXIT;
  2154. }
  2155. }
  2156. else
  2157. {
  2158. rgUPropVal[ul].pCColumnIds = NULL;
  2159. }
  2160. // Transfer value
  2161. VariantInit(&(rgUPropVal[ul].vValue));
  2162. if( FAILED(hr = VariantCopy(&(rgUPropVal[ul].vValue),
  2163. &(pUPropVal->vValue))) )
  2164. goto EXIT;
  2165. }
  2166. EXIT:
  2167. VariantClear(&(dbProp.vValue));
  2168. return hr;
  2169. }
  2170. void ClearPropertyInError()
  2171. {
  2172. ATLASSERT( m_rgdwPropsInError );
  2173. memset(m_rgdwPropsInError, 0, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
  2174. }
  2175. void CopyUPropSetsSupported(DWORD* rgdwSupported)
  2176. {
  2177. memcpy(rgdwSupported, m_rgdwSupported, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
  2178. }
  2179. virtual HRESULT InitUPropSetsSupported() = 0;
  2180. virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet) = 0;
  2181. ULONG GetCountofWritablePropsInPropSet(ULONG iPropSet)
  2182. {
  2183. ULONG cWritable = 0;
  2184. UPROPINFO* pUPropInfo;
  2185. ATLASSERT( m_pUPropSet );
  2186. ATLASSERT( iPropSet < m_cUPropSet );
  2187. pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
  2188. for(ULONG ul=0; ul<m_pUPropSet[iPropSet].cUPropInfo; ul++)
  2189. {
  2190. if( pUPropInfo[ul].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2191. cWritable++;
  2192. }
  2193. return cWritable;
  2194. }
  2195. void CopyUPropInfo(ULONG iPropSet, UPROPINFO** rgpUPropInfo)
  2196. {
  2197. ATLASSERT( rgpUPropInfo );
  2198. ATLASSERT( iPropSet < m_cUPropSet );
  2199. memcpy(rgpUPropInfo, m_pUProp[iPropSet].rgpUPropInfo, m_pUProp[iPropSet].cPropIds * sizeof(UPROPINFO*));
  2200. }
  2201. virtual HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar) = 0;
  2202. typedef UPROPSET* (*PGetPropSet)(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet, GUID* pguidSet);
  2203. HRESULT InternalInitUPropSetsSupported(PGetPropSet pfnGetSet)
  2204. {
  2205. ULONG cPropSet = 0, cElemsPerSupported = 0;
  2206. INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemsPerSupported, NULL, (GUID*)&GUID_NULL);
  2207. UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  2208. if (pPropSet == NULL)
  2209. return E_OUTOFMEMORY;
  2210. pPropSet = (*pfnGetSet)(&cPropSet, &cElemsPerSupported, pPropSet, (GUID*)&GUID_NULL);
  2211. memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
  2212. CoTaskMemFree(pPropSet);
  2213. return S_OK;
  2214. }
  2215. HRESULT InternalGetDefaultValue(PGetPropSet pfnGetSet, ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar)
  2216. {
  2217. if (pdwOption == NULL || pVar == NULL)
  2218. return E_INVALIDARG;
  2219. ULONG cUPropSet = 0, cElemPerSupported =0;
  2220. INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemPerSupported, NULL, (GUID*)&GUID_NULL);
  2221. UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  2222. if (pPropSet == NULL)
  2223. return E_OUTOFMEMORY;
  2224. pPropSet = (*pfnGetSet)(&cUPropSet, &cElemPerSupported, pPropSet, (GUID*)&GUID_NULL);
  2225. ATLASSERT(iPropSet < cUPropSet);
  2226. for (ULONG iProp = 0; iProp < pPropSet[iPropSet].cUPropInfo; iProp++)
  2227. {
  2228. UPROPINFO& rInfo = pPropSet[iPropSet].pUPropInfo[iProp];
  2229. if (rInfo.dwPropId == dwPropId)
  2230. {
  2231. pVar->vt = rInfo.VarType;
  2232. *pdwOption = rInfo.dwOption;
  2233. switch(rInfo.VarType)
  2234. {
  2235. case VT_BSTR:
  2236. pVar->bstrVal = SysAllocString(rInfo.szVal);
  2237. break;
  2238. default:
  2239. pVar->lVal = (DWORD)rInfo.dwVal;
  2240. break;
  2241. }
  2242. CoTaskMemFree(pPropSet);
  2243. return S_OK;
  2244. }
  2245. }
  2246. CoTaskMemFree(pPropSet);
  2247. return E_FAIL;
  2248. }
  2249. HRESULT InternalFInit(PGetPropSet pfnGetSet, CUtlPropsBase* pCopyMe = NULL)
  2250. {
  2251. HRESULT hr;
  2252. ULONG ulPropId;
  2253. ULONG cPropIds;
  2254. ULONG iPropSet;
  2255. ULONG iNewDex;
  2256. UPROPINFO** rgpUPropInfo;
  2257. UPROPVAL* rgUPropVal;
  2258. UPROPINFO* pUPropInfo;
  2259. // If a pointer is passed in, we should copy that property object
  2260. if( pCopyMe )
  2261. {
  2262. // Establish some base values
  2263. m_cUPropSet = pCopyMe->m_cUPropSet;
  2264. if (m_pUPropSet != NULL)
  2265. CoTaskMemFree(m_pUPropSet);
  2266. m_pUPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * m_cUPropSet);
  2267. if (m_pUPropSet == NULL)
  2268. return E_OUTOFMEMORY;
  2269. memcpy(m_pUPropSet, pCopyMe->m_pUPropSet, sizeof(UPROPSET) * m_cUPropSet);
  2270. m_cElemPerSupported = pCopyMe->m_cElemPerSupported;
  2271. ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) );
  2272. // Retrieve Supported Bitmask
  2273. ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2274. ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2275. if( m_rgdwSupported == NULL|| m_rgdwPropsInError == NULL)
  2276. {
  2277. delete[] m_rgdwSupported;
  2278. delete[] m_rgdwPropsInError;
  2279. return E_OUTOFMEMORY;
  2280. }
  2281. ClearPropertyInError();
  2282. pCopyMe->CopyUPropSetsSupported(m_rgdwSupported);
  2283. }
  2284. else
  2285. {
  2286. INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &m_cElemPerSupported, NULL, (GUID*)&GUID_NULL);
  2287. UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  2288. if (pSet == NULL)
  2289. return E_OUTOFMEMORY;
  2290. pSet = (*pfnGetSet)(&m_cUPropSet, &m_cElemPerSupported, pSet, (GUID*)&GUID_NULL);
  2291. if (m_pUPropSet != NULL)
  2292. CoTaskMemFree(m_pUPropSet);
  2293. m_pUPropSet = pSet;
  2294. ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) );
  2295. if( !m_cUPropSet || !m_cElemPerSupported )
  2296. return E_FAIL;
  2297. ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2298. ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2299. if( m_rgdwSupported == NULL || m_rgdwPropsInError == NULL)
  2300. {
  2301. delete[] m_rgdwSupported;
  2302. delete[] m_rgdwPropsInError;
  2303. return E_OUTOFMEMORY;
  2304. }
  2305. else
  2306. ClearPropertyInError();
  2307. if( FAILED(hr = InitUPropSetsSupported()) )
  2308. {
  2309. delete[] m_rgdwSupported;
  2310. m_rgdwSupported = NULL;
  2311. return hr;
  2312. }
  2313. }
  2314. // Allocate UPROPS structures for the count of Property sets
  2315. ATLTRY(m_pUProp = (UPROP*) new UPROP[m_cUPropSet])
  2316. if( m_pUProp)
  2317. {
  2318. memset(m_pUProp, 0, m_cUPropSet * sizeof(UPROP));
  2319. }
  2320. else
  2321. {
  2322. m_cUPropSet = 0;
  2323. return E_OUTOFMEMORY;
  2324. }
  2325. // With in the UPROPS Structure allocate and intialize the
  2326. // Property IDs that belong to this property set.
  2327. for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
  2328. {
  2329. cPropIds = GetCountofWritablePropsInPropSet(iPropSet);
  2330. if( cPropIds > 0 )
  2331. {
  2332. ATLTRY(rgpUPropInfo = (UPROPINFO**) new UPROPINFO*[cPropIds])
  2333. ATLTRY(rgUPropVal = (UPROPVAL*) new UPROPVAL[cPropIds])
  2334. if( rgpUPropInfo != NULL && rgUPropVal != NULL)
  2335. {
  2336. if( pCopyMe )
  2337. {
  2338. pCopyMe->CopyUPropInfo(iPropSet, rgpUPropInfo);
  2339. if( FAILED(hr = pCopyMe->CopyUPropVal(iPropSet, rgUPropVal)) )
  2340. return hr;
  2341. }
  2342. else
  2343. {
  2344. // Clear Pointer Array
  2345. memset(rgpUPropInfo, 0, cPropIds * sizeof(UPROPINFO*));
  2346. // Set Pointer to correct property ids with a property set
  2347. pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
  2348. // Set up the writable property buffers
  2349. iNewDex = 0;
  2350. for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
  2351. {
  2352. if( pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2353. {
  2354. // Following ATLASSERT indicates that the are more
  2355. // writable properties then space allocated
  2356. ATLASSERT(iNewDex < cPropIds);
  2357. rgpUPropInfo[iNewDex] = &(pUPropInfo[ulPropId]);
  2358. rgUPropVal[iNewDex].dwOption = DBPROPOPTIONS_SETIFCHEAP;
  2359. rgUPropVal[iNewDex].pCColumnIds = NULL;
  2360. rgUPropVal[iNewDex].dwFlags = 0;
  2361. VariantInit(&(rgUPropVal[iNewDex].vValue));
  2362. GetDefaultValue(iPropSet, pUPropInfo[ulPropId].dwPropId,
  2363. &(rgUPropVal[iNewDex].dwOption), &(rgUPropVal[iNewDex].vValue));
  2364. iNewDex++;
  2365. }
  2366. }
  2367. ATLASSERT(cPropIds == iNewDex);
  2368. }
  2369. m_pUProp[iPropSet].rgpUPropInfo = rgpUPropInfo;
  2370. m_pUProp[iPropSet].pUPropVal = rgUPropVal;
  2371. m_pUProp[iPropSet].cPropIds = cPropIds;
  2372. }
  2373. else
  2374. {
  2375. delete[] rgpUPropInfo;
  2376. delete[] rgUPropVal;
  2377. return E_OUTOFMEMORY;
  2378. }
  2379. }
  2380. }
  2381. // Finally determine if there are any hidden property sets.. Those
  2382. // that do not show up in GetPropertyInfo and should not be returns on
  2383. // a 0, NULL call to GetProperties
  2384. for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
  2385. {
  2386. if( m_pUPropSet[iPropSet].dwFlags & UPROPSET_HIDDEN )
  2387. m_cUPropSetHidden++;
  2388. }
  2389. return S_OK;
  2390. }
  2391. //Check the arguments for Set Properties
  2392. static HRESULT SetPropertiesArgChk(const ULONG cPropertySets, const DBPROPSET rgPropertySets[])
  2393. {
  2394. if( cPropertySets > 0 && !rgPropertySets )
  2395. return E_INVALIDARG;
  2396. // New argument check for > 1 cPropertyIDs and NULL pointer for
  2397. // array of property ids.
  2398. for(ULONG ul=0; ul<cPropertySets; ul++)
  2399. {
  2400. if( rgPropertySets[ul].cProperties && !(rgPropertySets[ul].rgProperties) )
  2401. return E_INVALIDARG;
  2402. }
  2403. return S_OK;
  2404. }
  2405. HRESULT GetProperties(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
  2406. ULONG* pcProperties, DBPROPSET** prgProperties,
  2407. const ULONG cSelectProps = 1, const GUID** ppGuid = NULL)
  2408. {
  2409. UPROPVAL* pUPropVal;
  2410. ULONG ulCurProp = 0;
  2411. ULONG cTmpPropertySets = cPropertySets;
  2412. HRESULT hr = S_OK;
  2413. ULONG ulSet = 0;
  2414. ULONG ulNext = 0;
  2415. ULONG cSets = 0;
  2416. ULONG cProps = 0;
  2417. ULONG ulProp = 0;
  2418. DWORD dwStatus = 0;
  2419. DBPROP* pProp = NULL;
  2420. DBPROP* pCurProp = NULL;
  2421. DBPROPSET* pPropSet = NULL;
  2422. UPROPINFO* pUPropInfo = NULL;
  2423. ULONG* piSetIndex = NULL;
  2424. ULONG* piIndex = NULL;
  2425. ULONG ulCurSet = 0;
  2426. ULONG iPropSet;
  2427. // ppGuid contains an array of GUIDs that the consumer can retrieve.
  2428. // This is based upon the interface calling this function
  2429. ATLASSERT(ppGuid != NULL);
  2430. // We need to have special handling for DBPROPSET_PROPERTIESINERROR..
  2431. // Turn on a flags to indicate this mode and make cTmpPropertySets
  2432. // appear to be 0
  2433. if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) &&
  2434. rgPropertySets &&
  2435. (rgPropertySets[0].guidPropertySet == DBPROPSET_PROPERTIESINERROR) )
  2436. {
  2437. cTmpPropertySets = 0;
  2438. dwStatus |= GETPROP_PROPSINERROR;
  2439. }
  2440. // If the consumer does not restrict the property sets
  2441. // by specify an array of property sets and a cTmpPropertySets
  2442. // greater than 0, then we need to make sure we
  2443. // have some to return
  2444. if( cTmpPropertySets == 0 )
  2445. {
  2446. // There are times when we are called from IRowsetInfo, ISessionProperties, etc.
  2447. // where we should return only the appropriate rowset when cTmpPropertySets is
  2448. // zero. This solves the problem if the user has more than one set specified in
  2449. // their PROPSET_MAP.
  2450. // Determine the number of property sets supported
  2451. if (ppGuid == NULL)
  2452. {
  2453. cSets = m_cUPropSet;
  2454. }
  2455. else
  2456. {
  2457. ULONG ulActualProps = 0;
  2458. piSetIndex = new ULONG[cSelectProps];
  2459. // Also, find the index for the set we are looking for
  2460. for (ULONG l=0; l<cSelectProps; l++)
  2461. {
  2462. for (piSetIndex[l]=0; piSetIndex[l]<m_cUPropSet; piSetIndex[l]++)
  2463. {
  2464. if (InlineIsEqualGUID(*m_pUPropSet[piSetIndex[l]].pPropSet, *ppGuid[l]))
  2465. {
  2466. ulActualProps++;
  2467. break;
  2468. }
  2469. }
  2470. }
  2471. // YIKES!
  2472. cSets = ulActualProps;
  2473. ulActualProps = 0;
  2474. piIndex = new ULONG[cSets];
  2475. for (l=0; l<cSelectProps; l++)
  2476. {
  2477. if (piSetIndex[l] != m_cUPropSet) // this is an invalid index
  2478. piIndex[ulActualProps++] = piSetIndex[l];
  2479. }
  2480. delete piSetIndex;
  2481. piSetIndex = NULL;
  2482. }
  2483. }
  2484. else
  2485. {
  2486. // Since special property set guids are not supported by
  2487. // GetProperties, we can just use the count of property
  2488. // sets given to us.
  2489. cSets = cTmpPropertySets;
  2490. }
  2491. // If no properties set, then return
  2492. if( cSets == 0 )
  2493. return S_OK;
  2494. // Allocate the DBPROPSET structures
  2495. pPropSet = (DBPROPSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPSET));
  2496. if(pPropSet)
  2497. {
  2498. memset(pPropSet, 0, cSets * sizeof(DBPROPSET));
  2499. // Fill in the output array
  2500. iPropSet = 0;
  2501. for(ulSet=0; ulSet<cSets; ulSet++)
  2502. {
  2503. // Depending of if Property sets are specified store the
  2504. // return property set.
  2505. if( cTmpPropertySets == 0 )
  2506. {
  2507. ULONG lSet;
  2508. if (ppGuid[ulSet] == NULL)
  2509. lSet = ulSet;
  2510. else
  2511. lSet = piIndex[ulSet];
  2512. if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
  2513. continue;
  2514. pPropSet[iPropSet].guidPropertySet = *(m_pUPropSet[lSet].pPropSet);
  2515. }
  2516. else
  2517. pPropSet[iPropSet].guidPropertySet = rgPropertySets[ulSet].guidPropertySet;
  2518. iPropSet++;
  2519. }
  2520. }
  2521. else
  2522. {
  2523. ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
  2524. delete piIndex;
  2525. piIndex = NULL;
  2526. return E_OUTOFMEMORY;
  2527. }
  2528. // Process requested or derived Property sets
  2529. iPropSet=0;
  2530. for(ulSet=0; ulSet<cSets; ulSet++)
  2531. {
  2532. cProps = 0;
  2533. pProp = NULL;
  2534. ulNext = 0;
  2535. dwStatus &= (GETPROP_ERRORSOCCURRED | GETPROP_VALIDPROP | GETPROP_PROPSINERROR);
  2536. // Calculate the number of property nodes needed for this
  2537. // property set.
  2538. if( cTmpPropertySets == 0 )
  2539. {
  2540. ULONG lSet;
  2541. if (ppGuid[ulSet] == NULL)
  2542. lSet = ulSet;
  2543. else
  2544. lSet = piIndex[ulSet];
  2545. // If processing requesting all property sets, do not
  2546. // return the hidden sets.
  2547. if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
  2548. continue;
  2549. cProps = m_pUPropSet[lSet].cUPropInfo;
  2550. // Add Enough space for node that are colid specific
  2551. cProps += GetCountofColids(&(m_pUProp[lSet]));
  2552. dwStatus |= GETPROP_ALLPROPIDS;
  2553. ulCurSet = lSet;
  2554. }
  2555. else
  2556. {
  2557. ATLASSERT(ulSet == iPropSet);
  2558. // If the count of PROPIDs is 0 or It is a special property set, then
  2559. // the consumer is requesting all propids for this property set.
  2560. if(rgPropertySets[ulSet].cPropertyIDs == 0)
  2561. {
  2562. dwStatus |= GETPROP_ALLPROPIDS;
  2563. // We have to determine if the property set is supported and if so
  2564. // the count of properties in the set.
  2565. BOOL bAvailable = false;
  2566. for (ULONG l=0; l<cSelectProps; l++)
  2567. {
  2568. if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  2569. bAvailable |= true;
  2570. }
  2571. if (bAvailable &&
  2572. GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) == S_OK)
  2573. {
  2574. cProps += m_pUPropSet[ulCurSet].cUPropInfo;
  2575. // Add Enough space for node that are colid specific
  2576. cProps += GetCountofColids(&m_pUProp[ulCurSet]);
  2577. }
  2578. else
  2579. {
  2580. // Not Supported
  2581. dwStatus |= GETPROP_ERRORSOCCURRED;
  2582. goto NEXT_SET;
  2583. }
  2584. }
  2585. else
  2586. {
  2587. cProps = rgPropertySets[ulSet].cPropertyIDs;
  2588. // Check to see if this is a supported interface based on ppGuid.
  2589. BOOL bAvailable = false;
  2590. for (ULONG l=0; l<cSelectProps; l++)
  2591. {
  2592. if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  2593. bAvailable |= true;
  2594. }
  2595. if (!bAvailable ||
  2596. (GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) != S_OK))
  2597. {
  2598. dwStatus |= GETPROP_NOTSUPPORTED;
  2599. dwStatus |= GETPROP_ERRORSOCCURRED;
  2600. }
  2601. }
  2602. }
  2603. // Allocate DBPROP array
  2604. if( cProps == 0 ) //Possible with Hidden Passthrough sets
  2605. goto NEXT_SET;
  2606. pProp = (DBPROP*)CoTaskMemAlloc(cProps * sizeof(DBPROP));
  2607. if( pProp )
  2608. {
  2609. // Initialize Buffer
  2610. memset(pProp, 0, cProps * sizeof(DBPROP));
  2611. for(ulProp=0; ulProp<cProps; ulProp++)
  2612. {
  2613. VariantInit(&(pProp[ulProp].vValue));
  2614. if( dwStatus & GETPROP_NOTSUPPORTED )
  2615. {
  2616. // Not supported, thus we need to mark all as NOT_SUPPORTED
  2617. pProp[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  2618. pProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  2619. }
  2620. }
  2621. // Make sure we support the property set
  2622. if( dwStatus & GETPROP_NOTSUPPORTED )
  2623. {
  2624. ulNext = cProps;
  2625. goto NEXT_SET;
  2626. }
  2627. // Now that we have determined we can support the property set, we
  2628. // need to gather current property values
  2629. for(ulProp=0; ulProp<cProps; ulProp++)
  2630. {
  2631. pCurProp = &(pProp[ulNext]);
  2632. //Initialize Variant Value
  2633. pCurProp->dwStatus = DBPROPSTATUS_OK;
  2634. // Retrieve current value of properties
  2635. if( dwStatus & GETPROP_ALLPROPIDS )
  2636. {
  2637. // Verify property is supported, if not do not return
  2638. if( !TESTBIT(&(m_rgdwSupported[ulCurSet * m_cElemPerSupported]), ulProp) )
  2639. continue;
  2640. // If we are looking for properties in error, then we should ignore all
  2641. // that are not in error.
  2642. if( (dwStatus & GETPROP_PROPSINERROR) &&
  2643. !TESTBIT(&(m_rgdwPropsInError[ulCurSet * m_cElemPerSupported]), ulProp) )
  2644. continue;
  2645. pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulProp]);
  2646. ATLASSERT( pUPropInfo );
  2647. pCurProp->dwPropertyID = pUPropInfo->dwPropId;
  2648. pCurProp->colid = DB_NULLID;
  2649. // If the property is WRITEABLE or CHANGABLE, then the value will
  2650. // be gotten from the UPROPVAL array, else it will be
  2651. // derive from the GetDefaultValue
  2652. if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2653. {
  2654. pUPropVal = &(m_pUProp[ulCurSet].
  2655. pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
  2656. ATLASSERT( pUPropVal );
  2657. // Check to see if this property supports column level,
  2658. // if so, dump those nodes
  2659. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2660. {
  2661. if( pUPropVal->pCColumnIds )
  2662. {
  2663. RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
  2664. continue;
  2665. }
  2666. }
  2667. pCurProp->dwOptions = pUPropVal->dwOption;
  2668. hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
  2669. }
  2670. else
  2671. {
  2672. GetDefaultValue(ulCurSet, pUPropInfo->dwPropId,
  2673. &(pCurProp->dwOptions), &(pCurProp->vValue));
  2674. }
  2675. // Return all Properties in Error with CONFLICT status
  2676. if( dwStatus & GETPROP_PROPSINERROR )
  2677. pCurProp->dwStatus = DBPROPSTATUS_CONFLICTING;
  2678. dwStatus |= GETPROP_VALIDPROP;
  2679. }
  2680. else
  2681. {
  2682. // Process Properties based on Restriction array.
  2683. pCurProp->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  2684. pCurProp->colid = DB_NULLID;
  2685. if( GetIndexofPropIdinPropSet(ulCurSet, pCurProp->dwPropertyID,
  2686. &ulCurProp) == S_OK)
  2687. {
  2688. // Supported
  2689. pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
  2690. ATLASSERT( pUPropInfo );
  2691. // If the property is WRITEABLE, then the value will
  2692. // be gotten from the UPROPVAL array, else it will be
  2693. // derive from the GetDefaultValue
  2694. if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2695. {
  2696. pUPropVal = &(m_pUProp[ulCurSet].
  2697. pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
  2698. ATLASSERT( pUPropVal );
  2699. // Check to see if this property supports column level,
  2700. // if so, dump those nodes
  2701. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2702. {
  2703. if( pUPropVal->pCColumnIds )
  2704. {
  2705. RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
  2706. continue;
  2707. }
  2708. }
  2709. pCurProp->dwOptions = pUPropVal->dwOption;
  2710. hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
  2711. }
  2712. else
  2713. {
  2714. GetDefaultValue(ulCurSet, pUPropInfo->dwPropId,
  2715. &(pCurProp->dwOptions), &(pCurProp->vValue));
  2716. }
  2717. dwStatus |= GETPROP_VALIDPROP;
  2718. }
  2719. else
  2720. {
  2721. // Not Supported
  2722. pCurProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  2723. dwStatus |= GETPROP_ERRORSOCCURRED;
  2724. }
  2725. }
  2726. // Increment return nodes count
  2727. ulNext++;
  2728. }
  2729. }
  2730. else
  2731. {
  2732. ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROP array for GetProperties\n");
  2733. if( pPropSet )
  2734. {
  2735. // Free any DBPROP arrays
  2736. for(ulSet=0; ulSet<cSets; ulSet++)
  2737. {
  2738. // Need to loop through all the VARIANTS and clear them
  2739. for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
  2740. VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
  2741. if( pPropSet[ulSet].rgProperties )
  2742. CoTaskMemFree(pPropSet[ulSet].rgProperties);
  2743. }
  2744. // Free DBPROPSET
  2745. CoTaskMemFree(pPropSet);
  2746. }
  2747. //Since we have no properties to return, then we
  2748. //need to free allocated memory and return 0,NULL
  2749. if(pPropSet)
  2750. {
  2751. // Free any DBPROP arrays
  2752. for(ulSet=0; ulSet<cSets; ulSet++)
  2753. {
  2754. // Need to loop through all the VARIANTS and clear them
  2755. for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
  2756. VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
  2757. if( pPropSet[ulSet].rgProperties )
  2758. CoTaskMemFree(pPropSet[ulSet].rgProperties);
  2759. }
  2760. // Free DBPROPSET
  2761. CoTaskMemFree(pPropSet);
  2762. }
  2763. *pcProperties = 0;
  2764. *prgProperties = NULL;
  2765. delete piIndex;
  2766. piIndex = NULL;
  2767. return E_OUTOFMEMORY;
  2768. }
  2769. NEXT_SET:
  2770. // It is possible that all properties are not supported,
  2771. // thus we should delete that memory and set rgProperties
  2772. // to NULL
  2773. if( ulNext == 0 && pProp )
  2774. {
  2775. CoTaskMemFree(pProp);
  2776. pProp = NULL;
  2777. }
  2778. pPropSet[iPropSet].cProperties = ulNext;
  2779. pPropSet[iPropSet].rgProperties = pProp;
  2780. iPropSet++;
  2781. }
  2782. *pcProperties = iPropSet;
  2783. *prgProperties = pPropSet;
  2784. delete piIndex;
  2785. piIndex = NULL;
  2786. // At least one propid was marked as not S_OK
  2787. if( dwStatus & GETPROP_ERRORSOCCURRED )
  2788. {
  2789. // If at least 1 property was set
  2790. if( dwStatus & GETPROP_VALIDPROP )
  2791. return DB_S_ERRORSOCCURRED;
  2792. else
  2793. {
  2794. // Do not free any of the memory on a DB_E_
  2795. return DB_E_ERRORSOCCURRED;
  2796. }
  2797. }
  2798. return S_OK;
  2799. }
  2800. ULONG GetCountofColids(UPROP* pUProp)
  2801. {
  2802. ULONG cExtra=0;
  2803. ATLASSERT(pUProp);
  2804. for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
  2805. {
  2806. if( pUProp->pUPropVal[ul].pCColumnIds )
  2807. cExtra += (pUProp->pUPropVal[ul].pCColumnIds)->GetCountOfPropColids();
  2808. }
  2809. return cExtra;
  2810. }
  2811. ULONG GetUPropValIndex(ULONG iCurSet, DBPROPID dwPropId)
  2812. {
  2813. for(ULONG ul=0; ul<m_pUProp[iCurSet].cPropIds; ul++)
  2814. {
  2815. if( (m_pUProp[iCurSet].rgpUPropInfo[ul])->dwPropId == dwPropId )
  2816. return ul;
  2817. }
  2818. return 0;
  2819. }
  2820. void RetrieveColumnIdProps(DBPROP* pCurProp, UPROPVAL* pUPropVal, ULONG* pulNext)
  2821. {
  2822. // Reset to first Node
  2823. CColumnIds* pColIds = pUPropVal->pCColumnIds;
  2824. HRESULT hr = E_FAIL;
  2825. for (int i = 0; i < pColIds->GetSize(); i++)
  2826. {
  2827. CPropColID colId;
  2828. hr = pColIds->GetValue(i, &(pCurProp->dwOptions), &(pCurProp->colid),&(pCurProp->vValue));
  2829. if (SUCCEEDED(hr))
  2830. pCurProp = &(pCurProp[++(*pulNext)]);
  2831. }
  2832. (*pulNext)++;
  2833. }
  2834. //Check the arguments for Retrieve Properties
  2835. HRESULT GetPropertiesArgChk(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
  2836. ULONG* pcProperties, DBPROPSET** prgProperties)
  2837. {
  2838. // Initialize values
  2839. if(pcProperties)
  2840. *pcProperties = 0;
  2841. if(prgProperties)
  2842. *prgProperties = NULL;
  2843. // Check Arguments
  2844. if( ((cPropertySets > 0) && !rgPropertySets) || !pcProperties || !prgProperties )
  2845. return E_INVALIDARG;
  2846. // New argument check for > 1 cPropertyIDs and NULL pointer for
  2847. // array of property ids.
  2848. for(ULONG ul=0; ul<cPropertySets; ul++)
  2849. {
  2850. if( rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs) )
  2851. return E_INVALIDARG;
  2852. // Check for propper formation of DBPROPSET_PROPERTIESINERROR
  2853. if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) &&
  2854. rgPropertySets[ul].guidPropertySet == DBPROPSET_PROPERTIESINERROR )
  2855. {
  2856. if( (cPropertySets > 1) ||
  2857. (rgPropertySets[ul].cPropertyIDs != 0) ||
  2858. (rgPropertySets[ul].rgPropertyIDs != NULL) )
  2859. return E_INVALIDARG;
  2860. }
  2861. }
  2862. return S_OK;
  2863. }
  2864. OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL) = 0;
  2865. };
  2866. // Implementation Class
  2867. template <class T>
  2868. class ATL_NO_VTABLE CUtlProps : public CUtlPropsBase
  2869. {
  2870. public:
  2871. CUtlProps(DWORD dwFlags = 0)
  2872. {
  2873. ClearMemberVars();
  2874. m_dwFlags = dwFlags;
  2875. }
  2876. ~CUtlProps()
  2877. {
  2878. FreeMemory();
  2879. }
  2880. void FreeMemory()
  2881. {
  2882. // Remove Property Information
  2883. if( m_pUProp )
  2884. {
  2885. for(ULONG ulPropSet=0; ulPropSet<m_cUPropSet; ulPropSet++)
  2886. {
  2887. UPROPVAL* pUPropVal = m_pUProp[ulPropSet].pUPropVal;
  2888. for(ULONG ulPropId=0; ulPropId<m_pUProp[ulPropSet].cPropIds; ulPropId++)
  2889. {
  2890. delete pUPropVal[ulPropId].pCColumnIds;
  2891. VariantClear(&(pUPropVal[ulPropId].vValue));
  2892. }
  2893. delete[] m_pUProp[ulPropSet].rgpUPropInfo;
  2894. delete[] m_pUProp[ulPropSet].pUPropVal;
  2895. }
  2896. }
  2897. delete[] m_pUProp;
  2898. delete[] m_rgdwSupported;
  2899. delete[] m_rgdwPropsInError;
  2900. delete[] m_rgiPropSetDex;
  2901. if (m_pUPropSet != NULL)
  2902. CoTaskMemFree(m_pUPropSet);
  2903. ClearMemberVars();
  2904. }
  2905. void ClearMemberVars()
  2906. {
  2907. m_cPropSetDex = 0;
  2908. m_cUPropSet = 0;
  2909. m_cUPropSetHidden = 0;
  2910. m_pUPropSet = NULL;
  2911. m_dwFlags = 0;
  2912. m_pUProp = NULL;
  2913. m_cElemPerSupported = 0;
  2914. m_rgdwSupported = NULL;
  2915. m_rgdwPropsInError = NULL;
  2916. m_rgiPropSetDex = NULL;
  2917. }
  2918. //Retrieve the property set indexes that match this property set.
  2919. HRESULT GetPropertySetIndex(GUID* pPropertySet)
  2920. {
  2921. DWORD dwFlag = 0;
  2922. ULONG ulSet;
  2923. ATLASSERT( m_cUPropSet && m_pUPropSet );
  2924. ATLASSERT( m_rgiPropSetDex );
  2925. ATLASSERT( pPropertySet );
  2926. m_cPropSetDex = 0;
  2927. if( *pPropertySet == DBPROPSET_DATASOURCEALL )
  2928. {
  2929. dwFlag = DBPROPFLAGS_DATASOURCE;
  2930. }
  2931. else if( *pPropertySet == DBPROPSET_DATASOURCEINFOALL )
  2932. {
  2933. dwFlag = DBPROPFLAGS_DATASOURCEINFO;
  2934. }
  2935. else if( *pPropertySet == DBPROPSET_ROWSETALL )
  2936. {
  2937. dwFlag = DBPROPFLAGS_ROWSET;
  2938. }
  2939. else if( *pPropertySet == DBPROPSET_DBINITALL )
  2940. {
  2941. dwFlag = DBPROPFLAGS_DBINIT;
  2942. }
  2943. else if( *pPropertySet == DBPROPSET_SESSIONALL )
  2944. {
  2945. dwFlag = DBPROPFLAGS_SESSION;
  2946. }
  2947. else // No scan required, just look for match.
  2948. {
  2949. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  2950. {
  2951. if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
  2952. {
  2953. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  2954. m_cPropSetDex++;
  2955. break;
  2956. }
  2957. }
  2958. goto EXIT;
  2959. }
  2960. // Scan through the property sets looking for matching attributes
  2961. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  2962. {
  2963. if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
  2964. {
  2965. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  2966. m_cPropSetDex++;
  2967. }
  2968. }
  2969. EXIT:
  2970. return (m_cPropSetDex) ? S_OK : S_FALSE;
  2971. }
  2972. OUT_OF_LINE HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar)
  2973. {
  2974. return InternalGetDefaultValue(T::_GetPropSet, iPropSet, dwPropId, pdwOption, pVar);
  2975. }
  2976. OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL)
  2977. {
  2978. return InternalFInit(T::_GetPropSet, pCopyMe);
  2979. }
  2980. HRESULT FillDefaultValues(ULONG ulPropSetTarget = ULONG_MAX)
  2981. {
  2982. HRESULT hr;
  2983. ULONG ulPropId;
  2984. ULONG iPropSet;
  2985. ULONG iNewDex;
  2986. // Fill in all the actual values.
  2987. // Typically because we now have an hdbc with which to get them.
  2988. // (Or we no longer have an hdbc, so must clear them.)
  2989. // Note that the UPROP (with values) array may be a subset of the UPROPINFO array.
  2990. // Only writable properties are in UPROP array.
  2991. // Maybe restrict to a single PropSet if within valid range [0...m_cUPropSet-1].
  2992. // Otherwise do all propsets.
  2993. iPropSet = (ulPropSetTarget < m_cUPropSet) ? ulPropSetTarget : 0;
  2994. for( ; iPropSet<m_cUPropSet; iPropSet++)
  2995. {
  2996. iNewDex = 0;
  2997. for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
  2998. {
  2999. if( m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3000. {
  3001. //Initialize dwFlags element of UPropVal
  3002. m_pUProp[iPropSet].pUPropVal[iNewDex].dwFlags = 0;
  3003. // Don't need this since SetProperties() resets these.
  3004. //ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption == DBPROPOPTIONS_SETIFCHEAP);
  3005. ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].pCColumnIds == NULL);
  3006. VariantClear(&m_pUProp[iPropSet].pUPropVal[iNewDex].vValue);
  3007. hr = GetDefaultValue(
  3008. iPropSet,
  3009. m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwPropId,
  3010. &m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption,
  3011. &m_pUProp[iPropSet].pUPropVal[iNewDex].vValue );
  3012. if (FAILED(hr))
  3013. return hr;
  3014. iNewDex++;
  3015. }
  3016. }
  3017. // We're through if restricting to single PropSet.
  3018. if (ulPropSetTarget < m_cUPropSet)
  3019. break;
  3020. }
  3021. return NOERROR;
  3022. }
  3023. // Translate Rowset IIDs to PROPSET structures ready to pass to SetProperties
  3024. HRESULT ConvertRowsetIIDtoDBPROPSET(const IID* piid, DBPROPSET* pPropSet)
  3025. {
  3026. HRESULT hr = S_OK;
  3027. DBPROP* pProp;
  3028. ATLASSERT( piid || pPropSet );
  3029. ATLASSERT( (pPropSet->cProperties == 1) || (pPropSet->rgProperties) );
  3030. pProp = &(pPropSet->rgProperties[0]);
  3031. if(InlineIsEqualGUID(*piid, IID_IAccessor))
  3032. pProp->dwPropertyID = DBPROP_IAccessor;
  3033. else if(InlineIsEqualGUID(*piid,IID_IColumnsInfo))
  3034. pProp->dwPropertyID = DBPROP_IColumnsInfo;
  3035. else if(InlineIsEqualGUID(*piid , IID_IRowset))
  3036. pProp->dwPropertyID = DBPROP_IRowset;
  3037. else if(InlineIsEqualGUID(*piid , IID_IRowsetInfo))
  3038. pProp->dwPropertyID = DBPROP_IRowsetInfo;
  3039. else if(InlineIsEqualGUID(*piid , IID_IRowsetLocate))
  3040. pProp->dwPropertyID = DBPROP_IRowsetLocate;
  3041. else if(InlineIsEqualGUID(*piid , IID_IColumnsRowset))
  3042. pProp->dwPropertyID = DBPROP_IColumnsRowset;
  3043. else if(InlineIsEqualGUID(*piid , IID_IRowsetResynch))
  3044. pProp->dwPropertyID = DBPROP_IRowsetResynch;
  3045. else if(InlineIsEqualGUID(*piid , IID_IRowsetScroll))
  3046. pProp->dwPropertyID = DBPROP_IRowsetScroll;
  3047. else if(InlineIsEqualGUID(*piid , IID_IRowsetChange))
  3048. pProp->dwPropertyID = DBPROP_IRowsetChange;
  3049. else if(InlineIsEqualGUID(*piid , IID_IRowsetUpdate))
  3050. pProp->dwPropertyID = DBPROP_IRowsetUpdate;
  3051. else if(InlineIsEqualGUID(*piid , IID_IRowsetIdentity))
  3052. pProp->dwPropertyID = DBPROP_IRowsetIdentity;
  3053. else if(InlineIsEqualGUID(*piid , IID_IConnectionPointContainer))
  3054. pProp->dwPropertyID = DBPROP_IConnectionPointContainer;
  3055. else if(InlineIsEqualGUID(*piid , IID_ISupportErrorInfo))
  3056. pProp->dwPropertyID = DBPROP_ISupportErrorInfo;
  3057. else if(InlineIsEqualGUID(*piid , IID_IRowsetIndex))
  3058. pProp->dwPropertyID = DBPROP_IRowsetIndex;
  3059. #if( OLEDBVER >= 0x0200 )
  3060. else if(InlineIsEqualGUID(*piid , IID_IRowsetLockRows))
  3061. pProp->dwPropertyID = DBPROP_IRowsetLockRows;
  3062. else if(InlineIsEqualGUID(*piid , IID_IProvideMoniker))
  3063. pProp->dwPropertyID = DBPROP_IProvideMoniker;
  3064. else if(InlineIsEqualGUID(*piid , IID_IRowsetNotify))
  3065. pProp->dwPropertyID = DBPROP_IRowsetNotify;
  3066. else if(InlineIsEqualGUID(*piid , IID_IReadData))
  3067. pProp->dwPropertyID = DBPROP_IReadData;
  3068. else if(InlineIsEqualGUID(*piid , IID_IRowsetExactScroll))
  3069. pProp->dwPropertyID = DBPROP_IRowsetExactScroll;
  3070. else if(InlineIsEqualGUID(*piid , IID_IRowsetNextRowset))
  3071. pProp->dwPropertyID = DBPROP_IRowsetNextRowset;
  3072. else if(InlineIsEqualGUID(*piid , IID_IRowsetDelete))
  3073. pProp->dwPropertyID = DBPROP_IRowsetDelete;
  3074. else if(InlineIsEqualGUID(*piid , IID_IRowsetDeleteBookmarks))
  3075. pProp->dwPropertyID = DBPROP_IRowsetDeleteBookmarks;
  3076. else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRow))
  3077. pProp->dwPropertyID = DBPROP_IRowsetNewRow;
  3078. else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRowAfter))
  3079. pProp->dwPropertyID = DBPROP_IRowsetNewRowAfter;
  3080. else if(InlineIsEqualGUID(*piid , IID_IRowsetWithParameters))
  3081. pProp->dwPropertyID = DBPROP_IRowsetWithParameters;
  3082. else if(InlineIsEqualGUID(*piid , IID_IRowsetFind))
  3083. pProp->dwPropertyID = DBPROP_IRowsetFind;
  3084. else if(InlineIsEqualGUID(*piid , IID_IRowsetAsynch))
  3085. pProp->dwPropertyID = DBPROP_IRowsetAsynch;
  3086. else if(InlineIsEqualGUID(*piid , IID_IRowsetKeys))
  3087. pProp->dwPropertyID = DBPROP_IRowsetKeys;
  3088. else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchAll))
  3089. pProp->dwPropertyID = DBPROP_IRowsetWatchAll;
  3090. else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchNotify))
  3091. pProp->dwPropertyID = DBPROP_IRowsetWatchNotify;
  3092. else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchRegion))
  3093. pProp->dwPropertyID = DBPROP_IRowsetWatchRegion;
  3094. else if(InlineIsEqualGUID(*piid , IID_IRowsetCopyRows))
  3095. pProp->dwPropertyID = DBPROP_IRowsetCopyRows;
  3096. #endif //#if( OLEDBVER >= 0x0200 )
  3097. else
  3098. hr = S_FALSE;
  3099. // If the IID can be mapped to a DBPROPID, the
  3100. // we need to initialize the vValue to TRUE
  3101. if(hr == S_OK)
  3102. {
  3103. // Set PropertySet
  3104. pPropSet->guidPropertySet = DBPROPSET_ROWSET;
  3105. // Set Property
  3106. pProp->dwOptions = DBPROPOPTIONS_REQUIRED;
  3107. pProp->dwStatus = 0;
  3108. pProp->colid = DB_NULLID;
  3109. VariantInit(&(pProp->vValue));
  3110. pProp->vValue.vt = VT_BOOL;
  3111. V_BOOL(&(pProp->vValue)) = VARIANT_TRUE;
  3112. }
  3113. return hr;
  3114. }
  3115. void SetPropertyInError(const ULONG iPropSet, const ULONG iPropId)
  3116. {
  3117. SETBIT(&(m_rgdwPropsInError[iPropSet * m_cElemPerSupported]), iPropId);
  3118. }
  3119. BOOL IsPropSet(const GUID* pguidPropSet, DBPROPID dwPropId)
  3120. {
  3121. HRESULT hr;
  3122. ULONG iPropSet;
  3123. ULONG iPropId;
  3124. VARIANT vValue;
  3125. DWORD dwOptions;
  3126. VariantInit(&vValue);
  3127. if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3128. {
  3129. if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3130. {
  3131. if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags &
  3132. (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3133. {
  3134. ULONG iPropVal = GetUPropValIndex(iPropSet, dwPropId);
  3135. dwOptions = m_pUProp[iPropSet].pUPropVal[iPropVal].dwOption;
  3136. hr = VariantCopy(&vValue, &(m_pUProp[iPropSet].
  3137. pUPropVal[iPropVal].vValue));
  3138. }
  3139. else
  3140. {
  3141. hr = GetDefaultValue(iPropSet, dwPropId,
  3142. &dwOptions, &vValue);
  3143. }
  3144. if( dwOptions == DBPROPOPTIONS_REQUIRED )
  3145. {
  3146. ATLASSERT( vValue.vt == VT_BOOL );
  3147. if( SUCCEEDED(hr) &&
  3148. (V_BOOL(&vValue) == VARIANT_TRUE) )
  3149. {
  3150. VariantClear(&vValue);
  3151. return TRUE;
  3152. }
  3153. }
  3154. }
  3155. }
  3156. VariantClear(&vValue);
  3157. return FALSE;
  3158. }
  3159. OUT_OF_LINE HRESULT GetPropValue(const GUID* pguidPropSet, DBPROPID dwPropId, VARIANT* pvValue)
  3160. {
  3161. HRESULT hr = E_FAIL;
  3162. ULONG iPropSet;
  3163. ULONG iPropId = 0;
  3164. DWORD dwOptions;
  3165. if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3166. {
  3167. if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3168. {
  3169. if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3170. {
  3171. hr = VariantCopy(pvValue, &(m_pUProp[iPropSet].pUPropVal[
  3172. GetUPropValIndex(iPropSet, dwPropId)].vValue));
  3173. }
  3174. else
  3175. {
  3176. VariantClear(pvValue);
  3177. hr = GetDefaultValue(iPropSet, dwPropId,
  3178. &dwOptions, pvValue);
  3179. }
  3180. }
  3181. }
  3182. return hr;
  3183. }
  3184. HRESULT SetPropValue(const GUID* pguidPropSet,DBPROPID dwPropId, VARIANT* pvValue)
  3185. {
  3186. HRESULT hr = E_FAIL;
  3187. ULONG iPropSet;
  3188. ULONG iPropId;
  3189. if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3190. {
  3191. if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3192. {
  3193. ATLASSERT( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) );
  3194. hr = VariantCopy(&(m_pUProp[iPropSet].pUPropVal[
  3195. GetUPropValIndex(iPropSet, dwPropId)].vValue), pvValue);
  3196. }
  3197. }
  3198. return hr;
  3199. }
  3200. //Pointer to properties in error mask
  3201. DWORD* GetPropsInErrorPtr(){return m_rgdwPropsInError;}
  3202. ULONG GetUPropSetCount() {return m_cUPropSet;}
  3203. void SetUPropSetCount(ULONG c) {m_cUPropSet = c;}
  3204. // NOTE: The following functions depend on all prior
  3205. // properties in the array being writable.
  3206. // This is because the UPROP array contains only writable elements,
  3207. // and the UPROPINFO array contains writable and read-only elements.
  3208. // (If this is a problem, we would need to define which one it came from
  3209. // and add the appropriate ATLASSERTs...)
  3210. //Get DBPROPOPTIONS_xx
  3211. DWORD GetPropOption(ULONG iPropSet, ULONG iProp)
  3212. {
  3213. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3214. return m_pUProp[iPropSet].pUPropVal[iProp].dwOption;
  3215. }
  3216. //Set DBPROPOPTIONS_xx
  3217. void SetPropOption(ULONG iPropSet, ULONG iProp, DWORD dwOption)
  3218. {
  3219. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3220. m_pUProp[iPropSet].pUPropVal[iProp].dwOption = dwOption;
  3221. }
  3222. //Determine if property is required and variant_true
  3223. BOOL IsRequiredTrue(ULONG iPropSet, ULONG iProp)
  3224. {
  3225. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3226. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
  3227. ATLASSERT(V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE
  3228. || V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_FALSE);
  3229. return( (m_pUProp[iPropSet].pUPropVal[iProp].dwOption == DBPROPOPTIONS_REQUIRED) &&
  3230. (V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE) );
  3231. }
  3232. DWORD GetInternalFlags(ULONG iPropSet, ULONG iProp)
  3233. {
  3234. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3235. return m_pUProp[iPropSet].pUPropVal[iProp].dwFlags;
  3236. }
  3237. void AddInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
  3238. {
  3239. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3240. m_pUProp[iPropSet].pUPropVal[iProp].dwFlags |= dwFlags;
  3241. }
  3242. void RemoveInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
  3243. {
  3244. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3245. m_pUProp[iPropSet].pUPropVal[iProp].dwFlags &= ~dwFlags;
  3246. }
  3247. VARIANT * GetVariant(ULONG iPropSet, ULONG iProp)
  3248. {
  3249. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3250. return & m_pUProp[iPropSet].pUPropVal[iProp].vValue;
  3251. }
  3252. HRESULT SetVariant(ULONG iPropSet, ULONG iProp, VARIANT *pv )
  3253. {
  3254. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3255. // Does VariantClear first.
  3256. return VariantCopy( &m_pUProp[iPropSet].pUPropVal[iProp].vValue, pv );
  3257. }
  3258. void SetValEmpty(ULONG iPropSet, ULONG iProp)
  3259. {
  3260. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3261. VariantClear( &m_pUProp[iPropSet].pUPropVal[iProp].vValue );
  3262. }
  3263. BOOL IsEmpty(ULONG iPropSet, ULONG iProp)
  3264. {
  3265. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3266. return ( m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_EMPTY);
  3267. }
  3268. void SetValBool(ULONG iPropSet, ULONG iProp, VARIANT_BOOL bVal)
  3269. {
  3270. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3271. // Note that we accept any "true" value.
  3272. VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3273. m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_BOOL;
  3274. V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) = (bVal ? VARIANT_TRUE : VARIANT_FALSE);
  3275. }
  3276. VARIANT_BOOL GetValBool(ULONG iPropSet, ULONG iProp)
  3277. {
  3278. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3279. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
  3280. return V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3281. }
  3282. void SetValShort(ULONG iPropSet, ULONG iProp, SHORT iVal )
  3283. {
  3284. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3285. VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3286. m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I2;
  3287. m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal = iVal;
  3288. }
  3289. SHORT GetValShort(ULONG iPropSet, ULONG iProp)
  3290. {
  3291. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3292. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I2);
  3293. return m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal;
  3294. }
  3295. void SetValLong(ULONG iPropSet, ULONG iProp, LONG lVal)
  3296. {
  3297. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3298. VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3299. m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I4;
  3300. m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal = lVal;
  3301. }
  3302. LONG GetValLong(ULONG iPropSet, ULONG iProp)
  3303. {
  3304. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3305. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I4);
  3306. return m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal;
  3307. }
  3308. HRESULT SetValString(ULONG iPropSet, ULONG iProp, const WCHAR *pwsz)
  3309. {
  3310. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3311. VARIANT *pv = &m_pUProp[iPropSet].pUPropVal[iProp].vValue;
  3312. VariantClear(pv);
  3313. pv->bstrVal = SysAllocString(pwsz);
  3314. if (pv->bstrVal)
  3315. pv->vt = VT_BSTR;
  3316. else
  3317. return E_FAIL;
  3318. // See if this was used for non-string type.
  3319. // Typically this is an easy way to pass integer as a string.
  3320. if (GetExpectedVarType(iPropSet,iProp) == VT_BSTR)
  3321. return NOERROR;
  3322. if (pwsz[0] != L'\0')
  3323. return VariantChangeType( pv, pv, 0, GetExpectedVarType(iPropSet,iProp) );
  3324. // Set to "", which for non-string means empty.
  3325. SysFreeString(pv->bstrVal);
  3326. pv->vt = VT_EMPTY;
  3327. return NOERROR;
  3328. }
  3329. const WCHAR * GetValString(ULONG iPropSet, ULONG iProp)
  3330. {
  3331. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3332. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BSTR);
  3333. return m_pUProp[iPropSet].pUPropVal[iProp].vValue.bstrVal;
  3334. }
  3335. const GUID * GetGuid(ULONG iPropSet)
  3336. {
  3337. ATLASSERT(iPropSet < m_cUPropSet);
  3338. return m_pUPropSet[iPropSet].pPropSet;
  3339. }
  3340. DWORD GetPropID(ULONG iPropSet, ULONG iProp)
  3341. {
  3342. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3343. return m_pUPropSet[iPropSet].pUPropInfo[iProp].dwPropId;
  3344. }
  3345. VARTYPE GetExpectedVarType(ULONG iPropSet, ULONG iProp)
  3346. {
  3347. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3348. return m_pUPropSet[iPropSet].pUPropInfo[iProp].VarType;
  3349. }
  3350. virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet)
  3351. {
  3352. ATLASSERT(pPropSet && pulCurSet);
  3353. for(ULONG ul=0; ul<m_cUPropSet; ul++)
  3354. {
  3355. if( *pPropSet == *(m_pUPropSet[ul].pPropSet) )
  3356. {
  3357. *pulCurSet = ul;
  3358. return S_OK;
  3359. }
  3360. }
  3361. return S_FALSE;
  3362. }
  3363. virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/)
  3364. {
  3365. return S_OK;
  3366. }
  3367. virtual HRESULT InitUPropSetsSupported()
  3368. {
  3369. return InternalInitUPropSetsSupported(T::_GetPropSet);
  3370. }
  3371. HRESULT GetIndexOfPropertyInSet(const GUID* pPropSet, DBPROPID dwPropertyId, ULONG* piCurPropId, ULONG* piCurSet)
  3372. {
  3373. HRESULT hr = GetIndexofPropSet(pPropSet, piCurSet);
  3374. if (hr == S_FALSE)
  3375. return hr;
  3376. UPROPINFO* pUPropInfo = m_pUPropSet[*piCurSet].pUPropInfo;
  3377. for(ULONG ul=0; ul<m_pUPropSet[*piCurSet].cUPropInfo; ul++)
  3378. {
  3379. if( dwPropertyId == pUPropInfo[ul].dwPropId )
  3380. *piCurPropId = ul;
  3381. return S_OK;
  3382. }
  3383. return S_FALSE;
  3384. }
  3385. HRESULT SetSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
  3386. {
  3387. ULONG iCurPropId, iCurSet;
  3388. if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3389. {
  3390. m_rgdwSupported[iCurSet * m_cElemPerSupported] |= 1 << iCurPropId;
  3391. return S_OK;
  3392. }
  3393. return S_FALSE;
  3394. }
  3395. HRESULT ClearSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
  3396. {
  3397. ULONG iCurPropId, iCurSet;
  3398. if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3399. {
  3400. m_rgdwSupported[iCurSet * m_cElemPerSupported] &= ~( 1 << iCurPropId);
  3401. return S_OK;
  3402. }
  3403. return S_FALSE;
  3404. }
  3405. HRESULT TestSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId, bool& bSet)
  3406. {
  3407. ULONG iCurPropId, iCurSet;
  3408. if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3409. {
  3410. bSet = (m_rgdwSupported[iCurSet * m_cElemPerSupported] & ( 1 << iCurPropId)) != 0;
  3411. return S_OK;
  3412. }
  3413. return S_FALSE;
  3414. }
  3415. void CopyPropsInError(DWORD* rgdwSupported)
  3416. {
  3417. memcpy(rgdwSupported, m_rgdwPropsInError, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
  3418. }
  3419. };
  3420. // IDBPropertiesImpl
  3421. // IDBProperties <- IUnknown
  3422. template <class T>
  3423. class ATL_NO_VTABLE IDBPropertiesImpl : public IDBProperties, public CUtlProps<T>
  3424. {
  3425. public:
  3426. STDMETHOD(GetProperties)(ULONG cPropertySets,
  3427. const DBPROPIDSET rgPropertySets[],
  3428. ULONG *pcProperties,
  3429. DBPROPSET **prgProperties)
  3430. {
  3431. ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetProperties\n");
  3432. T* pT = (T*)this;
  3433. HRESULT hr = GetPropertiesArgChk(cPropertySets, rgPropertySets, pcProperties, prgProperties);
  3434. if (FAILED(hr))
  3435. return hr;
  3436. if(SUCCEEDED(hr))
  3437. {
  3438. // Check for other invalid arguments
  3439. for (ULONG i=0; i<cPropertySets; i++)
  3440. {
  3441. if (InlineIsEqualGUID(rgPropertySets[i].guidPropertySet, DBPROPSET_PROPERTIESINERROR))
  3442. if (pcProperties != NULL || prgProperties != NULL || cPropertySets > 1)
  3443. return E_INVALIDARG;
  3444. }
  3445. }
  3446. if (SUCCEEDED(hr))
  3447. {
  3448. const GUID* ppGuid[3];
  3449. if (pT->m_dwStatus & DSF_INITIALIZED)
  3450. {
  3451. ppGuid[0] = &DBPROPSET_DBINIT;
  3452. ppGuid[1] = &DBPROPSET_DATASOURCE;
  3453. ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
  3454. hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets,
  3455. pcProperties, prgProperties, 3, ppGuid);
  3456. }
  3457. else
  3458. {
  3459. ppGuid[0] = &DBPROPSET_DBINIT;
  3460. hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets,
  3461. pcProperties, prgProperties, 1, ppGuid);
  3462. }
  3463. }
  3464. return hr;
  3465. }
  3466. STDMETHOD(GetPropertyInfo)(ULONG cPropertySets,
  3467. const DBPROPIDSET rgPropertySets[],
  3468. ULONG *pcPropertyInfoSets,
  3469. DBPROPINFOSET **prgPropertyInfoSets,
  3470. OLECHAR **ppDescBuffer)
  3471. {
  3472. ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetPropertyInfo\n");
  3473. T* pT = (T*)this;
  3474. if (pT->m_pCUtlPropInfo == NULL)
  3475. {
  3476. // Go ahead and create the m_pCUtlPropInfo but do not change the
  3477. // Initialized status of the provider (see IDBInitialize::Initialize).
  3478. ATLTRACE2(atlTraceDBProvider, 0, "m_pCUtlPropInfo == NULL\n");
  3479. pT->Lock();
  3480. delete pT->m_pCUtlPropInfo;
  3481. ATLTRY(pT->m_pCUtlPropInfo = new CUtlPropInfo<T>())
  3482. pT->Unlock();
  3483. if (pT->m_pCUtlPropInfo == NULL)
  3484. {
  3485. ATLTRACE2(atlTraceDBProvider, 0, "IDBProperties::GetPropertyInfo Error : OOM\n");
  3486. return E_OUTOFMEMORY;
  3487. }
  3488. HRESULT hr = pT->m_pCUtlPropInfo->FInit();
  3489. if (hr != S_OK)
  3490. {
  3491. pT->Lock();
  3492. delete pT->m_pCUtlPropInfo;
  3493. pT->m_pCUtlPropInfo = NULL;
  3494. pT->Unlock();
  3495. }
  3496. }
  3497. // Initialize
  3498. if( pcPropertyInfoSets )
  3499. *pcPropertyInfoSets = 0;
  3500. if( prgPropertyInfoSets )
  3501. *prgPropertyInfoSets = NULL;
  3502. if( ppDescBuffer )
  3503. *ppDescBuffer = NULL;
  3504. // Check Arguments
  3505. if( ((cPropertySets > 0) && !rgPropertySets) ||
  3506. !pcPropertyInfoSets || !prgPropertyInfoSets )
  3507. return E_INVALIDARG;
  3508. // New argument check for > 1 cPropertyIDs and NULL pointer for
  3509. // array of property ids.
  3510. const DWORD SPECIAL_GROUP = 1;
  3511. const DWORD SPECIAL_SINGLE = 2;
  3512. const DWORD SPECIALS = SPECIAL_GROUP | SPECIAL_SINGLE;
  3513. DWORD dwSpecial = 0;
  3514. for(ULONG ul=0; ul<cPropertySets; ul++)
  3515. {
  3516. if( (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEALL) ||
  3517. (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEINFOALL) ||
  3518. (rgPropertySets[ul].guidPropertySet == DBPROPSET_DBINITALL) ||
  3519. (rgPropertySets[ul].guidPropertySet == DBPROPSET_SESSIONALL) ||
  3520. (rgPropertySets[ul].guidPropertySet == DBPROPSET_ROWSETALL) )
  3521. dwSpecial |= SPECIAL_GROUP;
  3522. else
  3523. dwSpecial |= SPECIAL_SINGLE;
  3524. if( (dwSpecial == SPECIALS) ||
  3525. (rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs)) )
  3526. return E_INVALIDARG;
  3527. }
  3528. if (pT->m_dwStatus & DSF_INITIALIZED)
  3529. return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets,
  3530. pcPropertyInfoSets, prgPropertyInfoSets,
  3531. ppDescBuffer, true);
  3532. else
  3533. return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets,
  3534. pcPropertyInfoSets, prgPropertyInfoSets,
  3535. ppDescBuffer, false, &DBPROPSET_DBINITALL);
  3536. }
  3537. STDMETHOD(SetProperties)(ULONG cPropertySets,
  3538. DBPROPSET rgPropertySets[])
  3539. {
  3540. ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::SetProperties\n");
  3541. HRESULT hr;
  3542. DBPROPSET* pdbPropSet = NULL;
  3543. ULONG iProp;
  3544. const GUID* ppGuid[3];
  3545. T* pT = (T*)this;
  3546. // Quick return if the Count of Properties is 0
  3547. if( cPropertySets == 0 )
  3548. return S_OK;
  3549. hr = CUtlProps<T>::SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3550. if(SUCCEEDED(hr))
  3551. {
  3552. // We need to handle the DBINIT properties specially after being initialized.
  3553. // - they should be treated as NOTSETTABLE at this point.
  3554. if( pT->m_dwStatus & DSF_INITIALIZED )
  3555. {
  3556. ATLASSERT(cPropertySets);
  3557. BOOL fFoundDBINIT = FALSE;
  3558. // Allocate a DBPROPSET structure of equal size
  3559. ATLTRY(pdbPropSet = new DBPROPSET[cPropertySets])
  3560. if( pdbPropSet == NULL )
  3561. return E_OUTOFMEMORY;
  3562. for(ULONG iNewSet=0,iSet=0; iSet<cPropertySets; iSet++)
  3563. {
  3564. // Remove any DBPROPSET_DBINIT values and mark them all
  3565. // as not settable
  3566. if( (rgPropertySets[iSet].guidPropertySet == DBPROPSET_DBINIT))
  3567. {
  3568. fFoundDBINIT = TRUE;
  3569. for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++)
  3570. rgPropertySets[iSet].rgProperties[iProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
  3571. }
  3572. else
  3573. {
  3574. // If not DBPROPSET_DBINIT then copy the DBPROPSET values
  3575. memcpy(&pdbPropSet[iNewSet++], &rgPropertySets[iSet], sizeof(DBPROPSET));
  3576. }
  3577. }
  3578. // If we have no propertyset to pass on to the property handler, we
  3579. // can exit
  3580. if( iNewSet == 0 )
  3581. {
  3582. hr = DB_E_ERRORSOCCURRED;
  3583. goto exit;
  3584. }
  3585. ppGuid[0] = &DBPROPSET_DBINIT;
  3586. ppGuid[1] = &DBPROPSET_DATASOURCE;
  3587. ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
  3588. hr = CUtlProps<T>::SetProperties(0, iNewSet, pdbPropSet, 3, ppGuid);
  3589. // If we have determined that one of the property sets was DBINIT, we may
  3590. // need to fixup the returned hr value.
  3591. if( fFoundDBINIT && SUCCEEDED(hr))
  3592. hr = DB_S_ERRORSOCCURRED;
  3593. }
  3594. else
  3595. {
  3596. // Note that m_pCUtlProps knows about initialization,
  3597. // so we don't have to here.
  3598. ppGuid[0] = &DBPROPSET_DBINIT;
  3599. hr = CUtlProps<T>::SetProperties(0, cPropertySets, rgPropertySets,
  3600. 1, ppGuid);
  3601. }
  3602. }
  3603. exit:
  3604. delete[] pdbPropSet;
  3605. return hr;
  3606. }
  3607. };
  3608. #define BEGIN_SCHEMA_MAP(SchemaClass) \
  3609. typedef SchemaClass _SchemaClass; \
  3610. HRESULT _SchemaSupport(GUID** ppGuid, \
  3611. IUnknown *pUnkOuter, \
  3612. REFIID rguidSchema, \
  3613. ULONG cRestrictions, \
  3614. const VARIANT rgRestrictions[], \
  3615. REFIID riid, \
  3616. ULONG cPropertySets, \
  3617. DBPROPSET rgPropertySets[], \
  3618. IUnknown **ppRowset) \
  3619. { \
  3620. int cGuids = 0; \
  3621. HRESULT hr = S_OK; \
  3622. if (ppGuid != NULL) \
  3623. *ppGuid = NULL;
  3624. #define SCHEMA_ENTRY(guid, rowsetClass) \
  3625. if (ppGuid != NULL && SUCCEEDED(hr)) \
  3626. { \
  3627. cGuids++; \
  3628. *ppGuid = (GUID*)CoTaskMemRealloc(*ppGuid, cGuids * sizeof(GUID)); \
  3629. hr = (*ppGuid == NULL) ? E_OUTOFMEMORY : S_OK; \
  3630. if (SUCCEEDED(hr)) \
  3631. (*ppGuid)[cGuids - 1] = guid; \
  3632. } \
  3633. else \
  3634. { \
  3635. if (InlineIsEqualGUID(guid, rguidSchema)) \
  3636. { \
  3637. rowsetClass* pRowset; \
  3638. hr = CreateSchemaRowset(pUnkOuter, cRestrictions, \
  3639. rgRestrictions, riid, cPropertySets, \
  3640. rgPropertySets, ppRowset, pRowset); \
  3641. return hr; \
  3642. } \
  3643. }
  3644. #define END_SCHEMA_MAP() \
  3645. if (ppGuid != NULL) \
  3646. return hr; \
  3647. return E_INVALIDARG; \
  3648. }
  3649. template <class SessionClass>
  3650. class ATL_NO_VTABLE IDBSchemaRowsetImpl: public IDBSchemaRowset
  3651. {
  3652. public:
  3653. OUT_OF_LINE HRESULT InternalCreateSchemaRowset(IUnknown *pUnkOuter, ULONG /*cRestrictions*/,
  3654. const VARIANT /*rgRestrictions*/[], REFIID riid,
  3655. ULONG cPropertySets, DBPROPSET rgPropertySets[],
  3656. IUnknown** ppRowset, IUnknown* pUnkThis, CUtlPropsBase* pProps,
  3657. IUnknown* pUnkSession)
  3658. {
  3659. HRESULT hr, hrProps = S_OK;
  3660. if (ppRowset != NULL)
  3661. *ppRowset = NULL;
  3662. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  3663. return DB_E_NOAGGREGATION;
  3664. CComPtr<IUnknown> spUnk;
  3665. hr = pUnkThis->QueryInterface(IID_IUnknown, (void**)&spUnk);
  3666. if (FAILED(hr))
  3667. return hr;
  3668. hr = pProps->FInit();
  3669. if (FAILED(hr))
  3670. return hr;
  3671. hr = pProps->SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3672. if (FAILED(hr))
  3673. return hr;
  3674. const GUID* ppGuid[1];
  3675. ppGuid[0] = &DBPROPSET_ROWSET;
  3676. // Call SetProperties. The true in the last parameter indicates
  3677. // the special behavior that takes place on rowset creation (i.e.
  3678. // it succeeds as long as any of the properties were not marked
  3679. // as DBPROPS_REQUIRED.
  3680. hrProps = pProps->SetProperties(0, cPropertySets, rgPropertySets,
  3681. 1, ppGuid, true);
  3682. if (FAILED(hrProps))
  3683. return hrProps;
  3684. if (ppRowset == NULL)
  3685. return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
  3686. CComQIPtr<IObjectWithSite> spSite = spUnk;
  3687. ATLASSERT(spSite != NULL);
  3688. hr = spSite->SetSite(pUnkSession);
  3689. if (FAILED(hr))
  3690. return hr;
  3691. if (InlineIsEqualGUID(riid, IID_NULL))
  3692. return E_NOINTERFACE;
  3693. hr = spUnk->QueryInterface(riid, (void**)ppRowset);
  3694. if (FAILED(hr))
  3695. {
  3696. *ppRowset = NULL;
  3697. return hr;
  3698. }
  3699. return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  3700. }
  3701. template <class SchemaRowsetClass>
  3702. HRESULT CreateSchemaRowset(IUnknown *pUnkOuter, ULONG cRestrictions,
  3703. const VARIANT rgRestrictions[], REFIID riid,
  3704. ULONG cPropertySets, DBPROPSET rgPropertySets[],
  3705. IUnknown** ppRowset, SchemaRowsetClass*& pSchemaRowset)
  3706. {
  3707. HRESULT hrProps, hr = S_OK;
  3708. SessionClass* pT = (SessionClass*) this;
  3709. CComPolyObject<SchemaRowsetClass>* pPolyObj;
  3710. if (FAILED(hr = CComPolyObject<SchemaRowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  3711. return hr;
  3712. pSchemaRowset = &(pPolyObj->m_contained);
  3713. hr = InternalCreateSchemaRowset(pUnkOuter, cRestrictions, rgRestrictions,
  3714. riid, cPropertySets, rgPropertySets, ppRowset,
  3715. pPolyObj, pT, pT->GetUnknown());
  3716. // Ref the created COM object and Auto release it on failure
  3717. if (FAILED(hr))
  3718. return hr;
  3719. hrProps = hr;
  3720. // Get a pointer to the Rowset instance
  3721. LONG cRowsAffected;
  3722. hr = pSchemaRowset->Execute(&cRowsAffected, cRestrictions, rgRestrictions);
  3723. if (FAILED(hr))
  3724. return hr;
  3725. return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  3726. }
  3727. void SetRestrictions(ULONG cRestrictions, GUID* /*rguidSchema*/, ULONG* rgRestrictions)
  3728. {
  3729. memset(rgRestrictions, 0, sizeof(ULONG) * cRestrictions);
  3730. }
  3731. STDMETHOD(GetSchemas)(ULONG * pcSchemas, GUID ** prgSchemas, ULONG** prgRest)
  3732. {
  3733. ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetSchemas\n");
  3734. if (pcSchemas != NULL)
  3735. *pcSchemas = 0;
  3736. if (prgSchemas != NULL)
  3737. *prgSchemas = NULL;
  3738. if (pcSchemas == NULL || prgSchemas == NULL)
  3739. return E_INVALIDARG;
  3740. SessionClass* pT = (SessionClass*)this;
  3741. HRESULT hr = pT->_SchemaSupport(prgSchemas, NULL, GUID_NULL, 0,
  3742. NULL, GUID_NULL, 0, NULL, NULL);
  3743. if (FAILED(hr))
  3744. return hr;
  3745. CComPtr<IMalloc> spMalloc;
  3746. hr = CoGetMalloc(1, &spMalloc);
  3747. if (FAILED(hr))
  3748. {
  3749. CoTaskMemFree(*prgSchemas);
  3750. *prgSchemas = NULL;
  3751. return hr;
  3752. }
  3753. *pcSchemas = (ULONG)(ULONG_PTR)spMalloc->GetSize(*prgSchemas) / sizeof(GUID);
  3754. if (prgRest != NULL)
  3755. {
  3756. // The OLE DB spec states that if prgRest == NULL not to return array
  3757. // but it also says that is E_INVALIDARG, so doing first
  3758. *prgRest = (ULONG*) spMalloc->Alloc(sizeof(ULONG) * (*pcSchemas));
  3759. if (*prgRest == NULL)
  3760. {
  3761. spMalloc->Free(*prgSchemas);
  3762. *prgSchemas = NULL;
  3763. return E_OUTOFMEMORY;
  3764. }
  3765. pT->SetRestrictions(*pcSchemas, *prgSchemas, *prgRest);
  3766. }
  3767. return hr;
  3768. }
  3769. STDMETHOD(GetRowset)(IUnknown *pUnkOuter, REFGUID rguidSchema, ULONG cRestrictions,
  3770. const VARIANT rgRestrictions[], REFIID riid, ULONG cPropertySets,
  3771. DBPROPSET rgPropertySets[], IUnknown **ppRowset)
  3772. {
  3773. ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetRowset\n");
  3774. SessionClass* pT = (SessionClass*)this;
  3775. return pT->_SchemaSupport(NULL, pUnkOuter, rguidSchema, cRestrictions,
  3776. rgRestrictions, riid, cPropertySets,
  3777. rgPropertySets, ppRowset);
  3778. }
  3779. };
  3780. // IDBCreateCommandImpl
  3781. template <class T, class CommandClass>
  3782. class ATL_NO_VTABLE IDBCreateCommandImpl : public IDBCreateCommand
  3783. {
  3784. public:
  3785. STDMETHOD(CreateCommand)(IUnknown *pUnkOuter,
  3786. REFIID riid,
  3787. IUnknown **ppvCommand)
  3788. {
  3789. ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateCommandImpl::CreateCommand\n");
  3790. if (ppvCommand == NULL)
  3791. return E_INVALIDARG;
  3792. HRESULT hr;
  3793. CComPolyObject<CommandClass>* pCommand;
  3794. // You can't QI for an interface other than IUnknown when aggregating
  3795. // and creating the object. You might ask for your own interface,
  3796. // which would be bad. Note, we return DB_E_NOAGGREGATION instead of
  3797. // CLASS_E_NOAGGREGATION due to OLE DB constraints.
  3798. if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid))
  3799. return DB_E_NOAGGREGATION;
  3800. hr = CComPolyObject<CommandClass>::CreateInstance(pUnkOuter, &pCommand);
  3801. if (FAILED(hr))
  3802. return hr;
  3803. // Ref the created COM object and Auto release it on failure
  3804. CComPtr<IUnknown> spUnk;
  3805. hr = pCommand->QueryInterface(&spUnk);
  3806. if (FAILED(hr))
  3807. {
  3808. delete pCommand; // must hand delete as it is not ref'd
  3809. return hr;
  3810. }
  3811. ATLASSERT(pCommand->m_contained.m_spUnkSite == NULL);
  3812. pCommand->m_contained.SetSite(this);
  3813. hr = pCommand->QueryInterface(riid, (void**)ppvCommand);
  3814. return hr;
  3815. }
  3816. };
  3817. // IGetDataSourceImpl
  3818. template <class T>
  3819. class ATL_NO_VTABLE IGetDataSourceImpl : public IGetDataSource
  3820. {
  3821. public:
  3822. STDMETHOD(GetDataSource)(REFIID riid,
  3823. IUnknown **ppDataSource)
  3824. {
  3825. ATLTRACE2(atlTraceDBProvider, 0, "IGetDataSourceImpl::GetDataSource\n");
  3826. if (ppDataSource == NULL)
  3827. return E_INVALIDARG;
  3828. T* pT = (T*) this;
  3829. ATLASSERT(pT->m_spUnkSite != NULL);
  3830. return pT->m_spUnkSite->QueryInterface(riid, (void**)ppDataSource);
  3831. }
  3832. };
  3833. // IOpenRowsetImpl
  3834. template <class SessionClass>
  3835. class IOpenRowsetImpl : public IOpenRowset
  3836. {
  3837. public:
  3838. template <class RowsetClass>
  3839. HRESULT CreateRowset(IUnknown* pUnkOuter,
  3840. DBID *pTableID, DBID *pIndexID,
  3841. REFIID riid,
  3842. ULONG cPropertySets, DBPROPSET rgPropertySets[],
  3843. IUnknown** ppRowset,
  3844. RowsetClass*& pRowsetObj)
  3845. {
  3846. HRESULT hr, hrProps = S_OK;
  3847. if (ppRowset != NULL)
  3848. *ppRowset = NULL;
  3849. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  3850. return DB_E_NOAGGREGATION;
  3851. CComPolyObject<RowsetClass>* pPolyObj;
  3852. if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  3853. return hr;
  3854. // Ref the created COM object and Auto release it on failure
  3855. CComPtr<IUnknown> spUnk;
  3856. hr = pPolyObj->QueryInterface(&spUnk);
  3857. if (FAILED(hr))
  3858. {
  3859. delete pPolyObj; // must hand delete as it is not ref'd
  3860. return hr;
  3861. }
  3862. // Get a pointer to the Rowset instance
  3863. pRowsetObj = &(pPolyObj->m_contained);
  3864. hr = pRowsetObj->FInit();
  3865. if (FAILED(hr))
  3866. return hr;
  3867. hr = pRowsetObj->SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3868. if (FAILED(hr))
  3869. return hr;
  3870. const GUID* ppGuid[1];
  3871. ppGuid[0] = &DBPROPSET_ROWSET;
  3872. // Call SetProperties. The true in the last parameter indicates
  3873. // the special behavior that takes place on rowset creation (i.e.
  3874. // it succeeds as long as any of the properties were not marked
  3875. // as DBPROPS_REQUIRED.
  3876. hrProps = pRowsetObj->SetProperties(0, cPropertySets, rgPropertySets,
  3877. 1, ppGuid, true);
  3878. if (FAILED(hrProps))
  3879. return hrProps;
  3880. pRowsetObj->SetSite(((SessionClass*)this)->GetUnknown());
  3881. hr = pRowsetObj->SetCommandText(pTableID, pIndexID);
  3882. if (FAILED(hr))
  3883. return hr;
  3884. DBROWCOUNT cRowsAffected;
  3885. if (FAILED(hr = pRowsetObj->Execute(NULL, &cRowsAffected)))
  3886. return hr;
  3887. if (InlineIsEqualGUID(riid, IID_NULL))
  3888. {
  3889. return E_NOINTERFACE;
  3890. }
  3891. else
  3892. {
  3893. if (ppRowset == NULL)
  3894. return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
  3895. hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
  3896. }
  3897. if (FAILED(hr))
  3898. {
  3899. *ppRowset = NULL;
  3900. return hr;
  3901. }
  3902. return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  3903. }
  3904. };
  3905. // IColumnsInfoImpl
  3906. template <class T>
  3907. class ATL_NO_VTABLE IColumnsInfoImpl :
  3908. public IColumnsInfo,
  3909. public CDBIDOps
  3910. {
  3911. public:
  3912. HRESULT CheckCommandText(IUnknown* pUnkThis)
  3913. {
  3914. HRESULT hr = E_FAIL;
  3915. CComPtr<ICommandText> spText;
  3916. if (SUCCEEDED(hr = pUnkThis->QueryInterface(IID_ICommandText, (void**)&spText)))
  3917. {
  3918. LPOLESTR szCommand;
  3919. hr = spText->GetCommandText(NULL, &szCommand);
  3920. if (SUCCEEDED(hr))
  3921. CoTaskMemFree(szCommand);
  3922. }
  3923. return hr;
  3924. }
  3925. OUT_OF_LINE HRESULT InternalGetColumnInfo(DBORDINAL *pcColumns, ATLCOLUMNINFO** ppInfo)
  3926. {
  3927. ATLASSERT(ppInfo != NULL);
  3928. T* pT = (T*) this;
  3929. if (pT->CheckCommandText(pT->GetUnknown()) == DB_E_NOCOMMAND)
  3930. return DB_E_NOCOMMAND;
  3931. *ppInfo = T::GetColumnInfo(pT, pcColumns);
  3932. return S_OK;
  3933. }
  3934. STDMETHOD(GetColumnInfo)(DBORDINAL *pcColumns,
  3935. DBCOLUMNINFO **prgInfo,
  3936. OLECHAR **ppStringsBuffer)
  3937. {
  3938. ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::GetColumnInfo\n");
  3939. if (pcColumns == NULL || prgInfo == NULL || ppStringsBuffer == NULL)
  3940. {
  3941. if (prgInfo != NULL)
  3942. *prgInfo = NULL;
  3943. if (ppStringsBuffer != NULL)
  3944. *ppStringsBuffer = NULL;
  3945. if (pcColumns != NULL)
  3946. *pcColumns = NULL;
  3947. return E_INVALIDARG;
  3948. }
  3949. // NULL out pointers in case of an error
  3950. *prgInfo = NULL;
  3951. *ppStringsBuffer = NULL;
  3952. *pcColumns = 0;
  3953. ATLCOLUMNINFO* pInfo;
  3954. HRESULT hr = InternalGetColumnInfo(pcColumns, &pInfo);
  3955. if (FAILED(hr))
  3956. return hr;
  3957. ATLASSERT(pInfo != NULL);
  3958. *prgInfo = (DBCOLUMNINFO*)CoTaskMemAlloc(*pcColumns * sizeof(DBCOLUMNINFO));
  3959. if (*prgInfo != NULL)
  3960. {
  3961. for (DBORDINAL iCol = 0, cwRequired = 0; iCol < *pcColumns; iCol++)
  3962. {
  3963. memcpy(&((*prgInfo)[iCol]), &pInfo[iCol], sizeof(DBCOLUMNINFO));
  3964. if (pInfo[iCol].pwszName)
  3965. {
  3966. cwRequired += wcslen(pInfo[iCol].pwszName) + 1;
  3967. }
  3968. }
  3969. *ppStringsBuffer = (OLECHAR*)CoTaskMemAlloc(cwRequired*sizeof(OLECHAR));
  3970. if (*ppStringsBuffer)
  3971. {
  3972. for (DBORDINAL iCol = 0, iOffset = 0; iCol < *pcColumns; iCol++)
  3973. {
  3974. if (pInfo[iCol].pwszName)
  3975. {
  3976. lstrcpyW(*ppStringsBuffer + iOffset, pInfo[iCol].pwszName);
  3977. iOffset += wcslen(*ppStringsBuffer + iOffset) + 1;
  3978. }
  3979. }
  3980. return S_OK;
  3981. }
  3982. else
  3983. {
  3984. ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate string buffer\n"));
  3985. CoTaskMemFree(*prgInfo);
  3986. *prgInfo = NULL;
  3987. *pcColumns = 0;
  3988. return E_OUTOFMEMORY;
  3989. }
  3990. }
  3991. else
  3992. {
  3993. ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ColumnInfo array\n"));
  3994. *prgInfo = NULL;
  3995. *pcColumns = 0;
  3996. return E_OUTOFMEMORY;
  3997. }
  3998. }
  3999. STDMETHOD(MapColumnIDs)(DBORDINAL cColumnIDs,
  4000. const DBID rgColumnIDs[],
  4001. DBORDINAL rgColumns[])
  4002. {
  4003. ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::MapColumnIDs\n");
  4004. USES_CONVERSION;
  4005. if ((cColumnIDs != 0 && rgColumnIDs == NULL) || rgColumns == NULL)
  4006. return E_INVALIDARG;
  4007. DBORDINAL cCols = 0;
  4008. DBORDINAL cColsInError = 0;
  4009. HRESULT hr = S_OK;
  4010. ATLCOLUMNINFO* pInfo;
  4011. for (DBORDINAL iColId = 0; iColId < cColumnIDs; iColId++)
  4012. {
  4013. hr = InternalGetColumnInfo(&cCols, &pInfo);
  4014. if (hr == DB_E_NOCOMMAND)
  4015. return hr;
  4016. ULONG iColMapCur = 0;
  4017. BOOL bDone = FALSE;
  4018. while(iColMapCur < cCols && !bDone)
  4019. {
  4020. hr = CompareDBIDs(&(pInfo[iColMapCur].columnid), &(rgColumnIDs[iColId]));
  4021. bDone = (hr == S_OK || FAILED(hr));
  4022. if (hr == S_OK)
  4023. rgColumns[iColId] = pInfo[iColMapCur].iOrdinal;
  4024. iColMapCur++;
  4025. }
  4026. if (!bDone || FAILED(hr))
  4027. {
  4028. rgColumns[iColId] = DB_INVALIDCOLUMN;
  4029. cColsInError++;
  4030. }
  4031. }
  4032. if (cColsInError > 0 && cColumnIDs == cColsInError)
  4033. return DB_E_ERRORSOCCURRED;
  4034. if (cColsInError > 0 && cColsInError < cColumnIDs)
  4035. return DB_S_ERRORSOCCURRED;
  4036. return S_OK;
  4037. }
  4038. };
  4039. //IConvertTypeImpl
  4040. template <class T>
  4041. class ATL_NO_VTABLE IConvertTypeImpl : public IConvertType, public CConvertHelper
  4042. {
  4043. public:
  4044. HRESULT InternalCanConvert(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags,
  4045. bool bIsCommand, bool bHasParamaters, IObjectWithSite* pSite)
  4046. {
  4047. // Check to see if conversion types are invalid. Note, this is just a
  4048. // quick test as it would be difficult to check each available type
  4049. // (as new DBTYPE values can be added).
  4050. if ((wFromType & 0x8000) || (wToType & 0x8000))
  4051. return E_INVALIDARG;
  4052. // Determine if new 2.x flags are valid
  4053. if((dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_COLUMN
  4054. && (dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_PARAMETER )
  4055. return DB_E_BADCONVERTFLAG;
  4056. #ifdef _LATER
  4057. // If the convert flags are for DBCONVERTFLAGS_FROMVARIANT, check to see
  4058. // that the type is a variant type
  4059. if (dwConvertFlags == DBCONVERTFLAGS_FROMVARIANT)
  4060. {
  4061. if (wFromType != DBTYPE_VARIANT)
  4062. return DB_E_BADTYPE;
  4063. }
  4064. #endif // _LATER
  4065. // Note, if the convert flag is either ISLONG or ISFIXEDLENGTH, then we should
  4066. // make sure we are not dealing with an OLE DB 1.x provider. However, since
  4067. // we default to 2.x providers, we don't check this. If you, change the
  4068. // DBPROP_PROVIDEROLEDBVER property in the DATASOURCEINFO group, you need to
  4069. // check the property value and return a DB_E_BADCONVERTFLAG if it is a 1.x
  4070. // provider.
  4071. // Do we have ISLONG on a fixed length data type?
  4072. DBTYPE dbtype = wFromType & ~(DBTYPE_BYREF|DBTYPE_VECTOR|DBTYPE_ARRAY|DBTYPE_RESERVED);
  4073. if ((dwConvertFlags & DBCONVERTFLAGS_ISLONG) &&
  4074. (dbtype != DBTYPE_WSTR && dbtype != DBTYPE_STR && dbtype != DBTYPE_BYTES && dbtype != DBTYPE_VARNUMERIC))
  4075. return DB_E_BADCONVERTFLAG;
  4076. if (dwConvertFlags == DBCONVERTFLAGS_PARAMETER)
  4077. {
  4078. // In the case where we are a rowset and ask for a parameter
  4079. // conversion, return DB_E_BADCONVERTFLAG
  4080. if (!bIsCommand)
  4081. return DB_E_BADCONVERTFLAG;
  4082. // In the case where we are a command and ask for a parameter
  4083. // conversion and ICommandWithParameters is not supported, return
  4084. // S_FALSE. We just can't convert them.
  4085. if (!bHasParamaters)
  4086. return S_FALSE;
  4087. }
  4088. // If we deal with a command and the user asks for a conversion on a rowset
  4089. // the DBPROP_ROWSETCONVERSIONSONCOMMAND must be suppored and set to TRUE.
  4090. if (bIsCommand && dwConvertFlags == DBCONVERTFLAGS_COLUMN)
  4091. {
  4092. CDBPropIDSet set(DBPROPSET_DATASOURCEINFO);
  4093. set.AddPropertyID(DBPROP_ROWSETCONVERSIONSONCOMMAND);
  4094. DBPROPSET* pPropSet = NULL;
  4095. ULONG ulPropSet = 0;
  4096. //HRESULT hr1 = S_OK;
  4097. // Get a pointer into the session
  4098. CComPtr<IGetDataSource> spDataSource = NULL;
  4099. CComPtr<IDBProperties> spProps = NULL;
  4100. // if any of these calls fail, we're either unable to retrieve the
  4101. // property or it is unsupported. Since the property is only on
  4102. // the data source object, we use the IObjectWithSite interface to
  4103. // get the session object and then the GetDataSource method to get
  4104. // the data source object itself.
  4105. if (FAILED(pSite->GetSite(IID_IGetDataSource, (void**)&spDataSource)))
  4106. return DB_E_BADCONVERTFLAG;
  4107. if (FAILED(spDataSource->GetDataSource(IID_IDBProperties,
  4108. (IUnknown**)&spProps)))
  4109. return DB_E_BADCONVERTFLAG;
  4110. if (FAILED(spProps->GetProperties(1, &set, &ulPropSet, &pPropSet)))
  4111. return DB_E_BADCONVERTFLAG;
  4112. if (pPropSet != NULL)
  4113. {
  4114. CComVariant var = pPropSet->rgProperties[0].vValue;
  4115. CoTaskMemFree(pPropSet->rgProperties);
  4116. CoTaskMemFree(pPropSet);
  4117. if (var.boolVal == VARIANT_FALSE)
  4118. return DB_E_BADCONVERTFLAG;
  4119. }
  4120. }
  4121. HRESULT hr = E_FAIL;
  4122. if (m_spConvert != NULL)
  4123. {
  4124. hr = m_spConvert->CanConvert(wFromType, wToType);
  4125. }
  4126. return hr;
  4127. }
  4128. STDMETHOD(CanConvert)(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags)
  4129. {
  4130. ATLTRACE2(atlTraceDBProvider, 0, "IConvertTypeImpl::CanConvert\n");
  4131. T* pT = (T*)this;
  4132. return pT->InternalCanConvert(wFromType, wToType, dwConvertFlags, pT->m_bIsCommand, pT->m_bHasParamaters, pT);
  4133. }
  4134. };
  4135. template <class T, class PropClass = T>
  4136. class ATL_NO_VTABLE ICommandPropertiesImpl :
  4137. public ICommandProperties,
  4138. public CUtlProps<PropClass>
  4139. {
  4140. public:
  4141. typedef PropClass _PropClass;
  4142. STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
  4143. const DBPROPIDSET rgPropertyIDSets[],
  4144. ULONG *pcPropertySets,
  4145. DBPROPSET **prgPropertySets)
  4146. {
  4147. ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::GetProperties\n");
  4148. HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  4149. const GUID* ppGuid[1];
  4150. ppGuid[0] = &DBPROPSET_ROWSET;
  4151. if(SUCCEEDED(hr))
  4152. hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
  4153. rgPropertyIDSets, pcPropertySets, prgPropertySets,
  4154. 1, ppGuid);
  4155. return hr;
  4156. }
  4157. STDMETHOD(SetProperties)(ULONG cPropertySets,
  4158. DBPROPSET rgPropertySets[])
  4159. {
  4160. ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::SetProperties\n");
  4161. HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
  4162. const GUID* ppGuid[1];
  4163. ppGuid[0] = &DBPROPSET_ROWSET;
  4164. if(SUCCEEDED(hr))
  4165. hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets,
  4166. rgPropertySets, 1, ppGuid);
  4167. return hr;
  4168. }
  4169. };
  4170. template <class T>
  4171. class CRunTimeFree
  4172. {
  4173. public:
  4174. static void Free(T* pData)
  4175. {
  4176. delete [] pData;
  4177. }
  4178. };
  4179. template <class T>
  4180. class CComFree
  4181. {
  4182. public:
  4183. static void Free(T* pData)
  4184. {
  4185. CoTaskMemFree(pData);
  4186. }
  4187. };
  4188. template <class T, class DeAllocator = CRunTimeFree < T > >
  4189. class CAutoMemRelease
  4190. {
  4191. public:
  4192. CAutoMemRelease()
  4193. {
  4194. m_pData = NULL;
  4195. }
  4196. CAutoMemRelease(T* pData)
  4197. {
  4198. m_pData = pData;
  4199. }
  4200. ~CAutoMemRelease()
  4201. {
  4202. Attach(NULL);
  4203. }
  4204. void Attach(T* pData)
  4205. {
  4206. DeAllocator::Free(m_pData);
  4207. m_pData = pData;
  4208. }
  4209. T* Detach()
  4210. {
  4211. T* pTemp = m_pData;
  4212. m_pData = NULL;
  4213. return pTemp;
  4214. }
  4215. T* m_pData;
  4216. };
  4217. template <class T>
  4218. class ATL_NO_VTABLE ICommandImpl : public ICommand
  4219. {
  4220. public:
  4221. ICommandImpl()
  4222. {
  4223. m_bIsExecuting = FALSE;
  4224. m_bCancelWhenExecuting = TRUE;
  4225. m_bCancel = FALSE;
  4226. }
  4227. HRESULT CancelExecution()
  4228. {
  4229. T* pT = (T*)this;
  4230. pT->Lock();
  4231. m_bCancel = TRUE;
  4232. pT->Unlock();
  4233. return S_OK;
  4234. }
  4235. STDMETHOD(Cancel)()
  4236. {
  4237. ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::Cancel\n");
  4238. HRESULT hr = S_OK;
  4239. T* pT = (T*)this;
  4240. if (m_bIsExecuting && m_bCancelWhenExecuting)
  4241. {
  4242. hr = pT->CancelExecution();
  4243. return hr;
  4244. }
  4245. if (m_bIsExecuting && !m_bCancelWhenExecuting)
  4246. hr = DB_E_CANTCANCEL;
  4247. return hr;
  4248. }
  4249. STDMETHOD(GetDBSession)(REFIID riid, IUnknown ** ppSession)
  4250. {
  4251. ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::GetDBSession\n");
  4252. T* pT = (T*)this;
  4253. ATLASSERT(pT->m_spUnkSite != NULL);
  4254. return pT->m_spUnkSite->QueryInterface(riid, (void**) ppSession);
  4255. }
  4256. template <class RowsetClass>
  4257. HRESULT CreateRowset(IUnknown* pUnkOuter, REFIID riid,
  4258. DBPARAMS * pParams, DBROWCOUNT * pcRowsAffected,
  4259. IUnknown** ppRowset,
  4260. RowsetClass*& pRowsetObj)
  4261. {
  4262. HRESULT hr;
  4263. USES_CONVERSION;
  4264. int iBind;
  4265. T* pT = (T*)this;
  4266. if (ppRowset != NULL)
  4267. *ppRowset = NULL;
  4268. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  4269. return DB_E_NOAGGREGATION;
  4270. CComPolyObject<RowsetClass>* pPolyObj;
  4271. if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  4272. return hr;
  4273. // Ref the created COM object and Auto release it on failure
  4274. CComPtr<IUnknown> spUnk;
  4275. hr = pPolyObj->QueryInterface(&spUnk);
  4276. if (FAILED(hr))
  4277. {
  4278. delete pPolyObj; // must hand delete as it is not ref'd
  4279. return hr;
  4280. }
  4281. // Get a pointer to the Rowset instance
  4282. pRowsetObj = &(pPolyObj->m_contained);
  4283. if (FAILED(hr = pRowsetObj->FInit(pT)))
  4284. return hr;
  4285. pRowsetObj->SetSite(pT->GetUnknown());
  4286. if (pT->m_strCommandText.Length() == 0)
  4287. {
  4288. ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::No command text specified.\n");
  4289. return DB_E_NOCOMMAND;
  4290. }
  4291. pRowsetObj->m_strCommandText = pT->m_strCommandText;
  4292. if (pRowsetObj->m_strCommandText == (BSTR)NULL)
  4293. return E_OUTOFMEMORY;
  4294. if (FAILED(hr = pRowsetObj->Execute(pParams, pcRowsAffected)))
  4295. return hr;
  4296. if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
  4297. {
  4298. if (ppRowset != NULL)
  4299. *ppRowset = NULL;
  4300. return hr;
  4301. }
  4302. hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
  4303. if (FAILED(hr))
  4304. return hr;
  4305. for (iBind = 0; iBind < pT->m_rgBindings.GetSize(); iBind++)
  4306. {
  4307. T::_BindType* pBind = NULL;
  4308. T::_BindType* pBindSrc = NULL;
  4309. ATLTRY(pBind = new T::_BindType);
  4310. if (pBind == NULL)
  4311. {
  4312. ATLTRACE2(atlTraceDBProvider, 0, "Failed to allocate memory for new Binding\n");
  4313. return E_OUTOFMEMORY;
  4314. }
  4315. // auto cleanup on failure
  4316. CAutoMemRelease<T::_BindType> amr(pBind);
  4317. pBindSrc = pT->m_rgBindings.GetValueAt(iBind);
  4318. if (pBindSrc == NULL)
  4319. {
  4320. ATLTRACE2(atlTraceDBProvider, 0, "The map appears to be corrupted, failing!!\n");
  4321. return E_FAIL;
  4322. }
  4323. if (!pRowsetObj->m_rgBindings.Add(pT->m_rgBindings.GetKeyAt(iBind), pBind))
  4324. {
  4325. ATLTRACE2(atlTraceDBProvider, 0, "Failed to add hAccessor to Map\n");
  4326. return E_OUTOFMEMORY;
  4327. }
  4328. if (pBindSrc->cBindings)
  4329. {
  4330. ATLTRY(pBind->pBindings = new DBBINDING[pBindSrc->cBindings])
  4331. if (pBind->pBindings == NULL)
  4332. {
  4333. ATLTRACE2(atlTraceDBProvider, 0, "Failed to Allocate dbbinding Array\n");
  4334. // We added it, must now remove on failure
  4335. pRowsetObj->m_rgBindings.Remove(pT->m_rgBindings.GetKeyAt(iBind));
  4336. return E_OUTOFMEMORY;
  4337. }
  4338. }
  4339. else
  4340. {
  4341. pBind->pBindings = NULL; // NULL Accessor
  4342. }
  4343. pBind->dwAccessorFlags = pBindSrc->dwAccessorFlags;
  4344. pBind->cBindings = pBindSrc->cBindings;
  4345. pBind->dwRef = 1;
  4346. memcpy (pBind->pBindings, pBindSrc->pBindings, (pBindSrc->cBindings)*sizeof(DBBINDING));
  4347. pBind = amr.Detach();
  4348. }
  4349. return S_OK;
  4350. }
  4351. unsigned m_bIsExecuting:1;
  4352. unsigned m_bCancelWhenExecuting:1;
  4353. unsigned m_bCancel:1;
  4354. };
  4355. template <class T>
  4356. class ATL_NO_VTABLE ICommandTextImpl : public ICommandImpl<T>
  4357. {
  4358. public:
  4359. STDMETHOD(GetCommandText)(GUID * /*pguidDialect*/,LPOLESTR * ppwszCommand)
  4360. {
  4361. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText\n");
  4362. UINT cchCommandText;
  4363. HRESULT hr = E_FAIL;
  4364. if (ppwszCommand == NULL)
  4365. {
  4366. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
  4367. return E_INVALIDARG;
  4368. }
  4369. if (m_strCommandText.m_str == NULL)
  4370. {
  4371. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
  4372. return DB_E_NOCOMMAND;
  4373. }
  4374. cchCommandText = sizeof(OLECHAR) * (m_strCommandText.Length() + 1);
  4375. *ppwszCommand = (OLECHAR*)CoTaskMemAlloc(cchCommandText);
  4376. if (*ppwszCommand != NULL)
  4377. {
  4378. memcpy(*ppwszCommand, m_strCommandText.m_str, cchCommandText);
  4379. *(*ppwszCommand + m_strCommandText.Length()) = (OLECHAR)NULL;
  4380. return S_OK;
  4381. }
  4382. *ppwszCommand = NULL;
  4383. return hr;
  4384. }
  4385. STDMETHOD(SetCommandText)(REFGUID /*rguidDialect*/,LPCOLESTR pwszCommand)
  4386. {
  4387. T* pT = (T*)this;
  4388. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::SetCommandText\n");
  4389. pT->Lock();
  4390. m_strCommandText = pwszCommand;
  4391. pT->Unlock();
  4392. return S_OK;
  4393. }
  4394. CComBSTR m_strCommandText;
  4395. };
  4396. // ISessionPropertiesImpl
  4397. template <class T, class PropClass = T>
  4398. class ATL_NO_VTABLE ISessionPropertiesImpl :
  4399. public ISessionProperties,
  4400. public CUtlProps<PropClass>
  4401. {
  4402. public:
  4403. typedef PropClass _PropClass;
  4404. STDMETHOD(GetProperties)(ULONG cPropertyIDSets,
  4405. const DBPROPIDSET rgPropertyIDSets[],
  4406. ULONG *pcPropertySets,
  4407. DBPROPSET **prgPropertySets)
  4408. {
  4409. ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::GetProperties\n");
  4410. HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  4411. const GUID* ppGuid[1];
  4412. ppGuid[0] = &DBPROPSET_SESSION;
  4413. if(SUCCEEDED(hr))
  4414. hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
  4415. rgPropertyIDSets, pcPropertySets, prgPropertySets,
  4416. 1, ppGuid);
  4417. return hr;
  4418. }
  4419. STDMETHOD(SetProperties)(ULONG cPropertySets,
  4420. DBPROPSET rgPropertySets[])
  4421. {
  4422. ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::SetProperties");
  4423. HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
  4424. const GUID* ppGuid[1];
  4425. ppGuid[0] = &DBPROPSET_SESSION;
  4426. if(SUCCEEDED(hr))
  4427. hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets, rgPropertySets,
  4428. 1, ppGuid);
  4429. return hr;
  4430. }
  4431. };
  4432. // Implementation Class
  4433. template <class BindType>
  4434. class ATL_NO_VTABLE IAccessorImplBase : public IAccessor
  4435. {
  4436. public:
  4437. STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
  4438. DBCOUNTITEM cBindings,
  4439. const DBBINDING rgBindings[],
  4440. DBLENGTH /*cbRowSize*/,
  4441. HACCESSOR *phAccessor,
  4442. DBBINDSTATUS rgStatus[])
  4443. {
  4444. if (!(dwAccessorFlags & DBACCESSOR_PARAMETERDATA) && !(dwAccessorFlags & DBACCESSOR_ROWDATA))
  4445. return DB_E_BADACCESSORFLAGS;
  4446. if (dwAccessorFlags == DBACCESSOR_INVALID)
  4447. return DB_E_BADACCESSORFLAGS;
  4448. if (dwAccessorFlags > 0x000F)
  4449. return DB_E_BADACCESSORFLAGS;
  4450. BindType *pBind = NULL;
  4451. ATLTRY(pBind = new BindType)
  4452. if (pBind == NULL)
  4453. {
  4454. ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ATL Binding struct\n"));
  4455. return E_OUTOFMEMORY;
  4456. }
  4457. if (cBindings)
  4458. {
  4459. ATLTRY(pBind->pBindings = new DBBINDING[cBindings])
  4460. if (pBind->pBindings == NULL)
  4461. {
  4462. delete pBind;
  4463. return E_OUTOFMEMORY;
  4464. }
  4465. }
  4466. else
  4467. pBind->pBindings = NULL; // NULL Accessor
  4468. pBind->dwAccessorFlags = dwAccessorFlags;
  4469. pBind->cBindings = cBindings;
  4470. pBind->dwRef = 1;
  4471. memcpy (pBind->pBindings, rgBindings, cBindings*sizeof(DBBINDING));
  4472. DBBINDSTATUS status = DBBINDSTATUS_OK;
  4473. memset (rgStatus, status, sizeof(DBBINDSTATUS)*cBindings);
  4474. *phAccessor = (ULONG_PTR)pBind;
  4475. return S_OK;
  4476. }
  4477. BOOL HasFlag(DBTYPE dbToCheck, DBTYPE dbCombo)
  4478. {
  4479. return ( (dbToCheck & dbCombo) == dbCombo );
  4480. }
  4481. HRESULT ValidateBindings(DBCOUNTITEM cBindings, const DBBINDING rgBindings[],
  4482. DBBINDSTATUS rgStatus[], bool bHasBookmarks)
  4483. {
  4484. HRESULT hr = S_OK;;
  4485. for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
  4486. {
  4487. const DBBINDING& rBindCur = rgBindings[iBinding];
  4488. if (rBindCur.iOrdinal == 0)
  4489. {
  4490. if (!m_bIsCommand && !bHasBookmarks)
  4491. {
  4492. hr = DB_E_ERRORSOCCURRED;
  4493. rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
  4494. continue;
  4495. }
  4496. }
  4497. if (rBindCur.dwPart == 0) // nothing to bind to
  4498. {
  4499. hr = DB_E_ERRORSOCCURRED;
  4500. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4501. continue;
  4502. }
  4503. if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_ARRAY)))
  4504. {
  4505. hr = DB_E_ERRORSOCCURRED;
  4506. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4507. continue;
  4508. }
  4509. if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_VECTOR)))
  4510. {
  4511. hr = DB_E_ERRORSOCCURRED;
  4512. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4513. continue;
  4514. }
  4515. if (HasFlag(rBindCur.wType, (DBTYPE_VECTOR | DBTYPE_ARRAY)))
  4516. {
  4517. hr = DB_E_ERRORSOCCURRED;
  4518. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4519. continue;
  4520. }
  4521. if (rBindCur.wType == DBTYPE_NULL || rBindCur.wType == DBTYPE_EMPTY)
  4522. {
  4523. hr = DB_E_ERRORSOCCURRED;
  4524. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4525. continue;
  4526. }
  4527. if (HasFlag(rBindCur.wType, DBTYPE_RESERVED))
  4528. {
  4529. hr = DB_E_ERRORSOCCURRED;
  4530. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4531. continue;
  4532. }
  4533. // Search for DBTYPE_BYREF | DBTYPE_EMPTY
  4534. if ((rBindCur.wType & 0xBFFF) == 0)
  4535. {
  4536. hr = DB_E_ERRORSOCCURRED;
  4537. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4538. continue;
  4539. }
  4540. if ((rBindCur.wType & 0xBFFE) == 0)
  4541. {
  4542. hr = DB_E_ERRORSOCCURRED;
  4543. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4544. continue;
  4545. }
  4546. if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED)
  4547. {
  4548. BOOL bIsPointerType = HasFlag(rBindCur.wType, DBTYPE_BYREF) ||
  4549. HasFlag(rBindCur.wType, DBTYPE_VECTOR) ||
  4550. HasFlag(rBindCur.wType, DBTYPE_ARRAY) ||
  4551. HasFlag(~(DBTYPE_BYREF) & rBindCur.wType, DBTYPE_BSTR);
  4552. if (!bIsPointerType)
  4553. {
  4554. hr = DB_E_ERRORSOCCURRED;
  4555. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4556. continue;
  4557. }
  4558. }
  4559. }
  4560. return hr;
  4561. }
  4562. unsigned m_bIsCommand:1;
  4563. unsigned m_bHasParamaters:1;
  4564. unsigned m_bIsChangeable:1;
  4565. };
  4566. // IAccessorImpl
  4567. template <class T, class BindType = ATLBINDINGS, class BindingVector = CSimpleMap < INT_PTR, BindType* > >
  4568. class ATL_NO_VTABLE IAccessorImpl : public IAccessorImplBase<BindType>
  4569. {
  4570. public:
  4571. typedef BindType _BindType;
  4572. typedef BindingVector _BindingVector;
  4573. IAccessorImpl()
  4574. {
  4575. m_bIsCommand = FALSE;
  4576. m_bHasParamaters = FALSE;
  4577. m_bIsChangeable = FALSE;
  4578. }
  4579. OUT_OF_LINE HRESULT InternalFinalConstruct(IUnknown* pUnkThis)
  4580. {
  4581. CComQIPtr<ICommand> spCommand = pUnkThis;
  4582. if (spCommand != NULL)
  4583. {
  4584. m_bIsCommand = TRUE;
  4585. CComQIPtr<ICommandWithParameters> spCommandParams = pUnkThis;
  4586. m_bHasParamaters = spCommandParams != NULL;
  4587. }
  4588. else // its a Rowset
  4589. {
  4590. CComQIPtr<IRowsetChange> spRSChange = pUnkThis;
  4591. m_bIsChangeable = spRSChange != NULL;
  4592. }
  4593. return S_OK;
  4594. }
  4595. HRESULT FinalConstruct()
  4596. {
  4597. T* pT = (T*)this;
  4598. return InternalFinalConstruct(pT->GetUnknown());
  4599. }
  4600. void FinalRelease()
  4601. {
  4602. #ifdef _DEBUG
  4603. if (m_rgBindings.GetSize())
  4604. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::~IAccessorImpl Bindings still in vector, removing\n");
  4605. #endif //_DEBUG
  4606. while (m_rgBindings.GetSize())
  4607. ReleaseAccessor((HACCESSOR)m_rgBindings.GetKeyAt(0), NULL);
  4608. }
  4609. STDMETHOD(AddRefAccessor)(HACCESSOR hAccessor,
  4610. DBREFCOUNT *pcRefCount)
  4611. {
  4612. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::AddRefAccessor\n");
  4613. if (hAccessor == NULL)
  4614. {
  4615. ATLTRACE2(atlTraceDBProvider, 0, _T("AddRefAccessor : Bad hAccessor\n"));
  4616. return E_INVALIDARG;
  4617. }
  4618. if (pcRefCount == NULL)
  4619. pcRefCount = (ULONG*)_alloca(sizeof(ULONG));
  4620. BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  4621. *pcRefCount = T::_ThreadModel::Increment((LONG*)&pBind->dwRef);
  4622. return S_OK;
  4623. }
  4624. OUT_OF_LINE ATLCOLUMNINFO* ValidateHelper(DBORDINAL* pcCols, CComPtr<IDataConvert> & rspConvert)
  4625. {
  4626. T* pT = (T*)this;
  4627. rspConvert = pT->m_spConvert;
  4628. return pT->GetColumnInfo(pT, pcCols);
  4629. }
  4630. OUT_OF_LINE HRESULT ValidateBindingsFromMetaData(DBCOUNTITEM cBindings, const DBBINDING rgBindings[],
  4631. DBBINDSTATUS rgStatus[], bool bHasBookmarks)
  4632. {
  4633. HRESULT hr = S_OK;
  4634. DBORDINAL cCols;
  4635. CComPtr<IDataConvert> spConvert;
  4636. ATLCOLUMNINFO* pColInfo = ValidateHelper(&cCols, spConvert);
  4637. ATLASSERT(pColInfo != NULL);
  4638. for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
  4639. {
  4640. const DBBINDING& rBindCur = rgBindings[iBinding];
  4641. DBORDINAL iOrdAdjusted;
  4642. if (bHasBookmarks)
  4643. iOrdAdjusted = rBindCur.iOrdinal; // Bookmarks start with ordinal 0
  4644. else
  4645. iOrdAdjusted = rBindCur.iOrdinal - 1; // Non-bookmarks start w/ ordinal 1
  4646. if (rBindCur.iOrdinal > cCols)
  4647. {
  4648. hr = DB_E_ERRORSOCCURRED;
  4649. rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
  4650. continue;
  4651. }
  4652. // If a binding specifies provider owned memory, and specifies type
  4653. // X | BYREF, and the provider's copy is not X or X | BYREF, return
  4654. // DBBINDSTATUS_BADBINDINFO
  4655. if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED)
  4656. {
  4657. if ((rBindCur.wType & DBTYPE_BYREF) != 0)
  4658. {
  4659. DBTYPE dbConsumerType = rBindCur.wType & 0xBFFF;
  4660. DBTYPE dbProviderType = pColInfo[iOrdAdjusted].wType & 0xBFFF;
  4661. if (dbConsumerType != dbProviderType)
  4662. {
  4663. hr = DB_E_ERRORSOCCURRED;
  4664. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4665. continue;
  4666. }
  4667. }
  4668. }
  4669. ATLASSERT(spConvert != NULL);
  4670. HRESULT hrConvert = spConvert->CanConvert(pColInfo[iOrdAdjusted].wType, rBindCur.wType);
  4671. if (FAILED(hrConvert) || hrConvert == S_FALSE)
  4672. {
  4673. hr = DB_E_ERRORSOCCURRED;
  4674. rgStatus[iBinding] = DBBINDSTATUS_UNSUPPORTEDCONVERSION;
  4675. continue;
  4676. }
  4677. }
  4678. return hr;
  4679. }
  4680. STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
  4681. DBCOUNTITEM cBindings,
  4682. const DBBINDING rgBindings[],
  4683. DBLENGTH cbRowSize,
  4684. HACCESSOR *phAccessor,
  4685. DBBINDSTATUS rgStatus[])
  4686. {
  4687. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor\n");
  4688. T* pT = (T*)this;
  4689. T::ObjectLock cab(pT);
  4690. if (!phAccessor)
  4691. {
  4692. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Inavlid NULL Parameter for HACCESSOR*\n");
  4693. return E_INVALIDARG;
  4694. }
  4695. *phAccessor = NULL;
  4696. if (cBindings != 0 && rgBindings == NULL)
  4697. {
  4698. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Bad Binding array\n");
  4699. return E_INVALIDARG;
  4700. }
  4701. if (dwAccessorFlags & DBACCESSOR_PASSBYREF)
  4702. {
  4703. CComVariant varByRef;
  4704. HRESULT hr = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BYREFACCESSORS, &varByRef);
  4705. if (FAILED(hr) || varByRef.boolVal == VARIANT_FALSE)
  4706. return DB_E_BYREFACCESSORNOTSUPPORTED;
  4707. }
  4708. if (!m_bHasParamaters)
  4709. {
  4710. if (dwAccessorFlags & DBACCESSOR_PARAMETERDATA)
  4711. return DB_E_BADACCESSORFLAGS;
  4712. }
  4713. if (m_bIsCommand || !m_bIsChangeable)
  4714. {
  4715. if (cBindings == 0) // No NULL Accessors on the command
  4716. return DB_E_NULLACCESSORNOTSUPPORTED;
  4717. }
  4718. if (rgStatus == NULL && cBindings) // Create a fake status array
  4719. rgStatus = (DBBINDSTATUS*)_alloca(cBindings*sizeof(DBBINDSTATUS));
  4720. // Validate the Binding passed
  4721. HRESULT hr;
  4722. bool bHasBookmarks = false;
  4723. CComVariant varBookmarks;
  4724. HRESULT hrLocal = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BOOKMARKS, &varBookmarks);
  4725. bHasBookmarks = (hrLocal == S_OK && varBookmarks.boolVal == VARIANT_TRUE);
  4726. hr = ValidateBindings(cBindings, rgBindings, rgStatus, bHasBookmarks);
  4727. if (FAILED(hr))
  4728. return hr;
  4729. if (!m_bIsCommand)
  4730. {
  4731. hr = ValidateBindingsFromMetaData(cBindings, rgBindings, rgStatus,
  4732. bHasBookmarks);
  4733. if (FAILED(hr))
  4734. return hr;
  4735. }
  4736. hr = IAccessorImplBase<BindType>::CreateAccessor(dwAccessorFlags, cBindings,
  4737. rgBindings, cbRowSize, phAccessor,rgStatus);
  4738. if (SUCCEEDED(hr))
  4739. {
  4740. ATLASSERT(*phAccessor != NULL);
  4741. BindType* pBind = (BindType*)*phAccessor;
  4742. hr = m_rgBindings.Add((HACCESSOR)pBind, pBind) ? S_OK : E_OUTOFMEMORY;
  4743. }
  4744. return hr;
  4745. }
  4746. STDMETHOD(GetBindings)(HACCESSOR hAccessor,
  4747. DBACCESSORFLAGS *pdwAccessorFlags,
  4748. DBCOUNTITEM *pcBindings,
  4749. DBBINDING **prgBindings)
  4750. {
  4751. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::GetBindings");
  4752. // Zero output parameters in case of failure
  4753. if (pdwAccessorFlags != NULL)
  4754. *pdwAccessorFlags = NULL;
  4755. if (pcBindings != NULL)
  4756. *pcBindings = NULL;
  4757. if (prgBindings != NULL)
  4758. *prgBindings = NULL;
  4759. // Check if any of the out params are NULL pointers
  4760. if ((pdwAccessorFlags && pcBindings && prgBindings) == NULL)
  4761. return E_INVALIDARG;
  4762. BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  4763. HRESULT hr = DB_E_BADACCESSORHANDLE;
  4764. if (pBind != NULL)
  4765. {
  4766. *pdwAccessorFlags = pBind->dwAccessorFlags;
  4767. *pcBindings = pBind->cBindings;
  4768. *prgBindings = (DBBINDING*)CoTaskMemAlloc(*pcBindings * sizeof(DBBINDING));
  4769. if (*prgBindings == NULL)
  4770. return E_OUTOFMEMORY;
  4771. memcpy(*prgBindings, pBind->pBindings, sizeof(DBBINDING) * (*pcBindings));
  4772. hr = S_OK;
  4773. }
  4774. return hr;
  4775. }
  4776. STDMETHOD(ReleaseAccessor)(HACCESSOR hAccessor,
  4777. DBREFCOUNT *pcRefCount)
  4778. {
  4779. ATLTRACE2(atlTraceDBProvider, 0, _T("IAccessorImpl::ReleaseAccessor\n"));
  4780. BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  4781. if (pBind == NULL)
  4782. return DB_E_BADACCESSORHANDLE;
  4783. if (pcRefCount == NULL)
  4784. pcRefCount = (DBREFCOUNT*)_alloca(sizeof(DBREFCOUNT));
  4785. *pcRefCount = T::_ThreadModel::Decrement((LONG*)&pBind->dwRef);
  4786. if (!(*pcRefCount))
  4787. {
  4788. delete [] pBind->pBindings;
  4789. delete pBind;
  4790. return m_rgBindings.Remove((int)hAccessor) ? S_OK : DB_E_BADACCESSORHANDLE;
  4791. }
  4792. return S_OK;
  4793. }
  4794. BindingVector m_rgBindings;
  4795. };
  4796. #define BEGIN_PROVIDER_COLUMN_MAP(theClass) \
  4797. typedef theClass _Class; \
  4798. template <class T> \
  4799. static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols) \
  4800. { \
  4801. pv; \
  4802. static ATLCOLUMNINFO _rgColumns [] = \
  4803. {
  4804. #define SIZEOF_MEMBER(memberOf, member) \
  4805. sizeof(((memberOf*)0)->member)
  4806. #define EXPANDGUID(guid) \
  4807. { guid.Data1, guid.Data2, guid.Data3, \
  4808. { guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] } }
  4809. #define PROVIDER_COLUMN_ENTRY_GN(name, ordinal, flags, colSize, dbtype, precision, scale, guid) \
  4810. { (LPOLESTR)name, (ITypeInfo*)NULL, (ULONG)ordinal, (DBCOLUMNFLAGS)flags, (ULONG)colSize, (DBTYPE)dbtype, (BYTE)precision, (BYTE)scale, { EXPANDGUID(guid), (DWORD)0, (LPOLESTR) name}, 0},
  4811. #define PROVIDER_COLUMN_ENTRY(name, ordinal, member) \
  4812. { \
  4813. (LPOLESTR)OLESTR(name), \
  4814. (ITypeInfo*)NULL, \
  4815. (ULONG)ordinal, \
  4816. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4817. (ULONG)sizeof(((_Class*)0)->member), \
  4818. _GetOleDBType(((_Class*)0)->member), \
  4819. (BYTE)0, \
  4820. (BYTE)0, \
  4821. { \
  4822. EXPANDGUID(GUID_NULL), \
  4823. (DWORD)2, \
  4824. (LPOLESTR) name \
  4825. }, \
  4826. offsetof(_Class, member) \
  4827. },
  4828. #define PROVIDER_COLUMN_ENTRY_LENGTH(name, ordinal, size, member) \
  4829. { \
  4830. (LPOLESTR)OLESTR(name), \
  4831. (ITypeInfo*)NULL, \
  4832. (ULONG)ordinal, \
  4833. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4834. (ULONG)size, \
  4835. _GetOleDBType(((_Class*)0)->member), \
  4836. (BYTE)0, \
  4837. (BYTE)0, \
  4838. { \
  4839. EXPANDGUID(GUID_NULL), \
  4840. (DWORD)2, \
  4841. (LPOLESTR) name \
  4842. }, \
  4843. offsetof(_Class, member) \
  4844. },
  4845. #define PROVIDER_COLUMN_ENTRY_TYPE_LENGTH(name, ordinal, type, size, member) \
  4846. { \
  4847. (LPOLESTR)OLESTR(name), \
  4848. (ITypeInfo*)NULL, \
  4849. (ULONG)ordinal, \
  4850. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4851. (ULONG)size, \
  4852. (DBTYPE)type, \
  4853. (BYTE)0, \
  4854. (BYTE)0, \
  4855. { \
  4856. EXPANDGUID(GUID_NULL), \
  4857. (DWORD)2, \
  4858. (LPOLESTR) name \
  4859. }, \
  4860. offsetof(_Class, member) \
  4861. },
  4862. #define PROVIDER_COLUMN_ENTRY_FIXED(name, ordinal, dbtype, member) \
  4863. { \
  4864. (LPOLESTR)OLESTR(name), \
  4865. (ITypeInfo*)NULL, \
  4866. (ULONG)ordinal, \
  4867. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4868. (ULONG)sizeof(((_Class*)0)->member), \
  4869. (DBTYPE)dbtype, \
  4870. (BYTE)0, \
  4871. (BYTE)0, \
  4872. { \
  4873. EXPANDGUID(GUID_NULL), \
  4874. (DWORD)2, \
  4875. (LPOLESTR) name \
  4876. }, \
  4877. offsetof(_Class, member) \
  4878. },
  4879. #define PROVIDER_COLUMN_ENTRY_STR(name, ordinal, member) \
  4880. { \
  4881. (LPOLESTR)OLESTR(name), \
  4882. (ITypeInfo*)NULL, \
  4883. (ULONG)ordinal, \
  4884. 0, \
  4885. (ULONG)sizeof(((_Class*)0)->member), \
  4886. DBTYPE_STR, \
  4887. (BYTE)0xFF, \
  4888. (BYTE)0xFF, \
  4889. { \
  4890. EXPANDGUID(GUID_NULL), \
  4891. (DWORD)2, \
  4892. (LPOLESTR) name \
  4893. }, \
  4894. offsetof(_Class, member) \
  4895. },
  4896. #define PROVIDER_COLUMN_ENTRY_WSTR(name, ordinal, member) \
  4897. { \
  4898. (LPOLESTR)OLESTR(name), \
  4899. (ITypeInfo*)NULL, \
  4900. (ULONG)ordinal, \
  4901. 0, \
  4902. (ULONG)sizeof(((_Class*)0)->member), \
  4903. DBTYPE_WSTR, \
  4904. (BYTE)0xFF, \
  4905. (BYTE)0xFF, \
  4906. { \
  4907. EXPANDGUID(GUID_NULL), \
  4908. (DWORD)2, \
  4909. (LPOLESTR) name \
  4910. }, \
  4911. offsetof(_Class, member) \
  4912. },
  4913. #define END_PROVIDER_COLUMN_MAP() \
  4914. }; *pcCols = sizeof(_rgColumns)/sizeof(ATLCOLUMNINFO); return _rgColumns;}
  4915. // Implementation Class
  4916. class CSimpleRow
  4917. {
  4918. public:
  4919. typedef DBROWCOUNT KeyType;
  4920. CSimpleRow(DBROWCOUNT iRowsetCur)
  4921. {
  4922. m_dwRef = 0;
  4923. m_iRowset = iRowsetCur;
  4924. }
  4925. ~CSimpleRow()
  4926. {
  4927. }
  4928. DWORD AddRefRow() { return CComObjectThreadModel::Increment((LPLONG)&m_dwRef); }
  4929. DWORD ReleaseRow() { return CComObjectThreadModel::Decrement((LPLONG)&m_dwRef); }
  4930. HRESULT Compare(CSimpleRow* pRow)
  4931. {
  4932. ATLASSERT(pRow != NULL);
  4933. return (m_iRowset == pRow->m_iRowset) ? S_OK : S_FALSE;
  4934. }
  4935. KeyType m_iRowset;
  4936. DWORD m_dwRef;
  4937. };
  4938. // IRowsetImpl
  4939. template <class T, class RowsetInterface,
  4940. class RowClass = CSimpleRow,
  4941. class MapClass = CSimpleMap < RowClass::KeyType, RowClass* > >
  4942. class ATL_NO_VTABLE IRowsetImpl : public RowsetInterface
  4943. {
  4944. public:
  4945. typedef RowClass _HRowClass;
  4946. IRowsetImpl()
  4947. {
  4948. m_iRowset = 0;
  4949. m_bCanScrollBack = false;
  4950. m_bCanFetchBack = false;
  4951. m_bReset = true;
  4952. }
  4953. ~IRowsetImpl()
  4954. {
  4955. for (int i = 0; i < m_rgRowHandles.GetSize(); i++)
  4956. delete (m_rgRowHandles.GetValueAt(i));
  4957. }
  4958. HRESULT RefRows(DBCOUNTITEM cRows, const HROW rghRows[], ULONG rgRefCounts[],
  4959. DBROWSTATUS rgRowStatus[], BOOL bAdd)
  4960. {
  4961. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
  4962. if (cRows == 0)
  4963. return S_OK;
  4964. if (rghRows == NULL)
  4965. return E_INVALIDARG;
  4966. T::ObjectLock cab((T*)this);
  4967. BOOL bSuccess1 = FALSE;
  4968. BOOL bFailed1 = FALSE;
  4969. DBROWSTATUS rs;
  4970. DWORD dwRef;
  4971. for (ULONG iRow = 0; iRow < cRows; iRow++)
  4972. {
  4973. HROW hRowCur = rghRows[iRow];
  4974. RowClass* pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRowCur);
  4975. if (pRow == NULL)
  4976. {
  4977. ATLTRACE2(atlTraceDBProvider, 0, "Could not find HANDLE %x in list\n");
  4978. rs = DBROWSTATUS_E_INVALID;
  4979. dwRef = 0;
  4980. bFailed1 = TRUE;
  4981. }
  4982. else
  4983. {
  4984. if (bAdd)
  4985. dwRef = pRow->AddRefRow();
  4986. else
  4987. {
  4988. dwRef = pRow->ReleaseRow();
  4989. if (dwRef == 0)
  4990. {
  4991. delete pRow;
  4992. m_rgRowHandles.Remove((RowClass::KeyType)hRowCur);
  4993. }
  4994. }
  4995. bSuccess1 = TRUE;
  4996. rs = DBROWSTATUS_S_OK;
  4997. }
  4998. if (rgRefCounts)
  4999. rgRefCounts[iRow] = dwRef;
  5000. if (rgRowStatus != NULL)
  5001. rgRowStatus[iRow] = rs;
  5002. }
  5003. if (!bSuccess1 && !bFailed1)
  5004. {
  5005. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RefRows Unexpected state\n");
  5006. return E_FAIL;
  5007. }
  5008. HRESULT hr = S_OK;
  5009. if (bSuccess1 && bFailed1)
  5010. hr = DB_S_ERRORSOCCURRED;
  5011. if (!bSuccess1 && bFailed1)
  5012. hr = DB_E_ERRORSOCCURRED;
  5013. return hr;
  5014. }
  5015. STDMETHOD(AddRefRows)(DBCOUNTITEM cRows,
  5016. const HROW rghRows[],
  5017. DBREFCOUNT rgRefCounts[],
  5018. DBROWSTATUS rgRowStatus[])
  5019. {
  5020. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
  5021. if (cRows == 0)
  5022. return S_OK;
  5023. return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, TRUE);
  5024. }
  5025. virtual DBSTATUS GetDBStatus(RowClass* , ATLCOLUMNINFO*)
  5026. {
  5027. return DBSTATUS_S_OK;
  5028. }
  5029. OUT_OF_LINE HRESULT GetDataHelper(HACCESSOR hAccessor,
  5030. ATLCOLUMNINFO*& rpInfo,
  5031. void** ppBinding,
  5032. void*& rpSrcData,
  5033. DBORDINAL& rcCols,
  5034. CComPtr<IDataConvert>& rspConvert,
  5035. RowClass* pRow)
  5036. {
  5037. ATLASSERT(ppBinding != NULL);
  5038. T* pT = (T*) this;
  5039. *ppBinding = (void*)pT->m_rgBindings.Lookup((int)hAccessor);
  5040. if (*ppBinding == NULL)
  5041. return DB_E_BADACCESSORHANDLE;
  5042. rpSrcData = (void*)&(pT->m_rgRowData[(int)(INT_PTR)(pRow->m_iRowset)]);
  5043. rpInfo = T::GetColumnInfo((T*)this, &rcCols);
  5044. rspConvert = pT->m_spConvert;
  5045. return S_OK;
  5046. }
  5047. STDMETHOD(GetData)(HROW hRow,
  5048. HACCESSOR hAccessor,
  5049. void *pDstData)
  5050. {
  5051. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetData\n");
  5052. if (pDstData == NULL)
  5053. return E_INVALIDARG;
  5054. HRESULT hr = S_OK;
  5055. RowClass* pRow = (RowClass*)hRow;
  5056. if (hRow == NULL || (pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRow)) == NULL)
  5057. return DB_E_BADROWHANDLE;
  5058. T::_BindType* pBinding;
  5059. void* pSrcData;
  5060. DBORDINAL cCols;
  5061. ATLCOLUMNINFO* pColInfo;
  5062. CComPtr<IDataConvert> spConvert;
  5063. hr = GetDataHelper(hAccessor, pColInfo, (void**)&pBinding, pSrcData, cCols, spConvert, pRow);
  5064. if (FAILED(hr))
  5065. return hr;
  5066. for (ULONG iBind =0; iBind < pBinding->cBindings; iBind++)
  5067. {
  5068. DBBINDING* pBindCur = &(pBinding->pBindings[iBind]);
  5069. for (ULONG iColInfo = 0;
  5070. iColInfo < cCols && pBindCur->iOrdinal != pColInfo[iColInfo].iOrdinal;
  5071. iColInfo++);
  5072. if (iColInfo == cCols)
  5073. return DB_E_BADORDINAL;
  5074. ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
  5075. // Ordinal found at iColInfo
  5076. BOOL bProvOwn = pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED;
  5077. bProvOwn;
  5078. DBSTATUS dbStat = GetDBStatus(pRow, pColCur);
  5079. // If the provider's field is NULL, we can optimize this situation,
  5080. // set the fields to 0 and continue.
  5081. if (dbStat == DBSTATUS_S_ISNULL)
  5082. {
  5083. if (pBindCur->dwPart & DBPART_STATUS)
  5084. *((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat;
  5085. if (pBindCur->dwPart & DBPART_LENGTH)
  5086. *((ULONG*)((BYTE*)(pDstData) + pBindCur->obLength)) = 0;
  5087. if (pBindCur->dwPart & DBPART_VALUE)
  5088. *((BYTE*)(pDstData) + pBindCur->obValue) = NULL;
  5089. continue;
  5090. }
  5091. DBLENGTH cbDst = pBindCur->cbMaxLen;
  5092. DBLENGTH cbCol;
  5093. BYTE* pSrcTemp;
  5094. if (bProvOwn && pColCur->wType == pBindCur->wType)
  5095. {
  5096. pSrcTemp = ((BYTE*)(pSrcData) + pColCur->cbOffset);
  5097. }
  5098. else
  5099. {
  5100. BYTE* pDstTemp = (BYTE*)pDstData + pBindCur->obValue;
  5101. switch (pColCur->wType)
  5102. {
  5103. case DBTYPE_STR:
  5104. cbCol = lstrlenA((LPSTR)(((BYTE*)pSrcData) + pColCur->cbOffset));
  5105. break;
  5106. case DBTYPE_WSTR:
  5107. case DBTYPE_BSTR:
  5108. cbCol = lstrlenW((LPWSTR)(((BYTE*)pSrcData) + pColCur->cbOffset)) * sizeof(WCHAR);
  5109. break;
  5110. default:
  5111. cbCol = pColCur->ulColumnSize;
  5112. break;
  5113. }
  5114. if (pBindCur->dwPart & DBPART_VALUE)
  5115. {
  5116. hr = spConvert->DataConvert(pColCur->wType, pBindCur->wType,
  5117. cbCol, &cbDst, (BYTE*)(pSrcData) + pColCur->cbOffset,
  5118. pDstTemp, pBindCur->cbMaxLen, dbStat, &dbStat,
  5119. pBindCur->bPrecision, pBindCur->bScale,0);
  5120. }
  5121. }
  5122. if (pBindCur->dwPart & DBPART_LENGTH)
  5123. *((DBLENGTH*)((BYTE*)(pDstData) + pBindCur->obLength)) = cbDst;
  5124. if (pBindCur->dwPart & DBPART_STATUS)
  5125. *((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat;
  5126. if (FAILED(hr))
  5127. return hr;
  5128. }
  5129. return hr;
  5130. }
  5131. HRESULT CreateRow(DBROWOFFSET lRowsOffset, DBCOUNTITEM& cRowsObtained, HROW* rgRows)
  5132. {
  5133. RowClass* pRow = NULL;
  5134. ATLASSERT(lRowsOffset >= 0);
  5135. RowClass::KeyType key = lRowsOffset+1;
  5136. ATLASSERT(key > 0);
  5137. pRow = m_rgRowHandles.Lookup(key);
  5138. if (pRow == NULL)
  5139. {
  5140. ATLTRY(pRow = new RowClass(lRowsOffset))
  5141. if (pRow == NULL)
  5142. return E_OUTOFMEMORY;
  5143. if (!m_rgRowHandles.Add(key, pRow))
  5144. return E_OUTOFMEMORY;
  5145. }
  5146. pRow->AddRefRow();
  5147. m_bReset = false;
  5148. rgRows[cRowsObtained++] = (HROW)key;
  5149. return S_OK;
  5150. }
  5151. STDMETHOD(GetNextRows)(HCHAPTER /*hReserved*/,
  5152. DBROWOFFSET lRowsOffset,
  5153. DBROWCOUNT cRows,
  5154. DBCOUNTITEM *pcRowsObtained,
  5155. HROW **prghRows)
  5156. {
  5157. DBROWOFFSET lTmpRows = lRowsOffset;
  5158. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetNextRows\n");
  5159. if (pcRowsObtained != NULL)
  5160. *pcRowsObtained = 0;
  5161. if (prghRows == NULL || pcRowsObtained == NULL)
  5162. return E_INVALIDARG;
  5163. if (cRows == 0)
  5164. return S_OK;
  5165. HRESULT hr = S_OK;
  5166. T* pT = (T*) this;
  5167. T::ObjectLock cab(pT);
  5168. if (lRowsOffset < 0 && !m_bCanScrollBack)
  5169. return DB_E_CANTSCROLLBACKWARDS;
  5170. if (cRows < 0 && !m_bCanFetchBack)
  5171. return DB_E_CANTFETCHBACKWARDS;
  5172. // Calculate # of rows in set and the base fetch position. If the rowset
  5173. // is at its head position, then lRowOffset < 0 means moving from the BACK
  5174. // of the rowset and not the front.
  5175. DBROWCOUNT cRowsInSet = pT->m_rgRowData.GetSize();
  5176. if (((lRowsOffset == LONG_MIN) && (cRowsInSet != LONG_MIN))
  5177. || (abs((int)(INT_PTR)lRowsOffset)) > cRowsInSet ||
  5178. (abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset < 0 && cRows < 0) ||
  5179. (abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset > 0 && cRows > 0))
  5180. return DB_S_ENDOFROWSET;
  5181. // In the case where the user is moving backwards after moving forwards,
  5182. // we do not wrap around to the end of the rowset.
  5183. if ((m_iRowset == 0 && !m_bReset && cRows < 0) ||
  5184. (((LONG)m_iRowset + lRowsOffset) > cRowsInSet) ||
  5185. (m_iRowset == (DWORD)cRowsInSet && lRowsOffset >= 0 && cRows > 0))
  5186. return DB_S_ENDOFROWSET;
  5187. // Note, if m_bReset, m_iRowset must be 0
  5188. if (lRowsOffset < 0 && m_bReset)
  5189. {
  5190. ATLASSERT(m_iRowset == 0);
  5191. m_iRowset = cRowsInSet;
  5192. }
  5193. int iStepSize = cRows >= 0 ? 1 : -1;
  5194. // If cRows == LONG_MIN, we can't use ABS on it. Therefore, we reset it
  5195. // to a value just greater than cRowsInSet
  5196. if (cRows == LONG_MIN && cRowsInSet != LONG_MIN)
  5197. cRows = cRowsInSet + 2; // set the value to something we can deal with
  5198. else
  5199. cRows = abs((int)(INT_PTR)cRows);
  5200. if (iStepSize < 0 && m_iRowset == 0 && m_bReset && lRowsOffset <= 0)
  5201. m_iRowset = cRowsInSet;
  5202. lRowsOffset += m_iRowset;
  5203. *pcRowsObtained = 0;
  5204. CAutoMemRelease<HROW, CComFree< HROW > > amr;
  5205. if (*prghRows == NULL)
  5206. {
  5207. DBROWCOUNT cHandlesToAlloc = (cRows > cRowsInSet) ? cRowsInSet : cRows;
  5208. if (iStepSize == 1 && (cRowsInSet - lRowsOffset) < cHandlesToAlloc)
  5209. cHandlesToAlloc = cRowsInSet - lRowsOffset;
  5210. if (iStepSize == -1 && lRowsOffset < cHandlesToAlloc)
  5211. cHandlesToAlloc = lRowsOffset;
  5212. *prghRows = (HROW*)CoTaskMemAlloc((cHandlesToAlloc) * sizeof(HROW*));
  5213. amr.Attach(*prghRows);
  5214. }
  5215. if (*prghRows == NULL)
  5216. return E_OUTOFMEMORY;
  5217. while ((lRowsOffset >= 0 && cRows != 0) &&
  5218. ((lRowsOffset < cRowsInSet) || (lRowsOffset <= cRowsInSet && iStepSize < 0)))
  5219. {
  5220. // cRows > cRowsInSet && iStepSize < 0
  5221. if (lRowsOffset == 0 && cRows > 0 && iStepSize < 0)
  5222. break;
  5223. // in the case where we have iStepSize < 0, move the row back
  5224. // further because we want the previous row
  5225. DBROWOFFSET lRow = lRowsOffset;
  5226. if ((lRowsOffset == 0) && (lTmpRows == 0) && (iStepSize < 0))
  5227. lRow = cRowsInSet;
  5228. if (iStepSize < 0)
  5229. lRow += iStepSize;
  5230. hr = pT->CreateRow(lRow, *pcRowsObtained, *prghRows);
  5231. if (FAILED(hr))
  5232. {
  5233. RefRows(*pcRowsObtained, *prghRows, NULL, NULL, FALSE);
  5234. for (ULONG iRowDel = 0; iRowDel < *pcRowsObtained; iRowDel++)
  5235. *prghRows[iRowDel] = NULL;
  5236. *pcRowsObtained = 0;
  5237. return hr;
  5238. }
  5239. cRows--;
  5240. lRowsOffset += iStepSize;
  5241. }
  5242. if ((lRowsOffset >= cRowsInSet && cRows) || (lRowsOffset < 0 && cRows) ||
  5243. (lRowsOffset == 0 && cRows > 0 && iStepSize < 0))
  5244. hr = DB_S_ENDOFROWSET;
  5245. m_iRowset = lRowsOffset;
  5246. if (SUCCEEDED(hr))
  5247. amr.Detach();
  5248. return hr;
  5249. }
  5250. STDMETHOD(ReleaseRows)(DBCOUNTITEM cRows,
  5251. const HROW rghRows[],
  5252. DBROWOPTIONS rgRowOptions[],
  5253. DBREFCOUNT rgRefCounts[],
  5254. DBROWSTATUS rgRowStatus[])
  5255. {
  5256. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::ReleaseRows\n");
  5257. if (cRows == 0)
  5258. return S_OK;
  5259. rgRowOptions;
  5260. return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, FALSE);
  5261. }
  5262. STDMETHOD(RestartPosition)(HCHAPTER /*hReserved*/)
  5263. {
  5264. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RestartPosition\n");
  5265. m_iRowset = 0;
  5266. m_bReset = true;
  5267. return S_OK;
  5268. }
  5269. MapClass m_rgRowHandles;
  5270. DBCOUNTITEM m_iRowset; // cursor
  5271. unsigned m_bCanScrollBack:1;
  5272. unsigned m_bCanFetchBack:1;
  5273. unsigned m_bReset:1;
  5274. };
  5275. ///////////////////////////////////////////////////////////////////////////
  5276. // IRowsetIdentityImpl
  5277. template <class T, class RowClass = CSimpleRow>
  5278. class ATL_NO_VTABLE IRowsetIdentityImpl : public IRowsetIdentity
  5279. {
  5280. public:
  5281. STDMETHOD(IsSameRow)(HROW hThisRow, HROW hThatRow)
  5282. {
  5283. ATLTRACE2(atlTraceDBProvider, 0, _T("IRowsetIdentityImpl::IsSameRow"));
  5284. T* pT = (T*)this;
  5285. // Validate row handles
  5286. RowClass* pRow1 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThisRow);
  5287. RowClass* pRow2 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThatRow);
  5288. if (pRow1 == NULL || pRow2 == NULL)
  5289. return DB_E_BADROWHANDLE;
  5290. return pRow1->Compare(pRow2);
  5291. };
  5292. };
  5293. template <class T>
  5294. class ATL_NO_VTABLE IInternalConnectionImpl : public IInternalConnection
  5295. {
  5296. public:
  5297. STDMETHOD(AddConnection)()
  5298. {
  5299. T* pT = (T*)this;
  5300. T::_ThreadModel::Increment(&pT->m_cSessionsOpen);
  5301. return S_OK;
  5302. }
  5303. STDMETHOD(ReleaseConnection)()
  5304. {
  5305. T* pT = (T*)this;
  5306. T::_ThreadModel::Decrement(&pT->m_cSessionsOpen);
  5307. return S_OK;
  5308. }
  5309. };
  5310. template <class T>
  5311. class ATL_NO_VTABLE IObjectWithSiteSessionImpl : public IObjectWithSiteImpl< T >
  5312. {
  5313. public:
  5314. ~IObjectWithSiteSessionImpl()
  5315. {
  5316. CComPtr<IInternalConnection> pConn;
  5317. if (m_spUnkSite != NULL)
  5318. {
  5319. if (SUCCEEDED(m_spUnkSite->QueryInterface(IID_IInternalConnection, (void**)&pConn)))
  5320. pConn->ReleaseConnection();
  5321. }
  5322. }
  5323. STDMETHOD(SetSite)(IUnknown* pCreator)
  5324. {
  5325. HRESULT hr = S_OK;
  5326. T* pT = (T*)this;
  5327. pT->Lock();
  5328. m_spUnkSite = pCreator;
  5329. pT->Unlock();
  5330. CComPtr<IInternalConnection> pConn;
  5331. if (pCreator != NULL)
  5332. {
  5333. hr = pCreator->QueryInterface(IID_IInternalConnection, (void**)&pConn);
  5334. if (SUCCEEDED(hr))
  5335. hr = pConn->AddConnection();
  5336. }
  5337. return hr;
  5338. }
  5339. };
  5340. template <class T>
  5341. class ATL_NO_VTABLE IRowsetCreatorImpl : public IObjectWithSiteImpl< T >
  5342. {
  5343. public:
  5344. STDMETHOD(SetSite)(IUnknown* pCreator)
  5345. {
  5346. T* pT = (T*)this;
  5347. HRESULT hr = S_OK;
  5348. pT->Lock();
  5349. m_spUnkSite = pCreator;
  5350. pT->Unlock();
  5351. CComVariant varPropScroll, varPropFetch;
  5352. HRESULT hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANSCROLLBACKWARDS, &varPropScroll);
  5353. if (SUCCEEDED(hrProps))
  5354. pT->m_bCanScrollBack = varPropScroll.boolVal == VARIANT_TRUE;
  5355. hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANFETCHBACKWARDS, &varPropFetch);
  5356. if (SUCCEEDED(hrProps))
  5357. pT->m_bCanFetchBack = (varPropFetch.boolVal == VARIANT_TRUE);
  5358. return hr;
  5359. }
  5360. };
  5361. // IRowsetInfoImpl
  5362. template <class T, class PropClass = T>
  5363. class ATL_NO_VTABLE IRowsetInfoImpl :
  5364. public IRowsetInfo,
  5365. public CUtlProps<PropClass>
  5366. {
  5367. public:
  5368. static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL))
  5369. {
  5370. return PropClass::_GetPropSet(pNumPropSets, pcElemPerSupported, pSet, pguidSet);
  5371. }
  5372. STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
  5373. const DBPROPIDSET rgPropertyIDSets[],
  5374. ULONG *pcPropertySets,
  5375. DBPROPSET **prgPropertySets)
  5376. {
  5377. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetProperties\n");
  5378. HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  5379. const GUID* ppGuid[1];
  5380. ppGuid[0] = &DBPROPSET_ROWSET;
  5381. if(SUCCEEDED(hr))
  5382. return CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
  5383. rgPropertyIDSets, pcPropertySets, prgPropertySets,
  5384. 1, ppGuid);
  5385. else
  5386. return hr;
  5387. }
  5388. OUT_OF_LINE ATLCOLUMNINFO* InternalGetColumnInfo(DBORDINAL* pcCols)
  5389. {
  5390. return T::GetColumnInfo((T*)this, pcCols);
  5391. }
  5392. STDMETHOD(GetReferencedRowset)(DBORDINAL iOrdinal,
  5393. REFIID riid,
  5394. IUnknown **ppReferencedRowset)
  5395. {
  5396. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset\n");
  5397. DBORDINAL cCols=0;
  5398. // Check Arguments
  5399. if( ppReferencedRowset == NULL )
  5400. {
  5401. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset : Error NULL IUnk output Param\n");
  5402. return E_INVALIDARG;
  5403. }
  5404. *ppReferencedRowset = NULL;
  5405. // Check to see if column in question is a bookmark
  5406. ATLCOLUMNINFO* pColInfo = InternalGetColumnInfo(&cCols);
  5407. for (ULONG iColInfo = 0;
  5408. iColInfo < cCols && iOrdinal != pColInfo[iColInfo].iOrdinal;
  5409. iColInfo++);
  5410. if (iColInfo == cCols)
  5411. return DB_E_BADORDINAL;
  5412. ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
  5413. if ((pColCur->dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) == 0)
  5414. return DB_E_NOTAREFERENCECOLUMN;
  5415. // Query for requested interface
  5416. return QueryInterface(riid, (void**)ppReferencedRowset);
  5417. }
  5418. STDMETHOD(GetSpecification)(REFIID riid,
  5419. IUnknown **ppSpecification)
  5420. {
  5421. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetSpecification\n");
  5422. if (ppSpecification == NULL)
  5423. return E_INVALIDARG;
  5424. T* pT = (T*) this;
  5425. T::ObjectLock cab(pT);
  5426. ATLASSERT(pT->m_spUnkSite != NULL);
  5427. return pT->m_spUnkSite->QueryInterface(riid, (void**)ppSpecification);
  5428. }
  5429. };
  5430. template <class T, class Storage, class CreatorClass,
  5431. class ArrayType = CSimpleArray<Storage>,
  5432. class RowClass = CSimpleRow,
  5433. class RowsetInterface = IRowsetImpl < T, IRowset, RowClass> >
  5434. class CRowsetImpl :
  5435. public CComObjectRootEx<CreatorClass::_ThreadModel>,
  5436. public IAccessorImpl<T>,
  5437. public IRowsetIdentityImpl<T, RowClass>,
  5438. public IRowsetCreatorImpl<T>,
  5439. public IRowsetInfoImpl<T, CreatorClass::_PropClass>,
  5440. public IColumnsInfoImpl<T>,
  5441. public IConvertTypeImpl<T>,
  5442. public RowsetInterface
  5443. {
  5444. public:
  5445. typedef CreatorClass _RowsetCreatorClass;
  5446. typedef ArrayType _RowsetArrayType;
  5447. typedef CRowsetImpl< T, Storage, CreatorClass, ArrayType, RowClass, RowsetInterface> _RowsetBaseClass;
  5448. BEGIN_COM_MAP(CRowsetImpl)
  5449. COM_INTERFACE_ENTRY(IAccessor)
  5450. COM_INTERFACE_ENTRY(IObjectWithSite)
  5451. COM_INTERFACE_ENTRY(IRowsetInfo)
  5452. COM_INTERFACE_ENTRY(IColumnsInfo)
  5453. COM_INTERFACE_ENTRY(IConvertType)
  5454. COM_INTERFACE_ENTRY(IRowsetIdentity)
  5455. COM_INTERFACE_ENTRY(IRowset)
  5456. END_COM_MAP()
  5457. HRESULT FinalConstruct()
  5458. {
  5459. HRESULT hr = IAccessorImpl<T>::FinalConstruct();
  5460. if (FAILED(hr))
  5461. return hr;
  5462. return CConvertHelper::FinalConstruct();
  5463. }
  5464. HRESULT NameFromDBID(DBID* pDBID, CComBSTR& bstr, bool bIndex)
  5465. {
  5466. if (pDBID->uName.pwszName != NULL)
  5467. {
  5468. bstr = pDBID->uName.pwszName;
  5469. if (m_strCommandText == (BSTR)NULL)
  5470. return E_OUTOFMEMORY;
  5471. return S_OK;
  5472. }
  5473. return (bIndex) ? DB_E_NOINDEX : DB_E_NOTABLE;
  5474. }
  5475. HRESULT GetCommandFromID(DBID* pTableID, DBID* pIndexID)
  5476. {
  5477. USES_CONVERSION;
  5478. HRESULT hr;
  5479. if (pTableID == NULL && pIndexID == NULL)
  5480. return E_INVALIDARG;
  5481. if (pTableID != NULL && pTableID->eKind == DBKIND_NAME)
  5482. {
  5483. hr = NameFromDBID(pTableID, m_strCommandText, true);
  5484. if (FAILED(hr))
  5485. return hr;
  5486. if (pIndexID != NULL)
  5487. {
  5488. if (pIndexID->eKind == DBKIND_NAME)
  5489. {
  5490. hr = NameFromDBID(pIndexID, m_strIndexText, false);
  5491. if (FAILED(hr))
  5492. {
  5493. m_strCommandText.Empty();
  5494. return hr;
  5495. }
  5496. }
  5497. else
  5498. {
  5499. m_strCommandText.Empty();
  5500. return DB_E_NOINDEX;
  5501. }
  5502. }
  5503. return S_OK;
  5504. }
  5505. if (pIndexID != NULL && pIndexID->eKind == DBKIND_NAME)
  5506. return NameFromDBID(pIndexID, m_strIndexText, false);
  5507. return S_OK;
  5508. }
  5509. HRESULT ValidateCommandID(DBID* pTableID, DBID* pIndexID)
  5510. {
  5511. HRESULT hr = S_OK;
  5512. if (pTableID != NULL)
  5513. {
  5514. hr = CUtlProps<T>::IsValidDBID(pTableID);
  5515. if (hr != S_OK)
  5516. return hr;
  5517. // Check for a NULL TABLE ID (where its a valid pointer but NULL)
  5518. if ((pTableID->eKind == DBKIND_GUID_NAME ||
  5519. pTableID->eKind == DBKIND_NAME ||
  5520. pTableID->eKind == DBKIND_PGUID_NAME)
  5521. && pTableID->uName.pwszName == NULL)
  5522. return DB_E_NOTABLE;
  5523. }
  5524. if (pIndexID != NULL)
  5525. hr = CUtlProps<T>::IsValidDBID(pIndexID);
  5526. return hr;
  5527. }
  5528. HRESULT SetCommandText(DBID* pTableID, DBID* pIndexID)
  5529. {
  5530. T* pT = (T*)this;
  5531. HRESULT hr = pT->ValidateCommandID(pTableID, pIndexID);
  5532. if (FAILED(hr))
  5533. return hr;
  5534. hr = pT->GetCommandFromID(pTableID, pIndexID);
  5535. return hr;
  5536. }
  5537. void FinalRelease()
  5538. {
  5539. m_rgRowData.RemoveAll();
  5540. }
  5541. static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols)
  5542. {
  5543. return Storage::GetColumnInfo(pv,pcCols);
  5544. }
  5545. CComBSTR m_strCommandText;
  5546. CComBSTR m_strIndexText;
  5547. ArrayType m_rgRowData;
  5548. };
  5549. class CTABLESRow
  5550. {
  5551. public:
  5552. WCHAR m_szCatalog[129];
  5553. WCHAR m_szSchema[129];
  5554. WCHAR m_szTable[129];
  5555. WCHAR m_szType[129];
  5556. WCHAR m_szDesc[129];
  5557. GUID m_guid;
  5558. ULONG m_ulPropID;
  5559. CTABLESRow()
  5560. {
  5561. m_szCatalog[0] = NULL;
  5562. m_szSchema[0] = NULL;
  5563. m_szTable[0] = NULL;
  5564. m_szType[0] = NULL;
  5565. m_szDesc[0] = NULL;
  5566. m_guid = GUID_NULL;
  5567. m_ulPropID = 0;
  5568. }
  5569. BEGIN_PROVIDER_COLUMN_MAP(CTABLESRow)
  5570. PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szCatalog)
  5571. PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szSchema)
  5572. PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTable)
  5573. PROVIDER_COLUMN_ENTRY("TABLE_TYPE", 4, m_szType)
  5574. PROVIDER_COLUMN_ENTRY("TABLE_GUID", 5, m_guid)
  5575. PROVIDER_COLUMN_ENTRY("DESCRIPTION", 6, m_szDesc)
  5576. PROVIDER_COLUMN_ENTRY("TABLE_PROPID", 7, m_ulPropID)
  5577. END_PROVIDER_COLUMN_MAP()
  5578. };
  5579. class CCOLUMNSRow
  5580. {
  5581. public:
  5582. WCHAR m_szTableCatalog[129];
  5583. WCHAR m_szTableSchema[129];
  5584. WCHAR m_szTableName[129];
  5585. WCHAR m_szColumnName[129];
  5586. GUID m_guidColumn;
  5587. ULONG m_ulColumnPropID;
  5588. DBORDINAL m_ulOrdinalPosition;
  5589. VARIANT_BOOL m_bColumnHasDefault;
  5590. WCHAR m_szColumnDefault[129];
  5591. ULONG m_ulColumnFlags;
  5592. VARIANT_BOOL m_bIsNullable;
  5593. USHORT m_nDataType;
  5594. GUID m_guidType;
  5595. DBLENGTH m_ulCharMaxLength;
  5596. ULONG m_ulCharOctetLength;
  5597. USHORT m_nNumericPrecision;
  5598. short m_nNumericScale;
  5599. ULONG m_ulDateTimePrecision;
  5600. WCHAR m_szCharSetCatalog[129];
  5601. WCHAR m_szCharSetSchema[129];
  5602. WCHAR m_szCharSetName[129];
  5603. WCHAR m_szCollationCatalog[129];
  5604. WCHAR m_szCollationSchema[129];
  5605. WCHAR m_szCollationName[129];
  5606. WCHAR m_szDomainCatalog[129];
  5607. WCHAR m_szDomainSchema[129];
  5608. WCHAR m_szDomainName[129];
  5609. WCHAR m_szDescription[129];
  5610. CCOLUMNSRow()
  5611. {
  5612. ClearMembers();
  5613. }
  5614. void ClearMembers()
  5615. {
  5616. m_szTableCatalog[0] = NULL;
  5617. m_szTableSchema[0] = NULL;
  5618. m_szTableName[0] = NULL;
  5619. m_szColumnName[0] = NULL;
  5620. m_guidColumn = GUID_NULL;
  5621. m_ulColumnPropID = 0;
  5622. m_ulOrdinalPosition = 0;
  5623. m_bColumnHasDefault = VARIANT_FALSE;
  5624. m_szColumnDefault[0] = NULL;
  5625. m_ulColumnFlags = 0;
  5626. m_bIsNullable = VARIANT_FALSE;
  5627. m_nDataType = 0;
  5628. m_guidType = GUID_NULL;
  5629. m_ulCharMaxLength = 0;
  5630. m_ulCharOctetLength = 0;
  5631. m_nNumericPrecision = 0;
  5632. m_nNumericScale = 0;
  5633. m_ulDateTimePrecision = 0;
  5634. m_szCharSetCatalog[0] = NULL;
  5635. m_szCharSetSchema[0] = NULL;
  5636. m_szCharSetName[0] = NULL;
  5637. m_szCollationCatalog[0] = NULL;
  5638. m_szCollationSchema[0] = NULL;
  5639. m_szCollationName[0] = NULL;
  5640. m_szDomainCatalog[0] = NULL;
  5641. m_szDomainSchema[0] = NULL;
  5642. m_szDomainName[0] = NULL;
  5643. m_szDescription[0] = NULL;
  5644. }
  5645. BEGIN_PROVIDER_COLUMN_MAP(CCOLUMNSRow)
  5646. PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szTableCatalog)
  5647. PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szTableSchema)
  5648. PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTableName)
  5649. PROVIDER_COLUMN_ENTRY("COLUMN_NAME", 4, m_szColumnName)
  5650. PROVIDER_COLUMN_ENTRY("COLUMN_GUID",5, m_guidColumn)
  5651. PROVIDER_COLUMN_ENTRY("COLUMN_PROPID",6, m_ulColumnPropID)
  5652. PROVIDER_COLUMN_ENTRY("ORDINAL_POSITION",7, m_ulOrdinalPosition)
  5653. PROVIDER_COLUMN_ENTRY("COLUMN_HASDEFAULT",8, m_bColumnHasDefault)
  5654. PROVIDER_COLUMN_ENTRY("COLUMN_DEFAULT",9, m_szColumnDefault)
  5655. PROVIDER_COLUMN_ENTRY("COLUMN_FLAGS",10, m_ulColumnFlags)
  5656. PROVIDER_COLUMN_ENTRY("IS_NULLABLE",11, m_bIsNullable)
  5657. PROVIDER_COLUMN_ENTRY("DATA_TYPE",12, m_nDataType)
  5658. PROVIDER_COLUMN_ENTRY("TYPE_GUID",13, m_guidType)
  5659. PROVIDER_COLUMN_ENTRY("CHARACTER_MAXIMUM_LENGTH",14, m_ulCharMaxLength)
  5660. PROVIDER_COLUMN_ENTRY("CHARACTER_OCTET_LENGTH",15, m_ulCharOctetLength)
  5661. PROVIDER_COLUMN_ENTRY("NUMERIC_PRECISION",16, m_nNumericPrecision)
  5662. PROVIDER_COLUMN_ENTRY("NUMERIC_SCALE",17, m_nNumericScale)
  5663. PROVIDER_COLUMN_ENTRY("DATETIME_PRECISION",18, m_ulDateTimePrecision)
  5664. PROVIDER_COLUMN_ENTRY("CHARACTER_SET_CATALOG", 19, m_szCharSetCatalog)
  5665. PROVIDER_COLUMN_ENTRY("CHARACTER_SET_SCHEMA", 20, m_szCharSetSchema)
  5666. PROVIDER_COLUMN_ENTRY("CHARACTER_SET_NAME", 21, m_szCharSetName)
  5667. PROVIDER_COLUMN_ENTRY("COLLATION_CATALOG", 22, m_szCollationCatalog)
  5668. PROVIDER_COLUMN_ENTRY("COLLATION_SCHEMA", 23, m_szCollationSchema)
  5669. PROVIDER_COLUMN_ENTRY("COLLATION_NAME", 24, m_szCollationName)
  5670. PROVIDER_COLUMN_ENTRY("DOMAIN_CATALOG", 25, m_szDomainCatalog)
  5671. PROVIDER_COLUMN_ENTRY("DOMAIN_SCHEMA", 26, m_szDomainSchema)
  5672. PROVIDER_COLUMN_ENTRY("DOMAIN_NAME", 27, m_szDomainName)
  5673. PROVIDER_COLUMN_ENTRY("DESCRIPTION", 28, m_szDescription)
  5674. END_PROVIDER_COLUMN_MAP()
  5675. };
  5676. template <class ArrayClass>
  5677. HRESULT InitFromRowset(ArrayClass& rgData, DBID* pTableID, DBID* pIndexID, IUnknown* pSession, LONG* pcRowsAffected)
  5678. {
  5679. CComQIPtr<IOpenRowset> spOpenRowset = pSession;
  5680. if (spOpenRowset == NULL)
  5681. return E_FAIL;
  5682. CComPtr<IColumnsInfo> spColInfo;
  5683. HRESULT hr = spOpenRowset->OpenRowset(NULL, pTableID, pIndexID, IID_IColumnsInfo, 0, NULL, (IUnknown**)&spColInfo);
  5684. if (FAILED(hr))
  5685. return hr;
  5686. LPOLESTR szColumns = NULL;
  5687. DBORDINAL cColumns = 0;
  5688. DBCOLUMNINFO* pColInfo = NULL;
  5689. hr = spColInfo->GetColumnInfo(&cColumns, &pColInfo, &szColumns);
  5690. if (FAILED(hr))
  5691. return hr;
  5692. *pcRowsAffected = 0;
  5693. for (ULONG iCol = 0; iCol < cColumns; iCol++)
  5694. {
  5695. CCOLUMNSRow crData;
  5696. DBCOLUMNINFO& rColCur = pColInfo[iCol];
  5697. lstrcpynW(crData.m_szTableName, pTableID->uName.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szTableName));
  5698. lstrcpynW(crData.m_szColumnName, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
  5699. lstrcpynW(crData.m_szDescription, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
  5700. GUID* pGuidCol = CDBIDOps::GetDBIDpGuid(rColCur.columnid);
  5701. if (pGuidCol)
  5702. crData.m_guidColumn = *pGuidCol;
  5703. else
  5704. crData.m_guidColumn = GUID_NULL;
  5705. crData.m_ulColumnPropID = CDBIDOps::GetPropIDFromDBID(rColCur.columnid);
  5706. crData.m_ulOrdinalPosition = rColCur.iOrdinal;
  5707. crData.m_ulColumnFlags = rColCur.dwFlags;
  5708. crData.m_bIsNullable = (rColCur.dwFlags & DBCOLUMNFLAGS_ISNULLABLE) ? VARIANT_TRUE : VARIANT_FALSE;
  5709. crData.m_nDataType = rColCur.wType;
  5710. crData.m_ulCharMaxLength = rColCur.ulColumnSize;
  5711. crData.m_nNumericPrecision = rColCur.bPrecision;
  5712. crData.m_nNumericScale = rColCur.bScale;
  5713. if (!rgData.Add(crData))
  5714. {
  5715. CoTaskMemFree(pColInfo);
  5716. CoTaskMemFree(szColumns);
  5717. return E_OUTOFMEMORY;
  5718. }
  5719. *pcRowsAffected++;
  5720. }
  5721. CoTaskMemFree(pColInfo);
  5722. CoTaskMemFree(szColumns);
  5723. return S_OK;
  5724. }
  5725. class CPROVIDER_TYPERow
  5726. {
  5727. public:
  5728. // Attributes
  5729. WCHAR m_szName[129];
  5730. USHORT m_nType;
  5731. ULONG m_ulSize;
  5732. WCHAR m_szPrefix[129];
  5733. WCHAR m_szSuffix[129];
  5734. WCHAR m_szCreateParams[129];
  5735. VARIANT_BOOL m_bIsNullable;
  5736. VARIANT_BOOL m_bCaseSensitive;
  5737. ULONG m_bSearchable;
  5738. VARIANT_BOOL m_bUnsignedAttribute;
  5739. VARIANT_BOOL m_bFixedPrecScale;
  5740. VARIANT_BOOL m_bAutoUniqueValue;
  5741. WCHAR m_szLocalTypeName[129];
  5742. short m_nMinScale;
  5743. short m_nMaxScale;
  5744. GUID m_guidType;
  5745. WCHAR m_szTypeLib[129];
  5746. WCHAR m_szVersion[129];
  5747. VARIANT_BOOL m_bIsLong;
  5748. VARIANT_BOOL m_bBestMatch;
  5749. VARIANT_BOOL m_bIsFixedLength;
  5750. CPROVIDER_TYPERow()
  5751. {
  5752. m_szName[0] = NULL;
  5753. m_nType = 0;
  5754. m_ulSize = 0;
  5755. m_szPrefix[0] = NULL;
  5756. m_szSuffix[0] = NULL;
  5757. m_szCreateParams[0] = NULL;
  5758. m_bIsNullable = VARIANT_FALSE;
  5759. m_bCaseSensitive = VARIANT_FALSE;
  5760. m_bSearchable = DB_UNSEARCHABLE;
  5761. m_bUnsignedAttribute = VARIANT_FALSE;
  5762. m_bFixedPrecScale = VARIANT_FALSE;
  5763. m_bAutoUniqueValue = VARIANT_FALSE;
  5764. m_szLocalTypeName[0] = NULL;
  5765. m_nMinScale = 0;
  5766. m_nMaxScale = 0;
  5767. m_guidType = GUID_NULL;
  5768. m_szTypeLib[0] = NULL;
  5769. m_szVersion[0] = NULL;
  5770. m_bIsLong = VARIANT_FALSE;
  5771. m_bBestMatch = VARIANT_FALSE;
  5772. m_bIsFixedLength = VARIANT_FALSE;
  5773. }
  5774. // Binding Maps
  5775. BEGIN_PROVIDER_COLUMN_MAP(CPROVIDER_TYPERow)
  5776. PROVIDER_COLUMN_ENTRY("TYPE_NAME", 1, m_szName)
  5777. PROVIDER_COLUMN_ENTRY("DATA_TYPE", 2, m_nType)
  5778. PROVIDER_COLUMN_ENTRY("COLUMN_SIZE", 3, m_ulSize)
  5779. PROVIDER_COLUMN_ENTRY("LITERAL_PREFIX", 4, m_szPrefix)
  5780. PROVIDER_COLUMN_ENTRY("LITERAL_SUFFIX", 5, m_szSuffix)
  5781. PROVIDER_COLUMN_ENTRY("CREATE_PARAMS", 6, m_szCreateParams)
  5782. PROVIDER_COLUMN_ENTRY("IS_NULLABLE", 7, m_bIsNullable)
  5783. PROVIDER_COLUMN_ENTRY("CASE_SENSITIVE", 8, m_bCaseSensitive)
  5784. PROVIDER_COLUMN_ENTRY("SEARCHABLE", 9, m_bSearchable)
  5785. PROVIDER_COLUMN_ENTRY("UNSIGNED_ATTRIBUTE", 10, ,m_bUnsignedAttribute)
  5786. PROVIDER_COLUMN_ENTRY("FIXED_PREC_SCALE", 11, m_bFixedPrecScale)
  5787. PROVIDER_COLUMN_ENTRY("AUTO_UNIQUE_VALUE", 12, m_bAutoUniqueValue)
  5788. PROVIDER_COLUMN_ENTRY("LOCAL_TYPE_NAME", 13, m_szLocalTypeName)
  5789. PROVIDER_COLUMN_ENTRY("MINIMUM_SCALE", 14, m_nMinScale)
  5790. PROVIDER_COLUMN_ENTRY("MAXIMUM_SCALE", 15, m_nMaxScale)
  5791. PROVIDER_COLUMN_ENTRY("GUID", 16, m_guidType)
  5792. PROVIDER_COLUMN_ENTRY("TYPELIB", 17, m_szTypeLib)
  5793. PROVIDER_COLUMN_ENTRY("VERSION", 18, m_szVersion)
  5794. PROVIDER_COLUMN_ENTRY("IS_LONG", 19, m_bIsLong)
  5795. PROVIDER_COLUMN_ENTRY("BEST_MATCH", 20, m_bBestMatch)
  5796. PROVIDER_COLUMN_ENTRY("IS_FIXEDLENGTH", 21, m_bIsFixedLength)
  5797. END_PROVIDER_COLUMN_MAP()
  5798. };
  5799. class CEnumRowsetImpl
  5800. {
  5801. public:
  5802. WCHAR m_szSourcesName[256];
  5803. WCHAR m_szSourcesParseName[256];
  5804. WCHAR m_szSourcesDescription[256];
  5805. unsigned short m_iType;
  5806. VARIANT_BOOL m_bIsParent;
  5807. BEGIN_PROVIDER_COLUMN_MAP(CEnumRowsetImpl)
  5808. PROVIDER_COLUMN_ENTRY("SOURCES_NAME", 1, m_szSourcesName)
  5809. PROVIDER_COLUMN_ENTRY("SOURCES_PARSENAME", 2, m_szSourcesParseName)
  5810. PROVIDER_COLUMN_ENTRY("SOURCES_DESCRIPTION", 3, m_szSourcesDescription)
  5811. PROVIDER_COLUMN_ENTRY("SOURCES_TYPE", 4, m_iType)
  5812. PROVIDER_COLUMN_ENTRY("SOURCES_ISPARENT", 5, m_bIsParent)
  5813. END_PROVIDER_COLUMN_MAP()
  5814. };
  5815. #endif