Partager via


Prise en charge des signets par le fournisseur

L’exemple de cette rubrique ajoute l’interface IRowsetLocate à la CCustomRowset classe. Dans presque tous les cas, vous commencez par ajouter une interface à un objet COM existant. Vous pouvez ensuite le tester en ajoutant d’autres appels à partir des modèles consommateur. L’exemple montre comment :

  • Ajoutez une interface à un fournisseur.

  • Déterminez dynamiquement les colonnes à retourner au consommateur.

  • Ajoutez la prise en charge des signets.

L'interface IRowsetLocate hérite de l'interface IRowset . Pour ajouter l’interface IRowsetLocate , héritez CCustomRowset de IRowsetLocateImpl.

L’ajout de l’interface IRowsetLocate est un peu différent de la plupart des interfaces. Pour aligner les VTABLEs, les modèles de fournisseur OLE DB ont un paramètre de modèle pour gérer l’interface dérivée. Le code suivant montre la nouvelle liste d’héritage :

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

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

Les quatrième, cinquième et sixième paramètres sont tous ajoutés. Cet exemple utilise les valeurs par défaut pour les quatrième et cinquième paramètres, mais spécifiez IRowsetLocateImpl comme sixième paramètre. IRowsetLocateImpl est une classe de modèle OLE DB qui prend deux paramètres de modèle : celles-ci raccordent l’interface IRowsetLocate à la CCustomRowset classe. Pour ajouter la plupart des interfaces, vous pouvez ignorer cette étape et passer à la suivante. Seules les IRowsetLocate interfaces doivent IRowsetScroll être gérées de cette façon.

Vous devez ensuite indiquer à l’utilisateur CCustomRowset d’appeler QueryInterface l’interface IRowsetLocate . Ajoutez la ligne COM_INTERFACE_ENTRY(IRowsetLocate) à la carte. Le mappage CCustomRowset d’interface doit apparaître comme indiqué dans le code suivant :

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

Vous devez également raccorder votre carte à la CRowsetImpl classe. Ajoutez la macro COM_INTERFACE_ENTRY_CHAIN pour se connecter à la CRowsetImpl carte. Créez également un typedef appelé RowsetBaseClass qui se compose des informations d’héritage. Ce typedef est arbitraire et peut être ignoré.

Enfin, gérez l’appel IColumnsInfo::GetColumnsInfo . Vous utilisez normalement les macros PROVIDER_COLUMN_ENTRY pour effectuer cette opération. Toutefois, un consommateur peut vouloir utiliser des signets. Vous devez être en mesure de modifier les colonnes retournées par le fournisseur selon que le consommateur demande un signet.

Pour gérer l’appel IColumnsInfo::GetColumnsInfo , supprimez le mappage PROVIDER_COLUMN dans la CTextData classe. La macro PROVIDER_COLUMN_MAP définit une fonction GetColumnInfo. Définissez votre propre GetColumnInfo fonction. La déclaration de fonction doit ressembler à ceci :

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

Ensuite, implémentez la GetColumnInfo fonction dans le fichier de RS.cpp personnalisécomme suit :

////////////////////////////////////////////////////////////////////
// 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 vérifie d’abord si une propriété appelée DBPROP_IRowsetLocate est définie. OLE DB a des propriétés pour chacune des interfaces facultatives de l’objet d’ensemble de lignes. Si le consommateur souhaite utiliser l’une de ces interfaces facultatives, il définit une propriété sur true. Le fournisseur peut ensuite vérifier cette propriété et effectuer une action spéciale en fonction de celui-ci.

Dans votre implémentation, vous obtenez la propriété à l’aide du pointeur vers l’objet de commande. Le pThis pointeur représente l’ensemble de lignes ou la classe de commandes. Étant donné que vous utilisez des modèles ici, vous devez le transmettre en tant que void pointeur ou que le code ne se compile pas.

Spécifiez un tableau statique pour contenir les informations de colonne. Si le consommateur ne souhaite pas la colonne signet, une entrée dans le tableau est perdue. Vous pouvez allouer dynamiquement ce tableau, mais vous devez vous assurer de le détruire correctement. Cet exemple définit et utilise les macros ADD_COLUMN_ENTRY et ADD_COLUMN_ENTRY_EX pour insérer les informations dans le tableau. Vous pouvez ajouter les macros au RS personnalisé. Fichier H, comme indiqué dans le code suivant :

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

Pour tester le code dans le consommateur, vous devez apporter quelques modifications au OnRun gestionnaire. La première modification apportée à la fonction est que vous ajoutez du code pour ajouter une propriété au jeu de propriétés. Le code définit la DBPROP_IRowsetLocate propriété sur true, indiquant ainsi au fournisseur que vous souhaitez la colonne signet. Le code du OnRun gestionnaire doit apparaître comme suit :

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

La boucle contient du while code pour appeler la Compare méthode dans l’interface IRowsetLocate . Le code que vous avez toujours passé doit toujours passer, car vous comparez exactement les mêmes signets. En outre, stockez un signet dans une variable temporaire afin de pouvoir l’utiliser une fois la while boucle terminée pour appeler la MoveToBookmark fonction dans les modèles consommateur. La MoveToBookmark fonction appelle la GetRowsAt méthode dans IRowsetLocate.

Vous devez également mettre à jour l’enregistrement utilisateur dans le consommateur. Ajoutez une entrée dans la classe pour gérer un signet et une entrée dans le 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()
};

Lorsque vous avez mis à jour le code, vous devez être en mesure de générer et d’exécuter le fournisseur avec l’interface IRowsetLocate .

Voir aussi

Techniques avancées du fournisseur