📄 s15_03.cpp
字号:
// Get the IColumnsInfo interface.
// See IColumnsInfo
XCHECK_HR(hr = pUnkRowset->QueryInterface(
IID_IColumnsInfo, (void**)&pIColumnsInfo));
// Get the columns information.
XCHECK_HR(hr = pIColumnsInfo->GetColumnInfo(
&cColumns, // pcColumns
&rgColumnInfo, // prgColumnInfo
&pStringsBuffer // ppStringBuffer
));
// Assume that we'll find the column.
hr = S_OK;
// Search for the column we need.
for( iCol = 0; iCol < cColumns; iCol++ )
{
// If the column name matches, we've found the column....
if( rgColumnInfo[iCol].pwszName &&
!wcscmp(pwszName, rgColumnInfo[iCol].pwszName) )
{
*plIndex = iCol;
goto CLEANUP;
}
}
// If we didn't find the column, we'll return S_FALSE.
hr = S_FALSE;
CLEANUP:
CoTaskMemFree(rgColumnInfo);
CoTaskMemFree(pStringsBuffer);
if( pIColumnsInfo )
pIColumnsInfo->Release();
return hr;
}
/////////////////////////////////////////////////////////////////
// 函数: DisplayColumnNames
//
// 显示行集的列名.
//
/////////////////////////////////////////////////////////////////
HRESULT DisplayColumnNames(IUnknown * pUnkRowset,
ULONG * rgDispSize )
{
HRESULT hr;
IColumnsInfo * pIColumnsInfo = NULL;
ULONG cColumns;
DBCOLUMNINFO * rgColumnInfo = NULL;
LPOLESTR pStringsBuffer = NULL;
WCHAR wszColumn[MAX_DISPLAY_SIZE + 1];
LPWSTR pwszColName;
ULONG iCol;
ULONG cSpaces;
ULONG iSpace;
// Get the IColumnsInfo interface for the rowset.
// See IColumnsInfo
XCHECK_HR(hr = pUnkRowset->QueryInterface(
IID_IColumnsInfo, (void**)&pIColumnsInfo));
// Get the columns information.
XCHECK_HR(hr = pIColumnsInfo->GetColumnInfo(
&cColumns, // pcColumns
&rgColumnInfo, // prgColumnInfo
&pStringsBuffer // ppStringBuffer
));
// Display the title of the row index column.
wprintf(L" Row | ");
// Display all column names.
for( iCol = 0; iCol < cColumns; iCol++ )
{
pwszColName = rgColumnInfo[iCol].pwszName;
// If the column name is NULL, we'll use a default string.
if( !pwszColName )
{
// Is this the bookmark column?
if( !rgColumnInfo[iCol].iOrdinal )
pwszColName = L"Bmk";
else
pwszColName = L"(null)";
}
// Ensure that the name is no longer than MAX_DISPLAY_SIZE.
wcsncpy(wszColumn, pwszColName, MAX_DISPLAY_SIZE);
wszColumn[min(rgDispSize[iCol], MAX_DISPLAY_SIZE)] = L'\0';
// Figure out how many spaces we need to print after
// this column name.
cSpaces = min(rgDispSize[iCol], MAX_DISPLAY_SIZE) - wcslen(wszColumn);
// Print the column name.
wprintf(L"%s", wszColumn);
// Now print any spaces necessary to align this column.
for(iSpace = 0; iSpace < cSpaces; iSpace++ )
putch(' ');
// Now end the column with a separator marker if necessary.
if( iCol < cColumns - 1 )
wprintf(L" | ");
}
// Done with the header, so print a new line.
wprintf(L"\n");
CLEANUP:
CoTaskMemFree(rgColumnInfo);
CoTaskMemFree(pStringsBuffer);
if( pIColumnsInfo )
pIColumnsInfo->Release();
return hr;
}
/////////////////////////////////////////////////////////////////
// 函数: DisplayRow
//
// 显示行集行数据.
//
/////////////////////////////////////////////////////////////////
HRESULT DisplayRow(ULONG iRow,
ULONG cBindings,
DBBINDING * rgBindings,
void * pData,
ULONG * rgDispSize )
{
HRESULT hr = S_OK;
WCHAR wszColumn[MAX_DISPLAY_SIZE + 1];
DBSTATUS dwStatus;
ULONG ulLength;
void * pvValue;
ULONG iCol;
ULONG cbRead;
ISequentialStream * pISeqStream = NULL;
ULONG cSpaces;
ULONG iSpace;
// Display the row number.
wprintf(L" [%d] | ", iRow);
// For each column that we have bound, display the data.
for( iCol = 0; iCol < cBindings; iCol++ )
{
// We have bound status, length, and the data value for all
// columns, so we know that these can all be used.
dwStatus = *(DBSTATUS *)((BYTE *)pData + rgBindings[iCol].obStatus);
ulLength = *(ULONG *)((BYTE *)pData + rgBindings[iCol].obLength);
pvValue = (BYTE *)pData + rgBindings[iCol].obValue;
// Check the status of this column. This decides
// exactly what will be displayed for the column.
switch( dwStatus )
{
// The data is NULL, so don't try to display it.
case DBSTATUS_S_ISNULL:
wcscpy(wszColumn, L"(null)");
break;
// The data was fetched, but may have been truncated.
// Display string data for this column to the user.
case DBSTATUS_S_TRUNCATED:
case DBSTATUS_S_OK:
case DBSTATUS_S_DEFAULT:
{
// We have bound the column either as a Unicode string
// (DBTYPE_WSTR) or as an ISequentialStream object
// (DBTYPE_IUNKNOWN), and we have to do different processing
// for each one of these possibilities.
switch( rgBindings[iCol].wType )
{
case DBTYPE_WSTR:
{
// Copy the string data.
wcsncpy(wszColumn, (WCHAR *)pvValue, MAX_DISPLAY_SIZE);
wszColumn[MAX_DISPLAY_SIZE - 1] = L'\0';
break;
}
case DBTYPE_IUNKNOWN:
{
// We've bound this as an ISequentialStream object,
// therefore the data in our buffer is a pointer
// to the object's ISequentialStream interface.
pISeqStream = *(ISequentialStream**)pvValue;
// We call ISequentialStream::Read to read bytes from
// the stream blindly into our buffer, simply as a
// demonstration of ISequentialStream. To display the
// data properly, the native provider type of this
// column should be accounted for; it could be
// DBTYPE_WSTR, in which case this works, or it could
// be DBTYPE_STR or DBTYPE_BYTES, in which case this
// won't display the data correctly.
CHECK_HR(hr = pISeqStream->Read(
wszColumn, // pBuffer
MAX_DISPLAY_SIZE, // cBytes
&cbRead // pcBytesRead
));
// Since streams don't provide NULL-termination,
// we'll NULL-terminate the resulting string ourselves.
wszColumn[cbRead / sizeof(WCHAR)] = L'\0';
// Release the stream object, now that we're done.
pISeqStream->Release();
pISeqStream = NULL;
break;
}
}
break;
}
// This is an error status, so don't try to display the data.
default:
wcscpy(wszColumn, L"(error status)");
break;
}
// Determine how many spaces we need to add after displaying this
// data to align it with this column in other rows.
cSpaces = min(rgDispSize[iCol], MAX_DISPLAY_SIZE) - wcslen(wszColumn);
// Print the column data.
wprintf(L"%s", wszColumn);
// Now print any spaces necessary.
for(iSpace = 0; iSpace < cSpaces; iSpace++ )
putch(' ');
// Now end the column with a separator marker if necessary.
if( iCol < cBindings - 1 )
wprintf(L" | ");
}
CLEANUP:
if( pISeqStream )
pISeqStream->Release();
// Print the row separator.
wprintf(L"\n");
return hr;
}
/////////////////////////////////////////////////////////////////
// 函数: FreeBindings
//
// 释放绑定数组和这个结构中分配的任何内存.
//
/////////////////////////////////////////////////////////////////
void FreeBindings(ULONG cBindings,
DBBINDING * rgBindings )
{
ULONG iBind;
// Free any memory used by DBOBJECT structures in the array.
for( iBind = 0; iBind < cBindings; iBind++ )
CoTaskMemFree(rgBindings[iBind].pObject);
// Now free the bindings array itself.
CoTaskMemFree(rgBindings);
}
/////////////////////////////////////////////////////////////////
// 函数: CreateCommand
//
// 这个函数试图用指定的会话对象(IUnknown接口指针)的IDBCreateCommand接口
// 创建一个命令对象. 因为这个接口是可选的, 所以有可能失败.
//
/////////////////////////////////////////////////////////////////
HRESULT CreateCommand(IUnknown *pUnkSession,
IUnknown **ppUnkCommand)
{
HRESULT hr;
IDBCreateCommand * pIDBCreateCommand = NULL;
// Attempt to create a command object from the session object.
XCHECK_HR(hr = pUnkSession->QueryInterface(
IID_IDBCreateCommand, (void**)&pIDBCreateCommand));
XCHECK_HR(hr = pIDBCreateCommand->CreateCommand(
NULL, // pUnkOuter
IID_ICommand, // riid
ppUnkCommand)); // ppCommand
CLEANUP:
if( pIDBCreateCommand )
pIDBCreateCommand->Release();
return hr;
}
/////////////////////////////////////////////////////////////////
// 函数: ExecuteCommand
//
// 这个函数接受一个命令对象的IUnknown接口指针, 并通过下面这些
// 步骤来创建行集对象:
// - 设置命令对象的属性; 这些属性将由提供程序用于由这个命令对象创建的行集.
// - 设置命令对象的命令文本.
// - 执行命令来创建一个新的行集对象.
//
/////////////////////////////////////////////////////////////////
HRESULT ExecuteCommand(IUnknown* pUnkCommand,
WCHAR* pwszCommandText,
ULONG cPropSets,
DBPROPSET* rgPropSets,
IUnknown** ppUnkRowset)
{
HRESULT hr;
ICommandText * pICommandText = NULL;
ICommandProperties * pICommandProperties = NULL;
// Set the properties on the command object.
XCHECK_HR(hr = pUnkCommand->QueryInterface(
IID_ICommandProperties, (void**)&pICommandProperties));
XCHECK_HR(hr = pICommandProperties->SetProperties(cPropSets,
rgPropSets));
// Set the text for this command, using the default command text
// dialect. All providers that support commands must support this
// dialect, and providers that support SQL must be able to recognize
// an SQL command as SQL when this dialect is specified.
XCHECK_HR(hr = pUnkCommand->QueryInterface(
IID_ICommandText, (void**)&pICommandText));
XCHECK_HR(hr = pICommandText->SetCommandText(
DBGUID_DEFAULT, // guidDialect
pwszCommandText)); // pwszCommandText
// And execute the command. Note that the user could have
// entered a non-row returning command, so we will check for
// that and return failure to prevent the display of the
// nonexistent rowset by the caller.
XCHECK_HR(hr = pICommandText->Execute(
NULL, // pUnkOuter
IID_IRowset, // riid
NULL, // pParams
NULL, // pcRowsAffected
ppUnkRowset)); // ppRowset
if( !*ppUnkRowset )
{
printf("\nThe command executed successfully, but did not " \
"return a rowset.\nNo rowset will be displayed.\n");
hr = E_FAIL;
}
CLEANUP:
if( pICommandText )
pICommandText->Release();
if( pICommandProperties )
pICommandProperties->Release();
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -