home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Internet 2000 May / MICD_2000_05.iso / CBuilder5 / INSTALL / DATA1.CAB / Program_Built_Files / Include / Atl / atldb.h < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-01  |  195.7 KB  |  6,401 lines

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