windows-nt/Source/XPSP1/NT/public/sdk/inc/atl30/atldb.h
2020-09-26 16:20:57 +08:00

6432 lines
191 KiB
C++

// 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