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

📄 rowset.cpp

📁 oledb的例子
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		pIColumnsInfo->Release();

	return hr;

}

/////////////////////////////////////////////////////////////////
// myCreateAccessor
//
// This function takes an IUnknown pointer for a rowset object
// and creates an accessor that describes the layout of the
// buffer we will use when we fetch data. The provider will fill
// this buffer according to the description contained in the
// accessor that we will create here.
//
/////////////////////////////////////////////////////////////////

HRESULT myCreateAccessor(	IUnknown *     pUnkRowset, 
													HACCESSOR *    phAccessor, 
													ULONG *        pcBindings, 
													DBBINDING **   prgBindings, 
													ULONG *        pcbRowSize
													)

{
	HRESULT        hr;
	IAccessor *    pIAccessor = NULL;

	// An accessor is basically a handle to a collection of bindings.
	// To create the accessor, we need to first create an array of
	// bindings for the columns in the rowset.
	CHECK_HR(hr = mySetupBindings(pUnkRowset, pcBindings, prgBindings, pcbRowSize));

	// Now that we have an array of bindings, tell the provider to
	// create the accessor for those bindings. We get back a handle
	// to this accessor, which we will use when fetching data.
	XCHECK_HR(hr = pUnkRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor));
	XCHECK_HR(hr = pIAccessor->CreateAccessor(
										DBACCESSOR_ROWDATA,                  // dwAccessorFlags
										*pcBindings,                         // cBindings
										*prgBindings,                        // rgBindings
										0,                                   // cbRowSize
										phAccessor,                          // phAccessor
										NULL                                 // rgStatus
										));

CLEANUP:
	if( pIAccessor )
		pIAccessor->Release();

	return hr;

}

/////////////////////////////////////////////////////////////////
// myDisplayRowset
//
// This function will display data from a rowset object and will
// allow the user to perform basic navigation of the rowset.
//
// The function takes a pointer to a rowset object's IUnknown
// and, optionally, the name of a column and a buffer that will
// receive the value of that column when the user selects a row.
//
/////////////////////////////////////////////////////////////////

HRESULT myDisplayRowset(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;
	ULONG         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
	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
	myGetProperty(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 = myFindColumn(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 = myCreateAccessor(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);
	// 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 = myUpdateDisplaySize(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
											));
			// Display the names of the rowset columns
			CHECK_HR(hr = myDisplayColumnNames(pIRowset, rgDispSize));
		}
		// 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 = myDisplayRow(iRow, cBindings, rgBindings, pCurData, rgDispSize));
		}
		// Allow the user to navigate the rowset. This displays the 
		// appropriate prompts, gets the user's input, may call 
		// IRowset::RestartPosition, and may copy data from a selected row 
		// to the selection buffer, if so directed. This will return S_OK 
		// if the user asked for more rows, S_FALSE if the user selected a 
		// row, or E_FAIL if the user quits.	
		hr = myInteractWithRowset(
						pIRowset,                // IRowset pointer, for RestartPosition
						&cRows,                  // updated with fetch direction value
						cRowsObtained,           // to indicate selection range
						fCanFetchBackwards,      // whether [P]revious is supported
						pData,                   // data pointer for copying selection
						cbRowSize,               // size of rows for copying selection
						iRetCol >= 0 ?           // bindings for the selection column,
						&rgBindings[iRetCol] :   // or NULL if no selection column
						NULL,
						cchBuffer,             // size of the selection buffer
						pwszBuffer);             // pointer to the selection buffer

		// 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:
	myFreeBindings(cBindings, rgBindings);
	CoTaskMemFree(rgDispSize);
	CoTaskMemFree(pData);
	if( pIRowset )
		pIRowset->Release();

	return hr;
}

/////////////////////////////////////////////////////////////////
// myInteractWithRowset
//
// This function allows the user to interact with the rowset. It
// prompts the user appropriately, gets the user's input, may
// call IRowset::RestartPosition if the user requests a restart,
// and will copy data from a selected row to the selection
// buffer.
//
/////////////////////////////////////////////////////////////////
HRESULT myInteractWithRowset(	IRowset *     pIRowset,
															LONG *        pcRows,
															ULONG         cRowsObtained,
															BOOL          fCanFetchBackwards,
															void *        pData,
															ULONG         cbRowSize,
															DBBINDING *   pBinding,
															ULONG         cchBuffer,
															LPWSTR        pwszBuffer
															)
{
	HRESULT       hr = S_OK;
	CHAR          ch;

	// Let the user know if no rows were fetched
	if( !cRowsObtained )
		printf(	"\n*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n" \
						"* *\n" \
						"* No rows obtained on this fetch! *\n" \
						"* *\n" \
						"*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");
	// Print navigation options
	if( fCanFetchBackwards )
		printf("\n[P]revious; [N]ext; [R]estart; ");
	else
		printf("\n[N]ext; [R]estart; ");

	// Print selection options
	if( cRowsObtained && pwszBuffer && pBinding )
		printf("[0]-[%d] for a row; ", cRowsObtained - 1);

	// User can always quit the program
	printf("[Q]uit? ");

	// Get the user's input

	while( TRUE )
	{
		// Get a character from the console
		ch = myGetChar();
		// Look for one of the allowed options; if not found, go
		// back around and wait for another input from the user
		// If we're looking for a row selection, allow the user to select
		// a row that we fetched, and then copy the data from the requested
		// column into the selection buffer we were passed
		if( pwszBuffer && pBinding && ch >= '0' && ch < (int)('0' + cRowsObtained) )
		{
			// Save the data for the selected row
			ULONG nSelection = ch - '0';
			_snwprintf(pwszBuffer, cchBuffer, L"%s", 
				(WCHAR *)((BYTE *)pData + cbRowSize * nSelection + 
				pBinding->obValue));
			pwszBuffer[cchBuffer] = L'\0';
			hr = S_FALSE;
		}
		// If the provider supports fetching backwards, set *pcRows
		// to -MAX_ROWS. When GetNextRows is called with this value,
		// it will fetch rows backwards from the current position
		// until it fetches MAX_ROWS rows or hits the end of the rowset.
		else if( fCanFetchBackwards && ch == 'p' )
		{
			// Fetch backwards
			*pcRows = -MAX_ROWS;
		}

		// Set *pcRows so that the next call to GetNextRows fetches
		// MAX_ROWS rows forward from the current position
		else if( ch == 'n' )
		{
			// Fetch forward
			*pcRows = MAX_ROWS;
		}

		// Call IRowset::RestartPosition, and fetch the first MAX_ROWS
		// rows of the rowset forward from there
		else if( ch == 'r' )
		{
			// RestartPosition
			*pcRows = MAX_ROWS;
			XCHECK_HR(hr = pIRowset->RestartPosition(DB_NULL_HCHAPTER));
			// Restarting a command may return the DB_S_COMMANDREEXECUTED
			// warning. If this happens, we still want the caller to
			// continue to display data, so we will reset the result code
			// to S_OK.
			hr = S_OK;
		}

		// Quit the program
		else if( ch == 'q' )
		{
			hr = E_FAIL;
		}

		// Invalid option; go back up and get another character from the
		// user
		else
		{
			continue;
		}

		// Echo the character and stop waiting for input
		printf("%c\n", ch);
		break;

	}

CLEANUP:

	return hr;

⌨️ 快捷键说明

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