515 lines
14 KiB
C++
515 lines
14 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Microsoft OLE DB RowsetViewer
|
|
// Copyright (C) 1994 - 1999 By Microsoft Corporation.
|
|
//
|
|
// @doc
|
|
//
|
|
// @module CROW.CPP
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
#include "Headers.h"
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// CRow::CRow
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
CRow::CRow(CMainWindow* pCMainWindow, CMDIChild* pCMDIChild)
|
|
: CDataAccess(eCRow, pCMainWindow, pCMDIChild)
|
|
{
|
|
//Row
|
|
m_pIRow = NULL;//Row Interface
|
|
m_pIGetSession = NULL;//Row Interface
|
|
|
|
m_pIColumnsInfo2 = NULL;//Row Interface
|
|
m_pICreateRow = NULL;//Row Interface
|
|
m_pIDBCreateCommand = NULL;//Row Interface
|
|
m_pIRowChange = NULL;//Row Interface
|
|
m_pIRowSchemaChange = NULL;//Row Interface
|
|
m_pIBindResource = NULL;//Row Interface
|
|
m_pIScopedOperations = NULL;//Row Interface
|
|
|
|
//ColAccess
|
|
m_cColAccess = 0;
|
|
m_rgColAccess = NULL;
|
|
|
|
//Listeners
|
|
|
|
//Data
|
|
m_hSourceRow = NULL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// CRow::~CRow
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
CRow::~CRow()
|
|
{
|
|
ReleaseObject(0);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// IUnknown** CRow::GetInterfaceAddress
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
IUnknown** CRow::GetInterfaceAddress(REFIID riid)
|
|
{
|
|
HANDLE_GETINTERFACE(IRow);
|
|
HANDLE_GETINTERFACE(IGetSession);
|
|
HANDLE_GETINTERFACE(IColumnsInfo2);
|
|
HANDLE_GETINTERFACE(ICreateRow);
|
|
HANDLE_GETINTERFACE(IDBCreateCommand);
|
|
HANDLE_GETINTERFACE(IRowChange);
|
|
HANDLE_GETINTERFACE(IRowSchemaChange);
|
|
HANDLE_GETINTERFACE(IBindResource);
|
|
HANDLE_GETINTERFACE(IScopedOperations);
|
|
|
|
//Otherwise delegate
|
|
return CDataAccess::GetInterfaceAddress(riid);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// CRow::AutoRelease
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::AutoRelease()
|
|
{
|
|
m_cColAccess = 0;
|
|
SAFE_FREE(m_rgColAccess);
|
|
|
|
//Rowset
|
|
RELEASE_INTERFACE(IRow);
|
|
RELEASE_INTERFACE(IGetSession);
|
|
|
|
RELEASE_INTERFACE(IColumnsInfo2);
|
|
RELEASE_INTERFACE(ICreateRow);
|
|
RELEASE_INTERFACE(IDBCreateCommand);
|
|
RELEASE_INTERFACE(IRowChange);
|
|
RELEASE_INTERFACE(IRowSchemaChange);
|
|
RELEASE_INTERFACE(IBindResource);
|
|
RELEASE_INTERFACE(IScopedOperations);
|
|
|
|
//Delegate
|
|
return CDataAccess::AutoRelease();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// CRow::AutoQI
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::AutoQI(DWORD dwCreateOpts)
|
|
{
|
|
//Delegate First so we have base interfaces
|
|
CDataAccess::AutoQI(dwCreateOpts);
|
|
|
|
//[MANDATORY] Obtain [mandatory] interfaces
|
|
if(dwCreateOpts & CREATE_QI_MANDATORY)
|
|
{
|
|
OBTAIN_INTERFACE(IRow);
|
|
OBTAIN_INTERFACE(IGetSession);
|
|
}
|
|
|
|
//Auto QI
|
|
if(dwCreateOpts & CREATE_QI_OPTIONAL)
|
|
{
|
|
OBTAIN_INTERFACE(IColumnsInfo2);
|
|
OBTAIN_INTERFACE(ICreateRow);
|
|
OBTAIN_INTERFACE(IDBCreateCommand);
|
|
OBTAIN_INTERFACE(IRowChange);
|
|
OBTAIN_INTERFACE(IRowSchemaChange);
|
|
OBTAIN_INTERFACE(IBindResource);
|
|
OBTAIN_INTERFACE(IScopedOperations);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// HRESULT CRow::DisplayObject
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::DisplayObject()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BINDCOLS eBindCols = (GetOptions()->m_dwAccessorOpts & ACCESSOR_BIND_BOOKMARK ? BIND_ALLCOLS : BIND_ALLCOLSEXPECTBOOKMARK);
|
|
|
|
if(m_pCMDIChild)
|
|
{
|
|
//First Clear the existing Window...
|
|
m_pCMDIChild->m_pCDataGrid->m_fLastFetchForward = FALSE;
|
|
m_pCMDIChild->m_pCDataGrid->m_lCurPos = 0;
|
|
TESTC(hr = m_pCMDIChild->m_pCDataGrid->ClearAll());
|
|
}
|
|
|
|
//Setup ColumnAccess Structures, (based off the ColumnInfo)
|
|
TESTC(hr = SetupColAccess(eBindCols));
|
|
|
|
if(m_pCMDIChild)
|
|
{
|
|
//Refresh the Columns and Rows
|
|
TESTC(hr = m_pCMDIChild->m_pCDataGrid->RefreshData());
|
|
}
|
|
|
|
//Delegate
|
|
TESTC(hr = CDataAccess::DisplayObject());
|
|
|
|
CLEANUP:
|
|
if(m_pCMDIChild)
|
|
m_pCMDIChild->UpdateControls();
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRow::GetObjectDesc
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
WCHAR* CRow::GetObjectDesc()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!m_strObjectDesc && m_hSourceRow)
|
|
{
|
|
WCHAR* pwszValue = NULL;
|
|
|
|
//0x00000000 = 1 Byte = 2 Asci Chars + "0x" + NULL Terminator
|
|
SAFE_ALLOC(pwszValue, WCHAR, POINTER_DISPLAYSIZE);
|
|
StringFormat(pwszValue, POINTER_DISPLAYSIZE, L"0x%p", (HANDLE)m_hSourceRow);
|
|
m_strObjectDesc.Attach(pwszValue);
|
|
}
|
|
|
|
CLEANUP:
|
|
return m_strObjectDesc;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// HRESULT CRow::CreateCommand
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::CreateCommand(CAggregate* pCAggregate, REFIID riid, IUnknown** ppIUnknown)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//Obtain the IDBCreateCommand Interface
|
|
IDBCreateCommand* pIDBCreateCommand = SOURCE_GETINTERFACE(this, IDBCreateCommand);
|
|
if(pIDBCreateCommand)
|
|
{
|
|
//CreateCommand
|
|
XTEST(hr = pIDBCreateCommand->CreateCommand(pCAggregate, riid, ppIUnknown));
|
|
TESTC(TRACE_METHOD(hr, L"IDBCreateCommand::CreateCommand(0x%p, %s, &0x%p)", pCAggregate, GetInterfaceName(riid), ppIUnknown ? *ppIUnknown : NULL));
|
|
|
|
//Handle Aggregation
|
|
if(pCAggregate)
|
|
TESTC(hr = pCAggregate->HandleAggregation(riid, ppIUnknown));
|
|
}
|
|
|
|
CLEANUP:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// HRESULT CRow::OpenRowset
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::OpenRowset(CAggregate* pCAggregate, DBID* pTableID, DBID* pIndexID, REFIID riid, ULONG cPropSets, DBPROPSET* rgPropSets, IUnknown** ppIUnknown)
|
|
{
|
|
HRESULT hr = E_FAIL; // HRESULT
|
|
|
|
if(!m_pIScopedOperations)
|
|
return E_FAIL;
|
|
|
|
WCHAR wszTableName[MAX_QUERY_LEN+1];
|
|
WCHAR wszIndexName[MAX_QUERY_LEN+1];
|
|
|
|
// From IOpenRowset, get a rowset object
|
|
DBIDToString(pTableID, wszTableName, MAX_QUERY_LEN);
|
|
DBIDToString(pIndexID, wszIndexName, MAX_QUERY_LEN);
|
|
|
|
XTEST_(hr = m_pIScopedOperations->OpenRowset(
|
|
pCAggregate, // pUnkOuter
|
|
pTableID, // pTableID
|
|
pIndexID, // pIndexID
|
|
riid, // refiid
|
|
cPropSets, // cProperties
|
|
rgPropSets, // rgProperties
|
|
ppIUnknown),S_OK); // IRowset pointer
|
|
TRACE_METHOD(hr, L"IScopedOperations::OpenRowset(0x%p, %s, %s, %s, %d, 0x%p, &0x%p)", pCAggregate, wszTableName, wszIndexName, GetInterfaceName(riid), cPropSets, rgPropSets, ppIUnknown ? *ppIUnknown : NULL);
|
|
|
|
//Display Errors (if occurred)
|
|
TESTC(hr = DisplayPropErrors(hr, cPropSets, rgPropSets));
|
|
|
|
//Handle Aggregation
|
|
if(pCAggregate)
|
|
TESTC(hr = pCAggregate->HandleAggregation(riid, ppIUnknown));
|
|
|
|
CLEANUP:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// HRESULT CRow::SetupColAccess
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::SetupColAccess(BINDCOLS eBindCols)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DBLENGTH dwOffset = 0;
|
|
ULONG i;
|
|
|
|
//Only capable of the Following Converions (for Display)
|
|
DWORD dwMaxLength = GetOptions()->m_dwMaxLength;
|
|
DWORD dwAccessorOpts = GetOptions()->m_dwAccessorOpts;
|
|
|
|
if(m_pIColumnsInfo == NULL)
|
|
return E_FAIL;
|
|
|
|
//GetColumnInfo
|
|
GetColInfo();
|
|
|
|
//Alloc the space to hold the ColumnAccess structs
|
|
ULONG cBindings = 0;
|
|
DBBINDING* rgBindings = NULL;
|
|
SAFE_ALLOC(m_rgColAccess, DBCOLUMNACCESS, m_ColumnInfo.GetCount());
|
|
SAFE_ALLOC(rgBindings, DBBINDING, m_ColumnInfo.GetCount());
|
|
|
|
//Figure out how big to make the buffer...
|
|
for(i=0; i<m_ColumnInfo.GetCount(); i++)
|
|
{
|
|
//Offset
|
|
m_rgColAccess[i].cbMaxLen = GetMaxDisplaySize(GetOptions()->GetBindingType(m_ColumnInfo[i].wType), m_ColumnInfo[i].wType, m_ColumnInfo[i].ulColumnSize, dwMaxLength);
|
|
dwOffset = ROUNDUP( dwOffset + m_rgColAccess[i].cbMaxLen );
|
|
}
|
|
|
|
//Size for pData
|
|
SAFE_REALLOC(m_pData, BYTE, dwOffset);
|
|
|
|
dwOffset = 0;
|
|
m_cColAccess = 0;
|
|
cBindings = 0;
|
|
for(i=0; i<m_ColumnInfo.GetCount(); i++)
|
|
{
|
|
DBCOLUMNINFO* pColInfo = &m_ColumnInfo[i];
|
|
DBCOLUMNACCESS* pColAccess = &m_rgColAccess[m_cColAccess];
|
|
DBBINDING* pBinding = &rgBindings[cBindings];
|
|
|
|
//Setup the Bindings
|
|
pColAccess->columnid = pColInfo->columnid;
|
|
pColAccess->bPrecision = pColInfo->bPrecision;
|
|
pColAccess->bScale = pColInfo->bScale;
|
|
pColAccess->wType = GetOptions()->GetBindingType(pColInfo->wType);
|
|
pColAccess->cbDataLen = 0;
|
|
|
|
//NOTE: This is setup above in the Previous for loop...
|
|
pColAccess->cbMaxLen = m_rgColAccess[i].cbMaxLen;
|
|
|
|
//BLOB or IUnknown Bindings
|
|
if(pColAccess->wType == DBTYPE_IUNKNOWN || pColInfo->wType == DBTYPE_IUNKNOWN ||
|
|
(pColInfo->dwFlags & DBCOLUMNFLAGS_ISLONG && (dwAccessorOpts & (ACCESSOR_BLOB_ISEQSTREAM|ACCESSOR_BLOB_ILOCKBYTES|ACCESSOR_BLOB_ISTORAGE|ACCESSOR_BLOB_ISTREAM))))
|
|
{
|
|
pColAccess->wType = DBTYPE_IUNKNOWN;
|
|
pColAccess->cbMaxLen = sizeof(IUnknown*);
|
|
}
|
|
|
|
//If the consumer requested not to bind the Value in Options, then set pData = NULL
|
|
//This is how the 2.5 spec says to indicate VALUE is not bound (since their is no dwPart).
|
|
pColAccess->pData = NULL;
|
|
if(dwAccessorOpts & ACCESSOR_BIND_VALUE)
|
|
pColAccess->pData = (BYTE*)m_pData + dwOffset;
|
|
|
|
//Initialize the Status to an error, so we don't end up freeing outofline
|
|
//data we haven't retreived yet...
|
|
pColAccess->dwStatus = DBSTATUS_E_UNAVAILABLE;
|
|
|
|
//Special Handling for other non-OLE DB defined convertable types to WSTR
|
|
//NOTE: The spec requires all supported types to be converted to
|
|
//WSTR, but this only applies where the OLE DB conversion is defined.
|
|
//Some are not defined so we need to bind nativly.
|
|
switch(pColInfo->wType)
|
|
{
|
|
case DBTYPE_IUNKNOWN:
|
|
case DBTYPE_IDISPATCH:
|
|
pColAccess->wType = pColInfo->wType;
|
|
pColAccess->cbMaxLen = sizeof(IUnknown*);
|
|
break;
|
|
|
|
case DBTYPE_HCHAPTER:
|
|
pColAccess->wType = pColInfo->wType;
|
|
pColAccess->cbMaxLen = sizeof(HCHAPTER);
|
|
break;
|
|
|
|
default:
|
|
//DBTYPE_VECTOR
|
|
if(pColInfo->wType & DBTYPE_VECTOR)
|
|
{
|
|
pColAccess->wType = pColInfo->wType;
|
|
pColAccess->cbMaxLen= sizeof(DBVECTOR);
|
|
}
|
|
|
|
//DBTYPE_ARRAY
|
|
if(pColInfo->wType & DBTYPE_ARRAY)
|
|
{
|
|
pColAccess->wType = pColInfo->wType;
|
|
pColAccess->cbMaxLen= sizeof(SAFEARRAY*);
|
|
}
|
|
break;
|
|
};
|
|
|
|
//Offset
|
|
dwOffset += pColAccess->cbMaxLen;
|
|
dwOffset = ROUNDUP( dwOffset );
|
|
|
|
//Build a real simple binding on top of this ColumnAccess struct.
|
|
//The reason is all of our data manipulations routines deal with binding structs, so instead
|
|
//have having numerous code lines, we will just map this to a binding struct...
|
|
pBinding->iOrdinal = pColInfo->iOrdinal;
|
|
pBinding->obStatus = (DBBYTEOFFSET)((BYTE*)&pColAccess->dwStatus - (BYTE*)m_pData);
|
|
pBinding->obLength = (DBBYTEOFFSET)((BYTE*)&pColAccess->cbDataLen - (BYTE*)m_pData);
|
|
pBinding->obValue = (DBBYTEOFFSET)((BYTE*)pColAccess->pData - (BYTE*)m_pData);
|
|
|
|
pBinding->pTypeInfo = NULL;
|
|
pBinding->pObject = NULL;
|
|
pBinding->pBindExt = NULL;
|
|
|
|
pBinding->dwPart = DBPART_LENGTH|DBPART_STATUS;
|
|
if(pColAccess->pData)
|
|
pBinding->dwPart |= DBPART_VALUE;
|
|
|
|
pBinding->dwMemOwner = (dwAccessorOpts & ACCESSOR_OWNED_PROVIDER) ? DBMEMOWNER_PROVIDEROWNED : DBMEMOWNER_CLIENTOWNED;
|
|
pBinding->eParamIO = DBPARAMIO_NOTPARAM;
|
|
|
|
pBinding->cbMaxLen = pColAccess->cbMaxLen;
|
|
pBinding->dwFlags = 0;
|
|
pBinding->wType = pColAccess->wType;
|
|
|
|
pBinding->bPrecision = pColAccess->bPrecision;
|
|
pBinding->bScale = pColAccess->bScale;
|
|
|
|
//Do we real want this column?
|
|
switch(eBindCols)
|
|
{
|
|
case BIND_ALLCOLS:
|
|
m_cColAccess++;
|
|
cBindings++;
|
|
break;
|
|
|
|
case BIND_ALLCOLSEXPECTBOOKMARK:
|
|
if(pColInfo->iOrdinal != 0)
|
|
{
|
|
m_cColAccess++;
|
|
cBindings++;
|
|
}
|
|
break;
|
|
|
|
case BIND_UPDATEABLECOLS:
|
|
if(pColInfo->dwFlags & DBCOLUMNFLAGS_WRITE || pColInfo->dwFlags & DBCOLUMNFLAGS_WRITEUNKNOWN)
|
|
{
|
|
m_cColAccess++;
|
|
cBindings++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Unhandled Type!");
|
|
break;
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
m_Bindings.Attach(cBindings, rgBindings);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// HRESULT CRow::GetColumns
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::GetColumns(ULONG cColAccess, DBCOLUMNACCESS* rgColAccess)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(m_pIRow == NULL)
|
|
return E_FAIL;
|
|
|
|
//GetColumns
|
|
XTEST(hr = m_pIRow->GetColumns(cColAccess, rgColAccess));
|
|
TESTC(TRACE_METHOD(hr, L"IRow::GetColumns(%lu, 0x%p)", cColAccess, rgColAccess));
|
|
|
|
CLEANUP:
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// HRESULT CRow::Open
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::Open(CAggregate* pCAggregate, DBID* pColumnID, REFGUID rguidObjectType, REFIID riid, IUnknown** ppIUnknown)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(m_pIRow == NULL)
|
|
return E_FAIL;
|
|
|
|
//Convert the DBID to a string for display...
|
|
WCHAR wszBuffer[MAX_QUERY_LEN+1] = {0};
|
|
DBIDToString(pColumnID, wszBuffer, MAX_QUERY_LEN);
|
|
|
|
//Open
|
|
XTEST(hr = m_pIRow->Open(pCAggregate, pColumnID, rguidObjectType, 0, riid, ppIUnknown));
|
|
TESTC(TRACE_METHOD(hr, L"IRow::Open(0x%p, %s, %s, 0, %s, &0x%p)", pCAggregate, wszBuffer, GetObjectTypeName(rguidObjectType), GetInterfaceName(riid), ppIUnknown ? *ppIUnknown : NULL));
|
|
|
|
//Handle Aggregation
|
|
if(pCAggregate)
|
|
TESTC(hr = pCAggregate->HandleAggregation(riid, ppIUnknown));
|
|
|
|
CLEANUP:
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// HRESULT CRow::Bind
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
HRESULT CRow::Bind(CAggregate* pCAggregate, WCHAR* pwszURL, DBBINDURLFLAG dwBindFlags, REFGUID rguidObjectType, REFIID riid, IUnknown** ppIUnknown)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DBBINDSTATUS dwBindStatus = 0;
|
|
|
|
if(m_pIBindResource == NULL)
|
|
return E_FAIL;
|
|
|
|
//Open
|
|
XTEST(hr = m_pIBindResource->Bind(pCAggregate, pwszURL, dwBindFlags, rguidObjectType, riid, NULL, NULL, &dwBindStatus, ppIUnknown));
|
|
TESTC(TRACE_METHOD(hr, L"IBindResource::Bind(0x%p, \"%s\", 0x%08x, %s, %s, NULL, NULL, &0x%p, &0x%p)", pCAggregate, pwszURL, dwBindFlags, GetObjectTypeName(rguidObjectType), GetInterfaceName(riid), &dwBindStatus, ppIUnknown ? *ppIUnknown : NULL));
|
|
|
|
//Handle Aggregation
|
|
if(pCAggregate)
|
|
TESTC(hr = pCAggregate->HandleAggregation(riid, ppIUnknown));
|
|
|
|
CLEANUP:
|
|
return hr;
|
|
} //CRow::Bind
|
|
|
|
|
|
|