STEP2.CPP

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


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



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


/////////////////////////////////////////////////////////////////////
// CS2Dialog::~CS2Dialog
//
/////////////////////////////////////////////////////////////////////
CS2Dialog::~CS2Dialog()
{
}


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



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

//On INIT we know we have a valid hWnd to store
pThis->m_hWnd = hWnd;

//Set Horizontal ScrollBar dimensions
SendDlgItemMessage(hWnd, IDL_INDEXES, LB_SETHORIZONTALEXTENT, (WPARAM)200, (LPARAM)0);

pThis->ResetIndexList(GetDlgItem(hWnd, IDL_INDEXES));
CenterDialog(hWnd);
return HANDLED_MSG;
}

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

// All buttons are handled the same way
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDB_PREV:
case IDOK:

case IDCANCEL:
//Record all selected indexes
pThis->RecordSelectedIndexes(GetDlgItem(hWnd, IDL_INDEXES));

//Get which indexes are really PrimaryKeys,
pThis->GetPrimaryKeys();

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

return UNHANDLED_MSG;
}


/////////////////////////////////////////////////////////////////////////////
// BOOL CS2Dialog::ResetIndexList
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS2Dialog::ResetIndexList(HWND hWnd)
{
HRESULT hr;
IDBSchemaRowset* pIDBSchemaRowset = NULL;

HROW* rghRows = NULL;
ULONG cRowsObtained = 0;
IRowset* pIRowset = NULL;

IAccessor* pIAccessor = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;

ULONG cIndexes = 0;
INDEXINFO* pIndexInfo = NULL;

Busy();

//set up the restrictions
const ULONG cRestrictions = 5;
VARIANT rgRestrictions[cRestrictions];
InitVariants(cRestrictions, rgRestrictions);

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

// Now make the call
SendMessage(hWnd, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0L);

// Bind the user and table name for the list
const ULONG cBindings = 6;
const DBBINDING rgBindings[cBindings] =
{
6,
offsetof(INDEXINFO, wszIndexName),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
MAX_NAME_LEN,
0,
DBTYPE_WSTR,
0,
0,

8,
offsetof(INDEXINFO, fUnique),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
sizeof(BOOL),
0,
DBTYPE_BOOL,
0,
0,

17,
offsetof(INDEXINFO, iOrdinal),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
sizeof(ULONG),
0,
DBTYPE_UI4,
0,
0,

18,
offsetof(INDEXINFO, wszColName),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
MAX_NAME_LEN,
0,
DBTYPE_WSTR,
0,
0,

19,
offsetof(INDEXINFO, guidCol),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
sizeof(GUID),
0,
DBTYPE_GUID,
0,
0,

21,
offsetof(INDEXINFO, dwCollation),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
sizeof(DWORD),
0,
DBTYPE_I4,
0,
0,
};

//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_EMPTY;
rgRestrictions[3].vt = DBTYPE_EMPTY;
rgRestrictions[4].vt = DBTYPE_BSTR;
SAFE_SYSALLOC(rgRestrictions[4].bstrVal, pCFromTable->m_wszTableName);

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

//GetRowset
//DBSCHEMA_INDEXES may not be supported by the driver.
//If an error occurs, just don't display IndexInfo
TESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_INDEXES, cRestrictions, rgRestrictions,
IID_IRowset, 0, NULL, (IUnknown **)&pIRowset));

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

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

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

for (ULONG i=0; i<cRowsObtained; i++)
{
ULONG iSel = 0;
SAFE_FREE(pIndexInfo);
SAFE_ALLOC(pIndexInfo, INDEXINFO, 1);

//Reset the IndexInfo
memset(pIndexInfo, 0, sizeof(INDEXINFO));

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

//If this is an index the ordinal will be 1 based
if(pIndexInfo->iOrdinal==0)
continue;

// New indexes are added to the list box
// Note: We pass an alloced pointer to the window to store
// We need to free all the pointers when the window closes
iSel = wSendMessage(hWnd, LB_ADDSTRING, (WPARAM)0, pIndexInfo->wszIndexName);
SendMessage(hWnd, LB_SETITEMDATA, (WPARAM)iSel, (LPARAM)pIndexInfo);

//Now that we have an actual index...
//Set pIndexInfo to NULL since its now stored in the Window ITEMDATA
//And we don't want the CLEANUP veriosn to delete it again
pIndexInfo = NULL;
cIndexes++;
}

//Release all the rows
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_rgIndexInfo)
{
LONGlFoundIndex;

for(ULONG i=0; i<pCFromTable->m_cIndexes; i++)
{
lFoundIndex = wSendMessage(hWnd, LB_FINDSTRINGEXACT,
(WPARAM)0, pCFromTable->m_rgIndexInfo[i].wszIndexName);

// If there was a selection, select it now
if(lFoundIndex != LB_ERR)
SendMessage(hWnd, LB_SETSEL, (WPARAM)TRUE, (LPARAM)lFoundIndex);
}
}
//Otherwise select all as default
else
SendMessage(hWnd, LB_SETSEL, (WPARAM)TRUE, (LPARAM)-1L);

