STEP1.CPP

//----------------------------------------------------------------------------- 
// Microsoft OLE DB TABLECOPY Sample
// Copyright (C) 1996 By Microsoft Corporation.
//
// @doc
//
// @module STEP1.CPP
//
//-----------------------------------------------------------------------------

/////////////////////////////////////////////////////////////////////
// Includes
//
/////////////////////////////////////////////////////////////////////
#include "wizard.h"
#include "common.h"
#include "table.h"


/////////////////////////////////////////////////////////////////////
// CS1Dialog::CS1Dialog
//
/////////////////////////////////////////////////////////////////////
CS1Dialog::CS1Dialog(HWND hWnd, HINSTANCE hInst, CTableCopy* pCTableCopy)
: CDialog(hWnd, hInst)
{
ASSERT(pCTableCopy);
m_pCTableCopy = pCTableCopy;
}


/////////////////////////////////////////////////////////////////////
// CS1Dialog::~CS1Dialog
//
/////////////////////////////////////////////////////////////////////
CS1Dialog::~CS1Dialog()
{
}


/////////////////////////////////////////////////////////////////////////////
// ULONG CS1Dialog::Display
//
/////////////////////////////////////////////////////////////////////////////
ULONG CS1Dialog::Display()
{
return DialogBoxParam(m_hInst, MAKEINTRESOURCE(IDD_FROM_INFO), NULL, DlgProc, (LPARAM)this);
}


/////////////////////////////////////////////////////////////////////
// CS1Dialog::DlgProc
//
/////////////////////////////////////////////////////////////////////
BOOL WINAPI CS1Dialog::DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
{
//Store the "this" pointer, since this is a static method
CS1Dialog* pThis = (CS1Dialog*)lParam;
SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);

//On INIT we know we have a valid hWnd to store
pThis->m_hWnd = hWnd;
CTable* pCFromTable = pThis->m_pCTableCopy->m_pCFromTable;

//Init all controls to the default values
pThis->InitControls();

// If there is a source to look at, Display the table list
if(pCFromTable->IsConnected())
pThis->ResetTableList(GetDlgItem(hWnd, IDL_TABLES), GetDlgItem(hWnd, IDL_COLUMNS));

pThis->RefreshControls();
CenterDialog(hWnd);
return HANDLED_MSG;
}

case WM_COMMAND:
{
//Obtain the "this" pointer
CS1Dialog* pThis = (CS1Dialog*)GetWindowLong(hWnd, GWL_USERDATA);

CTable* pCFromTable = pThis->m_pCTableCopy->m_pCFromTable;
CTable* pCToTable = pThis->m_pCTableCopy->m_pCToTable;

// First check for regular command ids
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDB_FROM_CONNECT:
{
//Try to connect to the DataSource
if(pCFromTable->Connect(hWnd))
pThis->ResetTableList(GetDlgItem(hWnd, IDL_TABLES), GetDlgItem(hWnd, IDL_COLUMNS));

pThis->RefreshControls();
return HANDLED_MSG;
}

case IDC_TABLES:
case IDC_VIEWS:
case IDC_SYSTABLES:
case IDC_SYNONYMS:
{
//Reset the available table list, with the new restrictions
pThis->ResetTableList(GetDlgItem(hWnd, IDL_TABLES), GetDlgItem(hWnd, IDL_COLUMNS));

//refresh any controls
pThis->RefreshControls();
return HANDLED_MSG;
}

case IDOK:
pThis->GetTableColInfo();

case IDCANCEL:
EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam));
return HANDLED_MSG;
}

