📄 irowsetchangeimpl.h
字号:
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetData() - hRow = %d\n");
if (!Supports(DBPROPVAL_UP_CHANGE))
{
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetData - Error - DBPROPVAL_UP_CHANGE not supported\n");
return DB_E_NOTSUPPORTED;
}
if (DelayedUpdateMode())
{
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetData - Error - delayed updates not supported\n");
return E_NOTIMPL;
}
if (pSrcData == NULL)
{
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetData - Error - (pSrcData == NULL)\n");
return E_INVALIDARG;
}
return SetDataHelper(hRow, hAccessor, pSrcData, true);
}
template <class T, class Storage, class Base>
HRESULT CRowsetChangeImpl<T, Storage, Base>::SetDataHelper(
HROW hRow,
HACCESSOR hAccessor,
void *pSrcData,
bool bSendNotifications)
{
// This code is based on IRowsetImpl::GetData().
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetDataHelper() - hRow = %d - notifications: %s\n",
hRow,
(bSendNotifications ? "on" : "off"));
T *pT = (T*)this;
T::_HRowClass* pRow = 0;
if (hRow == 0 || (pRow = pT->m_rgRowHandles.Lookup((T::_HRowClass::KeyType)hRow)) == NULL)
{
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetDataHelper - Error - Bad row handle\n");
return DB_E_BADROWHANDLE;
}
T::_BindType* pBinding;
void* pDstData;
ULONG cCols;
ATLCOLUMNINFO* pColInfo;
CComPtr<IDataConvert> spConvert;
HRESULT hr = pT->GetDataHelper(hAccessor, pColInfo, (void**)&pBinding, pDstData, cCols, spConvert, pRow);
if (FAILED(hr))
{
return hr;
}
// convert the pBinding structure into an array of ULONG of column ordinals
ULONG *rgColumns = 0;
CAutoMemRelease<ULONG> crapHelper(rgColumns);
if (bSendNotifications)
{
rgColumns = new ULONG[pBinding->cBindings];
for (size_t i = 0; i < pBinding->cBindings; i++)
{
rgColumns[i] = pBinding->pBindings[i].iOrdinal;
}
if (!SendPreSetDataNotifications(hRow, pBinding->cBindings, rgColumns))
{
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetDataHelper - cancelled\n", pBinding->cBindings);
return DB_E_CANCELED;
}
}
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetDataHelper - Bindings for %d columns\n", pBinding->cBindings);
for (ULONG iBind =0; SUCCEEDED(hr) && iBind < pBinding->cBindings; iBind++)
{
DBBINDING* pBindCur = &(pBinding->pBindings[iBind]);
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetChange::SetDataHelper - Bindings for column ordinal %d\n", pBindCur->iOrdinal);
ATLCOLUMNINFO* pColCur = FindColByOrdinal(pColInfo, cCols, pBindCur->iOrdinal);
if (!pColCur)
{
hr = DB_E_BADORDINAL;
}
else
{
BOOL bProvOwn = (pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED);
DBSTATUS dbStat = pT->GetDBStatus(pRow, pColCur);
// If the data field is NULL, we can optimize this situation,
// set the field to 0 and continue.
if (dbStat == DBSTATUS_S_ISNULL)
{
if (pBindCur->dwPart & DBPART_VALUE)
{
*((ULONG*)((BYTE*)(pDstData) + pColCur->cbOffset)) = 0;
}
}
else
{
// This is broken, we are using the column size or the length of string
// for the size of the incomming data...
ULONG cbDst = pColCur->ulColumnSize;
ULONG cbCol;
BYTE* pSrcTemp;
if (bProvOwn && pColCur->wType == pBindCur->wType)
{
// This looks really broken, but this is how GetData works...
pSrcTemp = ((BYTE*)(pSrcData) + pBindCur->obValue);
}
else
{
BYTE* pDstTemp = (BYTE*)pDstData + pColCur->cbOffset;
switch (pColCur->wType)
{
case DBTYPE_STR:
cbCol = lstrlenA((LPSTR)(((BYTE*)pSrcData) + pBindCur->obValue));
break;
case DBTYPE_WSTR:
case DBTYPE_BSTR:
cbCol = lstrlenW((LPWSTR)(((BYTE*)pSrcData) + pBindCur->obValue)) * sizeof(WCHAR);
break;
default:
cbCol = pColCur->ulColumnSize;
break;
}
if (pBindCur->dwPart & DBPART_VALUE)
{
hr = spConvert->DataConvert(pBindCur->wType, pColCur->wType,
cbCol, &cbDst, (BYTE*)(pSrcData) + pBindCur->obValue,
pDstTemp, pColCur->ulColumnSize, dbStat, &dbStat,
pBindCur->bPrecision, pBindCur->bScale,0);
}
}
}
}
}
if (bSendNotifications)
{
if (SUCCEEDED(hr))
{
SendPostSetDataNotifications(hRow, pBinding->cBindings, rgColumns);
}
else
{
SendFailedSetDataNotifications(hRow, pBinding->cBindings, rgColumns);
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Internal checks to see what functionality to expose
///////////////////////////////////////////////////////////////////////////////
template <class T, class Storage, class Base>
bool CRowsetChangeImpl<T, Storage, Base>::Supports(UINT updateMask)
{
T *pT = (T*)this;
CComQIPtr<IRowsetInfo> spProps = pT->GetUnknown();
CDBPropIDSet set(DBPROPSET_ROWSET);
set.AddPropertyID(DBPROP_UPDATABILITY);
DBPROPSET* pPropSet = NULL;
ULONG ulPropSet = 0;
HRESULT hr;
if (spProps)
{
hr = spProps->GetProperties(1, &set, &ulPropSet, &pPropSet);
}
bool bSupported = false;
if (pPropSet)
{
CComVariant var = pPropSet->rgProperties[0].vValue;
CoTaskMemFree(pPropSet->rgProperties);
CoTaskMemFree(pPropSet);
if (SUCCEEDED(hr) && (var.iVal & updateMask))
{
bSupported = true;
}
}
return bSupported;
}
///////////////////////////////////////////////////////////////////////////////
// Notifications
///////////////////////////////////////////////////////////////////////////////
template <class T, class Storage, class Base>
bool CRowsetChangeImpl<T, Storage, Base>::SendPreRowChangeNotifications(
DBREASON eReason,
ULONG cRows,
const ULONG rgRows[])
{
// If in delayed update and we havent changed the row...
// then send DBREASON_FIRST_CHANGE at all stages as well
HRESULT hr = Fire_OnRowChange(
cRows,
rgRows,
eReason,
DBEVENTPHASE_OKTODO,
false);
if (FAILED(hr))
{
// If we're cancelled then we still need to send the failed to do
// notification...
SendFailedRowChangeNotifications(eReason, cRows, rgRows);
return false;
}
hr = Fire_OnRowChange(
cRows,
rgRows,
eReason,
DBEVENTPHASE_ABOUTTODO,
false);
if (FAILED(hr))
{
// If we're cancelled then we still need to send the failed to do
// notification...
SendFailedRowChangeNotifications(eReason, cRows, rgRows);
return false;
}
return true;
}
template <class T, class Storage, class Base>
void CRowsetChangeImpl<T, Storage, Base>::SendPostRowChangeNotifications(
DBREASON eReason,
ULONG cRows,
const ULONG rgRows[])
{
// If in delayed update and we havent changed the row...
// then send DBREASON_FIRST_CHANGE at all stages as well
Fire_OnRowChange(
cRows,
rgRows,
eReason,
DBEVENTPHASE_SYNCHAFTER,
true);
Fire_OnRowChange(
cRows,
rgRows,
eReason,
DBEVENTPHASE_DIDEVENT,
true);
}
template <class T, class Storage, class Base>
void CRowsetChangeImpl<T, Storage, Base>::SendFailedRowChangeNotifications(
DBREASON eReason,
ULONG cRows,
const ULONG rgRows[])
{
// If in delayed update and we havent changed the row...
// then send DBREASON_FIRST_CHANGE at all stages as well
Fire_OnRowChange(
cRows,
rgRows,
eReason,
DBEVENTPHASE_FAILEDTODO,
true);
}
template <class T, class Storage, class Base>
bool CRowsetChangeImpl<T, Storage, Base>::SendPreSetDataNotifications(
HROW hRow,
ULONG cColumns,
ULONG rgColumns[])
{
// If in delayed update and we havent changed the row...
// then send DBREASON_FIRST_CHANGE at all stages as well
HRESULT hr = Fire_OnFieldChange(
hRow,
cColumns,
rgColumns,
DBREASON_COLUMN_SET,
DBEVENTPHASE_OKTODO,
false);
if (FAILED(hr))
{
// If we're cancelled then we still need to send the failed to do
// notification...
SendFailedSetDataNotifications(hRow, cColumns, rgColumns);
return false;
}
hr = Fire_OnFieldChange(
hRow,
cColumns,
rgColumns,
DBREASON_COLUMN_SET,
DBEVENTPHASE_ABOUTTODO,
false);
if (FAILED(hr))
{
// If we're cancelled then we still need to send the failed to do
// notification...
SendFailedSetDataNotifications(hRow, cColumns, rgColumns);
return false;
}
return true;
}
template <class T, class Storage, class Base>
void CRowsetChangeImpl<T, Storage, Base>::SendPostSetDataNotifications(
HROW hRow,
ULONG cColumns,
ULONG rgColumns[])
{
// If in delayed update and we havent changed the row...
// then send DBREASON_FIRST_CHANGE at all stages as well
Fire_OnFieldChange(
hRow,
cColumns,
rgColumns,
DBREASON_COLUMN_SET,
DBEVENTPHASE_SYNCHAFTER,
true);
Fire_OnFieldChange(
hRow,
cColumns,
rgColumns,
DBREASON_COLUMN_SET,
DBEVENTPHASE_DIDEVENT,
true);
}
template <class T, class Storage, class Base>
void CRowsetChangeImpl<T, Storage, Base>::SendFailedSetDataNotifications(
HROW hRow,
ULONG cColumns,
ULONG rgColumns[])
{
// If in delayed update and we havent changed the row...
// then send DBREASON_FIRST_CHANGE at all stages as well
Fire_OnFieldChange(
hRow,
cColumns,
rgColumns,
DBREASON_COLUMN_SET,
DBEVENTPHASE_FAILEDTODO,
true);
}
template <class T, class Storage, class Base>
ATLCOLUMNINFO *CRowsetChangeImpl<T, Storage, Base>::FindColByOrdinal(
ATLCOLUMNINFO *pColInfo,
ULONG cCols,
UINT iOrdinal)
{
if (cCols == 0 || pColInfo == 0)
{
return 0;
}
ATLCOLUMNINFO *pThisCol = pColInfo;
ULONG iColInfo;
for (iColInfo = 0;
iColInfo < cCols && iOrdinal != pThisCol->iOrdinal;
iColInfo++, pThisCol++)
{
// Empty loop body
}
if (iColInfo == cCols)
{
pThisCol = 0;
}
return pThisCol;
}
#endif // __I_ROWSET_CHANGE_IMPL__INCLUDED__
///////////////////////////////////////////////////////////////////////////////
// End of file...
///////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -