home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / vcoledb / consumer / dbviewer / dblistvw.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  26.5 KB  |  1,103 lines

  1. // DBListVw.cpp : implementation file
  2. //
  3. // This is a part of the Microsoft Foundation Classes and
  4. // Templates (MFC&T).
  5. // Copyright (C) 1998 Microsoft Corporation
  6. // All rights reserved.
  7. //
  8. // This source code is only intended as a supplement to the
  9. // MFC&T Reference and related electronic documentation provided
  10. // with the library.  See these sources for detailed information
  11. // regarding the MFC&T product.
  12. //
  13.  
  14. #include "stdafx.h"
  15. #include "DBViewer.h"
  16. #include "DBListVw.h"
  17. #include "editdlg.h"
  18. #include "errordlg.h"
  19. #include "dbexcept.h"
  20. #include <tchar.h>
  21.  
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CDBListView
  30.  
  31. IMPLEMENT_DYNCREATE(CDBListView, CListView)
  32.  
  33. CDBListView::CDBListView()
  34. {
  35.     m_pSession = NULL;
  36.     m_bEditable = FALSE;
  37.     m_pMultipleCommand = NULL;
  38. }
  39.  
  40. CDBListView::~CDBListView()
  41. {
  42.     m_pSession = NULL;
  43.     if (m_pMultipleCommand != NULL)
  44.         delete m_pMultipleCommand;
  45. }
  46.  
  47.  
  48. BEGIN_MESSAGE_MAP(CDBListView, CListView)
  49.     //{{AFX_MSG_MAP(CDBListView)
  50.     ON_WM_CREATE()
  51.     ON_WM_LBUTTONDBLCLK()
  52.     ON_UPDATE_COMMAND_UI(ID_NEXT_RESULT, OnUpdateNextResult)
  53.     ON_COMMAND(ID_NEXT_RESULT, OnNextResult)
  54.     //}}AFX_MSG_MAP
  55.     ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeyDown)
  56. END_MESSAGE_MAP()
  57.  
  58. /////////////////////////////////////////////////////////////////////////////
  59. // CDBListView drawing
  60.  
  61. void CDBListView::OnDraw(CDC* pDC)
  62. {
  63.     CDocument* pDoc = GetDocument();
  64.     // TODO: add draw code here
  65. }
  66.  
  67. /////////////////////////////////////////////////////////////////////////////
  68. // CDBListView diagnostics
  69.  
  70. #ifdef _DEBUG
  71. void CDBListView::AssertValid() const
  72. {
  73.     CListView::AssertValid();
  74. }
  75.  
  76. void CDBListView::Dump(CDumpContext& dc) const
  77. {
  78.     CListView::Dump(dc);
  79. }
  80.  
  81. CDBViewDoc* CDBListView::GetDocument() // non-debug version is inline
  82. {
  83.     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDBViewDoc)));
  84.     return (CDBViewDoc*)m_pDocument;
  85. }
  86. #endif //_DEBUG
  87.  
  88. /////////////////////////////////////////////////////////////////////////////
  89. // CDBListView message handlers
  90.  
  91. int CDBListView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  92. {
  93.     lpCreateStruct->style |= LVS_REPORT | LVS_NOSORTHEADER | LVS_SINGLESEL;
  94.     if (CListView::OnCreate(lpCreateStruct) == -1)
  95.         return -1;
  96.  
  97.     // Give the document a pointer to this view
  98.     GetDocument()->m_pListView = this;
  99.  
  100.     return 0;
  101. }
  102.  
  103. void CDBListView::EraseList()
  104. {
  105.     CListCtrlEx& ctlList = (CListCtrlEx&) GetListCtrl();
  106.     ctlList.DeleteAllItems();
  107.     while(ctlList.DeleteColumn(0));
  108.     UpdateWindow();
  109. }
  110.  
  111.  
  112. void CDBListView::ShowDatabase()
  113. {
  114.     ASSERT(m_pSession);
  115.  
  116.     // Here, show database information (probably similar to Catalog3)
  117.  
  118. }
  119.  
  120. void CDBListView::ShowTableData(LPCTSTR lpszTableName)
  121. {
  122.     USES_CONVERSION;
  123.  
  124.     CCommand<CManualAccessor> rs;
  125.     CColumns* pColumns      = NULL;
  126.     CPrimaryKeys* pKeys     = NULL;
  127.     int nItem               = 0;
  128.     CListCtrlEx& ctlList    = (CListCtrlEx&) GetListCtrl();
  129.     struct MYBIND* pBind    = NULL;
  130.  
  131.     // If we were in a multiple result set situation, destroy the
  132.     // existing result set.
  133.     if (m_pMultipleCommand != NULL)
  134.     {
  135.         delete m_pMultipleCommand;
  136.         m_pMultipleCommand = NULL;
  137.     }
  138.  
  139.     ASSERT(m_pSession);
  140.     ASSERT(lpszTableName != NULL);
  141.  
  142.     TRY
  143.     {
  144.         // Get Column Information for the table we want
  145.         pColumns = new CColumns;
  146.         if (pColumns->Open(*m_pSession, NULL, NULL, lpszTableName) != S_OK)
  147.             AfxThrowOLEDBException(pColumns->m_spRowset, IID_IDBSchemaRowset);
  148.  
  149.         // Generate Column Headers
  150.         EraseList();
  151.         ULONG ulColumns = 0;
  152.         while (pColumns->MoveNext() == S_OK)
  153.         {
  154.             ulColumns++;
  155.             ctlList.AddColumn(pColumns->m_szColumnName, ulColumns);
  156.         }
  157.  
  158.         delete pColumns;
  159.         pColumns = NULL;
  160.         m_ulFields = ulColumns;
  161.         pBind = new MYBIND[m_ulFields];
  162.  
  163.         rs.CreateAccessor(m_ulFields, pBind, sizeof(MYBIND)*m_ulFields);
  164.         for (ULONG l=0; l<m_ulFields; l++)
  165.             rs.AddBindEntry(l+1, DBTYPE_STR, sizeof(TCHAR)*40, &pBind[l].szValue,
  166.                     NULL, &pBind[l].dwStatus);
  167.  
  168.         // Check for multi word table names
  169.         if (strchr(lpszTableName, ' '))
  170.             m_strTable.Format("'%s'", lpszTableName);
  171.         else
  172.             m_strTable = lpszTableName;
  173.  
  174.         // Create a rowset containing data.
  175.         m_strQuery.Format("select * from %s", m_strTable);
  176.  
  177.         // Determine if there are primary keys to order by
  178.         pKeys = new CPrimaryKeys;
  179.         bool bFirst = TRUE;
  180.         if (pKeys->Open(*m_pSession, NULL, NULL, lpszTableName) == S_OK)
  181.         {
  182.             while(pKeys->MoveNext() == S_OK)
  183.             {
  184.                 if (bFirst != FALSE)
  185.                 {
  186.                     m_strQuery += _T(" ORDER BY ");
  187.                     bFirst = FALSE;
  188.                 }
  189.                 else
  190.                     m_strQuery += _T(", ");
  191.  
  192.                 m_strQuery += pKeys->m_szColumnName;
  193.             }
  194.         }
  195.         delete pKeys;
  196.         pKeys = NULL;
  197.  
  198.         if (rs.Open(*m_pSession, m_strQuery) != S_OK)
  199.             AfxThrowOLEDBException(rs.m_spCommand, IID_ICommand);
  200.  
  201.         // Display the data (to the maximum # of records allowed)
  202.         int nLoaded = DisplayData((CRowset*)&rs, pBind);
  203.  
  204.         delete pBind;
  205.         pBind = NULL;
  206.         CString strRecCount;
  207.         strRecCount.Format(_T("Loaded %d of %d total records"), nLoaded, nItem);
  208.         UpdateWindow();
  209.         ((CFrameWnd *) AfxGetMainWnd())->SetMessageText(strRecCount);
  210.     }
  211.     CATCH(COLEDBException, e)
  212.     {
  213.         if (pColumns != NULL)
  214.             delete pColumns;
  215.  
  216.         if (pKeys != NULL)
  217.             delete pKeys;
  218.  
  219.         if (pBind != NULL)
  220.             delete pBind;
  221.  
  222.         CErrorsDialog dlg;
  223.         dlg.Init(e->m_lpUnk, e->m_iid);
  224.         dlg.DoModal();
  225.     }
  226.     END_CATCH
  227. }
  228.  
  229.  
  230. void CDBListView::ShowTableSchema(LPCTSTR lpszTableName)
  231. {
  232.     USES_CONVERSION;
  233.     CTables*    pTableSet = NULL;
  234.  
  235.     // If we were in a multiple result set situation, destroy the
  236.     // existing result set.
  237.     if (m_pMultipleCommand != NULL)
  238.     {
  239.         delete m_pMultipleCommand;
  240.         m_pMultipleCommand = NULL;
  241.     }
  242.  
  243.     ASSERT(m_pSession);
  244.  
  245.     m_bVertical = lpszTableName != NULL;
  246.     DisplayColumnHeadings(IDS_COL_TABLE);
  247.  
  248.     int nItem = 0;
  249.  
  250.     // Not editable
  251.     m_bEditable = FALSE;
  252.  
  253.     pTableSet = new CTables;
  254.     // (can simply hard code max size)
  255.     char lpszType[64];
  256.  
  257.     strcpy(lpszType, "TABLE");
  258.     if (((CDBViewApp *)AfxGetApp())->m_bShowSystemObjects)
  259.         strcat(lpszType, ", SYSTEM TABLE");
  260.  
  261.     if (pTableSet->Open(*m_pSession, NULL, NULL, lpszTableName, lpszType) != S_OK)
  262.         return;
  263.  
  264.     while(pTableSet->MoveNext() == S_OK)
  265.     {
  266.         // We do not handle multi-word tables or procedures.  Normally,
  267.         // only Access handles these.
  268.         if (_tcschr(pTableSet->m_szName, _T(' ')) != NULL)
  269.             continue;
  270.  
  271.         AddItem(nItem, 0, pTableSet->m_szName);
  272.         AddItem(nItem, 1, pTableSet->m_szType);
  273.         AddItem(nItem, 2, pTableSet->m_szSchema);
  274.         AddItem(nItem, 3, pTableSet->m_szCatalog);
  275.         AddItem(nItem, 4, pTableSet->m_szDescription);
  276.         nItem++;
  277.     }
  278.  
  279.     delete pTableSet;
  280.     pTableSet = NULL;
  281.     AdjustColumnWidths();
  282. }
  283.  
  284. void CDBListView::ShowProcedures(LPCTSTR lpszProcedureName)
  285. {
  286.     USES_CONVERSION;
  287.     CProcedures*    pProcedureSet = NULL;
  288.  
  289.     ASSERT(m_pSession);
  290.  
  291.     m_bEditable = FALSE;
  292.     m_bVertical = lpszProcedureName != NULL;
  293.     DisplayColumnHeadings(IDS_COL_PROC);
  294.  
  295.     int nItem = 0;
  296.  
  297.     pProcedureSet = new CProcedures;
  298.     if (pProcedureSet->Open(*m_pSession, NULL, NULL, lpszProcedureName) != S_OK)
  299.         return;
  300.  
  301.     while(pProcedureSet->MoveNext() == S_OK)
  302.     {
  303.         // We do not handle multi-word tables or procedures.  Normally,
  304.         // only Access handles these.
  305.         if (_tcschr(pProcedureSet->m_szName, _T(' ')) != NULL)
  306.             continue;
  307.  
  308.         AddItem(nItem, 0, pProcedureSet->m_szName);
  309.         AddItem(nItem, 1, pProcedureSet->m_szCatalog);
  310.         AddItem(nItem, 2, pProcedureSet->m_szSchema);
  311.         AddItem(nItem, 3, pProcedureSet->m_szDescription);
  312.  
  313.         CString strType;
  314.         strType.Format("%d", pProcedureSet->m_nType);
  315.         AddItem(nItem, 4, strType);
  316.         nItem++;
  317.     }
  318.  
  319.     delete pProcedureSet;
  320.     pProcedureSet = NULL;
  321.     AdjustColumnWidths();
  322. }
  323.  
  324. void CDBListView::AdjustColumnWidths()
  325. {
  326.     CListCtrlEx& ctlList = (CListCtrlEx&) GetListCtrl();
  327.     ctlList.SetColumnWidth(-1,-3);
  328. }
  329.  
  330. void CDBListView::AddItem(int nItem, int nSubItem, LPCTSTR lpszItem)
  331. {
  332.     CListCtrlEx& ctlList = (CListCtrlEx&) GetListCtrl();
  333.  
  334.     if (m_bVertical)
  335.         ctlList.AddItem(nSubItem, 1, lpszItem);
  336.     else
  337.         ctlList.AddItem(nItem, nSubItem, lpszItem);
  338. }
  339.  
  340. void CDBListView::DisplayColumnHeadings(UINT nStringID)
  341. {
  342.     CString strHeadings;
  343.     strHeadings.LoadString(nStringID);
  344.  
  345.     CListCtrlEx& ctlList = (CListCtrlEx&) GetListCtrl();
  346.  
  347.     int nPos;
  348.     int nCount = 0;
  349.  
  350.     EraseList();
  351.  
  352.     if (m_bVertical)
  353.     {
  354.         ctlList.AddColumn(_T("Property     "),0);
  355.         ctlList.AddColumn(_T("Value     "),1);
  356.         m_nColumns = 2;
  357.     }
  358.     while ((nPos = strHeadings.Find(_T(","))) != -1){
  359.         CString strItem;
  360.         strItem = strHeadings.Left(nPos);
  361.         if (m_bVertical)
  362.             ctlList.AddItem(nCount++,0,strItem);
  363.         else
  364.             ctlList.AddColumn(strItem,nCount++);
  365.         strItem = strHeadings.Mid(nPos + 1);
  366.         strHeadings = strItem;
  367.     }
  368.     if (m_bVertical)
  369.         ctlList.AddItem(nCount,0,strHeadings);
  370.     else
  371.         ctlList.AddColumn(strHeadings,nCount);
  372.     m_nColumns = nCount;
  373. }
  374.  
  375. void CDBListView::OnLButtonDblClk(UINT nFlags, CPoint point)
  376. {
  377.     CListCtrlEx& ctlList = (CListCtrlEx&) GetListCtrl();
  378.     LV_HITTESTINFO lvInfo;
  379.     lvInfo.pt = point;
  380.  
  381.     if (ctlList.HitTest(&lvInfo) != -1)
  382.     {
  383.         // Invoke Edit Database Dialog
  384.         CEditDlg editDlg(&ctlList, lvInfo.iItem, m_ulFields);
  385.  
  386.         if (editDlg.DoModal() == IDOK)
  387.         {
  388.             // Update Database
  389.             if (UpdateDatabase(lvInfo.iItem, &editDlg))
  390.             {
  391.                 // Requery Database
  392.                 ShowTableData(m_strTable);
  393.             }
  394.         }
  395.     }
  396.  
  397.     CListView::OnLButtonDblClk(nFlags, point);
  398. }
  399.  
  400. BOOL CDBListView::UpdateDatabase(int nRow, CEditDlg* pEditDlg)
  401. {
  402.     USES_CONVERSION;
  403.     CCommand<CManualAccessor> rs;
  404.     struct MYBIND*  pBind               = NULL;
  405.     struct MYBIND*  pCol                = NULL;
  406.     TCHAR           (*lpszParams)[40]   = NULL;
  407.     CPrimaryKeys*   pKeys       = NULL;
  408.     CPtrArray       strColumnArray;
  409.     CListCtrlEx&    ctlList             = (CListCtrlEx&) GetListCtrl();
  410.     ULONG           ulParams            = 0;
  411.     bool            bConstraintColumns  = false;
  412.  
  413.     // If we were in a multiple result set situation, just ignore
  414.     // this command.
  415.     if (m_pMultipleCommand != NULL)
  416.         return FALSE;
  417.  
  418.     ASSERT(m_pSession);
  419.  
  420.     TRY
  421.     {
  422.         // Get the select string to select the unique record we wish to update
  423.         // Open the Table and load it into
  424.  
  425.         CDBPropSet propset(DBPROPSET_ROWSET);
  426.         propset.AddProperty(DBPROP_IRowsetChange, true);
  427.         propset.AddProperty(DBPROP_UPDATABILITY,
  428.                     DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE);
  429.  
  430.         // Get column name from list control
  431.         pKeys = new CPrimaryKeys;
  432.         ASSERT(pKeys != NULL);
  433.  
  434.         if (pKeys->Open(*m_pSession, NULL, NULL, m_strTable) == S_OK)
  435.         {
  436.             if (pKeys->MoveNext() == S_OK)
  437.                 bConstraintColumns = true;
  438.         }
  439.  
  440.         for (ULONG i=0; i<m_ulFields; i++)
  441.         {
  442.             LV_COLUMN lvColumn;
  443.             TCHAR szColumnName[40];
  444.  
  445.             lvColumn.mask = LVCF_TEXT;
  446.             lvColumn.pszText = &szColumnName[0];
  447.             lvColumn.cchTextMax = 40;
  448.             lvColumn.iSubItem = i;
  449.  
  450.             ctlList.GetColumn(i, &lvColumn);
  451.  
  452.  
  453.             if (bConstraintColumns != false)
  454.             {
  455.                 // Note, we depend upon the sort order of the provider
  456.                 // being catalog, schema, table name, column name as
  457.                 // provided in the spec.
  458.                 if (_tcscmp(szColumnName, pKeys->m_szColumnName) == 0)
  459.                 {
  460.                     // column is a constraint column
  461.                     if (pKeys->MoveNext() != S_OK)
  462.                         bConstraintColumns = false;
  463.  
  464.                     // Don't add the column to our list of bindings
  465.                     continue;
  466.                 }
  467.             }
  468.             pCol = new MYBIND;
  469.             _tcscpy(pCol->szValue, szColumnName);
  470.             pCol->dwStatus = i+1;   // Ordinal of the column
  471.             strColumnArray.Add(pCol);
  472.         }
  473.  
  474.         delete pKeys;
  475.         pKeys = NULL;
  476.  
  477.         SelectRecord(nRow, &rs, &lpszParams, &ulParams);
  478.  
  479.         // Create a temporary buffer and bind it the columns
  480.         ULONG ulFields = strColumnArray.GetUpperBound() + 1;
  481.         pBind = new MYBIND[ulFields];
  482.         rs.CreateAccessor(ulFields, pBind, sizeof(MYBIND)*ulFields);
  483.         for (ULONG l=0; l<ulFields; l++)
  484.         {
  485.             pCol = (MYBIND*)strColumnArray[l];
  486.             pBind[l].dwStatus = DBSTATUS_S_OK;
  487.             rs.AddBindEntry(pCol->dwStatus, DBTYPE_STR, sizeof(TCHAR)*40,
  488.                 &pBind[l].szValue, NULL, &pBind[l].dwStatus);
  489.  
  490.         }
  491.  
  492.         if (rs.Open(&propset) != S_OK)
  493.             AfxThrowOLEDBException(rs.m_spRowset, IID_IRowset);
  494.  
  495.         rs.MoveNext();
  496.  
  497.         for (i = 0; i<ulFields; i++)
  498.         {
  499.             pCol = (MYBIND*)strColumnArray[i];
  500.             CString strKey = pCol->szValue;
  501.  
  502.             // Get item from list view
  503.             CString strValue = pEditDlg->GetValue(strKey);
  504.  
  505.             if (strValue != pBind[i].szValue)
  506.                 _tcsncpy(pBind[i].szValue, strValue, 40);
  507.  
  508.             delete pCol;    // We no longer require the column information
  509.             pCol = NULL;
  510.         }
  511.  
  512.         strColumnArray.RemoveAll();
  513.         rs.SetData();
  514.  
  515.         // Cleanup
  516.         if (pBind != NULL)
  517.             delete pBind;
  518.  
  519.         if (lpszParams != NULL)
  520.             delete [ulParams]lpszParams;
  521.     }
  522.     CATCH(COLEDBException, e)
  523.     {
  524.         if (pBind != NULL)
  525.             delete pBind;
  526.  
  527.         if (lpszParams != NULL)
  528.             delete [ulParams]lpszParams;
  529.         CErrorsDialog dlg;
  530.         dlg.Init(e->m_lpUnk, e->m_iid);
  531.         dlg.DoModal();
  532.  
  533.         return FALSE;
  534.     }
  535.     END_CATCH
  536.  
  537.     return TRUE;
  538. }
  539.  
  540. void CDBListView::CallProcedure(LPCTSTR lpszProcName)
  541. {
  542.     USES_CONVERSION;
  543.     CProcedureParameters*       pProcParam  = NULL;
  544.     CCommand<CManualAccessor, CRowset, CMultipleResults>*   prs;
  545.     CListCtrlEx&                ctlList     = (CListCtrlEx&) GetListCtrl();
  546.     CMapStringToString          mapInput;
  547.     struct MYBIND*              pParams     = NULL;
  548.     ULONG                       ulParams    = 0;
  549.     CPtrArray                   arrColInfo;
  550.     CWordArray                  arrType;
  551.     struct MYBIND*              pParamInfo = NULL;
  552.  
  553.     // If we were in a multiple result set situation, destroy the
  554.     // existing result set.
  555.     if (m_pMultipleCommand != NULL)
  556.     {
  557.         delete m_pMultipleCommand;
  558.         m_pMultipleCommand = NULL;
  559.     }
  560.  
  561.     ASSERT(m_pSession);
  562.     ASSERT(lpszProcName != NULL);
  563.  
  564.     // Create the stored procedure string
  565.     CString strProc, strCall, strTemp("? = ");
  566.     strProc.Format("Call %s ", lpszProcName);
  567.     int nFirst = 0;
  568.     int i=0;
  569.     int nReturnValue = 0;
  570.  
  571.     pProcParam = new CProcedureParameters;
  572.  
  573.     if (pProcParam->Open(*m_pSession, NULL, NULL, lpszProcName) == S_OK)
  574.     {
  575.         while (pProcParam->MoveNext() == S_OK)
  576.         {
  577.             if (pProcParam->m_nDataType != NULL)
  578.             {
  579.                 ulParams++;
  580.                 pParamInfo = new MYBIND;
  581.                 pParamInfo->dwStatus = ulParams;;
  582.                 _tcsncpy(pParamInfo->szValue, pProcParam->m_szName, 40);
  583.                 arrColInfo.Add(pParamInfo);
  584.                 arrType.Add((WORD)pProcParam->m_nDataType);
  585.             }
  586.  
  587.             // Handle return type
  588.             switch (pProcParam->m_nDataType)
  589.             {
  590.                 case DBPARAMTYPE_RETURNVALUE:
  591.                     strTemp += strProc;
  592.                     strProc = strTemp;
  593.                     nReturnValue = 1;
  594.                     break;
  595.  
  596.                 case DBPARAMTYPE_INPUT:
  597.                 case DBPARAMTYPE_INPUTOUTPUT:
  598.                     mapInput.SetAt(pProcParam->m_szName, "");
  599.  
  600.                 case DBPARAMTYPE_OUTPUT:
  601.                     if (nFirst == 0)
  602.                     {
  603.                         strProc += "(?";
  604.                         nFirst++;
  605.                     }
  606.                     else
  607.                         strProc += ", ?";
  608.                     break;
  609.  
  610.                 default:
  611.                     break;
  612.             }
  613.         }
  614.     }
  615.  
  616.     delete pProcParam;
  617.     pProcParam = NULL;
  618.  
  619.     if (nFirst > 0)
  620.         strProc += ")";
  621.  
  622.     strCall.Format("{ %s }", strProc);
  623.     prs = new CCommand<CManualAccessor, CRowset, CMultipleResults>;
  624.     prs->Create(*m_pSession, strCall);
  625.     prs->Prepare(1);
  626.  
  627.     if (ulParams > 0)
  628.     {
  629.         DBPARAMBINDINFO* pBindInfo = new DBPARAMBINDINFO[ulParams];
  630.         ULONG* pOrdinals = new ULONG[ulParams];
  631.         pParams = new MYBIND[ulParams];
  632.  
  633.         // Make the bindings for the accessor based on the DBTYPE_STR
  634.         // data type
  635.         prs->CreateParameterAccessor(ulParams, &pParams[0], sizeof(MYBIND)*ulParams);
  636.         for (ULONG l=0; l<ulParams; l++)
  637.         {
  638.             // Set up information for the SetParameterInfo call
  639.             pOrdinals[l] = l+1;
  640.             pBindInfo[l].pwszDataSourceType = T2OLE(_T("DBTYPE_CHAR"));
  641.             pBindInfo[l].pwszName = NULL;
  642.             pBindInfo[l].ulParamSize = 40;
  643.             pBindInfo[l].bPrecision = 0;
  644.             pBindInfo[l].bScale = 0;
  645.  
  646.             DWORD dwFlags = 0;
  647.             if (arrType[l] == DBPARAMTYPE_INPUT ||
  648.                 arrType[l] == DBPARAMTYPE_INPUTOUTPUT)
  649.                 dwFlags |= DBPARAMFLAGS_ISINPUT;
  650.  
  651.             if (arrType[l] == DBPARAMTYPE_OUTPUT ||
  652.                 arrType[l] == DBPARAMTYPE_INPUTOUTPUT ||
  653.                 arrType[l] == DBPARAMTYPE_RETURNVALUE)
  654.                 dwFlags |= DBPARAMFLAGS_ISOUTPUT;
  655.             pBindInfo[l].dwFlags = dwFlags;
  656.  
  657.  
  658.             // Set up information for bindings
  659.             pParamInfo = (MYBIND*)arrColInfo[l];
  660.  
  661.             if (arrType[l] == DBPARAMTYPE_RETURNVALUE)
  662.             {
  663.                 prs->AddParameterEntry(1, DBTYPE_STR, sizeof(TCHAR)*40,
  664.                     &pParams[l].szValue, NULL, &pParams[l].dwStatus, DBPARAMIO_OUTPUT);
  665.             }
  666.             else
  667.             {
  668.                 prs->AddParameterEntry(l+1, DBTYPE_STR, sizeof(TCHAR)*40,
  669.                     &pParams[l].szValue, NULL, &pParams[l].dwStatus, arrType[l]);
  670.             }
  671.  
  672.             delete pParamInfo;
  673.             pParamInfo = NULL;
  674.         }
  675.  
  676.         // Call ICommandWithParameters::SetParameterInfo so that we can
  677.         // tell the provider to convert the parameter types to DBTYPE_STR
  678.         prs->SetParameterInfo(ulParams, pOrdinals, pBindInfo);
  679.         delete pOrdinals;
  680.         delete pBindInfo;
  681.     }
  682.     arrColInfo.RemoveAll();
  683.  
  684.     // Place values in the parameter buffers
  685.     if (!mapInput.IsEmpty())
  686.     {
  687.         CEditDlg dlg(mapInput);
  688.  
  689.         if (dlg.DoModal() != IDOK)
  690.         {
  691.             if (pParams != NULL)
  692.                 delete pParams;
  693.             return;
  694.         }
  695.  
  696.         POSITION pos = mapInput.GetStartPosition();
  697.  
  698.         ULONG   l=0;
  699.         ULONG   ulCount=0;
  700.         while (pos != NULL)
  701.         {
  702.             for(l=ulCount; l<ulParams; l++)
  703.             {
  704.                 if (arrType[l] == DBPARAMTYPE_INPUT ||
  705.                     arrType[l] == DBPARAMTYPE_INPUTOUTPUT)
  706.                 {
  707.                     CString strKey, strValue;
  708.                     mapInput.GetNextAssoc(pos, strKey, strValue);
  709.                     strValue = dlg.GetValue(strKey);
  710.                     _tcsncpy(pParams[l].szValue, strValue, 40);
  711.                     ulCount = l+1;
  712.                 }
  713.             }
  714.         }
  715.     }
  716.  
  717.     // Open the rowset to get the information so we can then bind the columns
  718.     if (prs->Open(NULL, NULL, false) != S_OK)
  719.     {
  720.         CErrorsDialog dlg;
  721.         dlg.Init(prs->m_spCommand, IID_ICommandPrepare);
  722.         dlg.DoModal();
  723.         delete prs;
  724.         prs = NULL;
  725.         delete pParams;
  726.         return;
  727.     }
  728.  
  729.     if (pParams != NULL)
  730.         delete pParams;
  731.  
  732.     m_pMultipleCommand = prs;
  733.     OnNextResult();
  734. }
  735.  
  736. int CDBListView::DisplayData(CRowset* pRS, struct MYBIND* pBind)
  737. {
  738.     CListCtrlEx&        ctlList = (CListCtrlEx&) GetListCtrl();
  739.  
  740.     // Display the data (to the maximum # of records allowed)
  741.     int nLoaded = 0;
  742.     int nMaxRecords = ((CDBViewApp*)AfxGetApp())->m_nMaxRecords;
  743.  
  744.     int nItem=0;
  745.     while (pRS->MoveNext() == S_OK)
  746.     {
  747.         if (nItem < nMaxRecords)
  748.         {
  749.             nLoaded++;
  750.             for (ULONG j=1; j<=m_ulFields; j++)
  751.             {
  752.                 if (pBind[j-1].dwStatus == DBSTATUS_S_ISNULL)
  753.                     _tcscpy(pBind[j-1].szValue, _T(""));
  754.                 ctlList.AddItem(nItem, j-1, pBind[j-1].szValue);
  755.             }
  756.             nItem++;
  757.         }
  758.     }
  759.  
  760.     return nLoaded;
  761. }
  762.  
  763. void CDBListView::InsertRecord(LPCTSTR lpszTableName)
  764. {
  765.     USES_CONVERSION;
  766.     CCommand<CManualAccessor> rs;
  767.     CColumns* pColumns          = NULL;
  768.     TCHAR (*lpszColumns)[40]    = NULL;
  769.     int nItem                   = 0;
  770.     CListCtrlEx& ctlList        = (CListCtrlEx&) GetListCtrl();
  771.     CStringList strList;
  772.  
  773.     // If we were in a multiple result set situation, just
  774.     // ignore this command
  775.     if (m_pMultipleCommand != NULL)
  776.         return;
  777.  
  778.     ASSERT(m_pSession);
  779.     ASSERT(lpszTableName != NULL);
  780.  
  781.     TRY
  782.     {
  783.         // Set the editable information
  784.         pColumns = new CColumns;
  785.         if (pColumns->Open(*m_pSession, NULL, NULL, lpszTableName) != S_OK)
  786.             AfxThrowOLEDBException(pColumns->m_spRowset, IID_IDBSchemaRowset);
  787.  
  788.         // Generate Column Headers
  789.         EraseList();
  790.         ULONG ulColumns = 0;
  791.         while (pColumns->MoveNext() == S_OK)
  792.         {
  793.             ulColumns++;
  794.             strList.AddTail(pColumns->m_szColumnName);
  795.             ctlList.AddColumn(pColumns->m_szColumnName, ulColumns);
  796.         }
  797.         m_ulFields = ulColumns;
  798.  
  799.         delete pColumns;
  800.         pColumns = NULL;
  801.         lpszColumns = new TCHAR[m_ulFields][40];
  802.  
  803.         // Create Bindings for the insertion
  804.         rs.CreateAccessor(m_ulFields, &lpszColumns[0], sizeof(TCHAR)*40*m_ulFields);
  805.         for (ULONG l=0; l<m_ulFields; l++)
  806.             rs.AddBindEntry(l+1, DBTYPE_STR, 40, &lpszColumns[l]);
  807.  
  808.         // Create a rowset containing data.
  809.         // Set up some properties for the rowset
  810.         CDBPropSet propset(DBPROPSET_ROWSET);
  811.         propset.AddProperty(DBPROP_IRowsetChange, true);
  812.         propset.AddProperty(DBPROP_UPDATABILITY,
  813.                     DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE);
  814.  
  815.         rs.Create(*m_pSession, m_strQuery);
  816.         rs.Prepare();
  817.         if (rs.Open(&propset) != S_OK)
  818.             AfxThrowOLEDBException(rs.m_spRowset, IID_IRowset);
  819.  
  820.         CEditDlg editDlg(&ctlList, 0, m_ulFields);
  821.  
  822.         if (editDlg.DoModal() != IDOK)
  823.         {
  824.             delete [m_ulFields]lpszColumns;
  825.             return;
  826.         }
  827.  
  828.         POSITION pos = strList.GetHeadPosition();
  829.         for (ULONG i=0; i<m_ulFields; i++)
  830.         {
  831.             CString strKey, strValue;
  832.  
  833.             // Insert new data
  834.             strKey = strList.GetNext(pos);
  835.             strValue = editDlg.GetValue(strKey);
  836.             _tcsncpy(lpszColumns[i], strValue, 40);
  837.         }
  838.  
  839.         // Update the database
  840.         if (rs.Insert(0) != S_OK)
  841.             AfxThrowOLEDBException(rs.m_spRowset, IID_IRowsetChange);
  842.         ShowTableData(lpszTableName);
  843.  
  844.         // Cleanup
  845.         if (lpszColumns != NULL)
  846.         {
  847.             delete [m_ulFields]lpszColumns;
  848.             lpszColumns = NULL;
  849.         }
  850.     }
  851.     CATCH(COLEDBException, e)
  852.     {
  853.         if (pColumns != NULL)
  854.             delete pColumns;
  855.  
  856.         if (lpszColumns != NULL)
  857.             delete [m_ulFields]lpszColumns;
  858.  
  859.         CErrorsDialog dlg;
  860.         dlg.Init(e->m_lpUnk, e->m_iid);
  861.         dlg.DoModal();
  862.     }
  863.     END_CATCH
  864. }
  865.  
  866. void CDBListView::OnKeyDown(NMHDR *pNotifyStruct,LRESULT *result)
  867. {
  868.     LV_KEYDOWN* pKeyDown = (LV_KEYDOWN *) pNotifyStruct;
  869.  
  870.     if (pKeyDown->wVKey == VK_DELETE)
  871.     {
  872.         BOOL bShowWarnings = ((CDBViewApp *)AfxGetApp())->m_bShowWarnings;
  873.         int retCode = IDYES;
  874.         if (bShowWarnings)
  875.         {
  876.             retCode = MessageBox(
  877.                 _T("Are you sure you want to delete this item ?"),
  878.                 _T("DBViewer - Warning"),MB_YESNO);
  879.  
  880.             if (retCode == IDYES)
  881.                 DeleteRecord();
  882.         }
  883.         else
  884.             DeleteRecord();
  885.     }
  886.  
  887.     *result = 0;
  888. }
  889.  
  890. void CDBListView::DeleteRecord()
  891. {
  892.     CCommand<CManualAccessor> rs;
  893.     TCHAR   (*lpszParams)[40] = NULL;
  894.     ULONG   ulParams = 0;
  895.     CListCtrlEx&    ctlList = (CListCtrlEx&) GetListCtrl();
  896.  
  897.     // If we were in a multiple result set situation, just
  898.     // ignore the command
  899.     if (m_pMultipleCommand != NULL)
  900.         return;
  901.  
  902.     // Check to see if we are editable or not
  903.     // Get the first selected item.
  904.     int nRow = ctlList.GetNextItem(-1, LVNI_SELECTED);
  905.     if (nRow == -1)
  906.         return;
  907.  
  908.     CDBPropSet propset(DBPROPSET_ROWSET);
  909.     propset.AddProperty(DBPROP_IRowsetChange, true);
  910.     propset.AddProperty(DBPROP_UPDATABILITY,
  911.                 DBPROPVAL_UP_INSERT | DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE);
  912.  
  913.     SelectRecord(nRow, &rs, &lpszParams, &ulParams);
  914.  
  915.     // Execute the Query
  916.     HRESULT hr = rs.Open(&propset);
  917.     if (hr == S_OK)
  918.     {
  919.         if (rs.MoveNext() == S_OK)
  920.             rs.Delete();
  921.     }
  922.     if (lpszParams != NULL)
  923.         delete [ulParams]lpszParams;
  924.  
  925.     ctlList.DeleteItem(nRow);
  926. //  DisplayData(rs);
  927. }
  928.  
  929. HRESULT CDBListView::SelectRecord(int nRow, CCommand<CManualAccessor>* pRS,
  930.     TCHAR (**lpszColumns)[40], ULONG* pulColumns)
  931. {
  932.     USES_CONVERSION;
  933.     CStringList         strList;
  934.     CList<ULONG, ULONG> colList;
  935.     CPrimaryKeys*       pKeys = NULL;
  936.     CListCtrlEx&        ctlList = (CListCtrlEx&) GetListCtrl();
  937.     CString             strQuery;
  938.     ULONG               nParams = 0;
  939.     HRESULT             hr;
  940.  
  941.     ASSERT(nRow > -1);
  942.     ASSERT(pulColumns != NULL);
  943.     ASSERT(pRS != NULL);
  944.     ASSERT(lpszColumns != NULL);
  945.  
  946.     strQuery.Format("select * from %s where ", m_strTable);
  947.  
  948.     // Get primary keys for rowset
  949.     pKeys = new CPrimaryKeys;
  950.     hr = pKeys->Open(*m_pSession, NULL, NULL, m_strTable);
  951.  
  952.     if (FAILED(hr))
  953.     {
  954.         delete pKeys;
  955.         return hr;
  956.     }
  957.  
  958.     while (pKeys->MoveNext() == S_OK)
  959.     {
  960.         // Maintain a list of indexes
  961.         strList.AddTail(pKeys->m_szColumnName);
  962.         colList.AddTail(pKeys->m_nOrdinal);
  963.     }
  964.  
  965.     delete pKeys;
  966.     pKeys = NULL;
  967.  
  968.     if (strList.IsEmpty())
  969.         return E_FAIL;
  970.  
  971.     POSITION pos = strList.GetHeadPosition();
  972.     nParams = strList.GetCount();
  973.     *pulColumns = nParams;
  974.     ASSERT(nParams > 0);
  975.     *lpszColumns = new TCHAR[nParams][40];
  976.  
  977.     // Set up the Query String
  978.     while (pos != NULL)
  979.     {
  980.         CString strIndex;
  981.         CString strKey = strList.GetNext(pos);
  982.  
  983.         strIndex.Format(" %s = ?", strKey);
  984.         strQuery += strIndex;
  985.  
  986.         if (pos != NULL)
  987.             strQuery += ",";
  988.     }
  989.  
  990.     POSITION posCol = colList.GetHeadPosition();
  991.     pRS->CreateParameterAccessor(nParams, *lpszColumns[0],
  992.         sizeof(TCHAR)*40*nParams);
  993.     ULONG ulNextParam = 0;
  994.     while (posCol != NULL)
  995.     {
  996.         pRS->AddParameterEntry(ulNextParam+1, DBTYPE_STR, sizeof(TCHAR)*40,
  997.             *lpszColumns[ulNextParam]);
  998.  
  999.         LV_ITEM lvIndexItem;
  1000.  
  1001.         ASSERT(ulNextParam < nParams);
  1002.  
  1003.         ULONG ulCol = colList.GetNext(posCol);
  1004.         lvIndexItem.mask = LVIF_TEXT;
  1005.         lvIndexItem.pszText = *lpszColumns[ulNextParam];
  1006.         lvIndexItem.cchTextMax = 40;
  1007.         lvIndexItem.iItem = nRow;
  1008.         lvIndexItem.iSubItem = ulCol-1;
  1009.         ctlList.GetItem(&lvIndexItem);
  1010.  
  1011.         ulNextParam++;
  1012.     }
  1013.  
  1014.     // Set the command text for execution
  1015.     pRS->Create(*m_pSession, strQuery);
  1016.     return S_OK;
  1017. }
  1018.  
  1019. void CDBListView::OnUpdateNextResult(CCmdUI* pCmdUI)
  1020. {
  1021.     if (m_pMultipleCommand != NULL)
  1022.         pCmdUI->Enable();
  1023.     else
  1024.         pCmdUI->Enable(false);
  1025. }
  1026.  
  1027. void CDBListView::OnNextResult()
  1028. {
  1029.     USES_CONVERSION;
  1030.  
  1031.     if (m_pMultipleCommand == NULL)
  1032.         return; // no opened command available.
  1033.  
  1034.     EraseList();
  1035.  
  1036.     if (m_pMultipleCommand->m_spRowset != NULL)
  1037.     {
  1038.         CListCtrlEx&                ctlList     = (CListCtrlEx&) GetListCtrl();
  1039.  
  1040.         // Get the column information and bind the output columns.
  1041.         ULONG           ulColumns = NULL;
  1042.         DBCOLUMNINFO*   pColumnInfo = NULL;
  1043.         OLECHAR*        pColumnNames = NULL;
  1044.         OLECHAR**       ppNames;
  1045.         struct MYBIND*  pColumns    = NULL;
  1046.  
  1047.         if (m_pMultipleCommand->GetColumnInfo(&ulColumns,
  1048.             &pColumnInfo, &pColumnNames) != S_OK)
  1049.         {
  1050.             delete m_pMultipleCommand;
  1051.             m_pMultipleCommand = NULL;
  1052.             return;
  1053.         }
  1054.  
  1055.         if (ulColumns > 0)
  1056.         {
  1057.             ppNames = new OLECHAR*[ulColumns];
  1058.             pColumns = new MYBIND[ulColumns];
  1059.             m_pMultipleCommand->CreateAccessor(ulColumns,
  1060.                 &pColumns[0], sizeof(MYBIND)*ulColumns);
  1061.  
  1062.             for (ULONG l=0; l<ulColumns; l++)
  1063.             {
  1064.                 ppNames[l] = pColumnNames;
  1065.                 if (*pColumnNames)
  1066.                 {
  1067.                     while(*pColumnNames++)
  1068.                         ;
  1069.                 }
  1070.                 ctlList.AddColumn(OLE2T(ppNames[l]), l+1);
  1071.                 m_pMultipleCommand->AddBindEntry(l+1, DBTYPE_STR,
  1072.                     sizeof(TCHAR)*40, &pColumns[l].szValue,
  1073.                     NULL, &pColumns[l].dwStatus);
  1074.             }
  1075.         }
  1076.         CoTaskMemFree(pColumnInfo);
  1077.         CoTaskMemFree(*ppNames);
  1078.         delete [] ppNames;
  1079.         m_ulFields = ulColumns;
  1080.         m_pMultipleCommand->Bind();
  1081.         DisplayData((CRowset*)m_pMultipleCommand, pColumns);
  1082.         delete pColumns;
  1083.         pColumns = NULL;
  1084.     }
  1085.     else
  1086.     {
  1087.         // Set the window text with the return value.
  1088.         CString strReturn;
  1089.         strReturn.Format("Stored procedure returned %ld\n", m_lRows);
  1090.         ((CFrameWnd *) AfxGetMainWnd())->SetMessageText(strReturn);
  1091.     }
  1092.  
  1093.     // Get the next result set
  1094.     HRESULT hr;
  1095.     hr = m_pMultipleCommand->GetNextResult(&m_lRows, false);
  1096.  
  1097.     if (FAILED(hr) || hr == DB_S_NORESULT)
  1098.     {
  1099.         delete m_pMultipleCommand;
  1100.         m_pMultipleCommand = NULL;
  1101.     }
  1102. }
  1103.