//Only enable the ListBox/Title if there are indexes
EnableWindow(GetDlgItem(m_hWnd, IDT_INDEXES),cIndexes);
EnableWindow(GetDlgItem(m_hWnd, IDL_INDEXES),cIndexes);

Busy();

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

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

SAFE_RELEASE(pIDBSchemaRowset);
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIAccessor);
SAFE_FREE(pIndexInfo);
SAFE_FREE(rghRows);
return hr==S_OK;
}




/////////////////////////////////////////////////////////////////////////////
// BOOL CS2Dialog::GetPrimaryKeys
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS2Dialog::GetPrimaryKeys()
{
HRESULT hr;
IDBSchemaRowset* pIDBSchemaRowset = NULL;

HROW* rghRows = NULL;
ULONG cRowsObtained = 0;
IRowset* pIRowset = NULL;

IAccessor* pIAccessor = NULL;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;

PRIMARYKEY PrimaryKey;
Busy();

//set up the restrictions
const ULONG cRestrictions = 3;
VARIANT rgRestrictions[cRestrictions];
InitVariants(cRestrictions, rgRestrictions);

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

// Bind the user and table name for the list
const ULONG cBindings = 3;
const DBBINDING rgBindings[cBindings] =
{
4,
offsetof(PRIMARYKEY, wszColName),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
MAX_NAME_LEN,
0,
DBTYPE_WSTR,
0,
0,

5,
offsetof(PRIMARYKEY, guidCol),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
sizeof(GUID),
0,
DBTYPE_GUID,
0,
0,

7,
offsetof(PRIMARYKEY, iOrdinal),
0,
0,
NULL,
NULL,
NULL,
DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED,
DBPARAMIO_NOTPARAM,
sizeof(ULONG),
0,
DBTYPE_UI4,
0,
0,
};

//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);

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

//GetRowset
//DBSCHEMA_PRIMARY_KEYS may not be supported by the driver.
//If an error occurs, just don't display PrimaryKey info
TESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_PRIMARY_KEYS, cRestrictions, rgRestrictions,
IID_IRowset, 0, NULL, (IUnknown **)&pIRowset));

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

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

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

for (ULONG i=0; i<cRowsObtained; i++)
{
//Reset the PrimaryKey
memset(&PrimaryKey, 0, sizeof(PRIMARYKEY));

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

//Need to find the corresponding column in IndexInfo and
//mark it as a primary key column
for(ULONG iIndex=0; iIndex<pCFromTable->m_cIndexes; iIndex++)
if(wcscmp(PrimaryKey.wszColName, pCFromTable->m_rgIndexInfo[iIndex].wszColName)==0)
pCFromTable->m_rgIndexInfo[iIndex].fIsPrimaryKey = TRUE;
}

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

Busy();

CLEANUP:
//Free Resriticions
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 CS2Dialog::RecordSelectedIndexes
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS2Dialog::RecordSelectedIndexes(HWND hWnd)
{
CTable* pCTable = m_pCTableCopy->m_pCFromTable;
LONG i,iSel;

//When we setup the IndexList, we stored the pointer of the index
//in the window. So now we need free all the indexes stored, and
//save all the indexes selected by the user.

//Get the Total Number of indexes in the window
LONG cIndexes = SendMessage(hWnd, LB_GETCOUNT, (WPARAM)0, (LPARAM)0l);
//Get the Number of selected indexes
LONG cSelIndexes = SendMessage(hWnd, LB_GETSELCOUNT, (WPARAM)0, (LPARAM)0l);

//Get the selected index ordinals
LONG* rgSelIndexes = NULL;
SAFE_ALLOC(rgSelIndexes, LONG, cSelIndexes);
SendMessage(hWnd, LB_GETSELITEMS, (WPARAM)cSelIndexes, (LPARAM)rgSelIndexes);

//Alloc Table struct for Indexes
pCTable->m_cIndexes = cSelIndexes;
SAFE_FREE(pCTable->m_rgIndexInfo);
SAFE_ALLOC(pCTable->m_rgIndexInfo, INDEXINFO, cSelIndexes);

//Loop over all the indexes
for(i=0, iSel=0; i<cIndexes; i++)
{
//Get the index pointer for this ordinal from the window
INDEXINFO* pIndexInfo = (INDEXINFO*)SendMessage(hWnd, LB_GETITEMDATA, (WPARAM)i, (LPARAM)0);
ASSERT(pIndexInfo);

//Save this index, if it is a selected one
if(iSel<cSelIndexes && i==rgSelIndexes[iSel])
{
memcpy(&pCTable->m_rgIndexInfo[iSel], pIndexInfo, sizeof(INDEXINFO));
iSel++;
}

//delete the indexinfo
SAFE_FREE(pIndexInfo);
}


CLEANUP:
SAFE_FREE(rgSelIndexes);
return TRUE;
}