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

6432 lines
297 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(const T& val, const T& valMin, const 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)-1)))
  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. pT->Unlock();
  1048. return DB_E_OBJECTOPEN;
  1049. }
  1050. delete m_pCUtlPropInfo;
  1051. m_pCUtlPropInfo = NULL;
  1052. pT->m_dwStatus |= DSF_PERSIST_DIRTY;
  1053. pT->m_dwStatus &= DSF_MASK_INIT; // Clear all non-init flags.
  1054. pT->Unlock();
  1055. return S_OK;
  1056. }
  1057. LONG m_cSessionsOpen;
  1058. DWORD m_dwStatus;
  1059. CUtlPropInfo<T>* m_pCUtlPropInfo;
  1060. STDMETHOD(Initialize)(void)
  1061. {
  1062. ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize\n");
  1063. T *pT = (T*)(this);
  1064. T::ObjectLock lock(pT);
  1065. HRESULT hr;
  1066. if (pT->m_dwStatus & DSF_INITIALIZED)
  1067. {
  1068. ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : Already Initialized\n");
  1069. return DB_E_ALREADYINITIALIZED;
  1070. }
  1071. delete m_pCUtlPropInfo;
  1072. m_pCUtlPropInfo = NULL;
  1073. ATLTRY(m_pCUtlPropInfo = new CUtlPropInfo<T>())
  1074. if (m_pCUtlPropInfo == NULL)
  1075. {
  1076. ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : OOM\n");
  1077. return E_OUTOFMEMORY;
  1078. }
  1079. hr = m_pCUtlPropInfo->FInit();
  1080. if (hr == S_OK)
  1081. {
  1082. pT->m_dwStatus |= DSF_INITIALIZED;
  1083. }
  1084. else
  1085. {
  1086. delete m_pCUtlPropInfo;
  1087. m_pCUtlPropInfo = NULL;
  1088. }
  1089. return hr;
  1090. }
  1091. };
  1092. // Implementation Class
  1093. class CPropColID :
  1094. public PROPCOLID,
  1095. public CDBIDOps
  1096. {
  1097. public:
  1098. CPropColID()
  1099. {
  1100. VariantInit(&vValue);
  1101. }
  1102. ~CPropColID()
  1103. {
  1104. FreeDBIDs(&dbidProperty);
  1105. VariantClear(&vValue);
  1106. }
  1107. bool operator==(const CPropColID& colId)
  1108. {
  1109. return (CompareDBIDs(&dbidProperty, &(colId.dbidProperty)) == S_OK) ? true : false;
  1110. }
  1111. };
  1112. class CColumnIds :
  1113. public CDBIDOps,
  1114. public CSimpleArray<CPropColID>
  1115. {
  1116. public:
  1117. PPROPCOLID AddNode()
  1118. {
  1119. CPropColID colID;
  1120. if (Add(colID))
  1121. return &(m_aT[GetSize()]);
  1122. return NULL;
  1123. }
  1124. HRESULT RemoveColumnId(const DBID* pdbidProp)
  1125. {
  1126. for (int i = 0; i < GetSize(); i++)
  1127. {
  1128. if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
  1129. return (RemoveAt(i)) ? S_OK : E_FAIL;
  1130. }
  1131. return E_FAIL;
  1132. }
  1133. HRESULT AddColumnId(DBPROP* pProp)
  1134. {
  1135. CPropColID colID;
  1136. HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pProp->colid));
  1137. if(FAILED(hr))
  1138. return hr;
  1139. colID.dwOption = pProp->dwOptions;
  1140. hr = VariantCopy(&(colID.vValue),&(pProp->vValue));
  1141. if(FAILED(hr))
  1142. return hr;
  1143. return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
  1144. }
  1145. HRESULT AddColumnId(PPROPCOLID pPropNode)
  1146. {
  1147. CPropColID colID;
  1148. HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pPropNode->dbidProperty));
  1149. if(FAILED(hr))
  1150. return hr;
  1151. colID.dwOption = pPropNode->dwOption;
  1152. hr = VariantCopy(&(colID.vValue),&(pPropNode->vValue));
  1153. if(FAILED(hr))
  1154. return hr;
  1155. return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
  1156. }
  1157. ULONG GetCountOfPropColids(){ return (ULONG)GetSize();}
  1158. PPROPCOLID FindColumnId(const DBID* pdbidProp)
  1159. {
  1160. for (int i = 0; i < GetSize(); i++)
  1161. {
  1162. if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
  1163. return &(m_aT[i]);
  1164. }
  1165. return NULL;
  1166. }
  1167. HRESULT GetValue(int iColId, DWORD* pdwOptions, DBID* pColid, VARIANT* pvValue)
  1168. {
  1169. HRESULT hr;
  1170. ATLASSERT(pdwOptions && pColid && pvValue);
  1171. ATLASSERT(iColId >= 0 && iColId < m_nSize);
  1172. CPropColID& colId = m_aT[iColId];
  1173. *pdwOptions = colId.dwOption;
  1174. CopyDBIDs( pColid, &(colId.dbidProperty) );
  1175. if(FAILED(hr = VariantCopy(pvValue, &(colId.vValue))))
  1176. return hr;
  1177. return S_OK;
  1178. }
  1179. };
  1180. const ULONG cchDescBuffSize = 256;
  1181. const DWORD DBINTERNFLAGS_CHANGED = 0x00000001;
  1182. // Rules for GetPropertiesArgChk
  1183. const DWORD ARGCHK_PROPERTIESINERROR = 0x00000001;
  1184. // Implementation Class
  1185. template <class T>
  1186. class CUtlPropInfo : public CBitFieldOps, public CDBIDOps
  1187. {
  1188. public:
  1189. enum EnumGetPropInfo
  1190. {
  1191. GETPROPINFO_ALLPROPIDS = 0x0001,
  1192. GETPROPINFO_NOTSUPPORTED = 0x0002,
  1193. GETPROPINFO_ERRORSOCCURRED = 0x0004,
  1194. GETPROPINFO_VALIDPROP = 0x0008
  1195. };
  1196. CUtlPropInfo()
  1197. {
  1198. m_cUPropSet = 0;
  1199. m_pUPropSet = NULL;
  1200. m_cPropSetDex = 0;
  1201. m_rgiPropSetDex = NULL;
  1202. m_cElemPerSupported = 0;
  1203. m_rgdwSupported = NULL;
  1204. }
  1205. ~CUtlPropInfo()
  1206. {
  1207. delete[] m_rgiPropSetDex;
  1208. delete[] m_rgdwSupported;
  1209. if (m_pUPropSet != NULL)
  1210. CoTaskMemFree(m_pUPropSet);
  1211. }
  1212. //Determine the number of description buffers needed
  1213. ULONG CalcDescripBuffers(ULONG cPropInfoSet, DBPROPINFOSET* pPropInfoSet)
  1214. {
  1215. ULONG cBuffers = 0;
  1216. ATLASSERT(m_pUPropSet);
  1217. ATLASSERT(cPropInfoSet && pPropInfoSet);
  1218. for(ULONG ulSet=0; ulSet<cPropInfoSet; ulSet++)
  1219. {
  1220. if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
  1221. {
  1222. for(ULONG ul=0; ul<m_cPropSetDex; ul++)
  1223. {
  1224. cBuffers += m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo;
  1225. }
  1226. }
  1227. }
  1228. return cBuffers;
  1229. }
  1230. //Retrieve the property set indexes that match this property set.
  1231. HRESULT GetPropertySetIndex(const GUID* pPropertySet)
  1232. {
  1233. DWORD dwFlag = 0;
  1234. ULONG ulSet;
  1235. ATLASSERT(m_cUPropSet && m_pUPropSet);
  1236. ATLASSERT(m_rgiPropSetDex);
  1237. ATLASSERT(pPropertySet);
  1238. m_cPropSetDex = 0;
  1239. if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEALL))
  1240. {
  1241. dwFlag = DBPROPFLAGS_DATASOURCE;
  1242. }
  1243. else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEINFOALL))
  1244. {
  1245. dwFlag = DBPROPFLAGS_DATASOURCEINFO;
  1246. }
  1247. else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_ROWSETALL))
  1248. {
  1249. dwFlag = DBPROPFLAGS_ROWSET;
  1250. }
  1251. else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_DBINITALL))
  1252. {
  1253. dwFlag = DBPROPFLAGS_DBINIT;
  1254. }
  1255. else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_SESSIONALL))
  1256. {
  1257. dwFlag = DBPROPFLAGS_SESSION;
  1258. }
  1259. else // No scan required, just look for match.
  1260. {
  1261. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  1262. {
  1263. if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
  1264. {
  1265. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  1266. m_cPropSetDex++;
  1267. break;
  1268. }
  1269. }
  1270. goto EXIT;
  1271. }
  1272. // Scan through the property sets looking for matching attributes
  1273. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  1274. {
  1275. if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
  1276. {
  1277. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  1278. m_cPropSetDex++;
  1279. }
  1280. }
  1281. EXIT:
  1282. return (m_cPropSetDex) ? S_OK : S_FALSE;
  1283. }
  1284. //Retrieve the property id pointer
  1285. HRESULT GetUPropInfoPtr(ULONG iPropSetDex, DBPROPID dwPropertyId, UPROPINFO** ppUPropInfo)
  1286. {
  1287. // Scan through the property sets looking for matching attributes
  1288. for(ULONG ulProps=0; ulProps<m_pUPropSet[iPropSetDex].cUPropInfo; ulProps++)
  1289. {
  1290. if( m_pUPropSet[iPropSetDex].pUPropInfo[ulProps].dwPropId == dwPropertyId )
  1291. {
  1292. *ppUPropInfo = &(m_pUPropSet[iPropSetDex].pUPropInfo[ulProps]);
  1293. // Test to see if the property is supported for this
  1294. // instantiation
  1295. return (TESTBIT(&(m_rgdwSupported[iPropSetDex * m_cElemPerSupported]), ulProps)) ? S_OK : S_FALSE;
  1296. }
  1297. }
  1298. return S_FALSE;
  1299. }
  1300. HRESULT FInit(GUID* pguidSet = (GUID*)&GUID_NULL)
  1301. {
  1302. HRESULT hr;
  1303. hr = InitAvailUPropSets(&m_cUPropSet, &m_pUPropSet, &m_cElemPerSupported, pguidSet);
  1304. if (FAILED(hr))
  1305. return hr;
  1306. ATLASSERT((m_cUPropSet != 0) && (m_cElemPerSupported != 0));
  1307. if(!m_cUPropSet || !m_cElemPerSupported)
  1308. return E_FAIL;
  1309. ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  1310. if(m_rgdwSupported == NULL)
  1311. return E_OUTOFMEMORY;
  1312. if(FAILED(hr = InitUPropSetsSupported()))
  1313. {
  1314. delete[] m_rgdwSupported;
  1315. m_rgdwSupported = NULL;
  1316. return hr;
  1317. }
  1318. if(m_cUPropSet)
  1319. {
  1320. ATLTRY(m_rgiPropSetDex = new ULONG[m_cUPropSet])
  1321. if(m_rgiPropSetDex == NULL)
  1322. {
  1323. delete [] m_rgdwSupported;
  1324. return E_OUTOFMEMORY;
  1325. }
  1326. }
  1327. return S_OK;
  1328. }
  1329. HRESULT GetPropertyInfo(ULONG cPropertySets,
  1330. const DBPROPIDSET rgPropertySets[], ULONG* pcPropertyInfoSets,
  1331. DBPROPINFOSET** prgPropertyInfoSets,
  1332. WCHAR** ppDescBuffer, bool bInitialized = true,
  1333. const GUID* pGuid = NULL)
  1334. {
  1335. HRESULT hr = S_OK;
  1336. ULONG ul, ulSet, ulNext, ulEnd;
  1337. ULONG ulOutIndex;
  1338. ULONG cSets;
  1339. ULONG cPropInfos;
  1340. ULONG ulIndex = 0;
  1341. DWORD dwStatus = 0;
  1342. DBPROPINFO* pPropInfo = NULL;
  1343. DBPROPINFO* pCurPropInfo = NULL;
  1344. WCHAR* pDescBuffer = NULL;
  1345. DBPROPINFOSET* pPropInfoSet = NULL;
  1346. UPROPINFO* pUPropInfo = NULL;
  1347. WCHAR wszBuff[256];
  1348. int cch;
  1349. // If the consumer does not restrict the property sets
  1350. // by specify an array of property sets and a cPropertySets
  1351. // greater than 0, then we need to make sure we
  1352. // have some to return
  1353. if(cPropertySets == 0)
  1354. {
  1355. // Determine the number of property sets supported
  1356. // In this case, it usually the enumerator or data source asking for
  1357. // DBPROPSET_DBINIT information.
  1358. if (pGuid != NULL)
  1359. cSets = 1;
  1360. else
  1361. cSets = m_cUPropSet;
  1362. }
  1363. else
  1364. {
  1365. cSets = 0;
  1366. // Determine number of property sets required
  1367. // This is only required when any of the "special" property set GUIDs were specified
  1368. for(ulSet=0; ulSet<cPropertySets; ulSet++)
  1369. {
  1370. if (GetPropertySetIndex(&(rgPropertySets[ulSet].guidPropertySet)) == S_OK)
  1371. cSets += m_cPropSetDex;
  1372. else
  1373. cSets++;
  1374. }
  1375. }
  1376. ATLASSERT(cSets);
  1377. // Allocate the DBPROPINFOSET structures
  1378. pPropInfoSet = (DBPROPINFOSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPINFOSET));
  1379. if(pPropInfoSet == NULL)
  1380. {
  1381. ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
  1382. hr = E_OUTOFMEMORY;
  1383. goto EXIT;
  1384. }
  1385. memset(pPropInfoSet, 0, cSets * sizeof(DBPROPINFOSET));
  1386. ulOutIndex = 0;
  1387. // VC 6.0 ulEnd = cPropertySets == 0 ? cSets : cPropertySets;
  1388. ulEnd = cSets; // VC 6.0 SP3
  1389. // Fill in the output array
  1390. for(ulSet=0; ulSet<ulEnd; ulSet++)
  1391. {
  1392. // Depending of if Property sets are specified store the
  1393. // return property set.
  1394. if (cPropertySets == 0)
  1395. {
  1396. if (pGuid != NULL)
  1397. {
  1398. GUID const& guidSet = *pGuid;
  1399. if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) ||
  1400. InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) ||
  1401. InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) ||
  1402. InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) ||
  1403. InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) &&
  1404. GetPropertySetIndex(&guidSet) == S_OK )
  1405. {
  1406. for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++)
  1407. {
  1408. pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet);
  1409. pPropInfoSet[ulOutIndex].cPropertyInfos = 0;
  1410. ulIndex = m_rgiPropSetDex[ul];
  1411. }
  1412. }
  1413. else
  1414. {
  1415. for (ULONG l=0; l<m_cUPropSet; l++)
  1416. {
  1417. if (InlineIsEqualGUID(*m_pUPropSet[l].pPropSet, *pGuid))
  1418. ulIndex = l;
  1419. }
  1420. if (l == m_cUPropSet)
  1421. {
  1422. ATLTRACE2(atlTraceDBProvider, 0, "Property Info Set not supported");
  1423. ulIndex = 0;
  1424. }
  1425. pPropInfoSet[ulSet].guidPropertySet = *pGuid;
  1426. }
  1427. }
  1428. else
  1429. {
  1430. pPropInfoSet[ulSet].guidPropertySet = *(m_pUPropSet[ulSet].pPropSet);
  1431. }
  1432. }
  1433. else
  1434. {
  1435. GUID const& guidSet = rgPropertySets[ulSet].guidPropertySet;
  1436. if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) ||
  1437. InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) ||
  1438. InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) ||
  1439. InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) ||
  1440. InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) &&
  1441. GetPropertySetIndex(&guidSet) == S_OK )
  1442. {
  1443. for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++)
  1444. {
  1445. pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet);
  1446. pPropInfoSet[ulOutIndex].cPropertyInfos = 0;
  1447. }
  1448. }
  1449. else
  1450. {
  1451. // Handle non-category property sets
  1452. // Handle unknown property sets
  1453. pPropInfoSet[ulOutIndex].guidPropertySet = guidSet;
  1454. pPropInfoSet[ulOutIndex].cPropertyInfos = rgPropertySets[ulSet].cPropertyIDs;
  1455. ulOutIndex++;
  1456. }
  1457. }
  1458. }
  1459. // Allocate a Description Buffer if needed
  1460. if( ppDescBuffer )
  1461. {
  1462. ULONG cBuffers = CalcDescripBuffers(cSets, pPropInfoSet);
  1463. if( cBuffers != 0 )
  1464. {
  1465. pDescBuffer = (WCHAR*)CoTaskMemAlloc(cBuffers * cchDescBuffSize * sizeof(WCHAR));
  1466. if(pDescBuffer == NULL)
  1467. {
  1468. hr = E_OUTOFMEMORY;
  1469. goto EXIT;
  1470. }
  1471. *ppDescBuffer = pDescBuffer;
  1472. memset(pDescBuffer, 0, (cBuffers * cchDescBuffSize * sizeof(WCHAR)));
  1473. }
  1474. }
  1475. // Process requested or derived Property sets
  1476. dwStatus = 0;
  1477. for(ulSet=0; ulSet<cSets; ulSet++)
  1478. {
  1479. ulNext=0;
  1480. cPropInfos = 0;
  1481. pPropInfo = NULL;
  1482. dwStatus &= (GETPROPINFO_ERRORSOCCURRED | GETPROPINFO_VALIDPROP);
  1483. // Calculate the number of property nodes needed for this
  1484. // property set.
  1485. if( cPropertySets == 0 )
  1486. {
  1487. ULONG ulTempSet;
  1488. if (pGuid != NULL)
  1489. ulTempSet = ulIndex;
  1490. else
  1491. ulTempSet = ulSet;
  1492. cPropInfos = m_pUPropSet[ulTempSet].cUPropInfo;
  1493. dwStatus |= GETPROPINFO_ALLPROPIDS;
  1494. m_rgiPropSetDex[0] = ulTempSet;
  1495. m_cPropSetDex = 1;
  1496. }
  1497. else
  1498. {
  1499. // If the count of PROPIDs is 0 (NOTE: the above routine already determined
  1500. // if it belonged to a category and if so set the count of properties to 0 for
  1501. // each propset in that category.
  1502. if( pPropInfoSet[ulSet].cPropertyInfos == 0 )
  1503. {
  1504. dwStatus |= GETPROPINFO_ALLPROPIDS;
  1505. // We have to determine if the property set is supported and if so
  1506. // the count of properties in the set.
  1507. if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
  1508. {
  1509. ATLASSERT( m_cPropSetDex == 1 );
  1510. cPropInfos += m_pUPropSet[m_rgiPropSetDex[0]].cUPropInfo;
  1511. }
  1512. else
  1513. {
  1514. // Not Supported
  1515. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1516. goto NEXT_SET;
  1517. }
  1518. }
  1519. else
  1520. {
  1521. // We also handle the case here where the user has requested
  1522. // a non-initialization group property info set while the
  1523. // provider is not initialized. In this case, properties should
  1524. // not be set.
  1525. cPropInfos = pPropInfoSet[ulSet].cPropertyInfos;
  1526. if( (GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_FALSE)
  1527. || (!bInitialized &&
  1528. !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINIT)) &&
  1529. !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINITALL))))
  1530. {
  1531. dwStatus |= GETPROPINFO_NOTSUPPORTED;
  1532. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1533. }
  1534. }
  1535. }
  1536. // Allocate DBPROP array
  1537. ATLASSERT( cPropInfos != 0 );
  1538. pPropInfo = (DBPROPINFO*)CoTaskMemAlloc(cPropInfos * sizeof(DBPROPINFO));
  1539. if( pPropInfo )
  1540. {
  1541. // Initialize Buffer
  1542. memset(pPropInfo, 0, cPropInfos * sizeof(DBPROPINFO));
  1543. for(ULONG ulProp=0; ulProp<cPropInfos; ulProp++)
  1544. {
  1545. VariantInit(&(pPropInfo[ulProp].vValues));
  1546. if( dwStatus & GETPROPINFO_NOTSUPPORTED )
  1547. {
  1548. // Not supported, thus we need to mark all as NOT_SUPPORTED
  1549. pPropInfo[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  1550. pPropInfo[ulProp].dwFlags = DBPROPFLAGS_NOTSUPPORTED;
  1551. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1552. }
  1553. }
  1554. // Make sure we support the property set
  1555. if( dwStatus & GETPROPINFO_NOTSUPPORTED )
  1556. {
  1557. ulNext = cPropInfos;
  1558. goto NEXT_SET;
  1559. }
  1560. // Retrieve the property information for this property set
  1561. for(ul=0; ul<m_cPropSetDex; ul++)
  1562. {
  1563. pUPropInfo = (m_pUPropSet[m_rgiPropSetDex[ul]].pUPropInfo);
  1564. ATLASSERT( pUPropInfo );
  1565. // Retrieve current value of properties
  1566. if( dwStatus & GETPROPINFO_ALLPROPIDS )
  1567. {
  1568. for(ulProp=0; ulProp<m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo; ulProp++)
  1569. {
  1570. // Verify property is supported, if not do not return
  1571. if( !TESTBIT(&(m_rgdwSupported[m_rgiPropSetDex[ul] * m_cElemPerSupported]), ulProp) )
  1572. continue;
  1573. pCurPropInfo = &(pPropInfo[ulNext]);
  1574. // If the ppDescBuffer pointer was not NULL, then
  1575. // we need supply description of the properties
  1576. if( ppDescBuffer )
  1577. {
  1578. // Set Buffer pointer
  1579. pCurPropInfo->pwszDescription = pDescBuffer;
  1580. // Load the string into temp buffer
  1581. cch = LoadDescription(pUPropInfo[ulProp].ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
  1582. if( cch )
  1583. {
  1584. // Adjust for '\0'
  1585. cch++;
  1586. // Transfer to official buffer if room
  1587. memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
  1588. pDescBuffer += cch;
  1589. }
  1590. else
  1591. {
  1592. wcscpy(pDescBuffer, L"UNKNOWN");
  1593. pDescBuffer += (wcslen(L"UNKNOWN") + 1);
  1594. }
  1595. }
  1596. pCurPropInfo->dwPropertyID = pUPropInfo[ulProp].dwPropId;
  1597. pCurPropInfo->dwFlags = pUPropInfo[ulProp].dwFlags;
  1598. pCurPropInfo->vtType = pUPropInfo[ulProp].VarType;
  1599. pCurPropInfo->vValues.vt = VT_EMPTY;
  1600. dwStatus |= GETPROPINFO_VALIDPROP;
  1601. // Increment to next available buffer
  1602. ulNext++;
  1603. }
  1604. }
  1605. else
  1606. {
  1607. ATLASSERT( m_cPropSetDex == 1 );
  1608. for( ulProp = 0; ulProp < cPropInfos; ulProp++, ulNext++ )
  1609. {
  1610. pCurPropInfo = &(pPropInfo[ulNext]);
  1611. // Process Properties based on Restriction array.
  1612. pCurPropInfo->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  1613. if( GetUPropInfoPtr(m_rgiPropSetDex[ul], pCurPropInfo->dwPropertyID, &pUPropInfo)
  1614. == S_OK )
  1615. {
  1616. // If the ppDescBuffer pointer was not NULL, then
  1617. // we need supply description of the properties
  1618. if( ppDescBuffer )
  1619. {
  1620. // Set Buffer pointer
  1621. pCurPropInfo->pwszDescription = pDescBuffer;
  1622. // Load the string into temp buffer
  1623. cch = LoadDescription(pUPropInfo->ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
  1624. if( cch )
  1625. {
  1626. // Adjust for '\0'
  1627. cch++;
  1628. // Transfer to official buffer if room
  1629. memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
  1630. pDescBuffer += cch;
  1631. }
  1632. else
  1633. {
  1634. wcscpy(pDescBuffer, L"UNKNOWN");
  1635. pDescBuffer += (wcslen(L"UNKNOWN") + 1);
  1636. }
  1637. }
  1638. pCurPropInfo->dwPropertyID = pUPropInfo->dwPropId;
  1639. pCurPropInfo->dwFlags = pUPropInfo->dwFlags;
  1640. pCurPropInfo->vtType = pUPropInfo->VarType;
  1641. dwStatus |= GETPROPINFO_VALIDPROP;
  1642. }
  1643. else
  1644. {
  1645. // Not Supported
  1646. pCurPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED;
  1647. dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1648. }
  1649. }
  1650. }
  1651. }
  1652. }
  1653. else
  1654. {
  1655. hr = E_OUTOFMEMORY;
  1656. goto EXIT;
  1657. }
  1658. NEXT_SET:
  1659. pPropInfoSet[ulSet].cPropertyInfos = ulNext;
  1660. pPropInfoSet[ulSet].rgPropertyInfos = pPropInfo;
  1661. }
  1662. // Success, set return values
  1663. *pcPropertyInfoSets = cSets;
  1664. *prgPropertyInfoSets = pPropInfoSet;
  1665. // At least one propid was marked as not S_OK
  1666. if( dwStatus & GETPROPINFO_ERRORSOCCURRED )
  1667. {
  1668. // If at least 1 property was set
  1669. if( dwStatus & GETPROPINFO_VALIDPROP )
  1670. return DB_S_ERRORSOCCURRED;
  1671. else
  1672. {
  1673. // Do not free any of the rgPropertyInfoSets, but
  1674. // do free the ppDescBuffer
  1675. if( pDescBuffer )
  1676. {
  1677. ATLASSERT( ppDescBuffer );
  1678. CoTaskMemFree(pDescBuffer);
  1679. *ppDescBuffer = NULL;
  1680. }
  1681. return DB_E_ERRORSOCCURRED;
  1682. }
  1683. }
  1684. return S_OK;
  1685. EXIT:
  1686. // Check if failure and clean up any allocated memory
  1687. if( FAILED(hr) &&
  1688. (hr != DB_E_ERRORSOCCURRED) )
  1689. {
  1690. // Free Description Buffer
  1691. if( pDescBuffer )
  1692. {
  1693. ATLASSERT( ppDescBuffer );
  1694. CoTaskMemFree(pDescBuffer);
  1695. *ppDescBuffer = NULL;
  1696. }
  1697. if( pPropInfoSet )
  1698. {
  1699. // Loop through Property Sets
  1700. for(ulSet=0; ulSet<cSets; ulSet++)
  1701. {
  1702. if( pPropInfoSet[ulSet].rgPropertyInfos )
  1703. CoTaskMemFree(pPropInfoSet[ulSet].rgPropertyInfos);
  1704. }
  1705. CoTaskMemFree(pPropInfoSet);
  1706. }
  1707. }
  1708. return hr;
  1709. }
  1710. ULONG m_cUPropSet; //count of UPropSet items
  1711. UPROPSET* m_pUPropSet; //Pointer to UPropset items
  1712. ULONG m_cPropSetDex; //count of UPropSet Indexes
  1713. ULONG* m_rgiPropSetDex;//array of UPropSet Index values
  1714. ULONG m_cElemPerSupported; //number of DWORDS per UPropSet to indicate supported UPropIds
  1715. DWORD* m_rgdwSupported;//array of DWORDs indicating supported UPropIds
  1716. HRESULT InitAvailUPropSets(ULONG* pcUPropSet, UPROPSET** ppUPropSet, ULONG* pcElemPerSupported, GUID* pguid)
  1717. {
  1718. ATLASSERT(pcUPropSet && ppUPropSet);
  1719. if (*ppUPropSet != NULL)
  1720. {
  1721. CoTaskMemFree(*ppUPropSet);
  1722. *ppUPropSet = NULL;
  1723. }
  1724. int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, pcElemPerSupported);
  1725. UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  1726. if (pSet == NULL)
  1727. return E_OUTOFMEMORY;
  1728. *ppUPropSet = T::_GetPropSet(pcUPropSet, pcElemPerSupported, pSet, pguid);
  1729. return S_OK;
  1730. }
  1731. virtual HRESULT InitUPropSetsSupported()
  1732. {
  1733. ULONG cPropSet = 0, cElemsPerSupported = 0;
  1734. int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, &cElemsPerSupported);
  1735. UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  1736. if (pSet == NULL)
  1737. return E_OUTOFMEMORY;
  1738. pSet = T::_GetPropSet(&cPropSet, &cElemsPerSupported, pSet);
  1739. memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
  1740. CoTaskMemFree(pSet);
  1741. return S_OK;
  1742. }
  1743. //Load a localized description
  1744. int LoadDescription(ULONG ids, PWSTR pwszBuff, ULONG cchBuff)
  1745. {
  1746. USES_CONVERSION;
  1747. TCHAR* pszBuf = (TCHAR*)_alloca(cchBuff * sizeof(TCHAR));
  1748. if (pszBuf == NULL)
  1749. return 0;
  1750. int nTemp = LoadString(_pModule->GetResourceInstance(), ids, pszBuf, cchBuff);
  1751. wcscpy(pwszBuff, T2W(pszBuf));
  1752. return nTemp;
  1753. }
  1754. };
  1755. class ATL_NO_VTABLE CUtlPropsBase : public CBitFieldOps, public CDBIDOps
  1756. {
  1757. public:
  1758. ULONG m_cUPropSet; //count of UPropSet items
  1759. UPROPSET* m_pUPropSet; //Pointer to UPropset items
  1760. UPROP* m_pUProp;
  1761. ULONG m_cUPropSetHidden; //Count of Hidden items
  1762. DWORD m_dwFlags; //Configuration flags
  1763. ULONG m_cPropSetDex; //count of UPropSet Indexes
  1764. ULONG* m_rgiPropSetDex; //pointer to Array of UPropSet Index values
  1765. ULONG m_cElemPerSupported;//number of DWORDS per UPropSet to indicate supported UPropIds
  1766. DWORD* m_rgdwSupported; //pointer to array of DWORDs indicating supported UPropIds
  1767. DWORD* m_rgdwPropsInError;//pointer to array of DWORDs indicating if property is in error
  1768. enum EnumUPropSetFlags
  1769. {
  1770. UPROPSET_HIDDEN = 0x00000001,
  1771. UPROPSET_PASSTHROUGH = 0x00000002
  1772. };
  1773. enum EnumGetProp
  1774. {
  1775. GETPROP_ALLPROPIDS = 0x0001,
  1776. GETPROP_NOTSUPPORTED = 0x0002,
  1777. GETPROP_ERRORSOCCURRED = 0x0004,
  1778. GETPROP_VALIDPROP = 0x0008,
  1779. GETPROP_PROPSINERROR = 0x0010
  1780. };
  1781. enum EnumSetProp
  1782. {
  1783. SETPROP_BADOPTION = 0x0001,
  1784. SETPROP_NOTSUPPORTED = 0x0002,
  1785. SETPROP_VALIDPROP = 0x0004,
  1786. SETPROP_ERRORS = 0x0008,
  1787. SETPROP_COLUMN_LEVEL = 0x0010,
  1788. SETPROP_WAS_REQUIRED = 0x0020
  1789. };
  1790. HRESULT SetPassThrough(const DBPROPSET* pPropSet)
  1791. {
  1792. ATLASSERT(pPropSet);
  1793. DBPROP* pProp = pPropSet->rgProperties;
  1794. //Default implementation just sets all properties as NOTSUPPORTED
  1795. for( ULONG ul=0; ul<pPropSet->cProperties; ul++, pProp++ )
  1796. pProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1797. return DB_E_ERRORSOCCURRED;
  1798. }
  1799. HRESULT GetIndexofPropIdinPropSet(ULONG iCurSet, DBPROPID dwPropertyId, ULONG* piCurPropId)
  1800. {
  1801. ATLASSERT(piCurPropId);
  1802. UPROPINFO* pUPropInfo = m_pUPropSet[iCurSet].pUPropInfo;
  1803. for(ULONG ul=0; ul<m_pUPropSet[iCurSet].cUPropInfo; ul++)
  1804. {
  1805. if( dwPropertyId == pUPropInfo[ul].dwPropId )
  1806. {
  1807. *piCurPropId = ul;
  1808. // Test to see if the property is supported for this
  1809. // instantiation
  1810. return (TESTBIT(&(m_rgdwSupported[iCurSet * m_cElemPerSupported]), ul)) ? S_OK : S_FALSE;
  1811. }
  1812. }
  1813. return S_FALSE;
  1814. }
  1815. virtual HRESULT IsValidValue(ULONG /*iCurSet*/, DBPROP* pDBProp)
  1816. {
  1817. ATLASSERT(pDBProp != NULL);
  1818. CComVariant var = pDBProp->vValue;
  1819. if (var.vt == VT_BOOL)
  1820. {
  1821. if (var.boolVal != VARIANT_TRUE && var.boolVal != VARIANT_FALSE)
  1822. return S_FALSE;
  1823. }
  1824. return S_OK;
  1825. }
  1826. virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/) = 0;
  1827. HRESULT SetProperty(ULONG iCurSet, ULONG iCurProp, DBPROP* pDBProp)
  1828. {
  1829. HRESULT hr = S_OK;
  1830. UPROP* pUProp;
  1831. UPROPVAL* pUPropVal;
  1832. UPROPINFO* pUPropInfo;
  1833. ULONG iUProp;
  1834. ATLASSERT( pDBProp );
  1835. // Set pointer to correct set
  1836. pUProp = &(m_pUProp[iCurSet]);
  1837. ATLASSERT( pUProp );
  1838. pUPropInfo = &(m_pUPropSet[iCurSet].pUPropInfo[iCurProp]);
  1839. ATLASSERT( pUPropInfo );
  1840. // Determine the index within m_pUProp
  1841. for(iUProp=0; iUProp<pUProp->cPropIds; iUProp++)
  1842. {
  1843. if( (pUProp->rgpUPropInfo[iUProp])->dwPropId == pDBProp->dwPropertyID )
  1844. break;
  1845. }
  1846. if( iUProp >= pUProp->cPropIds )
  1847. {
  1848. ATLASSERT( !"Should have found index of property to set" );
  1849. hr = E_FAIL;
  1850. pDBProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1851. goto EXIT;
  1852. }
  1853. //Get the UPROPVAL node pointer within that propset.
  1854. pUPropVal = &(pUProp->pUPropVal[iUProp]);
  1855. ATLASSERT( pUPropVal );
  1856. // Handle VT_EMPTY, which indicates to the provider to
  1857. // reset this property to the providers default
  1858. if( pDBProp->vValue.vt == VT_EMPTY )
  1859. {
  1860. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  1861. {
  1862. // Remove any nodes, because the default applies to
  1863. // all columns
  1864. delete pUPropVal->pCColumnIds;
  1865. pUPropVal->pCColumnIds = NULL;
  1866. }
  1867. // Should clear here, since previous values may already
  1868. // have been cached and need to be replaced.
  1869. VariantClear(&(pUPropVal->vValue));
  1870. pUPropVal->dwFlags &= ~DBINTERNFLAGS_CHANGED;
  1871. hr = GetDefaultValue(iCurSet, pDBProp->dwPropertyID,
  1872. &(pUPropVal->dwOption), &(pUPropVal->vValue));
  1873. goto EXIT;
  1874. }
  1875. // Column Level
  1876. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  1877. {
  1878. // Check to see if it applies to all
  1879. if( (CompareDBIDs(&(pDBProp->colid), &DB_NULLID) == S_OK) )
  1880. {
  1881. // Remove the Columns Storage object
  1882. delete pUPropVal->pCColumnIds;
  1883. pUPropVal->pCColumnIds = NULL;
  1884. pUPropVal->dwOption = pDBProp->dwOptions;
  1885. if( FAILED(hr = VariantCopy(&(pUPropVal->vValue),
  1886. &(pDBProp->vValue))) )
  1887. goto EXIT;
  1888. pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  1889. }
  1890. else // Does not apply to all columns
  1891. {
  1892. if( pUPropVal->pCColumnIds == NULL )
  1893. ATLTRY(pUPropVal->pCColumnIds = new CColumnIds)
  1894. if( pUPropVal->pCColumnIds )
  1895. {
  1896. if( FAILED(hr = (pUPropVal->pCColumnIds)->AddColumnId(pDBProp)) )
  1897. goto EXIT;
  1898. pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  1899. }
  1900. else
  1901. {
  1902. hr = E_OUTOFMEMORY;
  1903. goto EXIT;
  1904. }
  1905. }
  1906. }
  1907. else
  1908. {
  1909. // Set for non-column level properties
  1910. pUPropVal->dwOption = pDBProp->dwOptions;
  1911. if( FAILED(hr = VariantCopy(&(pUPropVal->vValue),
  1912. &(pDBProp->vValue))) )
  1913. goto EXIT;
  1914. OnPropertyChanged(iCurSet, pDBProp);
  1915. pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  1916. }
  1917. EXIT:
  1918. if( SUCCEEDED(hr) )
  1919. pDBProp->dwStatus = DBPROPSTATUS_OK;
  1920. return hr;
  1921. }
  1922. HRESULT SetProperties(const DWORD /*dwStatus*/, const ULONG cPropertySets,
  1923. const DBPROPSET rgPropertySets[], const ULONG cSelectProps = 1,
  1924. const GUID** ppGuid = NULL, bool bIsCreating = false)
  1925. {
  1926. DWORD dwState = 0;
  1927. ULONG ulCurSet, ulProp, ulCurProp = 0;
  1928. DBPROP* rgDBProp;
  1929. UPROPINFO* pUPropInfo;
  1930. VARIANT vDefaultValue;
  1931. DWORD dwOption;
  1932. // ppGuid specifies the property sets that the consumer can set based
  1933. // on the interface that called this function.
  1934. ATLASSERT(ppGuid != NULL);
  1935. if ((cPropertySets != 0) && (rgPropertySets == NULL))
  1936. return E_INVALIDARG;
  1937. // Initialize Variant
  1938. VariantInit(&vDefaultValue);
  1939. // Process property sets
  1940. for(ULONG ulSet=0; ulSet<cPropertySets; ulSet++)
  1941. {
  1942. if ((rgPropertySets[ulSet].cProperties != 0) && (rgPropertySets[ulSet].rgProperties == NULL))
  1943. return E_INVALIDARG;
  1944. bool bAvailable = false;
  1945. for (ULONG l=0; l<cSelectProps; l++)
  1946. {
  1947. if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  1948. bAvailable |= true;
  1949. }
  1950. // Make sure we support the property set
  1951. if( !bAvailable ||
  1952. (GetIndexofPropSet(&(rgPropertySets[ulSet].guidPropertySet), &ulCurSet) == S_FALSE ))
  1953. {
  1954. // Not supported, thus we need to mark all as NOT_SUPPORTED
  1955. rgDBProp = rgPropertySets[ulSet].rgProperties;
  1956. for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
  1957. {
  1958. dwState |= SETPROP_ERRORS;
  1959. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  1960. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1961. }
  1962. continue;
  1963. }
  1964. // Handle property sets marked as pass through
  1965. if( m_pUPropSet[ulCurSet].dwFlags & UPROPSET_PASSTHROUGH )
  1966. {
  1967. HRESULT hr = SetPassThrough(&rgPropertySets[ulSet]);
  1968. if( hr == DB_E_ERRORSOCCURRED )
  1969. {
  1970. dwState |= SETPROP_ERRORS;
  1971. dwState |= SETPROP_WAS_REQUIRED;
  1972. }
  1973. else if( hr == DB_S_ERRORSOCCURRED )
  1974. {
  1975. dwState |= SETPROP_ERRORS;
  1976. dwState |= SETPROP_VALIDPROP;
  1977. }
  1978. else
  1979. {
  1980. ATLASSERT( hr == S_OK );
  1981. dwState |= SETPROP_VALIDPROP;
  1982. }
  1983. continue;
  1984. }
  1985. // Handle properties of a supported property set
  1986. rgDBProp = rgPropertySets[ulSet].rgProperties;
  1987. for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
  1988. {
  1989. // Is this a supported PROPID for this property set
  1990. if( GetIndexofPropIdinPropSet(ulCurSet, rgDBProp[ulProp].dwPropertyID,
  1991. &ulCurProp) == S_FALSE)
  1992. {
  1993. dwState |= SETPROP_ERRORS;
  1994. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  1995. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  1996. continue;
  1997. }
  1998. // Set the pUPropInfo pointer
  1999. pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
  2000. ATLASSERT( pUPropInfo );
  2001. // check dwOption for a valid option
  2002. if( (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_REQUIRED) &&
  2003. (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_SETIFCHEAP) )
  2004. {
  2005. ATLTRACE2(atlTraceDBProvider, 0, "SetProperties dwOptions Invalid: %u\n", rgDBProp[ulProp].dwOptions);
  2006. dwState |= SETPROP_ERRORS;
  2007. dwState |= SETPROP_WAS_REQUIRED;
  2008. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADOPTION;
  2009. continue;
  2010. }
  2011. // Check that the property is settable
  2012. // We do not check against DBPROPFLAGS_CHANGE here
  2013. if( (pUPropInfo->dwFlags & DBPROPFLAGS_WRITE) == 0 )
  2014. {
  2015. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_OK;
  2016. VariantClear(&vDefaultValue);
  2017. // VT_EMPTY against a read only property should be a no-op since
  2018. // the VT_EMPTY means the default.
  2019. if( V_VT(&rgDBProp[ulProp].vValue) == VT_EMPTY )
  2020. {
  2021. dwState |= SETPROP_VALIDPROP;
  2022. continue;
  2023. }
  2024. if( SUCCEEDED(GetDefaultValue(ulCurSet, rgDBProp[ulProp].dwPropertyID,
  2025. &dwOption, &(vDefaultValue))) )
  2026. {
  2027. if( V_VT(&rgDBProp[ulProp].vValue) == V_VT(&vDefaultValue) )
  2028. {
  2029. switch( V_VT(&vDefaultValue) )
  2030. {
  2031. case VT_BOOL:
  2032. if( V_BOOL(&rgDBProp[ulProp].vValue) == V_BOOL(&vDefaultValue) )
  2033. {
  2034. dwState |= SETPROP_VALIDPROP;
  2035. continue;
  2036. }
  2037. break;
  2038. case VT_I2:
  2039. if( V_I2(&rgDBProp[ulProp].vValue) == V_I2(&vDefaultValue) )
  2040. {
  2041. dwState |= SETPROP_VALIDPROP;
  2042. continue;
  2043. }
  2044. break;
  2045. case VT_I4:
  2046. if( V_I4(&rgDBProp[ulProp].vValue) == V_I4(&vDefaultValue) )
  2047. {
  2048. dwState |= SETPROP_VALIDPROP;
  2049. continue;
  2050. }
  2051. break;
  2052. case VT_BSTR:
  2053. if( wcscmp(V_BSTR(&rgDBProp[ulProp].vValue), V_BSTR(&vDefaultValue)) == 0 )
  2054. {
  2055. dwState |= SETPROP_VALIDPROP;
  2056. continue;
  2057. }
  2058. break;
  2059. }
  2060. }
  2061. }
  2062. dwState |= SETPROP_ERRORS;
  2063. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2064. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
  2065. continue;
  2066. }
  2067. // Check that the property is being set with the correct VARTYPE
  2068. if( (rgDBProp[ulProp].vValue.vt != pUPropInfo->VarType) &&
  2069. (rgDBProp[ulProp].vValue.vt != VT_EMPTY) )
  2070. {
  2071. dwState |= SETPROP_ERRORS;
  2072. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2073. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
  2074. continue;
  2075. }
  2076. // Check that the value is legal
  2077. if( (rgDBProp[ulProp].vValue.vt != VT_EMPTY) &&
  2078. IsValidValue(ulCurSet, &(rgDBProp[ulProp])) == S_FALSE )
  2079. {
  2080. dwState |= SETPROP_ERRORS;
  2081. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2082. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
  2083. continue;
  2084. }
  2085. // Check for a bad COLID, we only catch bad DBIDs
  2086. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2087. {
  2088. if( CDBIDOps::IsValidDBID(&(rgDBProp[ulProp].colid)) == S_FALSE )
  2089. {
  2090. dwState |= SETPROP_ERRORS;
  2091. dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  2092. rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADCOLUMN;
  2093. continue;
  2094. }
  2095. dwState |= SETPROP_COLUMN_LEVEL;
  2096. }
  2097. if( SUCCEEDED(SetProperty(ulCurSet, ulCurProp, /*pUPropInfo,*/ &(rgDBProp[ulProp]))) )
  2098. {
  2099. dwState |= SETPROP_VALIDPROP;
  2100. }
  2101. }
  2102. }
  2103. VariantClear(&vDefaultValue);
  2104. // At least one propid was marked as not S_OK
  2105. if( dwState & SETPROP_ERRORS )
  2106. {
  2107. if (!bIsCreating)
  2108. {
  2109. return (dwState & SETPROP_VALIDPROP) ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED;
  2110. }
  2111. else
  2112. {
  2113. return (dwState & SETPROP_WAS_REQUIRED) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;
  2114. }
  2115. }
  2116. return S_OK;
  2117. }
  2118. OUT_OF_LINE HRESULT CopyUPropVal(ULONG iPropSet, UPROPVAL* rgUPropVal)
  2119. {
  2120. HRESULT hr = S_OK;
  2121. UPROP* pUProp;
  2122. UPROPVAL* pUPropVal;
  2123. DBPROP dbProp;
  2124. ATLASSERT(rgUPropVal);
  2125. ATLASSERT(iPropSet < m_cUPropSet);
  2126. VariantInit(&dbProp.vValue);
  2127. pUProp = &(m_pUProp[iPropSet]);
  2128. for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
  2129. {
  2130. pUPropVal = &(pUProp->pUPropVal[ul]);
  2131. // Transfer dwOptions
  2132. rgUPropVal[ul].dwOption = pUPropVal->dwOption;
  2133. // Transfer Flags
  2134. rgUPropVal[ul].dwFlags = pUPropVal->dwFlags;
  2135. // Transfer Column Properties
  2136. if( pUPropVal->pCColumnIds )
  2137. {
  2138. ATLTRY(rgUPropVal[ul].pCColumnIds = new CColumnIds)
  2139. if( rgUPropVal[ul].pCColumnIds )
  2140. {
  2141. CColumnIds* pColIds = pUPropVal->pCColumnIds;
  2142. for (int i = 0; i < pColIds->GetSize(); i++)
  2143. {
  2144. hr = (pUPropVal->pCColumnIds)->GetValue(i, &(dbProp.dwOptions),&(dbProp.colid), &(dbProp.vValue));
  2145. if( FAILED(hr) )
  2146. goto EXIT;
  2147. if( FAILED(hr = (rgUPropVal[ul].pCColumnIds)->AddColumnId(&dbProp)) )
  2148. goto EXIT;
  2149. }
  2150. }
  2151. else
  2152. {
  2153. hr = E_OUTOFMEMORY;
  2154. goto EXIT;
  2155. }
  2156. }
  2157. else
  2158. {
  2159. rgUPropVal[ul].pCColumnIds = NULL;
  2160. }
  2161. // Transfer value
  2162. VariantInit(&(rgUPropVal[ul].vValue));
  2163. if( FAILED(hr = VariantCopy(&(rgUPropVal[ul].vValue),
  2164. &(pUPropVal->vValue))) )
  2165. goto EXIT;
  2166. }
  2167. EXIT:
  2168. VariantClear(&(dbProp.vValue));
  2169. return hr;
  2170. }
  2171. void ClearPropertyInError()
  2172. {
  2173. ATLASSERT( m_rgdwPropsInError );
  2174. memset(m_rgdwPropsInError, 0, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
  2175. }
  2176. void CopyUPropSetsSupported(DWORD* rgdwSupported)
  2177. {
  2178. memcpy(rgdwSupported, m_rgdwSupported, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
  2179. }
  2180. virtual HRESULT InitUPropSetsSupported() = 0;
  2181. virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet) = 0;
  2182. ULONG GetCountofWritablePropsInPropSet(ULONG iPropSet)
  2183. {
  2184. ULONG cWritable = 0;
  2185. UPROPINFO* pUPropInfo;
  2186. ATLASSERT( m_pUPropSet );
  2187. ATLASSERT( iPropSet < m_cUPropSet );
  2188. pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
  2189. for(ULONG ul=0; ul<m_pUPropSet[iPropSet].cUPropInfo; ul++)
  2190. {
  2191. if( pUPropInfo[ul].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2192. cWritable++;
  2193. }
  2194. return cWritable;
  2195. }
  2196. void CopyUPropInfo(ULONG iPropSet, UPROPINFO** rgpUPropInfo)
  2197. {
  2198. ATLASSERT( rgpUPropInfo );
  2199. ATLASSERT( iPropSet < m_cUPropSet );
  2200. memcpy(rgpUPropInfo, m_pUProp[iPropSet].rgpUPropInfo, m_pUProp[iPropSet].cPropIds * sizeof(UPROPINFO*));
  2201. }
  2202. virtual HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar) = 0;
  2203. typedef UPROPSET* (*PGetPropSet)(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet, GUID* pguidSet);
  2204. HRESULT InternalInitUPropSetsSupported(PGetPropSet pfnGetSet)
  2205. {
  2206. ULONG cPropSet = 0, cElemsPerSupported = 0;
  2207. INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemsPerSupported, NULL, (GUID*)&GUID_NULL);
  2208. UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  2209. if (pPropSet == NULL)
  2210. return E_OUTOFMEMORY;
  2211. pPropSet = (*pfnGetSet)(&cPropSet, &cElemsPerSupported, pPropSet, (GUID*)&GUID_NULL);
  2212. memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
  2213. CoTaskMemFree(pPropSet);
  2214. return S_OK;
  2215. }
  2216. HRESULT InternalGetDefaultValue(PGetPropSet pfnGetSet, ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar)
  2217. {
  2218. if (pdwOption == NULL || pVar == NULL)
  2219. return E_INVALIDARG;
  2220. ULONG cUPropSet = 0, cElemPerSupported =0;
  2221. INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemPerSupported, NULL, (GUID*)&GUID_NULL);
  2222. UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  2223. if (pPropSet == NULL)
  2224. return E_OUTOFMEMORY;
  2225. pPropSet = (*pfnGetSet)(&cUPropSet, &cElemPerSupported, pPropSet, (GUID*)&GUID_NULL);
  2226. ATLASSERT(iPropSet < cUPropSet);
  2227. for (ULONG iProp = 0; iProp < pPropSet[iPropSet].cUPropInfo; iProp++)
  2228. {
  2229. UPROPINFO& rInfo = pPropSet[iPropSet].pUPropInfo[iProp];
  2230. if (rInfo.dwPropId == dwPropId)
  2231. {
  2232. pVar->vt = rInfo.VarType;
  2233. *pdwOption = rInfo.dwOption;
  2234. switch(rInfo.VarType)
  2235. {
  2236. case VT_BSTR:
  2237. pVar->bstrVal = SysAllocString(rInfo.szVal);
  2238. break;
  2239. default:
  2240. pVar->lVal = (DWORD)rInfo.dwVal;
  2241. break;
  2242. }
  2243. CoTaskMemFree(pPropSet);
  2244. return S_OK;
  2245. }
  2246. }
  2247. CoTaskMemFree(pPropSet);
  2248. return E_FAIL;
  2249. }
  2250. HRESULT InternalFInit(PGetPropSet pfnGetSet, CUtlPropsBase* pCopyMe = NULL)
  2251. {
  2252. HRESULT hr;
  2253. ULONG ulPropId;
  2254. ULONG cPropIds;
  2255. ULONG iPropSet;
  2256. ULONG iNewDex;
  2257. UPROPINFO** rgpUPropInfo;
  2258. UPROPVAL* rgUPropVal;
  2259. UPROPINFO* pUPropInfo;
  2260. // If a pointer is passed in, we should copy that property object
  2261. if( pCopyMe )
  2262. {
  2263. // Establish some base values
  2264. m_cUPropSet = pCopyMe->m_cUPropSet;
  2265. if (m_pUPropSet != NULL)
  2266. CoTaskMemFree(m_pUPropSet);
  2267. m_pUPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * m_cUPropSet);
  2268. if (m_pUPropSet == NULL)
  2269. return E_OUTOFMEMORY;
  2270. memcpy(m_pUPropSet, pCopyMe->m_pUPropSet, sizeof(UPROPSET) * m_cUPropSet);
  2271. m_cElemPerSupported = pCopyMe->m_cElemPerSupported;
  2272. ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) );
  2273. // Retrieve Supported Bitmask
  2274. ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2275. ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2276. if( m_rgdwSupported == NULL|| m_rgdwPropsInError == NULL)
  2277. {
  2278. delete[] m_rgdwSupported;
  2279. delete[] m_rgdwPropsInError;
  2280. return E_OUTOFMEMORY;
  2281. }
  2282. ClearPropertyInError();
  2283. pCopyMe->CopyUPropSetsSupported(m_rgdwSupported);
  2284. }
  2285. else
  2286. {
  2287. INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &m_cElemPerSupported, NULL, (GUID*)&GUID_NULL);
  2288. UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  2289. if (pSet == NULL)
  2290. return E_OUTOFMEMORY;
  2291. pSet = (*pfnGetSet)(&m_cUPropSet, &m_cElemPerSupported, pSet, (GUID*)&GUID_NULL);
  2292. if (m_pUPropSet != NULL)
  2293. CoTaskMemFree(m_pUPropSet);
  2294. m_pUPropSet = pSet;
  2295. ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) );
  2296. if( !m_cUPropSet || !m_cElemPerSupported )
  2297. return E_FAIL;
  2298. ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2299. ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2300. if( m_rgdwSupported == NULL || m_rgdwPropsInError == NULL)
  2301. {
  2302. delete[] m_rgdwSupported;
  2303. delete[] m_rgdwPropsInError;
  2304. return E_OUTOFMEMORY;
  2305. }
  2306. else
  2307. ClearPropertyInError();
  2308. if( FAILED(hr = InitUPropSetsSupported()) )
  2309. {
  2310. delete[] m_rgdwSupported;
  2311. m_rgdwSupported = NULL;
  2312. return hr;
  2313. }
  2314. }
  2315. // Allocate UPROPS structures for the count of Property sets
  2316. ATLTRY(m_pUProp = (UPROP*) new UPROP[m_cUPropSet])
  2317. if( m_pUProp)
  2318. {
  2319. memset(m_pUProp, 0, m_cUPropSet * sizeof(UPROP));
  2320. }
  2321. else
  2322. {
  2323. m_cUPropSet = 0;
  2324. return E_OUTOFMEMORY;
  2325. }
  2326. // With in the UPROPS Structure allocate and intialize the
  2327. // Property IDs that belong to this property set.
  2328. for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
  2329. {
  2330. cPropIds = GetCountofWritablePropsInPropSet(iPropSet);
  2331. if( cPropIds > 0 )
  2332. {
  2333. ATLTRY(rgpUPropInfo = (UPROPINFO**) new UPROPINFO*[cPropIds])
  2334. ATLTRY(rgUPropVal = (UPROPVAL*) new UPROPVAL[cPropIds])
  2335. if( rgpUPropInfo != NULL && rgUPropVal != NULL)
  2336. {
  2337. if( pCopyMe )
  2338. {
  2339. pCopyMe->CopyUPropInfo(iPropSet, rgpUPropInfo);
  2340. if( FAILED(hr = pCopyMe->CopyUPropVal(iPropSet, rgUPropVal)) )
  2341. return hr;
  2342. }
  2343. else
  2344. {
  2345. // Clear Pointer Array
  2346. memset(rgpUPropInfo, 0, cPropIds * sizeof(UPROPINFO*));
  2347. // Set Pointer to correct property ids with a property set
  2348. pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
  2349. // Set up the writable property buffers
  2350. iNewDex = 0;
  2351. for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
  2352. {
  2353. if( pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2354. {
  2355. // Following ATLASSERT indicates that the are more
  2356. // writable properties then space allocated
  2357. ATLASSERT(iNewDex < cPropIds);
  2358. rgpUPropInfo[iNewDex] = &(pUPropInfo[ulPropId]);
  2359. rgUPropVal[iNewDex].dwOption = DBPROPOPTIONS_SETIFCHEAP;
  2360. rgUPropVal[iNewDex].pCColumnIds = NULL;
  2361. rgUPropVal[iNewDex].dwFlags = 0;
  2362. VariantInit(&(rgUPropVal[iNewDex].vValue));
  2363. GetDefaultValue(iPropSet, pUPropInfo[ulPropId].dwPropId,
  2364. &(rgUPropVal[iNewDex].dwOption), &(rgUPropVal[iNewDex].vValue));
  2365. iNewDex++;
  2366. }
  2367. }
  2368. ATLASSERT(cPropIds == iNewDex);
  2369. }
  2370. m_pUProp[iPropSet].rgpUPropInfo = rgpUPropInfo;
  2371. m_pUProp[iPropSet].pUPropVal = rgUPropVal;
  2372. m_pUProp[iPropSet].cPropIds = cPropIds;
  2373. }
  2374. else
  2375. {
  2376. delete[] rgpUPropInfo;
  2377. delete[] rgUPropVal;
  2378. return E_OUTOFMEMORY;
  2379. }
  2380. }
  2381. }
  2382. // Finally determine if there are any hidden property sets.. Those
  2383. // that do not show up in GetPropertyInfo and should not be returns on
  2384. // a 0, NULL call to GetProperties
  2385. for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
  2386. {
  2387. if( m_pUPropSet[iPropSet].dwFlags & UPROPSET_HIDDEN )
  2388. m_cUPropSetHidden++;
  2389. }
  2390. return S_OK;
  2391. }
  2392. //Check the arguments for Set Properties
  2393. static HRESULT SetPropertiesArgChk(const ULONG cPropertySets, const DBPROPSET rgPropertySets[])
  2394. {
  2395. if( cPropertySets > 0 && !rgPropertySets )
  2396. return E_INVALIDARG;
  2397. // New argument check for > 1 cPropertyIDs and NULL pointer for
  2398. // array of property ids.
  2399. for(ULONG ul=0; ul<cPropertySets; ul++)
  2400. {
  2401. if( rgPropertySets[ul].cProperties && !(rgPropertySets[ul].rgProperties) )
  2402. return E_INVALIDARG;
  2403. }
  2404. return S_OK;
  2405. }
  2406. HRESULT GetProperties(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
  2407. ULONG* pcProperties, DBPROPSET** prgProperties,
  2408. const ULONG cSelectProps = 1, const GUID** ppGuid = NULL)
  2409. {
  2410. UPROPVAL* pUPropVal;
  2411. ULONG ulCurProp = 0;
  2412. ULONG cTmpPropertySets = cPropertySets;
  2413. HRESULT hr = S_OK;
  2414. ULONG ulSet = 0;
  2415. ULONG ulNext = 0;
  2416. ULONG cSets = 0;
  2417. ULONG cProps = 0;
  2418. ULONG ulProp = 0;
  2419. DWORD dwStatus = 0;
  2420. DBPROP* pProp = NULL;
  2421. DBPROP* pCurProp = NULL;
  2422. DBPROPSET* pPropSet = NULL;
  2423. UPROPINFO* pUPropInfo = NULL;
  2424. ULONG* piSetIndex = NULL;
  2425. ULONG* piIndex = NULL;
  2426. ULONG ulCurSet = 0;
  2427. ULONG iPropSet;
  2428. // ppGuid contains an array of GUIDs that the consumer can retrieve.
  2429. // This is based upon the interface calling this function
  2430. ATLASSERT(ppGuid != NULL);
  2431. // We need to have special handling for DBPROPSET_PROPERTIESINERROR..
  2432. // Turn on a flags to indicate this mode and make cTmpPropertySets
  2433. // appear to be 0
  2434. if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) &&
  2435. rgPropertySets &&
  2436. (rgPropertySets[0].guidPropertySet == DBPROPSET_PROPERTIESINERROR) )
  2437. {
  2438. cTmpPropertySets = 0;
  2439. dwStatus |= GETPROP_PROPSINERROR;
  2440. }
  2441. // If the consumer does not restrict the property sets
  2442. // by specify an array of property sets and a cTmpPropertySets
  2443. // greater than 0, then we need to make sure we
  2444. // have some to return
  2445. if( cTmpPropertySets == 0 )
  2446. {
  2447. // There are times when we are called from IRowsetInfo, ISessionProperties, etc.
  2448. // where we should return only the appropriate rowset when cTmpPropertySets is
  2449. // zero. This solves the problem if the user has more than one set specified in
  2450. // their PROPSET_MAP.
  2451. // Determine the number of property sets supported
  2452. if (ppGuid == NULL)
  2453. {
  2454. cSets = m_cUPropSet;
  2455. }
  2456. else
  2457. {
  2458. ULONG ulActualProps = 0;
  2459. piSetIndex = new ULONG[cSelectProps];
  2460. // Also, find the index for the set we are looking for
  2461. for (ULONG l=0; l<cSelectProps; l++)
  2462. {
  2463. for (piSetIndex[l]=0; piSetIndex[l]<m_cUPropSet; piSetIndex[l]++)
  2464. {
  2465. if (InlineIsEqualGUID(*m_pUPropSet[piSetIndex[l]].pPropSet, *ppGuid[l]))
  2466. {
  2467. ulActualProps++;
  2468. break;
  2469. }
  2470. }
  2471. }
  2472. // YIKES!
  2473. cSets = ulActualProps;
  2474. ulActualProps = 0;
  2475. piIndex = new ULONG[cSets];
  2476. for (l=0; l<cSelectProps; l++)
  2477. {
  2478. if (piSetIndex[l] != m_cUPropSet) // this is an invalid index
  2479. piIndex[ulActualProps++] = piSetIndex[l];
  2480. }
  2481. delete [] piSetIndex;
  2482. piSetIndex = NULL;
  2483. }
  2484. }
  2485. else
  2486. {
  2487. // Since special property set guids are not supported by
  2488. // GetProperties, we can just use the count of property
  2489. // sets given to us.
  2490. cSets = cTmpPropertySets;
  2491. }
  2492. // If no properties set, then return
  2493. if( cSets == 0 )
  2494. return S_OK;
  2495. // Allocate the DBPROPSET structures
  2496. pPropSet = (DBPROPSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPSET));
  2497. if(pPropSet)
  2498. {
  2499. memset(pPropSet, 0, cSets * sizeof(DBPROPSET));
  2500. // Fill in the output array
  2501. iPropSet = 0;
  2502. for(ulSet=0; ulSet<cSets; ulSet++)
  2503. {
  2504. // Depending of if Property sets are specified store the
  2505. // return property set.
  2506. if( cTmpPropertySets == 0 )
  2507. {
  2508. ULONG lSet;
  2509. if (ppGuid[ulSet] == NULL)
  2510. lSet = ulSet;
  2511. else
  2512. lSet = piIndex[ulSet];
  2513. if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
  2514. continue;
  2515. pPropSet[iPropSet].guidPropertySet = *(m_pUPropSet[lSet].pPropSet);
  2516. }
  2517. else
  2518. pPropSet[iPropSet].guidPropertySet = rgPropertySets[ulSet].guidPropertySet;
  2519. iPropSet++;
  2520. }
  2521. }
  2522. else
  2523. {
  2524. ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
  2525. delete [] piIndex;
  2526. piIndex = NULL;
  2527. return E_OUTOFMEMORY;
  2528. }
  2529. // Process requested or derived Property sets
  2530. iPropSet=0;
  2531. for(ulSet=0; ulSet<cSets; ulSet++)
  2532. {
  2533. cProps = 0;
  2534. pProp = NULL;
  2535. ulNext = 0;
  2536. dwStatus &= (GETPROP_ERRORSOCCURRED | GETPROP_VALIDPROP | GETPROP_PROPSINERROR);
  2537. // Calculate the number of property nodes needed for this
  2538. // property set.
  2539. if( cTmpPropertySets == 0 )
  2540. {
  2541. ULONG lSet;
  2542. if (ppGuid[ulSet] == NULL)
  2543. lSet = ulSet;
  2544. else
  2545. lSet = piIndex[ulSet];
  2546. // If processing requesting all property sets, do not
  2547. // return the hidden sets.
  2548. if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
  2549. continue;
  2550. cProps = m_pUPropSet[lSet].cUPropInfo;
  2551. // Add Enough space for node that are colid specific
  2552. cProps += GetCountofColids(&(m_pUProp[lSet]));
  2553. dwStatus |= GETPROP_ALLPROPIDS;
  2554. ulCurSet = lSet;
  2555. }
  2556. else
  2557. {
  2558. ATLASSERT(ulSet == iPropSet);
  2559. // If the count of PROPIDs is 0 or It is a special property set, then
  2560. // the consumer is requesting all propids for this property set.
  2561. if(rgPropertySets[ulSet].cPropertyIDs == 0)
  2562. {
  2563. dwStatus |= GETPROP_ALLPROPIDS;
  2564. // We have to determine if the property set is supported and if so
  2565. // the count of properties in the set.
  2566. BOOL bAvailable = false;
  2567. for (ULONG l=0; l<cSelectProps; l++)
  2568. {
  2569. if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  2570. bAvailable |= true;
  2571. }
  2572. if (bAvailable &&
  2573. GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) == S_OK)
  2574. {
  2575. cProps += m_pUPropSet[ulCurSet].cUPropInfo;
  2576. // Add Enough space for node that are colid specific
  2577. cProps += GetCountofColids(&m_pUProp[ulCurSet]);
  2578. }
  2579. else
  2580. {
  2581. // Not Supported
  2582. dwStatus |= GETPROP_ERRORSOCCURRED;
  2583. goto NEXT_SET;
  2584. }
  2585. }
  2586. else
  2587. {
  2588. cProps = rgPropertySets[ulSet].cPropertyIDs;
  2589. // Check to see if this is a supported interface based on ppGuid.
  2590. BOOL bAvailable = false;
  2591. for (ULONG l=0; l<cSelectProps; l++)
  2592. {
  2593. if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  2594. bAvailable |= true;
  2595. }
  2596. if (!bAvailable ||
  2597. (GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) != S_OK))
  2598. {
  2599. dwStatus |= GETPROP_NOTSUPPORTED;
  2600. dwStatus |= GETPROP_ERRORSOCCURRED;
  2601. }
  2602. }
  2603. }
  2604. // Allocate DBPROP array
  2605. if( cProps == 0 ) //Possible with Hidden Passthrough sets
  2606. goto NEXT_SET;
  2607. pProp = (DBPROP*)CoTaskMemAlloc(cProps * sizeof(DBPROP));
  2608. if( pProp )
  2609. {
  2610. // Initialize Buffer
  2611. memset(pProp, 0, cProps * sizeof(DBPROP));
  2612. for(ulProp=0; ulProp<cProps; ulProp++)
  2613. {
  2614. VariantInit(&(pProp[ulProp].vValue));
  2615. if( dwStatus & GETPROP_NOTSUPPORTED )
  2616. {
  2617. // Not supported, thus we need to mark all as NOT_SUPPORTED
  2618. pProp[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  2619. pProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  2620. }
  2621. }
  2622. // Make sure we support the property set
  2623. if( dwStatus & GETPROP_NOTSUPPORTED )
  2624. {
  2625. ulNext = cProps;
  2626. goto NEXT_SET;
  2627. }
  2628. // Now that we have determined we can support the property set, we
  2629. // need to gather current property values
  2630. for(ulProp=0; ulProp<cProps; ulProp++)
  2631. {
  2632. pCurProp = &(pProp[ulNext]);
  2633. //Initialize Variant Value
  2634. pCurProp->dwStatus = DBPROPSTATUS_OK;
  2635. // Retrieve current value of properties
  2636. if( dwStatus & GETPROP_ALLPROPIDS )
  2637. {
  2638. // Verify property is supported, if not do not return
  2639. if( !TESTBIT(&(m_rgdwSupported[ulCurSet * m_cElemPerSupported]), ulProp) )
  2640. continue;
  2641. // If we are looking for properties in error, then we should ignore all
  2642. // that are not in error.
  2643. if( (dwStatus & GETPROP_PROPSINERROR) &&
  2644. !TESTBIT(&(m_rgdwPropsInError[ulCurSet * m_cElemPerSupported]), ulProp) )
  2645. continue;
  2646. pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulProp]);
  2647. ATLASSERT( pUPropInfo );
  2648. pCurProp->dwPropertyID = pUPropInfo->dwPropId;
  2649. pCurProp->colid = DB_NULLID;
  2650. // If the property is WRITEABLE or CHANGABLE, then the value will
  2651. // be gotten from the UPROPVAL array, else it will be
  2652. // derive from the GetDefaultValue
  2653. if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2654. {
  2655. pUPropVal = &(m_pUProp[ulCurSet].
  2656. pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
  2657. ATLASSERT( pUPropVal );
  2658. // Check to see if this property supports column level,
  2659. // if so, dump those nodes
  2660. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2661. {
  2662. if( pUPropVal->pCColumnIds )
  2663. {
  2664. RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
  2665. continue;
  2666. }
  2667. }
  2668. pCurProp->dwOptions = pUPropVal->dwOption;
  2669. hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
  2670. }
  2671. else
  2672. {
  2673. GetDefaultValue(ulCurSet, pUPropInfo->dwPropId,
  2674. &(pCurProp->dwOptions), &(pCurProp->vValue));
  2675. }
  2676. // Return all Properties in Error with CONFLICT status
  2677. if( dwStatus & GETPROP_PROPSINERROR )
  2678. pCurProp->dwStatus = DBPROPSTATUS_CONFLICTING;
  2679. dwStatus |= GETPROP_VALIDPROP;
  2680. }
  2681. else
  2682. {
  2683. // Process Properties based on Restriction array.
  2684. pCurProp->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  2685. pCurProp->colid = DB_NULLID;
  2686. if( GetIndexofPropIdinPropSet(ulCurSet, pCurProp->dwPropertyID,
  2687. &ulCurProp) == S_OK)
  2688. {
  2689. // Supported
  2690. pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
  2691. ATLASSERT( pUPropInfo );
  2692. // If the property is WRITEABLE, then the value will
  2693. // be gotten from the UPROPVAL array, else it will be
  2694. // derive from the GetDefaultValue
  2695. if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2696. {
  2697. pUPropVal = &(m_pUProp[ulCurSet].
  2698. pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
  2699. ATLASSERT( pUPropVal );
  2700. // Check to see if this property supports column level,
  2701. // if so, dump those nodes
  2702. if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2703. {
  2704. if( pUPropVal->pCColumnIds )
  2705. {
  2706. RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
  2707. continue;
  2708. }
  2709. }
  2710. pCurProp->dwOptions = pUPropVal->dwOption;
  2711. hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
  2712. }
  2713. else
  2714. {
  2715. GetDefaultValue(ulCurSet, pUPropInfo->dwPropId,
  2716. &(pCurProp->dwOptions), &(pCurProp->vValue));
  2717. }
  2718. dwStatus |= GETPROP_VALIDPROP;
  2719. }
  2720. else
  2721. {
  2722. // Not Supported
  2723. pCurProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  2724. dwStatus |= GETPROP_ERRORSOCCURRED;
  2725. }
  2726. }
  2727. // Increment return nodes count
  2728. ulNext++;
  2729. }
  2730. }
  2731. else
  2732. {
  2733. ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROP array for GetProperties\n");
  2734. if( pPropSet )
  2735. {
  2736. // Free any DBPROP arrays
  2737. for(ulSet=0; ulSet<cSets; ulSet++)
  2738. {
  2739. // Need to loop through all the VARIANTS and clear them
  2740. for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
  2741. VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
  2742. if( pPropSet[ulSet].rgProperties )
  2743. CoTaskMemFree(pPropSet[ulSet].rgProperties);
  2744. }
  2745. // Free DBPROPSET
  2746. CoTaskMemFree(pPropSet);
  2747. }
  2748. //Since we have no properties to return, then we
  2749. //need to free allocated memory and return 0,NULL
  2750. if(pPropSet)
  2751. {
  2752. // Free any DBPROP arrays
  2753. for(ulSet=0; ulSet<cSets; ulSet++)
  2754. {
  2755. // Need to loop through all the VARIANTS and clear them
  2756. for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
  2757. VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
  2758. if( pPropSet[ulSet].rgProperties )
  2759. CoTaskMemFree(pPropSet[ulSet].rgProperties);
  2760. }
  2761. // Free DBPROPSET
  2762. CoTaskMemFree(pPropSet);
  2763. }
  2764. *pcProperties = 0;
  2765. *prgProperties = NULL;
  2766. delete [] piIndex;
  2767. piIndex = NULL;
  2768. return E_OUTOFMEMORY;
  2769. }
  2770. NEXT_SET:
  2771. // It is possible that all properties are not supported,
  2772. // thus we should delete that memory and set rgProperties
  2773. // to NULL
  2774. if( ulNext == 0 && pProp )
  2775. {
  2776. CoTaskMemFree(pProp);
  2777. pProp = NULL;
  2778. }
  2779. pPropSet[iPropSet].cProperties = ulNext;
  2780. pPropSet[iPropSet].rgProperties = pProp;
  2781. iPropSet++;
  2782. }
  2783. *pcProperties = iPropSet;
  2784. *prgProperties = pPropSet;
  2785. delete piIndex;
  2786. piIndex = NULL;
  2787. // At least one propid was marked as not S_OK
  2788. if( dwStatus & GETPROP_ERRORSOCCURRED )
  2789. {
  2790. // If at least 1 property was set
  2791. if( dwStatus & GETPROP_VALIDPROP )
  2792. return DB_S_ERRORSOCCURRED;
  2793. else
  2794. {
  2795. // Do not free any of the memory on a DB_E_
  2796. return DB_E_ERRORSOCCURRED;
  2797. }
  2798. }
  2799. return S_OK;
  2800. }
  2801. ULONG GetCountofColids(UPROP* pUProp)
  2802. {
  2803. ULONG cExtra=0;
  2804. ATLASSERT(pUProp);
  2805. for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
  2806. {
  2807. if( pUProp->pUPropVal[ul].pCColumnIds )
  2808. cExtra += (pUProp->pUPropVal[ul].pCColumnIds)->GetCountOfPropColids();
  2809. }
  2810. return cExtra;
  2811. }
  2812. ULONG GetUPropValIndex(ULONG iCurSet, DBPROPID dwPropId)
  2813. {
  2814. for(ULONG ul=0; ul<m_pUProp[iCurSet].cPropIds; ul++)
  2815. {
  2816. if( (m_pUProp[iCurSet].rgpUPropInfo[ul])->dwPropId == dwPropId )
  2817. return ul;
  2818. }
  2819. return 0;
  2820. }
  2821. void RetrieveColumnIdProps(DBPROP* pCurProp, UPROPVAL* pUPropVal, ULONG* pulNext)
  2822. {
  2823. // Reset to first Node
  2824. CColumnIds* pColIds = pUPropVal->pCColumnIds;
  2825. HRESULT hr = E_FAIL;
  2826. for (int i = 0; i < pColIds->GetSize(); i++)
  2827. {
  2828. CPropColID colId;
  2829. hr = pColIds->GetValue(i, &(pCurProp->dwOptions), &(pCurProp->colid),&(pCurProp->vValue));
  2830. if (SUCCEEDED(hr))
  2831. pCurProp = &(pCurProp[++(*pulNext)]);
  2832. }
  2833. (*pulNext)++;
  2834. }
  2835. //Check the arguments for Retrieve Properties
  2836. HRESULT GetPropertiesArgChk(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
  2837. ULONG* pcProperties, DBPROPSET** prgProperties)
  2838. {
  2839. // Initialize values
  2840. if(pcProperties)
  2841. *pcProperties = 0;
  2842. if(prgProperties)
  2843. *prgProperties = NULL;
  2844. // Check Arguments
  2845. if( ((cPropertySets > 0) && !rgPropertySets) || !pcProperties || !prgProperties )
  2846. return E_INVALIDARG;
  2847. // New argument check for > 1 cPropertyIDs and NULL pointer for
  2848. // array of property ids.
  2849. for(ULONG ul=0; ul<cPropertySets; ul++)
  2850. {
  2851. if( rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs) )
  2852. return E_INVALIDARG;
  2853. // Check for propper formation of DBPROPSET_PROPERTIESINERROR
  2854. if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) &&
  2855. rgPropertySets[ul].guidPropertySet == DBPROPSET_PROPERTIESINERROR )
  2856. {
  2857. if( (cPropertySets > 1) ||
  2858. (rgPropertySets[ul].cPropertyIDs != 0) ||
  2859. (rgPropertySets[ul].rgPropertyIDs != NULL) )
  2860. return E_INVALIDARG;
  2861. }
  2862. }
  2863. return S_OK;
  2864. }
  2865. OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL) = 0;
  2866. };
  2867. // Implementation Class
  2868. template <class T>
  2869. class ATL_NO_VTABLE CUtlProps : public CUtlPropsBase
  2870. {
  2871. public:
  2872. CUtlProps(DWORD dwFlags = 0)
  2873. {
  2874. ClearMemberVars();
  2875. m_dwFlags = dwFlags;
  2876. }
  2877. ~CUtlProps()
  2878. {
  2879. FreeMemory();
  2880. }
  2881. void FreeMemory()
  2882. {
  2883. // Remove Property Information
  2884. if( m_pUProp )
  2885. {
  2886. for(ULONG ulPropSet=0; ulPropSet<m_cUPropSet; ulPropSet++)
  2887. {
  2888. UPROPVAL* pUPropVal = m_pUProp[ulPropSet].pUPropVal;
  2889. for(ULONG ulPropId=0; ulPropId<m_pUProp[ulPropSet].cPropIds; ulPropId++)
  2890. {
  2891. delete pUPropVal[ulPropId].pCColumnIds;
  2892. VariantClear(&(pUPropVal[ulPropId].vValue));
  2893. }
  2894. delete[] m_pUProp[ulPropSet].rgpUPropInfo;
  2895. delete[] m_pUProp[ulPropSet].pUPropVal;
  2896. }
  2897. }
  2898. delete[] m_pUProp;
  2899. delete[] m_rgdwSupported;
  2900. delete[] m_rgdwPropsInError;
  2901. delete[] m_rgiPropSetDex;
  2902. if (m_pUPropSet != NULL)
  2903. CoTaskMemFree(m_pUPropSet);
  2904. ClearMemberVars();
  2905. }
  2906. void ClearMemberVars()
  2907. {
  2908. m_cPropSetDex = 0;
  2909. m_cUPropSet = 0;
  2910. m_cUPropSetHidden = 0;
  2911. m_pUPropSet = NULL;
  2912. m_dwFlags = 0;
  2913. m_pUProp = NULL;
  2914. m_cElemPerSupported = 0;
  2915. m_rgdwSupported = NULL;
  2916. m_rgdwPropsInError = NULL;
  2917. m_rgiPropSetDex = NULL;
  2918. }
  2919. //Retrieve the property set indexes that match this property set.
  2920. HRESULT GetPropertySetIndex(GUID* pPropertySet)
  2921. {
  2922. DWORD dwFlag = 0;
  2923. ULONG ulSet;
  2924. ATLASSERT( m_cUPropSet && m_pUPropSet );
  2925. ATLASSERT( m_rgiPropSetDex );
  2926. ATLASSERT( pPropertySet );
  2927. m_cPropSetDex = 0;
  2928. if( *pPropertySet == DBPROPSET_DATASOURCEALL )
  2929. {
  2930. dwFlag = DBPROPFLAGS_DATASOURCE;
  2931. }
  2932. else if( *pPropertySet == DBPROPSET_DATASOURCEINFOALL )
  2933. {
  2934. dwFlag = DBPROPFLAGS_DATASOURCEINFO;
  2935. }
  2936. else if( *pPropertySet == DBPROPSET_ROWSETALL )
  2937. {
  2938. dwFlag = DBPROPFLAGS_ROWSET;
  2939. }
  2940. else if( *pPropertySet == DBPROPSET_DBINITALL )
  2941. {
  2942. dwFlag = DBPROPFLAGS_DBINIT;
  2943. }
  2944. else if( *pPropertySet == DBPROPSET_SESSIONALL )
  2945. {
  2946. dwFlag = DBPROPFLAGS_SESSION;
  2947. }
  2948. else // No scan required, just look for match.
  2949. {
  2950. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  2951. {
  2952. if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
  2953. {
  2954. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  2955. m_cPropSetDex++;
  2956. break;
  2957. }
  2958. }
  2959. goto EXIT;
  2960. }
  2961. // Scan through the property sets looking for matching attributes
  2962. for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  2963. {
  2964. if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
  2965. {
  2966. m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  2967. m_cPropSetDex++;
  2968. }
  2969. }
  2970. EXIT:
  2971. return (m_cPropSetDex) ? S_OK : S_FALSE;
  2972. }
  2973. OUT_OF_LINE HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar)
  2974. {
  2975. return InternalGetDefaultValue(T::_GetPropSet, iPropSet, dwPropId, pdwOption, pVar);
  2976. }
  2977. OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL)
  2978. {
  2979. return InternalFInit(T::_GetPropSet, pCopyMe);
  2980. }
  2981. HRESULT FillDefaultValues(ULONG ulPropSetTarget = ULONG_MAX)
  2982. {
  2983. HRESULT hr;
  2984. ULONG ulPropId;
  2985. ULONG iPropSet;
  2986. ULONG iNewDex;
  2987. // Fill in all the actual values.
  2988. // Typically because we now have an hdbc with which to get them.
  2989. // (Or we no longer have an hdbc, so must clear them.)
  2990. // Note that the UPROP (with values) array may be a subset of the UPROPINFO array.
  2991. // Only writable properties are in UPROP array.
  2992. // Maybe restrict to a single PropSet if within valid range [0...m_cUPropSet-1].
  2993. // Otherwise do all propsets.
  2994. iPropSet = (ulPropSetTarget < m_cUPropSet) ? ulPropSetTarget : 0;
  2995. for( ; iPropSet<m_cUPropSet; iPropSet++)
  2996. {
  2997. iNewDex = 0;
  2998. for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
  2999. {
  3000. if( m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3001. {
  3002. //Initialize dwFlags element of UPropVal
  3003. m_pUProp[iPropSet].pUPropVal[iNewDex].dwFlags = 0;
  3004. // Don't need this since SetProperties() resets these.
  3005. //ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption == DBPROPOPTIONS_SETIFCHEAP);
  3006. ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].pCColumnIds == NULL);
  3007. VariantClear(&m_pUProp[iPropSet].pUPropVal[iNewDex].vValue);
  3008. hr = GetDefaultValue(
  3009. iPropSet,
  3010. m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwPropId,
  3011. &m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption,
  3012. &m_pUProp[iPropSet].pUPropVal[iNewDex].vValue );
  3013. if (FAILED(hr))
  3014. return hr;
  3015. iNewDex++;
  3016. }
  3017. }
  3018. // We're through if restricting to single PropSet.
  3019. if (ulPropSetTarget < m_cUPropSet)
  3020. break;
  3021. }
  3022. return NOERROR;
  3023. }
  3024. // Translate Rowset IIDs to PROPSET structures ready to pass to SetProperties
  3025. HRESULT ConvertRowsetIIDtoDBPROPSET(const IID* piid, DBPROPSET* pPropSet)
  3026. {
  3027. HRESULT hr = S_OK;
  3028. DBPROP* pProp;
  3029. ATLASSERT( piid || pPropSet );
  3030. ATLASSERT( (pPropSet->cProperties == 1) || (pPropSet->rgProperties) );
  3031. pProp = &(pPropSet->rgProperties[0]);
  3032. if(InlineIsEqualGUID(*piid, IID_IAccessor))
  3033. pProp->dwPropertyID = DBPROP_IAccessor;
  3034. else if(InlineIsEqualGUID(*piid,IID_IColumnsInfo))
  3035. pProp->dwPropertyID = DBPROP_IColumnsInfo;
  3036. else if(InlineIsEqualGUID(*piid , IID_IRowset))
  3037. pProp->dwPropertyID = DBPROP_IRowset;
  3038. else if(InlineIsEqualGUID(*piid , IID_IRowsetInfo))
  3039. pProp->dwPropertyID = DBPROP_IRowsetInfo;
  3040. else if(InlineIsEqualGUID(*piid , IID_IRowsetLocate))
  3041. pProp->dwPropertyID = DBPROP_IRowsetLocate;
  3042. else if(InlineIsEqualGUID(*piid , IID_IColumnsRowset))
  3043. pProp->dwPropertyID = DBPROP_IColumnsRowset;
  3044. else if(InlineIsEqualGUID(*piid , IID_IRowsetResynch))
  3045. pProp->dwPropertyID = DBPROP_IRowsetResynch;
  3046. else if(InlineIsEqualGUID(*piid , IID_IRowsetScroll))
  3047. pProp->dwPropertyID = DBPROP_IRowsetScroll;
  3048. else if(InlineIsEqualGUID(*piid , IID_IRowsetChange))
  3049. pProp->dwPropertyID = DBPROP_IRowsetChange;
  3050. else if(InlineIsEqualGUID(*piid , IID_IRowsetUpdate))
  3051. pProp->dwPropertyID = DBPROP_IRowsetUpdate;
  3052. else if(InlineIsEqualGUID(*piid , IID_IRowsetIdentity))
  3053. pProp->dwPropertyID = DBPROP_IRowsetIdentity;
  3054. else if(InlineIsEqualGUID(*piid , IID_IConnectionPointContainer))
  3055. pProp->dwPropertyID = DBPROP_IConnectionPointContainer;
  3056. else if(InlineIsEqualGUID(*piid , IID_ISupportErrorInfo))
  3057. pProp->dwPropertyID = DBPROP_ISupportErrorInfo;
  3058. else if(InlineIsEqualGUID(*piid , IID_IRowsetIndex))
  3059. pProp->dwPropertyID = DBPROP_IRowsetIndex;
  3060. #if( OLEDBVER >= 0x0200 )
  3061. else if(InlineIsEqualGUID(*piid , IID_IRowsetLockRows))
  3062. pProp->dwPropertyID = DBPROP_IRowsetLockRows;
  3063. else if(InlineIsEqualGUID(*piid , IID_IProvideMoniker))
  3064. pProp->dwPropertyID = DBPROP_IProvideMoniker;
  3065. else if(InlineIsEqualGUID(*piid , IID_IRowsetNotify))
  3066. pProp->dwPropertyID = DBPROP_IRowsetNotify;
  3067. else if(InlineIsEqualGUID(*piid , IID_IReadData))
  3068. pProp->dwPropertyID = DBPROP_IReadData;
  3069. else if(InlineIsEqualGUID(*piid , IID_IRowsetExactScroll))
  3070. pProp->dwPropertyID = DBPROP_IRowsetExactScroll;
  3071. else if(InlineIsEqualGUID(*piid , IID_IRowsetNextRowset))
  3072. pProp->dwPropertyID = DBPROP_IRowsetNextRowset;
  3073. else if(InlineIsEqualGUID(*piid , IID_IRowsetDelete))
  3074. pProp->dwPropertyID = DBPROP_IRowsetDelete;
  3075. else if(InlineIsEqualGUID(*piid , IID_IRowsetDeleteBookmarks))
  3076. pProp->dwPropertyID = DBPROP_IRowsetDeleteBookmarks;
  3077. else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRow))
  3078. pProp->dwPropertyID = DBPROP_IRowsetNewRow;
  3079. else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRowAfter))
  3080. pProp->dwPropertyID = DBPROP_IRowsetNewRowAfter;
  3081. else if(InlineIsEqualGUID(*piid , IID_IRowsetWithParameters))
  3082. pProp->dwPropertyID = DBPROP_IRowsetWithParameters;
  3083. else if(InlineIsEqualGUID(*piid , IID_IRowsetFind))
  3084. pProp->dwPropertyID = DBPROP_IRowsetFind;
  3085. else if(InlineIsEqualGUID(*piid , IID_IRowsetAsynch))
  3086. pProp->dwPropertyID = DBPROP_IRowsetAsynch;
  3087. else if(InlineIsEqualGUID(*piid , IID_IRowsetKeys))
  3088. pProp->dwPropertyID = DBPROP_IRowsetKeys;
  3089. else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchAll))
  3090. pProp->dwPropertyID = DBPROP_IRowsetWatchAll;
  3091. else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchNotify))
  3092. pProp->dwPropertyID = DBPROP_IRowsetWatchNotify;
  3093. else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchRegion))
  3094. pProp->dwPropertyID = DBPROP_IRowsetWatchRegion;
  3095. else if(InlineIsEqualGUID(*piid , IID_IRowsetCopyRows))
  3096. pProp->dwPropertyID = DBPROP_IRowsetCopyRows;
  3097. #endif //#if( OLEDBVER >= 0x0200 )
  3098. else
  3099. hr = S_FALSE;
  3100. // If the IID can be mapped to a DBPROPID, the
  3101. // we need to initialize the vValue to TRUE
  3102. if(hr == S_OK)
  3103. {
  3104. // Set PropertySet
  3105. pPropSet->guidPropertySet = DBPROPSET_ROWSET;
  3106. // Set Property
  3107. pProp->dwOptions = DBPROPOPTIONS_REQUIRED;
  3108. pProp->dwStatus = 0;
  3109. pProp->colid = DB_NULLID;
  3110. VariantInit(&(pProp->vValue));
  3111. pProp->vValue.vt = VT_BOOL;
  3112. V_BOOL(&(pProp->vValue)) = VARIANT_TRUE;
  3113. }
  3114. return hr;
  3115. }
  3116. void SetPropertyInError(const ULONG iPropSet, const ULONG iPropId)
  3117. {
  3118. SETBIT(&(m_rgdwPropsInError[iPropSet * m_cElemPerSupported]), iPropId);
  3119. }
  3120. BOOL IsPropSet(const GUID* pguidPropSet, DBPROPID dwPropId)
  3121. {
  3122. HRESULT hr;
  3123. ULONG iPropSet;
  3124. ULONG iPropId;
  3125. VARIANT vValue;
  3126. DWORD dwOptions;
  3127. VariantInit(&vValue);
  3128. if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3129. {
  3130. if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3131. {
  3132. if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags &
  3133. (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3134. {
  3135. ULONG iPropVal = GetUPropValIndex(iPropSet, dwPropId);
  3136. dwOptions = m_pUProp[iPropSet].pUPropVal[iPropVal].dwOption;
  3137. hr = VariantCopy(&vValue, &(m_pUProp[iPropSet].
  3138. pUPropVal[iPropVal].vValue));
  3139. }
  3140. else
  3141. {
  3142. hr = GetDefaultValue(iPropSet, dwPropId,
  3143. &dwOptions, &vValue);
  3144. }
  3145. if( dwOptions == DBPROPOPTIONS_REQUIRED )
  3146. {
  3147. ATLASSERT( vValue.vt == VT_BOOL );
  3148. if( SUCCEEDED(hr) &&
  3149. (V_BOOL(&vValue) == VARIANT_TRUE) )
  3150. {
  3151. VariantClear(&vValue);
  3152. return TRUE;
  3153. }
  3154. }
  3155. }
  3156. }
  3157. VariantClear(&vValue);
  3158. return FALSE;
  3159. }
  3160. OUT_OF_LINE HRESULT GetPropValue(const GUID* pguidPropSet, DBPROPID dwPropId, VARIANT* pvValue)
  3161. {
  3162. HRESULT hr = E_FAIL;
  3163. ULONG iPropSet;
  3164. ULONG iPropId = 0;
  3165. DWORD dwOptions;
  3166. if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3167. {
  3168. if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3169. {
  3170. if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3171. {
  3172. hr = VariantCopy(pvValue, &(m_pUProp[iPropSet].pUPropVal[
  3173. GetUPropValIndex(iPropSet, dwPropId)].vValue));
  3174. }
  3175. else
  3176. {
  3177. VariantClear(pvValue);
  3178. hr = GetDefaultValue(iPropSet, dwPropId,
  3179. &dwOptions, pvValue);
  3180. }
  3181. }
  3182. }
  3183. return hr;
  3184. }
  3185. HRESULT SetPropValue(const GUID* pguidPropSet,DBPROPID dwPropId, VARIANT* pvValue)
  3186. {
  3187. HRESULT hr = E_FAIL;
  3188. ULONG iPropSet;
  3189. ULONG iPropId;
  3190. if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3191. {
  3192. if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3193. {
  3194. ATLASSERT( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) );
  3195. hr = VariantCopy(&(m_pUProp[iPropSet].pUPropVal[
  3196. GetUPropValIndex(iPropSet, dwPropId)].vValue), pvValue);
  3197. }
  3198. }
  3199. return hr;
  3200. }
  3201. //Pointer to properties in error mask
  3202. DWORD* GetPropsInErrorPtr(){return m_rgdwPropsInError;}
  3203. ULONG GetUPropSetCount() {return m_cUPropSet;}
  3204. void SetUPropSetCount(ULONG c) {m_cUPropSet = c;}
  3205. // NOTE: The following functions depend on all prior
  3206. // properties in the array being writable.
  3207. // This is because the UPROP array contains only writable elements,
  3208. // and the UPROPINFO array contains writable and read-only elements.
  3209. // (If this is a problem, we would need to define which one it came from
  3210. // and add the appropriate ATLASSERTs...)
  3211. //Get DBPROPOPTIONS_xx
  3212. DWORD GetPropOption(ULONG iPropSet, ULONG iProp)
  3213. {
  3214. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3215. return m_pUProp[iPropSet].pUPropVal[iProp].dwOption;
  3216. }
  3217. //Set DBPROPOPTIONS_xx
  3218. void SetPropOption(ULONG iPropSet, ULONG iProp, DWORD dwOption)
  3219. {
  3220. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3221. m_pUProp[iPropSet].pUPropVal[iProp].dwOption = dwOption;
  3222. }
  3223. //Determine if property is required and variant_true
  3224. BOOL IsRequiredTrue(ULONG iPropSet, ULONG iProp)
  3225. {
  3226. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3227. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
  3228. ATLASSERT(V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE
  3229. || V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_FALSE);
  3230. return( (m_pUProp[iPropSet].pUPropVal[iProp].dwOption == DBPROPOPTIONS_REQUIRED) &&
  3231. (V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE) );
  3232. }
  3233. DWORD GetInternalFlags(ULONG iPropSet, ULONG iProp)
  3234. {
  3235. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3236. return m_pUProp[iPropSet].pUPropVal[iProp].dwFlags;
  3237. }
  3238. void AddInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
  3239. {
  3240. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3241. m_pUProp[iPropSet].pUPropVal[iProp].dwFlags |= dwFlags;
  3242. }
  3243. void RemoveInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
  3244. {
  3245. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3246. m_pUProp[iPropSet].pUPropVal[iProp].dwFlags &= ~dwFlags;
  3247. }
  3248. VARIANT * GetVariant(ULONG iPropSet, ULONG iProp)
  3249. {
  3250. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3251. return & m_pUProp[iPropSet].pUPropVal[iProp].vValue;
  3252. }
  3253. HRESULT SetVariant(ULONG iPropSet, ULONG iProp, VARIANT *pv )
  3254. {
  3255. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3256. // Does VariantClear first.
  3257. return VariantCopy( &m_pUProp[iPropSet].pUPropVal[iProp].vValue, pv );
  3258. }
  3259. void SetValEmpty(ULONG iPropSet, ULONG iProp)
  3260. {
  3261. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3262. VariantClear( &m_pUProp[iPropSet].pUPropVal[iProp].vValue );
  3263. }
  3264. BOOL IsEmpty(ULONG iPropSet, ULONG iProp)
  3265. {
  3266. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3267. return ( m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_EMPTY);
  3268. }
  3269. void SetValBool(ULONG iPropSet, ULONG iProp, VARIANT_BOOL bVal)
  3270. {
  3271. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3272. // Note that we accept any "true" value.
  3273. VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3274. m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_BOOL;
  3275. V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) = (bVal ? VARIANT_TRUE : VARIANT_FALSE);
  3276. }
  3277. VARIANT_BOOL GetValBool(ULONG iPropSet, ULONG iProp)
  3278. {
  3279. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3280. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
  3281. return V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3282. }
  3283. void SetValShort(ULONG iPropSet, ULONG iProp, SHORT iVal )
  3284. {
  3285. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3286. VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3287. m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I2;
  3288. m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal = iVal;
  3289. }
  3290. SHORT GetValShort(ULONG iPropSet, ULONG iProp)
  3291. {
  3292. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3293. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I2);
  3294. return m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal;
  3295. }
  3296. void SetValLong(ULONG iPropSet, ULONG iProp, LONG lVal)
  3297. {
  3298. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3299. VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3300. m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I4;
  3301. m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal = lVal;
  3302. }
  3303. LONG GetValLong(ULONG iPropSet, ULONG iProp)
  3304. {
  3305. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3306. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I4);
  3307. return m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal;
  3308. }
  3309. HRESULT SetValString(ULONG iPropSet, ULONG iProp, const WCHAR *pwsz)
  3310. {
  3311. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3312. VARIANT *pv = &m_pUProp[iPropSet].pUPropVal[iProp].vValue;
  3313. VariantClear(pv);
  3314. pv->bstrVal = SysAllocString(pwsz);
  3315. if (pv->bstrVal)
  3316. pv->vt = VT_BSTR;
  3317. else
  3318. return E_FAIL;
  3319. // See if this was used for non-string type.
  3320. // Typically this is an easy way to pass integer as a string.
  3321. if (GetExpectedVarType(iPropSet,iProp) == VT_BSTR)
  3322. return NOERROR;
  3323. if (pwsz[0] != L'\0')
  3324. return VariantChangeType( pv, pv, 0, GetExpectedVarType(iPropSet,iProp) );
  3325. // Set to "", which for non-string means empty.
  3326. SysFreeString(pv->bstrVal);
  3327. pv->vt = VT_EMPTY;
  3328. return NOERROR;
  3329. }
  3330. const WCHAR * GetValString(ULONG iPropSet, ULONG iProp)
  3331. {
  3332. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3333. ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BSTR);
  3334. return m_pUProp[iPropSet].pUPropVal[iProp].vValue.bstrVal;
  3335. }
  3336. const GUID * GetGuid(ULONG iPropSet)
  3337. {
  3338. ATLASSERT(iPropSet < m_cUPropSet);
  3339. return m_pUPropSet[iPropSet].pPropSet;
  3340. }
  3341. DWORD GetPropID(ULONG iPropSet, ULONG iProp)
  3342. {
  3343. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3344. return m_pUPropSet[iPropSet].pUPropInfo[iProp].dwPropId;
  3345. }
  3346. VARTYPE GetExpectedVarType(ULONG iPropSet, ULONG iProp)
  3347. {
  3348. ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3349. return m_pUPropSet[iPropSet].pUPropInfo[iProp].VarType;
  3350. }
  3351. virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet)
  3352. {
  3353. ATLASSERT(pPropSet && pulCurSet);
  3354. for(ULONG ul=0; ul<m_cUPropSet; ul++)
  3355. {
  3356. if( *pPropSet == *(m_pUPropSet[ul].pPropSet) )
  3357. {
  3358. *pulCurSet = ul;
  3359. return S_OK;
  3360. }
  3361. }
  3362. return S_FALSE;
  3363. }
  3364. virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/)
  3365. {
  3366. return S_OK;
  3367. }
  3368. virtual HRESULT InitUPropSetsSupported()
  3369. {
  3370. return InternalInitUPropSetsSupported(T::_GetPropSet);
  3371. }
  3372. HRESULT GetIndexOfPropertyInSet(const GUID* pPropSet, DBPROPID dwPropertyId, ULONG* piCurPropId, ULONG* piCurSet)
  3373. {
  3374. HRESULT hr = GetIndexofPropSet(pPropSet, piCurSet);
  3375. if (hr == S_FALSE)
  3376. return hr;
  3377. UPROPINFO* pUPropInfo = m_pUPropSet[*piCurSet].pUPropInfo;
  3378. for(ULONG ul=0; ul<m_pUPropSet[*piCurSet].cUPropInfo; ul++)
  3379. {
  3380. if( dwPropertyId == pUPropInfo[ul].dwPropId )
  3381. *piCurPropId = ul;
  3382. return S_OK;
  3383. }
  3384. return S_FALSE;
  3385. }
  3386. HRESULT SetSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
  3387. {
  3388. ULONG iCurPropId, iCurSet;
  3389. if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3390. {
  3391. m_rgdwSupported[iCurSet * m_cElemPerSupported] |= 1 << iCurPropId;
  3392. return S_OK;
  3393. }
  3394. return S_FALSE;
  3395. }
  3396. HRESULT ClearSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
  3397. {
  3398. ULONG iCurPropId, iCurSet;
  3399. if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3400. {
  3401. m_rgdwSupported[iCurSet * m_cElemPerSupported] &= ~( 1 << iCurPropId);
  3402. return S_OK;
  3403. }
  3404. return S_FALSE;
  3405. }
  3406. HRESULT TestSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId, bool& bSet)
  3407. {
  3408. ULONG iCurPropId, iCurSet;
  3409. if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3410. {
  3411. bSet = (m_rgdwSupported[iCurSet * m_cElemPerSupported] & ( 1 << iCurPropId)) != 0;
  3412. return S_OK;
  3413. }
  3414. return S_FALSE;
  3415. }
  3416. void CopyPropsInError(DWORD* rgdwSupported)
  3417. {
  3418. memcpy(rgdwSupported, m_rgdwPropsInError, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
  3419. }
  3420. };
  3421. // IDBPropertiesImpl
  3422. // IDBProperties <- IUnknown
  3423. template <class T>
  3424. class ATL_NO_VTABLE IDBPropertiesImpl : public IDBProperties, public CUtlProps<T>
  3425. {
  3426. public:
  3427. STDMETHOD(GetProperties)(ULONG cPropertySets,
  3428. const DBPROPIDSET rgPropertySets[],
  3429. ULONG *pcProperties,
  3430. DBPROPSET **prgProperties)
  3431. {
  3432. ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetProperties\n");
  3433. T* pT = (T*)this;
  3434. HRESULT hr = GetPropertiesArgChk(cPropertySets, rgPropertySets, pcProperties, prgProperties);
  3435. if (FAILED(hr))
  3436. return hr;
  3437. if(SUCCEEDED(hr))
  3438. {
  3439. // Check for other invalid arguments
  3440. for (ULONG i=0; i<cPropertySets; i++)
  3441. {
  3442. if (InlineIsEqualGUID(rgPropertySets[i].guidPropertySet, DBPROPSET_PROPERTIESINERROR))
  3443. if (pcProperties != NULL || prgProperties != NULL || cPropertySets > 1)
  3444. return E_INVALIDARG;
  3445. }
  3446. }
  3447. if (SUCCEEDED(hr))
  3448. {
  3449. const GUID* ppGuid[3];
  3450. if (pT->m_dwStatus & DSF_INITIALIZED)
  3451. {
  3452. ppGuid[0] = &DBPROPSET_DBINIT;
  3453. ppGuid[1] = &DBPROPSET_DATASOURCE;
  3454. ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
  3455. hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets,
  3456. pcProperties, prgProperties, 3, ppGuid);
  3457. }
  3458. else
  3459. {
  3460. ppGuid[0] = &DBPROPSET_DBINIT;
  3461. hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets,
  3462. pcProperties, prgProperties, 1, ppGuid);
  3463. }
  3464. }
  3465. return hr;
  3466. }
  3467. STDMETHOD(GetPropertyInfo)(ULONG cPropertySets,
  3468. const DBPROPIDSET rgPropertySets[],
  3469. ULONG *pcPropertyInfoSets,
  3470. DBPROPINFOSET **prgPropertyInfoSets,
  3471. OLECHAR **ppDescBuffer)
  3472. {
  3473. ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetPropertyInfo\n");
  3474. T* pT = (T*)this;
  3475. if (pT->m_pCUtlPropInfo == NULL)
  3476. {
  3477. // Go ahead and create the m_pCUtlPropInfo but do not change the
  3478. // Initialized status of the provider (see IDBInitialize::Initialize).
  3479. ATLTRACE2(atlTraceDBProvider, 0, "m_pCUtlPropInfo == NULL\n");
  3480. pT->Lock();
  3481. delete pT->m_pCUtlPropInfo;
  3482. ATLTRY(pT->m_pCUtlPropInfo = new CUtlPropInfo<T>())
  3483. pT->Unlock();
  3484. if (pT->m_pCUtlPropInfo == NULL)
  3485. {
  3486. ATLTRACE2(atlTraceDBProvider, 0, "IDBProperties::GetPropertyInfo Error : OOM\n");
  3487. return E_OUTOFMEMORY;
  3488. }
  3489. HRESULT hr = pT->m_pCUtlPropInfo->FInit();
  3490. if (hr != S_OK)
  3491. {
  3492. pT->Lock();
  3493. delete pT->m_pCUtlPropInfo;
  3494. pT->m_pCUtlPropInfo = NULL;
  3495. pT->Unlock();
  3496. }
  3497. }
  3498. // Initialize
  3499. if( pcPropertyInfoSets )
  3500. *pcPropertyInfoSets = 0;
  3501. if( prgPropertyInfoSets )
  3502. *prgPropertyInfoSets = NULL;
  3503. if( ppDescBuffer )
  3504. *ppDescBuffer = NULL;
  3505. // Check Arguments
  3506. if( ((cPropertySets > 0) && !rgPropertySets) ||
  3507. !pcPropertyInfoSets || !prgPropertyInfoSets )
  3508. return E_INVALIDARG;
  3509. // New argument check for > 1 cPropertyIDs and NULL pointer for
  3510. // array of property ids.
  3511. const DWORD SPECIAL_GROUP = 1;
  3512. const DWORD SPECIAL_SINGLE = 2;
  3513. const DWORD SPECIALS = SPECIAL_GROUP | SPECIAL_SINGLE;
  3514. DWORD dwSpecial = 0;
  3515. for(ULONG ul=0; ul<cPropertySets; ul++)
  3516. {
  3517. if( (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEALL) ||
  3518. (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEINFOALL) ||
  3519. (rgPropertySets[ul].guidPropertySet == DBPROPSET_DBINITALL) ||
  3520. (rgPropertySets[ul].guidPropertySet == DBPROPSET_SESSIONALL) ||
  3521. (rgPropertySets[ul].guidPropertySet == DBPROPSET_ROWSETALL) )
  3522. dwSpecial |= SPECIAL_GROUP;
  3523. else
  3524. dwSpecial |= SPECIAL_SINGLE;
  3525. if( (dwSpecial == SPECIALS) ||
  3526. (rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs)) )
  3527. return E_INVALIDARG;
  3528. }
  3529. if (pT->m_dwStatus & DSF_INITIALIZED)
  3530. return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets,
  3531. pcPropertyInfoSets, prgPropertyInfoSets,
  3532. ppDescBuffer, true);
  3533. else
  3534. return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets,
  3535. pcPropertyInfoSets, prgPropertyInfoSets,
  3536. ppDescBuffer, false, &DBPROPSET_DBINITALL);
  3537. }
  3538. STDMETHOD(SetProperties)(ULONG cPropertySets,
  3539. DBPROPSET rgPropertySets[])
  3540. {
  3541. ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::SetProperties\n");
  3542. HRESULT hr;
  3543. DBPROPSET* pdbPropSet = NULL;
  3544. ULONG iProp;
  3545. const GUID* ppGuid[3];
  3546. T* pT = (T*)this;
  3547. // Quick return if the Count of Properties is 0
  3548. if( cPropertySets == 0 )
  3549. return S_OK;
  3550. hr = CUtlProps<T>::SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3551. if(SUCCEEDED(hr))
  3552. {
  3553. // We need to handle the DBINIT properties specially after being initialized.
  3554. // - they should be treated as NOTSETTABLE at this point.
  3555. if( pT->m_dwStatus & DSF_INITIALIZED )
  3556. {
  3557. ATLASSERT(cPropertySets);
  3558. BOOL fFoundDBINIT = FALSE;
  3559. // Allocate a DBPROPSET structure of equal size
  3560. ATLTRY(pdbPropSet = new DBPROPSET[cPropertySets])
  3561. if( pdbPropSet == NULL )
  3562. return E_OUTOFMEMORY;
  3563. for(ULONG iNewSet=0,iSet=0; iSet<cPropertySets; iSet++)
  3564. {
  3565. // Remove any DBPROPSET_DBINIT values and mark them all
  3566. // as not settable
  3567. if( (rgPropertySets[iSet].guidPropertySet == DBPROPSET_DBINIT))
  3568. {
  3569. fFoundDBINIT = TRUE;
  3570. for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++)
  3571. rgPropertySets[iSet].rgProperties[iProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
  3572. }
  3573. else
  3574. {
  3575. // If not DBPROPSET_DBINIT then copy the DBPROPSET values
  3576. memcpy(&pdbPropSet[iNewSet++], &rgPropertySets[iSet], sizeof(DBPROPSET));
  3577. }
  3578. }
  3579. // If we have no propertyset to pass on to the property handler, we
  3580. // can exit
  3581. if( iNewSet == 0 )
  3582. {
  3583. hr = DB_E_ERRORSOCCURRED;
  3584. goto exit;
  3585. }
  3586. ppGuid[0] = &DBPROPSET_DBINIT;
  3587. ppGuid[1] = &DBPROPSET_DATASOURCE;
  3588. ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
  3589. hr = CUtlProps<T>::SetProperties(0, iNewSet, pdbPropSet, 3, ppGuid);
  3590. // If we have determined that one of the property sets was DBINIT, we may
  3591. // need to fixup the returned hr value.
  3592. if( fFoundDBINIT && SUCCEEDED(hr))
  3593. hr = DB_S_ERRORSOCCURRED;
  3594. }
  3595. else
  3596. {
  3597. // Note that m_pCUtlProps knows about initialization,
  3598. // so we don't have to here.
  3599. ppGuid[0] = &DBPROPSET_DBINIT;
  3600. hr = CUtlProps<T>::SetProperties(0, cPropertySets, rgPropertySets,
  3601. 1, ppGuid);
  3602. }
  3603. }
  3604. exit:
  3605. delete[] pdbPropSet;
  3606. return hr;
  3607. }
  3608. };
  3609. #define BEGIN_SCHEMA_MAP(SchemaClass) \
  3610. typedef SchemaClass _SchemaClass; \
  3611. HRESULT _SchemaSupport(GUID** ppGuid, \
  3612. IUnknown *pUnkOuter, \
  3613. REFIID rguidSchema, \
  3614. ULONG cRestrictions, \
  3615. const VARIANT rgRestrictions[], \
  3616. REFIID riid, \
  3617. ULONG cPropertySets, \
  3618. DBPROPSET rgPropertySets[], \
  3619. IUnknown **ppRowset) \
  3620. { \
  3621. int cGuids = 0; \
  3622. HRESULT hr = S_OK; \
  3623. if (ppGuid != NULL) \
  3624. *ppGuid = NULL;
  3625. #define SCHEMA_ENTRY(guid, rowsetClass) \
  3626. if (ppGuid != NULL && SUCCEEDED(hr)) \
  3627. { \
  3628. cGuids++; \
  3629. *ppGuid = (GUID*)CoTaskMemRealloc(*ppGuid, cGuids * sizeof(GUID)); \
  3630. hr = (*ppGuid == NULL) ? E_OUTOFMEMORY : S_OK; \
  3631. if (SUCCEEDED(hr)) \
  3632. (*ppGuid)[cGuids - 1] = guid; \
  3633. } \
  3634. else \
  3635. { \
  3636. if (InlineIsEqualGUID(guid, rguidSchema)) \
  3637. { \
  3638. rowsetClass* pRowset; \
  3639. hr = CreateSchemaRowset(pUnkOuter, cRestrictions, \
  3640. rgRestrictions, riid, cPropertySets, \
  3641. rgPropertySets, ppRowset, pRowset); \
  3642. return hr; \
  3643. } \
  3644. }
  3645. #define END_SCHEMA_MAP() \
  3646. if (ppGuid != NULL) \
  3647. return hr; \
  3648. return E_INVALIDARG; \
  3649. }
  3650. template <class SessionClass>
  3651. class ATL_NO_VTABLE IDBSchemaRowsetImpl: public IDBSchemaRowset
  3652. {
  3653. public:
  3654. OUT_OF_LINE HRESULT InternalCreateSchemaRowset(IUnknown *pUnkOuter, ULONG /*cRestrictions*/,
  3655. const VARIANT /*rgRestrictions*/[], REFIID riid,
  3656. ULONG cPropertySets, DBPROPSET rgPropertySets[],
  3657. IUnknown** ppRowset, IUnknown* pUnkThis, CUtlPropsBase* pProps,
  3658. IUnknown* pUnkSession)
  3659. {
  3660. HRESULT hr, hrProps = S_OK;
  3661. if (ppRowset != NULL)
  3662. *ppRowset = NULL;
  3663. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  3664. return DB_E_NOAGGREGATION;
  3665. CComPtr<IUnknown> spUnk;
  3666. hr = pUnkThis->QueryInterface(IID_IUnknown, (void**)&spUnk);
  3667. if (FAILED(hr))
  3668. return hr;
  3669. hr = pProps->FInit();
  3670. if (FAILED(hr))
  3671. return hr;
  3672. hr = pProps->SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3673. if (FAILED(hr))
  3674. return hr;
  3675. const GUID* ppGuid[1];
  3676. ppGuid[0] = &DBPROPSET_ROWSET;
  3677. // Call SetProperties. The true in the last parameter indicates
  3678. // the special behavior that takes place on rowset creation (i.e.
  3679. // it succeeds as long as any of the properties were not marked
  3680. // as DBPROPS_REQUIRED.
  3681. hrProps = pProps->SetProperties(0, cPropertySets, rgPropertySets,
  3682. 1, ppGuid, true);
  3683. if (FAILED(hrProps))
  3684. return hrProps;
  3685. if (ppRowset == NULL)
  3686. return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
  3687. CComQIPtr<IObjectWithSite> spSite = spUnk;
  3688. ATLASSERT(spSite != NULL);
  3689. hr = spSite->SetSite(pUnkSession);
  3690. if (FAILED(hr))
  3691. return hr;
  3692. if (InlineIsEqualGUID(riid, IID_NULL))
  3693. return E_NOINTERFACE;
  3694. hr = spUnk->QueryInterface(riid, (void**)ppRowset);
  3695. if (FAILED(hr))
  3696. {
  3697. *ppRowset = NULL;
  3698. return hr;
  3699. }
  3700. return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  3701. }
  3702. template <class SchemaRowsetClass>
  3703. HRESULT CreateSchemaRowset(IUnknown *pUnkOuter, ULONG cRestrictions,
  3704. const VARIANT rgRestrictions[], REFIID riid,
  3705. ULONG cPropertySets, DBPROPSET rgPropertySets[],
  3706. IUnknown** ppRowset, SchemaRowsetClass*& pSchemaRowset)
  3707. {
  3708. HRESULT hrProps, hr = S_OK;
  3709. SessionClass* pT = (SessionClass*) this;
  3710. CComPolyObject<SchemaRowsetClass>* pPolyObj;
  3711. if (FAILED(hr = CComPolyObject<SchemaRowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  3712. return hr;
  3713. pSchemaRowset = &(pPolyObj->m_contained);
  3714. hr = InternalCreateSchemaRowset(pUnkOuter, cRestrictions, rgRestrictions,
  3715. riid, cPropertySets, rgPropertySets, ppRowset,
  3716. pPolyObj, pT, pT->GetUnknown());
  3717. // Ref the created COM object and Auto release it on failure
  3718. if (FAILED(hr))
  3719. return hr;
  3720. hrProps = hr;
  3721. // Get a pointer to the Rowset instance
  3722. LONG cRowsAffected;
  3723. hr = pSchemaRowset->Execute(&cRowsAffected, cRestrictions, rgRestrictions);
  3724. if (FAILED(hr))
  3725. return hr;
  3726. return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  3727. }
  3728. void SetRestrictions(ULONG cRestrictions, GUID* /*rguidSchema*/, ULONG* rgRestrictions)
  3729. {
  3730. memset(rgRestrictions, 0, sizeof(ULONG) * cRestrictions);
  3731. }
  3732. STDMETHOD(GetSchemas)(ULONG * pcSchemas, GUID ** prgSchemas, ULONG** prgRest)
  3733. {
  3734. ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetSchemas\n");
  3735. if (pcSchemas != NULL)
  3736. *pcSchemas = 0;
  3737. if (prgSchemas != NULL)
  3738. *prgSchemas = NULL;
  3739. if (pcSchemas == NULL || prgSchemas == NULL)
  3740. return E_INVALIDARG;
  3741. SessionClass* pT = (SessionClass*)this;
  3742. HRESULT hr = pT->_SchemaSupport(prgSchemas, NULL, GUID_NULL, 0,
  3743. NULL, GUID_NULL, 0, NULL, NULL);
  3744. if (FAILED(hr))
  3745. return hr;
  3746. CComPtr<IMalloc> spMalloc;
  3747. hr = CoGetMalloc(1, &spMalloc);
  3748. if (FAILED(hr))
  3749. {
  3750. CoTaskMemFree(*prgSchemas);
  3751. *prgSchemas = NULL;
  3752. return hr;
  3753. }
  3754. *pcSchemas = (ULONG)(ULONG_PTR)spMalloc->GetSize(*prgSchemas) / sizeof(GUID);
  3755. if (prgRest != NULL)
  3756. {
  3757. // The OLE DB spec states that if prgRest == NULL not to return array
  3758. // but it also says that is E_INVALIDARG, so doing first
  3759. *prgRest = (ULONG*) spMalloc->Alloc(sizeof(ULONG) * (*pcSchemas));
  3760. if (*prgRest == NULL)
  3761. {
  3762. spMalloc->Free(*prgSchemas);
  3763. *prgSchemas = NULL;
  3764. return E_OUTOFMEMORY;
  3765. }
  3766. pT->SetRestrictions(*pcSchemas, *prgSchemas, *prgRest);
  3767. }
  3768. return hr;
  3769. }
  3770. STDMETHOD(GetRowset)(IUnknown *pUnkOuter, REFGUID rguidSchema, ULONG cRestrictions,
  3771. const VARIANT rgRestrictions[], REFIID riid, ULONG cPropertySets,
  3772. DBPROPSET rgPropertySets[], IUnknown **ppRowset)
  3773. {
  3774. ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetRowset\n");
  3775. SessionClass* pT = (SessionClass*)this;
  3776. return pT->_SchemaSupport(NULL, pUnkOuter, rguidSchema, cRestrictions,
  3777. rgRestrictions, riid, cPropertySets,
  3778. rgPropertySets, ppRowset);
  3779. }
  3780. };
  3781. // IDBCreateCommandImpl
  3782. template <class T, class CommandClass>
  3783. class ATL_NO_VTABLE IDBCreateCommandImpl : public IDBCreateCommand
  3784. {
  3785. public:
  3786. STDMETHOD(CreateCommand)(IUnknown *pUnkOuter,
  3787. REFIID riid,
  3788. IUnknown **ppvCommand)
  3789. {
  3790. ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateCommandImpl::CreateCommand\n");
  3791. if (ppvCommand == NULL)
  3792. return E_INVALIDARG;
  3793. HRESULT hr;
  3794. CComPolyObject<CommandClass>* pCommand;
  3795. // You can't QI for an interface other than IUnknown when aggregating
  3796. // and creating the object. You might ask for your own interface,
  3797. // which would be bad. Note, we return DB_E_NOAGGREGATION instead of
  3798. // CLASS_E_NOAGGREGATION due to OLE DB constraints.
  3799. if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid))
  3800. return DB_E_NOAGGREGATION;
  3801. hr = CComPolyObject<CommandClass>::CreateInstance(pUnkOuter, &pCommand);
  3802. if (FAILED(hr))
  3803. return hr;
  3804. // Ref the created COM object and Auto release it on failure
  3805. CComPtr<IUnknown> spUnk;
  3806. hr = pCommand->QueryInterface(&spUnk);
  3807. if (FAILED(hr))
  3808. {
  3809. delete pCommand; // must hand delete as it is not ref'd
  3810. return hr;
  3811. }
  3812. ATLASSERT(pCommand->m_contained.m_spUnkSite == NULL);
  3813. pCommand->m_contained.SetSite(this);
  3814. hr = pCommand->QueryInterface(riid, (void**)ppvCommand);
  3815. return hr;
  3816. }
  3817. };
  3818. // IGetDataSourceImpl
  3819. template <class T>
  3820. class ATL_NO_VTABLE IGetDataSourceImpl : public IGetDataSource
  3821. {
  3822. public:
  3823. STDMETHOD(GetDataSource)(REFIID riid,
  3824. IUnknown **ppDataSource)
  3825. {
  3826. ATLTRACE2(atlTraceDBProvider, 0, "IGetDataSourceImpl::GetDataSource\n");
  3827. if (ppDataSource == NULL)
  3828. return E_INVALIDARG;
  3829. T* pT = (T*) this;
  3830. ATLASSERT(pT->m_spUnkSite != NULL);
  3831. return pT->m_spUnkSite->QueryInterface(riid, (void**)ppDataSource);
  3832. }
  3833. };
  3834. // IOpenRowsetImpl
  3835. template <class SessionClass>
  3836. class IOpenRowsetImpl : public IOpenRowset
  3837. {
  3838. public:
  3839. template <class RowsetClass>
  3840. HRESULT CreateRowset(IUnknown* pUnkOuter,
  3841. DBID *pTableID, DBID *pIndexID,
  3842. REFIID riid,
  3843. ULONG cPropertySets, DBPROPSET rgPropertySets[],
  3844. IUnknown** ppRowset,
  3845. RowsetClass*& pRowsetObj)
  3846. {
  3847. HRESULT hr, hrProps = S_OK;
  3848. if (ppRowset != NULL)
  3849. *ppRowset = NULL;
  3850. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  3851. return DB_E_NOAGGREGATION;
  3852. CComPolyObject<RowsetClass>* pPolyObj;
  3853. if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  3854. return hr;
  3855. // Ref the created COM object and Auto release it on failure
  3856. CComPtr<IUnknown> spUnk;
  3857. hr = pPolyObj->QueryInterface(&spUnk);
  3858. if (FAILED(hr))
  3859. {
  3860. delete pPolyObj; // must hand delete as it is not ref'd
  3861. return hr;
  3862. }
  3863. // Get a pointer to the Rowset instance
  3864. pRowsetObj = &(pPolyObj->m_contained);
  3865. hr = pRowsetObj->FInit();
  3866. if (FAILED(hr))
  3867. return hr;
  3868. hr = pRowsetObj->SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3869. if (FAILED(hr))
  3870. return hr;
  3871. const GUID* ppGuid[1];
  3872. ppGuid[0] = &DBPROPSET_ROWSET;
  3873. // Call SetProperties. The true in the last parameter indicates
  3874. // the special behavior that takes place on rowset creation (i.e.
  3875. // it succeeds as long as any of the properties were not marked
  3876. // as DBPROPS_REQUIRED.
  3877. hrProps = pRowsetObj->SetProperties(0, cPropertySets, rgPropertySets,
  3878. 1, ppGuid, true);
  3879. if (FAILED(hrProps))
  3880. return hrProps;
  3881. pRowsetObj->SetSite(((SessionClass*)this)->GetUnknown());
  3882. hr = pRowsetObj->SetCommandText(pTableID, pIndexID);
  3883. if (FAILED(hr))
  3884. return hr;
  3885. DBROWCOUNT cRowsAffected;
  3886. if (FAILED(hr = pRowsetObj->Execute(NULL, &cRowsAffected)))
  3887. return hr;
  3888. if (InlineIsEqualGUID(riid, IID_NULL))
  3889. {
  3890. return E_NOINTERFACE;
  3891. }
  3892. else
  3893. {
  3894. if (ppRowset == NULL)
  3895. return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
  3896. hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
  3897. }
  3898. if (FAILED(hr))
  3899. {
  3900. *ppRowset = NULL;
  3901. return hr;
  3902. }
  3903. return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  3904. }
  3905. };
  3906. // IColumnsInfoImpl
  3907. template <class T>
  3908. class ATL_NO_VTABLE IColumnsInfoImpl :
  3909. public IColumnsInfo,
  3910. public CDBIDOps
  3911. {
  3912. public:
  3913. HRESULT CheckCommandText(IUnknown* pUnkThis)
  3914. {
  3915. HRESULT hr = E_FAIL;
  3916. CComPtr<ICommandText> spText;
  3917. if (SUCCEEDED(hr = pUnkThis->QueryInterface(IID_ICommandText, (void**)&spText)))
  3918. {
  3919. LPOLESTR szCommand;
  3920. hr = spText->GetCommandText(NULL, &szCommand);
  3921. if (SUCCEEDED(hr))
  3922. CoTaskMemFree(szCommand);
  3923. }
  3924. return hr;
  3925. }
  3926. OUT_OF_LINE HRESULT InternalGetColumnInfo(DBORDINAL *pcColumns, ATLCOLUMNINFO** ppInfo)
  3927. {
  3928. ATLASSERT(ppInfo != NULL);
  3929. T* pT = (T*) this;
  3930. if (pT->CheckCommandText(pT->GetUnknown()) == DB_E_NOCOMMAND)
  3931. return DB_E_NOCOMMAND;
  3932. *ppInfo = T::GetColumnInfo(pT, pcColumns);
  3933. return S_OK;
  3934. }
  3935. STDMETHOD(GetColumnInfo)(DBORDINAL *pcColumns,
  3936. DBCOLUMNINFO **prgInfo,
  3937. OLECHAR **ppStringsBuffer)
  3938. {
  3939. ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::GetColumnInfo\n");
  3940. if (pcColumns == NULL || prgInfo == NULL || ppStringsBuffer == NULL)
  3941. {
  3942. if (prgInfo != NULL)
  3943. *prgInfo = NULL;
  3944. if (ppStringsBuffer != NULL)
  3945. *ppStringsBuffer = NULL;
  3946. if (pcColumns != NULL)
  3947. *pcColumns = NULL;
  3948. return E_INVALIDARG;
  3949. }
  3950. // NULL out pointers in case of an error
  3951. *prgInfo = NULL;
  3952. *ppStringsBuffer = NULL;
  3953. *pcColumns = 0;
  3954. ATLCOLUMNINFO* pInfo;
  3955. HRESULT hr = InternalGetColumnInfo(pcColumns, &pInfo);
  3956. if (FAILED(hr))
  3957. return hr;
  3958. ATLASSERT(pInfo != NULL);
  3959. *prgInfo = (DBCOLUMNINFO*)CoTaskMemAlloc(*pcColumns * sizeof(DBCOLUMNINFO));
  3960. if (*prgInfo != NULL)
  3961. {
  3962. for (DBORDINAL iCol = 0, cwRequired = 0; iCol < *pcColumns; iCol++)
  3963. {
  3964. memcpy(&((*prgInfo)[iCol]), &pInfo[iCol], sizeof(DBCOLUMNINFO));
  3965. if (pInfo[iCol].pwszName)
  3966. {
  3967. cwRequired += wcslen(pInfo[iCol].pwszName) + 1;
  3968. }
  3969. }
  3970. *ppStringsBuffer = (OLECHAR*)CoTaskMemAlloc(cwRequired*sizeof(OLECHAR));
  3971. if (*ppStringsBuffer)
  3972. {
  3973. for (DBORDINAL iCol = 0, iOffset = 0; iCol < *pcColumns; iCol++)
  3974. {
  3975. if (pInfo[iCol].pwszName)
  3976. {
  3977. lstrcpyW(*ppStringsBuffer + iOffset, pInfo[iCol].pwszName);
  3978. iOffset += wcslen(*ppStringsBuffer + iOffset) + 1;
  3979. }
  3980. }
  3981. return S_OK;
  3982. }
  3983. else
  3984. {
  3985. ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate string buffer\n"));
  3986. CoTaskMemFree(*prgInfo);
  3987. *prgInfo = NULL;
  3988. *pcColumns = 0;
  3989. return E_OUTOFMEMORY;
  3990. }
  3991. }
  3992. else
  3993. {
  3994. ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ColumnInfo array\n"));
  3995. *prgInfo = NULL;
  3996. *pcColumns = 0;
  3997. return E_OUTOFMEMORY;
  3998. }
  3999. }
  4000. STDMETHOD(MapColumnIDs)(DBORDINAL cColumnIDs,
  4001. const DBID rgColumnIDs[],
  4002. DBORDINAL rgColumns[])
  4003. {
  4004. ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::MapColumnIDs\n");
  4005. USES_CONVERSION;
  4006. if ((cColumnIDs != 0 && rgColumnIDs == NULL) || rgColumns == NULL)
  4007. return E_INVALIDARG;
  4008. DBORDINAL cCols = 0;
  4009. DBORDINAL cColsInError = 0;
  4010. HRESULT hr = S_OK;
  4011. ATLCOLUMNINFO* pInfo;
  4012. for (DBORDINAL iColId = 0; iColId < cColumnIDs; iColId++)
  4013. {
  4014. hr = InternalGetColumnInfo(&cCols, &pInfo);
  4015. if (hr == DB_E_NOCOMMAND)
  4016. return hr;
  4017. ULONG iColMapCur = 0;
  4018. BOOL bDone = FALSE;
  4019. while(iColMapCur < cCols && !bDone)
  4020. {
  4021. hr = CompareDBIDs(&(pInfo[iColMapCur].columnid), &(rgColumnIDs[iColId]));
  4022. bDone = (hr == S_OK || FAILED(hr));
  4023. if (hr == S_OK)
  4024. rgColumns[iColId] = pInfo[iColMapCur].iOrdinal;
  4025. iColMapCur++;
  4026. }
  4027. if (!bDone || FAILED(hr))
  4028. {
  4029. rgColumns[iColId] = DB_INVALIDCOLUMN;
  4030. cColsInError++;
  4031. }
  4032. }
  4033. if (cColsInError > 0 && cColumnIDs == cColsInError)
  4034. return DB_E_ERRORSOCCURRED;
  4035. if (cColsInError > 0 && cColsInError < cColumnIDs)
  4036. return DB_S_ERRORSOCCURRED;
  4037. return S_OK;
  4038. }
  4039. };
  4040. //IConvertTypeImpl
  4041. template <class T>
  4042. class ATL_NO_VTABLE IConvertTypeImpl : public IConvertType, public CConvertHelper
  4043. {
  4044. public:
  4045. HRESULT InternalCanConvert(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags,
  4046. bool bIsCommand, bool bHasParamaters, IObjectWithSite* pSite)
  4047. {
  4048. // Check to see if conversion types are invalid. Note, this is just a
  4049. // quick test as it would be difficult to check each available type
  4050. // (as new DBTYPE values can be added).
  4051. if ((wFromType & 0x8000) || (wToType & 0x8000))
  4052. return E_INVALIDARG;
  4053. // Determine if new 2.x flags are valid
  4054. if((dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_COLUMN
  4055. && (dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_PARAMETER )
  4056. return DB_E_BADCONVERTFLAG;
  4057. #ifdef _LATER
  4058. // If the convert flags are for DBCONVERTFLAGS_FROMVARIANT, check to see
  4059. // that the type is a variant type
  4060. if (dwConvertFlags == DBCONVERTFLAGS_FROMVARIANT)
  4061. {
  4062. if (wFromType != DBTYPE_VARIANT)
  4063. return DB_E_BADTYPE;
  4064. }
  4065. #endif // _LATER
  4066. // Note, if the convert flag is either ISLONG or ISFIXEDLENGTH, then we should
  4067. // make sure we are not dealing with an OLE DB 1.x provider. However, since
  4068. // we default to 2.x providers, we don't check this. If you, change the
  4069. // DBPROP_PROVIDEROLEDBVER property in the DATASOURCEINFO group, you need to
  4070. // check the property value and return a DB_E_BADCONVERTFLAG if it is a 1.x
  4071. // provider.
  4072. // Do we have ISLONG on a fixed length data type?
  4073. DBTYPE dbtype = wFromType & ~(DBTYPE_BYREF|DBTYPE_VECTOR|DBTYPE_ARRAY|DBTYPE_RESERVED);
  4074. if ((dwConvertFlags & DBCONVERTFLAGS_ISLONG) &&
  4075. (dbtype != DBTYPE_WSTR && dbtype != DBTYPE_STR && dbtype != DBTYPE_BYTES && dbtype != DBTYPE_VARNUMERIC))
  4076. return DB_E_BADCONVERTFLAG;
  4077. if (dwConvertFlags == DBCONVERTFLAGS_PARAMETER)
  4078. {
  4079. // In the case where we are a rowset and ask for a parameter
  4080. // conversion, return DB_E_BADCONVERTFLAG
  4081. if (!bIsCommand)
  4082. return DB_E_BADCONVERTFLAG;
  4083. // In the case where we are a command and ask for a parameter
  4084. // conversion and ICommandWithParameters is not supported, return
  4085. // S_FALSE. We just can't convert them.
  4086. if (!bHasParamaters)
  4087. return S_FALSE;
  4088. }
  4089. // If we deal with a command and the user asks for a conversion on a rowset
  4090. // the DBPROP_ROWSETCONVERSIONSONCOMMAND must be suppored and set to TRUE.
  4091. if (bIsCommand && dwConvertFlags == DBCONVERTFLAGS_COLUMN)
  4092. {
  4093. CDBPropIDSet set(DBPROPSET_DATASOURCEINFO);
  4094. set.AddPropertyID(DBPROP_ROWSETCONVERSIONSONCOMMAND);
  4095. DBPROPSET* pPropSet = NULL;
  4096. ULONG ulPropSet = 0;
  4097. //HRESULT hr1 = S_OK;
  4098. // Get a pointer into the session
  4099. CComPtr<IGetDataSource> spDataSource = NULL;
  4100. CComPtr<IDBProperties> spProps = NULL;
  4101. // if any of these calls fail, we're either unable to retrieve the
  4102. // property or it is unsupported. Since the property is only on
  4103. // the data source object, we use the IObjectWithSite interface to
  4104. // get the session object and then the GetDataSource method to get
  4105. // the data source object itself.
  4106. if (FAILED(pSite->GetSite(IID_IGetDataSource, (void**)&spDataSource)))
  4107. return DB_E_BADCONVERTFLAG;
  4108. if (FAILED(spDataSource->GetDataSource(IID_IDBProperties,
  4109. (IUnknown**)&spProps)))
  4110. return DB_E_BADCONVERTFLAG;
  4111. if (FAILED(spProps->GetProperties(1, &set, &ulPropSet, &pPropSet)))
  4112. return DB_E_BADCONVERTFLAG;
  4113. if (pPropSet != NULL)
  4114. {
  4115. CComVariant var = pPropSet->rgProperties[0].vValue;
  4116. CoTaskMemFree(pPropSet->rgProperties);
  4117. CoTaskMemFree(pPropSet);
  4118. if (var.boolVal == VARIANT_FALSE)
  4119. return DB_E_BADCONVERTFLAG;
  4120. }
  4121. }
  4122. HRESULT hr = E_FAIL;
  4123. if (m_spConvert != NULL)
  4124. {
  4125. hr = m_spConvert->CanConvert(wFromType, wToType);
  4126. }
  4127. return hr;
  4128. }
  4129. STDMETHOD(CanConvert)(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags)
  4130. {
  4131. ATLTRACE2(atlTraceDBProvider, 0, "IConvertTypeImpl::CanConvert\n");
  4132. T* pT = (T*)this;
  4133. return pT->InternalCanConvert(wFromType, wToType, dwConvertFlags, pT->m_bIsCommand, pT->m_bHasParamaters, pT);
  4134. }
  4135. };
  4136. template <class T, class PropClass = T>
  4137. class ATL_NO_VTABLE ICommandPropertiesImpl :
  4138. public ICommandProperties,
  4139. public CUtlProps<PropClass>
  4140. {
  4141. public:
  4142. typedef PropClass _PropClass;
  4143. STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
  4144. const DBPROPIDSET rgPropertyIDSets[],
  4145. ULONG *pcPropertySets,
  4146. DBPROPSET **prgPropertySets)
  4147. {
  4148. ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::GetProperties\n");
  4149. HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  4150. const GUID* ppGuid[1];
  4151. ppGuid[0] = &DBPROPSET_ROWSET;
  4152. if(SUCCEEDED(hr))
  4153. hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
  4154. rgPropertyIDSets, pcPropertySets, prgPropertySets,
  4155. 1, ppGuid);
  4156. return hr;
  4157. }
  4158. STDMETHOD(SetProperties)(ULONG cPropertySets,
  4159. DBPROPSET rgPropertySets[])
  4160. {
  4161. ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::SetProperties\n");
  4162. HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
  4163. const GUID* ppGuid[1];
  4164. ppGuid[0] = &DBPROPSET_ROWSET;
  4165. if(SUCCEEDED(hr))
  4166. hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets,
  4167. rgPropertySets, 1, ppGuid);
  4168. return hr;
  4169. }
  4170. };
  4171. template <class T>
  4172. class CRunTimeFree
  4173. {
  4174. public:
  4175. static void Free(T* pData)
  4176. {
  4177. delete [] pData;
  4178. }
  4179. };
  4180. template <class T>
  4181. class CComFree
  4182. {
  4183. public:
  4184. static void Free(T* pData)
  4185. {
  4186. CoTaskMemFree(pData);
  4187. }
  4188. };
  4189. template <class T, class DeAllocator = CRunTimeFree < T > >
  4190. class CAutoMemRelease
  4191. {
  4192. public:
  4193. CAutoMemRelease()
  4194. {
  4195. m_pData = NULL;
  4196. }
  4197. CAutoMemRelease(T* pData)
  4198. {
  4199. m_pData = pData;
  4200. }
  4201. ~CAutoMemRelease()
  4202. {
  4203. Attach(NULL);
  4204. }
  4205. void Attach(T* pData)
  4206. {
  4207. DeAllocator::Free(m_pData);
  4208. m_pData = pData;
  4209. }
  4210. T* Detach()
  4211. {
  4212. T* pTemp = m_pData;
  4213. m_pData = NULL;
  4214. return pTemp;
  4215. }
  4216. T* m_pData;
  4217. };
  4218. template <class T>
  4219. class ATL_NO_VTABLE ICommandImpl : public ICommand
  4220. {
  4221. public:
  4222. ICommandImpl()
  4223. {
  4224. m_bIsExecuting = FALSE;
  4225. m_bCancelWhenExecuting = TRUE;
  4226. m_bCancel = FALSE;
  4227. }
  4228. HRESULT CancelExecution()
  4229. {
  4230. T* pT = (T*)this;
  4231. pT->Lock();
  4232. m_bCancel = TRUE;
  4233. pT->Unlock();
  4234. return S_OK;
  4235. }
  4236. STDMETHOD(Cancel)()
  4237. {
  4238. ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::Cancel\n");
  4239. HRESULT hr = S_OK;
  4240. T* pT = (T*)this;
  4241. if (m_bIsExecuting && m_bCancelWhenExecuting)
  4242. {
  4243. hr = pT->CancelExecution();
  4244. return hr;
  4245. }
  4246. if (m_bIsExecuting && !m_bCancelWhenExecuting)
  4247. hr = DB_E_CANTCANCEL;
  4248. return hr;
  4249. }
  4250. STDMETHOD(GetDBSession)(REFIID riid, IUnknown ** ppSession)
  4251. {
  4252. ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::GetDBSession\n");
  4253. T* pT = (T*)this;
  4254. ATLASSERT(pT->m_spUnkSite != NULL);
  4255. return pT->m_spUnkSite->QueryInterface(riid, (void**) ppSession);
  4256. }
  4257. template <class RowsetClass>
  4258. HRESULT CreateRowset(IUnknown* pUnkOuter, REFIID riid,
  4259. DBPARAMS * pParams, DBROWCOUNT * pcRowsAffected,
  4260. IUnknown** ppRowset,
  4261. RowsetClass*& pRowsetObj)
  4262. {
  4263. HRESULT hr;
  4264. USES_CONVERSION;
  4265. int iBind;
  4266. T* pT = (T*)this;
  4267. if (ppRowset != NULL)
  4268. *ppRowset = NULL;
  4269. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  4270. return DB_E_NOAGGREGATION;
  4271. CComPolyObject<RowsetClass>* pPolyObj;
  4272. if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  4273. return hr;
  4274. // Ref the created COM object and Auto release it on failure
  4275. CComPtr<IUnknown> spUnk;
  4276. hr = pPolyObj->QueryInterface(&spUnk);
  4277. if (FAILED(hr))
  4278. {
  4279. delete pPolyObj; // must hand delete as it is not ref'd
  4280. return hr;
  4281. }
  4282. // Get a pointer to the Rowset instance
  4283. pRowsetObj = &(pPolyObj->m_contained);
  4284. if (FAILED(hr = pRowsetObj->FInit(pT)))
  4285. return hr;
  4286. pRowsetObj->SetSite(pT->GetUnknown());
  4287. if (pT->m_strCommandText.Length() == 0)
  4288. {
  4289. ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::No command text specified.\n");
  4290. return DB_E_NOCOMMAND;
  4291. }
  4292. pRowsetObj->m_strCommandText = pT->m_strCommandText;
  4293. if (pRowsetObj->m_strCommandText == (BSTR)NULL)
  4294. return E_OUTOFMEMORY;
  4295. if (FAILED(hr = pRowsetObj->Execute(pParams, pcRowsAffected)))
  4296. return hr;
  4297. if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
  4298. {
  4299. if (ppRowset != NULL)
  4300. *ppRowset = NULL;
  4301. return hr;
  4302. }
  4303. hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
  4304. if (FAILED(hr))
  4305. return hr;
  4306. for (iBind = 0; iBind < pT->m_rgBindings.GetSize(); iBind++)
  4307. {
  4308. T::_BindType* pBind = NULL;
  4309. T::_BindType* pBindSrc = NULL;
  4310. ATLTRY(pBind = new T::_BindType);
  4311. if (pBind == NULL)
  4312. {
  4313. ATLTRACE2(atlTraceDBProvider, 0, "Failed to allocate memory for new Binding\n");
  4314. return E_OUTOFMEMORY;
  4315. }
  4316. // auto cleanup on failure
  4317. CAutoMemRelease<T::_BindType> amr(pBind);
  4318. pBindSrc = pT->m_rgBindings.GetValueAt(iBind);
  4319. if (pBindSrc == NULL)
  4320. {
  4321. ATLTRACE2(atlTraceDBProvider, 0, "The map appears to be corrupted, failing!!\n");
  4322. return E_FAIL;
  4323. }
  4324. if (!pRowsetObj->m_rgBindings.Add(pT->m_rgBindings.GetKeyAt(iBind), pBind))
  4325. {
  4326. ATLTRACE2(atlTraceDBProvider, 0, "Failed to add hAccessor to Map\n");
  4327. return E_OUTOFMEMORY;
  4328. }
  4329. if (pBindSrc->cBindings)
  4330. {
  4331. ATLTRY(pBind->pBindings = new DBBINDING[pBindSrc->cBindings])
  4332. if (pBind->pBindings == NULL)
  4333. {
  4334. ATLTRACE2(atlTraceDBProvider, 0, "Failed to Allocate dbbinding Array\n");
  4335. // We added it, must now remove on failure
  4336. pRowsetObj->m_rgBindings.Remove(pT->m_rgBindings.GetKeyAt(iBind));
  4337. return E_OUTOFMEMORY;
  4338. }
  4339. }
  4340. else
  4341. {
  4342. pBind->pBindings = NULL; // NULL Accessor
  4343. }
  4344. pBind->dwAccessorFlags = pBindSrc->dwAccessorFlags;
  4345. pBind->cBindings = pBindSrc->cBindings;
  4346. pBind->dwRef = 1;
  4347. memcpy (pBind->pBindings, pBindSrc->pBindings, (pBindSrc->cBindings)*sizeof(DBBINDING));
  4348. pBind = amr.Detach();
  4349. }
  4350. return S_OK;
  4351. }
  4352. unsigned m_bIsExecuting:1;
  4353. unsigned m_bCancelWhenExecuting:1;
  4354. unsigned m_bCancel:1;
  4355. };
  4356. template <class T>
  4357. class ATL_NO_VTABLE ICommandTextImpl : public ICommandImpl<T>
  4358. {
  4359. public:
  4360. STDMETHOD(GetCommandText)(GUID * /*pguidDialect*/,LPOLESTR * ppwszCommand)
  4361. {
  4362. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText\n");
  4363. UINT cchCommandText;
  4364. HRESULT hr = E_FAIL;
  4365. if (ppwszCommand == NULL)
  4366. {
  4367. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
  4368. return E_INVALIDARG;
  4369. }
  4370. if (m_strCommandText.m_str == NULL)
  4371. {
  4372. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
  4373. return DB_E_NOCOMMAND;
  4374. }
  4375. cchCommandText = sizeof(OLECHAR) * (m_strCommandText.Length() + 1);
  4376. *ppwszCommand = (OLECHAR*)CoTaskMemAlloc(cchCommandText);
  4377. if (*ppwszCommand != NULL)
  4378. {
  4379. memcpy(*ppwszCommand, m_strCommandText.m_str, cchCommandText);
  4380. *(*ppwszCommand + m_strCommandText.Length()) = (OLECHAR)NULL;
  4381. return S_OK;
  4382. }
  4383. *ppwszCommand = NULL;
  4384. return hr;
  4385. }
  4386. STDMETHOD(SetCommandText)(REFGUID /*rguidDialect*/,LPCOLESTR pwszCommand)
  4387. {
  4388. T* pT = (T*)this;
  4389. ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::SetCommandText\n");
  4390. pT->Lock();
  4391. m_strCommandText = pwszCommand;
  4392. pT->Unlock();
  4393. return S_OK;
  4394. }
  4395. CComBSTR m_strCommandText;
  4396. };
  4397. // ISessionPropertiesImpl
  4398. template <class T, class PropClass = T>
  4399. class ATL_NO_VTABLE ISessionPropertiesImpl :
  4400. public ISessionProperties,
  4401. public CUtlProps<PropClass>
  4402. {
  4403. public:
  4404. typedef PropClass _PropClass;
  4405. STDMETHOD(GetProperties)(ULONG cPropertyIDSets,
  4406. const DBPROPIDSET rgPropertyIDSets[],
  4407. ULONG *pcPropertySets,
  4408. DBPROPSET **prgPropertySets)
  4409. {
  4410. ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::GetProperties\n");
  4411. HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  4412. const GUID* ppGuid[1];
  4413. ppGuid[0] = &DBPROPSET_SESSION;
  4414. if(SUCCEEDED(hr))
  4415. hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
  4416. rgPropertyIDSets, pcPropertySets, prgPropertySets,
  4417. 1, ppGuid);
  4418. return hr;
  4419. }
  4420. STDMETHOD(SetProperties)(ULONG cPropertySets,
  4421. DBPROPSET rgPropertySets[])
  4422. {
  4423. ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::SetProperties");
  4424. HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
  4425. const GUID* ppGuid[1];
  4426. ppGuid[0] = &DBPROPSET_SESSION;
  4427. if(SUCCEEDED(hr))
  4428. hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets, rgPropertySets,
  4429. 1, ppGuid);
  4430. return hr;
  4431. }
  4432. };
  4433. // Implementation Class
  4434. template <class BindType>
  4435. class ATL_NO_VTABLE IAccessorImplBase : public IAccessor
  4436. {
  4437. public:
  4438. STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
  4439. DBCOUNTITEM cBindings,
  4440. const DBBINDING rgBindings[],
  4441. DBLENGTH /*cbRowSize*/,
  4442. HACCESSOR *phAccessor,
  4443. DBBINDSTATUS rgStatus[])
  4444. {
  4445. if (!(dwAccessorFlags & DBACCESSOR_PARAMETERDATA) && !(dwAccessorFlags & DBACCESSOR_ROWDATA))
  4446. return DB_E_BADACCESSORFLAGS;
  4447. if (dwAccessorFlags == DBACCESSOR_INVALID)
  4448. return DB_E_BADACCESSORFLAGS;
  4449. if (dwAccessorFlags > 0x000F)
  4450. return DB_E_BADACCESSORFLAGS;
  4451. BindType *pBind = NULL;
  4452. ATLTRY(pBind = new BindType)
  4453. if (pBind == NULL)
  4454. {
  4455. ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ATL Binding struct\n"));
  4456. return E_OUTOFMEMORY;
  4457. }
  4458. if (cBindings)
  4459. {
  4460. ATLTRY(pBind->pBindings = new DBBINDING[cBindings])
  4461. if (pBind->pBindings == NULL)
  4462. {
  4463. delete pBind;
  4464. return E_OUTOFMEMORY;
  4465. }
  4466. }
  4467. else
  4468. pBind->pBindings = NULL; // NULL Accessor
  4469. pBind->dwAccessorFlags = dwAccessorFlags;
  4470. pBind->cBindings = cBindings;
  4471. pBind->dwRef = 1;
  4472. memcpy (pBind->pBindings, rgBindings, cBindings*sizeof(DBBINDING));
  4473. DBBINDSTATUS status = DBBINDSTATUS_OK;
  4474. memset (rgStatus, status, sizeof(DBBINDSTATUS)*cBindings);
  4475. *phAccessor = (ULONG_PTR)pBind;
  4476. return S_OK;
  4477. }
  4478. BOOL HasFlag(DBTYPE dbToCheck, DBTYPE dbCombo)
  4479. {
  4480. return ( (dbToCheck & dbCombo) == dbCombo );
  4481. }
  4482. HRESULT ValidateBindings(DBCOUNTITEM cBindings, const DBBINDING rgBindings[],
  4483. DBBINDSTATUS rgStatus[], bool bHasBookmarks)
  4484. {
  4485. HRESULT hr = S_OK;;
  4486. for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
  4487. {
  4488. const DBBINDING& rBindCur = rgBindings[iBinding];
  4489. if (rBindCur.iOrdinal == 0)
  4490. {
  4491. if (!m_bIsCommand && !bHasBookmarks)
  4492. {
  4493. hr = DB_E_ERRORSOCCURRED;
  4494. rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
  4495. continue;
  4496. }
  4497. }
  4498. if (rBindCur.dwPart == 0) // nothing to bind to
  4499. {
  4500. hr = DB_E_ERRORSOCCURRED;
  4501. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4502. continue;
  4503. }
  4504. if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_ARRAY)))
  4505. {
  4506. hr = DB_E_ERRORSOCCURRED;
  4507. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4508. continue;
  4509. }
  4510. if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_VECTOR)))
  4511. {
  4512. hr = DB_E_ERRORSOCCURRED;
  4513. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4514. continue;
  4515. }
  4516. if (HasFlag(rBindCur.wType, (DBTYPE_VECTOR | DBTYPE_ARRAY)))
  4517. {
  4518. hr = DB_E_ERRORSOCCURRED;
  4519. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4520. continue;
  4521. }
  4522. if (rBindCur.wType == DBTYPE_NULL || rBindCur.wType == DBTYPE_EMPTY)
  4523. {
  4524. hr = DB_E_ERRORSOCCURRED;
  4525. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4526. continue;
  4527. }
  4528. if (HasFlag(rBindCur.wType, DBTYPE_RESERVED))
  4529. {
  4530. hr = DB_E_ERRORSOCCURRED;
  4531. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4532. continue;
  4533. }
  4534. // Search for DBTYPE_BYREF | DBTYPE_EMPTY
  4535. if ((rBindCur.wType & 0xBFFF) == 0)
  4536. {
  4537. hr = DB_E_ERRORSOCCURRED;
  4538. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4539. continue;
  4540. }
  4541. if ((rBindCur.wType & 0xBFFE) == 0)
  4542. {
  4543. hr = DB_E_ERRORSOCCURRED;
  4544. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4545. continue;
  4546. }
  4547. if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED)
  4548. {
  4549. BOOL bIsPointerType = HasFlag(rBindCur.wType, DBTYPE_BYREF) ||
  4550. HasFlag(rBindCur.wType, DBTYPE_VECTOR) ||
  4551. HasFlag(rBindCur.wType, DBTYPE_ARRAY) ||
  4552. HasFlag(~(DBTYPE_BYREF) & rBindCur.wType, DBTYPE_BSTR);
  4553. if (!bIsPointerType)
  4554. {
  4555. hr = DB_E_ERRORSOCCURRED;
  4556. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4557. continue;
  4558. }
  4559. }
  4560. }
  4561. return hr;
  4562. }
  4563. unsigned m_bIsCommand:1;
  4564. unsigned m_bHasParamaters:1;
  4565. unsigned m_bIsChangeable:1;
  4566. };
  4567. // IAccessorImpl
  4568. template <class T, class BindType = ATLBINDINGS, class BindingVector = CSimpleMap < INT_PTR, BindType* > >
  4569. class ATL_NO_VTABLE IAccessorImpl : public IAccessorImplBase<BindType>
  4570. {
  4571. public:
  4572. typedef BindType _BindType;
  4573. typedef BindingVector _BindingVector;
  4574. IAccessorImpl()
  4575. {
  4576. m_bIsCommand = FALSE;
  4577. m_bHasParamaters = FALSE;
  4578. m_bIsChangeable = FALSE;
  4579. }
  4580. OUT_OF_LINE HRESULT InternalFinalConstruct(IUnknown* pUnkThis)
  4581. {
  4582. CComQIPtr<ICommand> spCommand = pUnkThis;
  4583. if (spCommand != NULL)
  4584. {
  4585. m_bIsCommand = TRUE;
  4586. CComQIPtr<ICommandWithParameters> spCommandParams = pUnkThis;
  4587. m_bHasParamaters = spCommandParams != NULL;
  4588. }
  4589. else // its a Rowset
  4590. {
  4591. CComQIPtr<IRowsetChange> spRSChange = pUnkThis;
  4592. m_bIsChangeable = spRSChange != NULL;
  4593. }
  4594. return S_OK;
  4595. }
  4596. HRESULT FinalConstruct()
  4597. {
  4598. T* pT = (T*)this;
  4599. return InternalFinalConstruct(pT->GetUnknown());
  4600. }
  4601. void FinalRelease()
  4602. {
  4603. #ifdef _DEBUG
  4604. if (m_rgBindings.GetSize())
  4605. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::~IAccessorImpl Bindings still in vector, removing\n");
  4606. #endif //_DEBUG
  4607. while (m_rgBindings.GetSize())
  4608. ReleaseAccessor((HACCESSOR)m_rgBindings.GetKeyAt(0), NULL);
  4609. }
  4610. STDMETHOD(AddRefAccessor)(HACCESSOR hAccessor,
  4611. DBREFCOUNT *pcRefCount)
  4612. {
  4613. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::AddRefAccessor\n");
  4614. if (hAccessor == NULL)
  4615. {
  4616. ATLTRACE2(atlTraceDBProvider, 0, _T("AddRefAccessor : Bad hAccessor\n"));
  4617. return E_INVALIDARG;
  4618. }
  4619. if (pcRefCount == NULL)
  4620. pcRefCount = (ULONG*)_alloca(sizeof(ULONG));
  4621. BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  4622. *pcRefCount = T::_ThreadModel::Increment((LONG*)&pBind->dwRef);
  4623. return S_OK;
  4624. }
  4625. OUT_OF_LINE ATLCOLUMNINFO* ValidateHelper(DBORDINAL* pcCols, CComPtr<IDataConvert> & rspConvert)
  4626. {
  4627. T* pT = (T*)this;
  4628. rspConvert = pT->m_spConvert;
  4629. return pT->GetColumnInfo(pT, pcCols);
  4630. }
  4631. OUT_OF_LINE HRESULT ValidateBindingsFromMetaData(DBCOUNTITEM cBindings, const DBBINDING rgBindings[],
  4632. DBBINDSTATUS rgStatus[], bool bHasBookmarks)
  4633. {
  4634. HRESULT hr = S_OK;
  4635. DBORDINAL cCols;
  4636. CComPtr<IDataConvert> spConvert;
  4637. ATLCOLUMNINFO* pColInfo = ValidateHelper(&cCols, spConvert);
  4638. ATLASSERT(pColInfo != NULL);
  4639. for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
  4640. {
  4641. const DBBINDING& rBindCur = rgBindings[iBinding];
  4642. DBORDINAL iOrdAdjusted;
  4643. if (bHasBookmarks)
  4644. iOrdAdjusted = rBindCur.iOrdinal; // Bookmarks start with ordinal 0
  4645. else
  4646. iOrdAdjusted = rBindCur.iOrdinal - 1; // Non-bookmarks start w/ ordinal 1
  4647. if (rBindCur.iOrdinal > cCols)
  4648. {
  4649. hr = DB_E_ERRORSOCCURRED;
  4650. rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
  4651. continue;
  4652. }
  4653. // If a binding specifies provider owned memory, and specifies type
  4654. // X | BYREF, and the provider's copy is not X or X | BYREF, return
  4655. // DBBINDSTATUS_BADBINDINFO
  4656. if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED)
  4657. {
  4658. if ((rBindCur.wType & DBTYPE_BYREF) != 0)
  4659. {
  4660. DBTYPE dbConsumerType = rBindCur.wType & 0xBFFF;
  4661. DBTYPE dbProviderType = pColInfo[iOrdAdjusted].wType & 0xBFFF;
  4662. if (dbConsumerType != dbProviderType)
  4663. {
  4664. hr = DB_E_ERRORSOCCURRED;
  4665. rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4666. continue;
  4667. }
  4668. }
  4669. }
  4670. ATLASSERT(spConvert != NULL);
  4671. HRESULT hrConvert = spConvert->CanConvert(pColInfo[iOrdAdjusted].wType, rBindCur.wType);
  4672. if (FAILED(hrConvert) || hrConvert == S_FALSE)
  4673. {
  4674. hr = DB_E_ERRORSOCCURRED;
  4675. rgStatus[iBinding] = DBBINDSTATUS_UNSUPPORTEDCONVERSION;
  4676. continue;
  4677. }
  4678. }
  4679. return hr;
  4680. }
  4681. STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
  4682. DBCOUNTITEM cBindings,
  4683. const DBBINDING rgBindings[],
  4684. DBLENGTH cbRowSize,
  4685. HACCESSOR *phAccessor,
  4686. DBBINDSTATUS rgStatus[])
  4687. {
  4688. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor\n");
  4689. T* pT = (T*)this;
  4690. T::ObjectLock cab(pT);
  4691. if (!phAccessor)
  4692. {
  4693. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Inavlid NULL Parameter for HACCESSOR*\n");
  4694. return E_INVALIDARG;
  4695. }
  4696. *phAccessor = NULL;
  4697. if (cBindings != 0 && rgBindings == NULL)
  4698. {
  4699. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Bad Binding array\n");
  4700. return E_INVALIDARG;
  4701. }
  4702. if (dwAccessorFlags & DBACCESSOR_PASSBYREF)
  4703. {
  4704. CComVariant varByRef;
  4705. HRESULT hr = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BYREFACCESSORS, &varByRef);
  4706. if (FAILED(hr) || varByRef.boolVal == VARIANT_FALSE)
  4707. return DB_E_BYREFACCESSORNOTSUPPORTED;
  4708. }
  4709. if (!m_bHasParamaters)
  4710. {
  4711. if (dwAccessorFlags & DBACCESSOR_PARAMETERDATA)
  4712. return DB_E_BADACCESSORFLAGS;
  4713. }
  4714. if (m_bIsCommand || !m_bIsChangeable)
  4715. {
  4716. if (cBindings == 0) // No NULL Accessors on the command
  4717. return DB_E_NULLACCESSORNOTSUPPORTED;
  4718. }
  4719. if (rgStatus == NULL && cBindings) // Create a fake status array
  4720. rgStatus = (DBBINDSTATUS*)_alloca(cBindings*sizeof(DBBINDSTATUS));
  4721. // Validate the Binding passed
  4722. HRESULT hr;
  4723. bool bHasBookmarks = false;
  4724. CComVariant varBookmarks;
  4725. HRESULT hrLocal = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BOOKMARKS, &varBookmarks);
  4726. bHasBookmarks = (hrLocal == S_OK && varBookmarks.boolVal == VARIANT_TRUE);
  4727. hr = ValidateBindings(cBindings, rgBindings, rgStatus, bHasBookmarks);
  4728. if (FAILED(hr))
  4729. return hr;
  4730. if (!m_bIsCommand)
  4731. {
  4732. hr = ValidateBindingsFromMetaData(cBindings, rgBindings, rgStatus,
  4733. bHasBookmarks);
  4734. if (FAILED(hr))
  4735. return hr;
  4736. }
  4737. hr = IAccessorImplBase<BindType>::CreateAccessor(dwAccessorFlags, cBindings,
  4738. rgBindings, cbRowSize, phAccessor,rgStatus);
  4739. if (SUCCEEDED(hr))
  4740. {
  4741. ATLASSERT(*phAccessor != NULL);
  4742. BindType* pBind = (BindType*)*phAccessor;
  4743. hr = m_rgBindings.Add((HACCESSOR)pBind, pBind) ? S_OK : E_OUTOFMEMORY;
  4744. }
  4745. return hr;
  4746. }
  4747. STDMETHOD(GetBindings)(HACCESSOR hAccessor,
  4748. DBACCESSORFLAGS *pdwAccessorFlags,
  4749. DBCOUNTITEM *pcBindings,
  4750. DBBINDING **prgBindings)
  4751. {
  4752. ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::GetBindings");
  4753. // Zero output parameters in case of failure
  4754. if (pdwAccessorFlags != NULL)
  4755. *pdwAccessorFlags = NULL;
  4756. if (pcBindings != NULL)
  4757. *pcBindings = NULL;
  4758. if (prgBindings != NULL)
  4759. *prgBindings = NULL;
  4760. // Check if any of the out params are NULL pointers
  4761. if ((pdwAccessorFlags && pcBindings && prgBindings) == NULL)
  4762. return E_INVALIDARG;
  4763. BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  4764. HRESULT hr = DB_E_BADACCESSORHANDLE;
  4765. if (pBind != NULL)
  4766. {
  4767. *pdwAccessorFlags = pBind->dwAccessorFlags;
  4768. *pcBindings = pBind->cBindings;
  4769. *prgBindings = (DBBINDING*)CoTaskMemAlloc(*pcBindings * sizeof(DBBINDING));
  4770. if (*prgBindings == NULL)
  4771. return E_OUTOFMEMORY;
  4772. memcpy(*prgBindings, pBind->pBindings, sizeof(DBBINDING) * (*pcBindings));
  4773. hr = S_OK;
  4774. }
  4775. return hr;
  4776. }
  4777. STDMETHOD(ReleaseAccessor)(HACCESSOR hAccessor,
  4778. DBREFCOUNT *pcRefCount)
  4779. {
  4780. ATLTRACE2(atlTraceDBProvider, 0, _T("IAccessorImpl::ReleaseAccessor\n"));
  4781. BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  4782. if (pBind == NULL)
  4783. return DB_E_BADACCESSORHANDLE;
  4784. if (pcRefCount == NULL)
  4785. pcRefCount = (DBREFCOUNT*)_alloca(sizeof(DBREFCOUNT));
  4786. *pcRefCount = T::_ThreadModel::Decrement((LONG*)&pBind->dwRef);
  4787. if (!(*pcRefCount))
  4788. {
  4789. delete [] pBind->pBindings;
  4790. delete pBind;
  4791. return m_rgBindings.Remove((int)hAccessor) ? S_OK : DB_E_BADACCESSORHANDLE;
  4792. }
  4793. return S_OK;
  4794. }
  4795. BindingVector m_rgBindings;
  4796. };
  4797. #define BEGIN_PROVIDER_COLUMN_MAP(theClass) \
  4798. typedef theClass _Class; \
  4799. template <class T> \
  4800. static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols) \
  4801. { \
  4802. pv; \
  4803. static ATLCOLUMNINFO _rgColumns [] = \
  4804. {
  4805. #define SIZEOF_MEMBER(memberOf, member) \
  4806. sizeof(((memberOf*)0)->member)
  4807. #define EXPANDGUID(guid) \
  4808. { guid.Data1, guid.Data2, guid.Data3, \
  4809. { guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] } }
  4810. #define PROVIDER_COLUMN_ENTRY_GN(name, ordinal, flags, colSize, dbtype, precision, scale, guid) \
  4811. { (LPOLESTR)name, (ITypeInfo*)NULL, (ULONG)ordinal, (DBCOLUMNFLAGS)flags, (ULONG)colSize, (DBTYPE)dbtype, (BYTE)precision, (BYTE)scale, { EXPANDGUID(guid), (DWORD)0, (LPOLESTR) name}, 0},
  4812. #define PROVIDER_COLUMN_ENTRY(name, ordinal, member) \
  4813. { \
  4814. (LPOLESTR)OLESTR(name), \
  4815. (ITypeInfo*)NULL, \
  4816. (ULONG)ordinal, \
  4817. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4818. (ULONG)sizeof(((_Class*)0)->member), \
  4819. _GetOleDBType(((_Class*)0)->member), \
  4820. (BYTE)0, \
  4821. (BYTE)0, \
  4822. { \
  4823. EXPANDGUID(GUID_NULL), \
  4824. (DWORD)2, \
  4825. (LPOLESTR) name \
  4826. }, \
  4827. offsetof(_Class, member) \
  4828. },
  4829. #define PROVIDER_COLUMN_ENTRY_LENGTH(name, ordinal, size, member) \
  4830. { \
  4831. (LPOLESTR)OLESTR(name), \
  4832. (ITypeInfo*)NULL, \
  4833. (ULONG)ordinal, \
  4834. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4835. (ULONG)size, \
  4836. _GetOleDBType(((_Class*)0)->member), \
  4837. (BYTE)0, \
  4838. (BYTE)0, \
  4839. { \
  4840. EXPANDGUID(GUID_NULL), \
  4841. (DWORD)2, \
  4842. (LPOLESTR) name \
  4843. }, \
  4844. offsetof(_Class, member) \
  4845. },
  4846. #define PROVIDER_COLUMN_ENTRY_TYPE_LENGTH(name, ordinal, type, size, member) \
  4847. { \
  4848. (LPOLESTR)OLESTR(name), \
  4849. (ITypeInfo*)NULL, \
  4850. (ULONG)ordinal, \
  4851. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4852. (ULONG)size, \
  4853. (DBTYPE)type, \
  4854. (BYTE)0, \
  4855. (BYTE)0, \
  4856. { \
  4857. EXPANDGUID(GUID_NULL), \
  4858. (DWORD)2, \
  4859. (LPOLESTR) name \
  4860. }, \
  4861. offsetof(_Class, member) \
  4862. },
  4863. #define PROVIDER_COLUMN_ENTRY_FIXED(name, ordinal, dbtype, member) \
  4864. { \
  4865. (LPOLESTR)OLESTR(name), \
  4866. (ITypeInfo*)NULL, \
  4867. (ULONG)ordinal, \
  4868. DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  4869. (ULONG)sizeof(((_Class*)0)->member), \
  4870. (DBTYPE)dbtype, \
  4871. (BYTE)0, \
  4872. (BYTE)0, \
  4873. { \
  4874. EXPANDGUID(GUID_NULL), \
  4875. (DWORD)2, \
  4876. (LPOLESTR) name \
  4877. }, \
  4878. offsetof(_Class, member) \
  4879. },
  4880. #define PROVIDER_COLUMN_ENTRY_STR(name, ordinal, member) \
  4881. { \
  4882. (LPOLESTR)OLESTR(name), \
  4883. (ITypeInfo*)NULL, \
  4884. (ULONG)ordinal, \
  4885. 0, \
  4886. (ULONG)sizeof(((_Class*)0)->member), \
  4887. DBTYPE_STR, \
  4888. (BYTE)0xFF, \
  4889. (BYTE)0xFF, \
  4890. { \
  4891. EXPANDGUID(GUID_NULL), \
  4892. (DWORD)2, \
  4893. (LPOLESTR) name \
  4894. }, \
  4895. offsetof(_Class, member) \
  4896. },
  4897. #define PROVIDER_COLUMN_ENTRY_WSTR(name, ordinal, member) \
  4898. { \
  4899. (LPOLESTR)OLESTR(name), \
  4900. (ITypeInfo*)NULL, \
  4901. (ULONG)ordinal, \
  4902. 0, \
  4903. (ULONG)sizeof(((_Class*)0)->member), \
  4904. DBTYPE_WSTR, \
  4905. (BYTE)0xFF, \
  4906. (BYTE)0xFF, \
  4907. { \
  4908. EXPANDGUID(GUID_NULL), \
  4909. (DWORD)2, \
  4910. (LPOLESTR) name \
  4911. }, \
  4912. offsetof(_Class, member) \
  4913. },
  4914. #define END_PROVIDER_COLUMN_MAP() \
  4915. }; *pcCols = sizeof(_rgColumns)/sizeof(ATLCOLUMNINFO); return _rgColumns;}
  4916. // Implementation Class
  4917. class CSimpleRow
  4918. {
  4919. public:
  4920. typedef DBROWCOUNT KeyType;
  4921. CSimpleRow(DBROWCOUNT iRowsetCur)
  4922. {
  4923. m_dwRef = 0;
  4924. m_iRowset = iRowsetCur;
  4925. }
  4926. ~CSimpleRow()
  4927. {
  4928. }
  4929. DWORD AddRefRow() { return CComObjectThreadModel::Increment((LPLONG)&m_dwRef); }
  4930. DWORD ReleaseRow() { return CComObjectThreadModel::Decrement((LPLONG)&m_dwRef); }
  4931. HRESULT Compare(CSimpleRow* pRow)
  4932. {
  4933. ATLASSERT(pRow != NULL);
  4934. return (m_iRowset == pRow->m_iRowset) ? S_OK : S_FALSE;
  4935. }
  4936. KeyType m_iRowset;
  4937. DWORD m_dwRef;
  4938. };
  4939. // IRowsetImpl
  4940. template <class T, class RowsetInterface,
  4941. class RowClass = CSimpleRow,
  4942. class MapClass = CSimpleMap < RowClass::KeyType, RowClass* > >
  4943. class ATL_NO_VTABLE IRowsetImpl : public RowsetInterface
  4944. {
  4945. public:
  4946. typedef RowClass _HRowClass;
  4947. IRowsetImpl()
  4948. {
  4949. m_iRowset = 0;
  4950. m_bCanScrollBack = false;
  4951. m_bCanFetchBack = false;
  4952. m_bReset = true;
  4953. }
  4954. ~IRowsetImpl()
  4955. {
  4956. for (int i = 0; i < m_rgRowHandles.GetSize(); i++)
  4957. delete (m_rgRowHandles.GetValueAt(i));
  4958. }
  4959. HRESULT RefRows(DBCOUNTITEM cRows, const HROW rghRows[], ULONG rgRefCounts[],
  4960. DBROWSTATUS rgRowStatus[], BOOL bAdd)
  4961. {
  4962. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
  4963. if (cRows == 0)
  4964. return S_OK;
  4965. if (rghRows == NULL)
  4966. return E_INVALIDARG;
  4967. T::ObjectLock cab((T*)this);
  4968. BOOL bSuccess1 = FALSE;
  4969. BOOL bFailed1 = FALSE;
  4970. DBROWSTATUS rs;
  4971. DWORD dwRef;
  4972. for (ULONG iRow = 0; iRow < cRows; iRow++)
  4973. {
  4974. HROW hRowCur = rghRows[iRow];
  4975. RowClass* pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRowCur);
  4976. if (pRow == NULL)
  4977. {
  4978. ATLTRACE2(atlTraceDBProvider, 0, "Could not find HANDLE %x in list\n");
  4979. rs = DBROWSTATUS_E_INVALID;
  4980. dwRef = 0;
  4981. bFailed1 = TRUE;
  4982. }
  4983. else
  4984. {
  4985. if (bAdd)
  4986. dwRef = pRow->AddRefRow();
  4987. else
  4988. {
  4989. dwRef = pRow->ReleaseRow();
  4990. if (dwRef == 0)
  4991. {
  4992. delete pRow;
  4993. m_rgRowHandles.Remove((RowClass::KeyType)hRowCur);
  4994. }
  4995. }
  4996. bSuccess1 = TRUE;
  4997. rs = DBROWSTATUS_S_OK;
  4998. }
  4999. if (rgRefCounts)
  5000. rgRefCounts[iRow] = dwRef;
  5001. if (rgRowStatus != NULL)
  5002. rgRowStatus[iRow] = rs;
  5003. }
  5004. if (!bSuccess1 && !bFailed1)
  5005. {
  5006. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RefRows Unexpected state\n");
  5007. return E_FAIL;
  5008. }
  5009. HRESULT hr = S_OK;
  5010. if (bSuccess1 && bFailed1)
  5011. hr = DB_S_ERRORSOCCURRED;
  5012. if (!bSuccess1 && bFailed1)
  5013. hr = DB_E_ERRORSOCCURRED;
  5014. return hr;
  5015. }
  5016. STDMETHOD(AddRefRows)(DBCOUNTITEM cRows,
  5017. const HROW rghRows[],
  5018. DBREFCOUNT rgRefCounts[],
  5019. DBROWSTATUS rgRowStatus[])
  5020. {
  5021. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
  5022. if (cRows == 0)
  5023. return S_OK;
  5024. return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, TRUE);
  5025. }
  5026. virtual DBSTATUS GetDBStatus(RowClass* , ATLCOLUMNINFO*)
  5027. {
  5028. return DBSTATUS_S_OK;
  5029. }
  5030. OUT_OF_LINE HRESULT GetDataHelper(HACCESSOR hAccessor,
  5031. ATLCOLUMNINFO*& rpInfo,
  5032. void** ppBinding,
  5033. void*& rpSrcData,
  5034. DBORDINAL& rcCols,
  5035. CComPtr<IDataConvert>& rspConvert,
  5036. RowClass* pRow)
  5037. {
  5038. ATLASSERT(ppBinding != NULL);
  5039. T* pT = (T*) this;
  5040. *ppBinding = (void*)pT->m_rgBindings.Lookup((int)hAccessor);
  5041. if (*ppBinding == NULL)
  5042. return DB_E_BADACCESSORHANDLE;
  5043. rpSrcData = (void*)&(pT->m_rgRowData[(int)(INT_PTR)(pRow->m_iRowset)]);
  5044. rpInfo = T::GetColumnInfo((T*)this, &rcCols);
  5045. rspConvert = pT->m_spConvert;
  5046. return S_OK;
  5047. }
  5048. STDMETHOD(GetData)(HROW hRow,
  5049. HACCESSOR hAccessor,
  5050. void *pDstData)
  5051. {
  5052. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetData\n");
  5053. if (pDstData == NULL)
  5054. return E_INVALIDARG;
  5055. HRESULT hr = S_OK;
  5056. RowClass* pRow = (RowClass*)hRow;
  5057. if (hRow == NULL || (pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRow)) == NULL)
  5058. return DB_E_BADROWHANDLE;
  5059. T::_BindType* pBinding;
  5060. void* pSrcData;
  5061. DBORDINAL cCols;
  5062. ATLCOLUMNINFO* pColInfo;
  5063. CComPtr<IDataConvert> spConvert;
  5064. hr = GetDataHelper(hAccessor, pColInfo, (void**)&pBinding, pSrcData, cCols, spConvert, pRow);
  5065. if (FAILED(hr))
  5066. return hr;
  5067. for (ULONG iBind =0; iBind < pBinding->cBindings; iBind++)
  5068. {
  5069. DBBINDING* pBindCur = &(pBinding->pBindings[iBind]);
  5070. for (ULONG iColInfo = 0;
  5071. iColInfo < cCols && pBindCur->iOrdinal != pColInfo[iColInfo].iOrdinal;
  5072. iColInfo++);
  5073. if (iColInfo == cCols)
  5074. return DB_E_BADORDINAL;
  5075. ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
  5076. // Ordinal found at iColInfo
  5077. BOOL bProvOwn = pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED;
  5078. bProvOwn;
  5079. DBSTATUS dbStat = GetDBStatus(pRow, pColCur);
  5080. // If the provider's field is NULL, we can optimize this situation,
  5081. // set the fields to 0 and continue.
  5082. if (dbStat == DBSTATUS_S_ISNULL)
  5083. {
  5084. if (pBindCur->dwPart & DBPART_STATUS)
  5085. *((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat;
  5086. if (pBindCur->dwPart & DBPART_LENGTH)
  5087. *((ULONG*)((BYTE*)(pDstData) + pBindCur->obLength)) = 0;
  5088. if (pBindCur->dwPart & DBPART_VALUE)
  5089. *((BYTE*)(pDstData) + pBindCur->obValue) = NULL;
  5090. continue;
  5091. }
  5092. ULONG cbDst = pBindCur->cbMaxLen;
  5093. ULONG cbCol;
  5094. BYTE* pSrcTemp;
  5095. if (bProvOwn && pColCur->wType == pBindCur->wType)
  5096. {
  5097. pSrcTemp = ((BYTE*)(pSrcData) + pColCur->cbOffset);
  5098. }
  5099. else
  5100. {
  5101. BYTE* pDstTemp = (BYTE*)pDstData + pBindCur->obValue;
  5102. switch (pColCur->wType)
  5103. {
  5104. case DBTYPE_STR:
  5105. cbCol = lstrlenA((LPSTR)(((BYTE*)pSrcData) + pColCur->cbOffset));
  5106. break;
  5107. case DBTYPE_WSTR:
  5108. case DBTYPE_BSTR:
  5109. cbCol = lstrlenW((LPWSTR)(((BYTE*)pSrcData) + pColCur->cbOffset)) * sizeof(WCHAR);
  5110. break;
  5111. default:
  5112. cbCol = pColCur->ulColumnSize;
  5113. break;
  5114. }
  5115. if (pBindCur->dwPart & DBPART_VALUE)
  5116. {
  5117. hr = spConvert->DataConvert(pColCur->wType, pBindCur->wType,
  5118. cbCol, &cbDst, (BYTE*)(pSrcData) + pColCur->cbOffset,
  5119. pDstTemp, pBindCur->cbMaxLen, dbStat, &dbStat,
  5120. pBindCur->bPrecision, pBindCur->bScale,0);
  5121. }
  5122. }
  5123. if (pBindCur->dwPart & DBPART_LENGTH)
  5124. *((DBLENGTH*)((BYTE*)(pDstData) + pBindCur->obLength)) = cbDst;
  5125. if (pBindCur->dwPart & DBPART_STATUS)
  5126. *((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat;
  5127. if (FAILED(hr))
  5128. return hr;
  5129. }
  5130. return hr;
  5131. }
  5132. HRESULT CreateRow(DBROWOFFSET lRowsOffset, DBCOUNTITEM& cRowsObtained, HROW* rgRows)
  5133. {
  5134. RowClass* pRow = NULL;
  5135. ATLASSERT(lRowsOffset >= 0);
  5136. RowClass::KeyType key = lRowsOffset+1;
  5137. ATLASSERT(key > 0);
  5138. pRow = m_rgRowHandles.Lookup(key);
  5139. if (pRow == NULL)
  5140. {
  5141. ATLTRY(pRow = new RowClass(lRowsOffset))
  5142. if (pRow == NULL)
  5143. return E_OUTOFMEMORY;
  5144. if (!m_rgRowHandles.Add(key, pRow))
  5145. return E_OUTOFMEMORY;
  5146. }
  5147. pRow->AddRefRow();
  5148. m_bReset = false;
  5149. rgRows[cRowsObtained++] = (HROW)key;
  5150. return S_OK;
  5151. }
  5152. STDMETHOD(GetNextRows)(HCHAPTER /*hReserved*/,
  5153. DBROWOFFSET lRowsOffset,
  5154. DBROWCOUNT cRows,
  5155. DBCOUNTITEM *pcRowsObtained,
  5156. HROW **prghRows)
  5157. {
  5158. DBROWOFFSET lTmpRows = lRowsOffset;
  5159. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetNextRows\n");
  5160. if (pcRowsObtained != NULL)
  5161. *pcRowsObtained = 0;
  5162. if (prghRows == NULL || pcRowsObtained == NULL)
  5163. return E_INVALIDARG;
  5164. if (cRows == 0)
  5165. return S_OK;
  5166. HRESULT hr = S_OK;
  5167. T* pT = (T*) this;
  5168. T::ObjectLock cab(pT);
  5169. if (lRowsOffset < 0 && !m_bCanScrollBack)
  5170. return DB_E_CANTSCROLLBACKWARDS;
  5171. if (cRows < 0 && !m_bCanFetchBack)
  5172. return DB_E_CANTFETCHBACKWARDS;
  5173. // Calculate # of rows in set and the base fetch position. If the rowset
  5174. // is at its head position, then lRowOffset < 0 means moving from the BACK
  5175. // of the rowset and not the front.
  5176. DBROWCOUNT cRowsInSet = pT->m_rgRowData.GetSize();
  5177. if (((lRowsOffset == LONG_MIN) && (cRowsInSet != LONG_MIN))
  5178. || (abs((int)(INT_PTR)lRowsOffset)) > cRowsInSet ||
  5179. (abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset < 0 && cRows < 0) ||
  5180. (abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset > 0 && cRows > 0))
  5181. return DB_S_ENDOFROWSET;
  5182. // In the case where the user is moving backwards after moving forwards,
  5183. // we do not wrap around to the end of the rowset.
  5184. if ((m_iRowset == 0 && !m_bReset && cRows < 0) ||
  5185. (((LONG)m_iRowset + lRowsOffset) > cRowsInSet) ||
  5186. (m_iRowset == (DWORD)cRowsInSet && lRowsOffset >= 0 && cRows > 0))
  5187. return DB_S_ENDOFROWSET;
  5188. // Note, if m_bReset, m_iRowset must be 0
  5189. if (lRowsOffset < 0 && m_bReset)
  5190. {
  5191. ATLASSERT(m_iRowset == 0);
  5192. m_iRowset = cRowsInSet;
  5193. }
  5194. int iStepSize = cRows >= 0 ? 1 : -1;
  5195. // If cRows == LONG_MIN, we can't use ABS on it. Therefore, we reset it
  5196. // to a value just greater than cRowsInSet
  5197. if (cRows == LONG_MIN && cRowsInSet != LONG_MIN)
  5198. cRows = cRowsInSet + 2; // set the value to something we can deal with
  5199. else
  5200. cRows = abs((int)(INT_PTR)cRows);
  5201. if (iStepSize < 0 && m_iRowset == 0 && m_bReset && lRowsOffset <= 0)
  5202. m_iRowset = cRowsInSet;
  5203. lRowsOffset += m_iRowset;
  5204. *pcRowsObtained = 0;
  5205. CAutoMemRelease<HROW, CComFree< HROW > > amr;
  5206. if (*prghRows == NULL)
  5207. {
  5208. DBROWCOUNT cHandlesToAlloc = (cRows > cRowsInSet) ? cRowsInSet : cRows;
  5209. if (iStepSize == 1 && (cRowsInSet - lRowsOffset) < cHandlesToAlloc)
  5210. cHandlesToAlloc = cRowsInSet - lRowsOffset;
  5211. if (iStepSize == -1 && lRowsOffset < cHandlesToAlloc)
  5212. cHandlesToAlloc = lRowsOffset;
  5213. *prghRows = (HROW*)CoTaskMemAlloc((cHandlesToAlloc) * sizeof(HROW*));
  5214. amr.Attach(*prghRows);
  5215. }
  5216. if (*prghRows == NULL)
  5217. return E_OUTOFMEMORY;
  5218. while ((lRowsOffset >= 0 && cRows != 0) &&
  5219. ((lRowsOffset < cRowsInSet) || (lRowsOffset <= cRowsInSet && iStepSize < 0)))
  5220. {
  5221. // cRows > cRowsInSet && iStepSize < 0
  5222. if (lRowsOffset == 0 && cRows > 0 && iStepSize < 0)
  5223. break;
  5224. // in the case where we have iStepSize < 0, move the row back
  5225. // further because we want the previous row
  5226. DBROWOFFSET lRow = lRowsOffset;
  5227. if ((lRowsOffset == 0) && (lTmpRows == 0) && (iStepSize < 0))
  5228. lRow = cRowsInSet;
  5229. if (iStepSize < 0)
  5230. lRow += iStepSize;
  5231. hr = pT->CreateRow(lRow, *pcRowsObtained, *prghRows);
  5232. if (FAILED(hr))
  5233. {
  5234. RefRows(*pcRowsObtained, *prghRows, NULL, NULL, FALSE);
  5235. for (ULONG iRowDel = 0; iRowDel < *pcRowsObtained; iRowDel++)
  5236. *prghRows[iRowDel] = NULL;
  5237. *pcRowsObtained = 0;
  5238. return hr;
  5239. }
  5240. cRows--;
  5241. lRowsOffset += iStepSize;
  5242. }
  5243. if ((lRowsOffset >= cRowsInSet && cRows) || (lRowsOffset < 0 && cRows) ||
  5244. (lRowsOffset == 0 && cRows > 0 && iStepSize < 0))
  5245. hr = DB_S_ENDOFROWSET;
  5246. m_iRowset = lRowsOffset;
  5247. if (SUCCEEDED(hr))
  5248. amr.Detach();
  5249. return hr;
  5250. }
  5251. STDMETHOD(ReleaseRows)(DBCOUNTITEM cRows,
  5252. const HROW rghRows[],
  5253. DBROWOPTIONS rgRowOptions[],
  5254. DBREFCOUNT rgRefCounts[],
  5255. DBROWSTATUS rgRowStatus[])
  5256. {
  5257. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::ReleaseRows\n");
  5258. if (cRows == 0)
  5259. return S_OK;
  5260. rgRowOptions;
  5261. return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, FALSE);
  5262. }
  5263. STDMETHOD(RestartPosition)(HCHAPTER /*hReserved*/)
  5264. {
  5265. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RestartPosition\n");
  5266. m_iRowset = 0;
  5267. m_bReset = true;
  5268. return S_OK;
  5269. }
  5270. MapClass m_rgRowHandles;
  5271. DBCOUNTITEM m_iRowset; // cursor
  5272. unsigned m_bCanScrollBack:1;
  5273. unsigned m_bCanFetchBack:1;
  5274. unsigned m_bReset:1;
  5275. };
  5276. ///////////////////////////////////////////////////////////////////////////
  5277. // IRowsetIdentityImpl
  5278. template <class T, class RowClass = CSimpleRow>
  5279. class ATL_NO_VTABLE IRowsetIdentityImpl : public IRowsetIdentity
  5280. {
  5281. public:
  5282. STDMETHOD(IsSameRow)(HROW hThisRow, HROW hThatRow)
  5283. {
  5284. ATLTRACE2(atlTraceDBProvider, 0, _T("IRowsetIdentityImpl::IsSameRow"));
  5285. T* pT = (T*)this;
  5286. // Validate row handles
  5287. RowClass* pRow1 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThisRow);
  5288. RowClass* pRow2 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThatRow);
  5289. if (pRow1 == NULL || pRow2 == NULL)
  5290. return DB_E_BADROWHANDLE;
  5291. return pRow1->Compare(pRow2);
  5292. };
  5293. };
  5294. template <class T>
  5295. class ATL_NO_VTABLE IInternalConnectionImpl : public IInternalConnection
  5296. {
  5297. public:
  5298. STDMETHOD(AddConnection)()
  5299. {
  5300. T* pT = (T*)this;
  5301. T::_ThreadModel::Increment(&pT->m_cSessionsOpen);
  5302. return S_OK;
  5303. }
  5304. STDMETHOD(ReleaseConnection)()
  5305. {
  5306. T* pT = (T*)this;
  5307. T::_ThreadModel::Decrement(&pT->m_cSessionsOpen);
  5308. return S_OK;
  5309. }
  5310. };
  5311. template <class T>
  5312. class ATL_NO_VTABLE IObjectWithSiteSessionImpl : public IObjectWithSiteImpl< T >
  5313. {
  5314. public:
  5315. ~IObjectWithSiteSessionImpl()
  5316. {
  5317. CComPtr<IInternalConnection> pConn;
  5318. if (m_spUnkSite != NULL)
  5319. {
  5320. if (SUCCEEDED(m_spUnkSite->QueryInterface(IID_IInternalConnection, (void**)&pConn)))
  5321. pConn->ReleaseConnection();
  5322. }
  5323. }
  5324. STDMETHOD(SetSite)(IUnknown* pCreator)
  5325. {
  5326. HRESULT hr = S_OK;
  5327. T* pT = (T*)this;
  5328. pT->Lock();
  5329. m_spUnkSite = pCreator;
  5330. pT->Unlock();
  5331. CComPtr<IInternalConnection> pConn;
  5332. if (pCreator != NULL)
  5333. {
  5334. hr = pCreator->QueryInterface(IID_IInternalConnection, (void**)&pConn);
  5335. if (SUCCEEDED(hr))
  5336. hr = pConn->AddConnection();
  5337. }
  5338. return hr;
  5339. }
  5340. };
  5341. template <class T>
  5342. class ATL_NO_VTABLE IRowsetCreatorImpl : public IObjectWithSiteImpl< T >
  5343. {
  5344. public:
  5345. STDMETHOD(SetSite)(IUnknown* pCreator)
  5346. {
  5347. T* pT = (T*)this;
  5348. HRESULT hr = S_OK;
  5349. pT->Lock();
  5350. m_spUnkSite = pCreator;
  5351. pT->Unlock();
  5352. CComVariant varPropScroll, varPropFetch;
  5353. HRESULT hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANSCROLLBACKWARDS, &varPropScroll);
  5354. if (SUCCEEDED(hrProps))
  5355. pT->m_bCanScrollBack = varPropScroll.boolVal == VARIANT_TRUE;
  5356. hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANFETCHBACKWARDS, &varPropFetch);
  5357. if (SUCCEEDED(hrProps))
  5358. pT->m_bCanFetchBack = (varPropFetch.boolVal == VARIANT_TRUE);
  5359. return hr;
  5360. }
  5361. };
  5362. // IRowsetInfoImpl
  5363. template <class T, class PropClass = T>
  5364. class ATL_NO_VTABLE IRowsetInfoImpl :
  5365. public IRowsetInfo,
  5366. public CUtlProps<PropClass>
  5367. {
  5368. public:
  5369. static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL))
  5370. {
  5371. return PropClass::_GetPropSet(pNumPropSets, pcElemPerSupported, pSet, pguidSet);
  5372. }
  5373. STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
  5374. const DBPROPIDSET rgPropertyIDSets[],
  5375. ULONG *pcPropertySets,
  5376. DBPROPSET **prgPropertySets)
  5377. {
  5378. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetProperties\n");
  5379. HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  5380. const GUID* ppGuid[1];
  5381. ppGuid[0] = &DBPROPSET_ROWSET;
  5382. if(SUCCEEDED(hr))
  5383. return CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
  5384. rgPropertyIDSets, pcPropertySets, prgPropertySets,
  5385. 1, ppGuid);
  5386. else
  5387. return hr;
  5388. }
  5389. OUT_OF_LINE ATLCOLUMNINFO* InternalGetColumnInfo(DBORDINAL* pcCols)
  5390. {
  5391. return T::GetColumnInfo((T*)this, pcCols);
  5392. }
  5393. STDMETHOD(GetReferencedRowset)(DBORDINAL iOrdinal,
  5394. REFIID riid,
  5395. IUnknown **ppReferencedRowset)
  5396. {
  5397. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset\n");
  5398. DBORDINAL cCols=0;
  5399. // Check Arguments
  5400. if( ppReferencedRowset == NULL )
  5401. {
  5402. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset : Error NULL IUnk output Param\n");
  5403. return E_INVALIDARG;
  5404. }
  5405. *ppReferencedRowset = NULL;
  5406. // Check to see if column in question is a bookmark
  5407. ATLCOLUMNINFO* pColInfo = InternalGetColumnInfo(&cCols);
  5408. for (ULONG iColInfo = 0;
  5409. iColInfo < cCols && iOrdinal != pColInfo[iColInfo].iOrdinal;
  5410. iColInfo++);
  5411. if (iColInfo == cCols)
  5412. return DB_E_BADORDINAL;
  5413. ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
  5414. if ((pColCur->dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) == 0)
  5415. return DB_E_NOTAREFERENCECOLUMN;
  5416. // Query for requested interface
  5417. return QueryInterface(riid, (void**)ppReferencedRowset);
  5418. }
  5419. STDMETHOD(GetSpecification)(REFIID riid,
  5420. IUnknown **ppSpecification)
  5421. {
  5422. ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetSpecification\n");
  5423. if (ppSpecification == NULL)
  5424. return E_INVALIDARG;
  5425. T* pT = (T*) this;
  5426. T::ObjectLock cab(pT);
  5427. ATLASSERT(pT->m_spUnkSite != NULL);
  5428. return pT->m_spUnkSite->QueryInterface(riid, (void**)ppSpecification);
  5429. }
  5430. };
  5431. template <class T, class Storage, class CreatorClass,
  5432. class ArrayType = CSimpleArray<Storage>,
  5433. class RowClass = CSimpleRow,
  5434. class RowsetInterface = IRowsetImpl < T, IRowset, RowClass> >
  5435. class CRowsetImpl :
  5436. public CComObjectRootEx<typename CreatorClass::_ThreadModel>,
  5437. public IAccessorImpl<T>,
  5438. public IRowsetIdentityImpl<T, RowClass>,
  5439. public IRowsetCreatorImpl<T>,
  5440. public IRowsetInfoImpl<T, typename CreatorClass::_PropClass>,
  5441. public IColumnsInfoImpl<T>,
  5442. public IConvertTypeImpl<T>,
  5443. public RowsetInterface
  5444. {
  5445. public:
  5446. typedef CreatorClass _RowsetCreatorClass;
  5447. typedef ArrayType _RowsetArrayType;
  5448. typedef CRowsetImpl< T, Storage, CreatorClass, ArrayType, RowClass, RowsetInterface> _RowsetBaseClass;
  5449. BEGIN_COM_MAP(CRowsetImpl)
  5450. COM_INTERFACE_ENTRY(IAccessor)
  5451. COM_INTERFACE_ENTRY(IObjectWithSite)
  5452. COM_INTERFACE_ENTRY(IRowsetInfo)
  5453. COM_INTERFACE_ENTRY(IColumnsInfo)
  5454. COM_INTERFACE_ENTRY(IConvertType)
  5455. COM_INTERFACE_ENTRY(IRowsetIdentity)
  5456. COM_INTERFACE_ENTRY(IRowset)
  5457. END_COM_MAP()
  5458. HRESULT FinalConstruct()
  5459. {
  5460. HRESULT hr = IAccessorImpl<T>::FinalConstruct();
  5461. if (FAILED(hr))
  5462. return hr;
  5463. return CConvertHelper::FinalConstruct();
  5464. }
  5465. HRESULT NameFromDBID(DBID* pDBID, CComBSTR& bstr, bool bIndex)
  5466. {
  5467. if (pDBID->uName.pwszName != NULL)
  5468. {
  5469. bstr = pDBID->uName.pwszName;
  5470. if (m_strCommandText == (BSTR)NULL)
  5471. return E_OUTOFMEMORY;
  5472. return S_OK;
  5473. }
  5474. return (bIndex) ? DB_E_NOINDEX : DB_E_NOTABLE;
  5475. }
  5476. HRESULT GetCommandFromID(DBID* pTableID, DBID* pIndexID)
  5477. {
  5478. USES_CONVERSION;
  5479. HRESULT hr;
  5480. if (pTableID == NULL && pIndexID == NULL)
  5481. return E_INVALIDARG;
  5482. if (pTableID != NULL && pTableID->eKind == DBKIND_NAME)
  5483. {
  5484. hr = NameFromDBID(pTableID, m_strCommandText, true);
  5485. if (FAILED(hr))
  5486. return hr;
  5487. if (pIndexID != NULL)
  5488. {
  5489. if (pIndexID->eKind == DBKIND_NAME)
  5490. {
  5491. hr = NameFromDBID(pIndexID, m_strIndexText, false);
  5492. if (FAILED(hr))
  5493. {
  5494. m_strCommandText.Empty();
  5495. return hr;
  5496. }
  5497. }
  5498. else
  5499. {
  5500. m_strCommandText.Empty();
  5501. return DB_E_NOINDEX;
  5502. }
  5503. }
  5504. return S_OK;
  5505. }
  5506. if (pIndexID != NULL && pIndexID->eKind == DBKIND_NAME)
  5507. return NameFromDBID(pIndexID, m_strIndexText, false);
  5508. return S_OK;
  5509. }
  5510. HRESULT ValidateCommandID(DBID* pTableID, DBID* pIndexID)
  5511. {
  5512. HRESULT hr = S_OK;
  5513. if (pTableID != NULL)
  5514. {
  5515. hr = CUtlProps<T>::IsValidDBID(pTableID);
  5516. if (hr != S_OK)
  5517. return hr;
  5518. // Check for a NULL TABLE ID (where its a valid pointer but NULL)
  5519. if ((pTableID->eKind == DBKIND_GUID_NAME ||
  5520. pTableID->eKind == DBKIND_NAME ||
  5521. pTableID->eKind == DBKIND_PGUID_NAME)
  5522. && pTableID->uName.pwszName == NULL)
  5523. return DB_E_NOTABLE;
  5524. }
  5525. if (pIndexID != NULL)
  5526. hr = CUtlProps<T>::IsValidDBID(pIndexID);
  5527. return hr;
  5528. }
  5529. HRESULT SetCommandText(DBID* pTableID, DBID* pIndexID)
  5530. {
  5531. T* pT = (T*)this;
  5532. HRESULT hr = pT->ValidateCommandID(pTableID, pIndexID);
  5533. if (FAILED(hr))
  5534. return hr;
  5535. hr = pT->GetCommandFromID(pTableID, pIndexID);
  5536. return hr;
  5537. }
  5538. void FinalRelease()
  5539. {
  5540. m_rgRowData.RemoveAll();
  5541. }
  5542. static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols)
  5543. {
  5544. return Storage::GetColumnInfo(pv,pcCols);
  5545. }
  5546. CComBSTR m_strCommandText;
  5547. CComBSTR m_strIndexText;
  5548. ArrayType m_rgRowData;
  5549. };
  5550. class CTABLESRow
  5551. {
  5552. public:
  5553. WCHAR m_szCatalog[129];
  5554. WCHAR m_szSchema[129];
  5555. WCHAR m_szTable[129];
  5556. WCHAR m_szType[129];
  5557. WCHAR m_szDesc[129];
  5558. GUID m_guid;
  5559. ULONG m_ulPropID;
  5560. CTABLESRow()
  5561. {
  5562. m_szCatalog[0] = NULL;
  5563. m_szSchema[0] = NULL;
  5564. m_szTable[0] = NULL;
  5565. m_szType[0] = NULL;
  5566. m_szDesc[0] = NULL;
  5567. m_guid = GUID_NULL;
  5568. m_ulPropID = 0;
  5569. }
  5570. BEGIN_PROVIDER_COLUMN_MAP(CTABLESRow)
  5571. PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szCatalog)
  5572. PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szSchema)
  5573. PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTable)
  5574. PROVIDER_COLUMN_ENTRY("TABLE_TYPE", 4, m_szType)
  5575. PROVIDER_COLUMN_ENTRY("TABLE_GUID", 5, m_guid)
  5576. PROVIDER_COLUMN_ENTRY("DESCRIPTION", 6, m_szDesc)
  5577. PROVIDER_COLUMN_ENTRY("TABLE_PROPID", 7, m_ulPropID)
  5578. END_PROVIDER_COLUMN_MAP()
  5579. };
  5580. class CCOLUMNSRow
  5581. {
  5582. public:
  5583. WCHAR m_szTableCatalog[129];
  5584. WCHAR m_szTableSchema[129];
  5585. WCHAR m_szTableName[129];
  5586. WCHAR m_szColumnName[129];
  5587. GUID m_guidColumn;
  5588. ULONG m_ulColumnPropID;
  5589. DBORDINAL m_ulOrdinalPosition;
  5590. VARIANT_BOOL m_bColumnHasDefault;
  5591. WCHAR m_szColumnDefault[129];
  5592. ULONG m_ulColumnFlags;
  5593. VARIANT_BOOL m_bIsNullable;
  5594. USHORT m_nDataType;
  5595. GUID m_guidType;
  5596. DBLENGTH m_ulCharMaxLength;
  5597. ULONG m_ulCharOctetLength;
  5598. USHORT m_nNumericPrecision;
  5599. short m_nNumericScale;
  5600. ULONG m_ulDateTimePrecision;
  5601. WCHAR m_szCharSetCatalog[129];
  5602. WCHAR m_szCharSetSchema[129];
  5603. WCHAR m_szCharSetName[129];
  5604. WCHAR m_szCollationCatalog[129];
  5605. WCHAR m_szCollationSchema[129];
  5606. WCHAR m_szCollationName[129];
  5607. WCHAR m_szDomainCatalog[129];
  5608. WCHAR m_szDomainSchema[129];
  5609. WCHAR m_szDomainName[129];
  5610. WCHAR m_szDescription[129];
  5611. CCOLUMNSRow()
  5612. {
  5613. ClearMembers();
  5614. }
  5615. void ClearMembers()
  5616. {
  5617. m_szTableCatalog[0] = NULL;
  5618. m_szTableSchema[0] = NULL;
  5619. m_szTableName[0] = NULL;
  5620. m_szColumnName[0] = NULL;
  5621. m_guidColumn = GUID_NULL;
  5622. m_ulColumnPropID = 0;
  5623. m_ulOrdinalPosition = 0;
  5624. m_bColumnHasDefault = VARIANT_FALSE;
  5625. m_szColumnDefault[0] = NULL;
  5626. m_ulColumnFlags = 0;
  5627. m_bIsNullable = VARIANT_FALSE;
  5628. m_nDataType = 0;
  5629. m_guidType = GUID_NULL;
  5630. m_ulCharMaxLength = 0;
  5631. m_ulCharOctetLength = 0;
  5632. m_nNumericPrecision = 0;
  5633. m_nNumericScale = 0;
  5634. m_ulDateTimePrecision = 0;
  5635. m_szCharSetCatalog[0] = NULL;
  5636. m_szCharSetSchema[0] = NULL;
  5637. m_szCharSetName[0] = NULL;
  5638. m_szCollationCatalog[0] = NULL;
  5639. m_szCollationSchema[0] = NULL;
  5640. m_szCollationName[0] = NULL;
  5641. m_szDomainCatalog[0] = NULL;
  5642. m_szDomainSchema[0] = NULL;
  5643. m_szDomainName[0] = NULL;
  5644. m_szDescription[0] = NULL;
  5645. }
  5646. BEGIN_PROVIDER_COLUMN_MAP(CCOLUMNSRow)
  5647. PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szTableCatalog)
  5648. PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szTableSchema)
  5649. PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTableName)
  5650. PROVIDER_COLUMN_ENTRY("COLUMN_NAME", 4, m_szColumnName)
  5651. PROVIDER_COLUMN_ENTRY("COLUMN_GUID",5, m_guidColumn)
  5652. PROVIDER_COLUMN_ENTRY("COLUMN_PROPID",6, m_ulColumnPropID)
  5653. PROVIDER_COLUMN_ENTRY("ORDINAL_POSITION",7, m_ulOrdinalPosition)
  5654. PROVIDER_COLUMN_ENTRY("COLUMN_HASDEFAULT",8, m_bColumnHasDefault)
  5655. PROVIDER_COLUMN_ENTRY("COLUMN_DEFAULT",9, m_szColumnDefault)
  5656. PROVIDER_COLUMN_ENTRY("COLUMN_FLAGS",10, m_ulColumnFlags)
  5657. PROVIDER_COLUMN_ENTRY("IS_NULLABLE",11, m_bIsNullable)
  5658. PROVIDER_COLUMN_ENTRY("DATA_TYPE",12, m_nDataType)
  5659. PROVIDER_COLUMN_ENTRY("TYPE_GUID",13, m_guidType)
  5660. PROVIDER_COLUMN_ENTRY("CHARACTER_MAXIMUM_LENGTH",14, m_ulCharMaxLength)
  5661. PROVIDER_COLUMN_ENTRY("CHARACTER_OCTET_LENGTH",15, m_ulCharOctetLength)
  5662. PROVIDER_COLUMN_ENTRY("NUMERIC_PRECISION",16, m_nNumericPrecision)
  5663. PROVIDER_COLUMN_ENTRY("NUMERIC_SCALE",17, m_nNumericScale)
  5664. PROVIDER_COLUMN_ENTRY("DATETIME_PRECISION",18, m_ulDateTimePrecision)
  5665. PROVIDER_COLUMN_ENTRY("CHARACTER_SET_CATALOG", 19, m_szCharSetCatalog)
  5666. PROVIDER_COLUMN_ENTRY("CHARACTER_SET_SCHEMA", 20, m_szCharSetSchema)
  5667. PROVIDER_COLUMN_ENTRY("CHARACTER_SET_NAME", 21, m_szCharSetName)
  5668. PROVIDER_COLUMN_ENTRY("COLLATION_CATALOG", 22, m_szCollationCatalog)
  5669. PROVIDER_COLUMN_ENTRY("COLLATION_SCHEMA", 23, m_szCollationSchema)
  5670. PROVIDER_COLUMN_ENTRY("COLLATION_NAME", 24, m_szCollationName)
  5671. PROVIDER_COLUMN_ENTRY("DOMAIN_CATALOG", 25, m_szDomainCatalog)
  5672. PROVIDER_COLUMN_ENTRY("DOMAIN_SCHEMA", 26, m_szDomainSchema)
  5673. PROVIDER_COLUMN_ENTRY("DOMAIN_NAME", 27, m_szDomainName)
  5674. PROVIDER_COLUMN_ENTRY("DESCRIPTION", 28, m_szDescription)
  5675. END_PROVIDER_COLUMN_MAP()
  5676. };
  5677. template <class ArrayClass>
  5678. HRESULT InitFromRowset(ArrayClass& rgData, DBID* pTableID, DBID* pIndexID, IUnknown* pSession, LONG* pcRowsAffected)
  5679. {
  5680. CComQIPtr<IOpenRowset> spOpenRowset = pSession;
  5681. if (spOpenRowset == NULL)
  5682. return E_FAIL;
  5683. CComPtr<IColumnsInfo> spColInfo;
  5684. HRESULT hr = spOpenRowset->OpenRowset(NULL, pTableID, pIndexID, IID_IColumnsInfo, 0, NULL, (IUnknown**)&spColInfo);
  5685. if (FAILED(hr))
  5686. return hr;
  5687. LPOLESTR szColumns = NULL;
  5688. DBORDINAL cColumns = 0;
  5689. DBCOLUMNINFO* pColInfo = NULL;
  5690. hr = spColInfo->GetColumnInfo(&cColumns, &pColInfo, &szColumns);
  5691. if (FAILED(hr))
  5692. return hr;
  5693. *pcRowsAffected = 0;
  5694. for (ULONG iCol = 0; iCol < cColumns; iCol++)
  5695. {
  5696. CCOLUMNSRow crData;
  5697. DBCOLUMNINFO& rColCur = pColInfo[iCol];
  5698. lstrcpynW(crData.m_szTableName, pTableID->uName.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szTableName));
  5699. lstrcpynW(crData.m_szColumnName, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
  5700. lstrcpynW(crData.m_szDescription, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
  5701. GUID* pGuidCol = CDBIDOps::GetDBIDpGuid(rColCur.columnid);
  5702. if (pGuidCol)
  5703. crData.m_guidColumn = *pGuidCol;
  5704. else
  5705. crData.m_guidColumn = GUID_NULL;
  5706. crData.m_ulColumnPropID = CDBIDOps::GetPropIDFromDBID(rColCur.columnid);
  5707. crData.m_ulOrdinalPosition = rColCur.iOrdinal;
  5708. crData.m_ulColumnFlags = rColCur.dwFlags;
  5709. crData.m_bIsNullable = (rColCur.dwFlags & DBCOLUMNFLAGS_ISNULLABLE) ? VARIANT_TRUE : VARIANT_FALSE;
  5710. crData.m_nDataType = rColCur.wType;
  5711. crData.m_ulCharMaxLength = rColCur.ulColumnSize;
  5712. crData.m_nNumericPrecision = rColCur.bPrecision;
  5713. crData.m_nNumericScale = rColCur.bScale;
  5714. if (!rgData.Add(crData))
  5715. {
  5716. CoTaskMemFree(pColInfo);
  5717. CoTaskMemFree(szColumns);
  5718. return E_OUTOFMEMORY;
  5719. }
  5720. (*pcRowsAffected)++;
  5721. }
  5722. CoTaskMemFree(pColInfo);
  5723. CoTaskMemFree(szColumns);
  5724. return S_OK;
  5725. }
  5726. class CPROVIDER_TYPERow
  5727. {
  5728. public:
  5729. // Attributes
  5730. WCHAR m_szName[129];
  5731. USHORT m_nType;
  5732. ULONG m_ulSize;
  5733. WCHAR m_szPrefix[129];
  5734. WCHAR m_szSuffix[129];
  5735. WCHAR m_szCreateParams[129];
  5736. VARIANT_BOOL m_bIsNullable;
  5737. VARIANT_BOOL m_bCaseSensitive;
  5738. ULONG m_bSearchable;
  5739. VARIANT_BOOL m_bUnsignedAttribute;
  5740. VARIANT_BOOL m_bFixedPrecScale;
  5741. VARIANT_BOOL m_bAutoUniqueValue;
  5742. WCHAR m_szLocalTypeName[129];
  5743. short m_nMinScale;
  5744. short m_nMaxScale;
  5745. GUID m_guidType;
  5746. WCHAR m_szTypeLib[129];
  5747. WCHAR m_szVersion[129];
  5748. VARIANT_BOOL m_bIsLong;
  5749. VARIANT_BOOL m_bBestMatch;
  5750. VARIANT_BOOL m_bIsFixedLength;
  5751. CPROVIDER_TYPERow()
  5752. {
  5753. m_szName[0] = NULL;
  5754. m_nType = 0;
  5755. m_ulSize = 0;
  5756. m_szPrefix[0] = NULL;
  5757. m_szSuffix[0] = NULL;
  5758. m_szCreateParams[0] = NULL;
  5759. m_bIsNullable = VARIANT_FALSE;
  5760. m_bCaseSensitive = VARIANT_FALSE;
  5761. m_bSearchable = DB_UNSEARCHABLE;
  5762. m_bUnsignedAttribute = VARIANT_FALSE;
  5763. m_bFixedPrecScale = VARIANT_FALSE;
  5764. m_bAutoUniqueValue = VARIANT_FALSE;
  5765. m_szLocalTypeName[0] = NULL;
  5766. m_nMinScale = 0;
  5767. m_nMaxScale = 0;
  5768. m_guidType = GUID_NULL;
  5769. m_szTypeLib[0] = NULL;
  5770. m_szVersion[0] = NULL;
  5771. m_bIsLong = VARIANT_FALSE;
  5772. m_bBestMatch = VARIANT_FALSE;
  5773. m_bIsFixedLength = VARIANT_FALSE;
  5774. }
  5775. // Binding Maps
  5776. BEGIN_PROVIDER_COLUMN_MAP(CPROVIDER_TYPERow)
  5777. PROVIDER_COLUMN_ENTRY("TYPE_NAME", 1, m_szName)
  5778. PROVIDER_COLUMN_ENTRY("DATA_TYPE", 2, m_nType)
  5779. PROVIDER_COLUMN_ENTRY("COLUMN_SIZE", 3, m_ulSize)
  5780. PROVIDER_COLUMN_ENTRY("LITERAL_PREFIX", 4, m_szPrefix)
  5781. PROVIDER_COLUMN_ENTRY("LITERAL_SUFFIX", 5, m_szSuffix)
  5782. PROVIDER_COLUMN_ENTRY("CREATE_PARAMS", 6, m_szCreateParams)
  5783. PROVIDER_COLUMN_ENTRY("IS_NULLABLE", 7, m_bIsNullable)
  5784. PROVIDER_COLUMN_ENTRY("CASE_SENSITIVE", 8, m_bCaseSensitive)
  5785. PROVIDER_COLUMN_ENTRY("SEARCHABLE", 9, m_bSearchable)
  5786. PROVIDER_COLUMN_ENTRY("UNSIGNED_ATTRIBUTE", 10, m_bUnsignedAttribute)
  5787. PROVIDER_COLUMN_ENTRY("FIXED_PREC_SCALE", 11, m_bFixedPrecScale)
  5788. PROVIDER_COLUMN_ENTRY("AUTO_UNIQUE_VALUE", 12, m_bAutoUniqueValue)
  5789. PROVIDER_COLUMN_ENTRY("LOCAL_TYPE_NAME", 13, m_szLocalTypeName)
  5790. PROVIDER_COLUMN_ENTRY("MINIMUM_SCALE", 14, m_nMinScale)
  5791. PROVIDER_COLUMN_ENTRY("MAXIMUM_SCALE", 15, m_nMaxScale)
  5792. PROVIDER_COLUMN_ENTRY("GUID", 16, m_guidType)
  5793. PROVIDER_COLUMN_ENTRY("TYPELIB", 17, m_szTypeLib)
  5794. PROVIDER_COLUMN_ENTRY("VERSION", 18, m_szVersion)
  5795. PROVIDER_COLUMN_ENTRY("IS_LONG", 19, m_bIsLong)
  5796. PROVIDER_COLUMN_ENTRY("BEST_MATCH", 20, m_bBestMatch)
  5797. PROVIDER_COLUMN_ENTRY("IS_FIXEDLENGTH", 21, m_bIsFixedLength)
  5798. END_PROVIDER_COLUMN_MAP()
  5799. };
  5800. class CEnumRowsetImpl
  5801. {
  5802. public:
  5803. WCHAR m_szSourcesName[256];
  5804. WCHAR m_szSourcesParseName[256];
  5805. WCHAR m_szSourcesDescription[256];
  5806. unsigned short m_iType;
  5807. VARIANT_BOOL m_bIsParent;
  5808. BEGIN_PROVIDER_COLUMN_MAP(CEnumRowsetImpl)
  5809. PROVIDER_COLUMN_ENTRY("SOURCES_NAME", 1, m_szSourcesName)
  5810. PROVIDER_COLUMN_ENTRY("SOURCES_PARSENAME", 2, m_szSourcesParseName)
  5811. PROVIDER_COLUMN_ENTRY("SOURCES_DESCRIPTION", 3, m_szSourcesDescription)
  5812. PROVIDER_COLUMN_ENTRY("SOURCES_TYPE", 4, m_iType)
  5813. PROVIDER_COLUMN_ENTRY("SOURCES_ISPARENT", 5, m_bIsParent)
  5814. END_PROVIDER_COLUMN_MAP()
  5815. };
  5816. #endif