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.