Aracılığıyla paylaş


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

Bu konudaki örnek, IRowsetLocate arabirimini CMyProviderRowset sınıfına ekler. Neredeyse bütün durumlarda var olan COM nesnesine bir arabirim ekleyerek başlarsınız. Sonra da tüketici şablonlarından çağrılar ekleyerek test edebilirsiniz. Örnek, aşağıdakilerin nasıl yapılacağını gösterir:

  • Sağlayıcıya arabirim eklemek.

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

  • Yer işareti desteği eklemek.

Arabirim IRowsetLocate, IRowset arabiriminden devralır. IRowsetLocate arabirimini eklemek için, IRowsetLocateImpl'den CMyProviderRowset devralınmalıdır.

IRowsetLocate arabirimini eklemek diğer bir çok arabirimi eklemekten biraz farklıdır. VTABLE'ları sıralayabilmek için, OLE DB sağlayıcı şablonlarının türetilmiş arabirimleri işleyen şablon parametresi vardır. Aşağıdaki kod yeni devralım listesini gösterir:

////////////////////////////////////////////////////////////////////////
// MyProviderRS.h

// CMyProviderRowset
class CMyProviderRowset : public CRowsetImpl< CMyProviderRowset, 
      CTextData, CMyProviderCommand, CAtlArray<CTextData>, 
      CSimpleRow, 
          IRowsetLocateImpl<CMyProviderRowset, IRowsetLocate> >

Dördüncü, beşinci ve altıncı parametrelerin hepsi eklenmiştir. Bu örnek dördüncü ve beşinci parametreler için varsayılanları kullanırken, altıncı parametre olarak IRowsetLocateImpl'yi belirtir. IRowsetLocateImpl, iki şablon parametresi alan OLE DB şablon sınıfıdır: bunlar IRowsetLocate arabirimini CMyProviderRowset sınıfına bağlar. Çoğu arabirim için bu adımı atlayıp sıradaki adıma geçebilirsiniz. Sadece IRowsetLocate ve IRowsetScroll arabirimleri bu şekilde işlenmelidir.

Daha sonra IRowsetLocate arabirimi için, CMyProviderRowset'e QueryInterface'i çağırmasını söylemeniz gerekir. Eşlemeye COM_INTERFACE_ENTRY(IRowsetLocate) satırını ekleyin. CMyProviderRowset için arabirim eşlemesi, aşağıdaki kod görüldüğü gibi olmalıdır:

////////////////////////////////////////////////////////////////////////
// MyProviderRS.h

typedef CRowsetImpl< CMyProviderRowset, CTextData, CMyProviderCommand, CAtlArray<CTextData>, CSimpleRow, IRowsetLocateImpl<CMyProviderRowset, IRowsetLocate> > _RowsetBaseClass;

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

Ayrıca eşlemenizi CRowsetImpl sınıfına bağlamanız gereklidir. CRowsetImpl eşlemesini bağlamak için COM_INTERFACE_ENTRY_CHAIN makrosuna ekleyin. Ayrıca, devralım bilgisinden oluşan RowsetBaseClass adlı bir typedef oluşturun. Bu typedef isteğe bağlıdır ve ihmal edilebilir.

Son olarak, IColumnsInfo::GetColumnsInfo çağrısını işleyin. Bunu yapmak için normalde PROVIDER_COLUMN_ENTRY makrosunu kullanırsınız. Ancak tüketici yer işaretlerini kullanmak isteyebilir. Tüketicinin yer işareti isteyip istemediğine göre sağlayıcının döndürdüğü sütunları değiştirebilmeniz gerekir.

IColumnsInfo::GetColumnsInfo çağrısını işlemek için, CTextData sınıfındaki PROVIDER_COLUMN eşlemesini siliniz. PROVIDER_COLUMN_MAP makrosu GetColumnInfo işlevini tanımlar. Kendi GetColumnInfo işlevinizi tanımlamanız gerekir. İşlev bildirimi şöyle görünmelidir:

////////////////////////////////////////////////////////////////////////
// MyProviderRS.H

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

Daha sonra MyProviderRS.cpp dosyasındaki GetColumnInfo işlevi aşağıdaki gibi gerçekleştirin:

////////////////////////////////////////////////////////////////////
// MyProviderRS.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(CMyProviderCommand* pThis, 
     ULONG* pcCols)
{
   return CommonGetColInfo<ICommandProperties>(pThis->GetUnknown(),
        pcCols);
}


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

GetColumnInfo öncelikle DBPROP_IRowsetLocate denen özelliğini ayarlanıp ayarlanmadığını denetler. OLE DB'nin satır kümesi nesnelerinden başka her isteğe bağlı arabirim için özellikleri vardır. Tüketici bu isteğe bağlı arabirimlerden birini kullanmak isterse, bir özelliği doğru olarak ayarlar. Daha sonra sağlayıcı bu özelliği denetleyerek, buna göre bir eylem belirler.

Kendi uygulamalarınızda, komut nesnesine olan işaretçiyi kullanarak özelliği alabilirsiniz. pThis işaretçisi satır kümesini veya komut sınıfını gösterir. Burada şablon kullandığınızdan dolayı, bunu void işaretçisi olarak geçmelisiniz yoksa kod derlenmez.

Sütun bilgisini saklamak için statik bir dizi belirtin. Tüketici yer işareti sütunu istemezse, dizideki bir girdi boşa harcanmış olur. Bu diziyi dinamik olarak ayırabilirsiniz fakat uygun şekilde yok edildiğinden emin olmalısınız. Bu örnek diziye bilgi eklemek için ADD_COLUMN_ENTRY ve ADD_COLUMN_ENTRY_EX makrolarını tanımlar ve kullanır. Aşağıdaki kodda görüldüğü gibi makroları MyProviderRS.H dosyasına ekleyebilirsiniz:

////////////////////////////////////////////////////////////////////////
// MyProviderRS.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, OnRun işleyicisinde birkaç değişiklik yapmalısınız. İşlevdeki yapacağınız ilk değişiklik, özellik kümesine bir özellik ilave etmek için kod eklemek olacaktır. Kod DBPROP_IRowsetLocate özelliğini doğruya ayarlar, böylece sağlayıcıya yer işareti sütununu istediğinizi söyler. OnRun işleyici 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("MyProvider.MyProvider.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);
}

While döngüsü IRowsetLocate arabirimindeki Compare yöntemi çağıran kodu tutar. Kodunuz her zaman geçmelidir, çünkü birebir aynı yer işaretlerini kıyaslıyorsunuz. Ayrıca, while döngüsü bittikten sonra tüketici şablonlarındaki MoveToBookmark işlevini çağırabilmek için geçici değişkende bir yer işareti saklayın. MoveToBookmark işlevi, IRowsetLocate'taki GetRowsAt yöntemi çağırır.

Ayrıca tüketicideki kullanıcı kayıtlarını da güncelleştirmeniz gerekir. Yer işaretini işlemek için sınıfa bir girdi ekleyin ve bir girdi de COLUMN_MAP'e 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üncellediğinizde, IRowsetLocate arabirimiyle sağlayıcıyı oluşturup yürütebilmeniz gerekir.

Ayrıca bkz.

Kavramlar

Gelişmiş Sağlayıcı Teknikleri