// Now look for notification messages
switch (GET_WM_COMMAND_CMD(wParam, lParam))
case LBN_SELCHANGE:
{
// A table change requires a new list of columns
if(IDL_TABLES == GET_WM_COMMAND_ID(wParam, lParam))
{
WCHAR wszName[MAX_NAME_LEN];

//Obtain the TableName includes (username.tablename)
WPARAM nRow = (WPARAM)SendDlgItemMessage(hWnd, IDL_TABLES, LB_GETCURSEL, 0, 0L);
wSendMessage(GetDlgItem(hWnd, IDL_TABLES), LB_GETTEXT, (WPARAM)nRow, wszName);

//Only Reset if selected a different TableName
if(wcscmp(wszName, pCFromTable->m_wszQualTableName)!=0)
{
//Extract just the tablename
ULONG ulTableOffset = SendDlgItemMessage(hWnd, IDL_TABLES, LB_GETITEMDATA, nRow, 0L);

//Qualified Name
wcscpy(pCFromTable->m_wszQualTableName, wszName);
wcscpy(pCFromTable->m_wszTableName, wszName + ulTableOffset);

//Schema Name
wcsncpy(pCFromTable->m_wszSchemaName, wszName, ulTableOffset);
pCFromTable->m_wszSchemaName[ulTableOffset-1] = L'\0';

//Free the current columns list, since the new
//table will have diffent columns
pCFromTable->m_cColumns = 0;
SAFE_FREE(pCFromTable->m_rgColDesc);

//Reset the column list, since we have a new table
pThis->ResetColInfo(GetDlgItem(hWnd, IDL_COLUMNS));

//Reset the index list, since we have a new table
pCFromTable->m_cIndexes = 0;
SAFE_FREE(pCFromTable->m_rgIndexInfo);

//Reset the "To" table, since we have a new table
pCToTable->m_wszTableName[0] = L'\0';
}
}

pThis->RefreshControls();
return HANDLED_MSG;
}
}
}

return UNHANDLED_MSG;
}


/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::InitControls
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::InitControls()
{
//Setup defaults
CheckDlgButton(m_hWnd, IDC_TABLES,m_pCTableCopy->m_dwShowTypes & SHOW_TABLES? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(m_hWnd, IDC_VIEWS,m_pCTableCopy->m_dwShowTypes & SHOW_VIEWS? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(m_hWnd, IDC_SYSTABLES,m_pCTableCopy->m_dwShowTypes & SHOW_SYSTABLES? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(m_hWnd, IDC_SYNONYMS,m_pCTableCopy->m_dwShowTypes & SHOW_SYNONYMS? BST_CHECKED : BST_UNCHECKED);

//Set Horizontal ScrollBar dimensions
SendDlgItemMessage(m_hWnd, IDL_TABLES, LB_SETHORIZONTALEXTENT, (WPARAM)120*4, (LPARAM)0);
SendDlgItemMessage(m_hWnd, IDL_COLUMNS, LB_SETHORIZONTALEXTENT, (WPARAM)120*4, (LPARAM)0);

return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::RefreshControls
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::RefreshControls()
{
// Must have a connection to edit other controls
BOOL fConnected = m_pCTableCopy->m_pCFromTable->IsConnected();
CDataSource* pCDataSource = m_pCTableCopy->m_pCFromTable->m_pCDataSource;

//Enable dialog items, only if connected
EnableWindow(GetDlgItem(m_hWnd, IDC_SHOW_TYPES),fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDC_TABLES),fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDC_VIEWS),fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDC_SYSTABLES),fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDC_SYNONYMS),fConnected);

EnableWindow(GetDlgItem(m_hWnd, IDT_TABLE_LIST),fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDT_COLUMN_LIST),fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDL_TABLES),fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDL_COLUMNS),fConnected);

//Save CheckBoxes status
m_pCTableCopy->m_dwShowTypes = SHOW_NONE;
if(IsDlgButtonChecked(m_hWnd, IDC_TABLES) == BST_CHECKED)
m_pCTableCopy->m_dwShowTypes |= SHOW_TABLES;
if(IsDlgButtonChecked(m_hWnd, IDC_VIEWS) == BST_CHECKED)
m_pCTableCopy->m_dwShowTypes |= SHOW_VIEWS;
if(IsDlgButtonChecked(m_hWnd, IDC_SYSTABLES) == BST_CHECKED)
m_pCTableCopy->m_dwShowTypes |= SHOW_SYSTABLES;
if(IsDlgButtonChecked(m_hWnd, IDC_SYNONYMS) == BST_CHECKED)
m_pCTableCopy->m_dwShowTypes |= SHOW_SYNONYMS;

//If there is at a table selected and at least 1 columns select
BOOL fColumnsSelected = (fConnected &&
SendDlgItemMessage(m_hWnd, IDL_COLUMNS, LB_GETSELCOUNT, 0, 0L));

//Enable OK/Next if there is at least 1 columns selected
EnableWindow(GetDlgItem(m_hWnd, IDOK),fColumnsSelected);

