|
|
// This is a part of the Active Template Library.
// Copyright (C) 1996-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.
#ifndef __ATLDB_H
#define __ATLDB_H
// OLE DB Provider Support
// Interface Impl Classes
//
// Data Source Object
//
// -Mandatory Interfaces:
// IDBCreateSession
// IDBInitialize
// IDBProperties
// IPersist
//
// Session Object
//
// -Mandatory Interfaces:
// IGetDataSource
// IOpenRowset
// ISessionProperties
//
// -Optional Interfaces:
// IDBCreateCommand
// IDBSchemaRowset
//
// Rowset Object
//
// -Mandatory Interfaces:
// IAccessor
// IColumnsInfo
// IConvertType
// IRowset
// IRowsetInfo
//
// -Optional Interfaces:
// IRowsetIdentity
//
// Command Object
//
// -Mandatory Interfaces:
// ICommand)
// IAccessor)
// ICommandProperties
// ICommandText - derives from ICommand
// IColumnsInfo
// IConvertType
#include <oledb.h>
#include <limits.h>
#include <oledberr.h>
#include <msdadc.h>
#include <atldbcli.h>
//Forwards
template <class T> class CUtlPropInfo; class CColumnIds;
// Additional Property Flag needed internally
const int DBPROPFLAGS_CHANGE = 0x40000000;
// ------------- STRUCTURE DEFINITIONS --------------------------------
struct UPROPVAL { DBPROPOPTIONS dwOption; CColumnIds* pCColumnIds; DWORD dwFlags; VARIANT vValue; };
struct UPROPINFO { DBPROPID dwPropId; ULONG ulIDS; VARTYPE VarType; DBPROPFLAGS dwFlags; union { DWORD_PTR dwVal; LPOLESTR szVal; }; DBPROPOPTIONS dwOption; };
struct UPROP { ULONG cPropIds; UPROPINFO** rgpUPropInfo; UPROPVAL* pUPropVal; };
struct PROPCOLID { DBID dbidProperty; // The column id information
DBPROPOPTIONS dwOption; VARIANT vValue; };
typedef PROPCOLID* PPROPCOLID;
struct UPROPSET { const GUID* pPropSet; ULONG cUPropInfo; UPROPINFO* pUPropInfo; DWORD dwFlags; };
struct ATLBINDINGS { DBBINDING* pBindings; DWORD dwRef; DBCOUNTITEM cBindings; DBACCESSORFLAGS dwAccessorFlags; };
struct ATLCOLUMNINFO { LPOLESTR pwszName; ITypeInfo *pTypeInfo; DBORDINAL iOrdinal; DBCOLUMNFLAGS dwFlags; DBLENGTH ulColumnSize; DBTYPE wType; BYTE bPrecision; BYTE bScale; DBID columnid; DBBYTEOFFSET cbOffset; };
//
// The following very large sections of defines are to implement auto determination
// of Preoperty map constants based on a stringized prop name. There is one set for
// Type (VT_), one for Init Value, and one for Property flags.
//
#define ABORTPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define ACTIVESESSIONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define APPENDONLY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define ASYNCTXNABORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define ASYNCTXNCOMMIT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define AUTH_CACHE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define AUTH_ENCRYPT_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define AUTH_INTEGRATED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define AUTH_MASK_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define AUTH_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define AUTH_PERSIST_ENCRYPTED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define AUTH_USERID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define BLOCKINGSTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define BOOKMARKS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define BOOKMARKSKIPPED_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define BOOKMARKTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define BYREFACCESSORS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define CACHEDEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define CANFETCHBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define CANHOLDROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define CANSCROLLBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define CATALOGLOCATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define CATALOGTERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define CATALOGUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define CHANGEINSERTEDROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE )
#define COL_AUTOINCREMENT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COL_DEFAULT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COL_DESCRIPTION_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COL_FIXEDLENGTH_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COL_NULLABLE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COL_PRIMARYKEY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COL_UNIQUE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COLUMNDEFINITION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define COLUMNRESTRICT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define COMMANDTIMEOUT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define COMMITPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define CONCATNULLBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define CURRENTCATALOG_Flags ( DBPROPFLAGS_DATASOURCE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define DATASOURCENAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define DATASOURCEREADONLY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define DBMSNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define DBMSVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define DEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define DELAYSTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define DSOTHREADMODEL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define GROUPBY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define HETEROGENEOUSTABLES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define IAccessor_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IColumnsInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IColumnsRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IConnectionPointContainer_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IConvertType_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetChange_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetIdentity_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetIndex_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetLocate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetResynch_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetScroll_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IRowsetUpdate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define ISupportErrorInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define ILockBytes_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define ISequentialStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IStorage_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define IDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define IMMOBILEROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_AUTOUPDATE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_CLUSTERED_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_FILLFACTOR_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_INITIALSIZE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_NULLCOLLATION_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_NULLS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_PRIMARYKEY_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_SORTBOOKMARKS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_TEMPINDEX_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_TYPE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INDEX_UNIQUE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_DATASOURCE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_HWND_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_IMPERSONATION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_LCID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_LOCATION_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_MODE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_PROMPT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_PROTECTION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_PROVIDERSTRING_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define INIT_TIMEOUT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define LITERALBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define LITERALIDENTITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MAXINDEXSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MAXOPENROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MAXPENDINGROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MAXROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define MAXROWSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MAXROWSIZEINCLUDESBLOB_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MAXTABLESINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MAYWRITECOLUMN_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define MEMORYUSAGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define MULTIPLEPARAMSETS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MULTIPLERESULTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MULTIPLESTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define MULTITABLEUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFICATIONPHASES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYCOLUMNSET_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWDELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWFIRSTCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWRESYNCH_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWSETRELEASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWSETFETCHPOSITIONCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWUNDOCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWUNDODELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWUNDOINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NOTIFYROWUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define NULLCOLLATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define OLEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define ORDERBYCOLUMNSINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define ORDEREDBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define OTHERINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define OTHERUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define OUTPUTPARAMETERAVAILABILITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define OWNINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define OWNUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define PERSISTENTIDTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define PREPAREABORTBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define PREPARECOMMITBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define PROCEDURETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define PROVIDERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define PROVIDEROLEDBVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define PROVIDERVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define QUICKRESTART_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define QUOTEDIDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define REENTRANTEVENTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define REMOVEDELETED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define REPORTMULTIPLECHANGES_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE )
#define RETURNPENDINGINSERTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define ROWRESTRICT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define ROWSETCONVERSIONSONCOMMAND_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define ROWTHREADMODEL_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define SCHEMATERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define SCHEMAUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define SERVERCURSOR_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define SESS_AUTOCOMMITISOLEVELS_Flags ( DBPROPFLAGS_SESSION | DBPROPFLAGS_READ )
#define SQLSUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define STRONGIDENTITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define STRUCTUREDSTORAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define SUBQUERIES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define SUPPORTEDTXNDDL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define SUPPORTEDTXNISOLEVELS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define SUPPORTEDTXNISORETAIN_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define TABLETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define TBL_TEMPTABLE_Flags ( DBPROPFLAGS_TABLE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define TRANSACTEDOBJECT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
#define UPDATABILITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
#define USERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
#define ABORTPRESERVE_Type VT_BOOL
#define ACTIVESESSIONS_Type VT_I4
#define APPENDONLY_Type VT_BOOL
#define ASYNCTXNABORT_Type VT_BOOL
#define ASYNCTXNCOMMIT_Type VT_BOOL
#define AUTH_CACHE_AUTHINFO_Type VT_BOOL
#define AUTH_ENCRYPT_PASSWORD_Type VT_BOOL
#define AUTH_INTEGRATED_Type VT_BSTR
#define AUTH_MASK_PASSWORD_Type VT_BOOL
#define AUTH_PASSWORD_Type VT_BSTR
#define AUTH_PERSIST_ENCRYPTED_Type VT_BOOL
#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Type VT_BOOL
#define AUTH_USERID_Type VT_BSTR
#define BLOCKINGSTORAGEOBJECTS_Type VT_BOOL
#define BOOKMARKS_Type VT_BOOL
#define BOOKMARKSKIPPED_Type VT_BOOL
#define BOOKMARKTYPE_Type VT_I4
#define BYREFACCESSORS_Type VT_BOOL
#define CACHEDEFERRED_Type VT_BOOL
#define CANFETCHBACKWARDS_Type VT_BOOL
#define CANHOLDROWS_Type VT_BOOL
#define CANSCROLLBACKWARDS_Type VT_BOOL
#define CATALOGLOCATION_Type VT_I4
#define CATALOGTERM_Type VT_BSTR
#define CATALOGUSAGE_Type VT_I4
#define CHANGEINSERTEDROWS_Type VT_BOOL
#define COL_AUTOINCREMENT_Type VT_BOOL
#define COL_DEFAULT_Type VT_BSTR
#define COL_DESCRIPTION_Type VT_BSTR
#define COL_FIXEDLENGTH_Type VT_BOOL
#define COL_NULLABLE_Type VT_BOOL
#define COL_PRIMARYKEY_Type VT_BOOL
#define COL_UNIQUE_Type VT_BOOL
#define COLUMNDEFINITION_Type VT_I4
#define COLUMNRESTRICT_Type VT_BOOL
#define COMMANDTIMEOUT_Type VT_I4
#define COMMITPRESERVE_Type VT_BOOL
#define CONCATNULLBEHAVIOR_Type VT_I4
#define CURRENTCATALOG_Type VT_BSTR
#define DATASOURCENAME_Type VT_BSTR
#define DATASOURCEREADONLY_Type VT_BOOL
#define DBMSNAME_Type VT_BSTR
#define DBMSVER_Type VT_BSTR
#define DEFERRED_Type VT_BOOL
#define DELAYSTORAGEOBJECTS_Type VT_BOOL
#define DSOTHREADMODEL_Type VT_I4
#define GROUPBY_Type VT_I4
#define HETEROGENEOUSTABLES_Type VT_I4
#define IAccessor_Type VT_BOOL
#define IColumnsInfo_Type VT_BOOL
#define IColumnsRowset_Type VT_BOOL
#define IConnectionPointContainer_Type VT_BOOL
#define IConvertType_Type VT_BOOL
#define IRowset_Type VT_BOOL
#define IRowsetChange_Type VT_BOOL
#define IRowsetIdentity_Type VT_BOOL
#define IRowsetIndex_Type VT_BOOL
#define IRowsetInfo_Type VT_BOOL
#define IRowsetLocate_Type VT_BOOL
#define IRowsetResynch_Type VT_BOOL
#define IRowsetScroll_Type VT_BOOL
#define IRowsetUpdate_Type VT_BOOL
#define ISupportErrorInfo_Type VT_BOOL
#define ILockBytes_Type VT_BOOL
#define ISequentialStream_Type VT_BOOL
#define IStorage_Type VT_BOOL
#define IStream_Type VT_BOOL
#define IDENTIFIERCASE_Type VT_I4
#define IMMOBILEROWS_Type VT_BOOL
#define INDEX_AUTOUPDATE_Type VT_BOOL
#define INDEX_CLUSTERED_Type VT_BOOL
#define INDEX_FILLFACTOR_Type VT_I4
#define INDEX_INITIALSIZE_Type VT_I4
#define INDEX_NULLCOLLATION_Type VT_I4
#define INDEX_NULLS_Type VT_I4
#define INDEX_PRIMARYKEY_Type VT_BOOL
#define INDEX_SORTBOOKMARKS_Type VT_BOOL
#define INDEX_TEMPINDEX_Type VT_BOOL
#define INDEX_TYPE_Type VT_I4
#define INDEX_UNIQUE_Type VT_BOOL
#define INIT_DATASOURCE_Type VT_BSTR
#define INIT_HWND_Type VT_I4
#define INIT_IMPERSONATION_LEVEL_Type VT_I4
#define INIT_LCID_Type VT_I4
#define INIT_LOCATION_Type VT_BSTR
#define INIT_MODE_Type VT_I4
#define INIT_PROMPT_Type VT_I2
#define INIT_PROTECTION_LEVEL_Type VT_I4
#define INIT_PROVIDERSTRING_Type VT_BSTR
#define INIT_TIMEOUT_Type VT_I4
#define LITERALBOOKMARKS_Type VT_BOOL
#define LITERALIDENTITY_Type VT_BOOL
#define MAXINDEXSIZE_Type VT_I4
#define MAXOPENROWS_Type VT_I4
#define MAXPENDINGROWS_Type VT_I4
#define MAXROWS_Type VT_I4
#define MAXROWSIZE_Type VT_I4
#define MAXROWSIZEINCLUDESBLOB_Type VT_BOOL
#define MAXTABLESINSELECT_Type VT_I4
#define MAYWRITECOLUMN_Type VT_BOOL
#define MEMORYUSAGE_Type VT_I4
#define MULTIPLEPARAMSETS_Type VT_BOOL
#define MULTIPLERESULTS_Type VT_I4
#define MULTIPLESTORAGEOBJECTS_Type VT_BOOL
#define MULTITABLEUPDATE_Type VT_BOOL
#define NOTIFICATIONPHASES_Type VT_I4
#define NOTIFYCOLUMNSET_Type VT_I4
#define NOTIFYROWDELETE_Type VT_I4
#define NOTIFYROWFIRSTCHANGE_Type VT_I4
#define NOTIFYROWINSERT_Type VT_I4
#define NOTIFYROWRESYNCH_Type VT_I4
#define NOTIFYROWSETRELEASE_Type VT_I4
#define NOTIFYROWSETFETCHPOSITIONCHANGE_Type VT_I4
#define NOTIFYROWUNDOCHANGE_Type VT_I4
#define NOTIFYROWUNDODELETE_Type VT_I4
#define NOTIFYROWUNDOINSERT_Type VT_I4
#define NOTIFYROWUPDATE_Type VT_I4
#define NULLCOLLATION_Type VT_I4
#define OLEOBJECTS_Type VT_I4
#define ORDERBYCOLUMNSINSELECT_Type VT_BOOL
#define ORDEREDBOOKMARKS_Type VT_BOOL
#define OTHERINSERT_Type VT_BOOL
#define OTHERUPDATEDELETE_Type VT_BOOL
#define OUTPUTPARAMETERAVAILABILITY_Type VT_I4
#define OWNINSERT_Type VT_BOOL
#define OWNUPDATEDELETE_Type VT_BOOL
#define PERSISTENTIDTYPE_Type VT_I4
#define PREPAREABORTBEHAVIOR_Type VT_I4
#define PREPARECOMMITBEHAVIOR_Type VT_I4
#define PROCEDURETERM_Type VT_BSTR
#define PROVIDERNAME_Type VT_BSTR
#define PROVIDEROLEDBVER_Type VT_BSTR
#define PROVIDERVER_Type VT_BSTR
#define QUICKRESTART_Type VT_BOOL
#define QUOTEDIDENTIFIERCASE_Type VT_I4
#define REENTRANTEVENTS_Type VT_BOOL
#define REMOVEDELETED_Type VT_BOOL
#define REPORTMULTIPLECHANGES_Type VT_BOOL
#define RETURNPENDINGINSERTS_Type VT_BOOL
#define ROWRESTRICT_Type VT_BOOL
#define ROWSETCONVERSIONSONCOMMAND_Type VT_BOOL
#define ROWTHREADMODEL_Type VT_I4
#define SCHEMATERM_Type VT_BSTR
#define SCHEMAUSAGE_Type VT_I4
#define SERVERCURSOR_Type VT_BOOL
#define SESS_AUTOCOMMITISOLEVELS_Type VT_I4
#define SQLSUPPORT_Type VT_I4
#define STRONGIDENTITY_Type VT_BOOL
#define STRUCTUREDSTORAGE_Type VT_I4
#define SUBQUERIES_Type VT_I4
#define SUPPORTEDTXNDDL_Type VT_I4
#define SUPPORTEDTXNISOLEVELS_Type VT_I4
#define SUPPORTEDTXNISORETAIN_Type VT_I4
#define TABLETERM_Type VT_BSTR
#define TBL_TEMPTABLE_Type VT_BOOL
#define TRANSACTEDOBJECT_Type VT_BOOL
#define UPDATABILITY_Type VT_I4
#define USERNAME_Type VT_BSTR
#define ABORTPRESERVE_Value VARIANT_FALSE
#define ACTIVESESSIONS_Value 0
#define APPENDONLY_Value VARIANT_FALSE
#define ASYNCTXNABORT_Value VARIANT_FALSE
#define ASYNCTXNCOMMIT_Value VARIANT_FALSE
#define AUTH_CACHE_AUTHINFO_Value VARIANT_FALSE
#define AUTH_ENCRYPT_PASSWORD_Value VARIANT_FALSE
#define AUTH_INTEGRATED_Value OLESTR("")
#define AUTH_MASK_PASSWORD_Value VARIANT_FALSE
#define AUTH_PASSWORD_Value OLESTR("")
#define AUTH_PERSIST_ENCRYPTED_Value VARIANT_FALSE
#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Value VARIANT_FALSE
#define AUTH_USERID_Value OLESTR("")
#define BLOCKINGSTORAGEOBJECTS_Value VARIANT_FALSE
#define BOOKMARKS_Value VARIANT_FALSE
#define BOOKMARKSKIPPED_Value VARIANT_FALSE
#define BOOKMARKTYPE_Value 0
#define BYREFACCESSORS_Value VARIANT_FALSE
#define CACHEDEFERRED_Value VARIANT_FALSE
#define CANFETCHBACKWARDS_Value VARIANT_TRUE
#define CANHOLDROWS_Value VARIANT_TRUE
#define CANSCROLLBACKWARDS_Value VARIANT_TRUE
#define CATALOGLOCATION_Value 0
#define CATALOGTERM_Value OLESTR("")
#define CATALOGUSAGE_Value 0
#define CHANGEINSERTEDROWS_Value VARIANT_FALSE
#define COL_AUTOINCREMENT_Value VARIANT_FALSE
#define COL_DEFAULT_Value OLESTR("")
#define COL_DESCRIPTION_Value OLESTR("")
#define COL_FIXEDLENGTH_Value VARIANT_FALSE
#define COL_NULLABLE_Value VARIANT_FALSE
#define COL_PRIMARYKEY_Value VARIANT_FALSE
#define COL_UNIQUE_Value VARIANT_FALSE
#define COLUMNDEFINITION_Value 0
#define COLUMNRESTRICT_Value VARIANT_FALSE
#define COMMANDTIMEOUT_Value 0
#define COMMITPRESERVE_Value VARIANT_FALSE
#define CONCATNULLBEHAVIOR_Value 0
#define CURRENTCATALOG_Value OLESTR("")
#define DATASOURCENAME_Value OLESTR("")
#define DATASOURCEREADONLY_Value VARIANT_TRUE
#define DBMSNAME_Value OLESTR("")
#define DBMSVER_Value OLESTR("")
#define DEFERRED_Value VARIANT_FALSE
#define DELAYSTORAGEOBJECTS_Value VARIANT_FALSE
#define DSOTHREADMODEL_Value DBPROPVAL_RT_APTMTTHREAD
#define GROUPBY_Value 0
#define HETEROGENEOUSTABLES_Value 0
#define IAccessor_Value VARIANT_TRUE
#define IColumnsInfo_Value VARIANT_TRUE
#define IColumnsRowset_Value VARIANT_FALSE
#define IConnectionPointContainer_Value VARIANT_FALSE
#define IConvertType_Value VARIANT_TRUE
#define IRowset_Value VARIANT_TRUE
#define IRowsetChange_Value VARIANT_FALSE
#define IRowsetIdentity_Value VARIANT_TRUE
#define IRowsetIndex_Value VARIANT_FALSE
#define IRowsetInfo_Value VARIANT_TRUE
#define IRowsetLocate_Value VARIANT_FALSE
#define IRowsetResynch_Value VARIANT_FALSE
#define IRowsetScroll_Value VARIANT_FALSE
#define IRowsetUpdate_Value VARIANT_FALSE
#define ISupportErrorInfo_Value VARIANT_FALSE
#define ILockBytes_Value VARIANT_FALSE
#define ISequentialStream_Value VARIANT_FALSE
#define IStorage_Value VARIANT_FALSE
#define IStream_Value VARIANT_FALSE
#define IDENTIFIERCASE_Value 0
#define IMMOBILEROWS_Value VARIANT_FALSE
#define INDEX_AUTOUPDATE_Value VARIANT_FALSE
#define INDEX_CLUSTERED_Value VARIANT_FALSE
#define INDEX_FILLFACTOR_Value 0
#define INDEX_INITIALSIZE_Value 0
#define INDEX_NULLCOLLATION_Value 0
#define INDEX_NULLS_Value 0
#define INDEX_PRIMARYKEY_Value VARIANT_FALSE
#define INDEX_SORTBOOKMARKS_Value VARIANT_FALSE
#define INDEX_TEMPINDEX_Value VARIANT_FALSE
#define INDEX_TYPE_Value 0
#define INDEX_UNIQUE_Value VARIANT_FALSE
#define INIT_DATASOURCE_Value OLESTR("")
#define INIT_HWND_Value 0
#define INIT_IMPERSONATION_LEVEL_Value 0
#define INIT_LCID_Value 0
#define INIT_LOCATION_Value OLESTR("")
#define INIT_MODE_Value 0
#define INIT_PROMPT_Value VT_I2
#define INIT_PROTECTION_LEVEL_Value 0
#define INIT_PROVIDERSTRING_Value OLESTR("")
#define INIT_TIMEOUT_Value 0
#define LITERALBOOKMARKS_Value VARIANT_FALSE
#define LITERALIDENTITY_Value VARIANT_FALSE
#define MAXINDEXSIZE_Value 0
#define MAXOPENROWS_Value 0
#define MAXPENDINGROWS_Value 0
#define MAXROWS_Value 0
#define MAXROWSIZE_Value 0
#define MAXROWSIZEINCLUDESBLOB_Value VARIANT_FALSE
#define MAXTABLESINSELECT_Value 0
#define MAYWRITECOLUMN_Value VARIANT_FALSE
#define MEMORYUSAGE_Value 0
#define MULTIPLEPARAMSETS_Value VARIANT_FALSE
#define MULTIPLERESULTS_Value 0
#define MULTIPLESTORAGEOBJECTS_Value VARIANT_FALSE
#define MULTITABLEUPDATE_Value VARIANT_FALSE
#define NOTIFICATIONPHASES_Value 0
#define NOTIFYCOLUMNSET_Value 0
#define NOTIFYROWDELETE_Value 0
#define NOTIFYROWFIRSTCHANGE_Value 0
#define NOTIFYROWINSERT_Value 0
#define NOTIFYROWRESYNCH_Value 0
#define NOTIFYROWSETRELEASE_Value 0
#define NOTIFYROWSETFETCHPOSITIONCHANGE_Value 0
#define NOTIFYROWUNDOCHANGE_Value 0
#define NOTIFYROWUNDODELETE_Value 0
#define NOTIFYROWUNDOINSERT_Value 0
#define NOTIFYROWUPDATE_Value 0
#define NULLCOLLATION_Value 0
#define OLEOBJECTS_Value 0
#define ORDERBYCOLUMNSINSELECT_Value VARIANT_FALSE
#define ORDEREDBOOKMARKS_Value VARIANT_FALSE
#define OTHERINSERT_Value VARIANT_FALSE
#define OTHERUPDATEDELETE_Value VARIANT_FALSE
#define OUTPUTPARAMETERAVAILABILITY_Value 0
#define OWNINSERT_Value VARIANT_FALSE
#define OWNUPDATEDELETE_Value VARIANT_FALSE
#define PERSISTENTIDTYPE_Value 0
#define PREPAREABORTBEHAVIOR_Value 0
#define PREPARECOMMITBEHAVIOR_Value 0
#define PROCEDURETERM_Value OLESTR("")
#define PROVIDERNAME_Value OLESTR("")
#define PROVIDEROLEDBVER_Value OLESTR("2.0")
#define PROVIDERVER_Value OLESTR("")
#define QUICKRESTART_Value VARIANT_FALSE
#define QUOTEDIDENTIFIERCASE_Value 0
#define REENTRANTEVENTS_Value VARIANT_FALSE
#define REMOVEDELETED_Value VARIANT_FALSE
#define REPORTMULTIPLECHANGES_Value VARIANT_FALSE
#define RETURNPENDINGINSERTS_Value VARIANT_FALSE
#define ROWRESTRICT_Value VARIANT_FALSE
#define ROWSETCONVERSIONSONCOMMAND_Value VARIANT_TRUE
#define ROWTHREADMODEL_Value 0
#define SCHEMATERM_Value OLESTR("")
#define SCHEMAUSAGE_Value 0
#define SERVERCURSOR_Value VARIANT_FALSE
#define SESS_AUTOCOMMITISOLEVELS_Value 0
#define SQLSUPPORT_Value 0
#define STRONGIDENTITY_Value VARIANT_FALSE
#define STRUCTUREDSTORAGE_Value 0
#define SUBQUERIES_Value 0
#define SUPPORTEDTXNDDL_Value 0
#define SUPPORTEDTXNISOLEVELS_Value 0
#define SUPPORTEDTXNISORETAIN_Value 0
#define TABLETERM_Value OLESTR("")
#define TBL_TEMPTABLE_Value VARIANT_FALSE
#define TRANSACTEDOBJECT_Value VARIANT_FALSE
#define UPDATABILITY_Value 0
#define USERNAME_Value OLESTR("")
#define OUT_OF_LINE virtual
#define BEGIN_PROPSET_MAP(Class) \
static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL)) \ { \ typedef Class _PropSetClass; \ ULONG& cElemsMax = *pcElemPerSupported; \ cElemsMax = 0; \ int nCurProp = 0; \ int cRemainder = 0; \ cRemainder;
#define BEGIN_PROPERTY_SET_EX(guid, flags) \
if (pNumPropSets != NULL) \ { \ pSet[nCurProp].pPropSet = &guid; \ pSet[nCurProp].dwFlags = flags; \ } \ static const UPROPINFO aProperty##guid[] = \ {
#define BEGIN_PROPERTY_SET(guid) BEGIN_PROPERTY_SET_EX(guid, 0)
#define PROPERTY_INFO_ENTRY_EX(dwPropID, vt, dwFlags, value, options) DBPROP_##dwPropID, IDS_DBPROP_##dwPropID, vt, dwFlags, (DWORD_PTR)value, (DBPROPOPTIONS)options,
#define PROPERTY_INFO_ENTRY_VALUE(dwPropID, value) PROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, ##dwPropID##_Flags, value, 0)
#define PROPERTY_INFO_ENTRY(dwPropID) PROPERTY_INFO_ENTRY_VALUE(dwPropID, dwPropID##_Value)
#define END_PROPERTY_SET(guid) \
}; \ if (pNumPropSets != NULL) \ { \ pSet[nCurProp].pUPropInfo = (UPROPINFO*)aProperty##guid; \ pSet[nCurProp].cUPropInfo = sizeof(aProperty##guid) / sizeof(UPROPINFO); \ cRemainder = (pSet[nCurProp].cUPropInfo % 32) ? 1 : 0; \ if (cElemsMax < (pSet[nCurProp].cUPropInfo / 32 + cRemainder)) \ { \ cElemsMax = (pSet[nCurProp].cUPropInfo / 32 + cRemainder); \ } \ } \ nCurProp++;
#define CHAIN_PROPERTY_SET(ChainClass) \
ULONG cPropSets##ChainClass, cElsSupported##ChainClass; \ int cSets##ChainClass = (int)(DWORD_PTR)ChainClass::_GetPropSet(NULL, &cElsSupported##ChainClass); \ if (pNumPropSets != NULL) \ { \ UPROPSET* pSetA = (UPROPSET*)_alloca(sizeof(UPROPSET)*cSets##ChainClass); \ UPROPSET* pSetTemp = ChainClass::_GetPropSet(&cPropSets##ChainClass, &cElsSupported##ChainClass, pSetA); \ cElemsMax = (cElemsMax < cElsSupported##ChainClass) ? cElsSupported##ChainClass : cElemsMax; \ ATLASSERT(pSetTemp); \ for (ULONG iSet = nCurProp; iSet < nCurProp+cPropSets##ChainClass; iSet++) \ { \ pSet[iSet].pPropSet = pSetTemp[iSet-nCurProp].pPropSet; \ pSet[iSet].dwFlags = pSetTemp[iSet-nCurProp].dwFlags; \ pSet[iSet].pUPropInfo = pSetTemp[iSet-nCurProp].pUPropInfo; \ pSet[iSet].cUPropInfo = pSetTemp[iSet-nCurProp].cUPropInfo; \ } \ } \ nCurProp += cSets##ChainClass;
#define END_PROPSET_MAP() \
if (pNumPropSets != NULL) \ { \ if (IsEqualGUID(*pguidSet, GUID_NULL)) \ { \ *pNumPropSets = nCurProp; \ return pSet; \ } \ else \ { \ *pNumPropSets = 1; \ UINT i = 0; \ for (; i < sizeof(pSet)/sizeof(UPROPSET) && IsEqualGUID(*(pSet[i].pPropSet), *pguidSet); i++); \ return (i == sizeof(pSet)/sizeof(UPROPSET)) ? &pSet[0] : &pSet[i]; \ } \ } \ return (UPROPSET*)(DWORD_PTR)nCurProp; \ }
// For DataSource flags IDBInitialize::m_dwStatus
enum DATASOURCE_FLAGS { DSF_MASK_INIT = 0xFFFFF00F, // Mask for stuff lasting over init/uninit.
DSF_PERSIST_DIRTY = 0x00000001, // Set if init string changes.
DSF_INITIALIZED = 0x00000010, // Have we been initialized.
};
#define DBID_USE_GUID_OR_PGUID(e) \
((1<<(e)) & \ ( 1<<DBKIND_GUID \ | 1<<DBKIND_GUID_NAME \ | 1<<DBKIND_GUID_PROPID \ | 1<<DBKIND_PGUID_NAME \ | 1<<DBKIND_PGUID_PROPID ))
#define DBID_USE_GUID(e) \
((1<<(e)) & \ ( 1<<DBKIND_GUID \ | 1<<DBKIND_GUID_NAME \ | 1<<DBKIND_GUID_PROPID ))
#define DBID_USE_PGUID(e) \
((1<<(e)) & \ ( 1<<DBKIND_PGUID_NAME \ | 1<<DBKIND_PGUID_PROPID ))
#define DBID_USE_NAME(e) \
((1<<(e)) & \ ( 1<<DBKIND_NAME \ | 1<<DBKIND_GUID_NAME \ | 1<<DBKIND_PGUID_NAME ))
#define DBID_USE_PROPID(e) \
((1<<(e)) & \ ( 1<<DBKIND_PROPID \ | 1<<DBKIND_GUID_PROPID \ | 1<<DBKIND_PGUID_PROPID ))
// Bookmark can be either guid or pguid.
#define DBID_IS_BOOKMARK(dbid) \
( DBID_USE_GUID(dbid.eKind) && dbid.uGuid.guid == DBCOL_SPECIALCOL \ || DBID_USE_PGUID(dbid.eKind) && *dbid.uGuid.pguid == DBCOL_SPECIALCOL )
#define DivDword(dw) (dw >> 5) // dw / 32 = dw / (sizeof(DWORD)*8)
#define ModDword(dw) (dw & (32-1)) // dw % 32
#define DwordSizeofBits(nBits) (nBits/32+1) // Use in array declarations
#define CLEARBITARRAY( rgdwFlags ) memset( rgdwFlags, 0, sizeof(rgdwFlags) )
template <class T> BOOL InRange(T& val, T& valMin, T& valMax) { return ( valMin <= val && val <= valMax ); } // Implementation Class
class CBitFieldOps { public: void SETBIT( DWORD rgdwFlags[], const DWORD dwBit ) { rgdwFlags[DivDword(dwBit)] |= 1 << ModDword(dwBit); }
void CLEARBIT( DWORD rgdwFlags[], const DWORD dwBit ) { rgdwFlags[DivDword(dwBit)] &= ~( 1 << ModDword(dwBit) ); }
DWORD TESTBIT( const DWORD rgdwFlags[], const DWORD dwBit ) { //old//Note: Not {0,1}, but from {0...2^32-1}.
// Note: Now returns {0,1}.
return ( rgdwFlags[DivDword(dwBit)] & ( 1 << ModDword(dwBit) ) ) != 0; } };
// Implementation Class
class CDBIDOps { public: HRESULT CompareDBIDs(const DBID* pdbid1, const DBID* pdbid2) { // Array of valid eKind matches, in addition to matching exactly.
static BYTE s_rgbKind[] = { DBKIND_PGUID_NAME, // DBKIND_GUID_NAME
DBKIND_PGUID_PROPID, // DBKIND_GUID_PROPID
DBKIND_NAME, // DBKIND_NAME
DBKIND_GUID_NAME, // DBKIND_PGUID_NAME
DBKIND_GUID_PROPID, // DBKIND_PGUID_PROPID
DBKIND_PROPID, // DBKIND_PROPID
DBKIND_GUID // DBKIND_GUID
};
if( !pdbid1 || !pdbid2 ) return S_FALSE;
// Assume a match, and discard early if we can.
if (!InRange(pdbid2->eKind, (DWORD)0, (DWORD)(sizeof(s_rgbKind)/sizeof(*s_rgbKind)))) { ATLTRACE2(atlTraceDBProvider, 0, "Column ID out of Range\n"); return E_FAIL; } if (pdbid1->eKind != pdbid2->eKind && pdbid1->eKind != s_rgbKind[pdbid2->eKind]) return S_FALSE;
if (DBID_USE_GUID_OR_PGUID(pdbid1->eKind)) { if (!DBID_USE_GUID_OR_PGUID(pdbid2->eKind)) return S_FALSE; // Compare GUIDs.
// Note that _GUID_ is equivalent to _PGUID_.
if (!InlineIsEqualGUID( DBID_USE_PGUID(pdbid1->eKind) ? *(pdbid1->uGuid.pguid) : pdbid1->uGuid.guid, DBID_USE_PGUID(pdbid2->eKind) ? *(pdbid2->uGuid.pguid) : pdbid2->uGuid.guid )) return S_FALSE; } if (DBID_USE_NAME(pdbid1->eKind)) { if (!DBID_USE_NAME(pdbid2->eKind)) return S_FALSE; // Compare names.
// Need to check if 1 is null and the other is not.
if ( ((pdbid1->uName.pwszName == NULL) && (pdbid2->uName.pwszName != NULL)) || ((pdbid1->uName.pwszName != NULL) && (pdbid2->uName.pwszName == NULL)) ) return S_FALSE; // Since the above check does not rule out both being null, which is
// a valid comparison, and wcscmp will GPF if they were, we need
// to check for valid pointers
if( pdbid1->uName.pwszName && pdbid2->uName.pwszName ) { // Assume null-terminated.
// Assume LCID match is OK (note diff with lstrcmp(), CompareString().)
if (wcscmp(pdbid1->uName.pwszName, pdbid2->uName.pwszName) != 0) return S_FALSE; } } if (DBID_USE_PROPID(pdbid1->eKind)) { if (!DBID_USE_PROPID(pdbid2->eKind)) return S_FALSE; // Compare PROPID.
if (pdbid1->uName.ulPropid != pdbid2->uName.ulPropid) return S_FALSE; }
// No reason to discard, so must have matched each field successfully.
return S_OK; }
static HRESULT IsValidDBID(const DBID* pdbid1) { ATLASSERT( pdbid1 );
if( pdbid1 && ((pdbid1->eKind == DBKIND_GUID_NAME) || (pdbid1->eKind == DBKIND_GUID_PROPID) || (pdbid1->eKind == DBKIND_NAME) || (pdbid1->eKind == DBKIND_PGUID_NAME) || (pdbid1->eKind == DBKIND_PGUID_PROPID) || (pdbid1->eKind == DBKIND_PROPID) || (pdbid1->eKind == DBKIND_GUID)) ) return S_OK; else return S_FALSE; } HRESULT CopyDBIDs(DBID* pdbidDest, const DBID* pdbidSrc) { size_t cwchBuffer;
ATLASSERT( pdbidDest || pdbidSrc );
if( !pdbidDest || !pdbidSrc ) return S_FALSE;
// Save eKind
pdbidDest->eKind = pdbidSrc->eKind;
switch( pdbidSrc->eKind ) {
case DBKIND_GUID_NAME: pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid; cwchBuffer = ocslen(pdbidSrc->uName.pwszName); cwchBuffer++; pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR)); if( pdbidDest->uName.pwszName ) memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR)); else return E_OUTOFMEMORY; break;
case DBKIND_GUID_PROPID: pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid; pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid; break; case DBKIND_NAME: cwchBuffer = ocslen(pdbidSrc->uName.pwszName); cwchBuffer++; pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR)); if( pdbidDest->uName.pwszName ) memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR)); else return E_OUTOFMEMORY; break; case DBKIND_PGUID_NAME: pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID)); if( pdbidDest->uGuid.pguid ) { *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid); cwchBuffer = ocslen(pdbidSrc->uName.pwszName); cwchBuffer++; pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR)); if( pdbidDest->uName.pwszName ) { memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR)); break; } else { CoTaskMemFree(pdbidDest->uGuid.pguid); pdbidDest->uGuid.pguid = NULL; } } return E_OUTOFMEMORY; case DBKIND_PGUID_PROPID: pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID)); if( pdbidDest->uGuid.pguid ) *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid); else return E_OUTOFMEMORY; pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid; break; case DBKIND_PROPID: pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid; break; case DBKIND_GUID: pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid; break; default: ATLASSERT(L"Unhandled dbid1.ekind"); return S_FALSE; }
return S_OK; } static GUID* GetDBIDpGuid(DBID& dbid) { GUID* pGuid; switch (dbid.eKind) { case DBKIND_PGUID_NAME: case DBKIND_PGUID_PROPID: pGuid = dbid.uGuid.pguid; break; case DBKIND_GUID_NAME: case DBKIND_GUID_PROPID: case DBKIND_GUID: pGuid = &(dbid.uGuid.guid); break; default: pGuid = NULL; }
return pGuid; } static ULONG GetPropIDFromDBID(DBID& dbid) { switch (dbid.eKind) { case DBKIND_GUID_PROPID: case DBKIND_PGUID_PROPID: case DBKIND_PROPID: return dbid.uName.ulPropid; default: return 0; } } void FreeDBIDs(DBID* pdbidSrc) { switch( pdbidSrc->eKind ) {
case DBKIND_GUID_NAME: CoTaskMemFree(pdbidSrc->uName.pwszName); break; case DBKIND_NAME: CoTaskMemFree(pdbidSrc->uName.pwszName); break; case DBKIND_PGUID_NAME: CoTaskMemFree(pdbidSrc->uGuid.pguid); CoTaskMemFree(pdbidSrc->uName.pwszName); break; case DBKIND_PGUID_PROPID: CoTaskMemFree(pdbidSrc->uGuid.pguid); break; case DBKIND_GUID_PROPID: case DBKIND_PROPID: case DBKIND_GUID: break; default: ATLASSERT(L"Unhandled dbid1.ekind"); break; } } };
extern "C" const CLSID CLSID_DataConvert;
class CConvertHelper { public: CConvertHelper() {} HRESULT FinalConstruct() { HRESULT hr = ::CoCreateInstance(CLSID_DataConvert, NULL, CLSCTX_INPROC_SERVER, IID_IDataConvert, (void**)&m_spConvert);
if (FAILED(hr)) return hr;
// Check to see if the data conversion routine is 2.0 capable, if so. Initialize
// the conversion routine to be 2.0.
DCINFO rgInfo[] = {{DCINFOTYPE_VERSION, {VT_UI4, 0, 0, 0, 0x0}}}; CComPtr<IDCInfo> spIDCInfo;
hr = m_spConvert->QueryInterface(&spIDCInfo); if (hr == S_OK) { V_UI4(&rgInfo->vData) = 0x200; // OLEDB Version 02.00
spIDCInfo->SetInfo(1, rgInfo); }
return hr; } CComPtr<IDataConvert> m_spConvert; };
// IDBCreateSessionImpl
template <class T, class SessionClass> class ATL_NO_VTABLE IDBCreateSessionImpl : public IDBCreateSession { public: STDMETHOD(CreateSession)(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppDBSession) { ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession\n"); if (ppDBSession == NULL) return E_INVALIDARG; T* pT = (T*)this; if (!(pT->m_dwStatus & DSF_INITIALIZED)) { ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession : Error not initialized\n"); *ppDBSession = NULL; return E_UNEXPECTED; } CComPolyObject<SessionClass> *pSession;
// You can't QI for an interface other than IUnknown when aggregating
// and creating the object. You might ask for your own interface,
// which would be bad. Note, we return DB_E_NOAGGREGATION instead of
// CLASS_E_NOAGGREGATION due to OLE DB constraints.
if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid)) return DB_E_NOAGGREGATION;
HRESULT hr = CComPolyObject<SessionClass>::CreateInstance(pUnkOuter, &pSession); if (SUCCEEDED(hr)) { CComPtr<IObjectWithSite> spCreator; hr = pSession->QueryInterface(IID_IObjectWithSite, (void**)&spCreator); if (SUCCEEDED(hr)) { spCreator->SetSite(this); hr = pSession->QueryInterface(riid, (void**)ppDBSession); } else delete pSession; } return hr; } };
// IDBInitializeImpl
template <class T> class ATL_NO_VTABLE IDBInitializeImpl : public IDBInitialize { public: IDBInitializeImpl() { m_dwStatus = 0; m_pCUtlPropInfo = NULL; m_cSessionsOpen = 0; } ~IDBInitializeImpl() { delete m_pCUtlPropInfo; }
STDMETHOD(Uninitialize)(void) { ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Uninitialize\n"); T* pT = (T*)this; pT->Lock(); if (pT->m_cSessionsOpen != 0) { ATLTRACE2(atlTraceDBProvider, 0, "Uninitialized called with Open Sessions\n"); return DB_E_OBJECTOPEN; } delete m_pCUtlPropInfo; m_pCUtlPropInfo = NULL; pT->m_dwStatus |= DSF_PERSIST_DIRTY; pT->m_dwStatus &= DSF_MASK_INIT; // Clear all non-init flags.
pT->Unlock(); return S_OK;
}
LONG m_cSessionsOpen; DWORD m_dwStatus; CUtlPropInfo<T>* m_pCUtlPropInfo;
STDMETHOD(Initialize)(void) {
ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize\n"); T *pT = (T*)(this); T::ObjectLock lock(pT); HRESULT hr; if (pT->m_dwStatus & DSF_INITIALIZED) { ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : Already Initialized\n"); return DB_E_ALREADYINITIALIZED; } delete m_pCUtlPropInfo; m_pCUtlPropInfo = NULL; ATLTRY(m_pCUtlPropInfo = new CUtlPropInfo<T>()) if (m_pCUtlPropInfo == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : OOM\n"); return E_OUTOFMEMORY; } hr = m_pCUtlPropInfo->FInit(); if (hr == S_OK) { pT->m_dwStatus |= DSF_INITIALIZED; } else { delete m_pCUtlPropInfo; m_pCUtlPropInfo = NULL; } return hr; }
};
// Implementation Class
class CPropColID : public PROPCOLID, public CDBIDOps { public: CPropColID() { VariantInit(&vValue); } ~CPropColID() { FreeDBIDs(&dbidProperty); VariantClear(&vValue); } bool operator==(const CPropColID& colId) { return (CompareDBIDs(&dbidProperty, &(colId.dbidProperty)) == S_OK) ? true : false; }
};
class CColumnIds : public CDBIDOps, public CSimpleArray<CPropColID>
{ public: PPROPCOLID AddNode() { CPropColID colID; if (Add(colID)) return &(m_aT[GetSize()]); return NULL; } HRESULT RemoveColumnId(const DBID* pdbidProp) { for (int i = 0; i < GetSize(); i++) { if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK) return (RemoveAt(i)) ? S_OK : E_FAIL; }
return E_FAIL; } HRESULT AddColumnId(DBPROP* pProp) { CPropColID colID; HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pProp->colid)); if(FAILED(hr)) return hr; colID.dwOption = pProp->dwOptions; hr = VariantCopy(&(colID.vValue),&(pProp->vValue)); if(FAILED(hr)) return hr; return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
} HRESULT AddColumnId(PPROPCOLID pPropNode) { CPropColID colID; HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pPropNode->dbidProperty)); if(FAILED(hr)) return hr; colID.dwOption = pPropNode->dwOption; hr = VariantCopy(&(colID.vValue),&(pPropNode->vValue)); if(FAILED(hr)) return hr; return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
} ULONG GetCountOfPropColids(){ return (ULONG)GetSize();} PPROPCOLID FindColumnId(const DBID* pdbidProp) { for (int i = 0; i < GetSize(); i++) { if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK) return &(m_aT[i]); }
return NULL; } HRESULT GetValue(int iColId, DWORD* pdwOptions, DBID* pColid, VARIANT* pvValue) { HRESULT hr;
ATLASSERT(pdwOptions && pColid && pvValue); ATLASSERT(iColId >= 0 && iColId < m_nSize);
CPropColID& colId = m_aT[iColId]; *pdwOptions = colId.dwOption; CopyDBIDs( pColid, &(colId.dbidProperty) ); if(FAILED(hr = VariantCopy(pvValue, &(colId.vValue)))) return hr; return S_OK; } };
const ULONG cchDescBuffSize = 256; const DWORD DBINTERNFLAGS_CHANGED = 0x00000001; // Rules for GetPropertiesArgChk
const DWORD ARGCHK_PROPERTIESINERROR = 0x00000001;
// Implementation Class
template <class T> class CUtlPropInfo : public CBitFieldOps, public CDBIDOps { public: enum EnumGetPropInfo { GETPROPINFO_ALLPROPIDS = 0x0001, GETPROPINFO_NOTSUPPORTED = 0x0002, GETPROPINFO_ERRORSOCCURRED = 0x0004, GETPROPINFO_VALIDPROP = 0x0008 };
CUtlPropInfo() { m_cUPropSet = 0; m_pUPropSet = NULL;
m_cPropSetDex = 0; m_rgiPropSetDex = NULL;
m_cElemPerSupported = 0; m_rgdwSupported = NULL; } ~CUtlPropInfo() { delete[] m_rgiPropSetDex; delete[] m_rgdwSupported; if (m_pUPropSet != NULL) CoTaskMemFree(m_pUPropSet); }
//Determine the number of description buffers needed
ULONG CalcDescripBuffers(ULONG cPropInfoSet, DBPROPINFOSET* pPropInfoSet) { ULONG cBuffers = 0;
ATLASSERT(m_pUPropSet); ATLASSERT(cPropInfoSet && pPropInfoSet);
for(ULONG ulSet=0; ulSet<cPropInfoSet; ulSet++) { if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK) { for(ULONG ul=0; ul<m_cPropSetDex; ul++) { cBuffers += m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo; } } }
return cBuffers; } //Retrieve the property set indexes that match this property set.
HRESULT GetPropertySetIndex(const GUID* pPropertySet) { DWORD dwFlag = 0; ULONG ulSet;
ATLASSERT(m_cUPropSet && m_pUPropSet); ATLASSERT(m_rgiPropSetDex); ATLASSERT(pPropertySet);
m_cPropSetDex = 0;
if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEALL)) { dwFlag = DBPROPFLAGS_DATASOURCE; } else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEINFOALL)) { dwFlag = DBPROPFLAGS_DATASOURCEINFO; } else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_ROWSETALL)) { dwFlag = DBPROPFLAGS_ROWSET; } else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_DBINITALL)) { dwFlag = DBPROPFLAGS_DBINIT; } else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_SESSIONALL)) { dwFlag = DBPROPFLAGS_SESSION; } else // No scan required, just look for match.
{ for(ulSet=0; ulSet<m_cUPropSet; ulSet++) { if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet ) { m_rgiPropSetDex[m_cPropSetDex] = ulSet; m_cPropSetDex++; break; } } goto EXIT; }
// Scan through the property sets looking for matching attributes
for(ulSet=0; ulSet<m_cUPropSet; ulSet++) { if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag ) { m_rgiPropSetDex[m_cPropSetDex] = ulSet; m_cPropSetDex++; } }
EXIT: return (m_cPropSetDex) ? S_OK : S_FALSE;
} //Retrieve the property id pointer
HRESULT GetUPropInfoPtr(ULONG iPropSetDex, DBPROPID dwPropertyId, UPROPINFO** ppUPropInfo) { // Scan through the property sets looking for matching attributes
for(ULONG ulProps=0; ulProps<m_pUPropSet[iPropSetDex].cUPropInfo; ulProps++) { if( m_pUPropSet[iPropSetDex].pUPropInfo[ulProps].dwPropId == dwPropertyId ) { *ppUPropInfo = &(m_pUPropSet[iPropSetDex].pUPropInfo[ulProps]); // Test to see if the property is supported for this
// instantiation
return (TESTBIT(&(m_rgdwSupported[iPropSetDex * m_cElemPerSupported]), ulProps)) ? S_OK : S_FALSE; } } return S_FALSE; } HRESULT FInit(GUID* pguidSet = (GUID*)&GUID_NULL) { HRESULT hr;
hr = InitAvailUPropSets(&m_cUPropSet, &m_pUPropSet, &m_cElemPerSupported, pguidSet); if (FAILED(hr)) return hr; ATLASSERT((m_cUPropSet != 0) && (m_cElemPerSupported != 0)); if(!m_cUPropSet || !m_cElemPerSupported) return E_FAIL;
ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported]) if(m_rgdwSupported == NULL) return E_OUTOFMEMORY;
if(FAILED(hr = InitUPropSetsSupported())) { delete[] m_rgdwSupported; m_rgdwSupported = NULL; return hr; } if(m_cUPropSet) { ATLTRY(m_rgiPropSetDex = new ULONG[m_cUPropSet]) if(m_rgiPropSetDex == NULL) { delete [] m_rgdwSupported; return E_OUTOFMEMORY; } } return S_OK; } HRESULT GetPropertyInfo(ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], ULONG* pcPropertyInfoSets, DBPROPINFOSET** prgPropertyInfoSets, WCHAR** ppDescBuffer, bool bInitialized = true, const GUID* pGuid = NULL) { HRESULT hr = S_OK; ULONG ul, ulSet, ulNext, ulEnd; ULONG ulOutIndex; ULONG cSets; ULONG cPropInfos; ULONG ulIndex = 0; DWORD dwStatus = 0; DBPROPINFO* pPropInfo = NULL; DBPROPINFO* pCurPropInfo = NULL; WCHAR* pDescBuffer = NULL; DBPROPINFOSET* pPropInfoSet = NULL; UPROPINFO* pUPropInfo = NULL; WCHAR wszBuff[256]; int cch;
// If the consumer does not restrict the property sets
// by specify an array of property sets and a cPropertySets
// greater than 0, then we need to make sure we
// have some to return
if(cPropertySets == 0) { // Determine the number of property sets supported
// In this case, it usually the enumerator or data source asking for
// DBPROPSET_DBINIT information.
if (pGuid != NULL) cSets = 1; else cSets = m_cUPropSet; } else { cSets = 0;
// Determine number of property sets required
// This is only required when any of the "special" property set GUIDs were specified
for(ulSet=0; ulSet<cPropertySets; ulSet++) { if (GetPropertySetIndex(&(rgPropertySets[ulSet].guidPropertySet)) == S_OK) cSets += m_cPropSetDex; else cSets++; } } ATLASSERT(cSets);
// Allocate the DBPROPINFOSET structures
pPropInfoSet = (DBPROPINFOSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPINFOSET)); if(pPropInfoSet == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n"); hr = E_OUTOFMEMORY; goto EXIT; }
memset(pPropInfoSet, 0, cSets * sizeof(DBPROPINFOSET));
ulOutIndex = 0; // VC 6.0 ulEnd = cPropertySets == 0 ? cSets : cPropertySets;
ulEnd = cSets; // VC 6.0 SP3
// Fill in the output array
for(ulSet=0; ulSet<ulEnd; ulSet++) { // Depending of if Property sets are specified store the
// return property set.
if (cPropertySets == 0) { if (pGuid != NULL) { GUID const& guidSet = *pGuid; if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) || InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) || InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) || InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) || InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) && GetPropertySetIndex(&guidSet) == S_OK ) { for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++) { pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet); pPropInfoSet[ulOutIndex].cPropertyInfos = 0; ulIndex = m_rgiPropSetDex[ul]; } } else { for (ULONG l=0; l<m_cUPropSet; l++) { if (InlineIsEqualGUID(*m_pUPropSet[l].pPropSet, *pGuid)) ulIndex = l; }
if (l == m_cUPropSet) { ATLTRACE2(atlTraceDBProvider, 0, "Property Info Set not supported"); ulIndex = 0; } pPropInfoSet[ulSet].guidPropertySet = *pGuid; } } else { pPropInfoSet[ulSet].guidPropertySet = *(m_pUPropSet[ulSet].pPropSet); } } else { GUID const& guidSet = rgPropertySets[ulSet].guidPropertySet; if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) || InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) || InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) || InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) || InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) && GetPropertySetIndex(&guidSet) == S_OK ) { for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++) { pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet); pPropInfoSet[ulOutIndex].cPropertyInfos = 0; } } else { // Handle non-category property sets
// Handle unknown property sets
pPropInfoSet[ulOutIndex].guidPropertySet = guidSet; pPropInfoSet[ulOutIndex].cPropertyInfos = rgPropertySets[ulSet].cPropertyIDs; ulOutIndex++; } } }
// Allocate a Description Buffer if needed
if( ppDescBuffer ) { ULONG cBuffers = CalcDescripBuffers(cSets, pPropInfoSet); if( cBuffers != 0 ) { pDescBuffer = (WCHAR*)CoTaskMemAlloc(cBuffers * cchDescBuffSize * sizeof(WCHAR)); if(pDescBuffer == NULL) { hr = E_OUTOFMEMORY; goto EXIT; } *ppDescBuffer = pDescBuffer; memset(pDescBuffer, 0, (cBuffers * cchDescBuffSize * sizeof(WCHAR))); } }
// Process requested or derived Property sets
dwStatus = 0; for(ulSet=0; ulSet<cSets; ulSet++) { ulNext=0; cPropInfos = 0; pPropInfo = NULL; dwStatus &= (GETPROPINFO_ERRORSOCCURRED | GETPROPINFO_VALIDPROP);
// Calculate the number of property nodes needed for this
// property set.
if( cPropertySets == 0 ) { ULONG ulTempSet; if (pGuid != NULL) ulTempSet = ulIndex; else ulTempSet = ulSet;
cPropInfos = m_pUPropSet[ulTempSet].cUPropInfo; dwStatus |= GETPROPINFO_ALLPROPIDS; m_rgiPropSetDex[0] = ulTempSet; m_cPropSetDex = 1; } else { // If the count of PROPIDs is 0 (NOTE: the above routine already determined
// if it belonged to a category and if so set the count of properties to 0 for
// each propset in that category.
if( pPropInfoSet[ulSet].cPropertyInfos == 0 ) { dwStatus |= GETPROPINFO_ALLPROPIDS; // We have to determine if the property set is supported and if so
// the count of properties in the set.
if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK) { ATLASSERT( m_cPropSetDex == 1 );
cPropInfos += m_pUPropSet[m_rgiPropSetDex[0]].cUPropInfo; } else { // Not Supported
dwStatus |= GETPROPINFO_ERRORSOCCURRED; goto NEXT_SET; } } else { // We also handle the case here where the user has requested
// a non-initialization group property info set while the
// provider is not initialized. In this case, properties should
// not be set.
cPropInfos = pPropInfoSet[ulSet].cPropertyInfos; if( (GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_FALSE) || (!bInitialized && !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINIT)) && !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINITALL)))) { dwStatus |= GETPROPINFO_NOTSUPPORTED; dwStatus |= GETPROPINFO_ERRORSOCCURRED; } } }
// Allocate DBPROP array
ATLASSERT( cPropInfos != 0 ); pPropInfo = (DBPROPINFO*)CoTaskMemAlloc(cPropInfos * sizeof(DBPROPINFO)); if( pPropInfo ) { // Initialize Buffer
memset(pPropInfo, 0, cPropInfos * sizeof(DBPROPINFO)); for(ULONG ulProp=0; ulProp<cPropInfos; ulProp++) { VariantInit(&(pPropInfo[ulProp].vValues)); if( dwStatus & GETPROPINFO_NOTSUPPORTED ) { // Not supported, thus we need to mark all as NOT_SUPPORTED
pPropInfo[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp]; pPropInfo[ulProp].dwFlags = DBPROPFLAGS_NOTSUPPORTED; dwStatus |= GETPROPINFO_ERRORSOCCURRED; } } // Make sure we support the property set
if( dwStatus & GETPROPINFO_NOTSUPPORTED ) { ulNext = cPropInfos; goto NEXT_SET; }
// Retrieve the property information for this property set
for(ul=0; ul<m_cPropSetDex; ul++) { pUPropInfo = (m_pUPropSet[m_rgiPropSetDex[ul]].pUPropInfo); ATLASSERT( pUPropInfo );
// Retrieve current value of properties
if( dwStatus & GETPROPINFO_ALLPROPIDS ) { for(ulProp=0; ulProp<m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo; ulProp++) { // Verify property is supported, if not do not return
if( !TESTBIT(&(m_rgdwSupported[m_rgiPropSetDex[ul] * m_cElemPerSupported]), ulProp) ) continue;
pCurPropInfo = &(pPropInfo[ulNext]);
// If the ppDescBuffer pointer was not NULL, then
// we need supply description of the properties
if( ppDescBuffer ) { // Set Buffer pointer
pCurPropInfo->pwszDescription = pDescBuffer;
// Load the string into temp buffer
cch = LoadDescription(pUPropInfo[ulProp].ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff))); if( cch ) { // Adjust for '\0'
cch++;
// Transfer to official buffer if room
memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR)); pDescBuffer += cch; } else { wcscpy(pDescBuffer, L"UNKNOWN"); pDescBuffer += (wcslen(L"UNKNOWN") + 1); } }
pCurPropInfo->dwPropertyID = pUPropInfo[ulProp].dwPropId; pCurPropInfo->dwFlags = pUPropInfo[ulProp].dwFlags; pCurPropInfo->vtType = pUPropInfo[ulProp].VarType; pCurPropInfo->vValues.vt = VT_EMPTY;
dwStatus |= GETPROPINFO_VALIDPROP; // Increment to next available buffer
ulNext++; } } else { ATLASSERT( m_cPropSetDex == 1 );
for( ulProp = 0; ulProp < cPropInfos; ulProp++, ulNext++ ) { pCurPropInfo = &(pPropInfo[ulNext]);
// Process Properties based on Restriction array.
pCurPropInfo->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
if( GetUPropInfoPtr(m_rgiPropSetDex[ul], pCurPropInfo->dwPropertyID, &pUPropInfo) == S_OK ) { // If the ppDescBuffer pointer was not NULL, then
// we need supply description of the properties
if( ppDescBuffer ) { // Set Buffer pointer
pCurPropInfo->pwszDescription = pDescBuffer;
// Load the string into temp buffer
cch = LoadDescription(pUPropInfo->ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff))); if( cch ) { // Adjust for '\0'
cch++;
// Transfer to official buffer if room
memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR)); pDescBuffer += cch; } else { wcscpy(pDescBuffer, L"UNKNOWN"); pDescBuffer += (wcslen(L"UNKNOWN") + 1); } }
pCurPropInfo->dwPropertyID = pUPropInfo->dwPropId; pCurPropInfo->dwFlags = pUPropInfo->dwFlags; pCurPropInfo->vtType = pUPropInfo->VarType;
dwStatus |= GETPROPINFO_VALIDPROP; } else { // Not Supported
pCurPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED; dwStatus |= GETPROPINFO_ERRORSOCCURRED; } } } } } else { hr = E_OUTOFMEMORY; goto EXIT; }
NEXT_SET: pPropInfoSet[ulSet].cPropertyInfos = ulNext; pPropInfoSet[ulSet].rgPropertyInfos = pPropInfo; }
// Success, set return values
*pcPropertyInfoSets = cSets; *prgPropertyInfoSets = pPropInfoSet;
// At least one propid was marked as not S_OK
if( dwStatus & GETPROPINFO_ERRORSOCCURRED ) { // If at least 1 property was set
if( dwStatus & GETPROPINFO_VALIDPROP ) return DB_S_ERRORSOCCURRED; else { // Do not free any of the rgPropertyInfoSets, but
// do free the ppDescBuffer
if( pDescBuffer ) { ATLASSERT( ppDescBuffer ); CoTaskMemFree(pDescBuffer); *ppDescBuffer = NULL; } return DB_E_ERRORSOCCURRED; } }
return S_OK; EXIT: // Check if failure and clean up any allocated memory
if( FAILED(hr) && (hr != DB_E_ERRORSOCCURRED) ) { // Free Description Buffer
if( pDescBuffer ) { ATLASSERT( ppDescBuffer );
CoTaskMemFree(pDescBuffer); *ppDescBuffer = NULL; }
if( pPropInfoSet ) { // Loop through Property Sets
for(ulSet=0; ulSet<cSets; ulSet++) { if( pPropInfoSet[ulSet].rgPropertyInfos ) CoTaskMemFree(pPropInfoSet[ulSet].rgPropertyInfos); }
CoTaskMemFree(pPropInfoSet); } }
return hr; }
ULONG m_cUPropSet; //count of UPropSet items
UPROPSET* m_pUPropSet; //Pointer to UPropset items
ULONG m_cPropSetDex; //count of UPropSet Indexes
ULONG* m_rgiPropSetDex;//array of UPropSet Index values
ULONG m_cElemPerSupported; //number of DWORDS per UPropSet to indicate supported UPropIds
DWORD* m_rgdwSupported;//array of DWORDs indicating supported UPropIds
HRESULT InitAvailUPropSets(ULONG* pcUPropSet, UPROPSET** ppUPropSet, ULONG* pcElemPerSupported, GUID* pguid) { ATLASSERT(pcUPropSet && ppUPropSet); if (*ppUPropSet != NULL) { CoTaskMemFree(*ppUPropSet); *ppUPropSet = NULL; } int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, pcElemPerSupported); UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets); if (pSet == NULL) return E_OUTOFMEMORY; *ppUPropSet = T::_GetPropSet(pcUPropSet, pcElemPerSupported, pSet, pguid); return S_OK; } virtual HRESULT InitUPropSetsSupported() { ULONG cPropSet = 0, cElemsPerSupported = 0; int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, &cElemsPerSupported); UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets); if (pSet == NULL) return E_OUTOFMEMORY; pSet = T::_GetPropSet(&cPropSet, &cElemsPerSupported, pSet); memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD)); CoTaskMemFree(pSet); return S_OK; } //Load a localized description
int LoadDescription(ULONG ids, PWSTR pwszBuff, ULONG cchBuff) { USES_CONVERSION; TCHAR* pszBuf = (TCHAR*)_alloca(cchBuff * sizeof(TCHAR)); if (pszBuf == NULL) return 0; int nTemp = LoadString(_pModule->GetResourceInstance(), ids, pszBuf, cchBuff); wcscpy(pwszBuff, T2W(pszBuf)); return nTemp; } };
class ATL_NO_VTABLE CUtlPropsBase : public CBitFieldOps, public CDBIDOps { public:
ULONG m_cUPropSet; //count of UPropSet items
UPROPSET* m_pUPropSet; //Pointer to UPropset items
UPROP* m_pUProp; ULONG m_cUPropSetHidden; //Count of Hidden items
DWORD m_dwFlags; //Configuration flags
ULONG m_cPropSetDex; //count of UPropSet Indexes
ULONG* m_rgiPropSetDex; //pointer to Array of UPropSet Index values
ULONG m_cElemPerSupported;//number of DWORDS per UPropSet to indicate supported UPropIds
DWORD* m_rgdwSupported; //pointer to array of DWORDs indicating supported UPropIds
DWORD* m_rgdwPropsInError;//pointer to array of DWORDs indicating if property is in error
enum EnumUPropSetFlags { UPROPSET_HIDDEN = 0x00000001, UPROPSET_PASSTHROUGH = 0x00000002 }; enum EnumGetProp { GETPROP_ALLPROPIDS = 0x0001, GETPROP_NOTSUPPORTED = 0x0002, GETPROP_ERRORSOCCURRED = 0x0004, GETPROP_VALIDPROP = 0x0008, GETPROP_PROPSINERROR = 0x0010 };
enum EnumSetProp { SETPROP_BADOPTION = 0x0001, SETPROP_NOTSUPPORTED = 0x0002, SETPROP_VALIDPROP = 0x0004, SETPROP_ERRORS = 0x0008, SETPROP_COLUMN_LEVEL = 0x0010, SETPROP_WAS_REQUIRED = 0x0020 };
HRESULT SetPassThrough(const DBPROPSET* pPropSet) { ATLASSERT(pPropSet);
DBPROP* pProp = pPropSet->rgProperties;
//Default implementation just sets all properties as NOTSUPPORTED
for( ULONG ul=0; ul<pPropSet->cProperties; ul++, pProp++ ) pProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
return DB_E_ERRORSOCCURRED; }
HRESULT GetIndexofPropIdinPropSet(ULONG iCurSet, DBPROPID dwPropertyId, ULONG* piCurPropId) { ATLASSERT(piCurPropId); UPROPINFO* pUPropInfo = m_pUPropSet[iCurSet].pUPropInfo; for(ULONG ul=0; ul<m_pUPropSet[iCurSet].cUPropInfo; ul++) { if( dwPropertyId == pUPropInfo[ul].dwPropId ) { *piCurPropId = ul; // Test to see if the property is supported for this
// instantiation
return (TESTBIT(&(m_rgdwSupported[iCurSet * m_cElemPerSupported]), ul)) ? S_OK : S_FALSE; } }
return S_FALSE; }
virtual HRESULT IsValidValue(ULONG /*iCurSet*/, DBPROP* pDBProp) { ATLASSERT(pDBProp != NULL); CComVariant var = pDBProp->vValue; if (var.vt == VT_BOOL) { if (var.boolVal != VARIANT_TRUE && var.boolVal != VARIANT_FALSE) return S_FALSE; }
return S_OK; }
virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/) = 0;
HRESULT SetProperty(ULONG iCurSet, ULONG iCurProp, DBPROP* pDBProp) { HRESULT hr = S_OK; UPROP* pUProp; UPROPVAL* pUPropVal; UPROPINFO* pUPropInfo; ULONG iUProp;
ATLASSERT( pDBProp );
// Set pointer to correct set
pUProp = &(m_pUProp[iCurSet]); ATLASSERT( pUProp );
pUPropInfo = &(m_pUPropSet[iCurSet].pUPropInfo[iCurProp]); ATLASSERT( pUPropInfo );
// Determine the index within m_pUProp
for(iUProp=0; iUProp<pUProp->cPropIds; iUProp++) { if( (pUProp->rgpUPropInfo[iUProp])->dwPropId == pDBProp->dwPropertyID ) break; }
if( iUProp >= pUProp->cPropIds ) { ATLASSERT( !"Should have found index of property to set" ); hr = E_FAIL; pDBProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED; goto EXIT; }
//Get the UPROPVAL node pointer within that propset.
pUPropVal = &(pUProp->pUPropVal[iUProp]); ATLASSERT( pUPropVal );
// Handle VT_EMPTY, which indicates to the provider to
// reset this property to the providers default
if( pDBProp->vValue.vt == VT_EMPTY ) { if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) { // Remove any nodes, because the default applies to
// all columns
delete pUPropVal->pCColumnIds; pUPropVal->pCColumnIds = NULL; }
// Should clear here, since previous values may already
// have been cached and need to be replaced.
VariantClear(&(pUPropVal->vValue));
pUPropVal->dwFlags &= ~DBINTERNFLAGS_CHANGED; hr = GetDefaultValue(iCurSet, pDBProp->dwPropertyID, &(pUPropVal->dwOption), &(pUPropVal->vValue));
goto EXIT; }
// Column Level
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) { // Check to see if it applies to all
if( (CompareDBIDs(&(pDBProp->colid), &DB_NULLID) == S_OK) ) { // Remove the Columns Storage object
delete pUPropVal->pCColumnIds; pUPropVal->pCColumnIds = NULL; pUPropVal->dwOption = pDBProp->dwOptions; if( FAILED(hr = VariantCopy(&(pUPropVal->vValue), &(pDBProp->vValue))) ) goto EXIT; pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED; } else // Does not apply to all columns
{ if( pUPropVal->pCColumnIds == NULL ) ATLTRY(pUPropVal->pCColumnIds = new CColumnIds)
if( pUPropVal->pCColumnIds ) { if( FAILED(hr = (pUPropVal->pCColumnIds)->AddColumnId(pDBProp)) ) goto EXIT; pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED; } else { hr = E_OUTOFMEMORY; goto EXIT; }
} } else { // Set for non-column level properties
pUPropVal->dwOption = pDBProp->dwOptions; if( FAILED(hr = VariantCopy(&(pUPropVal->vValue), &(pDBProp->vValue))) ) goto EXIT; OnPropertyChanged(iCurSet, pDBProp); pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED; }
EXIT: if( SUCCEEDED(hr) ) pDBProp->dwStatus = DBPROPSTATUS_OK;
return hr; }
HRESULT SetProperties(const DWORD /*dwStatus*/, const ULONG cPropertySets, const DBPROPSET rgPropertySets[], const ULONG cSelectProps = 1, const GUID** ppGuid = NULL, bool bIsCreating = false) { DWORD dwState = 0; ULONG ulCurSet, ulProp, ulCurProp = 0; DBPROP* rgDBProp; UPROPINFO* pUPropInfo; VARIANT vDefaultValue; DWORD dwOption;
// ppGuid specifies the property sets that the consumer can set based
// on the interface that called this function.
ATLASSERT(ppGuid != NULL);
if ((cPropertySets != 0) && (rgPropertySets == NULL)) return E_INVALIDARG;
// Initialize Variant
VariantInit(&vDefaultValue);
// Process property sets
for(ULONG ulSet=0; ulSet<cPropertySets; ulSet++) { if ((rgPropertySets[ulSet].cProperties != 0) && (rgPropertySets[ulSet].rgProperties == NULL)) return E_INVALIDARG;
bool bAvailable = false; for (ULONG l=0; l<cSelectProps; l++) { if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet)) bAvailable |= true; }
// Make sure we support the property set
if( !bAvailable || (GetIndexofPropSet(&(rgPropertySets[ulSet].guidPropertySet), &ulCurSet) == S_FALSE )) { // Not supported, thus we need to mark all as NOT_SUPPORTED
rgDBProp = rgPropertySets[ulSet].rgProperties; for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++) { dwState |= SETPROP_ERRORS; dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED; } continue; }
// Handle property sets marked as pass through
if( m_pUPropSet[ulCurSet].dwFlags & UPROPSET_PASSTHROUGH ) { HRESULT hr = SetPassThrough(&rgPropertySets[ulSet]); if( hr == DB_E_ERRORSOCCURRED ) { dwState |= SETPROP_ERRORS; dwState |= SETPROP_WAS_REQUIRED; } else if( hr == DB_S_ERRORSOCCURRED ) { dwState |= SETPROP_ERRORS; dwState |= SETPROP_VALIDPROP; } else { ATLASSERT( hr == S_OK ); dwState |= SETPROP_VALIDPROP; }
continue; }
// Handle properties of a supported property set
rgDBProp = rgPropertySets[ulSet].rgProperties; for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++) { // Is this a supported PROPID for this property set
if( GetIndexofPropIdinPropSet(ulCurSet, rgDBProp[ulProp].dwPropertyID, &ulCurProp) == S_FALSE) { dwState |= SETPROP_ERRORS; dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED; continue; }
// Set the pUPropInfo pointer
pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]); ATLASSERT( pUPropInfo );
// check dwOption for a valid option
if( (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_REQUIRED) && (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_SETIFCHEAP) ) { ATLTRACE2(atlTraceDBProvider, 0, "SetProperties dwOptions Invalid: %u\n", rgDBProp[ulProp].dwOptions); dwState |= SETPROP_ERRORS; dwState |= SETPROP_WAS_REQUIRED; rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADOPTION; continue; }
// Check that the property is settable
// We do not check against DBPROPFLAGS_CHANGE here
if( (pUPropInfo->dwFlags & DBPROPFLAGS_WRITE) == 0 ) { rgDBProp[ulProp].dwStatus = DBPROPSTATUS_OK;
VariantClear(&vDefaultValue);
// VT_EMPTY against a read only property should be a no-op since
// the VT_EMPTY means the default.
if( V_VT(&rgDBProp[ulProp].vValue) == VT_EMPTY ) { dwState |= SETPROP_VALIDPROP; continue; }
if( SUCCEEDED(GetDefaultValue(ulCurSet, rgDBProp[ulProp].dwPropertyID, &dwOption, &(vDefaultValue))) ) { if( V_VT(&rgDBProp[ulProp].vValue) == V_VT(&vDefaultValue) ) { switch( V_VT(&vDefaultValue) ) { case VT_BOOL: if( V_BOOL(&rgDBProp[ulProp].vValue) == V_BOOL(&vDefaultValue) ) { dwState |= SETPROP_VALIDPROP; continue; } break; case VT_I2: if( V_I2(&rgDBProp[ulProp].vValue) == V_I2(&vDefaultValue) ) { dwState |= SETPROP_VALIDPROP; continue; } break; case VT_I4: if( V_I4(&rgDBProp[ulProp].vValue) == V_I4(&vDefaultValue) ) { dwState |= SETPROP_VALIDPROP; continue; } break; case VT_BSTR: if( wcscmp(V_BSTR(&rgDBProp[ulProp].vValue), V_BSTR(&vDefaultValue)) == 0 ) { dwState |= SETPROP_VALIDPROP; continue; } break; } } }
dwState |= SETPROP_ERRORS; dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSETTABLE; continue; }
// Check that the property is being set with the correct VARTYPE
if( (rgDBProp[ulProp].vValue.vt != pUPropInfo->VarType) && (rgDBProp[ulProp].vValue.vt != VT_EMPTY) ) { dwState |= SETPROP_ERRORS; dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE; continue; }
// Check that the value is legal
if( (rgDBProp[ulProp].vValue.vt != VT_EMPTY) && IsValidValue(ulCurSet, &(rgDBProp[ulProp])) == S_FALSE ) { dwState |= SETPROP_ERRORS; dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE; continue; }
// Check for a bad COLID, we only catch bad DBIDs
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) { if( CDBIDOps::IsValidDBID(&(rgDBProp[ulProp].colid)) == S_FALSE ) { dwState |= SETPROP_ERRORS; dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADCOLUMN; continue; } dwState |= SETPROP_COLUMN_LEVEL;
}
if( SUCCEEDED(SetProperty(ulCurSet, ulCurProp, /*pUPropInfo,*/ &(rgDBProp[ulProp]))) ) { dwState |= SETPROP_VALIDPROP; } } }
VariantClear(&vDefaultValue);
// At least one propid was marked as not S_OK
if( dwState & SETPROP_ERRORS ) { if (!bIsCreating) { return (dwState & SETPROP_VALIDPROP) ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED; } else { return (dwState & SETPROP_WAS_REQUIRED) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED; } }
return S_OK; }
OUT_OF_LINE HRESULT CopyUPropVal(ULONG iPropSet, UPROPVAL* rgUPropVal) { HRESULT hr = S_OK; UPROP* pUProp; UPROPVAL* pUPropVal; DBPROP dbProp;
ATLASSERT(rgUPropVal); ATLASSERT(iPropSet < m_cUPropSet);
VariantInit(&dbProp.vValue);
pUProp = &(m_pUProp[iPropSet]); for(ULONG ul=0; ul<pUProp->cPropIds; ul++) { pUPropVal = &(pUProp->pUPropVal[ul]);
// Transfer dwOptions
rgUPropVal[ul].dwOption = pUPropVal->dwOption;
// Transfer Flags
rgUPropVal[ul].dwFlags = pUPropVal->dwFlags;
// Transfer Column Properties
if( pUPropVal->pCColumnIds ) { ATLTRY(rgUPropVal[ul].pCColumnIds = new CColumnIds) if( rgUPropVal[ul].pCColumnIds ) { CColumnIds* pColIds = pUPropVal->pCColumnIds; for (int i = 0; i < pColIds->GetSize(); i++) { hr = (pUPropVal->pCColumnIds)->GetValue(i, &(dbProp.dwOptions),&(dbProp.colid), &(dbProp.vValue)); if( FAILED(hr) ) goto EXIT; if( FAILED(hr = (rgUPropVal[ul].pCColumnIds)->AddColumnId(&dbProp)) ) goto EXIT; } } else { hr = E_OUTOFMEMORY; goto EXIT; } } else { rgUPropVal[ul].pCColumnIds = NULL; }
// Transfer value
VariantInit(&(rgUPropVal[ul].vValue)); if( FAILED(hr = VariantCopy(&(rgUPropVal[ul].vValue), &(pUPropVal->vValue))) ) goto EXIT; }
EXIT: VariantClear(&(dbProp.vValue)); return hr; } void ClearPropertyInError() { ATLASSERT( m_rgdwPropsInError ); memset(m_rgdwPropsInError, 0, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); }
void CopyUPropSetsSupported(DWORD* rgdwSupported) { memcpy(rgdwSupported, m_rgdwSupported, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); }
virtual HRESULT InitUPropSetsSupported() = 0;
virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet) = 0;
ULONG GetCountofWritablePropsInPropSet(ULONG iPropSet) { ULONG cWritable = 0; UPROPINFO* pUPropInfo;
ATLASSERT( m_pUPropSet ); ATLASSERT( iPropSet < m_cUPropSet );
pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
for(ULONG ul=0; ul<m_pUPropSet[iPropSet].cUPropInfo; ul++) { if( pUPropInfo[ul].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) cWritable++; }
return cWritable; }
void CopyUPropInfo(ULONG iPropSet, UPROPINFO** rgpUPropInfo) { ATLASSERT( rgpUPropInfo ); ATLASSERT( iPropSet < m_cUPropSet ); memcpy(rgpUPropInfo, m_pUProp[iPropSet].rgpUPropInfo, m_pUProp[iPropSet].cPropIds * sizeof(UPROPINFO*)); }
virtual HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar) = 0;
typedef UPROPSET* (*PGetPropSet)(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet, GUID* pguidSet);
HRESULT InternalInitUPropSetsSupported(PGetPropSet pfnGetSet) { ULONG cPropSet = 0, cElemsPerSupported = 0; INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemsPerSupported, NULL, (GUID*)&GUID_NULL); UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets); if (pPropSet == NULL) return E_OUTOFMEMORY; pPropSet = (*pfnGetSet)(&cPropSet, &cElemsPerSupported, pPropSet, (GUID*)&GUID_NULL); memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD)); CoTaskMemFree(pPropSet); return S_OK; }
HRESULT InternalGetDefaultValue(PGetPropSet pfnGetSet, ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar) { if (pdwOption == NULL || pVar == NULL) return E_INVALIDARG;
ULONG cUPropSet = 0, cElemPerSupported =0;
INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemPerSupported, NULL, (GUID*)&GUID_NULL); UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets); if (pPropSet == NULL) return E_OUTOFMEMORY; pPropSet = (*pfnGetSet)(&cUPropSet, &cElemPerSupported, pPropSet, (GUID*)&GUID_NULL);
ATLASSERT(iPropSet < cUPropSet); for (ULONG iProp = 0; iProp < pPropSet[iPropSet].cUPropInfo; iProp++) { UPROPINFO& rInfo = pPropSet[iPropSet].pUPropInfo[iProp]; if (rInfo.dwPropId == dwPropId) { pVar->vt = rInfo.VarType; *pdwOption = rInfo.dwOption; switch(rInfo.VarType) { case VT_BSTR: pVar->bstrVal = SysAllocString(rInfo.szVal); break; default: pVar->lVal = (DWORD)rInfo.dwVal; break; } CoTaskMemFree(pPropSet); return S_OK; } } CoTaskMemFree(pPropSet); return E_FAIL; }
HRESULT InternalFInit(PGetPropSet pfnGetSet, CUtlPropsBase* pCopyMe = NULL) { HRESULT hr; ULONG ulPropId; ULONG cPropIds; ULONG iPropSet; ULONG iNewDex; UPROPINFO** rgpUPropInfo; UPROPVAL* rgUPropVal; UPROPINFO* pUPropInfo;
// If a pointer is passed in, we should copy that property object
if( pCopyMe ) { // Establish some base values
m_cUPropSet = pCopyMe->m_cUPropSet; if (m_pUPropSet != NULL) CoTaskMemFree(m_pUPropSet); m_pUPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * m_cUPropSet); if (m_pUPropSet == NULL) return E_OUTOFMEMORY; memcpy(m_pUPropSet, pCopyMe->m_pUPropSet, sizeof(UPROPSET) * m_cUPropSet); m_cElemPerSupported = pCopyMe->m_cElemPerSupported; ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) ); // Retrieve Supported Bitmask
ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported]) ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported]) if( m_rgdwSupported == NULL|| m_rgdwPropsInError == NULL) { delete[] m_rgdwSupported; delete[] m_rgdwPropsInError; return E_OUTOFMEMORY; } ClearPropertyInError(); pCopyMe->CopyUPropSetsSupported(m_rgdwSupported);
} else { INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &m_cElemPerSupported, NULL, (GUID*)&GUID_NULL); UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets); if (pSet == NULL) return E_OUTOFMEMORY; pSet = (*pfnGetSet)(&m_cUPropSet, &m_cElemPerSupported, pSet, (GUID*)&GUID_NULL); if (m_pUPropSet != NULL) CoTaskMemFree(m_pUPropSet); m_pUPropSet = pSet; ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) ); if( !m_cUPropSet || !m_cElemPerSupported ) return E_FAIL;
ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported]) ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported]) if( m_rgdwSupported == NULL || m_rgdwPropsInError == NULL) { delete[] m_rgdwSupported; delete[] m_rgdwPropsInError; return E_OUTOFMEMORY; } else ClearPropertyInError();
if( FAILED(hr = InitUPropSetsSupported()) ) { delete[] m_rgdwSupported; m_rgdwSupported = NULL; return hr; } }
// Allocate UPROPS structures for the count of Property sets
ATLTRY(m_pUProp = (UPROP*) new UPROP[m_cUPropSet]) if( m_pUProp) { memset(m_pUProp, 0, m_cUPropSet * sizeof(UPROP)); } else { m_cUPropSet = 0; return E_OUTOFMEMORY; }
// With in the UPROPS Structure allocate and intialize the
// Property IDs that belong to this property set.
for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++) { cPropIds = GetCountofWritablePropsInPropSet(iPropSet);
if( cPropIds > 0 ) { ATLTRY(rgpUPropInfo = (UPROPINFO**) new UPROPINFO*[cPropIds]) ATLTRY(rgUPropVal = (UPROPVAL*) new UPROPVAL[cPropIds]) if( rgpUPropInfo != NULL && rgUPropVal != NULL) { if( pCopyMe ) { pCopyMe->CopyUPropInfo(iPropSet, rgpUPropInfo); if( FAILED(hr = pCopyMe->CopyUPropVal(iPropSet, rgUPropVal)) ) return hr; } else { // Clear Pointer Array
memset(rgpUPropInfo, 0, cPropIds * sizeof(UPROPINFO*));
// Set Pointer to correct property ids with a property set
pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
// Set up the writable property buffers
iNewDex = 0; for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++) { if( pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) { // Following ATLASSERT indicates that the are more
// writable properties then space allocated
ATLASSERT(iNewDex < cPropIds);
rgpUPropInfo[iNewDex] = &(pUPropInfo[ulPropId]); rgUPropVal[iNewDex].dwOption = DBPROPOPTIONS_SETIFCHEAP; rgUPropVal[iNewDex].pCColumnIds = NULL; rgUPropVal[iNewDex].dwFlags = 0; VariantInit(&(rgUPropVal[iNewDex].vValue)); GetDefaultValue(iPropSet, pUPropInfo[ulPropId].dwPropId, &(rgUPropVal[iNewDex].dwOption), &(rgUPropVal[iNewDex].vValue)); iNewDex++; } }
ATLASSERT(cPropIds == iNewDex); }
m_pUProp[iPropSet].rgpUPropInfo = rgpUPropInfo; m_pUProp[iPropSet].pUPropVal = rgUPropVal; m_pUProp[iPropSet].cPropIds = cPropIds; } else { delete[] rgpUPropInfo; delete[] rgUPropVal; return E_OUTOFMEMORY; } } }
// Finally determine if there are any hidden property sets.. Those
// that do not show up in GetPropertyInfo and should not be returns on
// a 0, NULL call to GetProperties
for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++) { if( m_pUPropSet[iPropSet].dwFlags & UPROPSET_HIDDEN ) m_cUPropSetHidden++; }
return S_OK; } //Check the arguments for Set Properties
static HRESULT SetPropertiesArgChk(const ULONG cPropertySets, const DBPROPSET rgPropertySets[]) { if( cPropertySets > 0 && !rgPropertySets ) return E_INVALIDARG;
// New argument check for > 1 cPropertyIDs and NULL pointer for
// array of property ids.
for(ULONG ul=0; ul<cPropertySets; ul++) { if( rgPropertySets[ul].cProperties && !(rgPropertySets[ul].rgProperties) ) return E_INVALIDARG; }
return S_OK; } HRESULT GetProperties(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], ULONG* pcProperties, DBPROPSET** prgProperties, const ULONG cSelectProps = 1, const GUID** ppGuid = NULL) { UPROPVAL* pUPropVal; ULONG ulCurProp = 0; ULONG cTmpPropertySets = cPropertySets; HRESULT hr = S_OK; ULONG ulSet = 0; ULONG ulNext = 0; ULONG cSets = 0; ULONG cProps = 0; ULONG ulProp = 0; DWORD dwStatus = 0; DBPROP* pProp = NULL; DBPROP* pCurProp = NULL; DBPROPSET* pPropSet = NULL; UPROPINFO* pUPropInfo = NULL; ULONG* piSetIndex = NULL; ULONG* piIndex = NULL; ULONG ulCurSet = 0; ULONG iPropSet;
// ppGuid contains an array of GUIDs that the consumer can retrieve.
// This is based upon the interface calling this function
ATLASSERT(ppGuid != NULL);
// We need to have special handling for DBPROPSET_PROPERTIESINERROR..
// Turn on a flags to indicate this mode and make cTmpPropertySets
// appear to be 0
if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) && rgPropertySets && (rgPropertySets[0].guidPropertySet == DBPROPSET_PROPERTIESINERROR) ) { cTmpPropertySets = 0; dwStatus |= GETPROP_PROPSINERROR; }
// If the consumer does not restrict the property sets
// by specify an array of property sets and a cTmpPropertySets
// greater than 0, then we need to make sure we
// have some to return
if( cTmpPropertySets == 0 ) { // There are times when we are called from IRowsetInfo, ISessionProperties, etc.
// where we should return only the appropriate rowset when cTmpPropertySets is
// zero. This solves the problem if the user has more than one set specified in
// their PROPSET_MAP.
// Determine the number of property sets supported
if (ppGuid == NULL) { cSets = m_cUPropSet; } else { ULONG ulActualProps = 0; piSetIndex = new ULONG[cSelectProps];
// Also, find the index for the set we are looking for
for (ULONG l=0; l<cSelectProps; l++) { for (piSetIndex[l]=0; piSetIndex[l]<m_cUPropSet; piSetIndex[l]++) { if (InlineIsEqualGUID(*m_pUPropSet[piSetIndex[l]].pPropSet, *ppGuid[l])) { ulActualProps++; break; } } }
// YIKES!
cSets = ulActualProps; ulActualProps = 0; piIndex = new ULONG[cSets]; for (l=0; l<cSelectProps; l++) { if (piSetIndex[l] != m_cUPropSet) // this is an invalid index
piIndex[ulActualProps++] = piSetIndex[l]; }
delete piSetIndex; piSetIndex = NULL;
} } else { // Since special property set guids are not supported by
// GetProperties, we can just use the count of property
// sets given to us.
cSets = cTmpPropertySets; }
// If no properties set, then return
if( cSets == 0 ) return S_OK;
// Allocate the DBPROPSET structures
pPropSet = (DBPROPSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPSET)); if(pPropSet) { memset(pPropSet, 0, cSets * sizeof(DBPROPSET));
// Fill in the output array
iPropSet = 0; for(ulSet=0; ulSet<cSets; ulSet++) { // Depending of if Property sets are specified store the
// return property set.
if( cTmpPropertySets == 0 ) { ULONG lSet;
if (ppGuid[ulSet] == NULL) lSet = ulSet; else lSet = piIndex[ulSet]; if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN ) continue;
pPropSet[iPropSet].guidPropertySet = *(m_pUPropSet[lSet].pPropSet); } else pPropSet[iPropSet].guidPropertySet = rgPropertySets[ulSet].guidPropertySet;
iPropSet++; } } else { ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n"); delete piIndex; piIndex = NULL; return E_OUTOFMEMORY; }
// Process requested or derived Property sets
iPropSet=0; for(ulSet=0; ulSet<cSets; ulSet++) { cProps = 0; pProp = NULL; ulNext = 0; dwStatus &= (GETPROP_ERRORSOCCURRED | GETPROP_VALIDPROP | GETPROP_PROPSINERROR);
// Calculate the number of property nodes needed for this
// property set.
if( cTmpPropertySets == 0 ) { ULONG lSet;
if (ppGuid[ulSet] == NULL) lSet = ulSet; else lSet = piIndex[ulSet];
// If processing requesting all property sets, do not
// return the hidden sets.
if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN ) continue;
cProps = m_pUPropSet[lSet].cUPropInfo;
// Add Enough space for node that are colid specific
cProps += GetCountofColids(&(m_pUProp[lSet])); dwStatus |= GETPROP_ALLPROPIDS; ulCurSet = lSet; } else { ATLASSERT(ulSet == iPropSet);
// If the count of PROPIDs is 0 or It is a special property set, then
// the consumer is requesting all propids for this property set.
if(rgPropertySets[ulSet].cPropertyIDs == 0) { dwStatus |= GETPROP_ALLPROPIDS; // We have to determine if the property set is supported and if so
// the count of properties in the set.
BOOL bAvailable = false; for (ULONG l=0; l<cSelectProps; l++) { if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet)) bAvailable |= true; }
if (bAvailable && GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) == S_OK) { cProps += m_pUPropSet[ulCurSet].cUPropInfo; // Add Enough space for node that are colid specific
cProps += GetCountofColids(&m_pUProp[ulCurSet]); } else { // Not Supported
dwStatus |= GETPROP_ERRORSOCCURRED; goto NEXT_SET;
} } else { cProps = rgPropertySets[ulSet].cPropertyIDs; // Check to see if this is a supported interface based on ppGuid.
BOOL bAvailable = false; for (ULONG l=0; l<cSelectProps; l++) { if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet)) bAvailable |= true; }
if (!bAvailable || (GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) != S_OK)) { dwStatus |= GETPROP_NOTSUPPORTED; dwStatus |= GETPROP_ERRORSOCCURRED; } } }
// Allocate DBPROP array
if( cProps == 0 ) //Possible with Hidden Passthrough sets
goto NEXT_SET;
pProp = (DBPROP*)CoTaskMemAlloc(cProps * sizeof(DBPROP)); if( pProp ) { // Initialize Buffer
memset(pProp, 0, cProps * sizeof(DBPROP)); for(ulProp=0; ulProp<cProps; ulProp++) { VariantInit(&(pProp[ulProp].vValue)); if( dwStatus & GETPROP_NOTSUPPORTED ) { // Not supported, thus we need to mark all as NOT_SUPPORTED
pProp[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp]; pProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED; } } // Make sure we support the property set
if( dwStatus & GETPROP_NOTSUPPORTED ) { ulNext = cProps; goto NEXT_SET; }
// Now that we have determined we can support the property set, we
// need to gather current property values
for(ulProp=0; ulProp<cProps; ulProp++) { pCurProp = &(pProp[ulNext]);
//Initialize Variant Value
pCurProp->dwStatus = DBPROPSTATUS_OK;
// Retrieve current value of properties
if( dwStatus & GETPROP_ALLPROPIDS ) { // Verify property is supported, if not do not return
if( !TESTBIT(&(m_rgdwSupported[ulCurSet * m_cElemPerSupported]), ulProp) ) continue;
// If we are looking for properties in error, then we should ignore all
// that are not in error.
if( (dwStatus & GETPROP_PROPSINERROR) && !TESTBIT(&(m_rgdwPropsInError[ulCurSet * m_cElemPerSupported]), ulProp) ) continue;
pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulProp]);
ATLASSERT( pUPropInfo );
pCurProp->dwPropertyID = pUPropInfo->dwPropId; pCurProp->colid = DB_NULLID;
// If the property is WRITEABLE or CHANGABLE, then the value will
// be gotten from the UPROPVAL array, else it will be
// derive from the GetDefaultValue
if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) { pUPropVal = &(m_pUProp[ulCurSet]. pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]); ATLASSERT( pUPropVal );
// Check to see if this property supports column level,
// if so, dump those nodes
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) { if( pUPropVal->pCColumnIds ) { RetrieveColumnIdProps(pProp, pUPropVal, &ulNext); continue; } }
pCurProp->dwOptions = pUPropVal->dwOption; hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue)); } else { GetDefaultValue(ulCurSet, pUPropInfo->dwPropId, &(pCurProp->dwOptions), &(pCurProp->vValue)); }
// Return all Properties in Error with CONFLICT status
if( dwStatus & GETPROP_PROPSINERROR ) pCurProp->dwStatus = DBPROPSTATUS_CONFLICTING;
dwStatus |= GETPROP_VALIDPROP; } else { // Process Properties based on Restriction array.
pCurProp->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp]; pCurProp->colid = DB_NULLID;
if( GetIndexofPropIdinPropSet(ulCurSet, pCurProp->dwPropertyID, &ulCurProp) == S_OK) { // Supported
pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]); ATLASSERT( pUPropInfo );
// If the property is WRITEABLE, then the value will
// be gotten from the UPROPVAL array, else it will be
// derive from the GetDefaultValue
if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) { pUPropVal = &(m_pUProp[ulCurSet]. pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]); ATLASSERT( pUPropVal );
// Check to see if this property supports column level,
// if so, dump those nodes
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) { if( pUPropVal->pCColumnIds ) { RetrieveColumnIdProps(pProp, pUPropVal, &ulNext); continue; } } pCurProp->dwOptions = pUPropVal->dwOption; hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue)); } else { GetDefaultValue(ulCurSet, pUPropInfo->dwPropId, &(pCurProp->dwOptions), &(pCurProp->vValue));
}
dwStatus |= GETPROP_VALIDPROP; } else { // Not Supported
pCurProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED; dwStatus |= GETPROP_ERRORSOCCURRED; } }
// Increment return nodes count
ulNext++; } } else { ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROP array for GetProperties\n"); if( pPropSet ) { // Free any DBPROP arrays
for(ulSet=0; ulSet<cSets; ulSet++) { // Need to loop through all the VARIANTS and clear them
for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++) VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue)); if( pPropSet[ulSet].rgProperties ) CoTaskMemFree(pPropSet[ulSet].rgProperties); }
// Free DBPROPSET
CoTaskMemFree(pPropSet); } //Since we have no properties to return, then we
//need to free allocated memory and return 0,NULL
if(pPropSet) { // Free any DBPROP arrays
for(ulSet=0; ulSet<cSets; ulSet++) { // Need to loop through all the VARIANTS and clear them
for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++) VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue)); if( pPropSet[ulSet].rgProperties ) CoTaskMemFree(pPropSet[ulSet].rgProperties); }
// Free DBPROPSET
CoTaskMemFree(pPropSet); } *pcProperties = 0; *prgProperties = NULL; delete piIndex; piIndex = NULL; return E_OUTOFMEMORY; }
NEXT_SET: // It is possible that all properties are not supported,
// thus we should delete that memory and set rgProperties
// to NULL
if( ulNext == 0 && pProp ) { CoTaskMemFree(pProp); pProp = NULL; }
pPropSet[iPropSet].cProperties = ulNext; pPropSet[iPropSet].rgProperties = pProp; iPropSet++; }
*pcProperties = iPropSet; *prgProperties = pPropSet;
delete piIndex; piIndex = NULL;
// At least one propid was marked as not S_OK
if( dwStatus & GETPROP_ERRORSOCCURRED ) { // If at least 1 property was set
if( dwStatus & GETPROP_VALIDPROP ) return DB_S_ERRORSOCCURRED; else { // Do not free any of the memory on a DB_E_
return DB_E_ERRORSOCCURRED; } }
return S_OK; }
ULONG GetCountofColids(UPROP* pUProp) { ULONG cExtra=0; ATLASSERT(pUProp); for(ULONG ul=0; ul<pUProp->cPropIds; ul++) { if( pUProp->pUPropVal[ul].pCColumnIds ) cExtra += (pUProp->pUPropVal[ul].pCColumnIds)->GetCountOfPropColids(); } return cExtra; }
ULONG GetUPropValIndex(ULONG iCurSet, DBPROPID dwPropId) { for(ULONG ul=0; ul<m_pUProp[iCurSet].cPropIds; ul++) { if( (m_pUProp[iCurSet].rgpUPropInfo[ul])->dwPropId == dwPropId ) return ul; } return 0; }
void RetrieveColumnIdProps(DBPROP* pCurProp, UPROPVAL* pUPropVal, ULONG* pulNext) { // Reset to first Node
CColumnIds* pColIds = pUPropVal->pCColumnIds; HRESULT hr = E_FAIL; for (int i = 0; i < pColIds->GetSize(); i++) { CPropColID colId; hr = pColIds->GetValue(i, &(pCurProp->dwOptions), &(pCurProp->colid),&(pCurProp->vValue)); if (SUCCEEDED(hr)) pCurProp = &(pCurProp[++(*pulNext)]); } (*pulNext)++; }
//Check the arguments for Retrieve Properties
HRESULT GetPropertiesArgChk(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], ULONG* pcProperties, DBPROPSET** prgProperties) { // Initialize values
if(pcProperties) *pcProperties = 0; if(prgProperties) *prgProperties = NULL;
// Check Arguments
if( ((cPropertySets > 0) && !rgPropertySets) || !pcProperties || !prgProperties ) return E_INVALIDARG;
// New argument check for > 1 cPropertyIDs and NULL pointer for
// array of property ids.
for(ULONG ul=0; ul<cPropertySets; ul++) { if( rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs) ) return E_INVALIDARG;
// Check for propper formation of DBPROPSET_PROPERTIESINERROR
if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) && rgPropertySets[ul].guidPropertySet == DBPROPSET_PROPERTIESINERROR ) { if( (cPropertySets > 1) || (rgPropertySets[ul].cPropertyIDs != 0) || (rgPropertySets[ul].rgPropertyIDs != NULL) ) return E_INVALIDARG; } }
return S_OK; }
OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL) = 0; };
// Implementation Class
template <class T> class ATL_NO_VTABLE CUtlProps : public CUtlPropsBase { public:
CUtlProps(DWORD dwFlags = 0) { ClearMemberVars(); m_dwFlags = dwFlags; } ~CUtlProps() { FreeMemory(); } void FreeMemory() { // Remove Property Information
if( m_pUProp ) { for(ULONG ulPropSet=0; ulPropSet<m_cUPropSet; ulPropSet++) { UPROPVAL* pUPropVal = m_pUProp[ulPropSet].pUPropVal; for(ULONG ulPropId=0; ulPropId<m_pUProp[ulPropSet].cPropIds; ulPropId++) { delete pUPropVal[ulPropId].pCColumnIds; VariantClear(&(pUPropVal[ulPropId].vValue)); } delete[] m_pUProp[ulPropSet].rgpUPropInfo; delete[] m_pUProp[ulPropSet].pUPropVal; }
}
delete[] m_pUProp; delete[] m_rgdwSupported; delete[] m_rgdwPropsInError; delete[] m_rgiPropSetDex;
if (m_pUPropSet != NULL) CoTaskMemFree(m_pUPropSet);
ClearMemberVars(); } void ClearMemberVars() { m_cPropSetDex = 0; m_cUPropSet = 0; m_cUPropSetHidden = 0; m_pUPropSet = NULL;
m_dwFlags = 0;
m_pUProp = NULL; m_cElemPerSupported = 0; m_rgdwSupported = NULL; m_rgdwPropsInError = NULL; m_rgiPropSetDex = NULL; }
//Retrieve the property set indexes that match this property set.
HRESULT GetPropertySetIndex(GUID* pPropertySet) { DWORD dwFlag = 0; ULONG ulSet;
ATLASSERT( m_cUPropSet && m_pUPropSet ); ATLASSERT( m_rgiPropSetDex ); ATLASSERT( pPropertySet );
m_cPropSetDex = 0;
if( *pPropertySet == DBPROPSET_DATASOURCEALL ) { dwFlag = DBPROPFLAGS_DATASOURCE; } else if( *pPropertySet == DBPROPSET_DATASOURCEINFOALL ) { dwFlag = DBPROPFLAGS_DATASOURCEINFO; } else if( *pPropertySet == DBPROPSET_ROWSETALL ) { dwFlag = DBPROPFLAGS_ROWSET; } else if( *pPropertySet == DBPROPSET_DBINITALL ) { dwFlag = DBPROPFLAGS_DBINIT; } else if( *pPropertySet == DBPROPSET_SESSIONALL ) { dwFlag = DBPROPFLAGS_SESSION; } else // No scan required, just look for match.
{ for(ulSet=0; ulSet<m_cUPropSet; ulSet++) { if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet ) { m_rgiPropSetDex[m_cPropSetDex] = ulSet; m_cPropSetDex++; break; } } goto EXIT; }
// Scan through the property sets looking for matching attributes
for(ulSet=0; ulSet<m_cUPropSet; ulSet++) { if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag ) { m_rgiPropSetDex[m_cPropSetDex] = ulSet; m_cPropSetDex++; } }
EXIT: return (m_cPropSetDex) ? S_OK : S_FALSE; }
OUT_OF_LINE HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar) { return InternalGetDefaultValue(T::_GetPropSet, iPropSet, dwPropId, pdwOption, pVar); }
OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL) { return InternalFInit(T::_GetPropSet, pCopyMe); } HRESULT FillDefaultValues(ULONG ulPropSetTarget = ULONG_MAX) { HRESULT hr; ULONG ulPropId; ULONG iPropSet; ULONG iNewDex;
// Fill in all the actual values.
// Typically because we now have an hdbc with which to get them.
// (Or we no longer have an hdbc, so must clear them.)
// Note that the UPROP (with values) array may be a subset of the UPROPINFO array.
// Only writable properties are in UPROP array.
// Maybe restrict to a single PropSet if within valid range [0...m_cUPropSet-1].
// Otherwise do all propsets.
iPropSet = (ulPropSetTarget < m_cUPropSet) ? ulPropSetTarget : 0;
for( ; iPropSet<m_cUPropSet; iPropSet++) { iNewDex = 0; for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++) { if( m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) { //Initialize dwFlags element of UPropVal
m_pUProp[iPropSet].pUPropVal[iNewDex].dwFlags = 0;
// Don't need this since SetProperties() resets these.
//ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption == DBPROPOPTIONS_SETIFCHEAP);
ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].pCColumnIds == NULL);
VariantClear(&m_pUProp[iPropSet].pUPropVal[iNewDex].vValue); hr = GetDefaultValue( iPropSet, m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwPropId, &m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption, &m_pUProp[iPropSet].pUPropVal[iNewDex].vValue ); if (FAILED(hr)) return hr; iNewDex++; } }
// We're through if restricting to single PropSet.
if (ulPropSetTarget < m_cUPropSet) break; } return NOERROR; }
// Translate Rowset IIDs to PROPSET structures ready to pass to SetProperties
HRESULT ConvertRowsetIIDtoDBPROPSET(const IID* piid, DBPROPSET* pPropSet) { HRESULT hr = S_OK; DBPROP* pProp;
ATLASSERT( piid || pPropSet ); ATLASSERT( (pPropSet->cProperties == 1) || (pPropSet->rgProperties) );
pProp = &(pPropSet->rgProperties[0]);
if(InlineIsEqualGUID(*piid, IID_IAccessor)) pProp->dwPropertyID = DBPROP_IAccessor; else if(InlineIsEqualGUID(*piid,IID_IColumnsInfo)) pProp->dwPropertyID = DBPROP_IColumnsInfo; else if(InlineIsEqualGUID(*piid , IID_IRowset)) pProp->dwPropertyID = DBPROP_IRowset; else if(InlineIsEqualGUID(*piid , IID_IRowsetInfo)) pProp->dwPropertyID = DBPROP_IRowsetInfo; else if(InlineIsEqualGUID(*piid , IID_IRowsetLocate)) pProp->dwPropertyID = DBPROP_IRowsetLocate; else if(InlineIsEqualGUID(*piid , IID_IColumnsRowset)) pProp->dwPropertyID = DBPROP_IColumnsRowset; else if(InlineIsEqualGUID(*piid , IID_IRowsetResynch)) pProp->dwPropertyID = DBPROP_IRowsetResynch; else if(InlineIsEqualGUID(*piid , IID_IRowsetScroll)) pProp->dwPropertyID = DBPROP_IRowsetScroll; else if(InlineIsEqualGUID(*piid , IID_IRowsetChange)) pProp->dwPropertyID = DBPROP_IRowsetChange; else if(InlineIsEqualGUID(*piid , IID_IRowsetUpdate)) pProp->dwPropertyID = DBPROP_IRowsetUpdate; else if(InlineIsEqualGUID(*piid , IID_IRowsetIdentity)) pProp->dwPropertyID = DBPROP_IRowsetIdentity; else if(InlineIsEqualGUID(*piid , IID_IConnectionPointContainer)) pProp->dwPropertyID = DBPROP_IConnectionPointContainer; else if(InlineIsEqualGUID(*piid , IID_ISupportErrorInfo)) pProp->dwPropertyID = DBPROP_ISupportErrorInfo; else if(InlineIsEqualGUID(*piid , IID_IRowsetIndex)) pProp->dwPropertyID = DBPROP_IRowsetIndex; #if( OLEDBVER >= 0x0200 )
else if(InlineIsEqualGUID(*piid , IID_IRowsetLockRows)) pProp->dwPropertyID = DBPROP_IRowsetLockRows; else if(InlineIsEqualGUID(*piid , IID_IProvideMoniker)) pProp->dwPropertyID = DBPROP_IProvideMoniker; else if(InlineIsEqualGUID(*piid , IID_IRowsetNotify)) pProp->dwPropertyID = DBPROP_IRowsetNotify; else if(InlineIsEqualGUID(*piid , IID_IReadData)) pProp->dwPropertyID = DBPROP_IReadData; else if(InlineIsEqualGUID(*piid , IID_IRowsetExactScroll)) pProp->dwPropertyID = DBPROP_IRowsetExactScroll; else if(InlineIsEqualGUID(*piid , IID_IRowsetNextRowset)) pProp->dwPropertyID = DBPROP_IRowsetNextRowset; else if(InlineIsEqualGUID(*piid , IID_IRowsetDelete)) pProp->dwPropertyID = DBPROP_IRowsetDelete; else if(InlineIsEqualGUID(*piid , IID_IRowsetDeleteBookmarks)) pProp->dwPropertyID = DBPROP_IRowsetDeleteBookmarks; else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRow)) pProp->dwPropertyID = DBPROP_IRowsetNewRow; else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRowAfter)) pProp->dwPropertyID = DBPROP_IRowsetNewRowAfter; else if(InlineIsEqualGUID(*piid , IID_IRowsetWithParameters)) pProp->dwPropertyID = DBPROP_IRowsetWithParameters; else if(InlineIsEqualGUID(*piid , IID_IRowsetFind)) pProp->dwPropertyID = DBPROP_IRowsetFind; else if(InlineIsEqualGUID(*piid , IID_IRowsetAsynch)) pProp->dwPropertyID = DBPROP_IRowsetAsynch; else if(InlineIsEqualGUID(*piid , IID_IRowsetKeys)) pProp->dwPropertyID = DBPROP_IRowsetKeys; else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchAll)) pProp->dwPropertyID = DBPROP_IRowsetWatchAll; else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchNotify)) pProp->dwPropertyID = DBPROP_IRowsetWatchNotify; else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchRegion)) pProp->dwPropertyID = DBPROP_IRowsetWatchRegion; else if(InlineIsEqualGUID(*piid , IID_IRowsetCopyRows)) pProp->dwPropertyID = DBPROP_IRowsetCopyRows; #endif //#if( OLEDBVER >= 0x0200 )
else hr = S_FALSE;
// If the IID can be mapped to a DBPROPID, the
// we need to initialize the vValue to TRUE
if(hr == S_OK) { // Set PropertySet
pPropSet->guidPropertySet = DBPROPSET_ROWSET;
// Set Property
pProp->dwOptions = DBPROPOPTIONS_REQUIRED; pProp->dwStatus = 0; pProp->colid = DB_NULLID;
VariantInit(&(pProp->vValue)); pProp->vValue.vt = VT_BOOL; V_BOOL(&(pProp->vValue)) = VARIANT_TRUE; }
return hr; }
void SetPropertyInError(const ULONG iPropSet, const ULONG iPropId) { SETBIT(&(m_rgdwPropsInError[iPropSet * m_cElemPerSupported]), iPropId); }
BOOL IsPropSet(const GUID* pguidPropSet, DBPROPID dwPropId) { HRESULT hr; ULONG iPropSet; ULONG iPropId; VARIANT vValue; DWORD dwOptions;
VariantInit(&vValue);
if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK ) { if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK ) { if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) { ULONG iPropVal = GetUPropValIndex(iPropSet, dwPropId);
dwOptions = m_pUProp[iPropSet].pUPropVal[iPropVal].dwOption; hr = VariantCopy(&vValue, &(m_pUProp[iPropSet]. pUPropVal[iPropVal].vValue)); } else { hr = GetDefaultValue(iPropSet, dwPropId, &dwOptions, &vValue); }
if( dwOptions == DBPROPOPTIONS_REQUIRED ) { ATLASSERT( vValue.vt == VT_BOOL ); if( SUCCEEDED(hr) && (V_BOOL(&vValue) == VARIANT_TRUE) ) { VariantClear(&vValue); return TRUE; } } } }
VariantClear(&vValue); return FALSE; } OUT_OF_LINE HRESULT GetPropValue(const GUID* pguidPropSet, DBPROPID dwPropId, VARIANT* pvValue) { HRESULT hr = E_FAIL; ULONG iPropSet; ULONG iPropId = 0; DWORD dwOptions;
if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK ) { if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK ) { if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) { hr = VariantCopy(pvValue, &(m_pUProp[iPropSet].pUPropVal[ GetUPropValIndex(iPropSet, dwPropId)].vValue)); } else { VariantClear(pvValue);
hr = GetDefaultValue(iPropSet, dwPropId, &dwOptions, pvValue); } } }
return hr; } HRESULT SetPropValue(const GUID* pguidPropSet,DBPROPID dwPropId, VARIANT* pvValue) { HRESULT hr = E_FAIL; ULONG iPropSet; ULONG iPropId;
if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK ) { if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK ) { ATLASSERT( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) );
hr = VariantCopy(&(m_pUProp[iPropSet].pUPropVal[ GetUPropValIndex(iPropSet, dwPropId)].vValue), pvValue); } }
return hr; }
//Pointer to properties in error mask
DWORD* GetPropsInErrorPtr(){return m_rgdwPropsInError;} ULONG GetUPropSetCount() {return m_cUPropSet;} void SetUPropSetCount(ULONG c) {m_cUPropSet = c;}
// NOTE: The following functions depend on all prior
// properties in the array being writable.
// This is because the UPROP array contains only writable elements,
// and the UPROPINFO array contains writable and read-only elements.
// (If this is a problem, we would need to define which one it came from
// and add the appropriate ATLASSERTs...)
//Get DBPROPOPTIONS_xx
DWORD GetPropOption(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); return m_pUProp[iPropSet].pUPropVal[iProp].dwOption; } //Set DBPROPOPTIONS_xx
void SetPropOption(ULONG iPropSet, ULONG iProp, DWORD dwOption) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); m_pUProp[iPropSet].pUPropVal[iProp].dwOption = dwOption; } //Determine if property is required and variant_true
BOOL IsRequiredTrue(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL); ATLASSERT(V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE || V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_FALSE);
return( (m_pUProp[iPropSet].pUPropVal[iProp].dwOption == DBPROPOPTIONS_REQUIRED) && (V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE) ); } DWORD GetInternalFlags(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); return m_pUProp[iPropSet].pUPropVal[iProp].dwFlags; } void AddInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); m_pUProp[iPropSet].pUPropVal[iProp].dwFlags |= dwFlags; } void RemoveInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); m_pUProp[iPropSet].pUPropVal[iProp].dwFlags &= ~dwFlags; } VARIANT * GetVariant(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); return & m_pUProp[iPropSet].pUPropVal[iProp].vValue; } HRESULT SetVariant(ULONG iPropSet, ULONG iProp, VARIANT *pv ) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); // Does VariantClear first.
return VariantCopy( &m_pUProp[iPropSet].pUPropVal[iProp].vValue, pv ); } void SetValEmpty(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); VariantClear( &m_pUProp[iPropSet].pUPropVal[iProp].vValue ); } BOOL IsEmpty(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); return ( m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_EMPTY); } void SetValBool(ULONG iPropSet, ULONG iProp, VARIANT_BOOL bVal) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); // Note that we accept any "true" value.
VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue); m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_BOOL; V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) = (bVal ? VARIANT_TRUE : VARIANT_FALSE); } VARIANT_BOOL GetValBool(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL); return V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue); } void SetValShort(ULONG iPropSet, ULONG iProp, SHORT iVal ) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue); m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I2; m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal = iVal; } SHORT GetValShort(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I2); return m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal; } void SetValLong(ULONG iPropSet, ULONG iProp, LONG lVal) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue); m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I4; m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal = lVal; } LONG GetValLong(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I4); return m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal; } HRESULT SetValString(ULONG iPropSet, ULONG iProp, const WCHAR *pwsz) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); VARIANT *pv = &m_pUProp[iPropSet].pUPropVal[iProp].vValue; VariantClear(pv); pv->bstrVal = SysAllocString(pwsz); if (pv->bstrVal) pv->vt = VT_BSTR; else return E_FAIL;
// See if this was used for non-string type.
// Typically this is an easy way to pass integer as a string.
if (GetExpectedVarType(iPropSet,iProp) == VT_BSTR) return NOERROR; if (pwsz[0] != L'\0') return VariantChangeType( pv, pv, 0, GetExpectedVarType(iPropSet,iProp) );
// Set to "", which for non-string means empty.
SysFreeString(pv->bstrVal); pv->vt = VT_EMPTY; return NOERROR; } const WCHAR * GetValString(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BSTR); return m_pUProp[iPropSet].pUPropVal[iProp].vValue.bstrVal; } const GUID * GetGuid(ULONG iPropSet) { ATLASSERT(iPropSet < m_cUPropSet); return m_pUPropSet[iPropSet].pPropSet; } DWORD GetPropID(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); return m_pUPropSet[iPropSet].pUPropInfo[iProp].dwPropId; } VARTYPE GetExpectedVarType(ULONG iPropSet, ULONG iProp) { ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) )); return m_pUPropSet[iPropSet].pUPropInfo[iProp].VarType; } virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet) { ATLASSERT(pPropSet && pulCurSet);
for(ULONG ul=0; ul<m_cUPropSet; ul++) { if( *pPropSet == *(m_pUPropSet[ul].pPropSet) ) { *pulCurSet = ul; return S_OK; } } return S_FALSE; }
virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/) { return S_OK; }
virtual HRESULT InitUPropSetsSupported() { return InternalInitUPropSetsSupported(T::_GetPropSet); }
HRESULT GetIndexOfPropertyInSet(const GUID* pPropSet, DBPROPID dwPropertyId, ULONG* piCurPropId, ULONG* piCurSet) { HRESULT hr = GetIndexofPropSet(pPropSet, piCurSet); if (hr == S_FALSE) return hr; UPROPINFO* pUPropInfo = m_pUPropSet[*piCurSet].pUPropInfo; for(ULONG ul=0; ul<m_pUPropSet[*piCurSet].cUPropInfo; ul++) { if( dwPropertyId == pUPropInfo[ul].dwPropId ) *piCurPropId = ul; return S_OK; }
return S_FALSE; } HRESULT SetSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId) { ULONG iCurPropId, iCurSet;
if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK) { m_rgdwSupported[iCurSet * m_cElemPerSupported] |= 1 << iCurPropId; return S_OK; } return S_FALSE; }
HRESULT ClearSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId) { ULONG iCurPropId, iCurSet;
if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK) { m_rgdwSupported[iCurSet * m_cElemPerSupported] &= ~( 1 << iCurPropId); return S_OK; } return S_FALSE; }
HRESULT TestSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId, bool& bSet) { ULONG iCurPropId, iCurSet;
if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK) { bSet = (m_rgdwSupported[iCurSet * m_cElemPerSupported] & ( 1 << iCurPropId)) != 0; return S_OK; } return S_FALSE; } void CopyPropsInError(DWORD* rgdwSupported) { memcpy(rgdwSupported, m_rgdwPropsInError, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); } };
// IDBPropertiesImpl
// IDBProperties <- IUnknown
template <class T> class ATL_NO_VTABLE IDBPropertiesImpl : public IDBProperties, public CUtlProps<T> { public: STDMETHOD(GetProperties)(ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], ULONG *pcProperties, DBPROPSET **prgProperties) { ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetProperties\n"); T* pT = (T*)this; HRESULT hr = GetPropertiesArgChk(cPropertySets, rgPropertySets, pcProperties, prgProperties); if (FAILED(hr)) return hr;
if(SUCCEEDED(hr)) { // Check for other invalid arguments
for (ULONG i=0; i<cPropertySets; i++) { if (InlineIsEqualGUID(rgPropertySets[i].guidPropertySet, DBPROPSET_PROPERTIESINERROR)) if (pcProperties != NULL || prgProperties != NULL || cPropertySets > 1) return E_INVALIDARG; } }
if (SUCCEEDED(hr)) { const GUID* ppGuid[3]; if (pT->m_dwStatus & DSF_INITIALIZED) { ppGuid[0] = &DBPROPSET_DBINIT; ppGuid[1] = &DBPROPSET_DATASOURCE; ppGuid[2] = &DBPROPSET_DATASOURCEINFO; hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets, pcProperties, prgProperties, 3, ppGuid); } else { ppGuid[0] = &DBPROPSET_DBINIT; hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets, pcProperties, prgProperties, 1, ppGuid); } }
return hr; }
STDMETHOD(GetPropertyInfo)(ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], ULONG *pcPropertyInfoSets, DBPROPINFOSET **prgPropertyInfoSets, OLECHAR **ppDescBuffer) { ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetPropertyInfo\n"); T* pT = (T*)this;
if (pT->m_pCUtlPropInfo == NULL) { // Go ahead and create the m_pCUtlPropInfo but do not change the
// Initialized status of the provider (see IDBInitialize::Initialize).
ATLTRACE2(atlTraceDBProvider, 0, "m_pCUtlPropInfo == NULL\n"); pT->Lock(); delete pT->m_pCUtlPropInfo; ATLTRY(pT->m_pCUtlPropInfo = new CUtlPropInfo<T>()) pT->Unlock(); if (pT->m_pCUtlPropInfo == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "IDBProperties::GetPropertyInfo Error : OOM\n"); return E_OUTOFMEMORY; } HRESULT hr = pT->m_pCUtlPropInfo->FInit(); if (hr != S_OK) { pT->Lock(); delete pT->m_pCUtlPropInfo; pT->m_pCUtlPropInfo = NULL; pT->Unlock(); } }
// Initialize
if( pcPropertyInfoSets ) *pcPropertyInfoSets = 0; if( prgPropertyInfoSets ) *prgPropertyInfoSets = NULL; if( ppDescBuffer ) *ppDescBuffer = NULL;
// Check Arguments
if( ((cPropertySets > 0) && !rgPropertySets) || !pcPropertyInfoSets || !prgPropertyInfoSets ) return E_INVALIDARG;
// New argument check for > 1 cPropertyIDs and NULL pointer for
// array of property ids.
const DWORD SPECIAL_GROUP = 1; const DWORD SPECIAL_SINGLE = 2; const DWORD SPECIALS = SPECIAL_GROUP | SPECIAL_SINGLE; DWORD dwSpecial = 0; for(ULONG ul=0; ul<cPropertySets; ul++) { if( (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEALL) || (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEINFOALL) || (rgPropertySets[ul].guidPropertySet == DBPROPSET_DBINITALL) || (rgPropertySets[ul].guidPropertySet == DBPROPSET_SESSIONALL) || (rgPropertySets[ul].guidPropertySet == DBPROPSET_ROWSETALL) ) dwSpecial |= SPECIAL_GROUP; else dwSpecial |= SPECIAL_SINGLE;
if( (dwSpecial == SPECIALS) || (rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs)) ) return E_INVALIDARG; }
if (pT->m_dwStatus & DSF_INITIALIZED) return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets, pcPropertyInfoSets, prgPropertyInfoSets, ppDescBuffer, true); else return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets, pcPropertyInfoSets, prgPropertyInfoSets, ppDescBuffer, false, &DBPROPSET_DBINITALL);
}
STDMETHOD(SetProperties)(ULONG cPropertySets, DBPROPSET rgPropertySets[]) { ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::SetProperties\n"); HRESULT hr; DBPROPSET* pdbPropSet = NULL; ULONG iProp; const GUID* ppGuid[3]; T* pT = (T*)this;
// Quick return if the Count of Properties is 0
if( cPropertySets == 0 ) return S_OK;
hr = CUtlProps<T>::SetPropertiesArgChk(cPropertySets, rgPropertySets); if(SUCCEEDED(hr)) { // We need to handle the DBINIT properties specially after being initialized.
// - they should be treated as NOTSETTABLE at this point.
if( pT->m_dwStatus & DSF_INITIALIZED ) { ATLASSERT(cPropertySets);
BOOL fFoundDBINIT = FALSE;
// Allocate a DBPROPSET structure of equal size
ATLTRY(pdbPropSet = new DBPROPSET[cPropertySets]) if( pdbPropSet == NULL ) return E_OUTOFMEMORY;
for(ULONG iNewSet=0,iSet=0; iSet<cPropertySets; iSet++) { // Remove any DBPROPSET_DBINIT values and mark them all
// as not settable
if( (rgPropertySets[iSet].guidPropertySet == DBPROPSET_DBINIT)) { fFoundDBINIT = TRUE; for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++) rgPropertySets[iSet].rgProperties[iProp].dwStatus = DBPROPSTATUS_NOTSETTABLE; } else { // If not DBPROPSET_DBINIT then copy the DBPROPSET values
memcpy(&pdbPropSet[iNewSet++], &rgPropertySets[iSet], sizeof(DBPROPSET)); } }
// If we have no propertyset to pass on to the property handler, we
// can exit
if( iNewSet == 0 ) { hr = DB_E_ERRORSOCCURRED; goto exit; }
ppGuid[0] = &DBPROPSET_DBINIT; ppGuid[1] = &DBPROPSET_DATASOURCE; ppGuid[2] = &DBPROPSET_DATASOURCEINFO; hr = CUtlProps<T>::SetProperties(0, iNewSet, pdbPropSet, 3, ppGuid);
// If we have determined that one of the property sets was DBINIT, we may
// need to fixup the returned hr value.
if( fFoundDBINIT && SUCCEEDED(hr)) hr = DB_S_ERRORSOCCURRED; } else { // Note that m_pCUtlProps knows about initialization,
// so we don't have to here.
ppGuid[0] = &DBPROPSET_DBINIT; hr = CUtlProps<T>::SetProperties(0, cPropertySets, rgPropertySets, 1, ppGuid); } }
exit: delete[] pdbPropSet; return hr; } };
#define BEGIN_SCHEMA_MAP(SchemaClass) \
typedef SchemaClass _SchemaClass; \ HRESULT _SchemaSupport(GUID** ppGuid, \ IUnknown *pUnkOuter, \ REFIID rguidSchema, \ ULONG cRestrictions, \ const VARIANT rgRestrictions[], \ REFIID riid, \ ULONG cPropertySets, \ DBPROPSET rgPropertySets[], \ IUnknown **ppRowset) \ { \ int cGuids = 0; \ HRESULT hr = S_OK; \ if (ppGuid != NULL) \ *ppGuid = NULL;
#define SCHEMA_ENTRY(guid, rowsetClass) \
if (ppGuid != NULL && SUCCEEDED(hr)) \ { \ cGuids++; \ *ppGuid = (GUID*)CoTaskMemRealloc(*ppGuid, cGuids * sizeof(GUID)); \ hr = (*ppGuid == NULL) ? E_OUTOFMEMORY : S_OK; \ if (SUCCEEDED(hr)) \ (*ppGuid)[cGuids - 1] = guid; \ } \ else \ { \ if (InlineIsEqualGUID(guid, rguidSchema)) \ { \ rowsetClass* pRowset; \ hr = CreateSchemaRowset(pUnkOuter, cRestrictions, \ rgRestrictions, riid, cPropertySets, \ rgPropertySets, ppRowset, pRowset); \ return hr; \ } \ }
#define END_SCHEMA_MAP() \
if (ppGuid != NULL) \ return hr; \ return E_INVALIDARG; \ }
template <class SessionClass> class ATL_NO_VTABLE IDBSchemaRowsetImpl: public IDBSchemaRowset { public:
OUT_OF_LINE HRESULT InternalCreateSchemaRowset(IUnknown *pUnkOuter, ULONG /*cRestrictions*/, const VARIANT /*rgRestrictions*/[], REFIID riid, ULONG cPropertySets, DBPROPSET rgPropertySets[], IUnknown** ppRowset, IUnknown* pUnkThis, CUtlPropsBase* pProps, IUnknown* pUnkSession) { HRESULT hr, hrProps = S_OK; if (ppRowset != NULL) *ppRowset = NULL; if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) return DB_E_NOAGGREGATION; CComPtr<IUnknown> spUnk; hr = pUnkThis->QueryInterface(IID_IUnknown, (void**)&spUnk); if (FAILED(hr)) return hr; hr = pProps->FInit(); if (FAILED(hr)) return hr; hr = pProps->SetPropertiesArgChk(cPropertySets, rgPropertySets); if (FAILED(hr)) return hr; const GUID* ppGuid[1]; ppGuid[0] = &DBPROPSET_ROWSET;
// Call SetProperties. The true in the last parameter indicates
// the special behavior that takes place on rowset creation (i.e.
// it succeeds as long as any of the properties were not marked
// as DBPROPS_REQUIRED.
hrProps = pProps->SetProperties(0, cPropertySets, rgPropertySets, 1, ppGuid, true); if (FAILED(hrProps)) return hrProps;
if (ppRowset == NULL) return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
CComQIPtr<IObjectWithSite> spSite = spUnk; ATLASSERT(spSite != NULL); hr = spSite->SetSite(pUnkSession); if (FAILED(hr)) return hr; if (InlineIsEqualGUID(riid, IID_NULL)) return E_NOINTERFACE; hr = spUnk->QueryInterface(riid, (void**)ppRowset); if (FAILED(hr)) { *ppRowset = NULL; return hr; } return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr; }
template <class SchemaRowsetClass> HRESULT CreateSchemaRowset(IUnknown *pUnkOuter, ULONG cRestrictions, const VARIANT rgRestrictions[], REFIID riid, ULONG cPropertySets, DBPROPSET rgPropertySets[], IUnknown** ppRowset, SchemaRowsetClass*& pSchemaRowset) { HRESULT hrProps, hr = S_OK; SessionClass* pT = (SessionClass*) this; CComPolyObject<SchemaRowsetClass>* pPolyObj; if (FAILED(hr = CComPolyObject<SchemaRowsetClass>::CreateInstance(pUnkOuter, &pPolyObj))) return hr; pSchemaRowset = &(pPolyObj->m_contained); hr = InternalCreateSchemaRowset(pUnkOuter, cRestrictions, rgRestrictions, riid, cPropertySets, rgPropertySets, ppRowset, pPolyObj, pT, pT->GetUnknown()); // Ref the created COM object and Auto release it on failure
if (FAILED(hr)) return hr;
hrProps = hr; // Get a pointer to the Rowset instance
LONG cRowsAffected; hr = pSchemaRowset->Execute(&cRowsAffected, cRestrictions, rgRestrictions); if (FAILED(hr)) return hr; return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr; }
void SetRestrictions(ULONG cRestrictions, GUID* /*rguidSchema*/, ULONG* rgRestrictions) { memset(rgRestrictions, 0, sizeof(ULONG) * cRestrictions); }
STDMETHOD(GetSchemas)(ULONG * pcSchemas, GUID ** prgSchemas, ULONG** prgRest) { ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetSchemas\n"); if (pcSchemas != NULL) *pcSchemas = 0; if (prgSchemas != NULL) *prgSchemas = NULL; if (pcSchemas == NULL || prgSchemas == NULL) return E_INVALIDARG;
SessionClass* pT = (SessionClass*)this;
HRESULT hr = pT->_SchemaSupport(prgSchemas, NULL, GUID_NULL, 0, NULL, GUID_NULL, 0, NULL, NULL); if (FAILED(hr)) return hr;
CComPtr<IMalloc> spMalloc; hr = CoGetMalloc(1, &spMalloc); if (FAILED(hr)) { CoTaskMemFree(*prgSchemas); *prgSchemas = NULL; return hr; } *pcSchemas = (ULONG)(ULONG_PTR)spMalloc->GetSize(*prgSchemas) / sizeof(GUID);
if (prgRest != NULL) { // The OLE DB spec states that if prgRest == NULL not to return array
// but it also says that is E_INVALIDARG, so doing first
*prgRest = (ULONG*) spMalloc->Alloc(sizeof(ULONG) * (*pcSchemas)); if (*prgRest == NULL) { spMalloc->Free(*prgSchemas); *prgSchemas = NULL; return E_OUTOFMEMORY; } pT->SetRestrictions(*pcSchemas, *prgSchemas, *prgRest); } return hr; } STDMETHOD(GetRowset)(IUnknown *pUnkOuter, REFGUID rguidSchema, ULONG cRestrictions, const VARIANT rgRestrictions[], REFIID riid, ULONG cPropertySets, DBPROPSET rgPropertySets[], IUnknown **ppRowset) { ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetRowset\n"); SessionClass* pT = (SessionClass*)this; return pT->_SchemaSupport(NULL, pUnkOuter, rguidSchema, cRestrictions, rgRestrictions, riid, cPropertySets, rgPropertySets, ppRowset);
}
};
// IDBCreateCommandImpl
template <class T, class CommandClass> class ATL_NO_VTABLE IDBCreateCommandImpl : public IDBCreateCommand { public: STDMETHOD(CreateCommand)(IUnknown *pUnkOuter, REFIID riid, IUnknown **ppvCommand) { ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateCommandImpl::CreateCommand\n"); if (ppvCommand == NULL) return E_INVALIDARG; HRESULT hr; CComPolyObject<CommandClass>* pCommand;
// You can't QI for an interface other than IUnknown when aggregating
// and creating the object. You might ask for your own interface,
// which would be bad. Note, we return DB_E_NOAGGREGATION instead of
// CLASS_E_NOAGGREGATION due to OLE DB constraints.
if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid)) return DB_E_NOAGGREGATION;
hr = CComPolyObject<CommandClass>::CreateInstance(pUnkOuter, &pCommand); if (FAILED(hr)) return hr; // Ref the created COM object and Auto release it on failure
CComPtr<IUnknown> spUnk; hr = pCommand->QueryInterface(&spUnk); if (FAILED(hr)) { delete pCommand; // must hand delete as it is not ref'd
return hr; } ATLASSERT(pCommand->m_contained.m_spUnkSite == NULL); pCommand->m_contained.SetSite(this); hr = pCommand->QueryInterface(riid, (void**)ppvCommand); return hr; }
};
// IGetDataSourceImpl
template <class T> class ATL_NO_VTABLE IGetDataSourceImpl : public IGetDataSource { public: STDMETHOD(GetDataSource)(REFIID riid, IUnknown **ppDataSource) { ATLTRACE2(atlTraceDBProvider, 0, "IGetDataSourceImpl::GetDataSource\n"); if (ppDataSource == NULL) return E_INVALIDARG; T* pT = (T*) this; ATLASSERT(pT->m_spUnkSite != NULL); return pT->m_spUnkSite->QueryInterface(riid, (void**)ppDataSource); } };
// IOpenRowsetImpl
template <class SessionClass> class IOpenRowsetImpl : public IOpenRowset { public: template <class RowsetClass> HRESULT CreateRowset(IUnknown* pUnkOuter, DBID *pTableID, DBID *pIndexID, REFIID riid, ULONG cPropertySets, DBPROPSET rgPropertySets[], IUnknown** ppRowset, RowsetClass*& pRowsetObj) { HRESULT hr, hrProps = S_OK; if (ppRowset != NULL) *ppRowset = NULL; if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) return DB_E_NOAGGREGATION; CComPolyObject<RowsetClass>* pPolyObj; if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj))) return hr; // Ref the created COM object and Auto release it on failure
CComPtr<IUnknown> spUnk; hr = pPolyObj->QueryInterface(&spUnk); if (FAILED(hr)) { delete pPolyObj; // must hand delete as it is not ref'd
return hr; } // Get a pointer to the Rowset instance
pRowsetObj = &(pPolyObj->m_contained); hr = pRowsetObj->FInit(); if (FAILED(hr)) return hr; hr = pRowsetObj->SetPropertiesArgChk(cPropertySets, rgPropertySets); if (FAILED(hr)) return hr;
const GUID* ppGuid[1]; ppGuid[0] = &DBPROPSET_ROWSET;
// Call SetProperties. The true in the last parameter indicates
// the special behavior that takes place on rowset creation (i.e.
// it succeeds as long as any of the properties were not marked
// as DBPROPS_REQUIRED.
hrProps = pRowsetObj->SetProperties(0, cPropertySets, rgPropertySets, 1, ppGuid, true); if (FAILED(hrProps)) return hrProps;
pRowsetObj->SetSite(((SessionClass*)this)->GetUnknown());
hr = pRowsetObj->SetCommandText(pTableID, pIndexID); if (FAILED(hr)) return hr; DBROWCOUNT cRowsAffected; if (FAILED(hr = pRowsetObj->Execute(NULL, &cRowsAffected))) return hr; if (InlineIsEqualGUID(riid, IID_NULL)) { return E_NOINTERFACE; } else { if (ppRowset == NULL) return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
hr = pPolyObj->QueryInterface(riid, (void**)ppRowset); }
if (FAILED(hr)) { *ppRowset = NULL; return hr; } return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr; }
};
// IColumnsInfoImpl
template <class T> class ATL_NO_VTABLE IColumnsInfoImpl : public IColumnsInfo, public CDBIDOps { public:
HRESULT CheckCommandText(IUnknown* pUnkThis) { HRESULT hr = E_FAIL; CComPtr<ICommandText> spText; if (SUCCEEDED(hr = pUnkThis->QueryInterface(IID_ICommandText, (void**)&spText))) { LPOLESTR szCommand; hr = spText->GetCommandText(NULL, &szCommand); if (SUCCEEDED(hr)) CoTaskMemFree(szCommand); } return hr; } OUT_OF_LINE HRESULT InternalGetColumnInfo(DBORDINAL *pcColumns, ATLCOLUMNINFO** ppInfo) { ATLASSERT(ppInfo != NULL); T* pT = (T*) this; if (pT->CheckCommandText(pT->GetUnknown()) == DB_E_NOCOMMAND) return DB_E_NOCOMMAND; *ppInfo = T::GetColumnInfo(pT, pcColumns); return S_OK;
} STDMETHOD(GetColumnInfo)(DBORDINAL *pcColumns, DBCOLUMNINFO **prgInfo, OLECHAR **ppStringsBuffer) { ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::GetColumnInfo\n"); if (pcColumns == NULL || prgInfo == NULL || ppStringsBuffer == NULL) { if (prgInfo != NULL) *prgInfo = NULL; if (ppStringsBuffer != NULL) *ppStringsBuffer = NULL; if (pcColumns != NULL) *pcColumns = NULL; return E_INVALIDARG; }
// NULL out pointers in case of an error
*prgInfo = NULL; *ppStringsBuffer = NULL; *pcColumns = 0;
ATLCOLUMNINFO* pInfo; HRESULT hr = InternalGetColumnInfo(pcColumns, &pInfo); if (FAILED(hr)) return hr; ATLASSERT(pInfo != NULL); *prgInfo = (DBCOLUMNINFO*)CoTaskMemAlloc(*pcColumns * sizeof(DBCOLUMNINFO)); if (*prgInfo != NULL) { for (DBORDINAL iCol = 0, cwRequired = 0; iCol < *pcColumns; iCol++) { memcpy(&((*prgInfo)[iCol]), &pInfo[iCol], sizeof(DBCOLUMNINFO)); if (pInfo[iCol].pwszName) { cwRequired += wcslen(pInfo[iCol].pwszName) + 1; } } *ppStringsBuffer = (OLECHAR*)CoTaskMemAlloc(cwRequired*sizeof(OLECHAR)); if (*ppStringsBuffer) { for (DBORDINAL iCol = 0, iOffset = 0; iCol < *pcColumns; iCol++) { if (pInfo[iCol].pwszName) { lstrcpyW(*ppStringsBuffer + iOffset, pInfo[iCol].pwszName); iOffset += wcslen(*ppStringsBuffer + iOffset) + 1; } } return S_OK; } else { ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate string buffer\n")); CoTaskMemFree(*prgInfo); *prgInfo = NULL; *pcColumns = 0; return E_OUTOFMEMORY; } } else { ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ColumnInfo array\n")); *prgInfo = NULL; *pcColumns = 0; return E_OUTOFMEMORY; }
}
STDMETHOD(MapColumnIDs)(DBORDINAL cColumnIDs, const DBID rgColumnIDs[], DBORDINAL rgColumns[]) { ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::MapColumnIDs\n"); USES_CONVERSION; if ((cColumnIDs != 0 && rgColumnIDs == NULL) || rgColumns == NULL) return E_INVALIDARG; DBORDINAL cCols = 0; DBORDINAL cColsInError = 0; HRESULT hr = S_OK; ATLCOLUMNINFO* pInfo; for (DBORDINAL iColId = 0; iColId < cColumnIDs; iColId++) { hr = InternalGetColumnInfo(&cCols, &pInfo); if (hr == DB_E_NOCOMMAND) return hr; ULONG iColMapCur = 0; BOOL bDone = FALSE; while(iColMapCur < cCols && !bDone) { hr = CompareDBIDs(&(pInfo[iColMapCur].columnid), &(rgColumnIDs[iColId])); bDone = (hr == S_OK || FAILED(hr)); if (hr == S_OK) rgColumns[iColId] = pInfo[iColMapCur].iOrdinal; iColMapCur++; } if (!bDone || FAILED(hr)) { rgColumns[iColId] = DB_INVALIDCOLUMN; cColsInError++; }
} if (cColsInError > 0 && cColumnIDs == cColsInError) return DB_E_ERRORSOCCURRED; if (cColsInError > 0 && cColsInError < cColumnIDs) return DB_S_ERRORSOCCURRED; return S_OK; } };
//IConvertTypeImpl
template <class T> class ATL_NO_VTABLE IConvertTypeImpl : public IConvertType, public CConvertHelper { public: HRESULT InternalCanConvert(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags, bool bIsCommand, bool bHasParamaters, IObjectWithSite* pSite) {
// Check to see if conversion types are invalid. Note, this is just a
// quick test as it would be difficult to check each available type
// (as new DBTYPE values can be added).
if ((wFromType & 0x8000) || (wToType & 0x8000)) return E_INVALIDARG;
// Determine if new 2.x flags are valid
if((dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_COLUMN && (dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_PARAMETER ) return DB_E_BADCONVERTFLAG;
#ifdef _LATER
// If the convert flags are for DBCONVERTFLAGS_FROMVARIANT, check to see
// that the type is a variant type
if (dwConvertFlags == DBCONVERTFLAGS_FROMVARIANT) { if (wFromType != DBTYPE_VARIANT) return DB_E_BADTYPE; } #endif // _LATER
// Note, if the convert flag is either ISLONG or ISFIXEDLENGTH, then we should
// make sure we are not dealing with an OLE DB 1.x provider. However, since
// we default to 2.x providers, we don't check this. If you, change the
// DBPROP_PROVIDEROLEDBVER property in the DATASOURCEINFO group, you need to
// check the property value and return a DB_E_BADCONVERTFLAG if it is a 1.x
// provider.
// Do we have ISLONG on a fixed length data type?
DBTYPE dbtype = wFromType & ~(DBTYPE_BYREF|DBTYPE_VECTOR|DBTYPE_ARRAY|DBTYPE_RESERVED); if ((dwConvertFlags & DBCONVERTFLAGS_ISLONG) && (dbtype != DBTYPE_WSTR && dbtype != DBTYPE_STR && dbtype != DBTYPE_BYTES && dbtype != DBTYPE_VARNUMERIC)) return DB_E_BADCONVERTFLAG;
if (dwConvertFlags == DBCONVERTFLAGS_PARAMETER) { // In the case where we are a rowset and ask for a parameter
// conversion, return DB_E_BADCONVERTFLAG
if (!bIsCommand) return DB_E_BADCONVERTFLAG;
// In the case where we are a command and ask for a parameter
// conversion and ICommandWithParameters is not supported, return
// S_FALSE. We just can't convert them.
if (!bHasParamaters) return S_FALSE; }
// If we deal with a command and the user asks for a conversion on a rowset
// the DBPROP_ROWSETCONVERSIONSONCOMMAND must be suppored and set to TRUE.
if (bIsCommand && dwConvertFlags == DBCONVERTFLAGS_COLUMN) { CDBPropIDSet set(DBPROPSET_DATASOURCEINFO); set.AddPropertyID(DBPROP_ROWSETCONVERSIONSONCOMMAND); DBPROPSET* pPropSet = NULL; ULONG ulPropSet = 0; //HRESULT hr1 = S_OK;
// Get a pointer into the session
CComPtr<IGetDataSource> spDataSource = NULL; CComPtr<IDBProperties> spProps = NULL;
// if any of these calls fail, we're either unable to retrieve the
// property or it is unsupported. Since the property is only on
// the data source object, we use the IObjectWithSite interface to
// get the session object and then the GetDataSource method to get
// the data source object itself.
if (FAILED(pSite->GetSite(IID_IGetDataSource, (void**)&spDataSource))) return DB_E_BADCONVERTFLAG; if (FAILED(spDataSource->GetDataSource(IID_IDBProperties, (IUnknown**)&spProps))) return DB_E_BADCONVERTFLAG; if (FAILED(spProps->GetProperties(1, &set, &ulPropSet, &pPropSet))) return DB_E_BADCONVERTFLAG;
if (pPropSet != NULL) { CComVariant var = pPropSet->rgProperties[0].vValue; CoTaskMemFree(pPropSet->rgProperties); CoTaskMemFree(pPropSet);
if (var.boolVal == VARIANT_FALSE) return DB_E_BADCONVERTFLAG; } } HRESULT hr = E_FAIL; if (m_spConvert != NULL) { hr = m_spConvert->CanConvert(wFromType, wToType); } return hr; } STDMETHOD(CanConvert)(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags) { ATLTRACE2(atlTraceDBProvider, 0, "IConvertTypeImpl::CanConvert\n"); T* pT = (T*)this; return pT->InternalCanConvert(wFromType, wToType, dwConvertFlags, pT->m_bIsCommand, pT->m_bHasParamaters, pT); } };
template <class T, class PropClass = T> class ATL_NO_VTABLE ICommandPropertiesImpl : public ICommandProperties, public CUtlProps<PropClass> { public: typedef PropClass _PropClass;
STDMETHOD(GetProperties)(const ULONG cPropertyIDSets, const DBPROPIDSET rgPropertyIDSets[], ULONG *pcPropertySets, DBPROPSET **prgPropertySets) { ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::GetProperties\n"); HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); const GUID* ppGuid[1]; ppGuid[0] = &DBPROPSET_ROWSET; if(SUCCEEDED(hr)) hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets, 1, ppGuid); return hr;
}
STDMETHOD(SetProperties)(ULONG cPropertySets, DBPROPSET rgPropertySets[]) { ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::SetProperties\n"); HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets); const GUID* ppGuid[1]; ppGuid[0] = &DBPROPSET_ROWSET; if(SUCCEEDED(hr)) hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets, rgPropertySets, 1, ppGuid); return hr; } };
template <class T> class CRunTimeFree { public:
static void Free(T* pData) { delete [] pData; } };
template <class T> class CComFree { public:
static void Free(T* pData) { CoTaskMemFree(pData); } };
template <class T, class DeAllocator = CRunTimeFree < T > > class CAutoMemRelease { public: CAutoMemRelease() { m_pData = NULL; }
CAutoMemRelease(T* pData) { m_pData = pData; }
~CAutoMemRelease() { Attach(NULL); }
void Attach(T* pData) { DeAllocator::Free(m_pData); m_pData = pData; }
T* Detach() { T* pTemp = m_pData; m_pData = NULL; return pTemp; }
T* m_pData; };
template <class T> class ATL_NO_VTABLE ICommandImpl : public ICommand { public: ICommandImpl() { m_bIsExecuting = FALSE; m_bCancelWhenExecuting = TRUE; m_bCancel = FALSE; } HRESULT CancelExecution() { T* pT = (T*)this; pT->Lock(); m_bCancel = TRUE; pT->Unlock(); return S_OK; } STDMETHOD(Cancel)() { ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::Cancel\n"); HRESULT hr = S_OK; T* pT = (T*)this;
if (m_bIsExecuting && m_bCancelWhenExecuting) { hr = pT->CancelExecution(); return hr; } if (m_bIsExecuting && !m_bCancelWhenExecuting) hr = DB_E_CANTCANCEL; return hr; } STDMETHOD(GetDBSession)(REFIID riid, IUnknown ** ppSession) { ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::GetDBSession\n"); T* pT = (T*)this; ATLASSERT(pT->m_spUnkSite != NULL); return pT->m_spUnkSite->QueryInterface(riid, (void**) ppSession); }
template <class RowsetClass> HRESULT CreateRowset(IUnknown* pUnkOuter, REFIID riid, DBPARAMS * pParams, DBROWCOUNT * pcRowsAffected, IUnknown** ppRowset, RowsetClass*& pRowsetObj) { HRESULT hr; USES_CONVERSION; int iBind; T* pT = (T*)this; if (ppRowset != NULL) *ppRowset = NULL; if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) return DB_E_NOAGGREGATION; CComPolyObject<RowsetClass>* pPolyObj; if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj))) return hr; // Ref the created COM object and Auto release it on failure
CComPtr<IUnknown> spUnk; hr = pPolyObj->QueryInterface(&spUnk); if (FAILED(hr)) { delete pPolyObj; // must hand delete as it is not ref'd
return hr; } // Get a pointer to the Rowset instance
pRowsetObj = &(pPolyObj->m_contained);
if (FAILED(hr = pRowsetObj->FInit(pT))) return hr; pRowsetObj->SetSite(pT->GetUnknown());
if (pT->m_strCommandText.Length() == 0) { ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::No command text specified.\n"); return DB_E_NOCOMMAND; }
pRowsetObj->m_strCommandText = pT->m_strCommandText; if (pRowsetObj->m_strCommandText == (BSTR)NULL) return E_OUTOFMEMORY; if (FAILED(hr = pRowsetObj->Execute(pParams, pcRowsAffected))) return hr; if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL) { if (ppRowset != NULL) *ppRowset = NULL; return hr; } hr = pPolyObj->QueryInterface(riid, (void**)ppRowset); if (FAILED(hr)) return hr; for (iBind = 0; iBind < pT->m_rgBindings.GetSize(); iBind++) { T::_BindType* pBind = NULL; T::_BindType* pBindSrc = NULL; ATLTRY(pBind = new T::_BindType); if (pBind == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "Failed to allocate memory for new Binding\n"); return E_OUTOFMEMORY; } // auto cleanup on failure
CAutoMemRelease<T::_BindType> amr(pBind); pBindSrc = pT->m_rgBindings.GetValueAt(iBind); if (pBindSrc == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "The map appears to be corrupted, failing!!\n"); return E_FAIL; } if (!pRowsetObj->m_rgBindings.Add(pT->m_rgBindings.GetKeyAt(iBind), pBind)) { ATLTRACE2(atlTraceDBProvider, 0, "Failed to add hAccessor to Map\n"); return E_OUTOFMEMORY; } if (pBindSrc->cBindings) { ATLTRY(pBind->pBindings = new DBBINDING[pBindSrc->cBindings]) if (pBind->pBindings == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "Failed to Allocate dbbinding Array\n"); // We added it, must now remove on failure
pRowsetObj->m_rgBindings.Remove(pT->m_rgBindings.GetKeyAt(iBind)); return E_OUTOFMEMORY; } } else { pBind->pBindings = NULL; // NULL Accessor
}
pBind->dwAccessorFlags = pBindSrc->dwAccessorFlags; pBind->cBindings = pBindSrc->cBindings; pBind->dwRef = 1; memcpy (pBind->pBindings, pBindSrc->pBindings, (pBindSrc->cBindings)*sizeof(DBBINDING)); pBind = amr.Detach(); }
return S_OK; }
unsigned m_bIsExecuting:1; unsigned m_bCancelWhenExecuting:1; unsigned m_bCancel:1; };
template <class T> class ATL_NO_VTABLE ICommandTextImpl : public ICommandImpl<T> { public: STDMETHOD(GetCommandText)(GUID * /*pguidDialect*/,LPOLESTR * ppwszCommand) { ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText\n"); UINT cchCommandText; HRESULT hr = E_FAIL; if (ppwszCommand == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n"); return E_INVALIDARG; } if (m_strCommandText.m_str == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n"); return DB_E_NOCOMMAND; } cchCommandText = sizeof(OLECHAR) * (m_strCommandText.Length() + 1); *ppwszCommand = (OLECHAR*)CoTaskMemAlloc(cchCommandText); if (*ppwszCommand != NULL) { memcpy(*ppwszCommand, m_strCommandText.m_str, cchCommandText); *(*ppwszCommand + m_strCommandText.Length()) = (OLECHAR)NULL; return S_OK; } *ppwszCommand = NULL; return hr; }
STDMETHOD(SetCommandText)(REFGUID /*rguidDialect*/,LPCOLESTR pwszCommand) { T* pT = (T*)this; ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::SetCommandText\n"); pT->Lock(); m_strCommandText = pwszCommand; pT->Unlock(); return S_OK; }
CComBSTR m_strCommandText; };
// ISessionPropertiesImpl
template <class T, class PropClass = T> class ATL_NO_VTABLE ISessionPropertiesImpl : public ISessionProperties, public CUtlProps<PropClass> { public: typedef PropClass _PropClass;
STDMETHOD(GetProperties)(ULONG cPropertyIDSets, const DBPROPIDSET rgPropertyIDSets[], ULONG *pcPropertySets, DBPROPSET **prgPropertySets) { ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::GetProperties\n"); HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); const GUID* ppGuid[1]; ppGuid[0] = &DBPROPSET_SESSION;
if(SUCCEEDED(hr)) hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets, 1, ppGuid); return hr;
}
STDMETHOD(SetProperties)(ULONG cPropertySets, DBPROPSET rgPropertySets[]) { ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::SetProperties"); HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets); const GUID* ppGuid[1];
ppGuid[0] = &DBPROPSET_SESSION; if(SUCCEEDED(hr)) hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets, rgPropertySets, 1, ppGuid); return hr; } };
// Implementation Class
template <class BindType> class ATL_NO_VTABLE IAccessorImplBase : public IAccessor { public:
STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags, DBCOUNTITEM cBindings, const DBBINDING rgBindings[], DBLENGTH /*cbRowSize*/, HACCESSOR *phAccessor, DBBINDSTATUS rgStatus[]) { if (!(dwAccessorFlags & DBACCESSOR_PARAMETERDATA) && !(dwAccessorFlags & DBACCESSOR_ROWDATA)) return DB_E_BADACCESSORFLAGS; if (dwAccessorFlags == DBACCESSOR_INVALID) return DB_E_BADACCESSORFLAGS; if (dwAccessorFlags > 0x000F) return DB_E_BADACCESSORFLAGS; BindType *pBind = NULL; ATLTRY(pBind = new BindType) if (pBind == NULL) { ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ATL Binding struct\n")); return E_OUTOFMEMORY; } if (cBindings) { ATLTRY(pBind->pBindings = new DBBINDING[cBindings]) if (pBind->pBindings == NULL) { delete pBind; return E_OUTOFMEMORY; } } else pBind->pBindings = NULL; // NULL Accessor
pBind->dwAccessorFlags = dwAccessorFlags; pBind->cBindings = cBindings; pBind->dwRef = 1; memcpy (pBind->pBindings, rgBindings, cBindings*sizeof(DBBINDING)); DBBINDSTATUS status = DBBINDSTATUS_OK; memset (rgStatus, status, sizeof(DBBINDSTATUS)*cBindings); *phAccessor = (ULONG_PTR)pBind; return S_OK; } BOOL HasFlag(DBTYPE dbToCheck, DBTYPE dbCombo) { return ( (dbToCheck & dbCombo) == dbCombo ); } HRESULT ValidateBindings(DBCOUNTITEM cBindings, const DBBINDING rgBindings[], DBBINDSTATUS rgStatus[], bool bHasBookmarks) { HRESULT hr = S_OK;;
for (ULONG iBinding = 0; iBinding < cBindings; iBinding++) { const DBBINDING& rBindCur = rgBindings[iBinding]; if (rBindCur.iOrdinal == 0) { if (!m_bIsCommand && !bHasBookmarks) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL; continue; } } if (rBindCur.dwPart == 0) // nothing to bind to
{ hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_ARRAY))) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_VECTOR))) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } if (HasFlag(rBindCur.wType, (DBTYPE_VECTOR | DBTYPE_ARRAY))) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } if (rBindCur.wType == DBTYPE_NULL || rBindCur.wType == DBTYPE_EMPTY) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } if (HasFlag(rBindCur.wType, DBTYPE_RESERVED)) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } // Search for DBTYPE_BYREF | DBTYPE_EMPTY
if ((rBindCur.wType & 0xBFFF) == 0) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } if ((rBindCur.wType & 0xBFFE) == 0) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED) { BOOL bIsPointerType = HasFlag(rBindCur.wType, DBTYPE_BYREF) || HasFlag(rBindCur.wType, DBTYPE_VECTOR) || HasFlag(rBindCur.wType, DBTYPE_ARRAY) || HasFlag(~(DBTYPE_BYREF) & rBindCur.wType, DBTYPE_BSTR); if (!bIsPointerType) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } }
} return hr; }
unsigned m_bIsCommand:1; unsigned m_bHasParamaters:1; unsigned m_bIsChangeable:1; };
// IAccessorImpl
template <class T, class BindType = ATLBINDINGS, class BindingVector = CSimpleMap < INT_PTR, BindType* > > class ATL_NO_VTABLE IAccessorImpl : public IAccessorImplBase<BindType> { public: typedef BindType _BindType; typedef BindingVector _BindingVector; IAccessorImpl() { m_bIsCommand = FALSE; m_bHasParamaters = FALSE; m_bIsChangeable = FALSE; } OUT_OF_LINE HRESULT InternalFinalConstruct(IUnknown* pUnkThis) { CComQIPtr<ICommand> spCommand = pUnkThis; if (spCommand != NULL) { m_bIsCommand = TRUE; CComQIPtr<ICommandWithParameters> spCommandParams = pUnkThis; m_bHasParamaters = spCommandParams != NULL; } else // its a Rowset
{ CComQIPtr<IRowsetChange> spRSChange = pUnkThis; m_bIsChangeable = spRSChange != NULL; } return S_OK; } HRESULT FinalConstruct() { T* pT = (T*)this; return InternalFinalConstruct(pT->GetUnknown()); } void FinalRelease() { #ifdef _DEBUG
if (m_rgBindings.GetSize()) ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::~IAccessorImpl Bindings still in vector, removing\n"); #endif //_DEBUG
while (m_rgBindings.GetSize()) ReleaseAccessor((HACCESSOR)m_rgBindings.GetKeyAt(0), NULL); } STDMETHOD(AddRefAccessor)(HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) { ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::AddRefAccessor\n"); if (hAccessor == NULL) { ATLTRACE2(atlTraceDBProvider, 0, _T("AddRefAccessor : Bad hAccessor\n")); return E_INVALIDARG; } if (pcRefCount == NULL) pcRefCount = (ULONG*)_alloca(sizeof(ULONG));
BindType* pBind = m_rgBindings.Lookup((int)hAccessor); *pcRefCount = T::_ThreadModel::Increment((LONG*)&pBind->dwRef); return S_OK; } OUT_OF_LINE ATLCOLUMNINFO* ValidateHelper(DBORDINAL* pcCols, CComPtr<IDataConvert> & rspConvert) { T* pT = (T*)this; rspConvert = pT->m_spConvert; return pT->GetColumnInfo(pT, pcCols); } OUT_OF_LINE HRESULT ValidateBindingsFromMetaData(DBCOUNTITEM cBindings, const DBBINDING rgBindings[], DBBINDSTATUS rgStatus[], bool bHasBookmarks) { HRESULT hr = S_OK; DBORDINAL cCols; CComPtr<IDataConvert> spConvert; ATLCOLUMNINFO* pColInfo = ValidateHelper(&cCols, spConvert); ATLASSERT(pColInfo != NULL); for (ULONG iBinding = 0; iBinding < cBindings; iBinding++) { const DBBINDING& rBindCur = rgBindings[iBinding]; DBORDINAL iOrdAdjusted; if (bHasBookmarks) iOrdAdjusted = rBindCur.iOrdinal; // Bookmarks start with ordinal 0
else iOrdAdjusted = rBindCur.iOrdinal - 1; // Non-bookmarks start w/ ordinal 1
if (rBindCur.iOrdinal > cCols) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL; continue; }
// If a binding specifies provider owned memory, and specifies type
// X | BYREF, and the provider's copy is not X or X | BYREF, return
// DBBINDSTATUS_BADBINDINFO
if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED) { if ((rBindCur.wType & DBTYPE_BYREF) != 0) { DBTYPE dbConsumerType = rBindCur.wType & 0xBFFF; DBTYPE dbProviderType = pColInfo[iOrdAdjusted].wType & 0xBFFF;
if (dbConsumerType != dbProviderType) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO; continue; } } }
ATLASSERT(spConvert != NULL); HRESULT hrConvert = spConvert->CanConvert(pColInfo[iOrdAdjusted].wType, rBindCur.wType); if (FAILED(hrConvert) || hrConvert == S_FALSE) { hr = DB_E_ERRORSOCCURRED; rgStatus[iBinding] = DBBINDSTATUS_UNSUPPORTEDCONVERSION; continue; } } return hr; } STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags, DBCOUNTITEM cBindings, const DBBINDING rgBindings[], DBLENGTH cbRowSize, HACCESSOR *phAccessor, DBBINDSTATUS rgStatus[]) { ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor\n"); T* pT = (T*)this; T::ObjectLock cab(pT);
if (!phAccessor) { ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Inavlid NULL Parameter for HACCESSOR*\n"); return E_INVALIDARG; } *phAccessor = NULL; if (cBindings != 0 && rgBindings == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Bad Binding array\n"); return E_INVALIDARG; } if (dwAccessorFlags & DBACCESSOR_PASSBYREF) { CComVariant varByRef; HRESULT hr = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BYREFACCESSORS, &varByRef); if (FAILED(hr) || varByRef.boolVal == VARIANT_FALSE) return DB_E_BYREFACCESSORNOTSUPPORTED; } if (!m_bHasParamaters) { if (dwAccessorFlags & DBACCESSOR_PARAMETERDATA) return DB_E_BADACCESSORFLAGS; } if (m_bIsCommand || !m_bIsChangeable) { if (cBindings == 0) // No NULL Accessors on the command
return DB_E_NULLACCESSORNOTSUPPORTED; }
if (rgStatus == NULL && cBindings) // Create a fake status array
rgStatus = (DBBINDSTATUS*)_alloca(cBindings*sizeof(DBBINDSTATUS));
// Validate the Binding passed
HRESULT hr; bool bHasBookmarks = false; CComVariant varBookmarks; HRESULT hrLocal = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BOOKMARKS, &varBookmarks); bHasBookmarks = (hrLocal == S_OK && varBookmarks.boolVal == VARIANT_TRUE);
hr = ValidateBindings(cBindings, rgBindings, rgStatus, bHasBookmarks); if (FAILED(hr)) return hr; if (!m_bIsCommand) { hr = ValidateBindingsFromMetaData(cBindings, rgBindings, rgStatus, bHasBookmarks); if (FAILED(hr)) return hr; } hr = IAccessorImplBase<BindType>::CreateAccessor(dwAccessorFlags, cBindings, rgBindings, cbRowSize, phAccessor,rgStatus); if (SUCCEEDED(hr)) { ATLASSERT(*phAccessor != NULL); BindType* pBind = (BindType*)*phAccessor; hr = m_rgBindings.Add((HACCESSOR)pBind, pBind) ? S_OK : E_OUTOFMEMORY; } return hr;
}
STDMETHOD(GetBindings)(HACCESSOR hAccessor, DBACCESSORFLAGS *pdwAccessorFlags, DBCOUNTITEM *pcBindings, DBBINDING **prgBindings) { ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::GetBindings");
// Zero output parameters in case of failure
if (pdwAccessorFlags != NULL) *pdwAccessorFlags = NULL;
if (pcBindings != NULL) *pcBindings = NULL;
if (prgBindings != NULL) *prgBindings = NULL;
// Check if any of the out params are NULL pointers
if ((pdwAccessorFlags && pcBindings && prgBindings) == NULL) return E_INVALIDARG;
BindType* pBind = m_rgBindings.Lookup((int)hAccessor); HRESULT hr = DB_E_BADACCESSORHANDLE; if (pBind != NULL) { *pdwAccessorFlags = pBind->dwAccessorFlags; *pcBindings = pBind->cBindings; *prgBindings = (DBBINDING*)CoTaskMemAlloc(*pcBindings * sizeof(DBBINDING)); if (*prgBindings == NULL) return E_OUTOFMEMORY; memcpy(*prgBindings, pBind->pBindings, sizeof(DBBINDING) * (*pcBindings)); hr = S_OK; } return hr; }
STDMETHOD(ReleaseAccessor)(HACCESSOR hAccessor, DBREFCOUNT *pcRefCount) { ATLTRACE2(atlTraceDBProvider, 0, _T("IAccessorImpl::ReleaseAccessor\n")); BindType* pBind = m_rgBindings.Lookup((int)hAccessor); if (pBind == NULL) return DB_E_BADACCESSORHANDLE;
if (pcRefCount == NULL) pcRefCount = (DBREFCOUNT*)_alloca(sizeof(DBREFCOUNT)); *pcRefCount = T::_ThreadModel::Decrement((LONG*)&pBind->dwRef); if (!(*pcRefCount)) { delete [] pBind->pBindings; delete pBind; return m_rgBindings.Remove((int)hAccessor) ? S_OK : DB_E_BADACCESSORHANDLE; } return S_OK; }
BindingVector m_rgBindings; };
#define BEGIN_PROVIDER_COLUMN_MAP(theClass) \
typedef theClass _Class; \ template <class T> \ static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols) \ { \ pv; \ static ATLCOLUMNINFO _rgColumns [] = \ {
#define SIZEOF_MEMBER(memberOf, member) \
sizeof(((memberOf*)0)->member) #define EXPANDGUID(guid) \
{ guid.Data1, guid.Data2, guid.Data3, \ { guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] } }
#define PROVIDER_COLUMN_ENTRY_GN(name, ordinal, flags, colSize, dbtype, precision, scale, guid) \
{ (LPOLESTR)name, (ITypeInfo*)NULL, (ULONG)ordinal, (DBCOLUMNFLAGS)flags, (ULONG)colSize, (DBTYPE)dbtype, (BYTE)precision, (BYTE)scale, { EXPANDGUID(guid), (DWORD)0, (LPOLESTR) name}, 0},
#define PROVIDER_COLUMN_ENTRY(name, ordinal, member) \
{ \ (LPOLESTR)OLESTR(name), \ (ITypeInfo*)NULL, \ (ULONG)ordinal, \ DBCOLUMNFLAGS_ISFIXEDLENGTH, \ (ULONG)sizeof(((_Class*)0)->member), \ _GetOleDBType(((_Class*)0)->member), \ (BYTE)0, \ (BYTE)0, \ { \ EXPANDGUID(GUID_NULL), \ (DWORD)2, \ (LPOLESTR) name \ }, \ offsetof(_Class, member) \ },
#define PROVIDER_COLUMN_ENTRY_LENGTH(name, ordinal, size, member) \
{ \ (LPOLESTR)OLESTR(name), \ (ITypeInfo*)NULL, \ (ULONG)ordinal, \ DBCOLUMNFLAGS_ISFIXEDLENGTH, \ (ULONG)size, \ _GetOleDBType(((_Class*)0)->member), \ (BYTE)0, \ (BYTE)0, \ { \ EXPANDGUID(GUID_NULL), \ (DWORD)2, \ (LPOLESTR) name \ }, \ offsetof(_Class, member) \ },
#define PROVIDER_COLUMN_ENTRY_TYPE_LENGTH(name, ordinal, type, size, member) \
{ \ (LPOLESTR)OLESTR(name), \ (ITypeInfo*)NULL, \ (ULONG)ordinal, \ DBCOLUMNFLAGS_ISFIXEDLENGTH, \ (ULONG)size, \ (DBTYPE)type, \ (BYTE)0, \ (BYTE)0, \ { \ EXPANDGUID(GUID_NULL), \ (DWORD)2, \ (LPOLESTR) name \ }, \ offsetof(_Class, member) \ },
#define PROVIDER_COLUMN_ENTRY_FIXED(name, ordinal, dbtype, member) \
{ \ (LPOLESTR)OLESTR(name), \ (ITypeInfo*)NULL, \ (ULONG)ordinal, \ DBCOLUMNFLAGS_ISFIXEDLENGTH, \ (ULONG)sizeof(((_Class*)0)->member), \ (DBTYPE)dbtype, \ (BYTE)0, \ (BYTE)0, \ { \ EXPANDGUID(GUID_NULL), \ (DWORD)2, \ (LPOLESTR) name \ }, \ offsetof(_Class, member) \ },
#define PROVIDER_COLUMN_ENTRY_STR(name, ordinal, member) \
{ \ (LPOLESTR)OLESTR(name), \ (ITypeInfo*)NULL, \ (ULONG)ordinal, \ 0, \ (ULONG)sizeof(((_Class*)0)->member), \ DBTYPE_STR, \ (BYTE)0xFF, \ (BYTE)0xFF, \ { \ EXPANDGUID(GUID_NULL), \ (DWORD)2, \ (LPOLESTR) name \ }, \ offsetof(_Class, member) \ },
#define PROVIDER_COLUMN_ENTRY_WSTR(name, ordinal, member) \
{ \ (LPOLESTR)OLESTR(name), \ (ITypeInfo*)NULL, \ (ULONG)ordinal, \ 0, \ (ULONG)sizeof(((_Class*)0)->member), \ DBTYPE_WSTR, \ (BYTE)0xFF, \ (BYTE)0xFF, \ { \ EXPANDGUID(GUID_NULL), \ (DWORD)2, \ (LPOLESTR) name \ }, \ offsetof(_Class, member) \ },
#define END_PROVIDER_COLUMN_MAP() \
}; *pcCols = sizeof(_rgColumns)/sizeof(ATLCOLUMNINFO); return _rgColumns;}
// Implementation Class
class CSimpleRow { public: typedef DBROWCOUNT KeyType;
CSimpleRow(DBROWCOUNT iRowsetCur) { m_dwRef = 0; m_iRowset = iRowsetCur; } ~CSimpleRow() { } DWORD AddRefRow() { return CComObjectThreadModel::Increment((LPLONG)&m_dwRef); } DWORD ReleaseRow() { return CComObjectThreadModel::Decrement((LPLONG)&m_dwRef); }
HRESULT Compare(CSimpleRow* pRow) { ATLASSERT(pRow != NULL); return (m_iRowset == pRow->m_iRowset) ? S_OK : S_FALSE; }
KeyType m_iRowset; DWORD m_dwRef; };
// IRowsetImpl
template <class T, class RowsetInterface, class RowClass = CSimpleRow, class MapClass = CSimpleMap < RowClass::KeyType, RowClass* > > class ATL_NO_VTABLE IRowsetImpl : public RowsetInterface { public: typedef RowClass _HRowClass; IRowsetImpl() { m_iRowset = 0; m_bCanScrollBack = false; m_bCanFetchBack = false; m_bReset = true; } ~IRowsetImpl() { for (int i = 0; i < m_rgRowHandles.GetSize(); i++) delete (m_rgRowHandles.GetValueAt(i)); } HRESULT RefRows(DBCOUNTITEM cRows, const HROW rghRows[], ULONG rgRefCounts[], DBROWSTATUS rgRowStatus[], BOOL bAdd) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n"); if (cRows == 0) return S_OK; if (rghRows == NULL) return E_INVALIDARG; T::ObjectLock cab((T*)this); BOOL bSuccess1 = FALSE; BOOL bFailed1 = FALSE; DBROWSTATUS rs; DWORD dwRef; for (ULONG iRow = 0; iRow < cRows; iRow++) { HROW hRowCur = rghRows[iRow]; RowClass* pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRowCur); if (pRow == NULL) { ATLTRACE2(atlTraceDBProvider, 0, "Could not find HANDLE %x in list\n"); rs = DBROWSTATUS_E_INVALID; dwRef = 0; bFailed1 = TRUE; } else { if (bAdd) dwRef = pRow->AddRefRow(); else { dwRef = pRow->ReleaseRow(); if (dwRef == 0) { delete pRow; m_rgRowHandles.Remove((RowClass::KeyType)hRowCur); } } bSuccess1 = TRUE; rs = DBROWSTATUS_S_OK; } if (rgRefCounts) rgRefCounts[iRow] = dwRef; if (rgRowStatus != NULL) rgRowStatus[iRow] = rs; } if (!bSuccess1 && !bFailed1) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RefRows Unexpected state\n"); return E_FAIL; } HRESULT hr = S_OK; if (bSuccess1 && bFailed1) hr = DB_S_ERRORSOCCURRED; if (!bSuccess1 && bFailed1) hr = DB_E_ERRORSOCCURRED; return hr; }
STDMETHOD(AddRefRows)(DBCOUNTITEM cRows, const HROW rghRows[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n"); if (cRows == 0) return S_OK; return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, TRUE); } virtual DBSTATUS GetDBStatus(RowClass* , ATLCOLUMNINFO*) { return DBSTATUS_S_OK; } OUT_OF_LINE HRESULT GetDataHelper(HACCESSOR hAccessor, ATLCOLUMNINFO*& rpInfo, void** ppBinding, void*& rpSrcData, DBORDINAL& rcCols, CComPtr<IDataConvert>& rspConvert, RowClass* pRow) { ATLASSERT(ppBinding != NULL); T* pT = (T*) this; *ppBinding = (void*)pT->m_rgBindings.Lookup((int)hAccessor); if (*ppBinding == NULL) return DB_E_BADACCESSORHANDLE; rpSrcData = (void*)&(pT->m_rgRowData[(int)(INT_PTR)(pRow->m_iRowset)]); rpInfo = T::GetColumnInfo((T*)this, &rcCols); rspConvert = pT->m_spConvert; return S_OK;
} STDMETHOD(GetData)(HROW hRow, HACCESSOR hAccessor, void *pDstData) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetData\n"); if (pDstData == NULL) return E_INVALIDARG; HRESULT hr = S_OK; RowClass* pRow = (RowClass*)hRow; if (hRow == NULL || (pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRow)) == NULL) return DB_E_BADROWHANDLE; T::_BindType* pBinding; void* pSrcData; DBORDINAL cCols; ATLCOLUMNINFO* pColInfo; CComPtr<IDataConvert> spConvert; hr = GetDataHelper(hAccessor, pColInfo, (void**)&pBinding, pSrcData, cCols, spConvert, pRow); if (FAILED(hr)) return hr; for (ULONG iBind =0; iBind < pBinding->cBindings; iBind++) { DBBINDING* pBindCur = &(pBinding->pBindings[iBind]); for (ULONG iColInfo = 0; iColInfo < cCols && pBindCur->iOrdinal != pColInfo[iColInfo].iOrdinal; iColInfo++); if (iColInfo == cCols) return DB_E_BADORDINAL; ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]); // Ordinal found at iColInfo
BOOL bProvOwn = pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED; bProvOwn; DBSTATUS dbStat = GetDBStatus(pRow, pColCur);
// If the provider's field is NULL, we can optimize this situation,
// set the fields to 0 and continue.
if (dbStat == DBSTATUS_S_ISNULL) { if (pBindCur->dwPart & DBPART_STATUS) *((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat;
if (pBindCur->dwPart & DBPART_LENGTH) *((ULONG*)((BYTE*)(pDstData) + pBindCur->obLength)) = 0;
if (pBindCur->dwPart & DBPART_VALUE) *((BYTE*)(pDstData) + pBindCur->obValue) = NULL; continue; } DBLENGTH cbDst = pBindCur->cbMaxLen; DBLENGTH cbCol; BYTE* pSrcTemp;
if (bProvOwn && pColCur->wType == pBindCur->wType) { pSrcTemp = ((BYTE*)(pSrcData) + pColCur->cbOffset); } else { BYTE* pDstTemp = (BYTE*)pDstData + pBindCur->obValue; switch (pColCur->wType) { case DBTYPE_STR: cbCol = lstrlenA((LPSTR)(((BYTE*)pSrcData) + pColCur->cbOffset)); break; case DBTYPE_WSTR: case DBTYPE_BSTR: cbCol = lstrlenW((LPWSTR)(((BYTE*)pSrcData) + pColCur->cbOffset)) * sizeof(WCHAR); break; default: cbCol = pColCur->ulColumnSize; break; } if (pBindCur->dwPart & DBPART_VALUE) { hr = spConvert->DataConvert(pColCur->wType, pBindCur->wType, cbCol, &cbDst, (BYTE*)(pSrcData) + pColCur->cbOffset, pDstTemp, pBindCur->cbMaxLen, dbStat, &dbStat, pBindCur->bPrecision, pBindCur->bScale,0); } } if (pBindCur->dwPart & DBPART_LENGTH) *((DBLENGTH*)((BYTE*)(pDstData) + pBindCur->obLength)) = cbDst; if (pBindCur->dwPart & DBPART_STATUS) *((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat; if (FAILED(hr)) return hr; } return hr; }
HRESULT CreateRow(DBROWOFFSET lRowsOffset, DBCOUNTITEM& cRowsObtained, HROW* rgRows) { RowClass* pRow = NULL; ATLASSERT(lRowsOffset >= 0); RowClass::KeyType key = lRowsOffset+1; ATLASSERT(key > 0); pRow = m_rgRowHandles.Lookup(key); if (pRow == NULL) { ATLTRY(pRow = new RowClass(lRowsOffset)) if (pRow == NULL) return E_OUTOFMEMORY; if (!m_rgRowHandles.Add(key, pRow)) return E_OUTOFMEMORY; } pRow->AddRefRow(); m_bReset = false; rgRows[cRowsObtained++] = (HROW)key; return S_OK; }
STDMETHOD(GetNextRows)(HCHAPTER /*hReserved*/, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM *pcRowsObtained, HROW **prghRows) { DBROWOFFSET lTmpRows = lRowsOffset; ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetNextRows\n"); if (pcRowsObtained != NULL) *pcRowsObtained = 0; if (prghRows == NULL || pcRowsObtained == NULL) return E_INVALIDARG; if (cRows == 0) return S_OK; HRESULT hr = S_OK; T* pT = (T*) this; T::ObjectLock cab(pT); if (lRowsOffset < 0 && !m_bCanScrollBack) return DB_E_CANTSCROLLBACKWARDS; if (cRows < 0 && !m_bCanFetchBack) return DB_E_CANTFETCHBACKWARDS;
// Calculate # of rows in set and the base fetch position. If the rowset
// is at its head position, then lRowOffset < 0 means moving from the BACK
// of the rowset and not the front.
DBROWCOUNT cRowsInSet = pT->m_rgRowData.GetSize(); if (((lRowsOffset == LONG_MIN) && (cRowsInSet != LONG_MIN)) || (abs((int)(INT_PTR)lRowsOffset)) > cRowsInSet || (abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset < 0 && cRows < 0) || (abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset > 0 && cRows > 0)) return DB_S_ENDOFROWSET;
// In the case where the user is moving backwards after moving forwards,
// we do not wrap around to the end of the rowset.
if ((m_iRowset == 0 && !m_bReset && cRows < 0) || (((LONG)m_iRowset + lRowsOffset) > cRowsInSet) || (m_iRowset == (DWORD)cRowsInSet && lRowsOffset >= 0 && cRows > 0)) return DB_S_ENDOFROWSET;
// Note, if m_bReset, m_iRowset must be 0
if (lRowsOffset < 0 && m_bReset) { ATLASSERT(m_iRowset == 0); m_iRowset = cRowsInSet; }
int iStepSize = cRows >= 0 ? 1 : -1;
// If cRows == LONG_MIN, we can't use ABS on it. Therefore, we reset it
// to a value just greater than cRowsInSet
if (cRows == LONG_MIN && cRowsInSet != LONG_MIN) cRows = cRowsInSet + 2; // set the value to something we can deal with
else cRows = abs((int)(INT_PTR)cRows);
if (iStepSize < 0 && m_iRowset == 0 && m_bReset && lRowsOffset <= 0) m_iRowset = cRowsInSet;
lRowsOffset += m_iRowset;
*pcRowsObtained = 0; CAutoMemRelease<HROW, CComFree< HROW > > amr; if (*prghRows == NULL) { DBROWCOUNT cHandlesToAlloc = (cRows > cRowsInSet) ? cRowsInSet : cRows; if (iStepSize == 1 && (cRowsInSet - lRowsOffset) < cHandlesToAlloc) cHandlesToAlloc = cRowsInSet - lRowsOffset; if (iStepSize == -1 && lRowsOffset < cHandlesToAlloc) cHandlesToAlloc = lRowsOffset; *prghRows = (HROW*)CoTaskMemAlloc((cHandlesToAlloc) * sizeof(HROW*)); amr.Attach(*prghRows); } if (*prghRows == NULL) return E_OUTOFMEMORY; while ((lRowsOffset >= 0 && cRows != 0) && ((lRowsOffset < cRowsInSet) || (lRowsOffset <= cRowsInSet && iStepSize < 0))) { // cRows > cRowsInSet && iStepSize < 0
if (lRowsOffset == 0 && cRows > 0 && iStepSize < 0) break;
// in the case where we have iStepSize < 0, move the row back
// further because we want the previous row
DBROWOFFSET lRow = lRowsOffset; if ((lRowsOffset == 0) && (lTmpRows == 0) && (iStepSize < 0)) lRow = cRowsInSet;
if (iStepSize < 0) lRow += iStepSize;
hr = pT->CreateRow(lRow, *pcRowsObtained, *prghRows); if (FAILED(hr)) { RefRows(*pcRowsObtained, *prghRows, NULL, NULL, FALSE); for (ULONG iRowDel = 0; iRowDel < *pcRowsObtained; iRowDel++) *prghRows[iRowDel] = NULL; *pcRowsObtained = 0; return hr; } cRows--; lRowsOffset += iStepSize; }
if ((lRowsOffset >= cRowsInSet && cRows) || (lRowsOffset < 0 && cRows) || (lRowsOffset == 0 && cRows > 0 && iStepSize < 0)) hr = DB_S_ENDOFROWSET; m_iRowset = lRowsOffset; if (SUCCEEDED(hr)) amr.Detach(); return hr; }
STDMETHOD(ReleaseRows)(DBCOUNTITEM cRows, const HROW rghRows[], DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::ReleaseRows\n"); if (cRows == 0) return S_OK; rgRowOptions; return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, FALSE); }
STDMETHOD(RestartPosition)(HCHAPTER /*hReserved*/) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RestartPosition\n"); m_iRowset = 0; m_bReset = true; return S_OK; }
MapClass m_rgRowHandles; DBCOUNTITEM m_iRowset; // cursor
unsigned m_bCanScrollBack:1; unsigned m_bCanFetchBack:1; unsigned m_bReset:1; };
///////////////////////////////////////////////////////////////////////////
// IRowsetIdentityImpl
template <class T, class RowClass = CSimpleRow> class ATL_NO_VTABLE IRowsetIdentityImpl : public IRowsetIdentity { public: STDMETHOD(IsSameRow)(HROW hThisRow, HROW hThatRow) { ATLTRACE2(atlTraceDBProvider, 0, _T("IRowsetIdentityImpl::IsSameRow")); T* pT = (T*)this;
// Validate row handles
RowClass* pRow1 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThisRow); RowClass* pRow2 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThatRow);
if (pRow1 == NULL || pRow2 == NULL) return DB_E_BADROWHANDLE;
return pRow1->Compare(pRow2); }; };
template <class T> class ATL_NO_VTABLE IInternalConnectionImpl : public IInternalConnection { public: STDMETHOD(AddConnection)() { T* pT = (T*)this; T::_ThreadModel::Increment(&pT->m_cSessionsOpen); return S_OK; } STDMETHOD(ReleaseConnection)() { T* pT = (T*)this; T::_ThreadModel::Decrement(&pT->m_cSessionsOpen); return S_OK; } };
template <class T> class ATL_NO_VTABLE IObjectWithSiteSessionImpl : public IObjectWithSiteImpl< T > { public:
~IObjectWithSiteSessionImpl() { CComPtr<IInternalConnection> pConn; if (m_spUnkSite != NULL) { if (SUCCEEDED(m_spUnkSite->QueryInterface(IID_IInternalConnection, (void**)&pConn))) pConn->ReleaseConnection(); } } STDMETHOD(SetSite)(IUnknown* pCreator) { HRESULT hr = S_OK; T* pT = (T*)this; pT->Lock(); m_spUnkSite = pCreator; pT->Unlock(); CComPtr<IInternalConnection> pConn; if (pCreator != NULL) { hr = pCreator->QueryInterface(IID_IInternalConnection, (void**)&pConn); if (SUCCEEDED(hr)) hr = pConn->AddConnection(); } return hr; } };
template <class T> class ATL_NO_VTABLE IRowsetCreatorImpl : public IObjectWithSiteImpl< T > { public:
STDMETHOD(SetSite)(IUnknown* pCreator) { T* pT = (T*)this; HRESULT hr = S_OK; pT->Lock(); m_spUnkSite = pCreator; pT->Unlock(); CComVariant varPropScroll, varPropFetch; HRESULT hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANSCROLLBACKWARDS, &varPropScroll); if (SUCCEEDED(hrProps)) pT->m_bCanScrollBack = varPropScroll.boolVal == VARIANT_TRUE; hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANFETCHBACKWARDS, &varPropFetch); if (SUCCEEDED(hrProps)) pT->m_bCanFetchBack = (varPropFetch.boolVal == VARIANT_TRUE); return hr; }
};
// IRowsetInfoImpl
template <class T, class PropClass = T> class ATL_NO_VTABLE IRowsetInfoImpl : public IRowsetInfo, public CUtlProps<PropClass> { public: static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL)) { return PropClass::_GetPropSet(pNumPropSets, pcElemPerSupported, pSet, pguidSet); } STDMETHOD(GetProperties)(const ULONG cPropertyIDSets, const DBPROPIDSET rgPropertyIDSets[], ULONG *pcPropertySets, DBPROPSET **prgPropertySets) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetProperties\n"); HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets); const GUID* ppGuid[1]; ppGuid[0] = &DBPROPSET_ROWSET; if(SUCCEEDED(hr)) return CUtlProps<PropClass>::GetProperties(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets, 1, ppGuid); else return hr; }
OUT_OF_LINE ATLCOLUMNINFO* InternalGetColumnInfo(DBORDINAL* pcCols) { return T::GetColumnInfo((T*)this, pcCols); }
STDMETHOD(GetReferencedRowset)(DBORDINAL iOrdinal, REFIID riid, IUnknown **ppReferencedRowset) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset\n"); DBORDINAL cCols=0;
// Check Arguments
if( ppReferencedRowset == NULL ) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset : Error NULL IUnk output Param\n"); return E_INVALIDARG; } *ppReferencedRowset = NULL;
// Check to see if column in question is a bookmark
ATLCOLUMNINFO* pColInfo = InternalGetColumnInfo(&cCols);
for (ULONG iColInfo = 0; iColInfo < cCols && iOrdinal != pColInfo[iColInfo].iOrdinal; iColInfo++); if (iColInfo == cCols) return DB_E_BADORDINAL; ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
if ((pColCur->dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) == 0) return DB_E_NOTAREFERENCECOLUMN;
// Query for requested interface
return QueryInterface(riid, (void**)ppReferencedRowset); }
STDMETHOD(GetSpecification)(REFIID riid, IUnknown **ppSpecification) { ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetSpecification\n"); if (ppSpecification == NULL) return E_INVALIDARG; T* pT = (T*) this; T::ObjectLock cab(pT); ATLASSERT(pT->m_spUnkSite != NULL); return pT->m_spUnkSite->QueryInterface(riid, (void**)ppSpecification); } };
template <class T, class Storage, class CreatorClass, class ArrayType = CSimpleArray<Storage>, class RowClass = CSimpleRow, class RowsetInterface = IRowsetImpl < T, IRowset, RowClass> > class CRowsetImpl : public CComObjectRootEx<CreatorClass::_ThreadModel>, public IAccessorImpl<T>, public IRowsetIdentityImpl<T, RowClass>, public IRowsetCreatorImpl<T>, public IRowsetInfoImpl<T, CreatorClass::_PropClass>, public IColumnsInfoImpl<T>, public IConvertTypeImpl<T>, public RowsetInterface { public:
typedef CreatorClass _RowsetCreatorClass; typedef ArrayType _RowsetArrayType; typedef CRowsetImpl< T, Storage, CreatorClass, ArrayType, RowClass, RowsetInterface> _RowsetBaseClass;
BEGIN_COM_MAP(CRowsetImpl) COM_INTERFACE_ENTRY(IAccessor) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY(IRowsetInfo) COM_INTERFACE_ENTRY(IColumnsInfo) COM_INTERFACE_ENTRY(IConvertType) COM_INTERFACE_ENTRY(IRowsetIdentity) COM_INTERFACE_ENTRY(IRowset) END_COM_MAP()
HRESULT FinalConstruct() { HRESULT hr = IAccessorImpl<T>::FinalConstruct(); if (FAILED(hr)) return hr; return CConvertHelper::FinalConstruct(); }
HRESULT NameFromDBID(DBID* pDBID, CComBSTR& bstr, bool bIndex) {
if (pDBID->uName.pwszName != NULL) { bstr = pDBID->uName.pwszName; if (m_strCommandText == (BSTR)NULL) return E_OUTOFMEMORY; return S_OK; }
return (bIndex) ? DB_E_NOINDEX : DB_E_NOTABLE; }
HRESULT GetCommandFromID(DBID* pTableID, DBID* pIndexID) { USES_CONVERSION; HRESULT hr;
if (pTableID == NULL && pIndexID == NULL) return E_INVALIDARG;
if (pTableID != NULL && pTableID->eKind == DBKIND_NAME) { hr = NameFromDBID(pTableID, m_strCommandText, true); if (FAILED(hr)) return hr; if (pIndexID != NULL) { if (pIndexID->eKind == DBKIND_NAME) { hr = NameFromDBID(pIndexID, m_strIndexText, false); if (FAILED(hr)) { m_strCommandText.Empty(); return hr; } } else { m_strCommandText.Empty(); return DB_E_NOINDEX; } } return S_OK; } if (pIndexID != NULL && pIndexID->eKind == DBKIND_NAME) return NameFromDBID(pIndexID, m_strIndexText, false);
return S_OK; }
HRESULT ValidateCommandID(DBID* pTableID, DBID* pIndexID) { HRESULT hr = S_OK;
if (pTableID != NULL) { hr = CUtlProps<T>::IsValidDBID(pTableID);
if (hr != S_OK) return hr;
// Check for a NULL TABLE ID (where its a valid pointer but NULL)
if ((pTableID->eKind == DBKIND_GUID_NAME || pTableID->eKind == DBKIND_NAME || pTableID->eKind == DBKIND_PGUID_NAME) && pTableID->uName.pwszName == NULL) return DB_E_NOTABLE; }
if (pIndexID != NULL) hr = CUtlProps<T>::IsValidDBID(pIndexID);
return hr; }
HRESULT SetCommandText(DBID* pTableID, DBID* pIndexID) { T* pT = (T*)this; HRESULT hr = pT->ValidateCommandID(pTableID, pIndexID); if (FAILED(hr)) return hr; hr = pT->GetCommandFromID(pTableID, pIndexID); return hr; } void FinalRelease() { m_rgRowData.RemoveAll(); }
static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols) { return Storage::GetColumnInfo(pv,pcCols); }
CComBSTR m_strCommandText; CComBSTR m_strIndexText; ArrayType m_rgRowData; };
class CTABLESRow { public:
WCHAR m_szCatalog[129]; WCHAR m_szSchema[129]; WCHAR m_szTable[129]; WCHAR m_szType[129]; WCHAR m_szDesc[129]; GUID m_guid; ULONG m_ulPropID;
CTABLESRow() { m_szCatalog[0] = NULL; m_szSchema[0] = NULL; m_szTable[0] = NULL; m_szType[0] = NULL; m_szDesc[0] = NULL; m_guid = GUID_NULL; m_ulPropID = 0; }
BEGIN_PROVIDER_COLUMN_MAP(CTABLESRow) PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szCatalog) PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szSchema) PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTable) PROVIDER_COLUMN_ENTRY("TABLE_TYPE", 4, m_szType) PROVIDER_COLUMN_ENTRY("TABLE_GUID", 5, m_guid) PROVIDER_COLUMN_ENTRY("DESCRIPTION", 6, m_szDesc) PROVIDER_COLUMN_ENTRY("TABLE_PROPID", 7, m_ulPropID) END_PROVIDER_COLUMN_MAP()
};
class CCOLUMNSRow { public:
WCHAR m_szTableCatalog[129]; WCHAR m_szTableSchema[129]; WCHAR m_szTableName[129]; WCHAR m_szColumnName[129]; GUID m_guidColumn; ULONG m_ulColumnPropID; DBORDINAL m_ulOrdinalPosition; VARIANT_BOOL m_bColumnHasDefault; WCHAR m_szColumnDefault[129]; ULONG m_ulColumnFlags; VARIANT_BOOL m_bIsNullable; USHORT m_nDataType; GUID m_guidType; DBLENGTH m_ulCharMaxLength; ULONG m_ulCharOctetLength; USHORT m_nNumericPrecision; short m_nNumericScale; ULONG m_ulDateTimePrecision; WCHAR m_szCharSetCatalog[129]; WCHAR m_szCharSetSchema[129]; WCHAR m_szCharSetName[129]; WCHAR m_szCollationCatalog[129]; WCHAR m_szCollationSchema[129]; WCHAR m_szCollationName[129]; WCHAR m_szDomainCatalog[129]; WCHAR m_szDomainSchema[129]; WCHAR m_szDomainName[129]; WCHAR m_szDescription[129];
CCOLUMNSRow() { ClearMembers(); }
void ClearMembers() { m_szTableCatalog[0] = NULL; m_szTableSchema[0] = NULL; m_szTableName[0] = NULL; m_szColumnName[0] = NULL; m_guidColumn = GUID_NULL; m_ulColumnPropID = 0; m_ulOrdinalPosition = 0; m_bColumnHasDefault = VARIANT_FALSE; m_szColumnDefault[0] = NULL; m_ulColumnFlags = 0; m_bIsNullable = VARIANT_FALSE; m_nDataType = 0; m_guidType = GUID_NULL; m_ulCharMaxLength = 0; m_ulCharOctetLength = 0; m_nNumericPrecision = 0; m_nNumericScale = 0; m_ulDateTimePrecision = 0; m_szCharSetCatalog[0] = NULL; m_szCharSetSchema[0] = NULL; m_szCharSetName[0] = NULL; m_szCollationCatalog[0] = NULL; m_szCollationSchema[0] = NULL; m_szCollationName[0] = NULL; m_szDomainCatalog[0] = NULL; m_szDomainSchema[0] = NULL; m_szDomainName[0] = NULL; m_szDescription[0] = NULL; }
BEGIN_PROVIDER_COLUMN_MAP(CCOLUMNSRow) PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szTableCatalog) PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szTableSchema) PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTableName) PROVIDER_COLUMN_ENTRY("COLUMN_NAME", 4, m_szColumnName) PROVIDER_COLUMN_ENTRY("COLUMN_GUID",5, m_guidColumn) PROVIDER_COLUMN_ENTRY("COLUMN_PROPID",6, m_ulColumnPropID) PROVIDER_COLUMN_ENTRY("ORDINAL_POSITION",7, m_ulOrdinalPosition) PROVIDER_COLUMN_ENTRY("COLUMN_HASDEFAULT",8, m_bColumnHasDefault) PROVIDER_COLUMN_ENTRY("COLUMN_DEFAULT",9, m_szColumnDefault) PROVIDER_COLUMN_ENTRY("COLUMN_FLAGS",10, m_ulColumnFlags) PROVIDER_COLUMN_ENTRY("IS_NULLABLE",11, m_bIsNullable) PROVIDER_COLUMN_ENTRY("DATA_TYPE",12, m_nDataType) PROVIDER_COLUMN_ENTRY("TYPE_GUID",13, m_guidType) PROVIDER_COLUMN_ENTRY("CHARACTER_MAXIMUM_LENGTH",14, m_ulCharMaxLength) PROVIDER_COLUMN_ENTRY("CHARACTER_OCTET_LENGTH",15, m_ulCharOctetLength) PROVIDER_COLUMN_ENTRY("NUMERIC_PRECISION",16, m_nNumericPrecision) PROVIDER_COLUMN_ENTRY("NUMERIC_SCALE",17, m_nNumericScale) PROVIDER_COLUMN_ENTRY("DATETIME_PRECISION",18, m_ulDateTimePrecision) PROVIDER_COLUMN_ENTRY("CHARACTER_SET_CATALOG", 19, m_szCharSetCatalog) PROVIDER_COLUMN_ENTRY("CHARACTER_SET_SCHEMA", 20, m_szCharSetSchema) PROVIDER_COLUMN_ENTRY("CHARACTER_SET_NAME", 21, m_szCharSetName) PROVIDER_COLUMN_ENTRY("COLLATION_CATALOG", 22, m_szCollationCatalog) PROVIDER_COLUMN_ENTRY("COLLATION_SCHEMA", 23, m_szCollationSchema) PROVIDER_COLUMN_ENTRY("COLLATION_NAME", 24, m_szCollationName) PROVIDER_COLUMN_ENTRY("DOMAIN_CATALOG", 25, m_szDomainCatalog) PROVIDER_COLUMN_ENTRY("DOMAIN_SCHEMA", 26, m_szDomainSchema) PROVIDER_COLUMN_ENTRY("DOMAIN_NAME", 27, m_szDomainName) PROVIDER_COLUMN_ENTRY("DESCRIPTION", 28, m_szDescription) END_PROVIDER_COLUMN_MAP() };
template <class ArrayClass> HRESULT InitFromRowset(ArrayClass& rgData, DBID* pTableID, DBID* pIndexID, IUnknown* pSession, LONG* pcRowsAffected) { CComQIPtr<IOpenRowset> spOpenRowset = pSession; if (spOpenRowset == NULL) return E_FAIL; CComPtr<IColumnsInfo> spColInfo; HRESULT hr = spOpenRowset->OpenRowset(NULL, pTableID, pIndexID, IID_IColumnsInfo, 0, NULL, (IUnknown**)&spColInfo); if (FAILED(hr)) return hr; LPOLESTR szColumns = NULL; DBORDINAL cColumns = 0; DBCOLUMNINFO* pColInfo = NULL; hr = spColInfo->GetColumnInfo(&cColumns, &pColInfo, &szColumns); if (FAILED(hr)) return hr; *pcRowsAffected = 0; for (ULONG iCol = 0; iCol < cColumns; iCol++) { CCOLUMNSRow crData; DBCOLUMNINFO& rColCur = pColInfo[iCol]; lstrcpynW(crData.m_szTableName, pTableID->uName.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szTableName)); lstrcpynW(crData.m_szColumnName, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName)); lstrcpynW(crData.m_szDescription, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName)); GUID* pGuidCol = CDBIDOps::GetDBIDpGuid(rColCur.columnid); if (pGuidCol) crData.m_guidColumn = *pGuidCol; else crData.m_guidColumn = GUID_NULL; crData.m_ulColumnPropID = CDBIDOps::GetPropIDFromDBID(rColCur.columnid); crData.m_ulOrdinalPosition = rColCur.iOrdinal; crData.m_ulColumnFlags = rColCur.dwFlags; crData.m_bIsNullable = (rColCur.dwFlags & DBCOLUMNFLAGS_ISNULLABLE) ? VARIANT_TRUE : VARIANT_FALSE; crData.m_nDataType = rColCur.wType; crData.m_ulCharMaxLength = rColCur.ulColumnSize; crData.m_nNumericPrecision = rColCur.bPrecision; crData.m_nNumericScale = rColCur.bScale; if (!rgData.Add(crData)) { CoTaskMemFree(pColInfo); CoTaskMemFree(szColumns); return E_OUTOFMEMORY; } *pcRowsAffected++; }
CoTaskMemFree(pColInfo); CoTaskMemFree(szColumns); return S_OK; }
class CPROVIDER_TYPERow { public: // Attributes
WCHAR m_szName[129]; USHORT m_nType; ULONG m_ulSize; WCHAR m_szPrefix[129]; WCHAR m_szSuffix[129]; WCHAR m_szCreateParams[129]; VARIANT_BOOL m_bIsNullable; VARIANT_BOOL m_bCaseSensitive; ULONG m_bSearchable; VARIANT_BOOL m_bUnsignedAttribute; VARIANT_BOOL m_bFixedPrecScale; VARIANT_BOOL m_bAutoUniqueValue; WCHAR m_szLocalTypeName[129]; short m_nMinScale; short m_nMaxScale; GUID m_guidType; WCHAR m_szTypeLib[129]; WCHAR m_szVersion[129]; VARIANT_BOOL m_bIsLong; VARIANT_BOOL m_bBestMatch; VARIANT_BOOL m_bIsFixedLength;
CPROVIDER_TYPERow() { m_szName[0] = NULL; m_nType = 0; m_ulSize = 0; m_szPrefix[0] = NULL; m_szSuffix[0] = NULL; m_szCreateParams[0] = NULL; m_bIsNullable = VARIANT_FALSE; m_bCaseSensitive = VARIANT_FALSE; m_bSearchable = DB_UNSEARCHABLE; m_bUnsignedAttribute = VARIANT_FALSE; m_bFixedPrecScale = VARIANT_FALSE; m_bAutoUniqueValue = VARIANT_FALSE; m_szLocalTypeName[0] = NULL; m_nMinScale = 0; m_nMaxScale = 0; m_guidType = GUID_NULL; m_szTypeLib[0] = NULL; m_szVersion[0] = NULL; m_bIsLong = VARIANT_FALSE; m_bBestMatch = VARIANT_FALSE; m_bIsFixedLength = VARIANT_FALSE; } // Binding Maps
BEGIN_PROVIDER_COLUMN_MAP(CPROVIDER_TYPERow) PROVIDER_COLUMN_ENTRY("TYPE_NAME", 1, m_szName) PROVIDER_COLUMN_ENTRY("DATA_TYPE", 2, m_nType) PROVIDER_COLUMN_ENTRY("COLUMN_SIZE", 3, m_ulSize) PROVIDER_COLUMN_ENTRY("LITERAL_PREFIX", 4, m_szPrefix) PROVIDER_COLUMN_ENTRY("LITERAL_SUFFIX", 5, m_szSuffix) PROVIDER_COLUMN_ENTRY("CREATE_PARAMS", 6, m_szCreateParams) PROVIDER_COLUMN_ENTRY("IS_NULLABLE", 7, m_bIsNullable) PROVIDER_COLUMN_ENTRY("CASE_SENSITIVE", 8, m_bCaseSensitive) PROVIDER_COLUMN_ENTRY("SEARCHABLE", 9, m_bSearchable) PROVIDER_COLUMN_ENTRY("UNSIGNED_ATTRIBUTE", 10, ,m_bUnsignedAttribute) PROVIDER_COLUMN_ENTRY("FIXED_PREC_SCALE", 11, m_bFixedPrecScale) PROVIDER_COLUMN_ENTRY("AUTO_UNIQUE_VALUE", 12, m_bAutoUniqueValue) PROVIDER_COLUMN_ENTRY("LOCAL_TYPE_NAME", 13, m_szLocalTypeName) PROVIDER_COLUMN_ENTRY("MINIMUM_SCALE", 14, m_nMinScale) PROVIDER_COLUMN_ENTRY("MAXIMUM_SCALE", 15, m_nMaxScale) PROVIDER_COLUMN_ENTRY("GUID", 16, m_guidType) PROVIDER_COLUMN_ENTRY("TYPELIB", 17, m_szTypeLib) PROVIDER_COLUMN_ENTRY("VERSION", 18, m_szVersion) PROVIDER_COLUMN_ENTRY("IS_LONG", 19, m_bIsLong) PROVIDER_COLUMN_ENTRY("BEST_MATCH", 20, m_bBestMatch) PROVIDER_COLUMN_ENTRY("IS_FIXEDLENGTH", 21, m_bIsFixedLength) END_PROVIDER_COLUMN_MAP() };
class CEnumRowsetImpl { public:
WCHAR m_szSourcesName[256]; WCHAR m_szSourcesParseName[256]; WCHAR m_szSourcesDescription[256]; unsigned short m_iType; VARIANT_BOOL m_bIsParent;
BEGIN_PROVIDER_COLUMN_MAP(CEnumRowsetImpl) PROVIDER_COLUMN_ENTRY("SOURCES_NAME", 1, m_szSourcesName) PROVIDER_COLUMN_ENTRY("SOURCES_PARSENAME", 2, m_szSourcesParseName) PROVIDER_COLUMN_ENTRY("SOURCES_DESCRIPTION", 3, m_szSourcesDescription) PROVIDER_COLUMN_ENTRY("SOURCES_TYPE", 4, m_iType) PROVIDER_COLUMN_ENTRY("SOURCES_ISPARENT", 5, m_bIsParent) END_PROVIDER_COLUMN_MAP()
};
#endif
|