2025-11-28 00:35:46 +09:00

1041 lines
41 KiB
C++

//-----------------------------------------------------------------------------
// Microsoft OLE DB TABLECOPY Sample
// Copyright (C) 1995-2000 Microsoft Corporation
//
// @doc
//
// @module STEP1.CPP
//
//-----------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////
// Includes
//
/////////////////////////////////////////////////////////////////////
#include "wizard.h"
#include "common.h"
#include "table.h"
/////////////////////////////////////////////////////////////////////
// Defines
//
/////////////////////////////////////////////////////////////////////
//Enum Column Header for the ListView controls
enum COL_HEADERS
{
//IDL_COLUMNS
COL_COLNAME = 0, //ColInfo.pwszName
COL_COLTYPE = 1, //ColInfo.wType
COL_COLORDINAL = 2, //ColInfo.iOrdinal
COL_COLSIZE = 3, //ColInfo.ulColumnSize
COL_COLPREC = 4, //ColInfo.bPrecision
COL_COLSCALE = 5, //ColInfo.bScale
COL_COLISFIXED = 6, //ColInfo.dwFlags ISFIXEDLENGTH
COL_COLISLONG = 7, //ColInfo.dwFlags ISLONG
COL_COLISNULLABLE = 8, //ColInfo.dwFlags ISNULLABLE
COL_COLWRITE = 9, //ColInfo.dwFlags WRITE
COL_COLISROWID =10, //ColInfo.dwFlags ISROWID
COL_COLISROWVER =11, //ColInfo.dwFlags ISROWVER
};
enum EICON
{
ICON_CATALOG = 0,
ICON_SCHEMA = 1,
ICON_TYPE = 2,
ICON_TABLE = 3,
ICON_SYSTABLE = 4,
ICON_VIEW = 5,
ICON_SYNONYM = 6,
ICON_COLUMN = 0,
ICON_READONLY = 1,
ICON_LONG = 2,
};
/////////////////////////////////////////////////////////////////////
// CS1Dialog::CS1Dialog
//
/////////////////////////////////////////////////////////////////////
CS1Dialog::CS1Dialog(HWND hWnd, HINSTANCE hInst, CTableCopy* pCTableCopy)
: CDialogBase(hWnd, hInst)
{
ASSERT(pCTableCopy);
m_pCTableCopy = pCTableCopy;
m_fEditing = FALSE;
m_cTables = 0;
m_rgTableInfo = NULL;
}
/////////////////////////////////////////////////////////////////////
// CS1Dialog::~CS1Dialog
//
/////////////////////////////////////////////////////////////////////
CS1Dialog::~CS1Dialog()
{
SAFE_FREE(m_rgTableInfo);
}
/////////////////////////////////////////////////////////////////////////////
// ULONG CS1Dialog::Display
//
/////////////////////////////////////////////////////////////////////////////
INT_PTR CS1Dialog::Display()
{
//Create a Modal dialog box
return DialogBoxParam(m_hInst, MAKEINTRESOURCE(IDD_FROM_INFO), NULL, (DLGPROC)DlgProc, (LPARAM)this);
}
/////////////////////////////////////////////////////////////////////
// CS1Dialog::DlgProc
//
/////////////////////////////////////////////////////////////////////
BOOL WINAPI CS1Dialog::DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static WCHAR wszBuffer[MAX_NAME_LEN+1];
switch(msg)
{
case WM_INITDIALOG:
{
Busy();
CS1Dialog* pThis = (CS1Dialog*)lParam;
SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
//On INIT we know we have a valid hWnd to store
CenterDialog(hWnd);
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();
pThis->m_pCTableCopy->m_pCWizard->DestroyPrevStep(WIZ_STEP1);
return HANDLED_MSG;
}//case WM_INITDIALOG
case WM_COMMAND:
{
//Obtain the "this" pointer
CS1Dialog *pThis = (CS1Dialog*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
CTable *pCFromTable = pThis->m_pCTableCopy->m_pCFromTable;
CTable *pCToTable = pThis->m_pCTableCopy->m_pCToTable;
CDataSource *pCToDataSource = pCToTable->m_pCDataSource;
CDataSource *pCFromDataSource = pCFromTable->m_pCDataSource;
//Filter out any Control Notification codes
if(GET_WM_COMMAND_CMD(wParam, lParam) > 1)
{
return UNHANDLED_MSG;
}
//LBN_SELCHANGE ListBox Selection change
if(GET_WM_COMMAND_CMD(wParam, lParam) == LBN_SELCHANGE
&& IDC_PROVIDER_NAME == GET_WM_COMMAND_ID(wParam, lParam))
{
Busy();
/*
//Get new selection
LONG iSel = 0;
if((iSel = SendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), CB_GETCURSEL, 0, 0L)) != CB_ERR)
{
//Since we have the CBS_SORT turned on, the order in the Combo Box does
//not match our array, so we pass the array index (lParam) as the item data
LONG lParam = SendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), CB_GETITEMDATA, iSel, 0L);
if((lParam < (LONG)pCFromDataSource->m_cProviderInfo) && (wcscmp(pCFromDataSource->m_rgProviderInfo[lParam].wszName, pCFromDataSource->m_pwszProviderName)!=0))
{
//Clear Table/Column List Views
SendMessage(GetDlgItem(hWnd, IDL_TABLES), TVM_DELETEITEM, (WPARAM)0, (LPARAM)TVI_ROOT);
SendMessage(GetDlgItem(hWnd, IDL_COLUMNS), LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0);
//Clear Table info
memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
pCFromTable->m_wszQualTableName[0] = EOL;
//Disconnect from the DataSource and Update controls
pCFromTable->m_pCDataSource->Disconnect();
pThis->RefreshControls();
}
}
else
{
//The user must have typed in a Provider Name directly
//This may not map to a provider in the list, so assume the name is a ProgID/CLSID
LONG lParam = wSendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), CB_GETLBTEXT, 0, wszBuffer);
}
return HANDLED_MSG;
*/
}
if(pThis->m_fEditing)
{
//There is a bug in the TreeView control for editing here is KB article
//Article ID: Q130691 BUG: ESC/ENTER Keys Don't Work When Editing Labels in TreeView
//So one way to work around this is to just have a flag (m_fEditing)
//to indicate we were in editing mode.
SendDlgItemMessage(hWnd, IDL_TABLES, TVM_ENDEDITLABELNOW, (WPARAM) (wParam==IDCANCEL ? TRUE : FALSE), (LPARAM)0);
return HANDLED_MSG;
}
// Now check for regular command ids
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDB_FROM_CONNECT:
{
//on connect get whatever is now listed in the drop down
LRESULT iSel = 0;
if((iSel = SendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), CB_GETCURSEL, 0, 0L)) != CB_ERR)
{
//Since we have the CBS_SORT turned on, the order in the Combo Box does
//not match our array, so we pass the array index (lParam) as the item data
LRESULT lParam = SendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), CB_GETITEMDATA, iSel, 0L);
pCFromTable->m_pCDataSource->m_pwszProviderName = pCFromDataSource->m_rgProviderInfo[lParam].wszName;
if((lParam < (LONG)pCFromDataSource->m_cProviderInfo) && (wcscmp(pCFromDataSource->m_rgProviderInfo[lParam].wszName, pCFromDataSource->m_pwszProviderName)!=0))
{
//Clear Table/Column List Views
SendMessage(GetDlgItem(hWnd, IDL_TABLES), TVM_DELETEITEM, (WPARAM)0, (LPARAM)TVI_ROOT);
SendMessage(GetDlgItem(hWnd, IDL_COLUMNS), LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0);
//Clear Table info
memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
pCFromTable->m_wszQualTableName[0] = EOL;
//Disconnect from the DataSource and Update controls
pCFromTable->m_pCDataSource->Disconnect();
}
}
else
{
//The user must have typed in a Provider Name directly
//This may not map to a provider in the list, so assume the name is a ProgID/CLSID
wSendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), WM_GETTEXT, MAX_NAME_LEN, wszBuffer);
pCFromTable->m_pCDataSource->m_pwszProviderName = wszBuffer;
}
//Try to connect to the DataSource
Busy();
if(pCFromTable->Connect(hWnd))
{
Busy();
//Clear Table info
memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
pCFromTable->m_wszQualTableName[0] = EOL;
//ResetTableList
pThis->ResetTableList(GetDlgItem(hWnd, IDL_TABLES), GetDlgItem(hWnd, IDL_COLUMNS));
}
pThis->RefreshControls();
return HANDLED_MSG;
}//case IDB_FROM_CONNECT
case IDOK:
Busy();
pThis->GetTableColInfo(GetDlgItem(hWnd, IDL_COLUMNS));
pThis->m_pCTableCopy->m_pCWizard->DisplayStep(WIZ_STEP2);
return HANDLED_MSG;
case IDCANCEL:
Busy();
EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam));
return HANDLED_MSG;
}//switch GET_WM_COMMAND_ID
return UNHANDLED_MSG;
}//case WM_COMMAND
// Now look for WM_NOTIFY messages
case WM_NOTIFY:
{
if(wParam == IDL_COLUMNS)
{
//Obtain the "this" pointer
CS1Dialog* pThis = (CS1Dialog*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
NM_LISTVIEW* pListView = (NM_LISTVIEW*)lParam;
switch(pListView->hdr.code)
{
case LVN_ITEMCHANGED:
{
//Refresh Controls, ("Next" button)
pThis->RefreshControls();
return UNHANDLED_MSG;
}
}
return UNHANDLED_MSG;
}
if(wParam == IDL_TABLES)
{
//Obtain the "this" pointer
CS1Dialog* pThis = (CS1Dialog*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
CTable* pCFromTable = pThis->m_pCTableCopy->m_pCFromTable;
NM_TREEVIEW* pTreeView = (NM_TREEVIEW*)lParam;
switch(pTreeView->hdr.code)
{
case TVN_BEGINLABELEDIT:
{
//Idicate we have started to edit
pThis->m_fEditing = TRUE;
return FALSE; //Allow the edited change
}
case TVN_ENDLABELEDIT:
{
Busy();
pThis->m_fEditing = FALSE;
TV_DISPINFO* pDispInfo = (TV_DISPINFO*)lParam;
//If Schemas are available - don't allow the change
if(pCFromTable->m_pCDataSource->m_pIDBSchemaRowset)
return FALSE;
//Just need to obtain the new tablename...
if(pDispInfo->item.pszText)
{
//Now update the window TableName myself
TV_ITEM tvItem = { TVIF_TEXT | TVIF_STATE, pDispInfo->item.hItem, TVIS_SELECTED, TVIS_SELECTED, pDispInfo->item.pszText, 0, 0, 0, 0, 0};
SendDlgItemMessage(hWnd, IDL_TABLES, TVM_SETITEM, (WPARAM)0, (LPARAM)&tvItem);
//Change the TableName (if different)
memset(&pThis->m_rgTableInfo[0], 0, sizeof(TABLEINFO));
ConvertToWCHAR(pDispInfo->item.pszText, pThis->m_rgTableInfo[0].wszTableName, MAX_NAME_LEN);
pThis->ChangeTableName(0);
}
//Refresh Controls ("Next" button);
pThis->RefreshControls();
return TRUE; //Allow the edited change
}
case TVN_SELCHANGED:
{
//There is a problem with the SELCHANGED notification
//It can be sent when either a item is selected or
//DELETED, since when an item deleted the selection moves
//to a different selection.
if((pTreeView->itemNew.state == TVIS_SELECTED && pTreeView->action)
|| (pTreeView->itemNew.state & TVIS_SELECTED && pTreeView->itemNew.state != TVIS_SELECTED))
{
Busy();
//We assume it sends us the Param of the item
ASSERT(pTreeView->itemNew.mask & TVIF_PARAM);
//Change the TableName (if different)
pThis->ChangeTableName((LONG)pTreeView->itemNew.lParam);
}
//Refresh Controls ("Next" button);
pThis->RefreshControls();
return UNHANDLED_MSG;
}
}
return UNHANDLED_MSG;
}//IDL_TABLES
return UNHANDLED_MSG;
}//WM_NOTIFY
}//msg
return UNHANDLED_MSG;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::InitControls
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::InitControls()
{
HWND hWndTable = GetDlgItem(m_hWnd, IDL_TABLES);
HWND hWndCol = GetDlgItem(m_hWnd, IDL_COLUMNS);
HWND hWndProv = GetDlgItem(m_hWnd, IDC_PROVIDER_NAME);
CDataSource *pCDataSource = m_pCTableCopy->m_pCFromTable->m_pCDataSource;
HRESULT hr;
//Create the Table ImageList
HIMAGELIST hTableImageList = ImageList_Create(16, 16, ILC_MASK, 1, 0 );
//IDI_CATALOG - normal catalog icon
HICON hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_CATALOG));
ImageList_AddIcon(hTableImageList, hIcon);
//IDI_SCHEMA - normal schema icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SCHEMA));
ImageList_AddIcon(hTableImageList, hIcon);
//IDI_TYPE - normal type icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_TYPE));
ImageList_AddIcon(hTableImageList, hIcon);
//IDI_TABLE - normal table icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_TABLE));
ImageList_AddIcon(hTableImageList, hIcon);
//IDI_SYSTABLE - normal system table icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SYSTABLE));
ImageList_AddIcon(hTableImageList, hIcon);
//IDI_VIEW - normal view icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_VIEW));
ImageList_AddIcon(hTableImageList, hIcon);
//IDI_SYNONYM - normal synonym icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SYNONYM));
ImageList_AddIcon(hTableImageList, hIcon);
//Set image list to the Table Window
TreeView_SetImageList(hWndTable, hTableImageList, TVSIL_NORMAL);
//Create the Col ImageList
HIMAGELIST hColImageList = ImageList_Create(16, 16, ILC_MASK, 1, 0 );
//IDI_COLUMN - normal column icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_COLUMN));
ImageList_AddIcon(hColImageList, hIcon);
//IDI_COLUMNREAD - read-only column icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_COLUMNREAD));
ImageList_AddIcon(hColImageList, hIcon);
//IDI_COLUMNLONG - long column icon
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_COLUMNLONG));
ImageList_AddIcon(hColImageList, hIcon);
//Set image list to the Table Window
ListView_SetImageList(hWndCol, hColImageList, LVSIL_SMALL);
//ListView COLUMNS
LV_InsertColumn(hWndCol, COL_COLNAME, "ColName");
LV_InsertColumn(hWndCol, COL_COLTYPE, "Type");
LV_InsertColumn(hWndCol, COL_COLSIZE, "Size");
LV_InsertColumn(hWndCol, COL_COLORDINAL, "Ordinal");
LV_InsertColumn(hWndCol, COL_COLPREC, "Precision");
LV_InsertColumn(hWndCol, COL_COLSCALE, "Scale");
LV_InsertColumn(hWndCol, COL_COLISFIXED, "ISFIXED");
LV_InsertColumn(hWndCol, COL_COLISLONG, "ISLONG");
LV_InsertColumn(hWndCol, COL_COLISNULLABLE, "ISNULLABLE");
LV_InsertColumn(hWndCol, COL_COLWRITE, "WRITE");
LV_InsertColumn(hWndCol, COL_COLISROWID, "ISROWID");
LV_InsertColumn(hWndCol, COL_COLISROWVER, "ISROWVER");
ULONG i;
//AutoSize all columns
for( i=0; i<=COL_COLISROWVER; i++)
SendMessage(hWndCol, LVM_SETCOLUMNWIDTH, (WPARAM)i, (LPARAM)LVSCW_AUTOSIZE_USEHEADER);
//Use Extended ListView Styles!
SendMessage(hWndCol, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_TWOCLICKACTIVATE | LVS_EX_SUBITEMIMAGES, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_TWOCLICKACTIVATE | LVS_EX_SUBITEMIMAGES);
//Initialize the Provider List (if not done so already)
if(pCDataSource->m_rgProviderInfo == NULL)
{
hr = pCDataSource->GetProviders();
}
WCHAR wszBuffer[MAX_NAME_LEN*2];
//Fill out the provider name combo box.
for(i=0; i<pCDataSource->m_cProviderInfo; i++)
{
//Add the name to the list
//Since we have the CBS_SORT turned on, the order in the Combo Box does
//not match our array, so we pass the array index (lParam) as the item data
StringCchPrintfW(wszBuffer, sizeof(wszBuffer)/sizeof(WCHAR), wsz_PROVIDER_INFO_, pCDataSource->m_rgProviderInfo[i].wszName);
LRESULT iIndex = wSendMessage(hWndProv, CB_ADDSTRING, (WPARAM)0, wszBuffer);
SendMessage(hWndProv, CB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)i);
}
//By default, it selects MSDASQL
if(pCDataSource->m_pwszProviderName == NULL)
{
pCDataSource->m_pwszProviderName = L"MSDASQL";
}
//Try and select the previous selected Provider
if(CB_ERR == wSendMessage(hWndProv, CB_SELECTSTRING, 0, pCDataSource->m_pwszProviderName))
{
//If not found, just select the first one
SendMessage(hWndProv, CB_SETCURSEL, 0, 0);
}
//Indicate were not in the middle of an TreeView editing command
m_fEditing = FALSE;
// Enable Connect button only if there are providers installed.
EnableWindow(GetDlgItem(m_hWnd, IDB_FROM_CONNECT), SendMessage(hWndProv, CB_GETCURSEL, 0, 0L) != CB_ERR);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::RefreshControls
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::RefreshControls()
{
CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
CDataSource* pCDataSource = pCFromTable->m_pCDataSource;
// Must have a connection to edit other controls
BOOL fConnected = pCFromTable->IsConnected();
LRESULT cSelColumns = SendDlgItemMessage(m_hWnd, IDL_COLUMNS, LVM_GETSELECTEDCOUNT, 0, 0);
//Enable dialog items, only if connected
EnableWindow(GetDlgItem(m_hWnd, IDL_TABLES), fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDL_COLUMNS), fConnected);
EnableWindow(GetDlgItem(m_hWnd, IDT_FROMTABLEHELP), fConnected);
//Enable OK/Next if there is a table and at least 1 column selected
EnableWindow(GetDlgItem(m_hWnd, IDOK), fConnected && cSelColumns);
//Store the selected ProviderName and ProviderDesc
LRESULT iSel = 0;
if((iSel = SendMessage(GetDlgItem(m_hWnd, IDC_PROVIDER_NAME), CB_GETCURSEL, 0, 0L)) != CB_ERR)
{
//Since we have the CBS_SORT turned on, the order in the Combo Box does
//not match our array, so we pass the array index (lParam) as the item data
LRESULT lParam = SendMessage(GetDlgItem(m_hWnd, IDC_PROVIDER_NAME), CB_GETITEMDATA, iSel, 0L);
ASSERT(lParam < (LONG)pCDataSource->m_cProviderInfo);
pCDataSource->m_pwszProviderName = pCDataSource->m_rgProviderInfo[lParam].wszName;
pCDataSource->m_pwszProviderParseName = pCDataSource->m_rgProviderInfo[lParam].wszParseName;
}
// Show user the connection string
if(fConnected)
{
//CONNECT_STRING
wSetDlgItemText(m_hWnd, IDT_CONNECT, wsz_CONNECT_STRING_,
pCDataSource->m_pwszProviderName,
pCDataSource->m_pwszDataSource,
pCDataSource->m_pwszDBMS,
pCDataSource->m_pwszDBMSVer,
pCDataSource->m_pwszProviderFileName,
pCDataSource->m_pwszProviderVer);
//TABLEHELPMSG
//Display the Qualified TableName
if(pCFromTable->m_TableInfo.wszTableName[0])
wSetDlgItemText(m_hWnd, IDT_FROMTABLEHELP, wsz_FROMQUALTABLE_, pCFromTable->m_wszQualTableName, cSelColumns);
else
wSetDlgItemText(m_hWnd, IDT_FROMTABLEHELP, wsz_FROMTABLEHELP_, pCDataSource->m_pwszTableTerm);
}
else
{
//NO CONNECT_STRING
wSetDlgItemText(m_hWnd, IDT_CONNECT, wsz_NOT_CONNECTED);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::GetTableColInfo
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::GetTableColInfo(HWND hWndCol)
{
CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
// Get the count of selected items
LRESULT cSelColumns = SendMessage(hWndCol, LVM_GETSELECTEDCOUNT, (WPARAM)0, (LPARAM)0);
LRESULT iIndex = -1;
//Loop over all the selected columns in the list
pCFromTable->m_cColumns = (ULONG)cSelColumns;
for(LRESULT i=0; i<cSelColumns; i++)
{
iIndex = SendMessage(hWndCol, LVM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)LVNI_SELECTED);
//"compact" the m_rgColDesc array to only the selected items
if(iIndex != LVM_ERR)
memmove(&pCFromTable->m_rgColDesc[i], &pCFromTable->m_rgColDesc[iIndex], sizeof(COLDESC));
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::CreateTableNode
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::CreateTableNode(TREEINFO* rgTreeInfo, ULONG ulNameOffset, LONG iParam, LONG iImage, LONG iSelectedImage)
{
//ulNameOffset is the offset into TABELEINFO indicating
//Catalog / Schema / Type name were interested in comparing
ASSERT(ulNameOffset == offsetof(TABLEINFO, wszCatalogName)
|| ulNameOffset == offsetof(TABLEINFO, wszSchemaName)
|| ulNameOffset == offsetof(TABLEINFO, wszType));
//Create the specified node in the tree.
//Basically this is a fairly complex function that builds the nodes to the
//TreeView control, listing Catalog/Schema/TableType/TableName heieracrcy.
//This is an extremly simple algortym that loops over the specified column
//(Catalog/Schema/Type) and adds only unique names as a node to the TreeView.
//It then updates "rgTreeInfo" hParents and hItems accordingly.
CHAR szBuffer[MAX_NAME_LEN];
ULONG i;
//Loop over all Tables
ULONG cFoundInfo = 0;
for(i=0; i<m_cTables; i++)
{
BOOL bFound = FALSE;
WCHAR* pwszName = (WCHAR*)((BYTE*)&m_rgTableInfo[i] + ulNameOffset);
//Try to find Type value in the FoundList
for(ULONG j=0; j<cFoundInfo; j++)
{
ULONG ulFoundIndex = rgTreeInfo[j].ulIndex;
WCHAR* pwszFoundName = (WCHAR*)((BYTE*)&m_rgTableInfo[ulFoundIndex] + ulNameOffset);
if(wcscmp(pwszName, pwszFoundName)==0
&& rgTreeInfo[i].hParent == rgTreeInfo[ulFoundIndex].hParent)
{
bFound = TRUE;
rgTreeInfo[i].hItem = rgTreeInfo[ulFoundIndex].hItem;
break;
}
}
if(!bFound && pwszName[0])
{
//Add it to the list
rgTreeInfo[cFoundInfo].ulIndex = i;
cFoundInfo++;
//Add it to the TreeView
ConvertToMBCS(pwszName, szBuffer, MAX_NAME_LEN);
rgTreeInfo[i].hItem = TV_InsertItem(GetDlgItem(m_hWnd, IDL_TABLES), rgTreeInfo[i].hParent, TVI_SORT, szBuffer, iParam, iImage, iSelectedImage);
}
}
//Update Parents
for(i=0; i<m_cTables; i++)
rgTreeInfo[i].hParent = rgTreeInfo[i].hItem;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::ResetTableList
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::ResetTableList(HWND hWndTable, HWND hWndCol)
{
HRESULT hr;
CHAR szBuffer[MAX_NAME_LEN];
IRowset* pIRowset = NULL;
IAccessor* pIAccessor = NULL;
//get the data
HROW* rghRows = NULL;
DBCOUNTITEM i,cRowsObtained = 0;
BOOL bFound = FALSE;
HACCESSOR hAccessor = DB_NULL_HACCESSOR;
TREEINFO* rgTreeInfo = NULL;
//Use the passed in Session interface
CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
CDataSource* pCFromDataSource = pCFromTable->m_pCDataSource;
IOpenRowset* pIOpenRowset = pCFromTable->m_pCDataSource->m_pIOpenRowset;
IDBSchemaRowset* pIDBSchemaRowset = pCFromTable->m_pCDataSource->m_pIDBSchemaRowset;
//Delete all previous items
SendMessage(hWndTable, TVM_DELETEITEM, (WPARAM)0, (LPARAM)TVI_ROOT);
SendMessage(hWndCol, LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0);
// Bind the user and table name for the list
const static ULONG cBindings = 4;
const static DBBINDING rgBindings[cBindings] =
{
//TABLE_CATALOG
1,
offsetof(TABLEINFO, wszCatalogName), // 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
//TABLE_SCHEMA
2,
offsetof(TABLEINFO, wszSchemaName), // 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
//TABLE_NAME
3, // ordinal
offsetof(TABLEINFO, 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
//TABLE_TYPE
4, // ordinal
offsetof(TABLEINFO, wszType), // 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
};
//Reset TableInfo
m_cTables = 0;
SAFE_FREE(m_rgTableInfo);
//Provider doesn't have to support IDBSchemaRowset
if(pIDBSchemaRowset)
{
//GetRowset
//DBSCHEMA_TABLES is required a SCHEMA (if IDBSchemaRowset is supported)
XTESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_TABLES, 0, NULL, IID_IRowset, 0, NULL,(IUnknown **)&pIRowset));
//Create the Accessor
XTESTC(hr = pIRowset->QueryInterface(IID_IAccessor, (void **)&pIAccessor));
XTESTC(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, rgBindings, 0, &hAccessor, NULL));
//Grab all the rows
while(TRUE)
{
XTESTC(hr = pIRowset->GetNextRows(NULL, 0, MAX_BLOCK_SIZE, &cRowsObtained, &rghRows));
//ENDOFROWSET
if(cRowsObtained==0)
break;
//Realloc Table struct for Table
SAFE_REALLOC(m_rgTableInfo, TABLEINFO, m_cTables + cRowsObtained);
memset(&m_rgTableInfo[m_cTables], 0, cRowsObtained*sizeof(TABLEINFO));
//Loop over the rows retrived
for(i=0; i<cRowsObtained; i++)
{
//Get the Data
XTESTC(hr = pIRowset->GetData(rghRows[i], hAccessor, &m_rgTableInfo[m_cTables]));
m_cTables++;
}
//Release the rows obtained
XTESTC(hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL));
SAFE_FREE(rghRows);
}
}
//Provider doesn't have to support IDBSchemaRowset
if(pIDBSchemaRowset == NULL)
{
m_cTables = 1;
SAFE_ALLOC(m_rgTableInfo, TABLEINFO, 1);
memset(m_rgTableInfo, 0, sizeof(TABLEINFO));
if(pCFromTable->m_TableInfo.wszTableName[0])
{
//Just Display the TableName in the EditBox
StringCchCopyW(m_rgTableInfo[0].wszTableName,
sizeof(m_rgTableInfo[0].wszTableName)/sizeof(WCHAR),
pCFromTable->m_TableInfo.wszTableName);
}
else
{
//Just Display "Enter - <TableTerm>"
StringCchPrintfW(m_rgTableInfo[0].wszTableName,
sizeof(m_rgTableInfo[0].wszTableName)/sizeof(WCHAR),
L"Enter - %s",
pCFromDataSource->m_pwszTableTerm);
}
}
//Create rgTreeInfo array
SAFE_ALLOC(rgTreeInfo, TREEINFO, m_cTables);
memset(rgTreeInfo, 0, m_cTables*sizeof(TREEINFO));
//Create Tree Nodes for the TreeView control
CreateTableNode(rgTreeInfo, offsetof(TABLEINFO, wszCatalogName), -1, ICON_CATALOG, ICON_CATALOG);
CreateTableNode(rgTreeInfo, offsetof(TABLEINFO, wszSchemaName), -1, ICON_SCHEMA, ICON_SCHEMA);
CreateTableNode(rgTreeInfo, offsetof(TABLEINFO, wszType), -1, ICON_TYPE, ICON_TYPE);
//Now display all the tables
for(i=0; i<m_cTables; i++)
{
//Add it to the TreeView
ConvertToMBCS(m_rgTableInfo[i].wszTableName, szBuffer, MAX_NAME_LEN);
if(wcscmp(m_rgTableInfo[i].wszType, L"TABLE")==0)
rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_TABLE, ICON_TABLE);
else if(wcscmp(m_rgTableInfo[i].wszType, L"VIEW")==0)
rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_VIEW, ICON_VIEW);
else if(wcscmp(m_rgTableInfo[i].wszType, L"SYSTEM TABLE")==0)
rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_SYSTABLE, ICON_SYSTABLE);
else
rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_SYNONYM, ICON_SYNONYM);
}
// If there was a previous selection, select it again on Back
bFound = FALSE;
if(pCFromTable->m_TableInfo.wszTableName[0])
{
//Find the previously selected TableName
//With TreeView controls there is no "Find" method as in ListView controls!
//So we have to simulate our own find, by seraching for the TableName
for(i=0; i<m_cTables; i++)
{
if(memcmp(&m_rgTableInfo[i], &pCFromTable->m_TableInfo, sizeof(TABLEINFO))==0)
{
bFound = TRUE;
//Select Table in the TreeView control
SendMessage(hWndTable, TVM_SELECTITEM, (WPARAM)TVGN_CARET, (LPARAM)rgTreeInfo[i].hItem);
ResetColInfo(GetDlgItem(m_hWnd, IDL_COLUMNS));
break;
}
}
}
if(!bFound)
{
//Reset TableInfo
memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
//Otheriwse if there was no previous selection, default to auto expand
//the "TABLE" type, or the first type in the tree
bFound = FALSE;
for(i=0; i<m_cTables; i++)
{
if(wcscmp(m_rgTableInfo[i].wszType, L"TABLE")==0)
{
bFound = TRUE;
SendMessage(hWndTable, TVM_ENSUREVISIBLE, (WPARAM)0, (LPARAM)rgTreeInfo[i].hItem);
break;
}
}
if(!bFound && m_cTables)
SendMessage(hWndTable, TVM_ENSUREVISIBLE, (WPARAM)0, (LPARAM)rgTreeInfo[0].hItem);
}
CLEANUP:
if(hAccessor && pIAccessor)
XTEST(pIAccessor->ReleaseAccessor(hAccessor,NULL));
SAFE_RELEASE(pIRowset);
SAFE_RELEASE(pIAccessor);
SAFE_FREE(rgTreeInfo);
SAFE_FREE(rghRows);
return hr==S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::ResetColInfo
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::ResetColInfo(HWND hWndCol)
{
HRESULT hr;
CHAR szBuffer[MAX_NAME_LEN];
ULONG i;
LONG lFoundColumn;
CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
IOpenRowset* pIOpenRowset = pCFromTable->m_pCDataSource->m_pIOpenRowset;
//Save the currently selected columns
ULONG cSelColumns = pCFromTable->m_cColumns;
COLDESC* rgSelColDesc = pCFromTable->m_rgColDesc;
//Reset current Window Column ListView
SendMessage(hWndCol, LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0L);
// Get a list of columns based on the selected table
pCFromTable->m_cColumns = 0;
pCFromTable->m_rgColDesc = NULL;
QTESTC(hr = pCFromTable->GetColInfo(IDR_PARAM_SETS));
//Loop through all columns and update window
for(i=0; i<pCFromTable->m_cColumns; i++)
{
COLDESC* pColDesc = &pCFromTable->m_rgColDesc[i];
//COLNAME (item)
ConvertToMBCS(pColDesc->wszColName, szBuffer, MAX_NAME_LEN);
LV_InsertItem(hWndCol, i, COL_COLNAME, szBuffer, 0, pColDesc->dwFlags & (DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_WRITEUNKNOWN) ? ((pColDesc->dwFlags & DBCOLUMNFLAGS_ISLONG) ? ICON_LONG : ICON_COLUMN) : ICON_READONLY);
//COLTYPE (subitem)
ConvertToMBCS(GetDBTypeName(pColDesc->wType), szBuffer, MAX_NAME_LEN);
LV_InsertItem(hWndCol, i, COL_COLTYPE, szBuffer);
//Ordinal (SubItem)
StringCchPrintfA(szBuffer, sizeof(szBuffer), "%d", pColDesc->iOrdinal);
LV_InsertItem(hWndCol, i, COL_COLORDINAL, szBuffer);
//ColumnSize (SubItem)
StringCchPrintfA(szBuffer, sizeof(szBuffer), "%d", pColDesc->ulColumnSize);
LV_InsertItem(hWndCol, i, COL_COLSIZE, szBuffer);
//Precision (SubItem)
StringCchPrintfA(szBuffer, sizeof(szBuffer), "%d", pColDesc->bPrecision);
LV_InsertItem(hWndCol, i, COL_COLPREC, szBuffer);
//Scale (SubItem)
StringCchPrintfA(szBuffer, sizeof(szBuffer), "%d", pColDesc->bScale);
LV_InsertItem(hWndCol, i, COL_COLSCALE, szBuffer);
//FLAGS (SubItem)
LV_InsertItem(hWndCol, i, COL_COLISFIXED, pColDesc->dwFlags & DBCOLUMNFLAGS_ISFIXEDLENGTH ? "TRUE" : "FALSE");
LV_InsertItem(hWndCol, i, COL_COLISLONG, pColDesc->dwFlags & DBCOLUMNFLAGS_ISLONG ? "TRUE" : "FALSE");
LV_InsertItem(hWndCol, i, COL_COLISNULLABLE, pColDesc->dwFlags & DBCOLUMNFLAGS_ISNULLABLE ? "TRUE" : "FALSE");
LV_InsertItem(hWndCol, i, COL_COLWRITE, pColDesc->dwFlags & (DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_WRITEUNKNOWN) ? "TRUE" : "FALSE");
LV_InsertItem(hWndCol, i, COL_COLISROWID, pColDesc->dwFlags & DBCOLUMNFLAGS_ISROWID ? "TRUE" : "FALSE");
LV_InsertItem(hWndCol, i, COL_COLISROWVER, pColDesc->dwFlags & DBCOLUMNFLAGS_ISROWVER ? "TRUE" : "FALSE");
}
// If there is an existing columns list (only on Back or error), then
// the user already has a list so use it.
lFoundColumn = -1;
for(i=0; i<cSelColumns; i++)
{
//Find the Column Name in the Window List
ConvertToMBCS(rgSelColDesc[i].wszColName, szBuffer, MAX_NAME_LEN);
lFoundColumn = LV_FindItem(hWndCol, szBuffer, lFoundColumn);
//Select the Column Name if found in the list, and bring into view
if(lFoundColumn != LVM_ERR)
{
LV_SetItemState(hWndCol, lFoundColumn, COL_COLNAME, LVIS_SELECTED, LVIS_SELECTED);
//Ensure that the first item is Visible
if(i==0)
SendMessage(hWndCol, LVM_ENSUREVISIBLE, (WPARAM)lFoundColumn, (LPARAM)FALSE);
}
}
//Otherwise, just select all as default
if(cSelColumns == 0)
{
for(i=0; i<pCFromTable->m_cColumns; i++)
LV_SetItemState(hWndCol, i, COL_COLNAME, LVIS_SELECTED, LVIS_SELECTED);
}
CLEANUP:
SAFE_FREE(rgSelColDesc);
return hr==S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CS1Dialog::ChangeTableName
//
/////////////////////////////////////////////////////////////////////////////
BOOL CS1Dialog::ChangeTableName(LONG iIndex)
{
CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
CTable* pCToTable = m_pCTableCopy->m_pCToTable;
//Index must fall with the m_rgTableInfo array range
//Otherwise we have selected a "tree-folder" and need to free the column list
if(iIndex < 0 || iIndex >= (LONG)m_cTables)
{
//Resest TableName
memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
//Reset current Window Column ListView
SendMessage(GetDlgItem(m_hWnd, IDL_COLUMNS), LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0L);
return FALSE;
}
//Only change the TableName if not equal to "Enter - <TableTerm>"
if(wcsstr(m_rgTableInfo[iIndex].wszTableName, L"Enter - "))
return FALSE;
//TableInfo
memcpy(&pCFromTable->m_TableInfo, &m_rgTableInfo[iIndex], sizeof(TABLEINFO));
//QualifiedTableName syntax
// #1. TableName
// #2. Owner.TableName (always a ".")
// #3. Catalog[CatalogSeperator]TableName
// #4. Catalog[CatalogSeperator]Owner.TableName
if(pCFromTable->m_TableInfo.wszSchemaName[0])
{
StringCchPrintfW(pCFromTable->m_wszQualTableName,
sizeof(pCFromTable->m_wszQualTableName)/sizeof(WCHAR),
L"%s.%s",
pCFromTable->m_TableInfo.wszSchemaName,
pCFromTable->m_TableInfo.wszTableName);
}
else
{
StringCchCopyW(pCFromTable->m_wszQualTableName,
sizeof(pCFromTable->m_wszQualTableName)/sizeof(WCHAR),
pCFromTable->m_TableInfo.wszTableName);
}
//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
ResetColInfo(GetDlgItem(m_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
memset(&pCToTable->m_TableInfo, 0, sizeof(TABLEINFO));
return TRUE;
}