You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1288 lines
38 KiB
1288 lines
38 KiB
//---------------------------------------------------------------------------
|
|
// CursorMain.cpp : CursorMain implementation
|
|
//
|
|
// Copyright (c) 1996 Microsoft Corporation, All Rights Reserved
|
|
// Developed by Sheridan Software Systems, Inc.
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "MSR2C.h"
|
|
#include "Notifier.h"
|
|
#include "RSColumn.h"
|
|
#include "RSSource.h"
|
|
#include "CursMain.h"
|
|
#include "ColUpdat.h"
|
|
#include "CursPos.h"
|
|
#include "CursBase.h"
|
|
#include "enumcnpt.h"
|
|
#include "Cursor.h"
|
|
#include "Bookmark.h"
|
|
#include "fastguid.h"
|
|
|
|
SZTHISFILE
|
|
|
|
#include "ARRAY_P.inl"
|
|
|
|
// static data
|
|
DWORD CVDCursorMain::s_dwMetaRefCount = 0;
|
|
ULONG CVDCursorMain::s_ulMetaColumns = 0;
|
|
CVDRowsetColumn * CVDCursorMain::s_rgMetaColumns = NULL;
|
|
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// CVDCursorMain - Constructor
|
|
//
|
|
CVDCursorMain::CVDCursorMain(LCID lcid) : m_resourceDLL(lcid)
|
|
{
|
|
m_fWeAddedMetaRef = FALSE;
|
|
m_fPassivated = FALSE;
|
|
m_fColumnsRowsetSupported = FALSE;
|
|
m_fInternalInsertRow = FALSE;
|
|
m_fInternalDeleteRows = FALSE;
|
|
m_fInternalSetData = FALSE;
|
|
|
|
m_fLiteralBookmarks = FALSE;
|
|
m_fOrderedBookmarks = FALSE;
|
|
m_fBookmarkSkipped = FALSE;
|
|
|
|
m_fConnected = FALSE;
|
|
m_dwAdviseCookie = 0;
|
|
m_ulColumns = 0;
|
|
m_rgColumns = NULL;
|
|
|
|
m_cbMaxBookmark = 0;
|
|
|
|
VDUpdateObjectCount(1); // update object count to prevent dll from being unloaded
|
|
|
|
#ifdef _DEBUG
|
|
g_cVDCursorMainCreated++;
|
|
#endif
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// ~CVDCursorMain - Destructor
|
|
//
|
|
CVDCursorMain::~CVDCursorMain()
|
|
{
|
|
Passivate();
|
|
|
|
VDUpdateObjectCount(-1); // update object count to allow dll to be unloaded
|
|
|
|
#ifdef _DEBUG
|
|
g_cVDCursorMainDestroyed++;
|
|
#endif
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// Pasivate when external ref count gets to zero
|
|
//
|
|
void CVDCursorMain::Passivate()
|
|
{
|
|
|
|
if (m_fPassivated)
|
|
return;
|
|
|
|
m_fPassivated = TRUE;
|
|
|
|
if (IsRowsetValid())
|
|
{
|
|
if (m_hAccessorBM)
|
|
GetAccessor()->ReleaseAccessor(m_hAccessorBM, NULL);
|
|
|
|
if (m_fConnected)
|
|
DisconnectIRowsetNotify();
|
|
}
|
|
|
|
DestroyColumns();
|
|
DestroyMetaColumns();
|
|
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// Create - Create cursor provider from row position or rowset
|
|
//=--------------------------------------------------------------------------=
|
|
// This function creates and initializes a new cursor main object
|
|
//
|
|
// Parameters:
|
|
// pRowPosition - [in] original IRowPosition provider (may be NULL)
|
|
// pRowset - [in] original IRowset provider
|
|
// ppCursor - [out] resulting ICursor provider
|
|
// lcid - [in] locale identifier
|
|
//
|
|
// Output:
|
|
// HRESULT - S_OK if successful
|
|
// E_INVALIDARG bad parameter
|
|
// E_OUTOFMEMORY not enough memory
|
|
// VD_E_CANNOTCONNECTIROWSETNOTIFY unable to connect IRowsetNotify
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT CVDCursorMain::Create(IRowPosition* pRowPosition, IRowset * pRowset, ICursor ** ppCursor, LCID lcid)
|
|
{
|
|
ASSERT_POINTER(pRowset, IRowset)
|
|
ASSERT_POINTER(ppCursor, ICursor*)
|
|
|
|
if (!pRowset || !ppCursor)
|
|
return E_INVALIDARG;
|
|
|
|
// create new cursor main object
|
|
CVDCursorMain * pCursorMain = new CVDCursorMain(lcid);
|
|
|
|
if (!pCursorMain)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// initialize rowset source
|
|
HRESULT hr = pCursorMain->Initialize(pRowset);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pCursorMain->Release();
|
|
return hr;
|
|
}
|
|
|
|
// create array of column objects
|
|
hr = pCursorMain->CreateColumns();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pCursorMain->Release();
|
|
return hr;
|
|
}
|
|
|
|
// create array of meta-column objects
|
|
hr = pCursorMain->CreateMetaColumns();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pCursorMain->Release();
|
|
return hr;
|
|
}
|
|
|
|
// create bookmark accessor
|
|
DBBINDING rgBindings[1];
|
|
DBBINDSTATUS rgStatus[1];
|
|
|
|
memset(rgBindings, 0, sizeof(DBBINDING));
|
|
|
|
rgBindings[0].iOrdinal = 0;
|
|
rgBindings[0].obValue = 4;
|
|
rgBindings[0].obLength = 0;
|
|
rgBindings[0].dwPart = DBPART_VALUE | DBPART_LENGTH;
|
|
rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
rgBindings[0].cbMaxLen = pCursorMain->GetMaxBookmarkLen();
|
|
rgBindings[0].wType = DBTYPE_BYTES;
|
|
|
|
hr = pCursorMain->GetAccessor()->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
1,
|
|
rgBindings,
|
|
0,
|
|
&pCursorMain->m_hAccessorBM,
|
|
rgStatus);
|
|
if (FAILED(hr))
|
|
{
|
|
pCursorMain->Release();
|
|
return VD_E_CANNOTCREATEBOOKMARKACCESSOR;
|
|
}
|
|
|
|
// create new cursor position object
|
|
CVDCursorPosition * pCursorPosition;
|
|
|
|
hr = CVDCursorPosition::Create(pRowPosition, pCursorMain, &pCursorPosition, &pCursorMain->m_resourceDLL);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pCursorMain->Release();
|
|
return hr;
|
|
}
|
|
|
|
// create new cursor object
|
|
CVDCursor * pCursor;
|
|
|
|
hr = CVDCursor::Create(pCursorPosition, &pCursor, &pCursorMain->m_resourceDLL);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
((CVDNotifier*)pCursorPosition)->Release();
|
|
pCursorMain->Release();
|
|
return hr;
|
|
}
|
|
|
|
// connect IRowsetNotify
|
|
hr = pCursorMain->ConnectIRowsetNotify();
|
|
|
|
if (SUCCEEDED(hr))
|
|
pCursorMain->m_fConnected = TRUE;
|
|
|
|
// check rowset properties
|
|
BOOL fCanHoldRows = TRUE;
|
|
|
|
IRowsetInfo * pRowsetInfo = pCursorMain->GetRowsetInfo();
|
|
|
|
if (pRowsetInfo)
|
|
{
|
|
DBPROPID propids[] = { DBPROP_LITERALBOOKMARKS,
|
|
DBPROP_ORDEREDBOOKMARKS,
|
|
DBPROP_BOOKMARKSKIPPED,
|
|
DBPROP_CANHOLDROWS };
|
|
|
|
const DBPROPIDSET propsetids[] = { propids, 4, {0,0,0,0} };
|
|
memcpy((void*)&propsetids[0].guidPropertySet, &DBPROPSET_ROWSET, sizeof(DBPROPSET_ROWSET));
|
|
|
|
ULONG cPropertySets = 0;
|
|
DBPROPSET * propset = NULL;
|
|
hr = pRowsetInfo->GetProperties(1, propsetids, &cPropertySets, &propset);
|
|
|
|
if (SUCCEEDED(hr) && propset && propset->rgProperties)
|
|
{
|
|
if (DBPROPSTATUS_OK == propset->rgProperties[0].dwStatus)
|
|
pCursorMain->m_fLiteralBookmarks = V_BOOL(&propset->rgProperties[0].vValue);
|
|
|
|
if (DBPROPSTATUS_OK == propset->rgProperties[1].dwStatus)
|
|
pCursorMain->m_fOrderedBookmarks = V_BOOL(&propset->rgProperties[1].vValue);
|
|
|
|
if (DBPROPSTATUS_OK == propset->rgProperties[2].dwStatus)
|
|
pCursorMain->m_fBookmarkSkipped = V_BOOL(&propset->rgProperties[2].vValue);
|
|
|
|
if (DBPROPSTATUS_OK == propset->rgProperties[3].dwStatus)
|
|
fCanHoldRows = V_BOOL(&propset->rgProperties[3].vValue);
|
|
}
|
|
|
|
if (propset)
|
|
{
|
|
if (propset->rgProperties)
|
|
g_pMalloc->Free(propset->rgProperties);
|
|
|
|
g_pMalloc->Free(propset);
|
|
}
|
|
}
|
|
|
|
// release our references
|
|
pCursorMain->Release();
|
|
((CVDNotifier*)pCursorPosition)->Release();
|
|
|
|
// check for required property
|
|
if (!fCanHoldRows)
|
|
{
|
|
pCursor->Release();
|
|
return VD_E_REQUIREDPROPERTYNOTSUPPORTED;
|
|
}
|
|
|
|
// we're done
|
|
*ppCursor = pCursor;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// Create - Create cursor provider from rowset
|
|
//=--------------------------------------------------------------------------=
|
|
// This function creates and initializes a new cursor main object
|
|
//
|
|
// Parameters:
|
|
// pRowset - [in] original IRowset provider
|
|
// ppCursor - [out] resulting ICursor provider
|
|
// lcid - [in] locale identifier
|
|
//
|
|
// Output:
|
|
// HRESULT - S_OK if successful
|
|
// E_INVALIDARG bad parameter
|
|
// E_OUTOFMEMORY not enough memory
|
|
// VD_E_CANNOTCONNECTIROWSETNOTIFY unable to connect IRowsetNotify
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT CVDCursorMain::Create(IRowset * pRowset, ICursor ** ppCursor, LCID lcid)
|
|
{
|
|
ASSERT_POINTER(pRowset, IRowset)
|
|
ASSERT_POINTER(ppCursor, ICursor*)
|
|
|
|
if (!pRowset || !ppCursor)
|
|
return E_INVALIDARG;
|
|
|
|
// create cursor as done before row position
|
|
return Create(NULL, pRowset, ppCursor, lcid);
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// Create - Create cursor provider from row position
|
|
//=--------------------------------------------------------------------------=
|
|
// This function creates and initializes a new cursor main object
|
|
//
|
|
// Parameters:
|
|
// pRowPosition - [in] original IRowPosition provider
|
|
// ppCursor - [out] resulting ICursor provider
|
|
// lcid - [in] locale identifier
|
|
//
|
|
// Output:
|
|
// HRESULT - S_OK if successful
|
|
// E_INVALIDARG bad parameter
|
|
// E_OUTOFMEMORY not enough memory
|
|
// VD_E_CANNOTCONNECTIROWSETNOTIFY unable to connect IRowPositionNotify
|
|
// VD_E_CANNOTGETROWSETINTERFACE unable to get IRowset
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT CVDCursorMain::Create(IRowPosition * pRowPosition, ICursor ** ppCursor, LCID lcid)
|
|
{
|
|
ASSERT_POINTER(pRowPosition, IRowPosition)
|
|
ASSERT_POINTER(ppCursor, ICursor*)
|
|
|
|
if (!pRowPosition || !ppCursor)
|
|
return E_INVALIDARG;
|
|
|
|
IRowset * pRowset;
|
|
|
|
// get IRowset from IRowPosition
|
|
HRESULT hr = pRowPosition->GetRowset(IID_IRowset, (IUnknown**)&pRowset);
|
|
|
|
if (FAILED(hr))
|
|
return VD_E_CANNOTGETROWSETINTERFACE;
|
|
|
|
// create cursor with new row position parameter
|
|
hr = Create(pRowPosition, pRowset, ppCursor, lcid);
|
|
|
|
pRowset->Release();
|
|
|
|
// we're done
|
|
return hr;
|
|
}
|
|
|
|
typedef struct tagVDMETADATA_METADATA
|
|
{
|
|
const CURSOR_DBCOLUMNID * pCursorColumnID;
|
|
ULONG cbMaxLength;
|
|
CHAR * pszName;
|
|
DWORD dwCursorType;
|
|
} VDMETADATA_METADATA;
|
|
|
|
#define MAX_METADATA_COLUMNS 21
|
|
|
|
static const VDMETADATA_METADATA g_MetaDataMetaData[MAX_METADATA_COLUMNS] =
|
|
{
|
|
// Bookmark column
|
|
{ &CURSOR_COLUMN_BMKTEMPORARY, sizeof(ULONG), NULL, CURSOR_DBTYPE_BLOB },
|
|
// data columns
|
|
{ &CURSOR_COLUMN_COLUMNID, sizeof(CURSOR_DBCOLUMNID), "COLUMN_COLUMNID", CURSOR_DBTYPE_COLUMNID },
|
|
{ &CURSOR_COLUMN_DATACOLUMN, sizeof(VARIANT_BOOL), "COLUMN_DATACOLUMN", CURSOR_DBTYPE_BOOL },
|
|
{ &CURSOR_COLUMN_ENTRYIDMAXLENGTH, sizeof(ULONG), "COLUMN_ENTRYIDMAXLENGTH",CURSOR_DBTYPE_I4 },
|
|
{ &CURSOR_COLUMN_FIXED, sizeof(VARIANT_BOOL), "COLUMN_FIXED", CURSOR_DBTYPE_BOOL },
|
|
{ &CURSOR_COLUMN_MAXLENGTH, sizeof(ULONG), "COLUMN_MAXLENGTH", CURSOR_DBTYPE_I4 },
|
|
{ &CURSOR_COLUMN_NAME, 256, "COLUMN_NAME", VT_LPWSTR },
|
|
{ &CURSOR_COLUMN_NULLABLE, sizeof(VARIANT_BOOL), "COLUMN_NULLABLE", CURSOR_DBTYPE_BOOL },
|
|
{ &CURSOR_COLUMN_NUMBER, sizeof(ULONG), "COLUMN_NUMBER", CURSOR_DBTYPE_I4 },
|
|
{ &CURSOR_COLUMN_SCALE, sizeof(ULONG), "COLUMN_SCALE", CURSOR_DBTYPE_I4 },
|
|
{ &CURSOR_COLUMN_TYPE, sizeof(ULONG), "COLUMN_TYPE", CURSOR_DBTYPE_I4 },
|
|
{ &CURSOR_COLUMN_UPDATABLE, sizeof(ULONG), "COLUMN_UPDATABLE", CURSOR_DBTYPE_I4 },
|
|
{ &CURSOR_COLUMN_BINDTYPE, sizeof(ULONG), "COLUMN_BINDTYPE", CURSOR_DBTYPE_I4 },
|
|
// optional metadata columns - supported with IColumnsRowset only)
|
|
{ &CURSOR_COLUMN_AUTOINCREMENT, sizeof(VARIANT_BOOL), "COLUMN_AUTOINCREMENT", CURSOR_DBTYPE_BOOL },
|
|
{ &CURSOR_COLUMN_BASECOLUMNNAME, 256, "COLUMN_BASECOLUMNNAME",VT_LPWSTR },
|
|
{ &CURSOR_COLUMN_BASENAME, 256, "COLUMN_BASENAME", VT_LPWSTR },
|
|
{ &CURSOR_COLUMN_COLLATINGORDER, sizeof(LCID), "COLUMN_COLLATINGORDER",CURSOR_DBTYPE_I4 },
|
|
{ &CURSOR_COLUMN_DEFAULTVALUE, 256, "COLUMN_DEFAULTVALUE", VT_LPWSTR },
|
|
{ &CURSOR_COLUMN_HASDEFAULT, sizeof(VARIANT_BOOL), "COLUMN_HASDEFAULT", CURSOR_DBTYPE_BOOL },
|
|
{ &CURSOR_COLUMN_CASESENSITIVE, sizeof(VARIANT_BOOL), "COLUMN_CASESENSITIVE", CURSOR_DBTYPE_BOOL },
|
|
{ &CURSOR_COLUMN_UNIQUE, sizeof(VARIANT_BOOL), "COLUMN_UNIQUE", CURSOR_DBTYPE_BOOL },
|
|
};
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// CreateMetaColumns - Create array of meta-column objects
|
|
//
|
|
HRESULT CVDCursorMain::CreateMetaColumns()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&g_CriticalSection);
|
|
|
|
if (!s_dwMetaRefCount)
|
|
{
|
|
// allocate a static aray of metadata metadata columns
|
|
s_rgMetaColumns = new CVDRowsetColumn[MAX_METADATA_COLUMNS];
|
|
|
|
if (!s_rgMetaColumns)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
s_ulMetaColumns = MAX_METADATA_COLUMNS; // number of columns for IColumnsInfo
|
|
|
|
// initialize the array elments from the static g_MetaDataMetaData table
|
|
for (int i = 0; i < MAX_METADATA_COLUMNS; i++)
|
|
{
|
|
s_rgMetaColumns[i].Initialize(g_MetaDataMetaData[i].pCursorColumnID,
|
|
(BOOL)i, // false for 1st column (bookmark) TRUE for all other columns
|
|
g_MetaDataMetaData[i].cbMaxLength,
|
|
g_MetaDataMetaData[i].pszName,
|
|
g_MetaDataMetaData[i].dwCursorType,
|
|
i ); // ordinal number
|
|
}
|
|
}
|
|
|
|
s_dwMetaRefCount++;
|
|
|
|
m_fWeAddedMetaRef = TRUE;
|
|
|
|
cleanup:
|
|
LeaveCriticalSection(&g_CriticalSection);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// DestroyMetaColumns - Destroy array of meta-columns objects
|
|
//
|
|
void CVDCursorMain::DestroyMetaColumns()
|
|
{
|
|
EnterCriticalSection(&g_CriticalSection);
|
|
|
|
if (m_fWeAddedMetaRef)
|
|
{
|
|
s_dwMetaRefCount--;
|
|
|
|
if (!s_dwMetaRefCount)
|
|
{
|
|
delete [] s_rgMetaColumns;
|
|
|
|
s_ulMetaColumns = 0;
|
|
s_rgMetaColumns = NULL;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_CriticalSection);
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// CreateColumns - Create array of column objects
|
|
//
|
|
HRESULT CVDCursorMain::CreateColumns()
|
|
{
|
|
IColumnsInfo * pColumnsInfo;
|
|
|
|
// try to get IRowset's simple metadata interface
|
|
HRESULT hr = m_pRowset->QueryInterface(IID_IColumnsInfo, (void**)&pColumnsInfo);
|
|
|
|
if (FAILED(hr))
|
|
return VD_E_CANNOTGETMANDATORYINTERFACE;
|
|
|
|
ULONG cColumns = 0;
|
|
DBCOLUMNINFO * pInfo = NULL;
|
|
WCHAR * pStringsBuffer = NULL;
|
|
|
|
// now get column information
|
|
hr = pColumnsInfo->GetColumnInfo(&cColumns, &pInfo, &pStringsBuffer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pColumnsInfo->Release();
|
|
return VD_E_CANNOTGETCOLUMNINFO;
|
|
}
|
|
|
|
// store column count
|
|
// note cColumns includes the bookmark column (0)
|
|
m_ulColumns = cColumns;
|
|
|
|
// add one for CURSOR_COLUMN_BMK_CURSOR
|
|
m_ulColumns++;
|
|
|
|
// if rowset supports DBPROP_BOOKMARKSKIPPED add two for
|
|
// CURSOR_COLUMN_BMK_TEMPORARYREL and CURSOR_COLUMN_BMK_CURSORREL
|
|
if (m_fBookmarkSkipped)
|
|
m_ulColumns += 2;
|
|
|
|
// create array of rowset column objects
|
|
m_rgColumns = new CVDRowsetColumn[m_ulColumns];
|
|
|
|
if (!m_rgColumns)
|
|
{
|
|
if (pInfo)
|
|
g_pMalloc->Free(pInfo);
|
|
|
|
if (pStringsBuffer)
|
|
g_pMalloc->Free(pStringsBuffer);
|
|
|
|
pColumnsInfo->Release();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
ULONG ulCursorOrdinal = 0;
|
|
|
|
// get maximum length of bookmarks
|
|
m_cbMaxBookmark = pInfo[0].ulColumnSize;
|
|
|
|
// initialize data column(s)
|
|
for (ULONG ulCol = 1; ulCol < cColumns; ulCol++)
|
|
{
|
|
m_rgColumns[ulCursorOrdinal].Initialize(ulCol, ulCursorOrdinal, &pInfo[ulCol], m_cbMaxBookmark);
|
|
ulCursorOrdinal++;
|
|
}
|
|
|
|
// initialize bookmark columns
|
|
pInfo[0].pwszName = NULL; // ICursor requires bookmark columns have a NULL name
|
|
|
|
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
|
|
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKTEMPORARY);
|
|
ulCursorOrdinal++;
|
|
|
|
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
|
|
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKCURSOR);
|
|
ulCursorOrdinal++;
|
|
|
|
if (m_fBookmarkSkipped)
|
|
{
|
|
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
|
|
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKTEMPORARYREL);
|
|
ulCursorOrdinal++;
|
|
|
|
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
|
|
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKCURSORREL);
|
|
ulCursorOrdinal++;
|
|
}
|
|
|
|
// free resources
|
|
if (pInfo)
|
|
g_pMalloc->Free(pInfo);
|
|
|
|
if (pStringsBuffer)
|
|
g_pMalloc->Free(pStringsBuffer);
|
|
|
|
pColumnsInfo->Release();
|
|
|
|
InitOptionalMetadata(cColumns);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// InitOptionalMetadata - gets additional metadata from IColumnsRowset (if available)
|
|
//
|
|
void CVDCursorMain::InitOptionalMetadata(ULONG cColumns)
|
|
{
|
|
// we should return if there is only a bookmark column
|
|
if (cColumns < 2)
|
|
return;
|
|
|
|
IColumnsRowset * pColumnsRowset = NULL;
|
|
|
|
// try to get IColumnsRowset interface
|
|
HRESULT hr = m_pRowset->QueryInterface(IID_IColumnsRowset, (void**)&pColumnsRowset);
|
|
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
IRowset * pRowset = NULL;
|
|
IColumnsInfo * pColumnsInfo = NULL;
|
|
IAccessor * pAccessor = NULL;
|
|
|
|
ULONG cOptColumnsAvailable = 0;
|
|
DBID * rgOptColumnsAvailable = NULL;
|
|
DBID * pOptColumnsAvailable = NULL; // work ptr
|
|
|
|
ULONG cOptColumns = 0;
|
|
DBID * rgOptColumns = NULL;
|
|
DBID * pOptColumns = NULL; //work ptr
|
|
|
|
ULONG ulBuffLen = 0;
|
|
BYTE * pBuff = NULL;
|
|
HACCESSOR hAccessor;
|
|
BOOL fAccessorCreated = FALSE;
|
|
|
|
HROW * rgRows = NULL;
|
|
ULONG cRowsObtained = 0;
|
|
|
|
// we are only interested in a few of the optional columns
|
|
ULONG rgColumnPropids[VD_COLUMNSROWSET_MAX_OPT_COLUMNS];
|
|
ULONG rgOrdinals[VD_COLUMNSROWSET_MAX_OPT_COLUMNS];
|
|
DBBINDING rgBindings[VD_COLUMNSROWSET_MAX_OPT_COLUMNS];
|
|
DBBINDING * pBinding = NULL; // work ptr
|
|
BOOL fMatched;
|
|
GUID guidCID = DBCIDGUID;
|
|
|
|
ULONG cColumnsMatched = 0;
|
|
ULONG i, j;
|
|
|
|
// get array of available columns
|
|
hr = pColumnsRowset->GetAvailableColumns(&cOptColumnsAvailable, &rgOptColumnsAvailable);
|
|
|
|
if (FAILED(hr) || 0 == cOptColumnsAvailable)
|
|
goto cleanup;
|
|
|
|
ASSERT_(rgOptColumnsAvailable);
|
|
|
|
// allocate enough DBIDs for the lesser of the total available columns or the total number of
|
|
// columns we're interested in
|
|
rgOptColumns = (DBID *)g_pMalloc->Alloc(min(cOptColumnsAvailable, VD_COLUMNSROWSET_MAX_OPT_COLUMNS)
|
|
* sizeof(DBID));
|
|
|
|
if (!rgOptColumns)
|
|
goto cleanup;
|
|
|
|
// initalize work pointers
|
|
pOptColumnsAvailable = rgOptColumnsAvailable;
|
|
pOptColumns = rgOptColumns;
|
|
pBinding = rgBindings;
|
|
|
|
memset(pBinding, 0, sizeof(DBBINDING) * VD_COLUMNSROWSET_MAX_OPT_COLUMNS);
|
|
|
|
// search available columns for the ones we are interested in copying them into rgOptColumns
|
|
for (i = 0; i < cOptColumnsAvailable && cColumnsMatched < VD_COLUMNSROWSET_MAX_OPT_COLUMNS; i++)
|
|
{
|
|
fMatched = FALSE; // initialize to false
|
|
if (DBKIND_GUID_PROPID == pOptColumnsAvailable->eKind &&
|
|
DO_GUIDS_MATCH(pOptColumnsAvailable->uGuid.guid, guidCID))
|
|
{
|
|
switch (pOptColumnsAvailable->uName.ulPropid)
|
|
{
|
|
case 12: //DBCOLUMN_COLLATINGSEQUENCE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)12};
|
|
pBinding->obValue = ulBuffLen;
|
|
ulBuffLen += sizeof(ULONG);
|
|
pBinding->obStatus = ulBuffLen;
|
|
ulBuffLen += sizeof(DBSTATUS);
|
|
pBinding->dwPart = DBPART_VALUE | DBPART_STATUS;
|
|
pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
pBinding->wType = DBTYPE_I4;
|
|
fMatched = TRUE;
|
|
break;
|
|
|
|
//string properties
|
|
case 10: //DBCOLUMN_BASECOLUMNNAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)10};
|
|
case 11: //DBCOLUMN_BASETABLENAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)11};
|
|
case 14: //DBCOLUMN_DEFAULTVALUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)14};
|
|
pBinding->obValue = ulBuffLen;
|
|
ulBuffLen += 512;
|
|
pBinding->obLength = ulBuffLen;
|
|
ulBuffLen += sizeof(ULONG);
|
|
pBinding->obStatus = ulBuffLen;
|
|
ulBuffLen += sizeof(DBSTATUS);
|
|
pBinding->dwPart = DBPART_VALUE | DBPART_LENGTH |DBPART_STATUS;
|
|
pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
pBinding->cbMaxLen = 512;
|
|
pBinding->wType = DBTYPE_WSTR;
|
|
fMatched = TRUE;
|
|
break;
|
|
|
|
// bool properties
|
|
case 16: //DBCOLUMN_HASDEFAULT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)16};
|
|
case 17: //DBCOLUMN_ISAUTOINCREMENT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)17};
|
|
case 18: //DBCOLUMN_ISCASESENSITIVE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)18};
|
|
case 21: //DBCOLUMN_ISUNIQUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)21};
|
|
pBinding->obValue = ulBuffLen;
|
|
ulBuffLen += sizeof(VARIANT_BOOL);
|
|
pBinding->obStatus = ulBuffLen;
|
|
ulBuffLen += sizeof(DBSTATUS);
|
|
pBinding->dwPart = DBPART_VALUE | DBPART_STATUS;
|
|
pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
|
|
pBinding->wType = DBTYPE_BOOL;
|
|
fMatched = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fMatched)
|
|
{
|
|
rgColumnPropids[cColumnsMatched] = pOptColumnsAvailable->uName.ulPropid;
|
|
*pOptColumns = *pOptColumnsAvailable;
|
|
pBinding++;
|
|
pOptColumns++;
|
|
cColumnsMatched++;
|
|
}
|
|
pOptColumnsAvailable++;
|
|
}
|
|
|
|
if (!cColumnsMatched)
|
|
goto cleanup;
|
|
|
|
// get column's rowset
|
|
hr = pColumnsRowset->GetColumnsRowset(NULL,
|
|
cColumnsMatched,
|
|
rgOptColumns,
|
|
IID_IRowset,
|
|
0,
|
|
NULL,
|
|
(IUnknown**)&pRowset);
|
|
|
|
if FAILED(hr)
|
|
{
|
|
ASSERT_(FALSE);
|
|
goto cleanup;
|
|
}
|
|
|
|
// get IColumnsInfo interface on column's rowset
|
|
hr = pRowset->QueryInterface(IID_IColumnsInfo, (void**)&pColumnsInfo);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ASSERT_(FALSE);
|
|
goto cleanup;
|
|
}
|
|
|
|
// get ordinals for our optional columns
|
|
hr = pColumnsInfo->MapColumnIDs(cColumnsMatched, rgOptColumns, rgOrdinals);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
ASSERT_(FALSE);
|
|
goto cleanup;
|
|
}
|
|
|
|
// update binding structures with ordinals
|
|
for (i = 0; i < cColumnsMatched; i++)
|
|
rgBindings[i].iOrdinal = rgOrdinals[i];
|
|
|
|
// get IAccessor interface on column's rowset
|
|
hr = pRowset->QueryInterface(IID_IAccessor, (void**)&pAccessor);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ASSERT_(FALSE);
|
|
goto cleanup;
|
|
}
|
|
|
|
// create accessor based on rgBindings array
|
|
hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
|
|
cColumnsMatched,
|
|
rgBindings,
|
|
ulBuffLen,
|
|
&hAccessor,
|
|
NULL);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
ASSERT_(FALSE);
|
|
goto cleanup;
|
|
}
|
|
|
|
// set flag that accessor was successfully created (used during cleanup)
|
|
fAccessorCreated = TRUE;
|
|
|
|
// allocate a buffer to hold the metadata
|
|
pBuff = (BYTE *)g_pMalloc->Alloc(ulBuffLen);
|
|
|
|
if (!pBuff)
|
|
{
|
|
ASSERT_(FALSE);
|
|
goto cleanup;
|
|
}
|
|
|
|
// get all rows (each row represents a column in the original rowset)
|
|
// except the first row which represents the bookmark column
|
|
hr = pRowset->GetNextRows(0, // reserved
|
|
1, // skip the bookmark row
|
|
cColumns - 1, // get 1 less than cColumns to account for bookmark row
|
|
&cRowsObtained, // return count of rows obtanied
|
|
&rgRows);
|
|
|
|
if (FAILED(hr) || !cRowsObtained)
|
|
{
|
|
ASSERT_(FALSE);
|
|
goto cleanup;
|
|
}
|
|
|
|
BYTE * pValue;
|
|
|
|
// loop through all rows obtained
|
|
for (i = 0; i < cRowsObtained; i++)
|
|
{
|
|
// call GetData to get the metadata for this row (which represents a column in the orig rowset)
|
|
hr = pRowset->GetData(rgRows[i], hAccessor, pBuff);
|
|
if SUCCEEDED(hr)
|
|
{
|
|
// now update the CVDRowsetColumn object (that this row represents)
|
|
// with the values returned from GetData
|
|
for (j = 0; j < cColumnsMatched; j++)
|
|
{
|
|
if (DBBINDSTATUS_OK != *(DBSTATUS*)(pBuff + rgBindings[j].obStatus))
|
|
continue;
|
|
|
|
// set pValue to point into buffer at correct offset
|
|
pValue = pBuff + rgBindings[j].obValue;
|
|
|
|
switch (rgColumnPropids[j])
|
|
{
|
|
case 12: //DBCOLUMN_COLLATINGSEQUENCE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)12};
|
|
m_rgColumns[i].SetCollatingOrder(*(LCID*)pValue);
|
|
break;
|
|
|
|
//string properties
|
|
case 10: //DBCOLUMN_BASECOLUMNNAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)10};
|
|
m_rgColumns[i].SetBaseColumnName((WCHAR*)pValue, *(ULONG*)(pBuff + rgBindings[j].obLength));
|
|
break;
|
|
case 11: //DBCOLUMN_BASETABLENAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)11};
|
|
m_rgColumns[i].SetBaseName((WCHAR*)pValue, *(ULONG*)(pBuff + rgBindings[j].obLength));
|
|
break;
|
|
case 14: //DBCOLUMN_DEFAULTVALUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)14};
|
|
m_rgColumns[i].SetDefaultValue((WCHAR*)pValue, *(ULONG*)(pBuff + rgBindings[j].obLength));
|
|
break;
|
|
|
|
// bool properties
|
|
case 16: //DBCOLUMN_HASDEFAULT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)16};
|
|
m_rgColumns[i].SetHasDefault(*(VARIANT_BOOL*)pValue);
|
|
break;
|
|
case 17: //DBCOLUMN_ISAUTOINCREMENT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)17};
|
|
m_rgColumns[i].SetAutoIncrement(*(VARIANT_BOOL*)pValue);
|
|
break;
|
|
case 18: //DBCOLUMN_ISCASESENSITIVE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)18};
|
|
m_rgColumns[i].SetCaseSensitive(*(VARIANT_BOOL*)pValue);
|
|
break;
|
|
case 21: //DBCOLUMN_ISUNIQUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)21};
|
|
m_rgColumns[i].SetUnique(*(VARIANT_BOOL*)pValue);
|
|
break;
|
|
default:
|
|
ASSERT_(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ASSERT_(FALSE);
|
|
}
|
|
|
|
m_fColumnsRowsetSupported = TRUE;
|
|
|
|
cleanup:
|
|
|
|
|
|
if (pBuff)
|
|
g_pMalloc->Free(pBuff);
|
|
|
|
if (pAccessor)
|
|
{
|
|
if (fAccessorCreated)
|
|
pAccessor->ReleaseAccessor(hAccessor, NULL);
|
|
pAccessor->Release();
|
|
}
|
|
|
|
if (pRowset)
|
|
{
|
|
if (cRowsObtained)
|
|
{
|
|
pRowset->ReleaseRows(cRowsObtained, rgRows, NULL, NULL, NULL);
|
|
ASSERT_(rgRows);
|
|
g_pMalloc->Free(rgRows);
|
|
}
|
|
pRowset->Release();
|
|
}
|
|
|
|
if (pColumnsInfo)
|
|
pColumnsInfo->Release();
|
|
|
|
if (rgOptColumnsAvailable)
|
|
g_pMalloc->Free(rgOptColumnsAvailable);
|
|
|
|
if (rgOptColumns)
|
|
g_pMalloc->Free(rgOptColumns);
|
|
|
|
if (pColumnsRowset)
|
|
pColumnsRowset->Release();
|
|
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// DestroyColumns - Destroy array of column objects
|
|
//
|
|
void CVDCursorMain::DestroyColumns()
|
|
{
|
|
delete [] m_rgColumns;
|
|
|
|
m_ulColumns = 0;
|
|
m_rgColumns = NULL;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// ConnectIRowsetNotify - Connect IRowsetNotify interface
|
|
//
|
|
HRESULT CVDCursorMain::ConnectIRowsetNotify()
|
|
{
|
|
IConnectionPointContainer * pConnectionPointContainer;
|
|
|
|
HRESULT hr = GetRowset()->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
|
|
|
|
if (FAILED(hr))
|
|
return VD_E_CANNOTCONNECTIROWSETNOTIFY;
|
|
|
|
IConnectionPoint * pConnectionPoint;
|
|
|
|
hr = pConnectionPointContainer->FindConnectionPoint(IID_IRowsetNotify, &pConnectionPoint);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pConnectionPointContainer->Release();
|
|
return VD_E_CANNOTCONNECTIROWSETNOTIFY;
|
|
}
|
|
|
|
hr = pConnectionPoint->Advise(&m_RowsetNotify, &m_dwAdviseCookie);
|
|
|
|
pConnectionPointContainer->Release();
|
|
pConnectionPoint->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// DisconnectIRowsetNotify - Disconnect IRowsetNotify interface
|
|
//
|
|
void CVDCursorMain::DisconnectIRowsetNotify()
|
|
{
|
|
IConnectionPointContainer * pConnectionPointContainer;
|
|
|
|
HRESULT hr = GetRowset()->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
|
|
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
IConnectionPoint * pConnectionPoint;
|
|
|
|
hr = pConnectionPointContainer->FindConnectionPoint(IID_IRowsetNotify, &pConnectionPoint);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pConnectionPointContainer->Release();
|
|
return;
|
|
}
|
|
|
|
hr = pConnectionPoint->Unadvise(m_dwAdviseCookie);
|
|
|
|
if (SUCCEEDED(hr))
|
|
m_dwAdviseCookie = 0; // clear connection point identifier
|
|
|
|
pConnectionPointContainer->Release();
|
|
pConnectionPoint->Release();
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IUnknown QueryInterface
|
|
//
|
|
HRESULT CVDCursorMain::QueryInterface(REFIID riid, void **ppvObjOut)
|
|
{
|
|
ASSERT_POINTER(ppvObjOut, IUnknown*)
|
|
|
|
if (!ppvObjOut)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObjOut = NULL;
|
|
|
|
if (DO_GUIDS_MATCH(riid, IID_IUnknown))
|
|
{
|
|
*ppvObjOut = this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IUnknown AddRef (needed to resolve ambiguity)
|
|
//
|
|
ULONG CVDCursorMain::AddRef(void)
|
|
{
|
|
return CVDNotifier::AddRef();
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IUnknown Release (needed to resolve ambiguity)
|
|
//
|
|
ULONG CVDCursorMain::Release(void)
|
|
{
|
|
|
|
if (1 == m_dwRefCount)
|
|
Passivate(); // unhook everything including notification sink
|
|
|
|
if (1 > --m_dwRefCount)
|
|
{
|
|
if (0 == m_RowsetNotify.GetRefCount())
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_dwRefCount;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IsSameRowAsNew - Determine if specified hRow is an addrow
|
|
//
|
|
BOOL CVDCursorMain::IsSameRowAsNew(HROW hrow)
|
|
{
|
|
for (int k = 0; k < m_Children.GetSize(); k++)
|
|
{
|
|
if (((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->IsSameRowAsNew(hrow) == S_OK)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// AddedRows - Get the number of add-rows in cursor
|
|
//
|
|
ULONG CVDCursorMain::AddedRows()
|
|
{
|
|
ULONG cAdded = 0;
|
|
|
|
for (int k = 0; k < m_Children.GetSize(); k++)
|
|
{
|
|
if (((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->GetEditMode() == CURSOR_DBEDITMODE_ADD)
|
|
cAdded++;
|
|
}
|
|
|
|
return cAdded;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify Methods
|
|
//=--------------------------------------------------------------------------=
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify OnFieldChange
|
|
//=--------------------------------------------------------------------------=
|
|
// Forward to all CVDCursorPosition objects in our family
|
|
//
|
|
HRESULT CVDCursorMain::OnFieldChange(IRowset *pRowset,
|
|
HROW hRow,
|
|
ULONG cColumns,
|
|
ULONG rgColumns[],
|
|
DBREASON eReason,
|
|
DBEVENTPHASE ePhase,
|
|
BOOL fCantDeny)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// return if notification caused by internal rowset call
|
|
if (m_fInternalSetData && eReason == DBREASON_COLUMN_SET)
|
|
return hr;
|
|
|
|
for (int k = 0; k < m_Children.GetSize(); k++)
|
|
{
|
|
hr = ((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->OnFieldChange(pRowset,
|
|
hRow,
|
|
cColumns,
|
|
rgColumns,
|
|
eReason,
|
|
ePhase,
|
|
fCantDeny);
|
|
if (hr)
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify OnRowChange
|
|
//=--------------------------------------------------------------------------=
|
|
// Forward to all CVDCursorPosition objects in our family
|
|
//
|
|
HRESULT CVDCursorMain::OnRowChange(IRowset *pRowset,
|
|
ULONG cRows,
|
|
const HROW rghRows[],
|
|
DBREASON eReason,
|
|
DBEVENTPHASE ePhase,
|
|
BOOL fCantDeny)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// return if notification caused by internal rowset call (either insert or delete)
|
|
if (m_fInternalInsertRow && eReason == DBREASON_ROW_INSERT || m_fInternalDeleteRows && eReason == DBREASON_ROW_DELETE)
|
|
return hr;
|
|
|
|
for (int k = 0; k < m_Children.GetSize(); k++)
|
|
{
|
|
hr = ((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->OnRowChange(pRowset,
|
|
cRows,
|
|
rghRows,
|
|
eReason,
|
|
ePhase,
|
|
fCantDeny);
|
|
if (hr)
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify OnRowsetChange
|
|
//=--------------------------------------------------------------------------=
|
|
// Forward to all CVDCursorPosition objects in our family
|
|
//
|
|
HRESULT CVDCursorMain::OnRowsetChange(IRowset *pRowset,
|
|
DBREASON eReason,
|
|
DBEVENTPHASE ePhase,
|
|
BOOL fCantDeny)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
for (int k = 0; k < m_Children.GetSize(); k++)
|
|
{
|
|
hr = ((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->OnRowsetChange(pRowset,
|
|
eReason,
|
|
ePhase,
|
|
fCantDeny);
|
|
if (hr)
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// CVDCursorMain::CVDRowsetNotify::m_pMainUnknown
|
|
//=--------------------------------------------------------------------------=
|
|
// this method is used when we're sitting in the private unknown object,
|
|
// and we need to get at the pointer for the main unknown. basically, it's
|
|
// a little better to do this pointer arithmetic than have to store a pointer
|
|
// to the parent, etc.
|
|
//
|
|
inline CVDCursorMain *CVDCursorMain::CVDRowsetNotify::m_pMainUnknown
|
|
(
|
|
void
|
|
)
|
|
{
|
|
return (CVDCursorMain *)((LPBYTE)this - offsetof(CVDCursorMain, m_RowsetNotify));
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// CVDCursorMain::CVDRowsetNotify::QueryInterface
|
|
//=--------------------------------------------------------------------------=
|
|
// this is the non-delegating internal QI routine.
|
|
//
|
|
// Parameters:
|
|
// REFIID - [in] interface they want
|
|
// void ** - [out] where they want to put the resulting object ptr.
|
|
//
|
|
// Output:
|
|
// HRESULT - S_OK, E_NOINTERFACE
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CVDCursorMain::CVDRowsetNotify::QueryInterface
|
|
(
|
|
REFIID riid,
|
|
void **ppvObjOut
|
|
)
|
|
{
|
|
if (!ppvObjOut)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObjOut = NULL;
|
|
|
|
if (DO_GUIDS_MATCH(riid, IID_IUnknown))
|
|
*ppvObjOut = (IUnknown *)this;
|
|
else
|
|
if (DO_GUIDS_MATCH(riid, IID_IRowsetNotify))
|
|
*ppvObjOut = (IUnknown *)this;
|
|
|
|
if (*ppvObjOut)
|
|
{
|
|
m_cRef++;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// CVDCursorMain::CVDRowsetNotify::AddRef
|
|
//=--------------------------------------------------------------------------=
|
|
// adds a tick to the current reference count.
|
|
//
|
|
// Output:
|
|
// ULONG - the new reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
ULONG CVDCursorMain::CVDRowsetNotify::AddRef
|
|
(
|
|
void
|
|
)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// CVDCursorMain::CVDRowsetNotify::Release
|
|
//=--------------------------------------------------------------------------=
|
|
// removes a tick from the count, and delets the object if necessary
|
|
//
|
|
// Output:
|
|
// ULONG - remaining refs
|
|
//
|
|
// Notes:
|
|
//
|
|
ULONG CVDCursorMain::CVDRowsetNotify::Release
|
|
(
|
|
void
|
|
)
|
|
{
|
|
ULONG cRef = --m_cRef;
|
|
|
|
if (!m_cRef && !m_pMainUnknown()->m_dwRefCount)
|
|
delete m_pMainUnknown();
|
|
|
|
return cRef;
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify Methods
|
|
//=--------------------------------------------------------------------------=
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify OnFieldChange
|
|
//=--------------------------------------------------------------------------=
|
|
// Forward to all CVDCursorPosition objects in our family
|
|
//
|
|
HRESULT CVDCursorMain::CVDRowsetNotify::OnFieldChange(IRowset *pRowset,
|
|
HROW hRow,
|
|
ULONG cColumns,
|
|
ULONG rgColumns[],
|
|
DBREASON eReason,
|
|
DBEVENTPHASE ePhase,
|
|
BOOL fCantDeny)
|
|
{
|
|
|
|
return m_pMainUnknown()->OnFieldChange(pRowset,
|
|
hRow,
|
|
cColumns,
|
|
rgColumns,
|
|
eReason,
|
|
ePhase,
|
|
fCantDeny);
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify OnRowChange
|
|
//=--------------------------------------------------------------------------=
|
|
// Forward to all CVDCursorPosition objects in our family
|
|
//
|
|
HRESULT CVDCursorMain::CVDRowsetNotify::OnRowChange(IRowset *pRowset,
|
|
ULONG cRows,
|
|
const HROW rghRows[],
|
|
DBREASON eReason,
|
|
DBEVENTPHASE ePhase,
|
|
BOOL fCantDeny)
|
|
{
|
|
return m_pMainUnknown()->OnRowChange(pRowset,
|
|
cRows,
|
|
rghRows,
|
|
eReason,
|
|
ePhase,
|
|
fCantDeny);
|
|
}
|
|
|
|
//=--------------------------------------------------------------------------=
|
|
// IRowsetNotify OnRowsetChange
|
|
//=--------------------------------------------------------------------------=
|
|
// Forward to all CVDCursorPosition objects in our family
|
|
//
|
|
HRESULT CVDCursorMain::CVDRowsetNotify::OnRowsetChange(IRowset *pRowset,
|
|
DBREASON eReason,
|
|
DBEVENTPHASE ePhase,
|
|
BOOL fCantDeny)
|
|
{
|
|
return m_pMainUnknown()->OnRowsetChange(pRowset,
|
|
eReason,
|
|
ePhase,
|
|
fCantDeny);
|
|
}
|
|
|