//----------------------------------------------------------------------------- // 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; im_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; im_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; im_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; iGetData(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 - " 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; im_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; im_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; iReleaseAccessor(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; im_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; im_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 - " 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; }