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

📄 icolumnsrowsetimpl.h

📁 The ATL OLE DB Provider templates only seem to support read-only rowsets and making them support upd
💻 H
字号:
#ifndef __I_COLUMNS_ROWSET_IMPL__INCLUDED__
#define __I_COLUMNS_ROWSET_IMPL__INCLUDED__

#include <atlcom.h>
#include <atldb.h>

#define PROVIDER_COLUMN_ENTRY_DBID(name, dbid, ordinal, member) \
{ \
	(LPOLESTR)OLESTR(name), \
	(ITypeInfo*)NULL, \
	(ULONG)ordinal, \
	DBCOLUMNFLAGS_ISFIXEDLENGTH, \
   (ULONG)sizeof(((_Class*)0)->member), \
	_GetOleDBType(((_Class*)0)->member), \
	(BYTE)0, \
	(BYTE)0, \
	{ \
		EXPANDGUID(dbid.uGuid.guid), \
		(DWORD)dbid.eKind, \
      (LPOLESTR)dbid.uName.ulPropid\
	}, \
   offsetof(_Class, member) \
},


class CColumnsRowsetRow
{
public:

	WCHAR    m_DBCOLUMN_IDNAME[129];
	GUID     m_DBCOLUMN_GUID;
   ULONG    m_DBCOLUMN_PROPID;
   WCHAR    m_DBCOLUMN_NAME[129];
   ULONG    m_DBCOLUMN_NUMBER;
   USHORT   m_DBCOLUMN_TYPE;
   IUnknown *m_DBCOLUMN_TYPEINFO;
   ULONG    m_DBCOLUMN_COLUMNSIZE;
   USHORT   m_DBCOLUMN_PRECISION;
   USHORT   m_DBCOLUMN_SCALE;
   ULONG    m_DBCOLUMN_FLAGS;
   WCHAR    m_DBCOLUMN_BASECOLUMNNAME[129];
   WCHAR    m_DBCOLUMN_BASETABLENAME[129];   
   BOOL     m_DBCOLUMN_KEYCOLUMN;
   
	CColumnsRowsetRow()
	{
		ClearMembers();
	}

	void ClearMembers()
	{
      m_DBCOLUMN_IDNAME[0] = NULL;
      m_DBCOLUMN_GUID = GUID_NULL;
      m_DBCOLUMN_PROPID = 0;
      m_DBCOLUMN_NAME[0] = 0;
      m_DBCOLUMN_NUMBER = 0;
      m_DBCOLUMN_TYPE = 0;
      m_DBCOLUMN_TYPEINFO = 0;
      m_DBCOLUMN_COLUMNSIZE = 0;
      m_DBCOLUMN_PRECISION = 0;
      m_DBCOLUMN_SCALE = 0;
      m_DBCOLUMN_FLAGS = 0;
      m_DBCOLUMN_BASECOLUMNNAME[0] = NULL;
      m_DBCOLUMN_BASETABLENAME[0] = NULL;
      m_DBCOLUMN_KEYCOLUMN = FALSE;
   }


BEGIN_PROVIDER_COLUMN_MAP(CColumnsRowsetRow)
	PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_IDNAME", DBCOLUMN_IDNAME, 1, m_DBCOLUMN_IDNAME)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_GUID", DBCOLUMN_GUID, 2, m_DBCOLUMN_GUID)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_PROPID", DBCOLUMN_PROPID, 3, m_DBCOLUMN_PROPID)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_NAME", DBCOLUMN_NAME, 4, m_DBCOLUMN_NAME)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_NUMBER", DBCOLUMN_NUMBER, 5, m_DBCOLUMN_NUMBER)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_TYPE", DBCOLUMN_TYPE, 6, m_DBCOLUMN_TYPE)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_TYPEINFO", DBCOLUMN_TYPEINFO, 7, m_DBCOLUMN_TYPEINFO)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_COLUMNSIZE", DBCOLUMN_COLUMNSIZE, 8, m_DBCOLUMN_COLUMNSIZE)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_PRECISION", DBCOLUMN_PRECISION, 9, m_DBCOLUMN_PRECISION)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_SCALE", DBCOLUMN_SCALE, 10, m_DBCOLUMN_SCALE)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_FLAGS", DBCOLUMN_FLAGS, 11, m_DBCOLUMN_FLAGS)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_BASECOLUMNNAME", DBCOLUMN_BASECOLUMNNAME, 12, m_DBCOLUMN_BASECOLUMNNAME)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_BASETABLENAME", DBCOLUMN_BASETABLENAME, 13, m_DBCOLUMN_BASETABLENAME)
   PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_KEYCOLUMN", DBCOLUMN_KEYCOLUMN, 14, m_DBCOLUMN_KEYCOLUMN)
END_PROVIDER_COLUMN_MAP()
};


template <class T, class CreatorClass>
class ATL_NO_VTABLE IColumnsRowsetImpl : public IColumnsRowset
{
   public:

      class CColumnsRowsetRowset : 
	   public CRowsetImpl< CColumnsRowsetRowset , CColumnsRowsetRow, CreatorClass>
      {
         public:

            HRESULT PopulateRowset(ULONG numCols, DBCOLUMNINFO *pColInfo)
            {
               for (ULONG i = 0 ; i < numCols; i++)
               {
                  // copy data out of the pColInfo struct and into the 
                  // rowset array 

                  CColumnsRowsetRow data;

                  // Should select the name correctly, rather than just assuming we'll use the name and
                  // not the guid and propid..

                  lstrcpynW(data.m_DBCOLUMN_IDNAME, pColInfo[i].pwszName , sizeof(data.m_DBCOLUMN_IDNAME));
	               data.m_DBCOLUMN_GUID = GUID_NULL;
                  data.m_DBCOLUMN_PROPID = 0;
                  
                  lstrcpynW(data.m_DBCOLUMN_NAME, pColInfo[i].pwszName , sizeof(data.m_DBCOLUMN_NAME));
                  data.m_DBCOLUMN_NUMBER = pColInfo[i].iOrdinal;
                  data.m_DBCOLUMN_TYPE = pColInfo[i].wType;
                  data.m_DBCOLUMN_TYPEINFO = pColInfo[i].pTypeInfo;
                  data.m_DBCOLUMN_COLUMNSIZE = pColInfo[i].ulColumnSize;
                  data.m_DBCOLUMN_PRECISION = pColInfo[i].bPrecision;
                  data.m_DBCOLUMN_SCALE = pColInfo[i].bScale;
                  data.m_DBCOLUMN_FLAGS = pColInfo[i].dwFlags;
                  lstrcpynW(data.m_DBCOLUMN_BASECOLUMNNAME, pColInfo[i].pwszName, sizeof(data.m_DBCOLUMN_BASECOLUMNNAME));
                  lstrcpynW(data.m_DBCOLUMN_BASETABLENAME, L"Table", sizeof(data.m_DBCOLUMN_BASETABLENAME));
                  data.m_DBCOLUMN_KEYCOLUMN = (pColInfo[i].iOrdinal == 0) || (pColInfo[i].dwFlags & DBCOLUMNFLAGS_ISROWID);

                  // Base the keycolumn decision on the flags too?
                  // Keycolumn is only used if the column has been displayed :( Pity as this renders the bookmarks
                  // useless..


                  if (!m_rgRowData.Add(data))
                  {
			            return E_OUTOFMEMORY;
                  }
               }

               return S_OK;
            }
      };

      STDMETHOD(GetAvailableColumns)(
         ULONG *pcOptColumns,
         DBID **prgOptColumns)
      {
		   ATLTRACE2(atlTraceDBProvider, 0, "IColumnsRowsetImpl::GetAvailableColumns()\n");

         if (!pcOptColumns || !prgOptColumns)
         {
            return E_INVALIDARG;
         }

         const ULONG c_numOptColumns = 3;

         *pcOptColumns = c_numOptColumns;

         DBID *pOptCols = (DBID*)CoTaskMemAlloc(sizeof(DBID) * c_numOptColumns);

         memset(pOptCols, 0, sizeof(DBID) * c_numOptColumns);

         pOptCols[0] = DBCOLUMN_BASETABLENAME;
         pOptCols[1] =  DBCOLUMN_BASECOLUMNNAME;
         pOptCols[2] =  DBCOLUMN_KEYCOLUMN;
      
         *pcOptColumns = c_numOptColumns;
         *prgOptColumns = pOptCols;

         return S_OK;
      }

      STDMETHOD(GetColumnsRowset)(
         IUnknown *pUnkOuter,
         ULONG cOptColumns,
         const DBID rgOptColumns[],
         REFIID riid,
         ULONG cPropertySets,
         DBPROPSET rgPropertySets[],
         IUnknown **ppColRowset)
      {
		   ATLTRACE2(atlTraceDBProvider, 0, "IColumnsRowsetImpl::GetColumnsRowset()\n");

         // need to create our columns rowset, 
         // then populate it from the actual rowset that we represent...
      
         // We can do that by using IColumnsInfo...

         CColumnsRowsetRowset *pColRowset = 0;

         HRESULT hr = CreateRowset(
            pUnkOuter, 
            riid, 
            cPropertySets, 
            rgPropertySets,
            pColRowset,
            ppColRowset);

         if (SUCCEEDED(hr))
         {
            if (pColRowset)
            {
               T *pT = (T*)this;

               CComQIPtr<IColumnsInfo> spColumnsInfo = pT->GetUnknown();

               if (spColumnsInfo)
               {
                  ULONG numCols = 0;
                  DBCOLUMNINFO *pColInfo = 0;
                  OLECHAR *pNotUsed = 0;

                  hr = spColumnsInfo->GetColumnInfo(&numCols, &pColInfo, &pNotUsed);

                  if (pNotUsed)
                  {
                     CoTaskMemFree(pNotUsed);
                  }

                  if (SUCCEEDED(hr))
                  {
                     hr = pColRowset->PopulateRowset(numCols, pColInfo);
                  }

                  CoTaskMemFree(pColInfo);
               }
            }
            else
            {
               hr = E_UNEXPECTED;
            }
         }
      
         return hr;
      }

