Makale numarası: 238539 - Son Gözden Geçirme: 15 Ekim 2002 Salı - Gözden geçirme: 1.1

Düzeltme:, Unicode sütunlar nedenler bellek ile CDynamicAccessor kullanma üzerine yazar ve diğer hataları

Sistem İpucuBu makale, kullandığınızdan farklı bir işletim sistemine yöneliktir. Sizinle ilgili olmayabilecek makale içeriği devre dışı bırakıldı.
Hepsini aç | Hepsini kapa

Belirtiler

CDynamicAccessor sınıfı almak veya bir Unicode dize sütunu (örneğin, bir SQL Server 7.0 nchar alanı), birkaç olası hata değerlerini ayarlamak için veya kullandığınızda aşağıdaki belirtilerden oluşabilir:
  • SetData ' i ça??rd???n?zda, DB_E_ERRORSOCCURED döndürülür.
  • Uygulama (Bu bağlantı, bir kısmı veya tamamı ingilizce olan içeriğe işaret edebilir.) yanıt vermiyor.
  • Erişim ihlali alıyorsunuz.

Neden

CDynamicAccessor dize tutmak için yeterli depolama alanı oluşturmaz. Arabellek için gereken uzunluğu almak için sütun bilgileri ulColumnSize üyesi CDynamicAccessor kullanır. Ancak, bu yöntem için alanın bayt sayısını değil karakter sayısını verir. Unicode dizesi tutmak için gerekli olan bayt sayısını elde etmek için 2 ile [sizeof(WCHAR)] çarpımı (alan için karakter sayısı), bu değer gerekir.

Ayrıca, aşağıdaki işlevleri doğru parçaları için (uzunluğu ve durumu) mahsup hesapla değil:
  • GetLength
  • SetLength
  • SetStatus
  • GetStatus

Çözüm

Bu soruna geçici bir çözüm bulmak için <a0></a0>, CDynamicAccessor yeni bir sınıf türetme yapıp yapmayacağınızı ve gerekli işlevleri DBTYPE_WSTR sütun karşılaştı her ulColumnSize 2 ile çarpılarak düzeltin.

Aşağıdaki örnek kod, sınıfın nasıl ortaya çıkabilecek bir örnektir:
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;
	}
};

				

Durum

Microsoft, bunun bu makalenin başında listelenen Microsoft ürünlerinde bir hata olduğunu onaylamıştır.

Bu sorun, Microsoft Visual C++ .NET ile giderilmiştir.

Daha fazla bilgi

Aşağıdaki örnek kod 18 karakterlik bir Unicode dizesi ile 20 karakter geniş Unicode metin sütununun (nvarchar) bir SQL tablosu eklerken, başarısız olan:
	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);
				

Bu makaledeki bilginin uygulandığı durum:
  • Microsoft OLE DB 2.7, Ne zaman ne ile kullanilir:
    • Microsoft Visual C++ 6.0 Enterprise Edition
    • Microsoft Visual C++ 6.0 Professional Edition
    • Microsoft Visual C++, 32-bit Learning Edition 6.0
Anahtar Kelimeler: 
kbmt kbbug kbconsumer kbdatabase kbdtl kbfix kbmdacnosweep kbnoupdate KB238539 KbMttr
Otomatik TercümeOtomatik Tercüme
ÖNEMLİ: Bu makale, bir kişi tarafından çevrilmek yerine, Microsoft makine-çevirisi yazılımı ile çevrilmiştir. Microsoft size hem kişiler tarafından çevrilmiş, hem de makine-çevrisi ile çevrilmiş makaleler sunar. Böylelikle, bilgi bankamızdaki tüm makalelere, kendi dilinizde ulaşmış olursunuz. Bununla birlikte, makine tarafından çevrilmiş makaleler mükemmel değildir. Bir yabancının sizin dilinizde konuşurken yapabileceği hatalar gibi, makale; kelime dağarcığı, söz dizim kuralları veya dil bilgisi açısından yanlışlar içerebilir. Microsoft, içeriğin yanlış çevrimi veya onun müşteri tarafından kullanımından doğan; kusur, hata veya zarardan sorumlu değildir. Microsoft ayrıca makine çevirisi yazılımını sıkça güncellemektedir.
Makalenin İngilizcesi aşağıdaki gibidir:238539  (http://support.microsoft.com/kb/238539/en-us/ )