⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s15_03.cpp

📁 本书分为五个部分
💻 CPP
📖 第 1 页 / 共 4 页
字号:

		case DBTYPE_DECIMAL:
		case DBTYPE_NUMERIC:
		case DBTYPE_DATE:
		case DBTYPE_DBDATE:
		case DBTYPE_DBTIMESTAMP:
		case DBTYPE_GUID:
			// Converted to a string, the above types will all fit into
			// 50 characters, so use that plus space for the terminator.
			rgBindings[iCol].cbMaxLen = (50 + 1) * sizeof(WCHAR);
			break;

		case DBTYPE_BYTES:
			// In converting DBTYPE_BYTES to a string, each byte
			// becomes two characters (e.g. 0xFF -> "FF"), so we
			// will use double the maximum size of the column plus
			// include space for the NULL terminator.
			rgBindings[iCol].cbMaxLen =
				(rgColumnInfo[iCol].ulColumnSize * 2 + 1) * sizeof(WCHAR);
			break;

		case DBTYPE_STR:
		case DBTYPE_WSTR:
		case DBTYPE_BSTR:
			// Going from a string to our string representation,
			// we can just take the maximum size of the column,
			// a count of characters, and include space for the
			// terminator, which is not included in the column size.
			rgBindings[iCol].cbMaxLen =
				(rgColumnInfo[iCol].ulColumnSize + 1) * sizeof(WCHAR);
			break;

		default:
			// For any other type, we will simply use our maximum
			// column buffer size, since the display size of these
			// columns may be variable (e.g. DBTYPE_VARIANT) or
			// unknown (e.g. provider-specific types).
			rgBindings[iCol].cbMaxLen = MAX_COL_SIZE;
			break;
		};

		// If the provider's native data type for this column is
		// DBTYPE_IUNKNOWN or this is a BLOB column and the user
		// has requested that we bind BLOB columns as ISequentialStream
		// objects, bind this column as an ISequentialStream object if
		// the provider supports our creating another ISequentialStream
		// binding.
		if( (rgColumnInfo[iCol].wType == DBTYPE_IUNKNOWN ||
			((rgColumnInfo[iCol].dwFlags & DBCOLUMNFLAGS_ISLONG) ))//&&
			//(g_dwFlags & USE_ISEQSTREAM))) &&
			&& (fMultipleObjs || !cStorageObjs) )
		{
			// To create an ISequentialStream object, we will
			// bind this column as DBTYPE_IUNKNOWN to indicate
			// that we are requesting this column as an object.
			rgBindings[iCol].wType = DBTYPE_IUNKNOWN;

			// We want to allocate enough space in our buffer for
			// the ISequentialStream pointer we will obtain from
			// the provider.
			rgBindings[iCol].cbMaxLen = sizeof(ISequentialStream *);

			// To specify the type of object that we want from the
			// provider, we need to create a DBOBJECT structure and
			// place it in our binding for this column.
			rgBindings[iCol].pObject =
				(DBOBJECT *)CoTaskMemAlloc(sizeof(DBOBJECT));
			CHECK_MEMORY(hr, rgBindings[iCol].pObject);

			// Direct the provider to create an ISequentialStream
			// object over the data for this column.
			rgBindings[iCol].pObject->iid = IID_ISequentialStream;

			// We want read access on the ISequentialStream
			// object that the provider will create for us.
			rgBindings[iCol].pObject->dwFlags = STGM_READ;

			// Keep track of the number of storage objects
			// (ISequentialStream is a storage interface) that we have
			// requested, so that we can avoid requesting multiple storage
			// objects from a provider that supports only a single storage
			// object in our bindings.
			cStorageObjs++;
		}   

		// Ensure that the bound maximum length is no more than the
		// maximum column size in bytes that we've defined.
		rgBindings[iCol].cbMaxLen   
			= min(rgBindings[iCol].cbMaxLen, MAX_COL_SIZE);

		// Update the offset past the end of this column's data so
		// that the next column will begin in the correct place in
		// the buffer.
		dwOffset = rgBindings[iCol].cbMaxLen + rgBindings[iCol].obValue;

		// Ensure that the data for the next column will be correctly
		// aligned for all platforms, or if we're done with columns,
		// that if we allocate space for multiple rows that the data
		// for every row is correctly aligned.
		dwOffset = ROUNDUP(dwOffset);
	}

	// Return the row size (the current dwOffset is the size of the row),
	// the count of bindings, and the bindings array to the caller.
	*pcbRowSize    = dwOffset;
	*pcBindings    = cColumns;
	*prgBindings   = rgBindings;

CLEANUP:
	CoTaskMemFree(rgColumnInfo);
	CoTaskMemFree(pStringBuffer);
	if( pIColumnsInfo )
		pIColumnsInfo->Release();
	return hr;
}

/////////////////////////////////////////////////////////////////
// 函数: DisplayRowset
//
// 显示行集对象数. 
//
/////////////////////////////////////////////////////////////////
HRESULT DisplayRowset(IUnknown *    pUnkRowset,
					  LPCWSTR       pwszColToReturn,
					  ULONG         cchBuffer,
					  LPWSTR        pwszBuffer )
{
	HRESULT       hr;
	IRowset *     pIRowset               = NULL;
	ULONG         cBindings;
	DBBINDING *   rgBindings             = NULL;   
	HACCESSOR     hAccessor              = DB_NULL_HACCESSOR;
	ULONG         cbRowSize;
	void *        pData                  = NULL;
	ULONG *       rgDispSize             = NULL;
	DBCOUNTITEM   cRowsObtained;
	HROW *        rghRows                = NULL;
	ULONG         iRow;
	LONG          cRows                  = MAX_ROWS;
	LONG          iRetCol                = -1;
	BOOL          fCanFetchBackwards;
	ULONG         iIndex;
	void *        pCurData;

	// Obtain the IRowset interface for use in fetching rows and data
	// See IRowset
	XCHECK_HR(hr = pUnkRowset->QueryInterface(
		IID_IRowset, (void**)&pIRowset));

	// Determine whether this rowset supports fetching data backwards;
	// we use this to determine whether the rowset can support moving
	// to the previous set of rows, described in more detail below
	GetProperty(pUnkRowset, IID_IRowset, DBPROP_CANFETCHBACKWARDS,
		DBPROPSET_ROWSET, &fCanFetchBackwards);

	// If the caller wants us to return the data for a particular column
	// from a user-selected row, we need to turn the column name into a
	// column ordinal.
	if( pwszColToReturn )
		CHECK_HR(hr = FindColumn(pUnkRowset, pwszColToReturn, &iRetCol));

	// Create an accessor. An accessor is basically a handle to a
	// collection of bindings that describes to the provider how to
	// copy (and convert, if necessary) column data into our buffer.
	// The accessor that this creates will bind all columns either as
	// DBTYPE_WSTR (a Unicode string) or as an ISequentialStream object
	// (used for BLOB data). This will also give us the size of the
	// row buffer that the accessor describes to the provider.
	CHECK_HR(hr = CreateAccessor(pUnkRowset, &hAccessor,
		&cBindings, &rgBindings, &cbRowSize));

	// Allocate enough memory to hold cRows rows of data; this is
	// where the actual row data from the provider will be placed.
	pData = CoTaskMemAlloc(cbRowSize * MAX_ROWS);
	CHECK_MEMORY(hr, pData);

	// Allocate memory for an array that we will use to calculate the
	// maximum display size used by each column in the current set of
	// rows.
	rgDispSize = (ULONG *)CoTaskMemAlloc(cBindings * sizeof(ULONG));
	CHECK_MEMORY(hr, rgDispSize);

	// Display the names of the rowset columns.
	CHECK_HR(hr = DisplayColumnNames(pIRowset, rgDispSize));

	// In this loop, we perform the following process:
	// - reset the maximum display size array
	// - try to get cRows row handles from the provider
	// - these handles are then used to actually get the row data from the
	//    provider copied into our allocated buffer
	// - calculate the maximum display size for each column
	// - release the row handles to the rows we obtained
	// - display the column names for the rowset
	// - display the row data for the rows that we fetched
	// - get user input
	// - free the provider-allocated row handle array
	// - repeat unless the user has chosen to quit or has selected a row
	while( hr == S_OK )
	{
		// Clear the maximum display size array.
		memset(rgDispSize, 0, cBindings * sizeof(ULONG));

		// Attempt to get cRows row handles from the provider.
		XCHECK_HR(hr = pIRowset->GetNextRows(
			DB_NULL_HCHAPTER,                      // hChapter
			0,                                     // lOffset
			cRows,                                 // cRows
			&cRowsObtained,                        // pcRowsObtained
			&rghRows                               // prghRows
			));

		// Loop over the row handles obtained from GetNextRows,
		// actually fetching the data for these rows into our buffer.
		for( iRow = 0; iRow < cRowsObtained; iRow++ )
		{
			// Find the location in our buffer where we want to place
			// the data for this row. Note that if we fetched rows
			// backwards (cRows < 0), the row handles obtained from the
			// provider are reversed from the order in which we want to
			// actually display the data on the screen, so we will
			// account for this. This ensures that the resulting order
			// of row data in the pData buffer matches the order we
			// wish to use to display the data.
			iIndex     = cRows > 0 ? iRow : cRowsObtained - iRow - 1;
			pCurData   = (BYTE*)pData + (cbRowSize * iIndex);

			// Get the data for this row handle. The provider will copy
			// (and convert, if necessary) the data for each of the
			// columns that are described in our Aaccessor into the given
			// buffer (pCurData).
			XCHECK_HR(hr = pIRowset->GetData(
				rghRows[iRow],                          // hRow
				hAccessor,                              // hAccessor
				pCurData                                // pData
				));

			// Update the maximum display size array, accounting for
			// this row.
			CHECK_HR(hr = UpdateDisplaySize(cBindings, rgBindings,
				pCurData, rgDispSize));
		}

		// If we obtained rows, release the row handles for the retrieved
		// rows and display the names of the rowset columns before we
		// display the data.
		if( cRowsObtained )
		{
			// Release the row handles that we obtained.
			XCHECK_HR(hr = pIRowset->ReleaseRows(
				cRowsObtained,                        // cRows
				rghRows,                              // rghRows
				NULL,                                 // rgRowOptions
				NULL,                                 // rgRefCounts
				NULL                                  // rgRowStatus
				));
		}

		// For each row that we obtained the data for, display this data.
		for( iRow = 0; iRow < cRowsObtained; iRow++ )
		{
			// Get a pointer to the data for this row.
			pCurData = (BYTE*)pData + (cbRowSize* iRow);

			// And display the row data.
			CHECK_HR(hr = DisplayRow(iRow, cBindings, rgBindings,
				pCurData, rgDispSize));
		}


		// Since we are allowing the provider to allocate the memory for
		// the row handle array, we will free this memory and reset the
		// pointer to NULL. If this is not NULL on the next call to
		// GetNextRows, the provider will assume that it points to an
		// allocated array of the required size (which may not be the case
		// if we obtained less than cRows rows from this last call to
		// GetNextRows).
		CoTaskMemFree(rghRows);
		rghRows = NULL;
	}

CLEANUP:
	FreeBindings(cBindings, rgBindings);
	CoTaskMemFree(rgDispSize);
	CoTaskMemFree(pData);
	if( pIRowset )
		pIRowset->Release();
	return hr;
}

/////////////////////////////////////////////////////////////////
// myUpdateDisplaySize
// Summary of Routines
//
// This function updates the rgDispSize array, keeping the
// maximum of the display size needed for the given data and
// the previous maximum size already in the array.
//
/////////////////////////////////////////////////////////////////
HRESULT UpdateDisplaySize(ULONG         cBindings,
						  DBBINDING *   rgBindings,
						  void *        pData,
						  ULONG *       rgDispSize )
{
	DBSTATUS      dwStatus;
	ULONG         cchLength;
	ULONG         iCol;

	// Loop through the bindings, comparing the size of each column
	// against the previously found maximum size for that column.
	for( iCol = 0; iCol < cBindings; iCol++ )
	{
		dwStatus = *(DBSTATUS *)((BYTE *)pData + rgBindings[iCol].obStatus);
		cchLength = ((*(ULONG *)((BYTE *)pData + rgBindings[iCol].obLength))
			/ sizeof(WCHAR));

		// The length that we need to display depends on the status
		// of this column and generally on the data in the column.
		switch( dwStatus )
		{
		case DBSTATUS_S_ISNULL:
			cchLength = 6;                              // "(null)"
			break;

		case DBSTATUS_S_TRUNCATED:
		case DBSTATUS_S_OK:
		case DBSTATUS_S_DEFAULT:
			if( rgBindings[iCol].wType == DBTYPE_IUNKNOWN )
				cchLength = 2 + 8;                      // "0x%08lx"

			// Ensure that the length is at least the minimum
			// display size.
			cchLength = max(cchLength, MIN_DISPLAY_SIZE);
			break;

		default:
			cchLength = 14;                        // "(error status)"
			break;
		}

		if( rgDispSize[iCol] < cchLength )
			rgDispSize[iCol] = cchLength;
	}

	return S_OK;
}

/////////////////////////////////////////////////////////////////
// 函数: FindColumn
//
// 查找指定(pwszName)列的索引.
//
/////////////////////////////////////////////////////////////////
HRESULT FindColumn(IUnknown *       pUnkRowset, 
				   LPCWSTR          pwszName,
				   LONG *           plIndex )
{
	HRESULT          hr;
	IColumnsInfo *   pIColumnsInfo    = NULL;
	ULONG            cColumns;
	DBCOLUMNINFO *   rgColumnInfo     = NULL;
	OLECHAR *        pStringsBuffer   = NULL;
	ULONG            iCol;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -