Suporte de 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 existente do COM. Você pode testá-lo adicionando mais chamadas a partir de modelos de consumidor. O exemplo demonstra como:
Adicione uma interface para um provedor.
Determine dinamicamente as colunas para retornar ao consumidor.
Adicione suporte de indicador.
O IRowsetLocate interface é herdeira 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 de provedor tem um parâmetro de modelo para lidar com 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, mas especificam 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 manipulados de forma.
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()
Também é necessário conectar seu mapa para o CRowsetImpl classe. Adicionar na macro para conectar-se em COM_INTERFACE_ENTRY_CHAIN a CRowsetImpl mapa. Além disso, crie um typedef chamado RowsetBaseClass que consiste de 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 no CTextData classe. A macro PROVIDER_COLUMN_MAP define uma função GetColumnInfo. Você precisará definir suas próprias GetColumnInfo função. A declaração da 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á definida. OLE DB tem propriedades para cada uma das interfaces opcionais desativar 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 sua implementação, você pode obter a propriedade usando o ponteiro para o objeto de comando. O pThis ponteiro representa a classe de comando ou linhas. Como usar modelos aqui, você precisa passar isso como um void ponteiro ou o código não compilar.
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 será desperdiçada. É possível alocar dinamicamente essa matriz, mas seria necessário certificar-se de destruí-lo corretamente. Este exemplo define e utiliza as macros, ADD_COLUMN_ENTRY e ADD_COLUMN_ENTRY_EX para inserir as informações na matriz. Você pode adicionar as macros para o 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 no consumidor, você precisa fazer algumas alterações para o OnRun o manipulador. A primeira alteração para a função é que você adicione código para adicionar uma propriedade para o conjunto de propriedades. Os conjuntos de códigos de DBPROP_IRowsetLocate a propriedade como true, assim, informando o provedor que você deseja que a coluna de indicador. O OnRun o código do 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. Além disso, armazenar um indicador em uma variável temporária, para que você pode usá-lo após o tempo terminar a chamada de loop a MoveToBookmark função em modelos de consumidor. O MoveToBookmark chamadas de função do GetRowsAt método na IRowsetLocate.
Você também precise atualizar o registro de usuário no consumidor. Adicionar uma entrada na classe para lidar com 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.