// Show user the connection string
if(fConnected)
{
wSetDlgItemText(m_hWnd, IDT_CONNECT, wsz_CONNECT_STRING_,
pCDataSource->m_pwszDataSource,
pCDataSource->m_pwszUserName,
pCDataSource->m_pwszPassword,
pCDataSource->m_pwszDBMS,
pCDataSource->m_pwszDBMSVer);
}
else
{
wSetDlgItemText(m_hWnd, IDT_CONNECT, wsz_NOT_CONNECTED);
wSetDlgItemText(m_hWnd, IDT_PROVIDER, wsz_NO_PROVIDER);
}

if(pCDataSource->m_pwszProvider)
{
wSetDlgItemText(m_hWnd, IDT_PROVIDER, wsz_PROVIDER_STRING_,
pCDataSource->m_pwszProvider,
pCDataSource->m_pwszProviderVer,
pCDataSource->m_pwszProviderOLEDBVer);
}
else
{
wSetDlgItemText(m_hWnd, IDT_PROVIDER, wsz_NO_PROVIDER);
}

return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::GetTableColInfo
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::GetTableColInfo()
{
CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;

// Initialize working variables
HWND hWndCol = GetDlgItem(m_hWnd, IDL_COLUMNS);

// Get the list of selected items
LONG cColumns = SendDlgItemMessage(m_hWnd, IDL_COLUMNS, LB_GETSELCOUNT, 0, 0L);
LONG*rgColumns = NULL;
SAFE_ALLOC(rgColumns, LONG, cColumns);
SendMessage(hWndCol, LB_GETSELITEMS, (WPARAM)cColumns, (LPARAM)rgColumns);

//Allocate space for the ColNames
SAFE_FREE(pCFromTable->m_rgColDesc);
SAFE_ALLOC(pCFromTable->m_rgColDesc, COLDESC, cColumns);
memset(pCFromTable->m_rgColDesc, 0, cColumns*sizeof(COLDESC));
pCFromTable->m_cColumns = cColumns;

if(LB_ERR != SendMessage(hWndCol, LB_GETSELITEMS, (WPARAM)cColumns, (LPARAM)rgColumns))
{
for(LONG i=0; i<cColumns; i++)
{
//Obtain the entire ColumnName with TypeInfo
wSendMessage(hWndCol, LB_GETTEXT, (WPARAM)rgColumns[i], pCFromTable->m_rgColDesc[i].wszColName);

//Obtain the ending point for just the table name
LONG lColumnOffset = SendMessage(hWndCol, LB_GETITEMDATA, (WPARAM)rgColumns[i], (LPARAM)0L);
ASSERT(lColumnOffset>=0 && lColumnOffset<MAX_NAME_LEN);

//End the ColName with an EOL, don't include the typeinfo
pCFromTable->m_rgColDesc[i].wszColName[lColumnOffset] = EOL;
}
}

CLEANUP:
SAFE_FREE(rgColumns);
return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::ResetTableList
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::ResetTableList(HWND hWndTable, HWND hWndCol)
{
HRESULT hr;

DWORDdwTableLoc;
LONGiRow;

WCHARwszTypes[MAX_NAME_LEN];
WCHARwszBuffer[MAX_NAME_LEN*2];
SCHEMATABLESSchemaTables;

IDBSchemaRowset* pIDBSchemaRowset = NULL;
IRowset* pIRowset = NULL;
IAccessor* pIAccessor = NULL;

//get the data
HROW*rghRows = NULL;
ULONGi,cRowsObtained = 0;

HACCESSOR hAccessor = DB_NULL_HACCESSOR;
Busy();

//Use the passed in Session interface
CTable*pCFromTable = m_pCTableCopy->m_pCFromTable;
IDBCreateCommand* pIDBCreateCommand = pCFromTable->m_pCDataSource->m_pIDBCreateCommand;

// Figure out types to enumrate based on options
SendMessage(hWndTable, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0L);
GetTypes(wszTypes);

//set up the restrictions
const ULONG cRestrictions = 4;
VARIANTrgRestrictions[cRestrictions];

//Init the restrictions
InitVariants(cRestrictions, rgRestrictions);

// Bind the user and table name for the list
const ULONG cBindings = 2;
const DBBINDING rgBindings[cBindings] = {
2,
offsetof(SCHEMATABLES, wszUserName),// offset of value in consumers buffer
0,// offset of length
0,// offset of status
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies Value is bound only
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
MAX_NAME_LEN,// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_WSTR, // data type indicator
0,// precision
0, // scale


3, // ordinal
offsetof(SCHEMATABLES, wszTableName),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies Value only
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,// input param
MAX_NAME_LEN,// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_WSTR, // data type indicator
0,// precision
0, // scale

};

//Setup the restrictions
rgRestrictions[0].vt = VT_BSTR;
SAFE_SYSALLOC(rgRestrictions[0].bstrVal, pCFromTable->m_pCDataSource->m_pwszCatalog);
rgRestrictions[1].vt = VT_EMPTY;
rgRestrictions[2].vt = VT_EMPTY;
rgRestrictions[3].vt = VT_BSTR;
SAFE_SYSALLOC(rgRestrictions[3].bstrVal, wszTypes);

//get IDBSchemaRowset interface
XTESTC(hr = pIDBCreateCommand->QueryInterface(IID_IDBSchemaRowset,(void**)&pIDBSchemaRowset));

//GetRowset
//DBSCHEMA_TABLES is required a SCHEMA
XTESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_TABLES, cRestrictions, rgRestrictions,
IID_IRowset, 0, NULL,(IUnknown **)&pIRowset));

