Sdílet prostřednictvím


Podpora zprostředkovatele pro záložky

Příklad v tomto tématu přidá rozhraní IRowsetLocate do třídy CMyProviderRowset.Téměř ve všech případech začnete přidáním rozhraní do existujícího objektu modelu COM.Potom jej můžete otestovat přidáním dalších volání ze šablon příjemce.Příklad ukazuje jak:

  • Přidat rozhraní ke zprostředkovateli.

  • Dynamicky určit sloupce, které se vrátí příjemci.

  • Přidat podporu záložek.

Rozhraní IRowsetLocate dědí z rozhraní IRowset.Chcete-li přidat rozhraní IRowsetLocate, musíte dědit CMyProviderRowset z IRowsetLocateImpl.

Přidání rozhraní IRowsetLocate se trochu liší od většiny rozhraní.Chcete-li seřadit virtuální tabulky, šablony zprostředkovatele technologie OLE DB obsahují parametr šablony ke zpracování odvozeného rozhraní.Následující kód ukazuje nový seznam dědičnosti:

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

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

Čtvrtý, pátý a šestý parametr je přidaný.Tento příklad používá výchozí hodnoty pro čtvrtý a pátý parametr a specifikuje IRowsetLocateImpl jako šestý parametr.IRowsetLocateImplje třída šablon technologie OLE DB, která přebírá dva parametry šablony: ty připojí IRowsetLocate na rozhraní CMyProviderRowset třídy.Při přidávání většiny rozhraní lze tento krok přeskočit a přesunout se na další.Pouze rozhraní IRowsetLocate a IRowsetScroll je třeba zpracovat tímto způsobem.

Musíte potom sdělit třídě CMyProviderRowset, aby volala QueryInterface pro rozhraní IRowsetLocate.Přidejte do mapy řádek COM_INTERFACE_ENTRY(IRowsetLocate).Mapa rozhraní pro CMyProviderRowset by měla vypadat jako v následujícím kódu:

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

Musíte také připojit mapu do třídy CRowsetImpl.Přidejte makro COM_INTERFACE_ENTRY_CHAIN, abyste připojili mapu CRowsetImpl.Také vytvořte definici typu nazvanou RowsetBaseClass, která obsahuje informace o dědičnosti.Tato definice typu je volitelná a může být ignorována.

Nakonec zpracujte volání IColumnsInfo::GetColumnsInfo.K tomu byste měli obvykle použít makra PROVIDER_COLUMN_ENTRY.Příjemce však může chtít používat záložky.Musíte být schopni změnit sloupce, které zprostředkovatel vrací, podle toho, zda příjemce požádá o záložku.

Chcete-li zpracovat volání IColumnsInfo::GetColumnsInfo, odstraňte mapu PROVIDER_COLUMN v třídě CTextData.Makro PROVIDER_COLUMN_MAP definuje funkce GetColumnInfo.Je třeba definovat vlastní funkce GetColumnInfo.Deklarace funkce by měla vypadat takto:

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

Poté implementujte funkci GetColumnInfo v souboru MyProviderRS.cpp takto:

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

GetColumnInfo první zkontroluje, zda je nastavena vlastnost DBPROP_IRowsetLocate.Technologie OLE DB má vlastnosti pro každé z volitelných rozhraní mimo objekt sady řádků.Pokud chce příjemce použít jedno z těchto volitelných rozhraní, nastaví vlastnost na hodnotu true.Zprostředkovatel potom může zkontrolovat tuto vlastnost a na základě toho přijmout zvláštní opatření.

Ve vaší implementaci získáte vlastnost, pokud použijete ukazatel na objekt příkazu.Ukazatel pThis představuje sadu řádků nebo třídu příkazu.Protože používáte šablony, bude nutné předat this jako ukazatel void nebo nebude kód zkompilován.

Určete statické pole, aby obsahovalo informace o sloupci.Pokud příjemce nechce sloupec záložky, jedna položka v poli zůstane nevyužitá.Toto pole můžete přidělit dynamicky, ale měli byste se ujistit, že bude zničeno správně.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 souboru MyProviderRS.H, jak je ukázáno v následujícím kódu:

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

Chcete-li otestovat kód v příjemci, musíte provést několik změn u obslužné rutiny OnRun.První změna u funkce je, že přidáte kód k přidání vlastnosti do sady vlastností.Kód nastaví vlastnost DBPROP_IRowsetLocate na hodnotu true, to říká zprostředkovateli, že chcete sloupec záložky.Kód obslužné rutiny OnRun 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("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);
}

Cyklus while obsahuje kód pro volání metody Compare v rozhraní IRowsetLocate.Kód, který máte, by měl vždy projít, protože porovnáváte přesně stejné záložky.Uložte také jednu záložku v dočasné proměnné, což Vám umožní ji využít poté, co cyklus while dokončí volání funkce MoveToBookmark v šablonách příjemce.Funkce MoveToBookmark volá metodu GetRowsAt v IRowsetLocate.

Potřebujete také aktualizovat uživatelský záznam v příjemci.Přidejte položku do třídy pro zpracování záložky a položku 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()
};

Poté, co aktualizujete kód, byste měli být schopni sestavit a spustit zprostředkovatele s rozhraním IRowsetLocate.

Viz také

Koncepty

Pokročilé techniky zprostředkování