Freigeben über


Anbieterunterstützung für Lesezeichen

Im Beispiel in diesem Thema wird der Klasse die IRowsetLocate CCustomRowset Schnittstelle hinzugefügt. In fast allen Fällen beginnen Sie mit dem Hinzufügen einer Schnittstelle zu einem vorhandenen COM-Objekt. Sie können sie dann testen, indem Sie weitere Aufrufe aus den Consumervorlagen hinzufügen. Das Beispiel veranschaulicht Folgendes:

  • Fügen Sie einem Anbieter eine Schnittstelle hinzu.

  • Bestimmen Sie dynamisch die Spalten, die an den Consumer zurückgegeben werden sollen.

  • Unterstützung für Textmarken hinzufügen.

Die IRowsetLocate -Schnittstelle erbt von der IRowset -Schnittstelle. Um die IRowsetLocate Schnittstelle hinzuzufügen, erben Sie CCustomRowset von IRowsetLocateImpl.

Das Hinzufügen der Schnittstelle unterscheidet sich etwas von den IRowsetLocate meisten Schnittstellen. Damit die VTABLEs-Zeile eingerichtet wird, verfügen die OLE DB-Anbietervorlagen über einen Vorlagenparameter, um die abgeleitete Schnittstelle zu verarbeiten. Der folgende Code zeigt die neue Vererbungsliste:

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

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

Die vierten, fünften und sechsten Parameter werden alle hinzugefügt. In diesem Beispiel werden die Standardwerte für die vierten und fünften Parameter verwendet, aber als sechster Parameter angegeben IRowsetLocateImpl . IRowsetLocateImpl ist eine OLE DB-Vorlagenklasse, die zwei Vorlagenparameter verwendet: Diese verbinden die IRowsetLocate Schnittstelle mit der CCustomRowset Klasse. Um die meisten Schnittstellen hinzuzufügen, können Sie diesen Schritt überspringen und zum nächsten wechseln. Nur die IRowsetLocate Schnittstellen IRowsetScroll müssen auf diese Weise behandelt werden.

Anschließend müssen Sie den CCustomRowset Aufruf QueryInterface für die IRowsetLocate Schnittstelle mitteilen. Fügen Sie der Karte die Linie COM_INTERFACE_ENTRY(IRowsetLocate) hinzu. Die Schnittstellenzuordnung CCustomRowset sollte wie im folgenden Code dargestellt angezeigt werden:

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

Außerdem müssen Sie Ihre Karte in die CRowsetImpl Klasse integrieren. Fügen Sie das COM_INTERFACE_ENTRY_CHAIN Makro hinzu, um in der CRowsetImpl Karte zu verbinden. Erstellen Sie außerdem eine typedef, RowsetBaseClass die aus den Vererbungsinformationen besteht. Dieser Typedef ist beliebig und kann ignoriert werden.

Behandeln Sie schließlich den IColumnsInfo::GetColumnsInfo Anruf. Normalerweise würden Sie dazu die PROVIDER_COLUMN_ENTRY Makros verwenden. Ein Verbraucher möchte jedoch möglicherweise Lesezeichen verwenden. Sie müssen in der Lage sein, die Spalten zu ändern, die der Anbieter zurückgibt, je nachdem, ob der Verbraucher nach einer Textmarke fragt.

Um den IColumnsInfo::GetColumnsInfo Anruf zu verarbeiten, löschen Sie die PROVIDER_COLUMN Karte in der CTextData Klasse. Das PROVIDER_COLUMN_MAP Makro definiert eine Funktion GetColumnInfo. Definieren Sie Ihre eigene GetColumnInfo Funktion. Die Funktionsdeklaration sollte wie folgt aussehen:

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

Implementieren Sie dann die GetColumnInfo Funktion in der Datei "CustomRS.cpp" wie folgt:

////////////////////////////////////////////////////////////////////
// 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 überprüft zuerst, ob eine aufgerufene Eigenschaft DBPROP_IRowsetLocate festgelegt ist. OLE DB verfügt über Eigenschaften für jede der optionalen Schnittstellen aus dem Rowset-Objekt. Wenn der Verbraucher eine dieser optionalen Schnittstellen verwenden möchte, wird eine Eigenschaft auf "true" festgelegt. Der Anbieter kann diese Eigenschaft dann überprüfen und basierend darauf spezielle Maßnahmen ergreifen.

In Ihrer Implementierung rufen Sie die Eigenschaft mithilfe des Zeigers auf das Befehlsobjekt ab. Der pThis Zeiger stellt das Rowset oder die Befehlsklasse dar. Da Sie hier Vorlagen verwenden, müssen Sie dies als void Zeiger übergeben, oder der Code wird nicht kompiliert.

Geben Sie ein statisches Array an, das die Spalteninformationen enthalten soll. Wenn der Verbraucher die Textmarkenspalte nicht verwenden möchte, wird ein Eintrag im Array verschwendet. Sie können dieses Array dynamisch zuordnen, aber Sie müssen sicherstellen, dass es ordnungsgemäß zerstört wird. In diesem Beispiel werden die Makros ADD_COLUMN_ENTRY und ADD_COLUMN_ENTRY_EX definiert und verwendet, um die Informationen in das Array einzufügen. Sie können die Makros dem benutzerdefiniertenRS hinzufügen. H-Datei wie im folgenden Code dargestellt:

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

Um den Code im Consumer zu testen, müssen Sie einige Änderungen am OnRun Handler vornehmen. Die erste Änderung an der Funktion besteht darin, dass Sie Code hinzufügen, um dem Eigenschaftensatz eine Eigenschaft hinzuzufügen. Der Code legt die DBPROP_IRowsetLocate Eigenschaft auf "true" fest und teilt dem Anbieter mit, dass die Textmarkespalte verwendet werden soll. Der OnRun Handlercode sollte wie folgt angezeigt werden:

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

Die while Schleife enthält Code zum Aufrufen der Compare Methode in der IRowsetLocate Schnittstelle. Der Code, den Sie immer übergeben haben, da Sie genau dieselben Lesezeichen vergleichen. Speichern Sie außerdem eine Textmarke in einer temporären Variablen, damit Sie sie verwenden können, nachdem die while Schleife beendet wurde, um die Funktion in den MoveToBookmark Consumervorlagen aufzurufen. Die MoveToBookmark Funktion ruft die GetRowsAt Methode in IRowsetLocate.

Außerdem müssen Sie den Benutzerdatensatz im Verbraucher aktualisieren. Fügen Sie einen Eintrag in der Klasse hinzu, um eine Textmarke und einen Eintrag in der COLUMN_MAP zu behandeln:

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

Wenn Sie den Code aktualisiert haben, sollten Sie in der Lage sein, den Anbieter mit der IRowsetLocate Schnittstelle zu erstellen und auszuführen.

Siehe auch

Erweiterte Anbietertechniken