XTESTC(hr = pIRowset->QueryInterface(IID_IAccessor, (void **)&pIAccessor));

//Create the Accessor
XTESTC(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, rgBindings, 0, &hAccessor, NULL));


//Grab all the rows
while(TRUE)
{
hr = pIRowset->GetNextRows(NULL, 0, MAX_BLOCK_SIZE, &cRowsObtained, &rghRows);
if(FAILED(hr) || cRowsObtained==0)
break;

//Loop over the rows retrived
for (i=0; i<cRowsObtained; i++)
{
//Reset the SchemaTables
memset(&SchemaTables, 0, sizeof(SCHEMATABLES));

//Get the Data
XTESTC(hr = pIRowset->GetData(rghRows[i], hAccessor, (void *)&SchemaTables));

// If there is a user, format buffer in a familiar way
if(SchemaTables.wszUserName[0])
{
//QualififedTableName = "dbo.authors"
swprintf(wszBuffer, L"%s%s%s", SchemaTables.wszUserName, pCFromTable->m_wszIDSeperator, SchemaTables.wszTableName);
iRow = wSendMessage(hWndTable, LB_ADDSTRING, (WPARAM)0, wszBuffer);
dwTableLoc = wcslen(SchemaTables.wszUserName) + wcslen(pCFromTable->m_wszIDSeperator);
}
else
{
//QualififedTableName = "authors"
iRow = wSendMessage(hWndTable, LB_ADDSTRING, (WPARAM)0, SchemaTables.wszTableName);
dwTableLoc = 0;
}

// Store the offset of the table name with the item, so that we know
// where to start translating later.
SendMessage(hWndTable, LB_SETITEMDATA, (WPARAM)iRow, (LPARAM)dwTableLoc);
}

//Release the rows obtained
XTESTC(hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL));
SAFE_FREE(rghRows);
}

// If there was a previous selection, select it again on Back
if(pCFromTable->m_wszQualTableName[0])
{
LONGlFoundTable;

lFoundTable = wSendMessage(hWndTable, LB_FINDSTRINGEXACT,
(WPARAM)0, pCFromTable->m_wszQualTableName);

// If there was a selection, select it now
if(lFoundTable != LB_ERR)
{
SendMessage(hWndTable, LB_SETCURSEL, (WPARAM)lFoundTable, (LPARAM)0L);
ResetColInfo(hWndCol);
}
else
{
//else we need to clear the columns list
SendMessage(hWndCol, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0L);
}
}

Busy();


CLEANUP:
//Free Restrictions
FreeVariants(cRestrictions, rgRestrictions);

if(hAccessor && pIAccessor)
XTEST(pIAccessor->ReleaseAccessor(hAccessor,NULL));

SAFE_RELEASE(pIDBSchemaRowset);
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIAccessor);

