Suporte do provedor para indicadores
O exemplo neste tópico adiciona o IRowsetLocate interface para o CMyProviderRowset classe.Em quase todos os casos, comece adicionando uma interface para um objeto COM existente.Você pode testá-lo adicionando mais chamadas de modelos de consumidor.O exemplo demonstra como:
Adicione uma interface a um provedor.
Determine dinamicamente as colunas para retornar para o consumidor.
Adicione suporte de indicador.
O IRowsetLocate interface herda de IRowset interface.Para adicionar o IRowsetLocate interface, herdam CMyProviderRowset de IRowsetLocateImpl.
Adicionando o IRowsetLocate interface é um pouco diferente da maioria das interfaces.Para que a linha TabelaV até o OLE DB modelos provedor tem um parâmetro de modelo para manipular a interface derivada.O código a seguir mostra a nova lista de herança:
////////////////////////////////////////////////////////////////////////
// MyProviderRS.h
// CMyProviderRowset
class CMyProviderRowset : public CRowsetImpl< CMyProviderRowset,
CTextData, CMyProviderCommand, CAtlArray<CTextData>,
CSimpleRow,
IRowsetLocateImpl<CMyProviderRowset, IRowsetLocate> >
O quarto, quinto e sexto parâmetros são adicionados.Este exemplo usa os padrões para o quarto e quinto parâmetros especificam mas IRowsetLocateImpl como o sexto parâmetro.IRowsetLocateImplé uma classe de modelo de banco de dados OLE que usa dois parâmetros de modelo: esses ligar o IRowsetLocate interface para o CMyProviderRowset classe.Para adicionar a maioria das interfaces, você pode ignorar esta etapa e mover para o próximo.Somente o IRowsetLocate e IRowsetScroll interfaces precisam ser tratadas dessa maneira.
Você precisa dizer a CMyProviderRowset para chamar QueryInterface para o IRowsetLocate interface.Adicione a linha COM_INTERFACE_ENTRY(IRowsetLocate) no mapa.O mapa de interface de CMyProviderRowset deve aparecer como mostrado no código a seguir:
////////////////////////////////////////////////////////////////////////
// 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()
Você também precisa conectar seu mapa para o CRowsetImpl classe.Adicionar a macro COM_INTERFACE_ENTRY_CHAIN conectar no CRowsetImpl mapa.Além disso, criar um typedef chamado RowsetBaseClass que consiste em informações de herança.Este typedef é arbitrário e pode ser ignorado.
Finalmente, lidar com o IColumnsInfo::GetColumnsInfo de chamada.Normalmente você usaria as macros PROVIDER_COLUMN_ENTRY para fazer isso.Entretanto, um consumidor pode querer usar marcadores.Você deve ser capaz de alterar as colunas que o provedor retorna dependendo se o consumidor solicita um indicador.
Para lidar com o IColumnsInfo::GetColumnsInfo chamar, exclua o PROVIDER_COLUMN mapear na CTextData classe.A macro PROVIDER_COLUMN_MAP define uma função GetColumnInfo.Você precisa definir seu próprio GetColumnInfo função.A declaração de função deve ter esta aparência:
////////////////////////////////////////////////////////////////////////
// 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);
...
};
Em seguida, implementar a GetColumnInfo funcionar no arquivo MyProviderRS.cpp da seguinte maneira:
////////////////////////////////////////////////////////////////////
// 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);
}
GetColumnInfoprimeira verifica se uma propriedade chamada DBPROP_IRowsetLocate está definido.OLE DB tem propriedades para cada uma das interfaces opcionais fora o objeto rowset.Se o consumidor quiser usar uma dessas interfaces opcionais, ele define uma propriedade como true.O provedor pode verificar essa propriedade e realizar ações especiais com base nele.
Na implementação, obtenha a propriedade usando o ponteiro para o objeto de comando.O pThis ponteiro representa a classe de comando ou de linhas.Como usar modelos aqui, você precisa passar isso como uma void ponteiro ou o código não compila.
Especifica uma matriz estática para conter as informações de coluna.Se o consumidor não deseja que a coluna de indicador, uma entrada na matriz é perdida.Você pode alocar dinamicamente essa matriz, mas você precisará certificar-se de destrui-la corretamente.Este exemplo define e usa as macros ADD_COLUMN_ENTRY e ADD_COLUMN_ENTRY_EX para inserir as informações no array.Você pode adicionar as macros no arquivo MyProviderRS.H, conforme mostrado no código a seguir:
////////////////////////////////////////////////////////////////////////
// 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;
Para testar o código do consumidor, você precisará fazer algumas alterações para o OnRun manipulador.A primeira alteração para a função é que você adicione código para adicionar uma propriedade para o conjunto de propriedades.O código define a DBPROP_IRowsetLocate propriedade como true, portanto, informando o provedor que você deseja que a coluna de indicador.O OnRun código de manipulador deve aparecer da seguinte maneira:
//////////////////////////////////////////////////////////////////////
// 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);
}
While loop contém código para chamar o Compare método de IRowsetLocate interface.O código que você tenha sempre deve passar porque você está comparando os indicadores de mesmos exatos.Também, armazenar um indicador em uma variável temporária que pode ser usado após o tempo terminar chamada de loop de MoveToBookmark função dos modelos de consumidor.O MoveToBookmark chamadas de função de GetRowsAt método IRowsetLocate.
Você também precisará atualizar o registro de usuário no consumidor.Adicionar uma entrada na classe para manipular um indicador e uma entrada de 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()
};
Quando você atualizar o código, você deve ser capaz de criar e executar o provedor com o IRowsetLocate interface.