Obsługa dostawców dla zakładek
Przykład w tym temacie dodaje IRowsetLocate
interfejs do CCustomRowset
klasy. W prawie wszystkich przypadkach należy zacząć od dodania interfejsu do istniejącego obiektu COM. Następnie możesz go przetestować, dodając więcej wywołań z szablonów odbiorców. W przykładzie pokazano, jak:
Dodaj interfejs do dostawcy.
Dynamicznie określa kolumny, które mają być zwracane do odbiorcy.
Dodaj obsługę zakładek.
Interfejs IRowsetLocate
dziedziczy z interfejsu IRowset
. Aby dodać IRowsetLocate
interfejs, dziedzicz CCustomRowset
z IRowsetLocateImpl.
Dodawanie interfejsu IRowsetLocate
różni się nieco od większości interfejsów. Aby utworzyć wiersz VTABLEs, szablony dostawcy OLE DB mają parametr szablonu do obsługi interfejsu pochodnego. Poniższy kod przedstawia nową listę dziedziczenia:
////////////////////////////////////////////////////////////////////////
// CustomRS.h
// CCustomRowset
class CCustomRowset : public CRowsetImpl< CCustomRowset,
CTextData, CCustomCommand, CAtlArray<CTextData>,
CSimpleRow,
IRowsetLocateImpl<CCustomRowset, IRowsetLocate>>
Wszystkie czwarte, piąte i szóste parametry są dodawane. W tym przykładzie użyto wartości domyślnych dla czwartych i piątych parametrów, ale określono IRowsetLocateImpl
jako szósty parametr. IRowsetLocateImpl
to klasa szablonu OLE DB, która przyjmuje dwa parametry szablonu: te podłączają IRowsetLocate
interfejs do CCustomRowset
klasy. Aby dodać większość interfejsów, możesz pominąć ten krok i przejść do następnego. IRowsetLocate
W ten sposób należy obsługiwać tylko interfejsy iIRowsetScroll
.
Następnie należy poinformować element , CCustomRowset
aby wywołać QueryInterface
IRowsetLocate
interfejs. Dodaj wiersz COM_INTERFACE_ENTRY(IRowsetLocate)
do mapy. Mapa interfejsu dla CCustomRowset
elementu powinna być wyświetlana, jak pokazano w poniższym kodzie:
////////////////////////////////////////////////////////////////////////
// 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()
Musisz również podłączyć mapę do CRowsetImpl
klasy. Dodaj makro COM_INTERFACE_ENTRY_CHAIN, aby podłączyć się do CRowsetImpl
mapy. Ponadto utwórz definicję typu o nazwie RowsetBaseClass
, która składa się z informacji o dziedziczeniu. Ta definicja typu jest dowolna i może być ignorowana.
Na koniec obsłuż wywołanie IColumnsInfo::GetColumnsInfo
. W tym celu zwykle należy użyć makr PROVIDER_COLUMN_ENTRY. Jednak użytkownik może chcieć użyć zakładek. Musisz mieć możliwość zmiany kolumn zwracanych przez dostawcę w zależności od tego, czy odbiorca prosi o zakładkę.
Aby obsłużyć wywołanie IColumnsInfo::GetColumnsInfo
, usuń mapę PROVIDER_COLUMN w CTextData
klasie . Makro PROVIDER_COLUMN_MAP definiuje funkcję GetColumnInfo
. Zdefiniuj własną GetColumnInfo
funkcję. Deklaracja funkcji powinna wyglądać następująco:
////////////////////////////////////////////////////////////////////////
// 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);
...
};
Następnie zaimplementuj GetColumnInfo
funkcję w pliku CustomRS.cpp w następujący sposób:
////////////////////////////////////////////////////////////////////
// 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
najpierw sprawdza, czy właściwość o nazwie DBPROP_IRowsetLocate
jest ustawiona. Baza danych OLE DB ma właściwości dla każdego z opcjonalnych interfejsów poza obiektem zestawu wierszy. Jeśli użytkownik chce użyć jednego z tych opcjonalnych interfejsów, ustawia właściwość na true. Następnie dostawca może sprawdzić tę właściwość i podjąć specjalne działania na jego podstawie.
W implementacji właściwość jest pobierana przy użyciu wskaźnika do obiektu polecenia. Wskaźnik pThis
reprezentuje zestaw wierszy lub klasę poleceń. Ponieważ w tym miejscu używasz szablonów, musisz przekazać go jako void
wskaźnik lub kod nie jest kompilowany.
Określ tablicę statyczną do przechowywania informacji o kolumnie. Jeśli użytkownik nie chce, aby kolumna zakładki została zmarnowana, wpis w tablicy zostanie zmarnowany. Tę tablicę można przydzielić dynamicznie, ale należy upewnić się, że została ona prawidłowo zniszczona. W tym przykładzie zdefiniowano i użyto makr ADD_COLUMN_ENTRY i ADD_COLUMN_ENTRY_EX w celu wstawienia informacji do tablicy. Makra można dodać do niestandardowegoserwera RS. Plik H, jak pokazano w poniższym kodzie:
////////////////////////////////////////////////////////////////////////
// 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;
Aby przetestować kod w odbiorcy, należy wprowadzić kilka zmian w procedurze OnRun
obsługi. Pierwsza zmiana funkcji polega na dodaniu kodu w celu dodania właściwości do zestawu właściwości. Kod ustawia DBPROP_IRowsetLocate
właściwość na wartość true, a tym samym informuje dostawcę, że chcesz utworzyć kolumnę zakładki. Kod OnRun
procedury obsługi powinien 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("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);
}
Pętla while
zawiera kod wywołujący metodę Compare
w interfejsie IRowsetLocate
. Kod, który należy zawsze przekazać, ponieważ porównujesz dokładnie te same zakładki. Ponadto zapisz jedną zakładkę w zmiennej tymczasowej, aby można było jej użyć po zakończeniu while
pętli w celu wywołania MoveToBookmark
funkcji w szablonach odbiorców. Funkcja MoveToBookmark
wywołuje metodę GetRowsAt
w pliku IRowsetLocate
.
Należy również zaktualizować rekord użytkownika w odbiorcy. Dodaj wpis w klasie, aby obsłużyć zakładkę 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 kodu powinno być możliwe skompilowanie i wykonanie dostawcy za pomocą interfejsu IRowsetLocate
.
Zobacz też
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla