Aracılığıyla paylaş


Yer İşaretleri Sağlayıcı Desteği

Bu konudaki örnek, arabirimini sınıfına CCustomRowset eklerIRowsetLocate. Hemen hemen her durumda, var olan bir COM nesnesine arabirim ekleyerek başlarsınız. Daha sonra tüketici şablonlarından daha fazla çağrı ekleyerek test edebilirsiniz. Örnekte aşağıdakilerin nasıl yapılacağını gösterilmektedir:

  • Sağlayıcıya arabirim ekleyin.

  • Tüketiciye döndürülecek sütunları dinamik olarak belirleyin.

  • Yer işareti desteği ekleyin.

Arabirim IRowsetLocate , arabirimden devralır IRowset . Arabirimi eklemek IRowsetLocate için IRowsetLocateImpl'den devralınCCustomRowset.

Arabirimi eklemek IRowsetLocate çoğu arabirimden biraz farklıdır. VTABLEs'in sıralı olmasını sağlamak için, OLE DB sağlayıcı şablonlarının türetilmiş arabirimi işlemek için bir şablon parametresi vardır. Aşağıdaki kod yeni devralma listesini gösterir:

////////////////////////////////////////////////////////////////////////
// CustomRS.h

// CCustomRowset
class CCustomRowset : public CRowsetImpl< CCustomRowset,
      CTextData, CCustomCommand, CAtlArray<CTextData>,
      CSimpleRow,
          IRowsetLocateImpl<CCustomRowset, IRowsetLocate>>

Dördüncü, beşinci ve altıncı parametrelerin tümü eklenir. Bu örnekte dördüncü ve beşinci parametreler için varsayılan değerler kullanılır ancak altıncı parametre olarak belirtilir IRowsetLocateImpl . IRowsetLocateImpl, iki şablon parametresi alan bir OLE DB şablon sınıfıdır: bunlar arabirimi sınıfa CCustomRowset bağlarIRowsetLocate. Çoğu arabirimi eklemek için bu adımı atlayabilir ve sonraki adıma geçebilirsiniz. IRowsetLocate Yalnızca ve IRowsetScroll arabirimlerinin bu şekilde işlenmesi gerekir.

Ardından arabirimini çağırmasını CCustomRowset QueryInterface IRowsetLocate bildirmeniz gerekir. Çizgiyi COM_INTERFACE_ENTRY(IRowsetLocate) haritaya ekleyin. için arabirim eşlemesi CCustomRowset aşağıdaki kodda gösterildiği gibi görünmelidir:

////////////////////////////////////////////////////////////////////////
// CustomRS.h

typedef CRowsetImpl< CCustomRowset, CTextData, CCustomCommand, CAtlArray<CTextData>, CSimpleRow, IRowsetLocateImpl<CCustomRowset, IRowsetLocate>> _RowsetBaseClass;

BEGIN_COM_MAP(CCustomRowset)
   COM_INTERFACE_ENTRY(IRowsetLocate)
   COM_INTERFACE_ENTRY_CHAIN(_RowsetBaseClass)
END_COM_MAP()

Ayrıca haritanızı sınıfa bağlamanız CRowsetImpl gerekir. Haritaya bağlanmak için COM_INTERFACE_ENTRY_CHAIN makroyu CRowsetImpl ekleyin. Ayrıca, devralma bilgilerinden oluşan adlı RowsetBaseClass bir tür tanımı oluşturun. Bu tür tanımı rastgeledir ve yoksayılabilir.

Son olarak, aramayı halledin IColumnsInfo::GetColumnsInfo . Bunu yapmak için normalde PROVIDER_COLUMN_ENTRY makrolarını kullanırsınız. Ancak, bir tüketici yer işaretlerini kullanmak isteyebilir. Sağlayıcının döndürdüğü sütunları, tüketicinin yer işareti isteyip istemediğine bağlı olarak değiştirebilmeniz gerekir.

Çağrıyı IColumnsInfo::GetColumnsInfo işlemek için sınıfındaki PROVIDER_COLUMN eşlemesini CTextData silin. PROVIDER_COLUMN_MAP makro bir işlevi GetColumnInfotanımlar. Kendi GetColumnInfo işlevinizi tanımlayın. İşlev bildirimi şöyle görünmelidir:

////////////////////////////////////////////////////////////////////////
// CustomRS.H

class CTextData
{
   ...
     // NOTE: Be sure you removed the PROVIDER_COLUMN_MAP!
   static ATLCOLUMNINFO* GetColumnInfo(CCustomRowset* pThis,
        ULONG* pcCols);
   static ATLCOLUMNINFO* GetColumnInfo(CCustomCommand* pThis,
        ULONG* pcCols);
...
};

