541 lines
11 KiB
C
541 lines
11 KiB
C
|
//------------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Sidewalk
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: oledbhelp.h
|
||
|
//
|
||
|
// Contents: OLE DB helper methods
|
||
|
//
|
||
|
// Owner: BassamT
|
||
|
//
|
||
|
// History: 11/30/97 BassamT Created.
|
||
|
//
|
||
|
//------------------------------------------------------------------------------
|
||
|
#if (!defined(BUILD_FOR_NT40))
|
||
|
#pragma once
|
||
|
|
||
|
//
|
||
|
// typedefs
|
||
|
//
|
||
|
|
||
|
|
||
|
// Column Number (cn). This number starts at 1.
|
||
|
typedef ULONG CNUM;
|
||
|
|
||
|
// Row number (rn). These numbers start at 0.
|
||
|
typedef ULONG RNUM;
|
||
|
|
||
|
// Offset (in bytes) into a structure or buffer (ob)
|
||
|
typedef DWORD OFFSET;
|
||
|
|
||
|
// Bookmark data type (bmk)
|
||
|
typedef ULONG BOOKMARK;
|
||
|
|
||
|
|
||
|
//
|
||
|
// constants that can be tuned for performance
|
||
|
//
|
||
|
|
||
|
// The maximum number of bytes to store inline for variable size data types.
|
||
|
const UINT k_cbInlineMax = 100;
|
||
|
|
||
|
// the number of rows to fetch at once.
|
||
|
const ULONG k_RowFetchCount = 20;
|
||
|
|
||
|
// Column alignment within a row.
|
||
|
// TODO : Should this be sizeof(DWORD) instead ?
|
||
|
const DWORD k_ColumnAlign = 8;
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// constants
|
||
|
//
|
||
|
|
||
|
// invalid row number
|
||
|
const CNUM CNUM_INVALID = 0xFFFFFFFF;
|
||
|
|
||
|
// invalid row number
|
||
|
const RNUM RNUM_INVALID = 0xFFFFFFFF;
|
||
|
|
||
|
//
|
||
|
// conversion helpers
|
||
|
//
|
||
|
const UINT k_cchUCHARAsDecimalString = sizeof("255") - 1;
|
||
|
const UINT k_cchUSHORTAsDecimalString = sizeof("32767") - 1;
|
||
|
const UINT k_cchUINTAsDecimalString = sizeof("4294967294") - 1;
|
||
|
const UINT k_cchUINTAsHexString = sizeof("FFFFFFFF") - 1;
|
||
|
const UINT k_cchINTAsDecimalString = sizeof("-2147483648") - 1;
|
||
|
const UINT k_cchBOOLAsDecimalString = sizeof("1") - 1;
|
||
|
const UINT k_cchDOUBLEAsDecimalString = sizeof("2.2250738585072014 E + 308") - 1;
|
||
|
|
||
|
//
|
||
|
// macros
|
||
|
//
|
||
|
#define static_wcslen(pwsz) ((sizeof(pwsz) / sizeof(WCHAR)) - 1)
|
||
|
|
||
|
#define inrange(z,zmin,zmax) ( (zmin) <= (z) && (z) <= (zmax) )
|
||
|
|
||
|
|
||
|
#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 ))
|
||
|
|
||
|
#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 SET_DBID_FROM_NAME(dbid, pwsz) \
|
||
|
dbid.eKind = DBKIND_NAME;\
|
||
|
dbid.uName.pwszName = pwsz;
|
||
|
|
||
|
#define IsBadPointer(v) (IsBadReadPtr((void*)hAccessor, sizeof(void*)))
|
||
|
|
||
|
//
|
||
|
// functions
|
||
|
//
|
||
|
|
||
|
inline DWORD RoundDown(DWORD dwSize, DWORD dwAmount)
|
||
|
{
|
||
|
return dwSize & ~(dwAmount - 1);
|
||
|
}
|
||
|
|
||
|
inline DWORD RoundUp(DWORD dwSize, DWORD dwAmount)
|
||
|
{
|
||
|
return (dwSize + (dwAmount - 1)) & ~(dwAmount - 1);
|
||
|
}
|
||
|
|
||
|
#define CLIENT_MALLOC(cb) (CoTaskMemAlloc(cb))
|
||
|
#define CLIENT_FREE(x) (CoTaskMemFree(x), x = NULL)
|
||
|
|
||
|
HRESULT CopyDBIDs(DBID * pdbidDest, const DBID *pdbidSrc);
|
||
|
BOOL CompareDBIDs(const DBID *pdbid1, const DBID *pdbid2);
|
||
|
HRESULT IsValidDBID(const DBID *pdbid);
|
||
|
void FreeDBID(DBID *pdbid);
|
||
|
|
||
|
INT CompareOLEDBTypes(DBTYPE wType, void * pvValue1, void * pvValue2);
|
||
|
|
||
|
|
||
|
inline BOOL IsColumnVarLength
|
||
|
//------------------------------------------------------------------------------
|
||
|
// return TRUE if the column is of a variable length type
|
||
|
(
|
||
|
DBTYPE wType
|
||
|
)
|
||
|
{
|
||
|
if (wType == DBTYPE_BSTR ||
|
||
|
wType == DBTYPE_STR ||
|
||
|
wType == DBTYPE_WSTR ||
|
||
|
wType == DBTYPE_BYTES)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
inline DWORD AdjustVariableTypesLength
|
||
|
//------------------------------------------------------------------------------
|
||
|
// adjusts the length of variable length data types
|
||
|
(
|
||
|
DBTYPE wType,
|
||
|
DWORD cb
|
||
|
)
|
||
|
{
|
||
|
|
||
|
if (wType == DBTYPE_STR)
|
||
|
{
|
||
|
return cb + 1;
|
||
|
}
|
||
|
|
||
|
if (wType == DBTYPE_WSTR)
|
||
|
{
|
||
|
return cb + sizeof(WCHAR);
|
||
|
}
|
||
|
|
||
|
return cb;
|
||
|
}
|
||
|
|
||
|
inline USHORT GetColumnMaxPrecision
|
||
|
//------------------------------------------------------------------------------
|
||
|
// returns the maximium possible precision of a column, given its type.
|
||
|
// Do not pass a byref, array, or vector column type.
|
||
|
(
|
||
|
DBTYPE wType
|
||
|
// [in] the OLE DB data type
|
||
|
)
|
||
|
{
|
||
|
if ((wType & DBTYPE_BYREF) ||
|
||
|
(wType & DBTYPE_ARRAY) ||
|
||
|
(wType & DBTYPE_VECTOR))
|
||
|
{
|
||
|
Assert (FALSE);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
switch( wType )
|
||
|
{
|
||
|
case DBTYPE_I1:
|
||
|
case DBTYPE_UI1:
|
||
|
return 3;
|
||
|
|
||
|
case DBTYPE_I2:
|
||
|
case DBTYPE_UI2:
|
||
|
return 5;
|
||
|
|
||
|
case DBTYPE_I4:
|
||
|
case DBTYPE_UI4:
|
||
|
return 10;
|
||
|
|
||
|
case DBTYPE_R4:
|
||
|
return 7;
|
||
|
|
||
|
case DBTYPE_I8:
|
||
|
return 19;
|
||
|
|
||
|
case DBTYPE_UI8:
|
||
|
return 20;
|
||
|
|
||
|
case DBTYPE_R8:
|
||
|
return 16;
|
||
|
|
||
|
case DBTYPE_DATE:
|
||
|
return 8;
|
||
|
|
||
|
case DBTYPE_CY:
|
||
|
return 19;
|
||
|
|
||
|
case DBTYPE_DECIMAL:
|
||
|
return 28;
|
||
|
|
||
|
case DBTYPE_NUMERIC:
|
||
|
return 38;
|
||
|
|
||
|
case DBTYPE_EMPTY:
|
||
|
case DBTYPE_NULL:
|
||
|
case DBTYPE_ERROR:
|
||
|
case DBTYPE_BOOL:
|
||
|
case DBTYPE_BSTR:
|
||
|
case DBTYPE_IDISPATCH:
|
||
|
case DBTYPE_IUNKNOWN:
|
||
|
case DBTYPE_VARIANT:
|
||
|
case DBTYPE_GUID:
|
||
|
case DBTYPE_BYTES:
|
||
|
case DBTYPE_STR:
|
||
|
case DBTYPE_WSTR:
|
||
|
case DBTYPE_DBDATE:
|
||
|
case DBTYPE_DBTIME:
|
||
|
case DBTYPE_DBTIMESTAMP:
|
||
|
case DBTYPE_HCHAPTER:
|
||
|
return 0;
|
||
|
|
||
|
default:
|
||
|
Assert (FALSE && "Unsupported data type");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline ULONG GetColumnSize
|
||
|
//------------------------------------------------------------------------------
|
||
|
// returns the size of the column in bytes
|
||
|
(
|
||
|
DBTYPE wType,
|
||
|
// [in] the OLE DB data type
|
||
|
DWORD cchMaxLength
|
||
|
// [in] if this is a variable size field then this is the max length
|
||
|
// if there is one defined. Otherwise this is 0xFFFFFFFF
|
||
|
)
|
||
|
{
|
||
|
// Handle BYREF destination separately
|
||
|
if ((wType & DBTYPE_BYREF) ||
|
||
|
(wType & DBTYPE_ARRAY) ||
|
||
|
(wType & DBTYPE_VECTOR))
|
||
|
{
|
||
|
return sizeof(void*);
|
||
|
}
|
||
|
|
||
|
switch( wType )
|
||
|
{
|
||
|
case DBTYPE_EMPTY:
|
||
|
case DBTYPE_NULL:
|
||
|
return 0;
|
||
|
|
||
|
case DBTYPE_I2:
|
||
|
case DBTYPE_UI2:
|
||
|
return 2;
|
||
|
|
||
|
case DBTYPE_I4:
|
||
|
case DBTYPE_R4:
|
||
|
case DBTYPE_UI4:
|
||
|
return 4;
|
||
|
|
||
|
case DBTYPE_I8:
|
||
|
case DBTYPE_R8:
|
||
|
case DBTYPE_DATE:
|
||
|
case DBTYPE_UI8:
|
||
|
return 8;
|
||
|
|
||
|
case DBTYPE_ERROR:
|
||
|
return sizeof(SCODE);
|
||
|
|
||
|
case DBTYPE_BOOL:
|
||
|
return sizeof(VARIANT_BOOL);
|
||
|
|
||
|
case DBTYPE_CY:
|
||
|
return sizeof(CY);
|
||
|
|
||
|
case DBTYPE_BSTR:
|
||
|
return sizeof(BSTR);
|
||
|
|
||
|
case DBTYPE_IDISPATCH:
|
||
|
return sizeof(IDispatch*);
|
||
|
|
||
|
case DBTYPE_IUNKNOWN:
|
||
|
return sizeof(IUnknown*);
|
||
|
|
||
|
case DBTYPE_VARIANT:
|
||
|
return sizeof(VARIANT);
|
||
|
|
||
|
case DBTYPE_DECIMAL:
|
||
|
return sizeof(DECIMAL);
|
||
|
|
||
|
case DBTYPE_I1:
|
||
|
case DBTYPE_UI1:
|
||
|
return 1;
|
||
|
|
||
|
case DBTYPE_GUID:
|
||
|
return sizeof(GUID);
|
||
|
|
||
|
case DBTYPE_BYTES:
|
||
|
return cchMaxLength;
|
||
|
|
||
|
case DBTYPE_STR:
|
||
|
return cchMaxLength * sizeof(char);
|
||
|
|
||
|
case DBTYPE_WSTR:
|
||
|
return cchMaxLength * sizeof(WCHAR);
|
||
|
|
||
|
case DBTYPE_NUMERIC:
|
||
|
return sizeof(DB_NUMERIC);
|
||
|
|
||
|
case DBTYPE_DBDATE:
|
||
|
return sizeof(DBDATE);
|
||
|
|
||
|
case DBTYPE_DBTIME:
|
||
|
return sizeof(DBTIME);
|
||
|
|
||
|
case DBTYPE_DBTIMESTAMP:
|
||
|
return sizeof(DBTIMESTAMP);
|
||
|
|
||
|
case DBTYPE_HCHAPTER:
|
||
|
return sizeof(HCHAPTER);
|
||
|
|
||
|
default:
|
||
|
Assert (FALSE && "Unsupported data type");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// IUnknown Macros
|
||
|
//
|
||
|
|
||
|
// put this macros in your class definition. Make sure that
|
||
|
// you inherit from IUnknown and that you use the
|
||
|
// INIT_IUNKNOWN macro in your class constructor
|
||
|
#define DEFINE_IUNKNOWN \
|
||
|
private:\
|
||
|
LONG _cRefs;\
|
||
|
public:\
|
||
|
STDMETHOD(InternalQueryInterface)(REFIID riid, void ** ppv);\
|
||
|
STDMETHOD(QueryInterface)(REFIID riid, void ** ppv)\
|
||
|
{\
|
||
|
return InternalQueryInterface(riid, ppv);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,AddRef)() \
|
||
|
{\
|
||
|
return InterlockedIncrement(&_cRefs);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,Release)()\
|
||
|
{\
|
||
|
if (InterlockedDecrement(&_cRefs) == 0)\
|
||
|
{\
|
||
|
delete this;\
|
||
|
return 0;\
|
||
|
}\
|
||
|
return _cRefs;\
|
||
|
}
|
||
|
|
||
|
#define INIT_IUNKNOWN _cRefs = 1;
|
||
|
|
||
|
#define DEFINE_IUNKNOWN_WITH_CALLBACK(x) \
|
||
|
private:\
|
||
|
LONG _cRefs;\
|
||
|
public:\
|
||
|
STDMETHOD(InternalQueryInterface)(REFIID riid, void ** ppv);\
|
||
|
STDMETHOD(QueryInterface)(REFIID riid, void ** ppv)\
|
||
|
{\
|
||
|
return InternalQueryInterface(riid, ppv);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,AddRef)() \
|
||
|
{\
|
||
|
return InterlockedIncrement(&_cRefs);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,Release)()\
|
||
|
{\
|
||
|
if (InterlockedDecrement(&_cRefs) == 0)\
|
||
|
{\
|
||
|
x();\
|
||
|
return 0;\
|
||
|
}\
|
||
|
return _cRefs;\
|
||
|
}
|
||
|
|
||
|
|
||
|
// put this macros in your class definition. Make sure that
|
||
|
// you inherit from IUnknown and that you use the
|
||
|
// INIT_AGGREGATE_IUNKNOWN macro in your class constructor.
|
||
|
// Also make sure that you use SET_OUTER_IUNKNOWN in wherever
|
||
|
// you get a pointer to the Outer IUnknown
|
||
|
interface INonDelegatingUnknown
|
||
|
{
|
||
|
virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface
|
||
|
(
|
||
|
REFIID riid,
|
||
|
void __RPC_FAR *__RPC_FAR *ppvObject
|
||
|
) = 0;
|
||
|
virtual ULONG STDMETHODCALLTYPE NonDelegatingAddRef(void) = 0;
|
||
|
virtual ULONG STDMETHODCALLTYPE NonDelegatingRelease(void) = 0;
|
||
|
};
|
||
|
|
||
|
#define DEFINE_AGGREGATE_IUNKNOWN \
|
||
|
private:\
|
||
|
IUnknown * _punkOuter;\
|
||
|
LONG _cRefs;\
|
||
|
public:\
|
||
|
STDMETHOD(InternalQueryInterface)(REFIID riid, void ** ppv);\
|
||
|
STDMETHOD(NonDelegatingQueryInterface)(REFIID riid, void ** ppv)\
|
||
|
{\
|
||
|
if (ppv == NULL) return E_INVALIDARG;\
|
||
|
if (riid != IID_IUnknown)\
|
||
|
{\
|
||
|
return InternalQueryInterface(riid, ppv);\
|
||
|
}\
|
||
|
else\
|
||
|
{\
|
||
|
*ppv = static_cast<INonDelegatingUnknown*>(this);\
|
||
|
NonDelegatingAddRef();\
|
||
|
return NOERROR;\
|
||
|
}\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,NonDelegatingAddRef)() \
|
||
|
{\
|
||
|
return InterlockedIncrement(&_cRefs);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,NonDelegatingRelease)()\
|
||
|
{\
|
||
|
if (InterlockedDecrement(&_cRefs) == 0)\
|
||
|
{\
|
||
|
delete this;\
|
||
|
return 0;\
|
||
|
}\
|
||
|
return _cRefs;\
|
||
|
}\
|
||
|
STDMETHOD(QueryInterface)(REFIID riid, void ** ppv)\
|
||
|
{\
|
||
|
return _punkOuter->QueryInterface(riid, ppv);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,AddRef)() \
|
||
|
{\
|
||
|
return _punkOuter->AddRef();\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,Release)()\
|
||
|
{\
|
||
|
return _punkOuter->Release();\
|
||
|
}
|
||
|
|
||
|
#define INIT_AGGREGATE_IUNKNOWN \
|
||
|
_punkOuter = reinterpret_cast<IUnknown*>(static_cast<INonDelegatingUnknown*>(this)); \
|
||
|
_cRefs = 1;
|
||
|
|
||
|
#define SET_OUTER_IUNKNOWN(punk) if (punk != NULL) _punkOuter = punk;
|
||
|
|
||
|
|
||
|
#define DEFINE_AGGREGATE_IUNKNOWN_WITH_CALLBACKS(_AddRef, _Release) \
|
||
|
private:\
|
||
|
IUnknown * _punkOuter;\
|
||
|
LONG _cRefs;\
|
||
|
public:\
|
||
|
STDMETHOD(InternalQueryInterface)(REFIID riid, void ** ppv);\
|
||
|
STDMETHOD(NonDelegatingQueryInterface)(REFIID riid, void ** ppv)\
|
||
|
{\
|
||
|
if (ppv == NULL) return E_INVALIDARG;\
|
||
|
if (riid != IID_IUnknown)\
|
||
|
{\
|
||
|
return InternalQueryInterface(riid, ppv);\
|
||
|
}\
|
||
|
else\
|
||
|
{\
|
||
|
*ppv = static_cast<INonDelegatingUnknown*>(this);\
|
||
|
NonDelegatingAddRef();\
|
||
|
return NOERROR;\
|
||
|
}\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,NonDelegatingAddRef)() \
|
||
|
{\
|
||
|
_AddRef();\
|
||
|
return InterlockedIncrement(&_cRefs);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,NonDelegatingRelease)()\
|
||
|
{\
|
||
|
_Release();\
|
||
|
if (InterlockedDecrement(&_cRefs) == 0)\
|
||
|
{\
|
||
|
delete this;\
|
||
|
return 0;\
|
||
|
}\
|
||
|
return _cRefs;\
|
||
|
}\
|
||
|
STDMETHOD(QueryInterface)(REFIID riid, void ** ppv)\
|
||
|
{\
|
||
|
return _punkOuter->QueryInterface(riid, ppv);\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,AddRef)() \
|
||
|
{\
|
||
|
return _punkOuter->AddRef();\
|
||
|
}\
|
||
|
STDMETHOD_(ULONG,Release)()\
|
||
|
{\
|
||
|
return _punkOuter->Release();\
|
||
|
}
|
||
|
#endif
|