文章編號: 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及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。