SAFE_FREE(rghRows);
return hr==S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::ResetColInfo
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::ResetColInfo(HWND hWndCol)
{
HRESULT hr;

WCHARwszBuffer[MAX_NAME_LEN];
SCHEMACOLUMNSSchemaColumns;

IDBSchemaRowset* pIDBSchemaRowset = NULL;
IRowset* pIRowset = NULL;
IAccessor* pIAccessor = NULL;

HACCESSOR hAccessor = DB_NULL_HACCESSOR;

HROW*rghRows = NULL;
ULONGi,cRowsObtained = 0;
Busy();

//Use the passed in Session interface
//Use the passed in Session interface
CTable*pCFromTable = m_pCTableCopy->m_pCFromTable;
IDBCreateCommand* pIDBCreateCommand = pCFromTable->m_pCDataSource->m_pIDBCreateCommand;

// Get a list of columns based on the selected table
SendMessage(hWndCol, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0L);

//set up the restrictions
const ULONG cRestrictions = 4;
VARIANTrgRestrictions[cRestrictions];

InitVariants(cRestrictions, rgRestrictions);

// Bind the user and table name for the list
const ULONG cBindings = 9;
const DBBINDING rgBindings[cBindings] =
{
4,
offsetof(SCHEMACOLUMNS, wszColName),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
MAX_NAME_LEN,// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_WSTR, // data type indicator
0,// precision
0, // scale

5,
offsetof(SCHEMACOLUMNS, guidCol),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(GUID),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_GUID, // data type indicator
0,// precision
0, // scale

7,
offsetof(SCHEMACOLUMNS, iOrdinal),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(ULONG),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_UI4, // data type indicator
0,// precision
0, // scale

10,
offsetof(SCHEMACOLUMNS, dwFlags),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(DBCOLUMNFLAGS),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_UI4, // data type indicator
0,// precision
0, // scale

12,
offsetof(SCHEMACOLUMNS, wType), // offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(USHORT),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_UI2, // data type indicator
0,// precision
0, // scale

13,
offsetof(SCHEMACOLUMNS, guidType), // offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(GUID),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_GUID, // data type indicator
0,// precision
0, // scale

14,
offsetof(SCHEMACOLUMNS, ulMaxLength),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(ULONG),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_UI4, // data type indicator
0,// precision
0, // scale

16,
offsetof(SCHEMACOLUMNS, wPrecision),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(USHORT),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_UI2, // data type indicator
0,// precision
0, // scale

17,
offsetof(SCHEMACOLUMNS, wScale),// offset of value in consumers buffer
0,// offset of length in consumers buffer
0,// offset of status in consumers buffer
NULL,// reserved
NULL,// for ole object
NULL,// reserved
DBPART_VALUE,// specifies value parts
DBMEMOWNER_CLIENTOWNED,// memory is client owned
DBPARAMIO_NOTPARAM,//
sizeof(USHORT),// size in bytes of the value part in the consumers buffer
0, // reserved
DBTYPE_UI2, // data type indicator
0,// precision
0, // scale
};


//set up the restrictions
rgRestrictions[0].vt = DBTYPE_BSTR;
SAFE_SYSALLOC(rgRestrictions[0].bstrVal, pCFromTable->m_pCDataSource->m_pwszCatalog);
rgRestrictions[1].vt = DBTYPE_EMPTY;
rgRestrictions[2].vt = DBTYPE_BSTR;
SAFE_SYSALLOC(rgRestrictions[2].bstrVal, pCFromTable->m_wszTableName);
rgRestrictions[3].vt = DBTYPE_EMPTY;

//get IDBSchemaRowset interface
XTESTC(hr = pIDBCreateCommand->QueryInterface(IID_IDBSchemaRowset,(void**)&pIDBSchemaRowset));

//GetRowset
//DBSCHEMA_COLUMNS is required a SCHEMA
XTESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_COLUMNS, cRestrictions, rgRestrictions,
IID_IRowset, 0, NULL, (IUnknown **)&pIRowset));

XTESTC(hr = pIRowset->QueryInterface(IID_IAccessor, (void **)&pIAccessor));

//Create the Accessor
XTESTC(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, rgBindings, 0, &hAccessor, NULL));

