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 / step2.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-12  |  20.1 KB  |  752 lines

  1. //-----------------------------------------------------------------------------
  2. // Microsoft OLE DB TABLECOPY Sample
  3. // Copyright (C) 1995-1998 Microsoft Corporation
  4. //
  5. // @doc
  6. //
  7. // @module STEP2.CPP
  8. //
  9. //-----------------------------------------------------------------------------
  10.  
  11.  
  12. /////////////////////////////////////////////////////////////////////
  13. // Includes
  14. //
  15. /////////////////////////////////////////////////////////////////////
  16. #include "wizard.h"
  17. #include "common.h"
  18. #include "tablecopy.h"
  19. #include "table.h"
  20.  
  21.  
  22.  
  23. /////////////////////////////////////////////////////////////////////
  24. // Defines
  25. //
  26. /////////////////////////////////////////////////////////////////////
  27. //Enum Index Header for the ListView controls
  28. enum COL_HEADERS
  29. {
  30.     //IDL_INDEXES
  31.     COL_INDEXNAME        = 0,    //IndexInfo.wszIndexName
  32.     COL_INDEXCOLNAME    = 1,    //IndexInfo.wszColName
  33.     COL_UNIQUE            = 2,    //IndexInfo.fUnique
  34.     COL_PRIMARYKEY        = 3,    //IndexInfo.fIsPrimaryKey
  35.     COL_COLLATION        = 4,    //IndexInfo.dwCollation
  36.     COL_AUTOUPDATE        = 5,    //IndexInfo.fAutoUpdate
  37.     COL_NULLS            = 6,    //IndexInfo.dwNulls
  38. };
  39.  
  40. enum INDEX_TYPE
  41. {
  42.     INDEXTYPE_INDEX            = 0,
  43.     INDEXTYPE_PRIMARYKEY    = 1,
  44. };
  45.  
  46. /////////////////////////////////////////////////////////////////////
  47. // CS2Dialog::CS2Dialog
  48. //
  49. /////////////////////////////////////////////////////////////////////
  50. CS2Dialog::CS2Dialog(HWND hWnd, HINSTANCE hInst, CTableCopy* pCTableCopy)
  51.     : CDialogBase(hWnd, hInst)
  52. {
  53.     ASSERT(pCTableCopy);
  54.     m_pCTableCopy = pCTableCopy;
  55. }
  56.  
  57.  
  58. /////////////////////////////////////////////////////////////////////
  59. // CS2Dialog::~CS2Dialog
  60. //
  61. /////////////////////////////////////////////////////////////////////
  62. CS2Dialog::~CS2Dialog()
  63. {
  64. }
  65.  
  66.  
  67. /////////////////////////////////////////////////////////////////////////////
  68. // ULONG CS2Dialog::Display
  69. //
  70. /////////////////////////////////////////////////////////////////////////////
  71. ULONG CS2Dialog::Display()
  72. {
  73.     //Create a modal dialog box
  74.     return DialogBoxParam(m_hInst, MAKEINTRESOURCE(IDD_INDEX_INFO), NULL, DlgProc, (LPARAM)this);
  75. }
  76.  
  77.  
  78. /////////////////////////////////////////////////////////////////////
  79. // CS2Dialog::DlgProc
  80. //
  81. /////////////////////////////////////////////////////////////////////
  82. BOOL WINAPI CS2Dialog::DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  83. {
  84.     switch(msg) 
  85.     {
  86.         case WM_INITDIALOG:
  87.         {
  88.             Busy();
  89.             //Store the "this" pointer, since this is a static method
  90.             CS2Dialog* pThis = (CS2Dialog*)lParam;
  91.             SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);
  92.             CTableCopy* pCTableCopy = pThis->m_pCTableCopy;
  93.             CWizard* pCWizard = pCTableCopy->m_pCWizard;
  94.  
  95.             LONG iPrevStep = pCWizard->m_iPrevStep;
  96.  
  97.             //On INIT we know we have a valid hWnd to store
  98.             CenterDialog(hWnd);
  99.             pThis->m_hWnd = hWnd;
  100.  
  101.             pThis->InitControls();
  102.             pThis->RefreshControls();
  103.  
  104.             pThis->ResetIndexList(GetDlgItem(hWnd, IDL_INDEXES));
  105.             pCWizard->DestroyPrevStep(WIZ_STEP2);
  106.             
  107.             //No since in even displaying this Dialog if there
  108.             //are no indexes...
  109.             if(pCTableCopy->m_pCFromTable->m_cIndexes == 0)
  110.                 pCWizard->DisplayStep(iPrevStep==WIZ_STEP1 ? WIZ_STEP3 : WIZ_STEP1);
  111.  
  112.             return HANDLED_MSG;
  113.         }
  114.         
  115.         case WM_COMMAND:
  116.         {
  117.             //Obtain the "this" pointer
  118.             CS2Dialog* pThis = (CS2Dialog*)GetWindowLong(hWnd, GWL_USERDATA);
  119.  
  120.             // All buttons are handled the same way
  121.             switch(GET_WM_COMMAND_ID(wParam, lParam)) 
  122.             {
  123.                 case IDOK:
  124.                 case IDB_PREV:
  125.                     //Record all selected indexes
  126.                     Busy();
  127.                     pThis->RecordSelectedIndexes(GetDlgItem(hWnd, IDL_INDEXES));
  128.                     pThis->m_pCTableCopy->m_pCWizard->DisplayStep((GET_WM_COMMAND_ID(wParam, lParam) == IDOK) ? WIZ_STEP3 : WIZ_STEP1);
  129.                     return HANDLED_MSG;
  130.  
  131.                 case IDCANCEL:
  132.                     //Record all selected indexes
  133.                     Busy();
  134.                     EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam));
  135.                     return HANDLED_MSG;
  136.             }
  137.         }
  138.     }
  139.  
  140.     return UNHANDLED_MSG;
  141. }
  142.  
  143.  
  144. /////////////////////////////////////////////////////////////////////////////
  145. // BOOL CS2Dialog::InitControls
  146. //
  147. /////////////////////////////////////////////////////////////////////////////
  148. BOOL CS2Dialog::InitControls()
  149. {
  150.     HWND hWndIndexes = GetDlgItem(m_hWnd, IDL_INDEXES);
  151.     
  152.     //Create the Index ImageList
  153.     HIMAGELIST hIndexImageList = ImageList_Create(16, 16, ILC_MASK, 1, 0 );
  154.  
  155.     //IDI_INDEX - normal index icon
  156.     HICON hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_INDEX));
  157.     ImageList_AddIcon(hIndexImageList, hIcon);
  158.     //IDI_PRIMARYKEY - primary key index icon
  159.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_PRIMARYKEY));
  160.     ImageList_AddIcon(hIndexImageList, hIcon);
  161.  
  162.     //Set image list to the Table Window 
  163.     ListView_SetImageList(hWndIndexes, hIndexImageList, LVSIL_SMALL);
  164.  
  165.     //ListView COLUMNS
  166.     LV_InsertColumn(hWndIndexes,    COL_INDEXNAME,        "Index");
  167.     LV_InsertColumn(hWndIndexes,    COL_INDEXCOLNAME,    "ColName");
  168.     LV_InsertColumn(hWndIndexes,    COL_UNIQUE,            "Unique");
  169.     LV_InsertColumn(hWndIndexes,    COL_PRIMARYKEY,        "PrimaryKey");
  170.     LV_InsertColumn(hWndIndexes,    COL_COLLATION,        "Collation");
  171.     LV_InsertColumn(hWndIndexes,    COL_AUTOUPDATE,        "AutoUpdate");
  172.     LV_InsertColumn(hWndIndexes,    COL_NULLS,            "Nulls");
  173.  
  174.     //AutoSize all columns
  175.     for(ULONG i=0; i<=COL_NULLS; i++)
  176.         SendMessage(hWndIndexes, LVM_SETCOLUMNWIDTH, (WPARAM)i,        (LPARAM)LVSCW_AUTOSIZE_USEHEADER);
  177.  
  178.     //Use Extended ListView Styles!
  179.     SendMessage(hWndIndexes, 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);
  180.     return TRUE;
  181. }
  182.  
  183. /////////////////////////////////////////////////////////////////////////////
  184. // BOOL CS2Dialog::RefreshControls
  185. //
  186. /////////////////////////////////////////////////////////////////////////////
  187. BOOL CS2Dialog::RefreshControls()
  188. {
  189.     BOOL fSchemas = m_pCTableCopy->m_pCFromTable->m_pCDataSource->m_pIDBSchemaRowset != NULL;
  190.  
  191.     //Display IndexWindow if there are on Schemas
  192.     EnableWindow(GetDlgItem(m_hWnd, IDT_INDEXMSG),    fSchemas);
  193.     EnableWindow(GetDlgItem(m_hWnd, IDL_INDEXES),    fSchemas);
  194.     return TRUE;
  195. }
  196.  
  197.  
  198. /////////////////////////////////////////////////////////////////////////////
  199. // BOOL CS2Dialog::ResetIndexList
  200. //
  201. /////////////////////////////////////////////////////////////////////////////
  202. BOOL CS2Dialog::ResetIndexList(HWND hWnd)
  203. {
  204.     HRESULT hr;
  205.     CHAR    szBuffer[MAX_NAME_LEN*2];
  206.     
  207.     HROW* rghRows = NULL;
  208.     ULONG i,cRowsObtained = 0;
  209.     IRowset* pIRowset = NULL;
  210.  
  211.     IAccessor* pIAccessor = NULL;
  212.     HACCESSOR hAccessor = DB_NULL_HACCESSOR;
  213.     
  214.     //Use the passed in Session interface
  215.     CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
  216.     IOpenRowset* pIOpenRowset = pCFromTable->m_pCDataSource->m_pIOpenRowset;
  217.     IDBSchemaRowset* pIDBSchemaRowset = pCFromTable->m_pCDataSource->m_pIDBSchemaRowset;
  218.  
  219.     //Provider doesn't have to support IDBSchemaRowset
  220.     if(pIDBSchemaRowset == NULL)
  221.     {
  222.         return TRUE;
  223.     }
  224.     
  225.     //Save the currently selected indexes
  226.     ULONG cSelIndexes = pCFromTable->m_cIndexes;
  227.     INDEXINFO* rgSelIndexInfo = pCFromTable->m_rgIndexInfo;
  228.     
  229.     //Reset the current IndexInfo
  230.     pCFromTable->m_cIndexes = 0;
  231.     pCFromTable->m_rgIndexInfo = NULL;
  232.  
  233.     // Now make the call
  234.     SendMessage(hWnd, LVM_DELETEALLITEMS, (WPARAM)0, (LPARAM)0);
  235.  
  236.     // Bind the user and table name for the list
  237.     const static ULONG cBindings = 13;
  238.     const static DBBINDING rgBindings[cBindings] = 
  239.         {
  240.             //INDEX_NAME
  241.             6,                 
  242.             offsetof(INDEXINFO, wszIndexName),
  243.             0,
  244.             0,    
  245.             NULL,            
  246.             NULL,         
  247.             NULL,        
  248.             DBPART_VALUE,
  249.             DBMEMOWNER_CLIENTOWNED,        
  250.             DBPARAMIO_NOTPARAM, 
  251.             MAX_NAME_LEN,         
  252.             0,                 
  253.             DBTYPE_WSTR,     
  254.             0,    
  255.             0,                 
  256.  
  257.             //UNIQUE
  258.             8,                 
  259.             offsetof(INDEXINFO, fUnique),
  260.             0,
  261.             0,    
  262.             NULL,            
  263.             NULL,         
  264.             NULL,        
  265.             DBPART_VALUE,
  266.             DBMEMOWNER_CLIENTOWNED,        
  267.             DBPARAMIO_NOTPARAM, 
  268.             sizeof(VARIANT_BOOL),         
  269.             0,                 
  270.             DBTYPE_BOOL,     
  271.             0,    
  272.             0,                 
  273.  
  274.             //CLUSTERED
  275.             9,                 
  276.             offsetof(INDEXINFO, fClustered),
  277.             0,
  278.             0,    
  279.             NULL,            
  280.             NULL,         
  281.             NULL,        
  282.             DBPART_VALUE,
  283.             DBMEMOWNER_CLIENTOWNED,        
  284.             DBPARAMIO_NOTPARAM, 
  285.             sizeof(VARIANT_BOOL),         
  286.             0,                 
  287.             DBTYPE_BOOL,     
  288.             0,    
  289.             0,                 
  290.  
  291.             //TYPE
  292.             10,                 
  293.             offsetof(INDEXINFO, wType),
  294.             0,
  295.             0,    
  296.             NULL,            
  297.             NULL,         
  298.             NULL,        
  299.             DBPART_VALUE,
  300.             DBMEMOWNER_CLIENTOWNED,        
  301.             DBPARAMIO_NOTPARAM, 
  302.             sizeof(DBTYPE),         
  303.             0,                 
  304.             DBTYPE_UI2,     
  305.             0,    
  306.             0,                 
  307.  
  308.             //FILL_FACTOR
  309.             11,                 
  310.             offsetof(INDEXINFO, dwFillFactor),
  311.             0,
  312.             0,    
  313.             NULL,            
  314.             NULL,         
  315.             NULL,        
  316.             DBPART_VALUE,
  317.             DBMEMOWNER_CLIENTOWNED,        
  318.             DBPARAMIO_NOTPARAM, 
  319.             sizeof(LONG),         
  320.             0,                 
  321.             DBTYPE_I4,     
  322.             0,    
  323.             0,                 
  324.  
  325.             //INITIAL_SIZE
  326.             12,                 
  327.             offsetof(INDEXINFO, dwInitialSize),
  328.             0,
  329.             0,    
  330.             NULL,            
  331.             NULL,         
  332.             NULL,        
  333.             DBPART_VALUE,
  334.             DBMEMOWNER_CLIENTOWNED,        
  335.             DBPARAMIO_NOTPARAM, 
  336.             sizeof(LONG),         
  337.             0,                 
  338.             DBTYPE_I4,     
  339.             0,    
  340.             0,                 
  341.  
  342.             //NULLS
  343.             13,                 
  344.             offsetof(INDEXINFO, dwNulls),
  345.             0,
  346.             0,    
  347.             NULL,            
  348.             NULL,         
  349.             NULL,        
  350.             DBPART_VALUE,
  351.             DBMEMOWNER_CLIENTOWNED,        
  352.             DBPARAMIO_NOTPARAM, 
  353.             sizeof(LONG),         
  354.             0,                 
  355.             DBTYPE_I4,     
  356.             0,    
  357.             0,                 
  358.  
  359.             //SORT_BOOKMARKS
  360.             14,                 
  361.             offsetof(INDEXINFO, fSortBookmarks),
  362.             0,
  363.             0,    
  364.             NULL,            
  365.             NULL,         
  366.             NULL,        
  367.             DBPART_VALUE,
  368.             DBMEMOWNER_CLIENTOWNED,        
  369.             DBPARAMIO_NOTPARAM, 
  370.             sizeof(VARIANT_BOOL),         
  371.             0,                 
  372.             DBTYPE_BOOL,     
  373.             0,    
  374.             0,                 
  375.  
  376.             //AUTO_UPDATE
  377.             15,                 
  378.             offsetof(INDEXINFO, fAutoUpdate),
  379.             0,
  380.             0,    
  381.             NULL,            
  382.             NULL,         
  383.             NULL,        
  384.             DBPART_VALUE,
  385.             DBMEMOWNER_CLIENTOWNED,        
  386.             DBPARAMIO_NOTPARAM, 
  387.             sizeof(VARIANT_BOOL),         
  388.             0,                 
  389.             DBTYPE_BOOL,     
  390.             0,    
  391.             0,                 
  392.  
  393.             //NULL_COLLATION
  394.             16,                 
  395.             offsetof(INDEXINFO, dwNullCollation),
  396.             0,
  397.             0,    
  398.             NULL,            
  399.             NULL,         
  400.             NULL,        
  401.             DBPART_VALUE,
  402.             DBMEMOWNER_CLIENTOWNED,        
  403.             DBPARAMIO_NOTPARAM, 
  404.             sizeof(LONG),         
  405.             0,                 
  406.             DBTYPE_I4,     
  407.             0,    
  408.             0,                 
  409.             
  410.             //ORDINAL_POSITION
  411.             17,                 
  412.             offsetof(INDEXINFO, iOrdinal),
  413.             0,
  414.             0,    
  415.             NULL,            
  416.             NULL,         
  417.             NULL,        
  418.             DBPART_VALUE,
  419.             DBMEMOWNER_CLIENTOWNED,        
  420.             DBPARAMIO_NOTPARAM, 
  421.             sizeof(ULONG),         
  422.             0,                 
  423.             DBTYPE_UI4,     
  424.             0,    
  425.             0,                 
  426.             
  427.             //COLUMN_NAME
  428.             18,                 
  429.             offsetof(INDEXINFO, wszColName),
  430.             0,    
  431.             0,    
  432.             NULL,            
  433.             NULL,         
  434.             NULL,        
  435.             DBPART_VALUE,
  436.             DBMEMOWNER_CLIENTOWNED,        
  437.             DBPARAMIO_NOTPARAM, 
  438.             MAX_NAME_LEN,         
  439.             0,                 
  440.             DBTYPE_WSTR,     
  441.             0,    
  442.             0,                 
  443.         
  444.             //COLLATION
  445.             21,                 
  446.             offsetof(INDEXINFO, dwCollation),
  447.             0,    
  448.             0,    
  449.             NULL,            
  450.             NULL,         
  451.             NULL,        
  452.             DBPART_VALUE,     
  453.             DBMEMOWNER_CLIENTOWNED,        
  454.             DBPARAMIO_NOTPARAM, 
  455.             sizeof(DWORD),         
  456.             0,                 
  457.             DBTYPE_I4,     
  458.             0,    
  459.             0,                 
  460.         };
  461.  
  462.     //set up the restrictions
  463.     const ULONG cRestrictions = 5;
  464.     VARIANT     rgRestrictions[cRestrictions];
  465.     
  466.     //set up the restrictions
  467.     InitVariants(cRestrictions, rgRestrictions);
  468.     SetRestriction(&rgRestrictions[0], pCFromTable->m_pCDataSource->m_pwszCatalog);
  469.     SetRestriction(&rgRestrictions[1], pCFromTable->m_TableInfo.wszSchemaName);
  470.     SetRestriction(&rgRestrictions[4], pCFromTable->m_TableInfo.wszTableName);
  471.     
  472.     //GetRowset
  473.     //DBSCHEMA_INDEXES may not be supported by the driver. 
  474.     //If an error occurs, just don't display IndexInfo
  475.     QTESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_INDEXES, cRestrictions, rgRestrictions, 
  476.                                         IID_IRowset, 0, NULL, (IUnknown **)&pIRowset));
  477.  
  478.     XTESTC(hr = pIRowset->QueryInterface(IID_IAccessor, (void **)&pIAccessor));
  479.     
  480.     //Create Accessor for IndexInfo
  481.     XTESTC(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, rgBindings, 0, &hAccessor, NULL));
  482.  
  483.     while(TRUE)
  484.     {
  485.         XTESTC(hr = pIRowset->GetNextRows(NULL, 0, MAX_BLOCK_SIZE, &cRowsObtained, &rghRows));
  486.         
  487.         //ENDOFROWSET
  488.         if(cRowsObtained==0) 
  489.             break;
  490.         
  491.         //Realloc Table struct for Indexes
  492.         SAFE_REALLOC(pCFromTable->m_rgIndexInfo, INDEXINFO, pCFromTable->m_cIndexes + cRowsObtained);
  493.         memset(&pCFromTable->m_rgIndexInfo[pCFromTable->m_cIndexes], 0, cRowsObtained*sizeof(INDEXINFO));
  494.  
  495.         //Loop over rows obtained
  496.         for(ULONG i=0; i<cRowsObtained; i++) 
  497.         {    
  498.             INDEXINFO* pIndexInfo = &pCFromTable->m_rgIndexInfo[pCFromTable->m_cIndexes];
  499.             
  500.             //Get the Data
  501.             XTESTC(hr = pIRowset->GetData(rghRows[i], hAccessor, (void*)pIndexInfo));
  502.                         
  503.             //If this is an index the ordinal will be 1 based
  504.             if(pIndexInfo->iOrdinal==0)
  505.                 continue;
  506.                 
  507.             //Only list the index if the column was selected to be copied
  508.             for(ULONG iCol=0; iCol<pCFromTable->m_cColumns; iCol++)
  509.             {
  510.                 if(wcscmp(pCFromTable->m_rgColDesc[iCol].wszColName, pIndexInfo->wszColName)==0)
  511.                 {
  512.                     //Now that we have an actual index...
  513.                     pCFromTable->m_cIndexes++;
  514.                     break;
  515.                 }
  516.             }
  517.                         
  518.         }
  519.             
  520.         //Release all the rows
  521.         XTESTC(hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL));
  522.         SAFE_FREE(rghRows);
  523.     }
  524.  
  525.     //GetPrimaryKey info
  526.     //Since DBSCHEMA_INDEXES doesn't have to return PrimaryKey info correctly (NULL)
  527.     //we will call DBSCHEMA_PRIMARYKEYS before displaying IndexInfo to make sure
  528.     //which columns are really PrimaryKeys.
  529.     GetPrimaryKeys();
  530.  
  531.     //Now list all indexes to the Index ListView window
  532.     for(i=0; i<pCFromTable->m_cIndexes; i++)
  533.     {
  534.         INDEXINFO* pIndexInfo = &pCFromTable->m_rgIndexInfo[i];
  535.  
  536.         //INDEXNAME (item)
  537.         ConvertToMBCS(pIndexInfo->wszIndexName, szBuffer, MAX_NAME_LEN);
  538.         LV_InsertItem(hWnd, i, COL_INDEXNAME, szBuffer, 0, pIndexInfo->fIsPrimaryKey ? INDEXTYPE_PRIMARYKEY : INDEXTYPE_INDEX);
  539.  
  540.         //INDEXCOLNAME (subitem)
  541.         ConvertToMBCS(pIndexInfo->wszColName, szBuffer, MAX_NAME_LEN);
  542.         LV_InsertItem(hWnd, i, COL_INDEXCOLNAME, szBuffer);
  543.         
  544.         //FLAGS (subitem)
  545.         LV_InsertItem(hWnd, i, COL_UNIQUE, pIndexInfo->fUnique ? "TRUE" : "FALSE");
  546.         LV_InsertItem(hWnd, i, COL_PRIMARYKEY, pIndexInfo->fIsPrimaryKey ? "TRUE" : "FALSE");
  547.         LV_InsertItem(hWnd, i, COL_AUTOUPDATE, pIndexInfo->fAutoUpdate ? "TRUE" : "FALSE");
  548.         LV_InsertItem(hWnd, i, COL_COLLATION, (pIndexInfo->dwCollation == DB_COLLATION_ASC) ? "ASC" : (pIndexInfo->dwCollation == DB_COLLATION_DESC) ? "DESC" : "NULL");
  549.         LV_InsertItem(hWnd, i, COL_NULLS, (pIndexInfo->dwNulls == DBPROPVAL_IN_DISALLOWNULL) ? "DISALLOWNULL" : (pIndexInfo->dwNulls == DBPROPVAL_IN_IGNORENULL) ? "IGNORENULL" : "IGNOREANYNULL");
  550.     }
  551.  
  552.     
  553.     // If there was a previous selection, select it again on Back
  554.     if(rgSelIndexInfo)
  555.     {
  556.         LONG lFoundIndex = -1;
  557.         for(i=0; i<cSelIndexes; i++)
  558.         {
  559.             //Find the "index" of the existing index
  560.             ConvertToMBCS(rgSelIndexInfo[i].wszIndexName, szBuffer, MAX_NAME_LEN);
  561.             lFoundIndex = LV_FindItem(hWnd, szBuffer, lFoundIndex);
  562.  
  563.             //If there was a selection, select it now
  564.             if(lFoundIndex != LVM_ERR)
  565.             {
  566.                 LV_SetItemState(hWnd, lFoundIndex, COL_INDEXNAME, LVIS_SELECTED, LVIS_SELECTED);
  567.             
  568.                 //Ensure that the first item is visible
  569.                 if(i==0)
  570.                     SendMessage(hWnd, LVM_ENSUREVISIBLE, (WPARAM)lFoundIndex, (LPARAM)FALSE);
  571.             }
  572.         }
  573.  
  574.     }    
  575.     //Otherwise select all as default
  576.     else 
  577.     {
  578.         for(i=0; i<pCFromTable->m_cIndexes; i++)
  579.             LV_SetItemState(hWnd, i, COL_INDEXNAME, LVIS_SELECTED, LVIS_SELECTED);
  580.     }
  581.         
  582.     //Only enable the ListBox/Title if there are indexes
  583.     EnableWindow(GetDlgItem(m_hWnd, IDT_INDEXMSG),    pCFromTable->m_cIndexes);
  584.     EnableWindow(hWnd,    pCFromTable->m_cIndexes);
  585.         
  586.     //AutoSize Index/ColName
  587.     if(pCFromTable->m_cIndexes)
  588.     {
  589.         SendMessage(hWnd, LVM_SETCOLUMNWIDTH, (WPARAM)COL_INDEXNAME, (LPARAM)LVSCW_AUTOSIZE);
  590.         SendMessage(hWnd, LVM_SETCOLUMNWIDTH, (WPARAM)COL_INDEXCOLNAME, (LPARAM)LVSCW_AUTOSIZE);
  591.     }
  592.  
  593. CLEANUP:
  594.     //Free Resriticions
  595.     FreeVariants(cRestrictions, rgRestrictions);
  596.     
  597.     if(hAccessor && pIAccessor)
  598.         XTEST(pIAccessor->ReleaseAccessor(hAccessor,NULL));
  599.  
  600.     SAFE_RELEASE(pIRowset);
  601.     SAFE_RELEASE(pIAccessor);
  602.     SAFE_FREE(rghRows);
  603.     SAFE_FREE(rgSelIndexInfo);
  604.     return hr==S_OK;
  605. }
  606.  
  607.  
  608.  
  609.  
  610. /////////////////////////////////////////////////////////////////////////////
  611. // BOOL CS2Dialog::GetPrimaryKeys
  612. //
  613. /////////////////////////////////////////////////////////////////////////////
  614. BOOL CS2Dialog::GetPrimaryKeys()
  615. {
  616.     HRESULT hr;
  617.     
  618.     HROW* rghRows = NULL;
  619.     ULONG cRowsObtained = 0;
  620.     IRowset* pIRowset = NULL;
  621.  
  622.     IAccessor* pIAccessor = NULL;
  623.     HACCESSOR hAccessor = DB_NULL_HACCESSOR;
  624.     
  625.     PRIMARYKEY PrimaryKey;
  626.     
  627.     //Use the passed in Session interface
  628.     CTable* pCFromTable = m_pCTableCopy->m_pCFromTable;
  629.     IOpenRowset* pIOpenRowset = pCFromTable->m_pCDataSource->m_pIOpenRowset;
  630.     IDBSchemaRowset* pIDBSchemaRowset = pCFromTable->m_pCDataSource->m_pIDBSchemaRowset;
  631.  
  632.     //Provider doesn't have to support IDBSchemaRowset
  633.     if(pIDBSchemaRowset == NULL)
  634.         return TRUE;
  635.     
  636.     // Bind the user and table name for the list
  637.     const static ULONG cBindings = 1;
  638.     const static DBBINDING rgBindings[cBindings] = 
  639.         {
  640.             4,                 
  641.             offsetof(PRIMARYKEY, wszColName),
  642.             0,
  643.             0,    
  644.             NULL,            
  645.             NULL,         
  646.             NULL,        
  647.             DBPART_VALUE,
  648.             DBMEMOWNER_CLIENTOWNED,        
  649.             DBPARAMIO_NOTPARAM, 
  650.             MAX_NAME_LEN,         
  651.             0,                 
  652.             DBTYPE_WSTR,     
  653.             0,    
  654.             0,                 
  655.         };
  656.  
  657.     //set up the restrictions
  658.     const ULONG cRestrictions = 3;
  659.     VARIANT     rgRestrictions[cRestrictions];
  660.  
  661.     //set up the restrictions
  662.     InitVariants(cRestrictions, rgRestrictions);
  663.     SetRestriction(&rgRestrictions[0], pCFromTable->m_pCDataSource->m_pwszCatalog);
  664.     SetRestriction(&rgRestrictions[1], pCFromTable->m_TableInfo.wszSchemaName);
  665.     SetRestriction(&rgRestrictions[2], pCFromTable->m_TableInfo.wszTableName);
  666.     
  667.     //GetRowset
  668.     //DBSCHEMA_PRIMARY_KEYS may not be supported by the driver. 
  669.     //If an error occurs, just don't display PrimaryKey info
  670.     QTESTC(hr = pIDBSchemaRowset->GetRowset(NULL, DBSCHEMA_PRIMARY_KEYS, cRestrictions, rgRestrictions, 
  671.                                         IID_IRowset, 0, NULL, (IUnknown **)&pIRowset));
  672.  
  673.     XTESTC(hr = pIRowset->QueryInterface(IID_IAccessor, (void **)&pIAccessor));
  674.     
  675.     //Create Accessor for IndexInfo
  676.     XTESTC(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, rgBindings, 0, &hAccessor, NULL));
  677.  
  678.     while(TRUE)
  679.     {
  680.         XTESTC(hr = pIRowset->GetNextRows(NULL, 0, MAX_BLOCK_SIZE, &cRowsObtained, &rghRows));
  681.         
  682.         //ENDOFROWSET
  683.         if(cRowsObtained==0)
  684.             break;
  685.         
  686.         for(ULONG i=0; i<cRowsObtained; i++) 
  687.         {    
  688.             //Reset the PrimaryKey
  689.             memset(&PrimaryKey, 0, sizeof(PRIMARYKEY));
  690.                 
  691.             //Get the Data
  692.             XTESTC(hr = pIRowset->GetData(rghRows[i], hAccessor, (void*)&PrimaryKey));
  693.         
  694.             //Need to find the corresponding column in IndexInfo and 
  695.             //mark it as a primary key column
  696.             for(ULONG iIndex=0; iIndex<pCFromTable->m_cIndexes; iIndex++)
  697.                 if(wcscmp(PrimaryKey.wszColName, pCFromTable->m_rgIndexInfo[iIndex].wszColName)==0)
  698.                     pCFromTable->m_rgIndexInfo[iIndex].fIsPrimaryKey = TRUE;
  699.  
  700.             //Need to find the corresponding column in m_rgColDesc and mark it as a primary key column
  701.             for(i=0; i<pCFromTable->m_cColumns; i++)
  702.                 if(wcscmp(PrimaryKey.wszColName, pCFromTable->m_rgColDesc[i].wszColName)==0)
  703.                     pCFromTable->m_rgColDesc[i].fIsPrimaryKey = TRUE;
  704.         }
  705.             
  706.         //Release all the rows
  707.         XTESTC(hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL));
  708.         SAFE_FREE(rghRows);
  709.     }
  710.  
  711. CLEANUP:
  712.     //Free Resriticions
  713.     FreeVariants(cRestrictions, rgRestrictions);
  714.     
  715.     if(hAccessor && pIAccessor)
  716.         XTEST(pIAccessor->ReleaseAccessor(hAccessor,NULL));
  717.  
  718.     SAFE_RELEASE(pIRowset);
  719.     SAFE_RELEASE(pIAccessor);
  720.     SAFE_FREE(rghRows);
  721.     return hr==S_OK;
  722. }
  723.  
  724.  
  725.  
  726. /////////////////////////////////////////////////////////////////////////////
  727. // BOOL CS2Dialog::RecordSelectedIndexes
  728. //
  729. /////////////////////////////////////////////////////////////////////////////
  730. BOOL CS2Dialog::RecordSelectedIndexes(HWND hWnd)
  731. {
  732.     CTable* pCTable = m_pCTableCopy->m_pCFromTable;
  733.     LONG i;
  734.  
  735.     // Get the count of selected items
  736.     LONG cSelIndexes = SendMessage(hWnd, LVM_GETSELECTEDCOUNT, (WPARAM)0, (LPARAM)0);
  737.     LONG iIndex = -1;
  738.  
  739.     //Loop over all the indexes
  740.     pCTable->m_cIndexes = cSelIndexes;
  741.     for(i=0; i<cSelIndexes; i++) 
  742.     {
  743.         iIndex = SendMessage(hWnd, LVM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)LVNI_SELECTED);
  744.         
  745.         //"compact" the m_rgColDesc array to only the selected items
  746.         if(iIndex != LVM_ERR)
  747.             memmove(&pCTable->m_rgIndexInfo[i], &pCTable->m_rgIndexInfo[iIndex], sizeof(INDEXINFO));
  748.     }
  749.  
  750.     return TRUE;
  751. }
  752.