Ardından özel RS.cpp dosyasında işlevini aşağıdaki gibi uygulayınGetColumnInfo:

////////////////////////////////////////////////////////////////////
// CustomRS.cpp

template <class TInterface>
ATLCOLUMNINFO* CommonGetColInfo(IUnknown* pPropsUnk, ULONG* pcCols)
{
   static ATLCOLUMNINFO _rgColumns[5];
   ULONG ulCols = 0;

   CComQIPtr<TInterface> spProps = pPropsUnk;

   CDBPropIDSet set(DBPROPSET_ROWSET);
   set.AddPropertyID(DBPROP_BOOKMARKS);
   DBPROPSET* pPropSet = NULL;
   ULONG ulPropSet = 0;
   HRESULT hr;

   if (spProps)
      hr = spProps->GetProperties(1, &set, &ulPropSet, &pPropSet);

   // Check the property flag for bookmarks, if it is set, set the
// zero ordinal entry in the column map with the bookmark
// information.

   if (pPropSet)
   {
      CComVariant var = pPropSet->rgProperties[0].vValue;
      CoTaskMemFree(pPropSet->rgProperties);
      CoTaskMemFree(pPropSet);

      if ((SUCCEEDED(hr) && (var.boolVal == VARIANT_TRUE)))
      {
         ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Bookmark"), 0,
                     sizeof(DWORD), DBTYPE_BYTES,
            0, 0, GUID_NULL, CAgentMan, dwBookmark,
                        DBCOLUMNFLAGS_ISBOOKMARK)
         ulCols++;
      }
   }

   // Next set the other columns up.
   ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Field1"), 1, 16, DBTYPE_STR,
          0xFF, 0xFF, GUID_NULL, CTextData, szField1)
   ulCols++;
   ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Field2"), 2, 16, DBTYPE_STR,
       0xFF, 0xFF, GUID_NULL, CTextData, szField2)
   ulCols++;

   if (pcCols != NULL)
      *pcCols = ulCols;

   return _rgColumns;
}

ATLCOLUMNINFO* CTextData::GetColumnInfo(CCustomCommand* pThis,
     ULONG* pcCols)
{
   return CommonGetColInfo<ICommandProperties>(pThis->GetUnknown(),
        pcCols);
}

ATLCOLUMNINFO* CAgentMan::GetColumnInfo(RUpdateRowset* pThis, ULONG* pcCols)
{
   return CommonGetColInfo<IRowsetInfo>(pThis->GetUnknown(), pcCols);
}

GetColumnInfo önce adlı DBPROP_IRowsetLocate özelliğin ayarlanıp ayarlanmadığını denetler. OLE DB, satır kümesi nesnesi dışında isteğe bağlı arabirimlerin her biri için özelliklere sahiptir. Tüketici bu isteğe bağlı arabirimlerden birini kullanmak istiyorsa, bir özelliği true olarak ayarlar. Sağlayıcı daha sonra bu özelliği denetleyebilir ve buna göre özel işlem yapabilir.

Uygulamanızda, komut nesnesinin işaretçisini kullanarak özelliğini alırsınız. İşaretçi pThis satır kümesini veya komut sınıfını temsil eder. Burada şablonları kullandığınızdan, bunu işaretçi void olarak geçirmeniz gerekir, aksi durumda kod derlenemez.

Sütun bilgilerini tutmak için statik bir dizi belirtin. Tüketici yer işareti sütununu istemiyorsa dizideki bir girdi boşa harcanmış olur. Bu diziyi dinamik olarak ayırabilirsiniz, ancak doğru şekilde yok etmek için emin olmanız gerekir. Bu örnek, bilgileri diziye eklemek için ADD_COLUMN_ENTRY ve ADD_COLUMN_ENTRY_EX makroları tanımlar ve kullanır. Makroları ÖzelRS'ye ekleyebilirsiniz. Aşağıdaki kodda gösterildiği gibi H dosyası:

////////////////////////////////////////////////////////////////////////
// CustomRS.h

#define ADD_COLUMN_ENTRY(ulCols, name, ordinal, colSize, type, precision, scale, guid, dataClass, member) \
   _rgColumns[ulCols].pwszName = (LPOLESTR)name; \
   _rgColumns[ulCols].pTypeInfo = (ITypeInfo*)NULL; \
   _rgColumns[ulCols].iOrdinal = (ULONG)ordinal; \
   _rgColumns[ulCols].dwFlags = 0; \
   _rgColumns[ulCols].ulColumnSize = (ULONG)colSize; \
   _rgColumns[ulCols].wType = (DBTYPE)type; \
   _rgColumns[ulCols].bPrecision = (BYTE)precision; \
   _rgColumns[ulCols].bScale = (BYTE)scale; \
   _rgColumns[ulCols].cbOffset = offsetof(dataClass, member);