   private :

      HRESULT CreateRowset(
         IUnknown * pUnkOuter,	
	      REFIID riid,				
         ULONG cPropertySets,
         DBPROPSET rgPropertySets[],
         CColumnsRowsetRowset *&pRowsetObj,
	      IUnknown **ppRowset)
      {
	      HRESULT hr;

         T* pT = (T*)this;

	      if (ppRowset != NULL)
         {
		      *ppRowset = NULL;
         }

	      if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
         {
		      return DB_E_NOAGGREGATION;
         }

	      CComPolyObject<CColumnsRowsetRowset>* pPolyObj;
	      
         if (FAILED(hr = CComPolyObject<CColumnsRowsetRowset>::CreateInstance(pUnkOuter, &pPolyObj)))
         {
		      return hr;
         }
	      
         // Ref the created COM object and Auto release it on failure
	      
         CComPtr<IUnknown> spUnk;
	      
         hr = pPolyObj->QueryInterface(&spUnk);
	      
         if (FAILED(hr))
	      {
		      delete pPolyObj; // must hand delete as it is not ref'd
		      return hr;
	      }
	      
         // Get a pointer to the Rowset instance
	      pRowsetObj = &(pPolyObj->m_contained);

	      if (FAILED(hr = pRowsetObj->FInit(pT)))
         {
		      return hr;
         }

         // Set Properties that were passed in.

         const GUID* ppGuid[1];
         ppGuid[0] = &DBPROPSET_ROWSET;

         // Call SetProperties.  The true in the last parameter indicates
         // the special behavior that takes place on rowset creation (i.e.
         // it succeeds as long as any of the properties were not marked
         // as DBPROPS_REQUIRED.

         hr = pRowsetObj->SetProperties(0, cPropertySets, rgPropertySets, 1, ppGuid, true);

         if (FAILED(hr))
         {
            return hr;
         }

	      pRowsetObj->SetSite(pT->GetUnknown());

	      if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
	      {
		      if (ppRowset != NULL)
			      *ppRowset = NULL;
		      return hr;
	      }

		   if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
		   {
			   if (ppRowset != NULL)
				   *ppRowset = NULL;
			   return hr;
		   }
		   hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
		   if (FAILED(hr))
			   return hr;
		   for (int iBind = 0; iBind < pT->m_rgBindings.GetSize(); iBind++)
		   {
			   T::_BindType* pBind = NULL;
			   T::_BindType* pBindSrc = NULL;
			   ATLTRY(pBind = new T::_BindType);
			   if (pBind == NULL)
			   {
				   ATLTRACE2(atlTraceDBProvider, 0, "Failed to allocate memory for new Binding\n");
				   return E_OUTOFMEMORY;
			   }
			   // auto cleanup on failure
			   CAutoMemRelease<T::_BindType> amr(pBind);
			   pBindSrc = pT->m_rgBindings.GetValueAt(iBind);
			   if (pBindSrc == NULL)
			   {
				   ATLTRACE2(atlTraceDBProvider, 0, "The map appears to be corrupted, failing!!\n");
				   return E_FAIL;
			   }
			   if (!pRowsetObj->m_rgBindings.Add(pT->m_rgBindings.GetKeyAt(iBind), pBind))
			   {
				   ATLTRACE2(atlTraceDBProvider, 0, "Failed to add hAccessor to Map\n");
				   return E_OUTOFMEMORY;
			   }
			   if (pBindSrc->cBindings)
			   {
				   ATLTRY(pBind->pBindings = new DBBINDING[pBindSrc->cBindings])
				   if (pBind->pBindings == NULL)
				   {
					   ATLTRACE2(atlTraceDBProvider, 0, "Failed to Allocate dbbinding Array\n");
					   // We added it, must now remove on failure
					   pRowsetObj->m_rgBindings.Remove(pT->m_rgBindings.GetKeyAt(iBind));
					   return E_OUTOFMEMORY;
				   }
			   }
			   else
			   {
				   pBind->pBindings = NULL; // NULL Accessor
			   }

			   pBind->dwAccessorFlags = pBindSrc->dwAccessorFlags;
			   pBind->cBindings = pBindSrc->cBindings;
			   pBind->dwRef = 1;
			   memcpy (pBind->pBindings, pBindSrc->pBindings, (pBindSrc->cBindings)*sizeof(DBBINDING));
			   pBind = amr.Detach();
		   }

	      return hr;
      }

};

#endif // __I_COLUMNS_ROWSET_IMPL__INCLUDED__

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -