文章編號: 238539 - 上次校閱: 2002年10月15日 - 版次: 1.1
FIX: 使用 CDynamicAccessor 具有記憶體覆寫的 Unicode 資料行原因和其他失敗
系統提示 本文適用於您使用的作業系統之外的作業系統。與您不相關的文章內容已停用。
當您使用
CDynamicAccessor 類別來擷取或設定 Unicode 字串資料行 (,例如一個 SQL Server 7.0 nchar 欄位),幾個可能的錯誤值或徵狀可能發生包括下列:
當您呼叫 SetData 時,就會傳回 DB_E_ERRORSOCCURED。 應用程式停止回應 (擱置)。 您收到存取違規。 CDynamicAccessor 並不會建立足夠的儲存區來容納字串。
CDynamicAccessor 使用資料行資訊
ulColumnSize 成員取得所需的緩衝區長度。不過,這個方法會產生欄位不的位元組數目的字元的數。這個值 ([] 欄位中的字元數目) 必須乘以 2 [
sizeof(WCHAR) ] 以取得容納 Unicode 字串所需的位元組數目。
而且,下列函式做不計算其組件 (長度和狀態) 的正確位移:
GetLength SetLength SetStatus GetStatus 如果需要替代的這個問題,從
CDynamicAccessor 衍生新的類別,並
ulColumnSize 乘以 2 不管
DBTYPE_WSTR 資料行,來更正所需的函式。
下列範例程式碼是類別可能會出現方式的範例:
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;
}
};
Microsoft 已確認這是在本文開頭所列之 Microsoft 產品中的有錯誤。
這個問題已經在 Microsoft Visual C++.NET 中獲得修正。
下列是失敗時具有 20 字元整個 Unicode 文字資料行 (nvarchar) 的 SQL 資料表中插入一個 18 個字元的 Unicode 字串的範例程式碼:
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);
這篇文章中的資訊適用於: Microsoft OLE DB 2.7?應用於: Microsoft Visual C++ 6.0 Enterprise Edition Microsoft Visual C++ 6.0 Professional Edition Microsoft Visual C++, 32-bit Learning Edition 6.0 kbmt kbbug kbconsumer kbdatabase kbdtl kbfix kbmdacnosweep kbnoupdate KB238539 KbMtzh
機器翻譯 重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:
238539 ?
(http://support.microsoft.com/kb/238539/en-us/
)
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。
為確保您的隱私權,在意見表中請勿包含您的連絡資訊。
謝謝您!您的意見將協助我們改進支援內容。如需更多協助選項,請造訪
說明及支援首頁 。