#define ADD_COLUMN_ENTRY_EX(ulCols, name, ordinal, colSize, type, precision, scale, guid, dataClass, member, flags) \
   _rgColumns[ulCols].pwszName = (LPOLESTR)name; \
   _rgColumns[ulCols].pTypeInfo = (ITypeInfo*)NULL; \
   _rgColumns[ulCols].iOrdinal = (ULONG)ordinal; \
   _rgColumns[ulCols].dwFlags = flags; \
   _rgColumns[ulCols].ulColumnSize = (ULONG)colSize; \
   _rgColumns[ulCols].wType = (DBTYPE)type; \
   _rgColumns[ulCols].bPrecision = (BYTE)precision; \
   _rgColumns[ulCols].bScale = (BYTE)scale; \
   _rgColumns[ulCols].cbOffset = offsetof(dataClass, member); \
   memset(&(_rgColumns[ulCols].columnid), 0, sizeof(DBID)); \
   _rgColumns[ulCols].columnid.uName.pwszName = (LPOLESTR)name;

Tüketicideki kodu test etmek için işleyicide birkaç değişiklik OnRun yapmanız gerekir. İşlevde yapılan ilk değişiklik, özellik kümesine özellik eklemek için kod eklemenizdir. Kod özelliği true olarak ayarlar DBPROP_IRowsetLocate , böylece sağlayıcıya yer işareti sütununu istediğinizi söyler. İşleyici OnRun kodu aşağıdaki gibi görünmelidir:

//////////////////////////////////////////////////////////////////////
// TestProv Consumer Application in TestProvDlg.cpp

void CTestProvDlg::OnRun()
{
   CCommand<CAccessor<CProvider>> table;
   CDataSource source;
   CSession   session;

   if (source.Open("Custom.Custom.1", NULL, NULL, NULL,
          NULL) != S_OK)
      return;

   if (session.Open(source) != S_OK)
      return;

   CDBPropSet propset(DBPROPSET_ROWSET);
   propset.AddProperty(DBPROP_IRowsetLocate, true);
   if (table.Open(session, _T("c:\\public\\testprf2\\myData.txt"),
          &propset) != S_OK)
      return;

   CBookmark<4> tempBookmark;
   ULONG ulCount=0;
   while (table.MoveNext() == S_OK)
   {

      DBCOMPARE compare;
      if (ulCount == 2)
         tempBookmark = table.bookmark;

HRESULT hr = table.Compare(table.dwBookmark, table.dwBookmark,
                 &compare);
      if (FAILED(hr))
         ATLTRACE(_T("Compare failed: 0x%X\n"), hr);
      else
         _ASSERTE(compare == DBCOMPARE_EQ);

      m_ctlString1.AddString(table.szField1);
      m_ctlString2.AddString(table.szField2);
      ulCount++;
   }

   table.MoveToBookmark(tempBookmark);
   m_ctlString1.AddString(table.szField1);
   m_ctlString2.AddString(table.szField2);
}

döngü, while arabiriminde IRowsetLocate yöntemini çağırmak Compare için kod içerir. Tam olarak aynı yer işaretlerini karşılaştırdığınız için sahip olduğunuz kodun her zaman geçmesi gerekir. Ayrıca, döngü bittikten sonra while tüketici şablonlarındaki işlevi çağırmak MoveToBookmark için kullanabileceğiniz geçici bir değişkende bir yer işareti depolayın. MoveToBookmark işlevi içinde GetRowsAt IRowsetLocateyöntemini çağırır.

Tüketicideki kullanıcı kaydını da güncelleştirmeniz gerekir. Bir yer işaretini ve COLUMN_MAP bir girişi işlemek için sınıfına bir giriş ekleyin:

///////////////////////////////////////////////////////////////////////
// TestProvDlg.cpp

class CProvider
{
// Attributes
public:
   CBookmark<4>    bookmark;  // Add this line
   char   szCommand[16];
   char   szText[256];

   // Binding Maps
BEGIN_ACCESSOR_MAP(CProvider, 1)
   BEGIN_ACCESSOR(0, true)   // auto accessor
      BOOKMARK_ENTRY(bookmark)  // Add this line
      COLUMN_ENTRY(1, szField1)
      COLUMN_ENTRY(2, szField2)
   END_ACCESSOR()
END_ACCESSOR_MAP()
};

Kodu güncelleştirdiğinizde, sağlayıcıyı arabirimiyle IRowsetLocate derleyip yürütebilmeniz gerekir.

Ayrıca bkz.

Gelişmiş Sağlayıcı Teknikleri