Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.
Quando utilizar a classe CDynamicAccessor para obter ou definir os valores de uma coluna da Unicode cadeia (por exemplo, um SQL Server 7.0 nchar campo), vários erros possíveis ou sintomas podem ocorrer, incluindo os seguintes:
DB_E_ERRORSOCCURED é devolvido quando chamada SetData .
CDynamicAccessor não cria existe memória suficiente para conter a cadeia. CDynamicAccessor utiliza o membro ulColumnSize as informações de coluna para obter o comprimento necessário para a memória intermédia. No entanto, este método produz o número de caracteres para o campo, não o número de bytes. Este valor (o número de caracteres de campo) tem de ser multiplicado pelo 2 [ sizeof(WCHAR) ] para obter o número de bytes necessários para conter a cadeia Unicode.
Além disso, as seguintes funções não calcular o desvio correctamente para as respectivas partes (comprimento e estado):
Para contornar este problema, deriva uma nova classe CDynamicAccessor e corrija as funções necessárias multiplicando ulColumnSize por 2 sempre que for encontrada uma coluna DBTYPE_WSTR .
O código de exemplo seguinte é um exemplo de como a classe pode aparecer:
class CDynAccessor: public CDynamicAccessor
{
public:
bool GetStatus(ULONG nColumn, DBSTATUS* pStatus) const
{
ATLASSERT(pStatus != NULL);
if (TranslateColumnNo(nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*pStatus = *(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR)), sizeof(ULONG)));
else
*pStatus = *(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG)));
return true;
}
else
return false;
}
bool GetStatus(TCHAR* pColumnName, DBSTATUS* pStatus) const
{
ATLASSERT(pColumnName != NULL);
ATLASSERT(pStatus != NULL);
ULONG nColumn;
if (GetInternalColumnNo(pColumnName, &nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*pStatus = *(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR)), sizeof(ULONG)));
else
*pStatus = *(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG)));
return true;
}
else
return false;
}
bool SetStatus(ULONG nColumn, DBSTATUS status)
{
if (TranslateColumnNo(nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR)), sizeof(ULONG))) = status;
else
*(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG))) = status;
return true;
}
else
return false;
}
bool SetStatus(TCHAR* pColumnName, DBSTATUS status)
{
ATLASSERT(pColumnName != NULL);
ULONG nColumn;
if (GetInternalColumnNo(pColumnName, &nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR)), sizeof(ULONG))) = status;
else
*(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG))) = status;
return true;
}
else
return false;
}
bool GetLength(ULONG nColumn, ULONG* pLength) const
{
ATLASSERT(pLength != NULL);
if (TranslateColumnNo(nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*pLength = *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR)));
else
*pLength = *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize));
return true;
}
else
return false;
}
bool GetLength(TCHAR* pColumnName, ULONG* pLength) const
{
ATLASSERT(pColumnName != NULL);
ATLASSERT(pLength != NULL);
ULONG nColumn;
if (GetInternalColumnNo(pColumnName, &nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*pLength = *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR)));
else
*pLength = *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize));
return true;
}
else
return false;
}
bool SetLength(ULONG nColumn, ULONG nLength)
{
if (TranslateColumnNo(nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR))) = nLength;
else
*(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize)) = nLength;
return true;
}
else
return false;
}
bool SetLength(TCHAR* pColumnName, ULONG nLength)
{
ATLASSERT(pColumnName != NULL);
ULONG nColumn;
if (GetInternalColumnNo(pColumnName, &nColumn))
{
if (DBTYPE_WSTR == m_pColumnInfo[nColumn].wType)
*(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize*sizeof(WCHAR))) = nLength;
else
*(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize)) = nLength;
return true;
}
else
return false;
}
HRESULT BindColumns(IUnknown* pUnk)
{
ATLASSERT(pUnk != NULL);
CComPtr<IAccessor> spAccessor;
HRESULT hr = pUnk->QueryInterface(&spAccessor);
if (FAILED(hr))
return hr;
ULONG i;
ULONG nOffset = 0, nLengthOffset, nStatusOffset;
// If the user hasn't specifed the column information to bind by calling AddBindEntry then
// we get it ourselves.
if (m_pColumnInfo == NULL)
{
CComPtr<IColumnsInfo> spColumnsInfo;
hr = pUnk->QueryInterface(&spColumnsInfo);
if (FAILED(hr))
return hr;
hr = spColumnsInfo->GetColumnInfo(&m_nColumns, &m_pColumnInfo, &m_pStringsBuffer);
if (FAILED(hr))
return hr;
m_bOverride = false;
}
else
m_bOverride = true;
DBBINDING* pBinding = NULL;
ATLTRY(pBinding= new DBBINDING[m_nColumns]);
if (pBinding == NULL)
return E_OUTOFMEMORY;
DBBINDING* pCurrent = pBinding;
DBOBJECT* pObject;
for (i = 0; i < m_nColumns; i++)
{
// If it's a BLOB or the column size is large enough for us to treat it as
// a BLOB then we also need to set up the DBOBJECT structure.
if (m_pColumnInfo[i].ulColumnSize > 1024 || m_pColumnInfo[i].wType == DBTYPE_IUNKNOWN)
{
pObject = NULL;
ATLTRY(pObject = new DBOBJECT);
if (pObject == NULL)
return E_OUTOFMEMORY;
pObject->dwFlags = STGM_READ;
pObject->iid = IID_ISequentialStream;
m_pColumnInfo[i].wType = DBTYPE_IUNKNOWN;
m_pColumnInfo[i].ulColumnSize = sizeof(IUnknown*);
}
else
pObject = NULL;
// If column is of type STR or WSTR increase length by 1
// to accommodate the NULL terminator.
if (m_pColumnInfo[i].wType == DBTYPE_STR ||
m_pColumnInfo[i].wType == DBTYPE_WSTR)
m_pColumnInfo[i].ulColumnSize += 1;
if (m_pColumnInfo[i].wType == DBTYPE_WSTR)
nLengthOffset = AddOffset(nOffset, m_pColumnInfo[i].ulColumnSize*sizeof(WCHAR));
else
nLengthOffset = AddOffset(nOffset, m_pColumnInfo[i].ulColumnSize);
nStatusOffset = AddOffset(nLengthOffset, sizeof(ULONG));
ULONG cbMaxLen;
if (m_pColumnInfo[i].wType == DBTYPE_WSTR)
cbMaxLen = m_pColumnInfo[i].ulColumnSize*sizeof(WCHAR);
else
cbMaxLen = m_pColumnInfo[i].ulColumnSize;
CAccessorBase::Bind(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
cbMaxLen, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
DBPARAMIO_NOTPARAM, nOffset,
nLengthOffset, nStatusOffset, pObject);
pCurrent++;
// Note that, because we're not using this for anything else, we're using the
// pTypeInfo element to store the offset to our data.
m_pColumnInfo[i].pTypeInfo = (ITypeInfo*)nOffset;
nOffset = AddOffset(nStatusOffset, sizeof(DBSTATUS));
}
// Allocate the accessor memory if we haven't done so yet.
if (m_pAccessorInfo == NULL)
{
hr = AllocateAccessorMemory(1); // We only have one accessor.
if (FAILED(hr))
{
delete [] pBinding;
return hr;
}
m_pAccessorInfo->bAutoAccessor = TRUE;
}
// Allocate enough memory for the data buffer and tell the rowset.
// Note that the rowset will free the memory in its destructor.
m_pBuffer = NULL;
ATLTRY(m_pBuffer = new BYTE[nOffset]);
if (m_pBuffer == NULL)
{
delete [] pBinding;
return E_OUTOFMEMORY;
}
hr = BindEntries(pBinding, m_nColumns, &m_pAccessorInfo->hAccessor,
nOffset, spAccessor);
delete [] pBinding;
return hr;
}
};
Segue-se exemplos de código que falha ao inserir uma cadeia de Unicode 18 caracteres numa tabela SQL com uma coluna de texto Unicode 20 caracteres de nível (nvarchar):
CDataSource ds;
CSession sn;
HRESULT hr;
CDBPropSet dbinit(DBPROPSET_DBINIT);
dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("sa"));
dbinit.AddProperty(DBPROP_INIT_CATALOG, OLESTR("pubs"));
dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("myserver"));
dbinit.AddProperty(DBPROP_INIT_LCID, (long)1033);
dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
hr = ds.Open(_T("SQLOLEDB"), &dbinit);
ATLASSERT(SUCCEEDED(hr)); //Is the Datasource name and the table name correct, above?
sn.Open(ds);
CCommand< CDynamicAccessor> cmd;
// To fix the problem, remark the above line that uses CDynamicAccessor
// and uncomment the line below that uses the new CDynamicAccessor-derived class.
// CCommand< CDynAccessor> cmd;
cmd.Create(sn, "Select * from TestTable");
CDBPropSet propset(DBPROPSET_ROWSET);
propset.AddProperty(DBPROP_IRowsetChange, true);
propset.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
hr = cmd.Open(&propset);
hr = cmd.MoveNext();
ULONG ul;
DBSTATUS stat;
cmd.GetLength(1, &ul); // This is probably not correct.
cmd.GetStatus(1, &stat); // This is probably not correct.
wchar_t * pszValue = (wchar_t *)cmd.GetValue(1);
wcscpy(pszValue, L"12345678901234567");
int len = wcslen(pszValue);
cmd.SetLength(1, len*2 );
cmd.SetStatus(1, DBSTATUS_S_OK);
hr = cmd.Insert();
cmd.GetStatus(1, &stat);
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine translation ou MT), não tendo sido portanto revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 238539
(http://support.microsoft.com/kb/238539/en-us/
)
Qual foi o esforço que despendeu pessoalmente para utilizar este artigo?
Muito baixo
Baixo
Moderado
Elevado
Muito elevado
Diga-nos porquê e o que podemos fazer para melhorar estas informações
Obrigado! Os seus comentários são utilizados para ajudar-nos a melhorar o conteúdo do nosso suporte. Para obter mais opções de assistência, visite a Home Page de Ajuda e Suporte.