Udostępnij za pośrednictwem


Obsługa dostawcy zakładki

W przykładzie tego tematu dodaje IRowsetLocate interfejsu do CMyProviderRowset klasy.Prawie we wszystkich przypadkach należy rozpocząć od Dodawanie interfejsu do istniejącego obiektu COM.Można następnie przetestuj je, dodając więcej połączeń z szablonów konsumenta.W przykładzie pokazano, jak:

  • Dodawanie interfejsu do dostawcy.

  • Dynamiczne określenie kolumn, aby powrócić do konsumenta.

  • Dodawanie obsługi zakładki.

IRowsetLocate Interfejsu dziedziczy z IRowset interfejsu.Aby dodać IRowsetLocate interfejsu, dziedziczą CMyProviderRowset z IRowsetLocateImpl.

Dodawanie IRowsetLocate interfejsu nieco różni się od większości interfejsów.Aby wiersz tablic metod wirtualnych w górę OLE DB dostawca szablony mają parametr szablonu do obsługi interfejsu pochodnego.Poniższy kod przedstawia nową listę dziedziczenia:

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

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

Czwartego, piątego i szóstego parametry wszystkie dodane.W tym przykładzie użyto ustawień domyślnych w czwartym i piątym parametry określają, ale IRowsetLocateImpl jako parametr szóstego.IRowsetLocateImplKlasa szablonu OLE DB, który przyjmuje dwa parametry szablonu: te spięcie IRowsetLocate interfejsu do CMyProviderRowset klasy.Aby dodać większość interfejsów, można pominąć ten krok i przejść do następnego.Tylko IRowsetLocate i IRowsetScroll interfejsy muszą być traktowane w ten sposób.

Następnie musisz powiedzieć CMyProviderRowset do wywołania QueryInterface do IRowsetLocate interfejsu.Dodawanie linii COM_INTERFACE_ENTRY(IRowsetLocate) do mapy.Mapa interfejsu dla CMyProviderRowset powinien pojawić się, jak pokazano w poniższym kodzie:

////////////////////////////////////////////////////////////////////////
// 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()

Trzeba także hook mapę do CRowsetImpl klasy.Dodaj w makrze hook w COM_INTERFACE_ENTRY_CHAIN CRowsetImpl mapy.Ponadto utworzyć element typedef, nazywane RowsetBaseClass zawiera informacje o dziedziczeniu.Ten element typedef jest arbitralny i można zignorować.

Wreszcie, obsługi IColumnsInfo::GetColumnsInfo wywołania.W tym celu byłyby normalnie używane makra PROVIDER_COLUMN_ENTRY.Jednakże konsument może zaistnieć potrzeba użycia zakładki.Musi być w stanie zmienić kolumny, które dostawca zwraca się w zależności od tego, czy konsument zwraca się do zakładki.

Do obsługi IColumnsInfo::GetColumnsInfo call, usuwanie PROVIDER_COLUMN mapę w CTextData klasy.Makro PROVIDER_COLUMN_MAP definiuje funkcję GetColumnInfo.Należy zdefiniować własne GetColumnInfo funkcji.Deklaracja funkcji powinna wyglądać następująco:

////////////////////////////////////////////////////////////////////////
// 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);
...
};

Następnie należy zaimplementować GetColumnInfo działają w pliku MyProviderRS.cpp w następujący sposób:

////////////////////////////////////////////////////////////////////
// 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);
}

GetColumnInfoSprawdza pierwszy, czy właściwość o nazwie DBPROP_IRowsetLocate jest ustawiona.OLE DB ma właściwości dla każdego z opcjonalnych interfejsów wyłączyć obiekt zestawu wierszy.Jeśli konsument chce skorzystać z jednej z tych interfejsów opcjonalne, ustawia właściwość na wartość true.Dostawcę można sprawdzić tę właściwość i podejmowania działań specjalnych na jej podstawie.

W implementacji pobrać właściwości za pomocą wskaźnika do obiektu command.pThis Wskaźnik reprezentuje klasę wierszy lub polecenia.Tutaj użyć szablonów, należy przejść, to jako void nie opracowują wskaźnik lub kod.

Określanie statycznego array zawiera informacje o kolumnie.Jeśli konsument nie kolumnę zakładki, marnuje się wpis w tablicy.Można dynamicznie przydzielić tej tablicy, ale trzeba upewnić się, zniszczyć ją poprawnie.W tym przykładzie definiuje i używa makra, ADD_COLUMN_ENTRY i ADD_COLUMN_ENTRY_EX, aby wstawić informacje do tablicy.Makra można dodać do pliku MyProviderRS.H, jak pokazano w poniższym kodzie:

////////////////////////////////////////////////////////////////////////
// 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;

Aby przetestować kod w konsumenta, należy dokonać kilku zmian do OnRun obsługi.Pierwsza zmiana funkcji jest, aby dodać kod, aby dodać właściwości do zestawu właściwości.Zestawy kodu DBPROP_IRowsetLocate właściwość ma wartość true, więc mówienie dostawca ma zostać wyświetlona kolumna zakładki.OnRun Kodu obsługi powinna wyglądać następująco:

//////////////////////////////////////////////////////////////////////
// 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 pętli zawiera kod wywołujący Compare metodę w IRowsetLocate interfejsu.Kod, który ma zawsze należy przekazać, ponieważ porównujesz dokładnie tym samym zakładki.Także przechowywać jednej zakładki w zmiennej tymczasowej, dzięki czemu można go użyć po zakończeniu pętli wykończenie wywołać MoveToBookmark funkcji w szablonach konsumenta.MoveToBookmark Działać wywołania GetRowsAt metodę w IRowsetLocate.

Należy także zaktualizować rekord użytkownika w konsumenta.Dodawanie pozycji w klasie obsługi zakładki i wpis w COLUMN_MAP:

///////////////////////////////////////////////////////////////////////
// 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()
};

Po zaktualizowaniu kod, można zbudować i wykonania dostawcy z IRowsetLocate interfejsu.

Zobacz też

Koncepcje

Zaawansowane techniki dostawcy