//Grab all the rows
while(TRUE)
{
hr = pIRowset->GetNextRows(NULL, 0, MAX_BLOCK_SIZE, &cRowsObtained, &rghRows);
if(FAILED(hr) || cRowsObtained==0)
break;

//Loop over the rows retrived
for(ULONG i=0; i<cRowsObtained; i++)
{
ULONG iColumn = 0;

//Reset the SchemaColumn struct
memset(&SchemaColumns, 0, sizeof(SCHEMACOLUMNS));

//Get the Data into the SchemaStruct
XTESTC(hr = pIRowset->GetData(rghRows[i], hAccessor, (void*)&SchemaColumns));

//Format the string
//ColumnName Type- For Non-Numeric Columns - Fixed Columns
//ColumnName Type(ulMaxLength)- For Non-Numeric Columns - Vairable Columns
//ColumnName Type(Precision, Scale)- For Numeric Columns
//ColumnName Type(Precision)- For Numeric Columns - No Scale
if(IsVariableType(SchemaColumns.wType))
{
swprintf(wszBuffer, L"%-20s \t[%s](%lu)", SchemaColumns.wszColName, GetDBTypeName(SchemaColumns.wType), SchemaColumns.ulMaxLength);
}
else if(SchemaColumns.wType==DBTYPE_NUMERIC || SchemaColumns.wType==DBTYPE_DECIMAL)
{
if(SchemaColumns.wScale)
swprintf(wszBuffer, L"%-20s \t[%s](%lu,%lu)", SchemaColumns.wszColName, GetDBTypeName(SchemaColumns.wType), SchemaColumns.wPrecision, SchemaColumns.wScale);
else
swprintf(wszBuffer, L"%-20s \t[%s](%lu)", SchemaColumns.wszColName, GetDBTypeName(SchemaColumns.wType), SchemaColumns.wPrecision);
}
else
{
swprintf(wszBuffer, wsz_COLUMN_FORMAT_, SchemaColumns.wszColName, GetDBTypeName(SchemaColumns.wType));
}

//Send the Formated String to the Window
iColumn = wSendMessage(hWndCol, LB_ADDSTRING, (WPARAM)0, wszBuffer);

//Now send where the ColName ends to the window
SendMessage(hWndCol, LB_SETITEMDATA, iColumn, (LPARAM)wcslen(SchemaColumns.wszColName));
}

//Release all rows
XTESTC(hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL));
SAFE_FREE(rghRows);
}

// If there is an existing columns list (only on Back or error), then
// the user already has a list so use it.
for(i=0; i<pCFromTable->m_cColumns; i++)
{
ASSERT(pCFromTable->m_rgColDesc);

//Find the Column Name in the Window List
swprintf(wszBuffer, L"%s ", pCFromTable->m_rgColDesc[i].wszColName);
LONG lFoundColumn = wSendMessage(hWndCol, LB_FINDSTRING, (WPARAM)0, wszBuffer);

//Select the Column Name if found in the list
if(lFoundColumn != LB_ERR)
SendMessage(hWndCol, LB_SETSEL, (WPARAM)TRUE, (LPARAM)lFoundColumn);
}

//Otherwise, just select all as default
if(pCFromTable->m_cColumns == 0)
SendMessage(hWndCol, LB_SETSEL, (WPARAM)TRUE, (LPARAM)-1L);

Busy();

CLEANUP:
//Free Restrictions
FreeVariants(cRestrictions, rgRestrictions);

if(hAccessor && pIAccessor)
XTEST(pIAccessor->ReleaseAccessor(hAccessor,NULL));

SAFE_RELEASE(pIDBSchemaRowset);
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIAccessor);

SAFE_FREE(rghRows);
return hr==S_OK;
}




/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::GetTypes
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::GetTypes(WCHAR* pwszTypes)
{
ASSERT(pwszTypes);
pwszTypes[0] = EOL;

//IDC_TABLES
if(IsDlgButtonChecked(m_hWnd, IDC_TABLES) == BST_CHECKED)
wcscat(pwszTypes, L"'TABLE',");

//IDC_VIEWS
if(IsDlgButtonChecked(m_hWnd, IDC_VIEWS) == BST_CHECKED)
wcscat(pwszTypes, L"'VIEW',");

//IDC_SYSTABLES
if(IsDlgButtonChecked(m_hWnd, IDC_SYSTABLES) == BST_CHECKED)
wcscat(pwszTypes, L"'SYSTEM TABLE',");

//IDC_SYNONYMS
if(IsDlgButtonChecked(m_hWnd, IDC_SYNONYMS) == BST_CHECKED)
wcscat(pwszTypes, L"'SYNONYM',");

//remove the trailing comma
if(pwszTypes[0] != EOL)
pwszTypes[wcslen(pwszTypes)-1] = EOL;

return TRUE;
}