⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irowsetchangeimpl.h

📁 The ATL OLE DB Provider templates only seem to support read-only rowsets and making them support upd
💻 H
📖 第 1 页 / 共 2 页
字号:
   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 + -