home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / oledb / tablecopy / step1.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-12  |  33.6 KB  |  981 lines

  1. //-----------------------------------------------------------------------------
  2. // Microsoft OLE DB TABLECOPY Sample
  3. // Copyright (C) 1995-1998 Microsoft Corporation
  4. //
  5. // @doc
  6. //
  7. // @module STEP1.CPP
  8. //
  9. //-----------------------------------------------------------------------------
  10.  
  11. /////////////////////////////////////////////////////////////////////
  12. // Includes
  13. //
  14. /////////////////////////////////////////////////////////////////////
  15. #include "wizard.h"
  16. #include "common.h"
  17. #include "table.h"
  18.  
  19. /////////////////////////////////////////////////////////////////////
  20. // Defines
  21. //
  22. /////////////////////////////////////////////////////////////////////
  23.  
  24. //Enum Column Header for the ListView controls
  25. enum COL_HEADERS
  26. {
  27.     //IDL_COLUMNS
  28.     COL_COLNAME            = 0,    //ColInfo.pwszName
  29.     COL_COLTYPE            = 1,    //ColInfo.wType
  30.     COL_COLORDINAL        = 2,    //ColInfo.iOrdinal
  31.     COL_COLSIZE            = 3,    //ColInfo.ulColumnSize
  32.     COL_COLPREC            = 4,    //ColInfo.bPrecision
  33.     COL_COLSCALE        = 5,    //ColInfo.bScale
  34.     COL_COLISFIXED        = 6,    //ColInfo.dwFlags ISFIXEDLENGTH
  35.     COL_COLISLONG        = 7,    //ColInfo.dwFlags ISLONG
  36.     COL_COLISNULLABLE    = 8,    //ColInfo.dwFlags ISNULLABLE
  37.     COL_COLWRITE        = 9,    //ColInfo.dwFlags WRITE
  38.     COL_COLISROWID        =10,    //ColInfo.dwFlags ISROWID
  39.     COL_COLISROWVER        =11,    //ColInfo.dwFlags ISROWVER
  40. };
  41.  
  42. enum EICON
  43. {
  44.     ICON_CATALOG        = 0,
  45.     ICON_SCHEMA            = 1,
  46.     ICON_TYPE            = 2,
  47.     ICON_TABLE            = 3,
  48.     ICON_SYSTABLE        = 4,
  49.     ICON_VIEW            = 5,
  50.     ICON_SYNONYM        = 6,
  51.  
  52.     ICON_COLUMN            = 0,
  53.     ICON_READONLY        = 1,
  54.     ICON_LONG            = 2,
  55. };
  56.  
  57.  
  58. /////////////////////////////////////////////////////////////////////
  59. // CS1Dialog::CS1Dialog
  60. //
  61. /////////////////////////////////////////////////////////////////////
  62. CS1Dialog::CS1Dialog(HWND hWnd, HINSTANCE hInst, CTableCopy* pCTableCopy)
  63.     : CDialogBase(hWnd, hInst)
  64. {
  65.     ASSERT(pCTableCopy);
  66.     m_pCTableCopy = pCTableCopy;
  67.     m_fEditing = FALSE;
  68.  
  69.     m_cTables = 0;
  70.     m_rgTableInfo = NULL;
  71. }
  72.  
  73.  
  74. /////////////////////////////////////////////////////////////////////
  75. // CS1Dialog::~CS1Dialog
  76. //
  77. /////////////////////////////////////////////////////////////////////
  78. CS1Dialog::~CS1Dialog()
  79. {
  80.     SAFE_FREE(m_rgTableInfo);
  81. }
  82.  
  83.  
  84. /////////////////////////////////////////////////////////////////////////////
  85. // ULONG CS1Dialog::Display
  86. //
  87. /////////////////////////////////////////////////////////////////////////////
  88. ULONG CS1Dialog::Display()
  89. {
  90.     //Create a Modal dialog box
  91.     return DialogBoxParam(m_hInst, MAKEINTRESOURCE(IDD_FROM_INFO), NULL, DlgProc, (LPARAM)this);
  92. }
  93.  
  94.  
  95. /////////////////////////////////////////////////////////////////////
  96. // CS1Dialog::DlgProc
  97. //
  98. /////////////////////////////////////////////////////////////////////
  99. BOOL WINAPI CS1Dialog::DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  100. {
  101.     switch(msg) 
  102.     {
  103.         case WM_INITDIALOG:
  104.         {
  105.             Busy();
  106.             CS1Dialog* pThis = (CS1Dialog*)lParam;
  107.             SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);
  108.             
  109.             //On INIT we know we have a valid hWnd to store
  110.             CenterDialog(hWnd);
  111.             pThis->m_hWnd = hWnd;
  112.             CTable* pCFromTable = pThis->m_pCTableCopy->m_pCFromTable;
  113.  
  114.             //Init all controls to the default values
  115.             pThis->InitControls();
  116.  
  117.             // If there is a source to look at, Display the table list
  118.             if(pCFromTable->IsConnected()) 
  119.                 pThis->ResetTableList(GetDlgItem(hWnd, IDL_TABLES), GetDlgItem(hWnd, IDL_COLUMNS));
  120.  
  121.             pThis->RefreshControls();
  122.             pThis->m_pCTableCopy->m_pCWizard->DestroyPrevStep(WIZ_STEP1);
  123.             return HANDLED_MSG;
  124.         }//case WM_INITDIALOG
  125.  
  126.         case WM_COMMAND:
  127.         {
  128.             //Obtain the "this" pointer
  129.             CS1Dialog* pThis = (CS1Dialog*)GetWindowLong(hWnd, GWL_USERDATA);
  130.  
  131.             CTable* pCFromTable = pThis->m_pCTableCopy->m_pCFromTable;        
  132.             CTable* pCToTable = pThis->m_pCTableCopy->m_pCToTable;        
  133.             CDataSource* pCToDataSource = pCToTable->m_pCDataSource;        
  134.             CDataSource* pCFromDataSource = pCFromTable->m_pCDataSource;        
  135.             
  136.             //Filter out any Control Notification codes
  137.             if(GET_WM_COMMAND_CMD(wParam, lParam) > 1)
  138.             {
  139.                 return UNHANDLED_MSG;
  140.             }
  141.  
  142.             //LBN_SELCHANGE ListBox Selection change
  143.             if(GET_WM_COMMAND_CMD(wParam, lParam) == LBN_SELCHANGE
  144.                 && IDC_PROVIDER_NAME == GET_WM_COMMAND_ID(wParam, lParam)) 
  145.             {
  146.                 Busy();
  147.                 //Get new selection
  148.                 LONG iSel = 0;
  149.                 if((iSel = SendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), CB_GETCURSEL, 0, 0L)) != CB_ERR)
  150.                 {
  151.                     //Since we have the CBS_SORT turned on, the order in the Combo Box does
  152.                     //not match our array, so we pass the array index (lParam) as the item data
  153.                     LONG lParam = SendMessage(GetDlgItem(pThis->m_hWnd, IDC_PROVIDER_NAME), CB_GETITEMDATA, iSel, 0L);
  154.                     if((lParam < (LONG)pCFromDataSource->m_cProviderInfo) && (wcscmp(pCFromDataSource->m_rgProviderInfo[lParam].wszName, pCFromDataSource->m_pwszProviderName)!=0))
  155.                     {
  156.                         //Clear Table/Column List Views
  157.                         SendMessage(GetDlgItem(hWnd, IDL_TABLES), TVM_DELETEITEM, (WPARAM)0, (LPARAM)TVI_ROOT);
  158.                         SendMessage(GetDlgItem(hWnd, IDL_COLUMNS), LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0);
  159.  
  160.                         //Clear Table info
  161.                         memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
  162.                         pCFromTable->m_wszQualTableName[0] = EOL;
  163.  
  164.                         //Disconnect from the DataSource and Update controls
  165.                         pCFromTable->m_pCDataSource->Disconnect();
  166.                         pThis->RefreshControls();
  167.                     }
  168.                 }
  169.                 return HANDLED_MSG;
  170.             }
  171.  
  172.             if(pThis->m_fEditing)
  173.             {
  174.                 //There is a bug in the TreeView control for editing here is KB article
  175.                 //Article ID: Q130691 BUG: ESC/ENTER Keys Don't Work When Editing Labels in TreeView
  176.                 //So one way to work around this is to just have a flag (m_fEditing)
  177.                 //to indicate we were in editing mode.
  178.                 SendDlgItemMessage(hWnd, IDL_TABLES, TVM_ENDEDITLABELNOW, (WPARAM) (wParam==IDCANCEL ? TRUE : FALSE), (LPARAM)0);
  179.                 return HANDLED_MSG;
  180.             }
  181.  
  182.             // Now check for regular command ids
  183.             switch(GET_WM_COMMAND_ID(wParam, lParam)) 
  184.             {
  185.                 case IDB_FROM_CONNECT:
  186.                 {
  187.                     //Try to connect to the DataSource
  188.                     Busy();
  189.                     if(pCFromTable->Connect(hWnd))
  190.                     {
  191.                         Busy();
  192.                         //Clear Table info
  193.                         memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
  194.                         pCFromTable->m_wszQualTableName[0] = EOL;
  195.  
  196.                         //ResetTableList
  197.                         pThis->ResetTableList(GetDlgItem(hWnd, IDL_TABLES), GetDlgItem(hWnd, IDL_COLUMNS));
  198.                     }
  199.                     
  200.                     pThis->RefreshControls();
  201.                     return HANDLED_MSG;
  202.                 }//case IDB_FROM_CONNECT
  203.  
  204.                 case IDOK:
  205.                     Busy();
  206.                     pThis->GetTableColInfo(GetDlgItem(hWnd, IDL_COLUMNS));
  207.                     pThis->m_pCTableCopy->m_pCWizard->DisplayStep(WIZ_STEP2);
  208.                     return HANDLED_MSG;
  209.                 
  210.                 case IDCANCEL:
  211.                     Busy();
  212.                     EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam));
  213.                     return HANDLED_MSG;
  214.             }//switch GET_WM_COMMAND_ID
  215.  
  216.             return UNHANDLED_MSG;
  217.         }//case WM_COMMAND
  218.  
  219.         
  220.         // Now look for WM_NOTIFY messages
  221.         case WM_NOTIFY:
  222.         {
  223.             if(wParam == IDL_COLUMNS)
  224.             {
  225.                 //Obtain the "this" pointer
  226.                 CS1Dialog* pThis = (CS1Dialog*)GetWindowLong(hWnd, GWL_USERDATA);
  227.                 NM_LISTVIEW* pListView = (NM_LISTVIEW*)lParam;
  228.             
  229.                 switch(pListView->hdr.code)
  230.                 {
  231.                     case LVN_ITEMCHANGED:
  232.                     {
  233.                         //Refresh Controls, ("Next" button)
  234.                         pThis->RefreshControls();
  235.                         return UNHANDLED_MSG;
  236.                     }
  237.                 }
  238.                 return UNHANDLED_MSG;
  239.             }
  240.  
  241.             if(wParam == IDL_TABLES)
  242.             {
  243.                 //Obtain the "this" pointer
  244.                 CS1Dialog* pThis = (CS1Dialog*)GetWindowLong(hWnd, GWL_USERDATA);
  245.                 CTable* pCFromTable = pThis->m_pCTableCopy->m_pCFromTable;
  246.                 NM_TREEVIEW* pTreeView = (NM_TREEVIEW*)lParam;
  247.             
  248.                 switch(pTreeView->hdr.code)
  249.                 {                                 
  250.                     case TVN_BEGINLABELEDIT:
  251.                     {
  252.                         //Idicate we have started to edit
  253.                         pThis->m_fEditing = TRUE;
  254.                         return FALSE; //Allow the edited change
  255.                     }
  256.  
  257.                     case TVN_ENDLABELEDIT:
  258.                     {
  259.                         Busy();
  260.                         pThis->m_fEditing = FALSE;
  261.                         TV_DISPINFO* pDispInfo = (TV_DISPINFO*)lParam;
  262.  
  263.                         //If Schemas are available - don't allow the change
  264.                         if(pCFromTable->m_pCDataSource->m_pIDBSchemaRowset)
  265.                             return FALSE;
  266.  
  267.                         //Just need to obtain the new tablename...
  268.                         if(pDispInfo->item.pszText)
  269.                         {
  270.                             //Now update the window TableName myself
  271.                             TV_ITEM tvItem = { TVIF_TEXT | TVIF_STATE, pDispInfo->item.hItem, TVIS_SELECTED, TVIS_SELECTED, pDispInfo->item.pszText, 0, 0, 0, 0, 0};
  272.                             SendDlgItemMessage(hWnd, IDL_TABLES, TVM_SETITEM, (WPARAM)0, (LPARAM)&tvItem);
  273.  
  274.                             //Change the TableName (if different)
  275.                             memset(&pThis->m_rgTableInfo[0], 0, sizeof(TABLEINFO));
  276.                             ConvertToWCHAR(pDispInfo->item.pszText, pThis->m_rgTableInfo[0].wszTableName, MAX_NAME_LEN);
  277.                             pThis->ChangeTableName(0); 
  278.                         }
  279.                                                 
  280.                         //Refresh Controls ("Next" button);
  281.                         pThis->RefreshControls();
  282.                         return TRUE; //Allow the edited change
  283.                     }
  284.                         
  285.                     case TVN_SELCHANGED:
  286.                     {
  287.                         //There is a problem with the SELCHANGED notification
  288.                         //It can be sent when either a item is selected or
  289.                         //DELETED, since when an item deleted the selection moves
  290.                         //to a different selection.
  291.                         if((pTreeView->itemNew.state == TVIS_SELECTED && pTreeView->action)
  292.                             || (pTreeView->itemNew.state & TVIS_SELECTED && pTreeView->itemNew.state != TVIS_SELECTED)) 
  293.                         {
  294.                             Busy();
  295.                             //We assume it sends us the Param of the item
  296.                             ASSERT(pTreeView->itemNew.mask & TVIF_PARAM);
  297.                 
  298.                             //Change the TableName (if different)
  299.                             pThis->ChangeTableName(pTreeView->itemNew.lParam); 
  300.                         }
  301.  
  302.                         //Refresh Controls ("Next" button);
  303.                         pThis->RefreshControls();
  304.                         return UNHANDLED_MSG;
  305.                     }
  306.                 }
  307.                 return UNHANDLED_MSG;
  308.             }//IDL_TABLES
  309.             return UNHANDLED_MSG;
  310.         }//WM_NOTIFY
  311.     }//msg
  312.  
  313.     return UNHANDLED_MSG;
  314. }
  315.  
  316.  
  317. /////////////////////////////////////////////////////////////////////////////
  318. // BOOL CS1Dialog::InitControls
  319. //
  320. /////////////////////////////////////////////////////////////////////////////
  321. BOOL CS1Dialog::InitControls()
  322. {
  323.     HWND hWndTable = GetDlgItem(m_hWnd, IDL_TABLES);
  324.     HWND hWndCol = GetDlgItem(m_hWnd, IDL_COLUMNS);
  325.     HWND hWndProv = GetDlgItem(m_hWnd, IDC_PROVIDER_NAME);
  326.     CDataSource* pCDataSource = m_pCTableCopy->m_pCFromTable->m_pCDataSource;
  327.     
  328.     //Create the Table ImageList
  329.     HIMAGELIST hTableImageList = ImageList_Create(16, 16, ILC_MASK, 1, 0 );
  330.  
  331.     //IDI_CATALOG - normal catalog icon
  332.     HICON hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_CATALOG));
  333.     ImageList_AddIcon(hTableImageList, hIcon);
  334.     //IDI_SCHEMA - normal schema icon
  335.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SCHEMA));
  336.     ImageList_AddIcon(hTableImageList, hIcon);
  337.     //IDI_TYPE - normal type icon
  338.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_TYPE));
  339.     ImageList_AddIcon(hTableImageList, hIcon);
  340.     //IDI_TABLE - normal table icon
  341.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_TABLE));
  342.     ImageList_AddIcon(hTableImageList, hIcon);
  343.     //IDI_SYSTABLE - normal system table icon
  344.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SYSTABLE));
  345.     ImageList_AddIcon(hTableImageList, hIcon);
  346.     //IDI_VIEW - normal view icon
  347.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_VIEW));
  348.     ImageList_AddIcon(hTableImageList, hIcon);
  349.     //IDI_SYNONYM - normal synonym icon
  350.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SYNONYM));
  351.     ImageList_AddIcon(hTableImageList, hIcon);
  352.  
  353.     //Set image list to the Table Window 
  354.     TreeView_SetImageList(hWndTable, hTableImageList, TVSIL_NORMAL);
  355.     
  356.     //Create the Col ImageList
  357.     HIMAGELIST hColImageList = ImageList_Create(16, 16, ILC_MASK, 1, 0 );
  358.  
  359.     //IDI_COLUMN - normal column icon
  360.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_COLUMN));
  361.     ImageList_AddIcon(hColImageList, hIcon);
  362.     //IDI_COLUMNREAD - read-only column icon
  363.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_COLUMNREAD));
  364.     ImageList_AddIcon(hColImageList, hIcon);
  365.     //IDI_COLUMNLONG - long column icon
  366.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_COLUMNLONG));
  367.     ImageList_AddIcon(hColImageList, hIcon);
  368.  
  369.     //Set image list to the Table Window 
  370.     ListView_SetImageList(hWndCol, hColImageList, LVSIL_SMALL);
  371.  
  372.     //ListView COLUMNS
  373.     LV_InsertColumn(hWndCol,    COL_COLNAME,        "ColName");
  374.     LV_InsertColumn(hWndCol,    COL_COLTYPE,        "Type");
  375.     LV_InsertColumn(hWndCol,    COL_COLSIZE,        "Size");
  376.     LV_InsertColumn(hWndCol,    COL_COLORDINAL,        "Ordinal");
  377.     LV_InsertColumn(hWndCol,    COL_COLPREC,        "Precision");
  378.     LV_InsertColumn(hWndCol,    COL_COLSCALE,        "Scale");
  379.     LV_InsertColumn(hWndCol,    COL_COLISFIXED,        "ISFIXED");
  380.     LV_InsertColumn(hWndCol,    COL_COLISLONG,        "ISLONG");
  381.     LV_InsertColumn(hWndCol,    COL_COLISNULLABLE,    "ISNULLABLE");
  382.     LV_InsertColumn(hWndCol,    COL_COLWRITE,        "WRITE");
  383.     LV_InsertColumn(hWndCol,    COL_COLISROWID,        "ISROWID");
  384.     LV_InsertColumn(hWndCol,    COL_COLISROWVER,    "ISROWVER");
  385.  
  386.     //AutoSize all columns
  387.     for(ULONG i=0; i<=COL_COLISROWVER; i++)
  388.         SendMessage(hWndCol, LVM_SETCOLUMNWIDTH, (WPARAM)i,        (LPARAM)LVSCW_AUTOSIZE_USEHEADER);
  389.  
  390.     //Use Extended ListView Styles!
  391.     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);
  392.  
  393.     //Initialize the Provider List (if not done so already)
  394.     if(pCDataSource->m_rgProviderInfo == NULL)
  395.         pCDataSource->GetProviders();
  396.     
  397.     WCHAR wszBuffer[MAX_NAME_LEN*2];
  398.  
  399.     //Fill out the provider name combo box.
  400.     for(i=0; i<pCDataSource->m_cProviderInfo; i++)
  401.     {
  402.         //Add the name to the list
  403.         //Since we have the CBS_SORT turned on, the order in the Combo Box does
  404.         //not match our array, so we pass the array index (lParam) as the item data
  405.         swprintf(wszBuffer, wsz_PROVIDER_INFO_, pCDataSource->m_rgProviderInfo[i].wszName, pCDataSource->m_rgProviderInfo[i].wszDescription);
  406.         LONG iIndex = wSendMessage(hWndProv, CB_ADDSTRING, (WPARAM)0, wszBuffer);
  407.         SendMessage(hWndProv, CB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)i);
  408.     }
  409.     
  410.     //By default, it selects MSDASQL
  411.     if(pCDataSource->m_pwszProviderName == NULL)
  412.         pCDataSource->m_pwszProviderName = L"MSDASQL";
  413.  
  414.     //Try and select the previous selected Provider
  415.     if(CB_ERR == wSendMessage(hWndProv, CB_SELECTSTRING, 0, pCDataSource->m_pwszProviderName))
  416.     {
  417.         //If not found, just select the first one
  418.         SendMessage(hWndProv, CB_SETCURSEL, 0, 0);
  419.     }
  420.  
  421.     //Indicate were not in the middle of an TreeView editing command
  422.     m_fEditing = FALSE;
  423.     
  424.     // Enable Connect button only if there are providers installed.
  425.     EnableWindow(GetDlgItem(m_hWnd, IDB_FROM_CONNECT), SendMessage(hWndProv, CB_GETCURSEL, 0, 0L) != CB_ERR);
  426.     return TRUE;
  427. }
  428.  
  429.  
  430. /////////////////////////////////////////////////////////////////////////////
  431. // BOOL CS1Dialog::RefreshControls
  432. //
  433. /////////////////////////////////////////////////////////////////////////////
  434. BOOL CS1Dialog::RefreshControls()
  435. {
  436.     CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
  437.     CDataSource* pCDataSource = pCFromTable->m_pCDataSource;
  438.  
  439.     // Must have a connection to edit other controls
  440.     BOOL fConnected = pCFromTable->IsConnected();
  441.     ULONG cSelColumns = SendDlgItemMessage(m_hWnd, IDL_COLUMNS, LVM_GETSELECTEDCOUNT, 0, 0);
  442.  
  443.     //Enable dialog items, only if connected
  444.     EnableWindow(GetDlgItem(m_hWnd, IDL_TABLES),        fConnected);
  445.     EnableWindow(GetDlgItem(m_hWnd, IDL_COLUMNS),        fConnected);
  446.     EnableWindow(GetDlgItem(m_hWnd, IDT_FROMTABLEHELP),    fConnected);
  447.      
  448.     //Enable OK/Next if there is a table and at least 1 column selected
  449.     EnableWindow(GetDlgItem(m_hWnd, IDOK),    fConnected && cSelColumns);
  450.  
  451.     //Store the selected ProviderName and ProviderDesc
  452.     LONG iSel = 0;
  453.     if((iSel = SendMessage(GetDlgItem(m_hWnd, IDC_PROVIDER_NAME), CB_GETCURSEL, 0, 0L)) != CB_ERR)
  454.     {
  455.         //Since we have the CBS_SORT turned on, the order in the Combo Box does
  456.         //not match our array, so we pass the array index (lParam) as the item data
  457.         LONG lParam = SendMessage(GetDlgItem(m_hWnd, IDC_PROVIDER_NAME), CB_GETITEMDATA, iSel, 0L);
  458.         ASSERT(lParam < (LONG)pCDataSource->m_cProviderInfo);
  459.         pCDataSource->m_pwszProviderName = pCDataSource->m_rgProviderInfo[lParam].wszName;
  460.         pCDataSource->m_pwszProviderParseName = pCDataSource->m_rgProviderInfo[lParam].wszParseName;
  461.     }
  462.  
  463.     // Show user the connection string
  464.     if(fConnected)
  465.     {
  466.         //CONNECT_STRING
  467.         wSetDlgItemText(m_hWnd, IDT_CONNECT, wsz_CONNECT_STRING_, 
  468.             pCDataSource->m_pwszProviderName,
  469.             pCDataSource->m_pwszDataSource, 
  470.             pCDataSource->m_pwszDBMS,
  471.             pCDataSource->m_pwszDBMSVer,
  472.             pCDataSource->m_pwszProviderFileName,
  473.             pCDataSource->m_pwszProviderVer);
  474.             
  475.         //TABLEHELPMSG
  476.         //Display the Qualified TableName
  477.         if(pCFromTable->m_TableInfo.wszTableName[0])
  478.             wSetDlgItemText(m_hWnd, IDT_FROMTABLEHELP, wsz_FROMQUALTABLE_, pCFromTable->m_wszQualTableName, cSelColumns);
  479.         else 
  480.             wSetDlgItemText(m_hWnd, IDT_FROMTABLEHELP, wsz_FROMTABLEHELP_, pCDataSource->m_pwszTableTerm);
  481.     }
  482.     else
  483.     {
  484.         //NO CONNECT_STRING
  485.         wSetDlgItemText(m_hWnd, IDT_CONNECT, wsz_NOT_CONNECTED);
  486.     }
  487.         
  488.     return TRUE;
  489. }
  490.  
  491.  
  492.  
  493. /////////////////////////////////////////////////////////////////////////////
  494. // BOOL CS1Dialog::GetTableColInfo
  495. //
  496. /////////////////////////////////////////////////////////////////////////////
  497. BOOL CS1Dialog::GetTableColInfo(HWND hWndCol)
  498. {
  499.     CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
  500.  
  501.     // Get the count of selected items
  502.     LONG cSelColumns = SendMessage(hWndCol, LVM_GETSELECTEDCOUNT, (WPARAM)0, (LPARAM)0);
  503.     LONG iIndex = -1;
  504.  
  505.     //Loop over all the selected columns in the list
  506.     pCFromTable->m_cColumns = cSelColumns;
  507.     for(LONG i=0; i<cSelColumns; i++) 
  508.     {
  509.         iIndex = SendMessage(hWndCol, LVM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)LVNI_SELECTED);
  510.         
  511.         //"compact" the m_rgColDesc array to only the selected items
  512.         if(iIndex != LVM_ERR)
  513.             memmove(&pCFromTable->m_rgColDesc[i], &pCFromTable->m_rgColDesc[iIndex], sizeof(COLDESC));
  514.     }
  515.     return TRUE;
  516. }
  517.  
  518.  
  519. /////////////////////////////////////////////////////////////////////////////
  520. // BOOL CS1Dialog::CreateTableNode
  521. //
  522. /////////////////////////////////////////////////////////////////////////////
  523. BOOL CS1Dialog::CreateTableNode(TREEINFO* rgTreeInfo, ULONG ulNameOffset, LONG iParam, LONG iImage, LONG iSelectedImage)
  524. {
  525.     //ulNameOffset is the offset into TABELEINFO indicating
  526.     //Catalog / Schema / Type name were interested in comparing
  527.     ASSERT(ulNameOffset == offsetof(TABLEINFO, wszCatalogName)
  528.         || ulNameOffset == offsetof(TABLEINFO, wszSchemaName)
  529.         || ulNameOffset == offsetof(TABLEINFO, wszType));
  530.     
  531.     //Create the specified node in the tree.
  532.     //Basically this is a fairly complex function that builds the nodes to the 
  533.     //TreeView control, listing Catalog/Schema/TableType/TableName heieracrcy.
  534.  
  535.     //This is an extremly simple algortym that loops over the specified column 
  536.     //(Catalog/Schema/Type) and adds only unique names as a node to the TreeView.
  537.     //It then updates "rgTreeInfo" hParents and hItems accordingly.
  538.  
  539.     CHAR szBuffer[MAX_NAME_LEN];
  540.  
  541.     //Loop over all Tables
  542.     ULONG cFoundInfo = 0;
  543.     for(ULONG i=0; i<m_cTables; i++)
  544.     {
  545.         BOOL bFound = FALSE;
  546.         WCHAR* pwszName = (WCHAR*)((BYTE*)&m_rgTableInfo[i] + ulNameOffset);
  547.  
  548.         //Try to find Type value in the FoundList
  549.         for(ULONG j=0; j<cFoundInfo; j++)
  550.         {
  551.             ULONG ulFoundIndex = rgTreeInfo[j].ulIndex;
  552.             WCHAR* pwszFoundName = (WCHAR*)((BYTE*)&m_rgTableInfo[ulFoundIndex] + ulNameOffset);
  553.             
  554.             if(wcscmp(pwszName, pwszFoundName)==0
  555.                 && rgTreeInfo[i].hParent == rgTreeInfo[ulFoundIndex].hParent)
  556.             {
  557.                 bFound = TRUE;
  558.                 rgTreeInfo[i].hItem = rgTreeInfo[ulFoundIndex].hItem;
  559.                 break;
  560.             }
  561.         }    
  562.         
  563.         if(!bFound && pwszName[0])
  564.         {
  565.             //Add it to the list
  566.             rgTreeInfo[cFoundInfo].ulIndex = i;
  567.             cFoundInfo++;
  568.  
  569.             //Add it to the TreeView
  570.             ConvertToMBCS(pwszName, szBuffer, MAX_NAME_LEN);
  571.             rgTreeInfo[i].hItem = TV_InsertItem(GetDlgItem(m_hWnd, IDL_TABLES), rgTreeInfo[i].hParent, TVI_SORT, szBuffer, iParam, iImage, iSelectedImage);
  572.         }
  573.     }
  574.  
  575.     //Update Parents
  576.     for(i=0; i<m_cTables; i++)
  577.         rgTreeInfo[i].hParent = rgTreeInfo[i].hItem;
  578.  
  579.     return TRUE;
  580. }
  581.  
  582. /////////////////////////////////////////////////////////////////////////////
  583. // BOOL CS1Dialog::ResetTableList
  584. //
  585. /////////////////////////////////////////////////////////////////////////////
  586. BOOL CS1Dialog::ResetTableList(HWND hWndTable, HWND hWndCol)
  587. {
  588.     HRESULT hr;
  589.     CHAR            szBuffer[MAX_NAME_LEN];
  590.  
  591.     IRowset* pIRowset = NULL;
  592.     IAccessor* pIAccessor = NULL;
  593.     
  594.     //get the data
  595.     HROW*    rghRows = NULL;
  596.     ULONG    i,cRowsObtained = 0;
  597.     BOOL    bFound = FALSE;
  598.  
  599.     HACCESSOR hAccessor = DB_NULL_HACCESSOR;
  600.     TREEINFO* rgTreeInfo = NULL;
  601.  
  602.     //Use the passed in Session interface
  603.     CTable*    pCFromTable = m_pCTableCopy->m_pCFromTable;
  604.     CDataSource* pCFromDataSource = pCFromTable->m_pCDataSource;
  605.     IOpenRowset* pIOpenRowset = pCFromTable->m_pCDataSource->m_pIOpenRowset;
  606.     IDBSchemaRowset* pIDBSchemaRowset = pCFromTable->m_pCDataSource->m_pIDBSchemaRowset;
  607.  
  608.     //Delete all previous items
  609.     SendMessage(hWndTable, TVM_DELETEITEM, (WPARAM)0, (LPARAM)TVI_ROOT);
  610.     SendMessage(hWndCol, LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0);
  611.  
  612.     // Bind the user and table name for the list
  613.     const static ULONG cBindings = 4;
  614.     const static DBBINDING rgBindings[cBindings] = 
  615.     {
  616.         //TABLE_CATALOG
  617.         1,                 
  618.         offsetof(TABLEINFO, wszCatalogName),    // offset of value in consumers buffer
  619.         0,                                    // offset of length
  620.         0,                                    // offset of status
  621.         NULL,                                // reserved
  622.         NULL,                                // for ole object
  623.         NULL,                                // reserved
  624.         DBPART_VALUE,                        // specifies Value is bound only                                        
  625.         DBMEMOWNER_CLIENTOWNED,                // memory is client owned
  626.         DBPARAMIO_NOTPARAM,                    // 
  627.         MAX_NAME_LEN,                        // size in bytes of the value part in the consumers buffer
  628.         0,                                     // reserved
  629.         DBTYPE_WSTR,                         // data type indicator
  630.         0,                                    // precision
  631.         0,                                     // scale
  632.  
  633.         //TABLE_SCHEMA
  634.         2,                 
  635.         offsetof(TABLEINFO, wszSchemaName),    // offset of value in consumers buffer
  636.         0,                                    // offset of length
  637.         0,                                    // offset of status
  638.         NULL,                                // reserved
  639.         NULL,                                // for ole object
  640.         NULL,                                // reserved
  641.         DBPART_VALUE,                        // specifies Value is bound only                                        
  642.         DBMEMOWNER_CLIENTOWNED,                // memory is client owned
  643.         DBPARAMIO_NOTPARAM,                    // 
  644.         MAX_NAME_LEN,                        // size in bytes of the value part in the consumers buffer
  645.         0,                                     // reserved
  646.         DBTYPE_WSTR,                         // data type indicator
  647.         0,                                    // precision
  648.         0,                                     // scale
  649.  
  650.         //TABLE_NAME
  651.         3,                                     // ordinal
  652.         offsetof(TABLEINFO, wszTableName),        // offset of value in consumers buffer
  653.         0,                                    // offset of length in consumers buffer
  654.         0,                                    // offset of status in consumers buffer
  655.         NULL,                                // reserved
  656.         NULL,                                // for ole object
  657.         NULL,                                // reserved
  658.         DBPART_VALUE,                        // specifies Value only
  659.         DBMEMOWNER_CLIENTOWNED,                // memory is client owned
  660.         DBPARAMIO_NOTPARAM,                    // input param
  661.         MAX_NAME_LEN,                        // size in bytes of the value part in the consumers buffer
  662.         0,                                     // reserved
  663.         DBTYPE_WSTR,                         // data type indicator
  664.         0,                                    // precision
  665.         0,                                     // scale
  666.  
  667.         //TABLE_TYPE
  668.         4,                                     // ordinal
  669.         offsetof(TABLEINFO, wszType),    // offset of value in consumers buffer
  670.         0,                                    // offset of length in consumers buffer
  671.         0,                                    // offset of status in consumers buffer
  672.         NULL,                                // reserved
  673.         NULL,                                // for ole object
  674.         NULL,                                // reserved
  675.         DBPART_VALUE,                        // specifies Value only
  676.         DBMEMOWNER_CLIENTOWNED,                // memory is client owned
  677.         DBPARAMIO_NOTPARAM,                    // input param
  678.         MAX_NAME_LEN,                        // size in bytes of the value part in the consumers buffer
  679.         0,                                     // reserved
  680.         DBTYPE_WSTR,                         // data type indicator
  681.         0,                                    // precision
  682.         0,                                     // scale
  683.        };
  684.  
  685.     //Reset TableInfo
  686.     m_cTables = 0;
  687.     SAFE_FREE(m_rgTableInfo);
  688.  
  689.     //Provider doesn't have to support IDBSchemaRowset
  690.     if(pIDBSchemaRowset)
  691.     {
  692.         //GetRowset
  693.         //DBSCHEMA_TABLES is required a SCHEMA (if IDBSchemaRowset is supported)
  694.         XTESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_TABLES, 0, NULL, IID_IRowset, 0, NULL,(IUnknown **)&pIRowset));
  695.  
  696.         //Create the Accessor
  697.         XTESTC(hr = pIRowset->QueryInterface(IID_IAccessor, (void **)&pIAccessor));
  698.         XTESTC(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, rgBindings, 0, &hAccessor, NULL));
  699.  
  700.         //Grab all the rows
  701.         while(TRUE)
  702.         {
  703.             XTESTC(hr = pIRowset->GetNextRows(NULL, 0, MAX_BLOCK_SIZE, &cRowsObtained, &rghRows));
  704.             
  705.             //ENDOFROWSET
  706.             if(cRowsObtained==0)
  707.                 break;
  708.         
  709.             //Realloc Table struct for Table
  710.             SAFE_REALLOC(m_rgTableInfo, TABLEINFO, m_cTables + cRowsObtained);
  711.             memset(&m_rgTableInfo[m_cTables], 0, cRowsObtained*sizeof(TABLEINFO));
  712.  
  713.             //Loop over the rows retrived
  714.             for(i=0; i<cRowsObtained; i++) 
  715.             {
  716.                 //Get the Data
  717.                 XTESTC(hr = pIRowset->GetData(rghRows[i], hAccessor, &m_rgTableInfo[m_cTables]));
  718.                 m_cTables++;
  719.             }
  720.  
  721.             //Release the rows obtained
  722.             XTESTC(hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL));
  723.             SAFE_FREE(rghRows);
  724.         }
  725.     }
  726.  
  727.     //Provider doesn't have to support IDBSchemaRowset
  728.     if(pIDBSchemaRowset == NULL)
  729.     {
  730.         m_cTables = 1;
  731.         SAFE_ALLOC(m_rgTableInfo, TABLEINFO, 1);
  732.         memset(m_rgTableInfo, 0, sizeof(TABLEINFO));
  733.  
  734.         if(pCFromTable->m_TableInfo.wszTableName[0])
  735.         {
  736.             //Just Display the TableName in the EditBox
  737.             wcscpy(m_rgTableInfo[0].wszTableName, pCFromTable->m_TableInfo.wszTableName);
  738.         }
  739.         else
  740.         {
  741.             //Just Display "Enter - <TableTerm>"
  742.             wcscpy(m_rgTableInfo[0].wszTableName, L"Enter - ");
  743.             wcscat(m_rgTableInfo[0].wszTableName, pCFromDataSource->m_pwszTableTerm);
  744.         }
  745.     }
  746.     
  747.  
  748.     //Create rgTreeInfo array
  749.     SAFE_ALLOC(rgTreeInfo, TREEINFO, m_cTables);
  750.     memset(rgTreeInfo, 0, m_cTables*sizeof(TREEINFO));
  751.  
  752.     //Create Tree Nodes for the TreeView control
  753.     CreateTableNode(rgTreeInfo, offsetof(TABLEINFO, wszCatalogName), -1, ICON_CATALOG, ICON_CATALOG); 
  754.     CreateTableNode(rgTreeInfo, offsetof(TABLEINFO, wszSchemaName),     -1, ICON_SCHEMA, ICON_SCHEMA); 
  755.     CreateTableNode(rgTreeInfo, offsetof(TABLEINFO, wszType),         -1, ICON_TYPE, ICON_TYPE); 
  756.  
  757.     //Now display all the tables
  758.     for(i=0; i<m_cTables; i++)
  759.     {
  760.         //Add it to the TreeView
  761.         ConvertToMBCS(m_rgTableInfo[i].wszTableName, szBuffer, MAX_NAME_LEN);
  762.  
  763.         if(wcscmp(m_rgTableInfo[i].wszType, L"TABLE")==0)
  764.             rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_TABLE, ICON_TABLE);
  765.         else if(wcscmp(m_rgTableInfo[i].wszType, L"VIEW")==0)
  766.             rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_VIEW, ICON_VIEW);
  767.         else if(wcscmp(m_rgTableInfo[i].wszType, L"SYSTEM TABLE")==0)
  768.             rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_SYSTABLE, ICON_SYSTABLE);
  769.         else
  770.             rgTreeInfo[i].hItem = TV_InsertItem(hWndTable, rgTreeInfo[i].hParent, TVI_SORT, szBuffer, (LONG)i, ICON_SYNONYM, ICON_SYNONYM);
  771.     }
  772.  
  773.     // If there was a previous selection, select it again on Back
  774.     bFound = FALSE;
  775.     if(pCFromTable->m_TableInfo.wszTableName[0])
  776.     {
  777.         //Find the previously selected TableName
  778.         //With TreeView controls there is no "Find" method as in ListView controls!
  779.         //So we have to simulate our own find, by seraching for the TableName
  780.         for(i=0; i<m_cTables; i++)
  781.         {
  782.             if(memcmp(&m_rgTableInfo[i], &pCFromTable->m_TableInfo, sizeof(TABLEINFO))==0)
  783.             {
  784.                 bFound = TRUE;
  785.                 //Select Table in the TreeView control
  786.                 SendMessage(hWndTable, TVM_SELECTITEM, (WPARAM)TVGN_CARET, (LPARAM)rgTreeInfo[i].hItem);
  787.                 ResetColInfo(GetDlgItem(m_hWnd, IDL_COLUMNS));
  788.                 break;
  789.             }
  790.         }
  791.     }
  792.  
  793.     if(!bFound)
  794.     {
  795.         //Reset TableInfo
  796.         memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
  797.     
  798.         //Otheriwse if there was no previous selection, default to auto expand
  799.         //the "TABLE" type, or the first type in the tree
  800.         bFound = FALSE;
  801.         for(i=0; i<m_cTables; i++)
  802.         {
  803.             if(wcscmp(m_rgTableInfo[i].wszType, L"TABLE")==0)
  804.             {
  805.                 bFound = TRUE;
  806.                 SendMessage(hWndTable, TVM_ENSUREVISIBLE, (WPARAM)0, (LPARAM)rgTreeInfo[i].hItem);
  807.                 break;
  808.             }
  809.         }
  810.  
  811.         if(!bFound && m_cTables)
  812.             SendMessage(hWndTable, TVM_ENSUREVISIBLE, (WPARAM)0, (LPARAM)rgTreeInfo[0].hItem);
  813.     }
  814.  
  815.  
  816. CLEANUP:
  817.     if(hAccessor && pIAccessor)
  818.         XTEST(pIAccessor->ReleaseAccessor(hAccessor,NULL));
  819.  
  820.     SAFE_RELEASE(pIRowset);
  821.     SAFE_RELEASE(pIAccessor);
  822.  
  823.     SAFE_FREE(rgTreeInfo);
  824.     SAFE_FREE(rghRows);
  825.     return hr==S_OK;
  826. }
  827.  
  828.  
  829. /////////////////////////////////////////////////////////////////////////////
  830. // BOOL CS1Dialog::ResetColInfo
  831. //
  832. /////////////////////////////////////////////////////////////////////////////
  833. BOOL CS1Dialog::ResetColInfo(HWND hWndCol)
  834. {
  835.     HRESULT hr;
  836.     CHAR    szBuffer[MAX_NAME_LEN];
  837.     ULONG    i;
  838.     LONG    lFoundColumn;
  839.  
  840.     CTable*    pCFromTable = m_pCTableCopy->m_pCFromTable;
  841.     IOpenRowset* pIOpenRowset = pCFromTable->m_pCDataSource->m_pIOpenRowset;
  842.  
  843.     //Save the currently selected columns
  844.     ULONG cSelColumns = pCFromTable->m_cColumns;
  845.     COLDESC* rgSelColDesc = pCFromTable->m_rgColDesc;
  846.     
  847.     //Reset current Window Column ListView
  848.     SendMessage(hWndCol, LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0L);
  849.     
  850.     // Get a list of columns based on the selected table
  851.     pCFromTable->m_cColumns = 0;
  852.     pCFromTable->m_rgColDesc = NULL;
  853.     QTESTC(hr = pCFromTable->GetColInfo(IDR_PARAM_SETS));
  854.  
  855.     //Loop through all columns and update window
  856.     for(i=0; i<pCFromTable->m_cColumns; i++)
  857.     {    
  858.         COLDESC* pColDesc = &pCFromTable->m_rgColDesc[i];
  859.  
  860.         //COLNAME (item)
  861.         ConvertToMBCS(pColDesc->wszColName, szBuffer, MAX_NAME_LEN);
  862.         LV_InsertItem(hWndCol, i, COL_COLNAME, szBuffer, 0, pColDesc->dwFlags & (DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_WRITEUNKNOWN) ? ((pColDesc->dwFlags & DBCOLUMNFLAGS_ISLONG) ? ICON_LONG : ICON_COLUMN) : ICON_READONLY);
  863.  
  864.         //COLTYPE (subitem)
  865.         ConvertToMBCS(GetDBTypeName(pColDesc->wType), szBuffer, MAX_NAME_LEN);
  866.         LV_InsertItem(hWndCol, i, COL_COLTYPE, szBuffer);
  867.  
  868.         //Ordinal (SubItem)
  869.         sprintf(szBuffer, "%d", pColDesc->iOrdinal);
  870.         LV_InsertItem(hWndCol, i, COL_COLORDINAL, szBuffer);
  871.  
  872.         //ColumnSize (SubItem)
  873.         sprintf(szBuffer, "%d", pColDesc->ulColumnSize);
  874.         LV_InsertItem(hWndCol, i, COL_COLSIZE, szBuffer);
  875.  
  876.         //Precision (SubItem)
  877.         sprintf(szBuffer, "%d", pColDesc->bPrecision);
  878.         LV_InsertItem(hWndCol, i, COL_COLPREC, szBuffer);
  879.  
  880.         //Scale (SubItem)
  881.         sprintf(szBuffer, "%d", pColDesc->bScale);
  882.         LV_InsertItem(hWndCol, i, COL_COLSCALE, szBuffer);
  883.  
  884.         //FLAGS (SubItem)
  885.         LV_InsertItem(hWndCol, i, COL_COLISFIXED, pColDesc->dwFlags & DBCOLUMNFLAGS_ISFIXEDLENGTH ? "TRUE" : "FALSE");
  886.         LV_InsertItem(hWndCol, i, COL_COLISLONG, pColDesc->dwFlags & DBCOLUMNFLAGS_ISLONG ? "TRUE" : "FALSE");
  887.         LV_InsertItem(hWndCol, i, COL_COLISNULLABLE, pColDesc->dwFlags & DBCOLUMNFLAGS_ISNULLABLE ? "TRUE" : "FALSE");
  888.         LV_InsertItem(hWndCol, i, COL_COLWRITE, pColDesc->dwFlags & (DBCOLUMNFLAGS_WRITE | DBCOLUMNFLAGS_WRITEUNKNOWN) ? "TRUE" : "FALSE");
  889.         LV_InsertItem(hWndCol, i, COL_COLISROWID, pColDesc->dwFlags & DBCOLUMNFLAGS_ISROWID ? "TRUE" : "FALSE");
  890.         LV_InsertItem(hWndCol, i, COL_COLISROWVER, pColDesc->dwFlags & DBCOLUMNFLAGS_ISROWVER ? "TRUE" : "FALSE");
  891.  
  892.     }
  893.     
  894.     // If there is an existing columns list (only on Back or error), then
  895.     // the user already has a list so use it.
  896.     lFoundColumn = -1;
  897.     for(i=0; i<cSelColumns; i++) 
  898.     {
  899.         //Find the Column Name in the Window List
  900.         ConvertToMBCS(rgSelColDesc[i].wszColName, szBuffer, MAX_NAME_LEN);
  901.         lFoundColumn = LV_FindItem(hWndCol, szBuffer, lFoundColumn);
  902.             
  903.         //Select the Column Name if found in the list, and bring into view
  904.         if(lFoundColumn != LVM_ERR)
  905.         {
  906.             LV_SetItemState(hWndCol, lFoundColumn, COL_COLNAME, LVIS_SELECTED, LVIS_SELECTED);
  907.  
  908.             //Ensure that the first item is Visible
  909.             if(i==0)
  910.                 SendMessage(hWndCol, LVM_ENSUREVISIBLE, (WPARAM)lFoundColumn, (LPARAM)FALSE);
  911.         }    
  912.     }
  913.     
  914.     //Otherwise, just select all as default
  915.     if(cSelColumns == 0)
  916.     {
  917.         for(i=0; i<pCFromTable->m_cColumns; i++)
  918.             LV_SetItemState(hWndCol, i, COL_COLNAME, LVIS_SELECTED, LVIS_SELECTED);
  919.     }
  920.  
  921. CLEANUP:
  922.     SAFE_FREE(rgSelColDesc);
  923.     return hr==S_OK;
  924. }
  925.  
  926.  
  927. /////////////////////////////////////////////////////////////////////////////
  928. // BOOL CS1Dialog::ChangeTableName
  929. //
  930. /////////////////////////////////////////////////////////////////////////////
  931. BOOL CS1Dialog::ChangeTableName(LONG iIndex)
  932. {
  933.     CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
  934.     CTable* pCToTable = m_pCTableCopy->m_pCToTable;
  935.     
  936.     //Index must fall with the m_rgTableInfo array range
  937.     //Otherwise we have selected a "tree-folder" and need to free the column list
  938.     if(iIndex < 0 || iIndex >= (LONG)m_cTables)
  939.     {
  940.         //Resest TableName
  941.         memset(&pCFromTable->m_TableInfo, 0, sizeof(TABLEINFO));
  942.  
  943.         //Reset current Window Column ListView
  944.         SendMessage(GetDlgItem(m_hWnd, IDL_COLUMNS), LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0L);
  945.         return FALSE;
  946.     }
  947.  
  948.     //Only change the TableName if not equal to "Enter - <TableTerm>"
  949.     if(wcsstr(m_rgTableInfo[iIndex].wszTableName, L"Enter - "))
  950.         return FALSE;
  951.  
  952.     //TableInfo
  953.     memcpy(&pCFromTable->m_TableInfo, &m_rgTableInfo[iIndex], sizeof(TABLEINFO));
  954.     
  955.     //QualifiedTableName syntax
  956.     // #1.  TableName
  957.     // #2.  Owner.TableName (always a ".")
  958.     // #3.  Catalog[CatalogSeperator]TableName
  959.     // #4.  Catalog[CatalogSeperator]Owner.TableName
  960.     if(pCFromTable->m_TableInfo.wszSchemaName[0])
  961.         swprintf(pCFromTable->m_wszQualTableName, L"%s.%s", pCFromTable->m_TableInfo.wszSchemaName, pCFromTable->m_TableInfo.wszTableName);
  962.     else
  963.         wcscpy(pCFromTable->m_wszQualTableName, pCFromTable->m_TableInfo.wszTableName);
  964.  
  965.     //Free the current columns list, since the new 
  966.     //table will have diffent columns
  967.     pCFromTable->m_cColumns = 0;
  968.     SAFE_FREE(pCFromTable->m_rgColDesc);
  969.     
  970.     //Reset the column list, since we have a new table
  971.     ResetColInfo(GetDlgItem(m_hWnd, IDL_COLUMNS));
  972.  
  973.     //Reset the index list, since we have a new table
  974.     pCFromTable->m_cIndexes = 0;
  975.     SAFE_FREE(pCFromTable->m_rgIndexInfo);
  976.  
  977.     //Reset the "To" table, since we have a new table
  978.     memset(&pCToTable->m_TableInfo, 0, sizeof(TABLEINFO));
  979.     return TRUE;
  980. }
  981.