Podpora zprostředkovatele pro záložky
Příklad v tomto tématu přidá IRowsetLocate
rozhraní do CCustomRowset
třídy. V téměř všech případech začnete přidáním rozhraní do existujícího objektu COM. Pak ho můžete otestovat přidáním dalších volání ze šablon příjemců. Příklad ukazuje, jak:
Přidejte rozhraní k poskytovateli.
Dynamicky určete sloupce, které se mají vrátit příjemci.
Přidejte podporu záložek.
Rozhraní IRowsetLocate
dědí z IRowset
rozhraní. Chcete-li přidat IRowsetLocate
rozhraní, dědí CCustomRowset
z IRowsetLocateImpl.
IRowsetLocate
Přidání rozhraní se trochu liší od většiny rozhraní. Chcete-li vytvořit řádek VTABLEs, šablony zprostředkovatele OLE DB mají parametr šablony pro zpracování odvozeného rozhraní. Nový seznam dědičnosti ukazuje následující kód:
////////////////////////////////////////////////////////////////////////
// CustomRS.h
// CCustomRowset
class CCustomRowset : public CRowsetImpl< CCustomRowset,
CTextData, CCustomCommand, CAtlArray<CTextData>,
CSimpleRow,
IRowsetLocateImpl<CCustomRowset, IRowsetLocate>>
Všechny přidané čtvrté, páté a šesté parametry. Tento příklad používá výchozí hodnoty pro čtvrtý a pátý parametr, ale jako IRowsetLocateImpl
šestý parametr. IRowsetLocateImpl
je třída šablony OLE DB, která přebírá dva parametry šablony: tyto připojují IRowsetLocate
rozhraní ke CCustomRowset
třídě. Pokud chcete přidat většinu rozhraní, můžete tento krok přeskočit a přejít na další. IRowsetLocate
IRowsetScroll
Tímto způsobem je potřeba zpracovat pouze rozhraní.
Pak musíte říct CCustomRowset
, aby volal QueryInterface
IRowsetLocate
pro rozhraní. Přidejte čáru COM_INTERFACE_ENTRY(IRowsetLocate)
do mapy. Mapa rozhraní by CCustomRowset
se měla zobrazit, jak je znázorněno v následujícím kódu:
////////////////////////////////////////////////////////////////////////
// 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()
Musíte také zavěsit mapu do CRowsetImpl
třídy. Přidejte do COM_INTERFACE_ENTRY_CHAIN makra pro připojení k mapě CRowsetImpl
. Vytvořte také typedef, RowsetBaseClass
který se skládá z informací o dědičnosti. Tento typovýef je libovolný a lze jej ignorovat.
Nakonec zařizte IColumnsInfo::GetColumnsInfo
hovor. Obvykle byste k tomu použili PROVIDER_COLUMN_ENTRY makra. Spotřebitel ale může chtít používat záložky. V závislosti na tom, jestli příjemce požádá o záložku, musíte být schopni změnit sloupce, které poskytovatel vrátí.
Pokud chcete volání zpracovat IColumnsInfo::GetColumnsInfo
, odstraňte PROVIDER_COLUMN mapování ve CTextData
třídě. Makro PROVIDER_COLUMN_MAP definuje funkci GetColumnInfo
. Definujte vlastní GetColumnInfo
funkci. Deklarace funkce by měla vypadat takto:
////////////////////////////////////////////////////////////////////////
// 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);
...
};
Pak implementujte GetColumnInfo
funkci v souboru CustomRS.cpp následujícím způsobem:
////////////////////////////////////////////////////////////////////
// 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
nejprve zkontroluje, zda je nastavena vlastnost.DBPROP_IRowsetLocate
OLE DB má vlastnosti pro každé volitelné rozhraní mimo objekt sady řádků. Pokud chce příjemce použít jedno z těchto volitelných rozhraní, nastaví vlastnost na true. Zprostředkovatel pak může tuto vlastnost zkontrolovat a na základě ní provést zvláštní akci.
V implementaci získáte vlastnost pomocí ukazatele na objekt příkazu. Ukazatel pThis
představuje sadu řádků nebo třídu příkazů. Protože tady používáte šablony, musíte ho předat jako void
ukazatel nebo kód se nekompiluje.
Zadejte statické pole pro uložení informací o sloupci. Pokud příjemce nechce sloupec záložky, položka v poli je nevyužitá. Toto pole můžete dynamicky přidělit, ale musíte ho správně zničit. Tento příklad definuje a používá makra ADD_COLUMN_ENTRY a ADD_COLUMN_ENTRY_EX k vložení informací do pole. Makra můžete přidat do vlastního rs. Soubor H, jak je znázorněno v následujícím kódu:
////////////////////////////////////////////////////////////////////////
// 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;
Pokud chcete otestovat kód v příjemci, musíte v obslužné rutině OnRun
provést několik změn. První změnou funkce je, že přidáte kód pro přidání vlastnosti do sady vlastností. Kód nastaví DBPROP_IRowsetLocate
vlastnost na true, čímž zprostředkovateli říká, že chcete sloupec záložky. Kód OnRun
obslužné rutiny by se měl zobrazit takto:
//////////////////////////////////////////////////////////////////////
// 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);
}
Smyčka while
obsahuje kód pro volání Compare
metody v IRowsetLocate
rozhraní. Kód, který jste měli mít, by měl vždy projít, protože porovnáváte úplně stejné záložky. Uložte také jednu záložku do dočasné proměnné, abyste ji mohli použít po while
dokončení smyčky pro volání MoveToBookmark
funkce v šablonách příjemců. Funkce MoveToBookmark
volá metodu GetRowsAt
v IRowsetLocate
.
Musíte také aktualizovat záznam uživatele v příjemci. Přidejte do třídy položku pro zpracování záložky a položky v 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 aktualizaci kódu byste měli být schopni sestavit a spustit zprostředkovatele pomocí IRowsetLocate
rozhraní.