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 / qurydemo / query.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-12  |  88.7 KB  |  2,896 lines

  1. //-----------------------------------------------------------------------------
  2. // Microsoft OLE DB QURYDEMO Sample
  3. // Copyright (C) 1995-1998 Microsoft Corporation
  4. //
  5. // @doc
  6. //
  7. // @module QUERY.CPP
  8. //
  9. //-----------------------------------------------------------------------------------
  10. /*
  11.     PROGRAM: QURYDEMO
  12.     ========
  13.  
  14.     PURPOSE:
  15.     ========    
  16.     demonstrates a simple MDI (Multiple Document Interface)application
  17.     that allows a user to simultaneously connect to multiple
  18.     hetrogeneous databases and perform SQL queries to get results.
  19.  
  20.     FUNCTIONS:
  21.     ==========
  22.     InitEnvironment() - Initialize OLE
  23.     DisplayProviders() - Display available Providers
  24.     ConnectDatabase() - Connect to a specific data source
  25.     DisplayConnections() - Display List of made connections
  26.     DisplayICommands() - Display list of ICommands
  27.     NewICommandWindow() - Open a new ICommand and update displays
  28.     ChangeCurrentCursor() - Change current cursor display
  29.     ChangeCurrentICommand() - Change current ICommand display
  30.     DisplayNewCrsrAndICommand() - update cusor & ICommand displays
  31.     FreeConnect() - free a IDBCreateCommand
  32.     FreeICommand() - free a ICommand
  33.     CloseICommandWindow() - close a ICommand window
  34.     ExecuteQuery() - execute a user specified query
  35.     CloseIDBCreateCommand() - check if all connections are closed
  36.     FreeEnvironment() - free OLE
  37.     ExecuteCommand() - Execute the ICommand and return an IRowset 
  38.     GetDataFromRowset() - Get the Data from the IRowset
  39.     SetupBindings() - Set the binding structure
  40.     CreateAccessor() - Create Accessor to store the Data
  41.     GetData() - Get the Data out of the rowset
  42.      
  43.  
  44.     COMMENTS:
  45.     =========
  46.     Created by Microsoft Corporation.
  47.     
  48.     The application uses MDI Child Window Titles to store values of
  49.     PROVIDER's and Command Objects. These values are also stored in the
  50.     comboboxes that are displayed on the toolbar.
  51.  
  52. */
  53. #define STRICT
  54. #define DBINITCONSTANTS
  55. #define INITGUID
  56.  
  57. #include <stdio.h>
  58. #include <string.h>
  59. #include <windows.h>
  60. #include <stddef.h>                // offsetof
  61. #include <assert.h>                // assert
  62.  
  63. #include "oledb.h"
  64. #include "oledberr.h"
  65. #include "msdaguid.h"
  66.  
  67. #include "qurydemo.h"  
  68.  
  69. // Globals
  70. extern HWND            hWndFrame;                 // Main Frame Window handle
  71. extern HWND            hWndCrsrList;            // hdbc(s) combobox on the tool bar
  72. extern HWND            hWndStmtList;            // hstmt(s) combobox on the tool bar
  73. extern HWND            hWndMDIClient;            // MDI Client window handle
  74. extern HWND            hWndActiveChild;        // Current active MDI Child window
  75. extern HINSTANCE    hAppInstance;            // Application instance
  76.  
  77. IMalloc*             g_pIMalloc = NULL;
  78.  
  79. int                    nChildCount;                    // Number of child windows currently open
  80. char                szDispBuffer[MAXDISPLAYSIZE+10];// Display Buffer
  81. unsigned char        rgbData[MAX_COL][MAXDATALEN];    // Results Data Array
  82. long                 dwDataLen[MAX_COL];                // Results Data Length Array
  83.  
  84. //char                szErrorDescription [MAXDISPLAYSIZE+1];
  85. //char                szErrorSource      [MAXDISPLAYSIZE+1];
  86.  
  87. //Variables and constants used for provider enumeration
  88. //#define   MAX_VALUE_NAME          300
  89. //#define   MAX_PROVIDER_NUM        10
  90. #define NUMELEM(p1) (sizeof(p1) / sizeof(p1[0]))
  91. #define COLUMN_ALIGNVAL 8
  92. #define ROUND_UP( Size, Amount ) (((DWORD)(Size) +  ((Amount) - 1)) & ~((Amount) - 1))
  93.  
  94. const ULONG    DEF_SOURCES_CBMAXLEN    = 64;
  95. const ULONG MAX_NUM_PROVIDERS        = 16;
  96.  
  97. IParseDisplayName*    g_pIParse = NULL;
  98. ULONG    g_cProvNames;
  99. CHAR    g_rgszProvName[MAX_NUM_PROVIDERS][DEF_SOURCES_CBMAXLEN];
  100. WCHAR    g_rgwszParseName[MAX_NUM_PROVIDERS][DEF_SOURCES_CBMAXLEN];
  101.  
  102. /*
  103.     FUNCTION: InitEnvironment()
  104.     COMMENTS: Allocate an environment handle for OLE function calls.
  105. */
  106. FAR PASCAL InitEnvironment()
  107. {
  108.     HRESULT        hr;
  109.  
  110.     // Initialize OLE
  111.     hr = CoInitialize( NULL );
  112.  
  113.     if (FAILED(hr))
  114.     {
  115.         DumpErrorHResult( hr, (LPSTR)"CoInitialize FAILED!!" );
  116.         return FALSE;
  117.     }
  118.  
  119.     // Retrieve the task memory allocator
  120.     hr = CoGetMalloc( MEMCTX_TASK, &g_pIMalloc );
  121.  
  122.     if (FAILED(hr))
  123.     {
  124.         DumpErrorHResult( hr, (LPSTR)"CoGetMalloc FAILED!!" );
  125.         return FALSE;
  126.     }
  127.  
  128.     // reset child window count
  129.     nChildCount = 0;
  130.     
  131.     // Return TRUE
  132.     return TRUE;
  133. }
  134.  
  135. /*
  136.     FUNCTION: DisplayProviders(HWND hWnd)
  137.     COMMENTS: Display a list of available Providers.
  138. */
  139. void FAR PASCAL DisplayProviders(HWND hWnd)
  140. {
  141.     ULONG        iProv;
  142.     HRESULT        hr;
  143.  
  144.     // Initialize count of provider names
  145.     g_cProvNames = 0;
  146.  
  147.     //Go to registry and get me the provider names
  148.     hr = EnumerateProviders();  
  149.     if (FAILED (hr))
  150.     {
  151.       MessageBox(hWndFrame, 
  152.                  "There was an error retrieve providers from the OLE DB Enumerator", 
  153.                  "Enumeration Error", 
  154.                  MB_OK | MB_ICONERROR);
  155.       return;
  156.     }
  157.  
  158.     //All returned Providerss in the provided combo box for display.
  159.     SendMessage(hWnd, CB_RESETCONTENT, 0, 0);
  160.     for (iProv=0; iProv<g_cProvNames; iProv++)
  161.        SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)(LPSTR)g_rgszProvName[iProv]);
  162.  
  163.     SendMessage(hWnd, CB_SETCURSEL, 0, 0);
  164. }
  165.  
  166. /*
  167.     FUNCTION: EnumerateProviders
  168.     COMMENTS: Display a list of available providers
  169. */
  170. HRESULT EnumerateProviders
  171.     (
  172.     )
  173. {
  174.     HRESULT                hr;
  175.     ULONG                ul, cRows = 0;
  176.     ISourcesRowset*        pISrcRowset = NULL;
  177.     IRowset*            pIRowset = NULL;
  178.     IAccessor*            pIAccessor = NULL;
  179.     BYTE*                pData = NULL;
  180.     DWORD                dwOffset;
  181.     HACCESSOR            hAccessor = NULL;
  182.     DBBINDING            rgBind[3];
  183.     HROW                rghRows[MAX_NUM_PROVIDERS];
  184.     HROW*                pRows = &rghRows[0];
  185.  
  186.     enum enumSOURCES_COLUMNS {
  187.         eid_SOURCES_NAME = 1,
  188.         eid_SOURCES_PARSENAME,
  189.         eid_SOURCES_DESCRIPTION,
  190.         eid_SOURCES_TYPE,
  191.         eid_SOURCES_ISPARENT,
  192.         eid_SOURCES_CLSID,
  193.         };
  194.  
  195.     static struct tagSOURCES
  196.     {
  197.         ULONG    iOrdinal;
  198.         DBTYPE    wType;
  199.         ULONG    cbMaxLen;    
  200.     } s_rgSources[] = {
  201.         eid_SOURCES_NAME,        DBTYPE_STR,        DEF_SOURCES_CBMAXLEN,
  202.         eid_SOURCES_PARSENAME,    DBTYPE_WSTR,    DEF_SOURCES_CBMAXLEN * sizeof(WCHAR),
  203.         eid_SOURCES_TYPE,        DBTYPE_UI4,        sizeof(ULONG),
  204.     };
  205.     
  206.     memset(rghRows, 0, sizeof(rghRows));
  207.  
  208.     // Initialize the OLE DB Enumerator
  209.     if( FAILED(hr = CoCreateInstance(CLSID_OLEDB_ENUMERATOR, NULL, 
  210.         CLSCTX_INPROC_SERVER, IID_ISourcesRowset, (LPVOID*)&pISrcRowset)) )
  211.     {
  212.         DumpErrorHResult( hr, (LPSTR)"CoCreateInstance FAILED!!" );
  213.         goto EXIT;
  214.     }
  215.  
  216.     // Retrieve the Rowset
  217.     if( FAILED(hr = pISrcRowset->GetSourcesRowset(NULL, IID_IRowset, 0, NULL, 
  218.         (IUnknown**)&pIRowset)) )
  219.     {
  220.         DumpErrorHResult( hr, (LPSTR)"GetSourcesRowset FAILED!!" );
  221.         goto EXIT;
  222.     }
  223.  
  224.     memset(rgBind, 0, sizeof(rgBind));
  225.  
  226.     if( FAILED(hr = pIRowset->QueryInterface(IID_IAccessor, (LPVOID*)&pIAccessor)) )
  227.     {
  228.         DumpErrorHResult( hr, (LPSTR)"QI of IID_IAccessor from pIRowset failed" );
  229.         goto EXIT;
  230.     }
  231.  
  232.     dwOffset = 0;
  233.     for(ul=0; ul< NUMELEM(s_rgSources); ul++)
  234.     {
  235.         rgBind[ul].dwPart        = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  236.         rgBind[ul].eParamIO        = DBPARAMIO_NOTPARAM;
  237.         rgBind[ul].iOrdinal        = s_rgSources[ul].iOrdinal;
  238.         rgBind[ul].wType        = s_rgSources[ul].wType;
  239.         rgBind[ul].obValue        = dwOffset + offsetof(COLUMNDATA,bData);
  240.         rgBind[ul].obLength        = dwOffset + offsetof(COLUMNDATA,dwLength);
  241.         rgBind[ul].obStatus        = dwOffset + offsetof(COLUMNDATA,wStatus);
  242.         rgBind[ul].cbMaxLen        = s_rgSources[ul].cbMaxLen;
  243.         rgBind[ul].dwMemOwner    = DBMEMOWNER_CLIENTOWNED;
  244.         dwOffset += rgBind[ul].cbMaxLen + offsetof( COLUMNDATA, bData );
  245.         dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  246.     }
  247.  
  248.     if( FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, NUMELEM(s_rgSources), 
  249.         rgBind, dwOffset, &hAccessor, NULL)) )
  250.     {
  251.         DumpErrorHResult( hr, (LPSTR)"Accessor Creation failed!!" );
  252.         goto EXIT;
  253.     }
  254.  
  255.     // Retrieve the providers
  256.     if( SUCCEEDED(hr = pIRowset->GetNextRows(NULL, 0, MAX_NUM_PROVIDERS, &cRows, &pRows)) )
  257.     {
  258.         // Allocate block of memory to retrieve the row data into.
  259.         pData = new BYTE[dwOffset];
  260.         if( pData == NULL )
  261.         {
  262.             DumpErrorHResult( E_OUTOFMEMORY, (LPSTR)"Unable to allocate memory for buffer");
  263.             goto EXIT;
  264.         }
  265.  
  266.         // Loop over the rows of data, collecting providers and discarding 
  267.         // enumerators..
  268.         for(ul=0; (ul<cRows) && (ul<MAX_NUM_PROVIDERS); ul++)
  269.         {
  270.             memset(pData, 0, dwOffset);
  271.  
  272.             if( SUCCEEDED(hr = pIRowset->GetData(rghRows[ul], hAccessor, pData)) )
  273.             {
  274.                 if( *((ULONG*)(pData + rgBind[2].obValue)) == DBSOURCETYPE_DATASOURCE )
  275.                 {
  276.                     // Store Provider Name
  277.                     strcpy(g_rgszProvName[g_cProvNames], (CHAR*)(pData + rgBind[0].obValue));
  278.                     
  279.                     // Store Parse Name
  280.                     wcscpy(g_rgwszParseName[g_cProvNames], (WCHAR*)(pData + rgBind[1].obValue));
  281.                     
  282.                     g_cProvNames++;
  283.                 }
  284.             }
  285.         }
  286.     }
  287.     else
  288.     {
  289.         DumpErrorHResult( hr, (LPSTR)"GetNextRows failed to retrieve Providers" );
  290.         goto EXIT;
  291.     }
  292.  
  293.     // Retrieve the IID_IParseDisplayName interface before returning
  294.     if( FAILED(hr = pISrcRowset->QueryInterface(IID_IParseDisplayName, (LPVOID*)&g_pIParse)) )
  295.     {
  296.         DumpErrorHResult( hr, (LPSTR)"QI for IParseDisplayName failed");
  297.         goto EXIT;
  298.     }
  299.  
  300. EXIT:
  301.     if( pData )
  302.         delete[] pData;
  303.  
  304.     if( pIAccessor )
  305.     {
  306.         if( hAccessor )
  307.         {
  308.             if( FAILED(hr = pIAccessor->ReleaseAccessor(hAccessor, NULL)) )
  309.                 DumpErrorHResult( hr, (LPSTR)"Release Accessor failed!!" );
  310.         }
  311.         pIAccessor->Release();
  312.     }
  313.  
  314.     if( pIRowset )
  315.     {
  316.         if( cRows )
  317.         {
  318.             if( FAILED(hr = pIRowset->ReleaseRows(cRows, rghRows, NULL, NULL, NULL)) )
  319.                 DumpErrorHResult( hr, (LPSTR)"Release of Row handles failed");
  320.         }
  321.         pIRowset->Release();
  322.     }
  323.  
  324.     if( pISrcRowset )
  325.         pISrcRowset->Release();
  326.     return hr;
  327. }
  328.  
  329.  
  330. //**********************************************************************
  331. // 
  332. // ConnectDatabase
  333. // 
  334. // Purpose:
  335. // 
  336. //     Initializes the PROVIDER and creates a IDBCreateCommand Object.
  337. //     
  338. // Parameters:
  339. //
  340. //     HWND             hWnd                - handle to the window
  341. // 
  342. // Return Value:
  343. //     TRUE         - Success
  344. //     FALSE        - Failure
  345. // 
  346. // Function Calls:
  347. //     Function                    Location
  348. // 
  349. //     IDBInitialize::Release      provider's Command object
  350. // 
  351. //     
  352. // Comments:      
  353. // 
  354. // 
  355. //**********************************************************************
  356. BOOL FAR PASCAL ConnectDatabase(HWND hWnd)
  357. {
  358.     // Global IDBInitialize Options
  359.     IMoniker*            pIMoniker            = NULL;    // Moniker
  360.     IDBInitialize *     pIDBInit            = NULL;    // IDBInitialize Object
  361.     IDBCreateCommand *    pIDBCreateCommand    = NULL;    // IDBCreateCommand
  362.     IDBCreateSession *    pIDBCreateSession    = NULL; // IDBCreateSession
  363.     IDBProperties*        pIDBProperties        = NULL; // IDBProperties
  364.     IOpenRowset *        pIOpenRowset        = NULL;    // IOpenRowset
  365.     IUnknown *            pIUnknown            = NULL;    // IUnknown
  366.     HRESULT                hr;                            // HRESULT
  367.     DBPROPSET            rgPropertySet[1];            // Array of property sets
  368.     DBPROP                rgProperties[5];            // Array of property values
  369.     BOOL                bReturn = FALSE;            // Return Value
  370.     short                iPrompt = 0;                // DBPROP_INIT_PROMPT value.
  371.     ULONG                iProp, iPDex;
  372.     ULONG                chEaten;
  373.  
  374.     // Strings for MSDASQL (CHAR & WCHAR)
  375.     CHAR                szProvName[MAXBUFLEN+1];    // Provider String
  376.     CHAR                szDBName[MAXBUFLEN+1];        // DSN String
  377.     WCHAR                wszBuff[MAXBUFLEN+1];        // WCHAR buffer
  378.     CHAR                szUserName[MAXBUFLEN+1];    // User Name
  379.     CHAR                szPassword[MAXBUFLEN+1];    // Password
  380.     CHAR                szBuffer[MAXBUFLEN+1];        // String Buffer
  381.     LRESULT             nResult;                    // Return Code
  382.     BOOL                fCommandWindow=FALSE;        // Flag to indicate Command support
  383.  
  384.     // Initialize Property Buffers
  385.     for(iProp=0; iProp<NUMELEM(rgProperties); iProp++)
  386.         VariantInit(&(rgProperties[iProp].vValue));
  387.  
  388.     // check if enough windows are already open, refuse connection
  389.     if (nChildCount >= MAXCHILDWNDS)
  390.     {
  391.         MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND);
  392.         return (FALSE);
  393.     }
  394.  
  395.     // Retrieve Provider values from the connect dialog box
  396.     GetDlgItemText(hWnd, IDCOMBO_PROVIDER, szProvName, MAXBUFLEN);
  397.     GetDlgItemText(hWnd, IDCOMBO_NAME,        szDBName,   MAXBUFLEN);
  398.     GetDlgItemText(hWnd, IDTEXT_USERID,    szUserName, MAXBUFLEN);
  399.     GetDlgItemText(hWnd, IDTEXT_PASSWORD,  szPassword, MAXBUFLEN);
  400.     if ((iPrompt = (short) SendMessage(GetDlgItem(hWnd, IDCOMBO_PROMPT), CB_GETCURSEL, 0, 0)) == CB_ERR)
  401.         iPrompt = 0;
  402.  
  403.     //Determine the ParseDisplayName
  404.     for(iPDex=0; iPDex<g_cProvNames; iPDex++)
  405.     {
  406.         if( strcmp((const char *)szProvName, (const char *) g_rgszProvName[iPDex])==0 )
  407.             break;
  408.     }
  409.  
  410.     if( iPDex >= g_cProvNames )
  411.     {
  412.         DumpErrorHResult( E_FAIL, (LPSTR)"Unknown Provider, Please Select Valid Provider" );
  413.         goto error;
  414.     }
  415.         
  416.     if( FAILED(hr = g_pIParse->ParseDisplayName(NULL, g_rgwszParseName[iPDex], &chEaten, &pIMoniker)) ) 
  417.     {
  418.         DumpErrorHResult( hr, (LPSTR)"ParseDisplayName failed");
  419.         goto error;
  420.     }
  421.  
  422.     if( FAILED(hr = BindMoniker(pIMoniker, 0, IID_IDBInitialize, (LPVOID*)&pIDBInit)) )
  423.     {
  424.         DumpErrorHResult( hr, (LPSTR)"BindMoniker failed");
  425.         goto error;
  426.     }
  427.  
  428.     iProp = 0;
  429.     // If DataSource name specified, then create property node
  430.     if( *szDBName != '\0' )
  431.     {
  432.         // Fill in Data Source
  433.         rgProperties[iProp].dwPropertyID        =    DBPROP_INIT_DATASOURCE;
  434.         rgProperties[iProp].dwOptions            =    DBPROPOPTIONS_REQUIRED;
  435.         rgProperties[iProp].colid                =    DB_NULLID;
  436.         MultiByteToWideChar(CP_ACP, 0, szDBName, -1, wszBuff, MAXBUFLEN+1);
  437.         V_VT(&(rgProperties[iProp].vValue))        =    VT_BSTR;
  438.         V_BSTR(&(rgProperties[iProp].vValue))    =    SysAllocString(wszBuff);
  439.         iProp++;
  440.     }
  441.  
  442.     // If User Name specified, then create property node
  443.     if( *szUserName != '\0' )
  444.     {
  445.         rgProperties[iProp].dwPropertyID    =    DBPROP_AUTH_USERID;
  446.         rgProperties[iProp].dwOptions            =    DBPROPOPTIONS_REQUIRED;
  447.         rgProperties[iProp].colid                =    DB_NULLID;
  448.         MultiByteToWideChar(CP_ACP, 0, szUserName, -1, wszBuff, MAXBUFLEN+1);
  449.         V_VT(&(rgProperties[iProp].vValue))        =    VT_BSTR;
  450.         V_BSTR(&(rgProperties[iProp].vValue))    =    SysAllocString(wszBuff);
  451.         iProp++;
  452.     }
  453.  
  454.     // If Password specified, then create property node
  455.     if( *szPassword != '\0' )
  456.     {
  457.         rgProperties[iProp].dwPropertyID    =    DBPROP_AUTH_PASSWORD;
  458.         rgProperties[iProp].dwOptions            =    DBPROPOPTIONS_REQUIRED;
  459.         rgProperties[iProp].colid                =    DB_NULLID;
  460.         MultiByteToWideChar(CP_ACP, 0, szPassword, -1, wszBuff, MAXBUFLEN+1);
  461.         V_VT(&(rgProperties[iProp].vValue))        =    VT_BSTR;
  462.         V_BSTR(&(rgProperties[iProp].vValue))    =    SysAllocString(wszBuff);
  463.         iProp++;
  464.     }
  465.  
  466.     // Set prompt level if one was given.
  467.     if (iPrompt)
  468.     {
  469.         rgProperties[iProp].dwPropertyID    =    DBPROP_INIT_PROMPT;
  470.         rgProperties[iProp].dwOptions            =    DBPROPOPTIONS_REQUIRED;
  471.         rgProperties[iProp].colid                =    DB_NULLID;
  472.         rgProperties[iProp].vValue.vt            = VT_I2;
  473.         rgProperties[iProp].vValue.iVal            = iPrompt;
  474.         iProp++;
  475.  
  476.         rgProperties[iProp].dwPropertyID    =    DBPROP_INIT_HWND;
  477.         rgProperties[iProp].dwOptions            =    DBPROPOPTIONS_REQUIRED;
  478.         rgProperties[iProp].colid                =    DB_NULLID;
  479.         rgProperties[iProp].vValue.vt            = VT_I4;
  480.         rgProperties[iProp].vValue.lVal            = (long) hWnd;
  481.         iProp++;
  482.     }
  483.  
  484.     if( iProp )
  485.     {
  486.         // Identify Property Set
  487.         rgPropertySet[0].rgProperties        =    rgProperties;
  488.         rgPropertySet[0].cProperties        =    iProp;
  489.         rgPropertySet[0].guidPropertySet    =    DBPROPSET_DBINIT;
  490.  
  491.         // from the DataSource Object get the Session Object
  492.         hr = pIDBInit->QueryInterface( 
  493.                             IID_IDBProperties, 
  494.                             (void**)&pIDBProperties );
  495.         if (FAILED(hr))
  496.         {
  497.             GetDetailedErrorInfo(hr, pIDBInit, IID_IDBInitialize, "QI for IDBProperties FAILED!!");
  498.             goto error;
  499.         }
  500.  
  501.         // Set Connection Properties
  502.         hr = pIDBProperties->SetProperties(1, rgPropertySet);
  503.         if (FAILED(hr))
  504.         {
  505.             GetDetailedErrorInfo(hr, pIDBProperties, IID_IDBProperties, "IDBProperties->SetProperties FAILED!!");
  506.             goto error;
  507.         }
  508.     } 
  509.  
  510.      // Initialize the PROVIDER
  511.     if( FAILED(hr = pIDBInit->Initialize()) )
  512.     {
  513.         GetDetailedErrorInfo(hr, pIDBInit, IID_IDBInitialize, "IDBInit->Initialize FAILED!!");
  514.         goto error;
  515.     }
  516.  
  517.     // from the DataSource Object get the Session Object
  518.     if( FAILED(hr = pIDBInit->QueryInterface( 
  519.                         IID_IDBCreateSession, 
  520.                         (void**)&pIDBCreateSession)) )
  521.     {
  522.         GetDetailedErrorInfo(hr, pIDBInit, IID_IDBInitialize, "QI for IDBCreateSession FAILED!!");
  523.         goto error;
  524.     }
  525.  
  526.     // from the Session object, attempt to get an IUnknown
  527.     if( FAILED(hr = pIDBCreateSession->CreateSession(NULL, IID_IUnknown, (IUnknown**)&pIUnknown)) )
  528.     {
  529.         GetDetailedErrorInfo(hr, pIDBCreateSession, IID_IDBCreateSession, "IDBCreateSession->CreateSession FAILED!!");
  530.         goto error;
  531.     }
  532.  
  533.     // from the Session object, attempt to get the IDBCreateCommand interface
  534.     if( FAILED(hr = pIUnknown->QueryInterface(
  535.                         IID_IDBCreateCommand, 
  536.                         (void**)&pIDBCreateCommand)) )
  537.     {
  538.         // if no Command object support, attempt to get the IOpenRowset interface
  539.         hr = pIUnknown->QueryInterface(
  540.                             IID_IOpenRowset, 
  541.                             (void**)&pIOpenRowset);
  542.         if (FAILED(hr))
  543.         {
  544.             GetDetailedErrorInfo(hr, pIUnknown, IID_IUnknown, "QI for IOpenRowset FAILED!!");
  545.             goto error;
  546.         }
  547.     }
  548.     else
  549.     {
  550.         fCommandWindow = TRUE;
  551.     }
  552.  
  553.     // update the combo-box with IUnknown from Session object
  554.     wsprintf( szBuffer, PROVIDER_SESSION_FORMAT, (LPSTR)szProvName, pIUnknown );
  555.  
  556.     nResult = (UINT)SendMessage(hWndCrsrList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  557.     SendMessage(hWndCrsrList, CB_SETCURSEL, (WPARAM)nResult, 0);
  558.     SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  559.     ChangeCurrentCursor(hWndCrsrList);
  560.     
  561.     if (fCommandWindow)
  562.     {
  563.         // Create a Command Object and its associated window.
  564.         NewICommandWindow();
  565.     }
  566.     else
  567.     {
  568.         NewIOpenRowsetWindow();
  569.     }
  570.  
  571.     bReturn = TRUE;
  572.  
  573. error:
  574.     if( pIMoniker )
  575.         pIMoniker->Release();
  576.  
  577.     // Initialize Property Buffers
  578.     for(iProp=0; iProp<NUMELEM(rgProperties); iProp++)
  579.         VariantClear(&(rgProperties[iProp].vValue));
  580.  
  581.     // If we are successully connected, and the IParse pointer
  582.     // exists release it.
  583.     if( bReturn && g_pIParse )
  584.     {
  585.         g_pIParse->Release();
  586.         g_pIParse = NULL;
  587.     }
  588.  
  589.     // Release IUnknown (for Session) on error only.
  590.     // The pointer value has been copied to the window.
  591.     if( (!bReturn) && (pIUnknown) )
  592.         pIUnknown->Release();
  593.  
  594.     if( (pIDBCreateCommand) )
  595.         pIDBCreateCommand->Release();
  596.  
  597.     if( (pIDBProperties) )
  598.         pIDBProperties->Release();
  599.  
  600.     if( (pIOpenRowset) )
  601.         pIOpenRowset->Release();
  602.  
  603.     if( pIDBCreateSession )
  604.         pIDBCreateSession->Release();
  605.  
  606.     if(pIDBInit)
  607.         pIDBInit->Release();
  608.  
  609.     return (bReturn);
  610.  
  611.  
  612. //**********************************************************************
  613. // 
  614. // DisplayConnections
  615. // 
  616. // Purpose:
  617. // 
  618. //     Display list of available hdbc(s) in the given list box.
  619. //     
  620. // Parameters:
  621. //
  622. //     HWND             hWndhdbc               - handle to the window
  623. // 
  624. // Return Value:
  625. // 
  626. // Function Calls:
  627. //     Function                    Location
  628. // 
  629. // 
  630. //     
  631. // Comments:      
  632. // 
  633. // 
  634. //**********************************************************************
  635. void FAR PASCAL DisplayConnections(HWND hWndhdbc)
  636. {
  637.     ULONG     nConnects;                // # of Connections
  638.     ULONG     count;                    // Count
  639.     char    szBuffer[MAXBUFLEN+1];    // String Buffer
  640.  
  641.     // Read the information from the  combo-box 
  642.     // on the tool bar and feed it in the given list box.
  643.     SendMessage(hWndhdbc, LB_RESETCONTENT, 0, 0);
  644.     nConnects = SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0);
  645.  
  646.     for (count = 0; count < nConnects; count++)
  647.     {
  648.         SendMessage(hWndCrsrList, CB_GETLBTEXT, count, (LPARAM)(LPSTR)szBuffer);
  649.         SendMessage(hWndhdbc, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  650.     }
  651.  
  652.     SendMessage(hWndhdbc, LB_SETCURSEL, 0, 0);
  653. }
  654.  
  655. //**********************************************************************
  656. // 
  657. // DisplayICommands
  658. // 
  659. // Purpose:
  660. // 
  661. //     Initializes the PROVIDER and creates a ICommand Object.
  662. //     Display list of ICommand Objects for the currently selected PROVIDER.
  663. //     
  664. // Parameters:
  665. //
  666. //  HWND             hWndhdbc                 - handle to the PROVIDER
  667. //     HWND             hWndhstmt                - handle to the ICommand
  668. //    int             nCrsrIndex                 - Count
  669. // 
  670. // Return Value:
  671. // 
  672. // Function Calls:
  673. //     Function                    Location
  674. // 
  675. // 
  676. //     
  677. // Comments:      
  678. // 
  679. // 
  680. //**********************************************************************
  681. void FAR PASCAL DisplayICommands(HWND hWndhstmt, HWND hWndhdbc, int nCrsrIndex)
  682. {
  683.     char                szBuffer[MAXBUFLEN+1];    // MDI child window title
  684.     HWND                hWndChild;                // MDI child window handle
  685.     IDBCreateCommand *     pIDBCreate1;            // IDBCreateCommand Object #1
  686.     IDBCreateCommand *     pIDBCreate2;            // IDBCreateCommand Object #2
  687.     ICommand *            pICommand;                // ICommand Object
  688.  
  689.     // Reset the Command list box in the disconnect dialog box
  690.     SendMessage(hWndhstmt, LB_RESETCONTENT, 0, 0);
  691.  
  692.     // Go through all available MDI child windows and check if the
  693.     // PROVIDER in the title matches the one selected in the list box.
  694.     // If they match, use the Command in the window title to create
  695.     // a new entry in the Command list box.
  696.     for (hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT))
  697.     {
  698.         // Class name check is necessary as some of MDI child
  699.         // windows may be iconized by the user and MDIClient
  700.         // in such cases create additional windows (such as icon titles).
  701.         GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  702.         
  703.         if (strcmp(szBuffer, OLEDBMDICLASS))
  704.             continue;
  705.  
  706.         GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  707.         sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate1, &pICommand);
  708.  
  709.         SendMessage(hWndhdbc, LB_GETTEXT, (WPARAM)nCrsrIndex, (LPARAM)(LPSTR)szBuffer);
  710.         sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate2);
  711.  
  712.         if (pIDBCreate1 != pIDBCreate2)
  713.             continue;
  714.  
  715.         wsprintf(szBuffer, ((hWndChild == hWndActiveChild) ?  CURQUERY_STRING:    QUERY_STRING), pICommand);
  716.         SendMessage(hWndhstmt, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  717.     }
  718.     SendMessage(hWndhstmt, LB_SETSEL, TRUE, 0);
  719. }
  720.  
  721. //**********************************************************************
  722. // 
  723. // NewICommandWindow
  724. // 
  725. // Purpose:
  726. // 
  727. //     Create a new ICommand Object on the current IDBCreateCommand.
  728. //     
  729. // Parameters:
  730. // 
  731. // Return Value:
  732. // 
  733. // Function Calls:
  734. //     Function                         Location
  735. // 
  736. //       IDBCreateCommand::CreateCommand    provider's Command object
  737. //     ICommand::Release                provider's Command object
  738. //        
  739. //     
  740. // Comments:      
  741. // 
  742. // 
  743. //**********************************************************************
  744. void FAR PASCAL NewICommandWindow()
  745. {
  746.     int                 nCurrenthdbc;                // Current PROVIDER
  747.     char                szBuffer[MAXBUFLEN+1];        // String in PROVIDER ComboBox on Toolbar
  748.     char                szProvName[MAXBUFLEN+1];    // DSN String
  749.     MDICREATESTRUCT        mcs;                        // MDI Child Window Create Struc
  750.     
  751.     IDBCreateCommand *     pIDBCreateCommand    = NULL;    // IDBCreateCommand Object
  752.     IOpenRowset *         pIOpenRowset        = NULL;    // IOpenRowset Object
  753.     ICommand *            pICommand            = NULL;    // ICommand Object
  754.     ICommand *            pIUnknown            = NULL;    // IUnknown for session Object
  755.     HRESULT                hr;                            // HRESULT
  756.     BOOL                bReturn                = FALSE;// Return Value
  757.  
  758.         
  759.     // check if there is PROVIDER selected in the Combo-Box
  760.     if ((nCurrenthdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0)) == CB_ERR)
  761.     {
  762.         MessageBox(hWndFrame, MAKECONNECT, NOSESSIONERROR, MB_OK | MB_ICONHAND);
  763.         return;
  764.     }
  765.     
  766.     // check if the number of windows exceeds MAXCHILDWNDS
  767.     if (nChildCount >= MAXCHILDWNDS)
  768.     {
  769.         MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND);
  770.         return;
  771.     }
  772.  
  773.     // Scan PROVIDER string and IDBCreateCommand value from the combo-box
  774.     SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nCurrenthdbc, (LPARAM)(LPSTR)szBuffer);
  775.     
  776.     sscanf(szBuffer, SCANPROVIDERSESSION_FORMAT, szProvName, &pIUnknown);
  777.         
  778.     // from the Session object, attempt to get the IDBCreateCommand interface
  779.     hr = pIUnknown->QueryInterface(
  780.                         IID_IDBCreateCommand, 
  781.                         (void**)&pIDBCreateCommand);
  782.     if (FAILED(hr))
  783.     {
  784.         // if no Command object support, attempt to get the IOpenRowset interface
  785.         hr = pIUnknown->QueryInterface(
  786.                             IID_IOpenRowset, 
  787.                             (void**)&pIOpenRowset);
  788.         if (FAILED(hr))
  789.         {
  790.             GetDetailedErrorInfo(hr, pIUnknown, IID_IUnknown, "QI for IOpenRowset FAILED!!");
  791.             goto error;
  792.         }
  793.     }
  794.     else
  795.     {
  796.         // Create a command object 
  797.         hr = pIDBCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown**)&pICommand);
  798.  
  799.         if (FAILED(hr))
  800.         {
  801.            GetDetailedErrorInfo(hr, pIDBCreateCommand, IID_IDBCreateCommand, "pIDBCreateCommand->CreateCommand FAILED!!");
  802.            goto error;
  803.         }
  804.     }
  805.  
  806.         
  807.     // create a new MDI client window. maximized, if the previous is so.
  808.     mcs.szClass = OLEDBMDICLASS;
  809.     mcs.szTitle = UNTITLED;
  810.     mcs.hOwner  = hAppInstance;
  811.     mcs.style   = hWndActiveChild && IsZoomed(hWndActiveChild) ? WS_MAXIMIZE : 0;
  812.     mcs.x = mcs.cx = mcs.y = mcs.cy = CW_USEDEFAULT;
  813.     hWndActiveChild = (HWND)(UINT)SendMessage(hWndMDIClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mcs);
  814.         
  815.     // check if it was created, if it wasn't free up resource and flag warning
  816.     if (!hWndActiveChild)
  817.     {
  818.         MessageBox(hWndFrame, CREATECHILDERR, EXECERROR, MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL);
  819.         goto error;
  820.     }
  821.         
  822.     // Display the Provider string, PROVIDER and IDBCreateCommand/IOpenRowset in the title
  823.     // of newly created window. Increment the child window counter
  824.      wsprintf(szBuffer, QUERY_STRING, pICommand);
  825.         
  826.     SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  827.     SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  828.     
  829.      wsprintf(szBuffer, PROVIDER_SESSION_COMMAND_FORMAT, (LPSTR)szProvName, pIUnknown, pICommand);
  830.     
  831.     SetWindowText(hWndActiveChild, szBuffer);
  832.     nChildCount++;
  833.     
  834.     // Update the Command Combo-Box on the tool bar.
  835.     ChangeCurrentICommand(hWndStmtList);
  836.     bReturn = TRUE;
  837.  
  838. error:
  839.     // Note that we obtained pIUnknown (Session ptr) from the window.
  840.     // So we leave it alone.
  841.  
  842.     // Release ICommand on error only.
  843.     // The pointer value has been copied to the window.
  844.     if (pICommand && !bReturn)
  845.         pICommand->Release();
  846.  
  847.     if (pIDBCreateCommand)
  848.         pIDBCreateCommand->Release();
  849.  
  850.     if (pIOpenRowset)
  851.         pIOpenRowset->Release();
  852. }
  853.  
  854.  
  855.  
  856.  
  857. //**********************************************************************
  858. // 
  859. // ChangeCurrentCursor
  860. // 
  861. // Purpose:
  862. // 
  863. //     Change the displayed PROVIDER in the PROVIDER(s) combobox.
  864. //     Also activate the appropriate MDI child window that
  865. //     has the same PROVIDER as the new PROVIDER in the combobox.
  866. //
  867. // Parameters:
  868. //
  869. //     HWND             hWndCrsrList               - handle to the window
  870. // 
  871. // Return Value:
  872. // 
  873. // Function Calls:
  874. //     Function                    Location
  875. // 
  876. // 
  877. //     
  878. // Comments:      
  879. // 
  880. // 
  881. //**********************************************************************
  882. void FAR PASCAL ChangeCurrentCursor(HWND hWndCrsrList)
  883. {
  884.     ULONG                nNewhdbc;                // New PROVIDER position
  885.     ULONG                nConnects;                // # of connections
  886.     ULONG                nCount;                    // Counter
  887.     char                szBuffer[MAXBUFLEN+1];    // String Buffer
  888.     BOOL                bChangedFocus;            // Activate different MDI child
  889.     HWND                hWndChild;                // MDI Child window
  890.     IDBCreateCommand*     pIDBCreate1;            // IDBCreateCommand #1
  891.     IDBCreateCommand*     pIDBCreate2;            // IDBCreateCommand #2
  892.     ICommand*            pICommand;                // ICommand Object
  893.  
  894.     // check to see if the current selection in the combo-box
  895.     // differs from the previous selection, if it is the same then
  896.     // simply return. Check is made by searching a marked string
  897.     // in the PROVIDER combobox.
  898.     nNewhdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0);
  899.     nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0);
  900.  
  901.     for(nCount = 0; nCount < nConnects; nCount++)
  902.     {
  903.         SendMessage(hWndCrsrList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer);
  904.         if (strstr(szBuffer, CUR_MARK))
  905.             break;
  906.     }
  907.  
  908.     if (nCount == nNewhdbc)
  909.         return;
  910.  
  911.     // if there was a current marked hdbc in the combobox, remove the
  912.     // mark from the string and replace it in the combobox.
  913.     if (nCount != nConnects)
  914.     {
  915.         SendMessage(hWndCrsrList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer);
  916.         szBuffer[strlen(szBuffer)-2] = '\0';
  917.         SendMessage(hWndCrsrList, CB_INSERTSTRING, nCount, (LPARAM)(LPSTR)szBuffer);
  918.         SendMessage(hWndCrsrList, CB_DELETESTRING, nCount+1, 0);
  919.     }
  920.     
  921.     // Create a new marked string with currently selected hdbc string in
  922.     // the combobox and replace it with the original.
  923.     SendMessage(hWndCrsrList, CB_GETLBTEXT, nNewhdbc, (LPARAM)(LPSTR)szBuffer);
  924.     strcat(szBuffer, CUR_MARK);
  925.     SendMessage(hWndCrsrList, CB_INSERTSTRING, nNewhdbc, (LPARAM)(LPSTR)szBuffer);
  926.     SendMessage(hWndCrsrList, CB_DELETESTRING, nNewhdbc+1, 0);
  927.     SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  928.  
  929.     // Reset the ICommand combobox. Search through the MDI child windows
  930.     // and collect all ICommands from window titles that have the same
  931.     // PROVIDER value as the newly selected PROVIDER in the PROVIDER(s) combo-box above.
  932.     SendMessage(hWndStmtList, CB_RESETCONTENT, 0, 0);
  933.     for (bChangedFocus=FALSE, hWndChild=GetWindow(hWndMDIClient, GW_CHILD);    hWndChild; hWndChild = GetWindow(
  934.         hWndChild, GW_HWNDNEXT))
  935.     {
  936.         // Check class name to skip iconized titles or other
  937.         // such non MDI Child windows
  938.         GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  939.         if (strcmp(szBuffer, OLEDBMDICLASS))
  940.             continue;
  941.  
  942.         GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  943.         sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate1, &pICommand);
  944.  
  945.         SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nNewhdbc, (LPARAM)(LPSTR)szBuffer);
  946.         sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate2);
  947.  
  948.         if (pIDBCreate1 != pIDBCreate2)
  949.             continue;
  950.                 
  951.         if (!bChangedFocus)
  952.         {
  953.             // If the first match is found, change the active window
  954.             // and update the ICommand(s) combobox with a new entry that
  955.             // has ICommand marked with current marker.
  956.             bChangedFocus = TRUE;
  957.             hWndActiveChild = hWndChild;
  958.             SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0);
  959.             wsprintf(szBuffer, CURQUERY_STRING, pICommand);
  960.             SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  961.             SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  962.         }
  963.         else
  964.         {
  965.             // simply add the ICommand in the ICommand(s) combobox.
  966.             wsprintf(szBuffer, QUERY_STRING, pICommand);
  967.             SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  968.         }
  969.     }
  970. }
  971.  
  972. //**********************************************************************
  973. // 
  974. // ChangeCurrentICommand
  975. // 
  976. // Purpose:
  977. // 
  978. //     Change the current selection in the ICommand(s) combobox.
  979. //     Update the current marker in the combobox and activate
  980. //     proper MDI Child window.
  981. //
  982. // Parameters:
  983. //
  984. //     HWND             hWndStmtList               - handle to the window
  985. // 
  986. // Return Value:
  987. // 
  988. // Function Calls:
  989. //     Function                    Location
  990. // 
  991. // 
  992. //     
  993. // Comments:      
  994. // 
  995. // 
  996. //**********************************************************************
  997. void FAR PASCAL ChangeCurrentICommand(HWND hWndStmtList)
  998. {
  999.     ULONG                nNewICommand;            // New Selection in Combo-Box
  1000.     ULONG                 nICommands;                // # of ICommands
  1001.     ULONG                 nCount;                    // Counter
  1002.     char                szBuffer[MAXBUFLEN+1];    // String Buffer
  1003.     HWND                hWndChild;                // MDI Child Window Handle
  1004.     IDBCreateCommand*     pIDBCreate1;            // IDBCreateCommand Object #1
  1005.     IDBCreateCommand*     pIDBCreate2;            // IDBCreateCommand Object #2
  1006.     ICommand*            pICommand1;                // ICommand Object #1
  1007.     ICommand*            pICommand2;                // ICommand Object #2
  1008.  
  1009.     // Find the index of new selection and total number of ICommand(s)
  1010.     nNewICommand = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0);
  1011.     nICommands      = (int)SendMessage(hWndStmtList, CB_GETCOUNT,  0, 0);
  1012.  
  1013.     // Check if the current selection is same as previous one, if
  1014.     // so simply return. Check for marker to determine previous selection
  1015.     for(nCount = 0; nCount < nICommands; nCount++)
  1016.     {
  1017.         SendMessage(hWndStmtList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer);
  1018.         if (strstr(szBuffer, CUR_MARK))
  1019.             break;
  1020.     }
  1021.  
  1022.     if (nCount == nNewICommand)
  1023.         return;
  1024.  
  1025.     // If a previous selection was found, remove current marker
  1026.     // and update it in the ICommand(s) combobox.
  1027.     if (nCount != nICommands)
  1028.     {
  1029.         SendMessage(hWndStmtList, CB_GETLBTEXT, nCount, (LPARAM)(LPSTR)szBuffer);
  1030.         szBuffer[strlen(szBuffer)-2] = '\0';
  1031.         SendMessage(hWndStmtList, CB_INSERTSTRING, nCount, (LPARAM)(LPSTR)szBuffer);
  1032.         SendMessage(hWndStmtList, CB_DELETESTRING, nCount+1, 0);
  1033.     }
  1034.     
  1035.     // Mark the current selection and update it in the ICommand(s) combobox
  1036.     SendMessage(hWndStmtList, CB_GETLBTEXT, nNewICommand, (LPARAM)(LPSTR)szBuffer);
  1037.     strcat(szBuffer, CUR_MARK);
  1038.     SendMessage(hWndStmtList, CB_INSERTSTRING, nNewICommand, (LPARAM)(LPSTR)szBuffer);
  1039.     SendMessage(hWndStmtList, CB_DELETESTRING, nNewICommand+1, 0);
  1040.     SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  1041.  
  1042.     // Scan ICommand value and DSN value from current selection in
  1043.     // PROVIDER(s) and ICommand(s) comboboxes.
  1044.     sscanf(szBuffer, QUERY_STRING, &pICommand1);
  1045.     
  1046.     SendMessage( hWndCrsrList, CB_GETLBTEXT, 
  1047.                 (UINT)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0),
  1048.                 (LPARAM)(LPSTR)szBuffer);
  1049.  
  1050.     sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate1);
  1051.  
  1052.     // Go through list of MDI Child windows and match the ICommand and PROVIDER
  1053.     // values. If a match if found (must be), activate the window
  1054.     for (hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT))
  1055.     {
  1056.         // Ignore non MDI child windows
  1057.         GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  1058.         if (strcmp(szBuffer, OLEDBMDICLASS))
  1059.             continue;
  1060.  
  1061.         GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  1062.         sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate2, &pICommand2);
  1063.  
  1064.         if (pIDBCreate1 == pIDBCreate2 && pICommand1 == pICommand2)
  1065.         {
  1066.             hWndActiveChild = hWndChild;
  1067.             SendMessage(hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChild, 0);
  1068.             break;
  1069.         }
  1070.     }
  1071. }
  1072.  
  1073. //**********************************************************************
  1074. // 
  1075. // DisplayNewCrsrAndICommand
  1076. // 
  1077. // Purpose:
  1078. // 
  1079. //     Change the current selection in the ICommand(s) combobox.
  1080. //     Update the current marker in the combobox and activate
  1081. //     proper MDI Child window.
  1082. //
  1083. // Parameters:
  1084. //
  1085. //     HWND             hWndStmtList               - handle to the window
  1086. // 
  1087. // Return Value:
  1088. // 
  1089. // Function Calls:
  1090. //     Function                    Location
  1091. // 
  1092. // 
  1093. //     
  1094. // Comments:      
  1095. // 
  1096. // 
  1097. //**********************************************************************
  1098. void FAR PASCAL DisplayNewCrsrAndICommand()
  1099. {
  1100.     ULONG                 nConnects;                // # of PROVIDER(s)
  1101.     ULONG                 nICommands;                // # of ICommand(s)
  1102.     ULONG                 nOldPROVIDER;                // Prev selected PROVIDER in combobox
  1103.     ULONG                nOldICommand;            // Prev selected ICommand in combobox
  1104.     ULONG                nIndex;                    // Counter
  1105.     char                szBuffer[MAXBUFLEN+1];    // String Buffer
  1106.     HWND                hWndChild;                // MDI Child Window
  1107.     IDBCreateCommand*     pIDBCreate1;            // IDBCreateCommand Object #1
  1108.     IDBCreateCommand*     pIDBCreate2;            // IDBCreateCommand Object #2
  1109.     ICommand*            pICommand1;                // ICommand Object #1
  1110.     ICommand*            pICommand2;                // ICommand Object #2
  1111.  
  1112.     // Scan PROVIDER and ICommand values from newly selected window
  1113.     GetWindowText(hWndActiveChild, szBuffer, MAXBUFLEN);
  1114.     sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate1, &pICommand1);
  1115.  
  1116.     // Search through list of PROVIDER(s) in PROVIDER combobox and find
  1117.     // matching PROVIDER. remove marker from prev selection and add
  1118.     // marker to the new selection. Update combobox accordingly.
  1119.     nConnects = (int)SendMessage(hWndCrsrList, CB_GETCOUNT,  0, 0);
  1120.     nOldPROVIDER   = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0);
  1121.  
  1122.     for(pIDBCreate2 = (IDBCreateCommand*)(nIndex = 0); pIDBCreate1 != pIDBCreate2; nIndex++)
  1123.     {
  1124.         SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  1125.         sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate2);
  1126.     }
  1127.  
  1128.     // Change in PROVIDER combobox required.
  1129.     if (--nIndex != nOldPROVIDER)
  1130.     {
  1131.         SendMessage(hWndCrsrList, CB_GETLBTEXT, nOldPROVIDER, (LPARAM)(LPSTR)szBuffer);
  1132.         szBuffer[strlen(szBuffer)-2] = '\0';
  1133.         SendMessage(hWndCrsrList, CB_INSERTSTRING, nOldPROVIDER, (LPARAM)(LPSTR)szBuffer);
  1134.         SendMessage(hWndCrsrList, CB_DELETESTRING, nOldPROVIDER+1, 0);
  1135.  
  1136.         SendMessage(hWndCrsrList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  1137.         strcat(szBuffer, CUR_MARK);
  1138.         SendMessage(hWndCrsrList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer);
  1139.         SendMessage(hWndCrsrList, CB_DELETESTRING, nIndex+1, 0);
  1140.         SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  1141.  
  1142.         // Reset the ICommand(s) combobox, search through the list
  1143.         // of MDI child windows and find all hstmt(s) associated to
  1144.         // new PROVIDER. Build the new list of ICommand(s) for the ICommand
  1145.         // combobox. Mark the one ICommand that matches the currently
  1146.         // activated MDI child window.
  1147.         SendMessage(hWndStmtList, CB_RESETCONTENT, 0, 0);
  1148.         for (hWndChild=GetWindow(hWndMDIClient,GW_CHILD);hWndChild;hWndChild=GetWindow(hWndChild,GW_HWNDNEXT))
  1149.         {
  1150.             GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  1151.             if (strcmp(szBuffer, OLEDBMDICLASS))
  1152.                 continue;
  1153.  
  1154.             GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  1155.             sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate2, &pICommand2);
  1156.  
  1157.             if (pIDBCreate1 != pIDBCreate2)
  1158.                 continue;
  1159.  
  1160.             if (hWndActiveChild == hWndChild)
  1161.             {
  1162.                 wsprintf(szBuffer, CURQUERY_STRING, pICommand2);
  1163.                 SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  1164.                 SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  1165.             }
  1166.             else
  1167.             {
  1168.                 wsprintf(szBuffer, QUERY_STRING, pICommand2);
  1169.                 SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  1170.             }
  1171.         }
  1172.     }
  1173.     // No change in PROVIDER combobox required
  1174.     else
  1175.     {
  1176.         // Go through the list of ICommand(s) in ICommand combobox.
  1177.         // Find the one that matches the currently activated MDI child window.
  1178.         nOldICommand = (int)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0);
  1179.         nICommands = (int)SendMessage(hWndStmtList, CB_GETCOUNT, 0, 0);
  1180.  
  1181.         for(pICommand2 = (ICommand*)(nIndex = 0); pICommand1 != pICommand2; nIndex++)
  1182.         {
  1183.             SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  1184.             sscanf(szBuffer, QUERY_STRING, &pICommand2);
  1185.         }
  1186.  
  1187.         // New index in ICommand differs from previous selection
  1188.         if (--nIndex != nOldICommand)
  1189.         {
  1190.             // Remove the marker from previous selection.
  1191.             // Add it to the new string and update the combobox display
  1192.             SendMessage(hWndStmtList, CB_GETLBTEXT, nOldICommand, (LPARAM)(LPSTR)szBuffer);
  1193.             szBuffer[strlen(szBuffer)-2] = '\0';
  1194.             SendMessage(hWndStmtList, CB_INSERTSTRING, nOldICommand, (LPARAM)(LPSTR)szBuffer);
  1195.             SendMessage(hWndStmtList, CB_DELETESTRING, nOldICommand+1, 0);
  1196.  
  1197.             SendMessage(hWndStmtList, CB_GETLBTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  1198.             strcat(szBuffer, CUR_MARK);
  1199.             SendMessage(hWndStmtList, CB_INSERTSTRING, nIndex, (LPARAM)(LPSTR)szBuffer);
  1200.             SendMessage(hWndStmtList, CB_DELETESTRING, nIndex+1, 0);
  1201.             SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  1202.         }
  1203.     }
  1204. }
  1205.  
  1206. //**********************************************************************
  1207. // 
  1208. // FreeConnect
  1209. // 
  1210. // Purpose:
  1211. // 
  1212. //     Disconnect and Free the currently selected PROVIDER in
  1213. //     the PROVIDER listbox in disconnect dialog. Call RELEASE
  1214. //     to free the PROVIDER. Close all MDI
  1215. //     child windows associated with this PROVIDER. That will
  1216. //     automatically free associated ICommand(s).
  1217. //
  1218. // Parameters:
  1219. //
  1220. //     HWND             hWndhdbc               - handle to the window
  1221. // 
  1222. // Return Value:
  1223. // 
  1224. // Function Calls:
  1225. //     Function                    Location
  1226. // 
  1227. //     IDBCreateCommand::Release   provider's Command object
  1228. //     
  1229. // Comments:      
  1230. // 
  1231. // 
  1232. //**********************************************************************
  1233. void FAR PASCAL FreeConnect(HWND hWndhdbc)
  1234. {
  1235.     int                 nIndex;                    // Current Selection in the listbox of disconnect dlg
  1236.     int                    nCurrent;                // Current Selected PROVIDER(s) combobox
  1237.     char                szBuffer[MAXBUFLEN+1];    // String Buffer
  1238.     char                szSelect[MAXBUFLEN+1];    // Original Selected PROVIDER(s) combobox
  1239.     char                szProvName[MAXBUFLEN+1];// DSN string
  1240.     HWND                hWndChild;                // MDI Child window
  1241.     IDBCreateCommand *     pIDBCreate1;            // IDBCreateCmmand Object #1
  1242.     IDBCreateCommand *     pIDBCreate2;            // IDBCreateCmmand Object #2
  1243.     IErrorInfo *        pIErrorInfo;            // IErrorInfo Object
  1244.  
  1245.     // Check current selection in the list box of disconnect dialog. 
  1246.     // Scan PROVIDER value from the current selection.
  1247.     if ((nIndex = (int)SendMessage(hWndhdbc, LB_GETCURSEL, 0, 0)) == LB_ERR)
  1248.         return;
  1249.  
  1250.     SendMessage(hWndhdbc, LB_GETTEXT, (WPARAM)nIndex, (LPARAM)(LPSTR)szBuffer);
  1251.     sscanf(szBuffer, SCANPROVIDERSESSION_FORMAT, szProvName, &pIDBCreate1);
  1252.  
  1253.     // Go through the list of MDI child windows and find matching PROVIDER(s)
  1254.     // close all children who have the same PROVIDER value. Closing them
  1255.     // automatically frees associated ICommands. See CloseICommandWindow.
  1256.     for(hWndChild = GetWindow(hWndMDIClient, GW_CHILD); hWndChild; )
  1257.     {
  1258.         // Store next window handle before destroying the currentone
  1259.         HWND hWndTemp = GetWindow(hWndChild, GW_HWNDNEXT);
  1260.         
  1261.         // Ignore non MDI child windows
  1262.         GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  1263.         if (!strcmp(szBuffer, OLEDBMDICLASS))
  1264.         {
  1265.             GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  1266.             sscanf(szBuffer, SCANSESSION_TITLEFORMAT, &pIDBCreate2);
  1267.             if (pIDBCreate1 == pIDBCreate2)
  1268.             {
  1269.                 // Destroy the window and restart search
  1270.                 SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0);
  1271.                 hWndTemp = GetWindow(hWndMDIClient, GW_CHILD);
  1272.             }
  1273.         }
  1274.         hWndChild = hWndTemp;
  1275.     }
  1276.  
  1277.     // Release the Command Object & return
  1278.     if( pIDBCreate1 )
  1279.         pIDBCreate1->Release();
  1280.  
  1281.     // Release any remaining error objects.  This is idempotent.
  1282.     // Otherwise the provider might have an outstanding global-object count.
  1283.     GetErrorInfo( 0, &pIErrorInfo );
  1284.     if (pIErrorInfo)
  1285.         pIErrorInfo->Release();
  1286.  
  1287.     // Unload any DLL's no longer being used
  1288.     CoFreeUnusedLibraries();
  1289.         
  1290.     // Update the PROVIDER(s) combobox display by removing the deleted PROVIDER
  1291.     // from the list and reselecting the previous selection
  1292.     wsprintf(szBuffer, PROVIDER_SESSION_FORMAT, (LPSTR)szProvName, pIDBCreate1);
  1293.     nCurrent = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0);
  1294.     SendMessage(hWndCrsrList, CB_GETLBTEXT, nCurrent, (LPARAM)(LPSTR)szSelect);
  1295.     nIndex = (int)SendMessage(hWndCrsrList, CB_FINDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  1296.     SendMessage(hWndCrsrList, CB_DELETESTRING, (WPARAM)nIndex, 0);
  1297.     SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szSelect);
  1298.     
  1299.     // If there is no query window open and the current selected PROVIDER
  1300.     // was deleted, make sure to make the next available PROVIDER as current
  1301.     if (SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) &&
  1302.         !GetWindow(hWndMDIClient, GW_CHILD) && (nCurrent == nIndex))
  1303.     {
  1304.         if ((nCurrent = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0))!=CB_ERR)
  1305.             return;
  1306.         SendMessage(hWndCrsrList, CB_GETLBTEXT, 0, (LPARAM)(LPSTR)szSelect);
  1307.         strcat(szSelect, CUR_MARK);
  1308.         SendMessage(hWndCrsrList, CB_INSERTSTRING, 0, (LPARAM)(LPSTR)szSelect);
  1309.         SendMessage(hWndCrsrList, CB_DELETESTRING, 1, 0);
  1310.         SendMessage(hWndCrsrList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szSelect);
  1311.     }
  1312. }
  1313.  
  1314. //**********************************************************************
  1315. // 
  1316. // FreeICommand
  1317. // 
  1318. // Purpose:
  1319. // 
  1320. //     Free a ICommand window based upon current selection in
  1321. //     ICommand list box in the disconnect dialog.
  1322. //
  1323. // Parameters:
  1324. //
  1325. //     HWND             hWndhstmt               - handle to the window
  1326. //     HWND             hWndhdbc                - handle to the window
  1327. //  int             nIndex                    - Index
  1328. // 
  1329. // Return Value:
  1330. // 
  1331. // Function Calls:
  1332. //     Function                    Location
  1333. // 
  1334. // 
  1335. //     
  1336. // Comments:      
  1337. // 
  1338. // 
  1339. //**********************************************************************
  1340. void FAR PASCAL FreeICommand(HWND hWndhstmt, HWND hWndhdbc, int nIndex)
  1341. {
  1342.     char                szBuffer[MAXBUFLEN+1];    // display buffer
  1343.     HWND                hWndChild;                // MDI child window
  1344.     IDBCreateCommand*     pIDBCreate1;            // IDBCreateCommand Object #1
  1345.     IDBCreateCommand*     pIDBCreate2;            // IDBCreateCommand Object #2
  1346.     ICommand*            pICommand1;                // ICommand Object #1
  1347.     ICommand*            pICommand2;                // ICommand Object #2
  1348.  
  1349.     // Scan the ICommand and PROVIDER values from the current selections in
  1350.     // respective listboxes of disconnect dialog box.
  1351.     SendMessage(hWndhstmt, LB_GETTEXT, nIndex, (LPARAM)(LPSTR)szBuffer);
  1352.     sscanf(szBuffer, QUERY_STRING, &pICommand1);
  1353.     SendMessage(hWndhdbc, LB_GETTEXT, (UINT)SendMessage(hWndhdbc, LB_GETCURSEL,    0, 0), (LPARAM)(LPSTR)szBuffer);
  1354.     sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate1);
  1355.         
  1356.     // Go through the list of MDI child windows and find matching window
  1357.     // that has same values for PROVIDER and ICommand. Destroy the matching window.
  1358.     // That will call CloseICommandWindow and free up associated ICommand(s).
  1359.     for(hWndChild=GetWindow(hWndMDIClient, GW_CHILD); hWndChild; hWndChild=GetWindow(hWndChild, GW_HWNDNEXT))
  1360.     {
  1361.         // Ignore non MDI child windows
  1362.         GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  1363.         if( strcmp(szBuffer, OLEDBMDICLASS) )
  1364.             continue;
  1365.  
  1366.         GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  1367.         sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate2, &pICommand2);
  1368.         if (pIDBCreate1 == pIDBCreate2 && pICommand1 == pICommand2)
  1369.             break;
  1370.     }
  1371.     SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0);
  1372. }
  1373.  
  1374. //**********************************************************************
  1375. // 
  1376. // CloseICommandWindow
  1377. // 
  1378. // Purpose:
  1379. // 
  1380. //     Close a ICommand window. 
  1381. //     Call ICommand->Release() to free associated ICommand(s).
  1382. //
  1383. // Parameters:
  1384. //
  1385. //     HWND             hWnd               - handle to the window
  1386. // 
  1387. // Return Value:
  1388. // 
  1389. // Function Calls:
  1390. //     Function                    Location
  1391. // 
  1392. //     ICommand::Release           provider's Command object
  1393. //     
  1394. // Comments:      
  1395. // 
  1396. // 
  1397. //**********************************************************************
  1398. void FAR PASCAL CloseICommandWindow(HWND hWnd)
  1399. {
  1400.     char        szBuffer[MAXBUFLEN+1];    // String buffer
  1401.     char        szSelect[MAXBUFLEN+1];    // Current Selected ICommand(s)
  1402.     ICommand*    pICommand;                // ICommand Object
  1403.  
  1404.     // Scan the ICommand value from the window title
  1405.     GetWindowText(hWnd, szBuffer, MAXBUFLEN);
  1406.     sscanf(szBuffer, SCANCOMMAND_TITLEFORMAT, &pICommand);
  1407.  
  1408.     // Release the Command Object & return
  1409.     if( pICommand )
  1410.         pICommand->Release();
  1411.  
  1412.     // Find the matching ICommand in the ICommand(s) combobox and remove it
  1413.     // from the list. Closure of a MDI child window will cause MDIClient
  1414.     // to automatically activate a different child window if available.
  1415.     // That will automatically refresh the ICommand and PROVIDER displays. 
  1416.     // See DisplayNewCrsrAndICommand function.
  1417.     wsprintf( szBuffer, QUERY_STRING, pICommand );
  1418.     
  1419.     SendMessage( hWndStmtList, CB_GETLBTEXT, 
  1420.                 (WPARAM)SendMessage(hWndStmtList, CB_GETCURSEL, 0, 0),
  1421.                 (LPARAM)(LPSTR)szSelect );
  1422.     
  1423.     SendMessage( hWndStmtList, CB_DELETESTRING, 
  1424.                 (WPARAM)SendMessage(hWndStmtList, CB_FINDSTRING, 0,
  1425.                 (LPARAM)(LPSTR)szBuffer), 0 );
  1426.     
  1427.     SendMessage( hWndStmtList, CB_SELECTSTRING,
  1428.                 (WPARAM)-1, 
  1429.                 (LPARAM)(LPSTR)szSelect );
  1430.     
  1431.     // Decrement the child window counter.
  1432.     nChildCount--;
  1433. }
  1434.  
  1435. //**********************************************************************
  1436. // 
  1437. // ExecuteQuery
  1438. // 
  1439. // Purpose:
  1440. // 
  1441. //     Execute the user typed SQL Statements in the currently 
  1442. //     active MDI child window. If successful, then prepare
  1443. //     the list of results and display it in the child listbox.
  1444. //     Display errors in the OLE DB function(s) failed.
  1445. //
  1446. // Parameters:
  1447. //
  1448. // Return Value:
  1449. // 
  1450. // Function Calls:
  1451. //     Function                    Location
  1452. // 
  1453. //     ExecuteCommand              query.cpp
  1454. //     GetDataFromRowset           query.cpp
  1455. // 
  1456. //     
  1457. // Comments:      
  1458. // 
  1459. // 
  1460. //**********************************************************************
  1461. void FAR PASCAL ExecuteQuery()
  1462. {
  1463.     CHAR                szBuffer[MAXBUFLEN+1];        // String Buffer
  1464.     WCHAR                wszBuffer[MAXBUFLEN+1];        // String Buffer (WCHAR)
  1465.     signed short int    swColLength = MAXDATALEN;    // Column Data Length
  1466.     HCURSOR                hOldCursor;                    // Default Cursor Handle
  1467.     IUnknown*            pIUnknown     = NULL;            // Session Object
  1468.     ICommand*            pICommand     = NULL;            // ICommand Object
  1469.     IOpenRowset*        pIOpenRowset= NULL;            // IOpenRowset Object
  1470.     IRowset*            pIRowset     = NULL;            // IRowset Object
  1471.     HRESULT                hr;                            // HRESULT
  1472.  
  1473.     // Check if there is an active window available
  1474.     if (!hWndActiveChild)
  1475.     {
  1476.         MessageBox(hWndFrame, ((SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) <=0) ?
  1477.             MAKECONNECT : OPENWINDOW ), NOCOMMANDERROR, MB_OK | MB_ICONHAND);
  1478.         return;
  1479.     }
  1480.  
  1481.     // Change cursor shape to hour glass
  1482.     hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT));
  1483.             
  1484.     // Scan PROVIDER, session and ICommand values
  1485.     GetWindowText(hWndActiveChild, (char*)szBuffer, MAXBUFLEN);
  1486.     sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIUnknown, &pICommand);
  1487.  
  1488.     // Get the user typed SQL
  1489.     GetWindowText(GetDlgItem((HWND)GetWindowLong(hWndActiveChild, GWLAPP_HDLG), IDTEXT_SQL), szBuffer, MAXBUFLEN);
  1490.  
  1491.     // Convert ANSI String to WCHAR    String
  1492.     MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, wszBuffer, MAXBUFLEN+1);
  1493.  
  1494.     // Execute the Command Object
  1495.     hr = ExecuteCommand( pIUnknown, pICommand, wszBuffer, &pIRowset ); 
  1496.  
  1497.     if (FAILED(hr))
  1498.         return;
  1499.  
  1500.     // Empty IRowset
  1501.     if( hr == ResultFromScode(S_FALSE) )
  1502.     { 
  1503.         DumpErrorHResult( ResultFromScode(S_OK), (LPSTR)"ExecuteCommand returned No Rowset!!" );
  1504.         return;
  1505.     }
  1506.  
  1507.     // Get Data from the IRowset Object
  1508.     GetDataFromRowset( pIRowset );
  1509. }
  1510.  
  1511.  
  1512. //**********************************************************************
  1513. // 
  1514. // CloseIDBCreateCommand
  1515. // 
  1516. // Purpose:
  1517. // 
  1518. //     Go through all open PROVIDER's (IDBCreateCommand(s) and ICommand(s)) 
  1519. //     and close them one by one.
  1520. //
  1521. // Parameters:
  1522. //
  1523. // Return Value:
  1524. // 
  1525. // Function Calls:
  1526. //     Function                    Location
  1527. // 
  1528. //     IDBCreateCommand::Release   provider's Command object
  1529. //     
  1530. // Comments:      
  1531. // 
  1532. // 
  1533. //**********************************************************************
  1534. BOOL FAR PASCAL CloseIDBCreateCommand()
  1535. {
  1536.     ULONG                 nIndex;                    // Index
  1537.     ULONG                nCount;                    // # of PROVIDER(s)
  1538.     char                szBuffer[MAXBUFLEN+1];    // String Buffer
  1539.     HWND                hWndChild;                // MDI Child Window
  1540.     IDBCreateCommand*     pIDBCreate1;            // IDBCreateCommand Object #1
  1541.     IDBCreateCommand*     pIDBCreate2;            // IDBCreateCommand Object #2
  1542.  
  1543.     // Get count of connected PROVIDER(s) from the PROVIDER(s) combobox on the toolbar
  1544.     if (!(nCount = (int)SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0)))
  1545.         return (TRUE);
  1546.  
  1547.     // Go through all available MDI child windows and for each PROVIDER,
  1548.     // find the matching MDI child window and ask it for closure, thereby
  1549.     // freeing the associated ICommand (see CloseICommandWindow). Once all
  1550.     // associated ICommand(s) are freed, free the PROVIDER
  1551.     for (nIndex = 0; nIndex < nCount; nIndex++)
  1552.     {       
  1553.         // Scan current indexed PROVIDER from PROVIDER(s) combobox
  1554.         SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nIndex, (LPARAM)(LPSTR)szBuffer);
  1555.         sscanf(szBuffer, SCANSESSION_FORMAT, &pIDBCreate1);
  1556.         
  1557.         // Search through the list of MDI Child Windows
  1558.         for(hWndChild = GetWindow(hWndMDIClient, GW_CHILD); hWndChild; )
  1559.         {
  1560.             // Store the next child, before destroying the current
  1561.             HWND hWndTemp = GetWindow(hWndChild, GW_HWNDNEXT);
  1562.         
  1563.             // Ignore non MDI child windows
  1564.             GetClassName(hWndChild, szBuffer, MAXBUFLEN);
  1565.             if (!strcmp(szBuffer, OLEDBMDICLASS))
  1566.             {
  1567.                 GetWindowText(hWndChild, szBuffer, MAXBUFLEN);
  1568.                 sscanf(szBuffer, SCANSESSION_TITLEFORMAT, &pIDBCreate2);
  1569.                 if (pIDBCreate1 == pIDBCreate2)
  1570.                 {
  1571.                     // Destroy the window and restart search
  1572.                     SendMessage(hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChild, 0);
  1573.                     hWndTemp = GetWindow(hWndMDIClient, GW_CHILD);
  1574.                 }
  1575.             }
  1576.             hWndChild = hWndTemp;
  1577.         }
  1578.  
  1579.         // Call IDBCreateCommand->Release() 
  1580.         // to free the current IDBCreateCommand resource
  1581.         if( pIDBCreate1 )
  1582.             pIDBCreate1->Release();
  1583.     }
  1584.     
  1585.     // Reset the PROVIDER(s) combobox display and display all connections
  1586.     // closed message. Return success to let application exit.
  1587.     SendMessage(hWndCrsrList, CB_RESETCONTENT, 0, 0);
  1588.     MessageBox(hWndFrame, CLOSEALLSESSION, LOGOUTINFO,    MB_OK | MB_ICONINFORMATION);
  1589.     return (TRUE);
  1590. }
  1591.  
  1592. /*
  1593.     FUNCTION: FreeEnvironment()
  1594.     COMMENTS: Free the OLE environment.
  1595. */
  1596. HRESULT FreeEnvironment()
  1597. {
  1598.     IErrorInfo    *pIErrorInfo;    //IErrorInfo
  1599.  
  1600.     // Release the task memory allocator
  1601.     if( g_pIMalloc )
  1602.         g_pIMalloc->Release();
  1603.  
  1604.     // Release any remaining error objects.  This is idempotent.
  1605.     // Otherwise the provider might have an outstanding global-object count.
  1606.     GetErrorInfo( 0, &pIErrorInfo );
  1607.     if (pIErrorInfo)
  1608.         pIErrorInfo->Release();
  1609.  
  1610.     // Free the error queues
  1611.     SetErrorInfo(0,NULL);
  1612.  
  1613.     // Uninitialize OLE
  1614.     CoUninitialize();
  1615.     return S_OK;
  1616. }
  1617.  
  1618.  
  1619. //**********************************************************************
  1620. // 
  1621. // ExecuteCommand
  1622. // 
  1623. // Purpose:
  1624. // 
  1625. //    Executes the query command that was previously set on the Command object,
  1626. //    and returns a first interface pointer on the resulting Rowset object.
  1627. // 
  1628. // Parameters:
  1629. //       IOpenRowset*    pIOpenRowset    - interface pointer to data provider's
  1630. //                                      IOpenRowset
  1631. //       ICommand*        pICommand       - interface pointer on data provider's
  1632. //                                      Command object
  1633. //       LPWSTR        wszBuffer        - SQL-style query string to be sent
  1634. //                                      to the Command object or table/file name to
  1635. //                                      be sent to IOpenRowset
  1636. //       IRowset**        ppIRowset_out   - out pointer through which to return 
  1637. //                                      interface pointer on provider's
  1638. //                                      Rowset object
  1639. // 
  1640. // Return Value:
  1641. //     S_OK        - Success
  1642. //     E_*         - Failure
  1643. // 
  1644. // Function Calls:
  1645. //     Function                    Location
  1646. //     
  1647. //     ICommand::Execute           provider's Command object
  1648. //     IMalloc::Free               OLE task memory allocator
  1649. //     
  1650. // 
  1651. //     assert                      c runtime
  1652. // 
  1653. // 
  1654. //     
  1655. // Comments:      
  1656. // 
  1657. //     The interface pointer returned through ppIRowset_out has been AddRef'ed, 
  1658. //     it must be Release'd later by the caller.
  1659. //
  1660. //**********************************************************************
  1661. HRESULT ExecuteCommand(
  1662.     IUnknown*    pIUnknown,        // Session object
  1663.     ICommand*    pICommand,        // Command object
  1664.     LPWSTR         wszBuffer,        // SQL String (WCHAR) or Table Name
  1665.     IRowset**    ppIRowset_out
  1666.     )
  1667. {
  1668.     ICommandText*        pICommandText = NULL;    // ICommandText Object
  1669.     IOpenRowset*        pIOpenRowset = NULL;
  1670.     DBID                TableID;                // Table ID
  1671.     HRESULT                hr = S_OK;                // HRESULT
  1672.  
  1673.     // Asserts
  1674.     assert(ppIRowset_out != NULL);
  1675.     assert(wszBuffer != NULL);
  1676.  
  1677.     memset(&TableID, 0, sizeof(DBID));
  1678.  
  1679.     // If no command object use IOpenRowset
  1680.     if (NULL == pICommand)
  1681.     {
  1682.         // if no Command object support, attempt to get the IOpenRowset interface
  1683.         if( FAILED(hr = pIUnknown->QueryInterface(IID_IOpenRowset, (void**)&pIOpenRowset)) )
  1684.         {
  1685.             GetDetailedErrorInfo(hr, pIUnknown, IID_IUnknown, "QI for IOpenRowset FAILED!!");
  1686.             goto error;
  1687.         }
  1688.         // Pass in table/file name
  1689.         TableID.eKind = DBKIND_NAME;
  1690.  
  1691.         TableID.uName.pwszName = wszBuffer;
  1692.  
  1693.         // From IOpenRowset, get a rowset object
  1694.         if( FAILED(hr = pIOpenRowset->OpenRowset(
  1695.                                 NULL,                            // pUnkOuter
  1696.                                 &TableID,                        // pTableID
  1697.                                 NULL,                            // pIndexID
  1698.                                 IID_IRowset,                    // refiid
  1699.                                 0,                                // cProperties
  1700.                                 NULL,                            // rgProperties
  1701.                                  (IUnknown**)ppIRowset_out)) )          // IRowset pointer
  1702.         {
  1703.              GetDetailedErrorInfo(hr, pIOpenRowset, IID_IOpenRowset, "IOpenRowset->OpenRowset FAILED!!");
  1704.             goto error;
  1705.         }
  1706.     }
  1707.     else
  1708.     {
  1709.         // QueryInterface for ICommandText::SetCommandText
  1710.         if( SUCCEEDED(hr = pICommand->QueryInterface(IID_ICommandText,(LPVOID*)&pICommandText)) )
  1711.         {
  1712.             // Tell the command object to copy this command text
  1713.             // The command object will then use this query when we call ICommand::Execute
  1714.             if( FAILED(hr = pICommandText->SetCommandText(DBGUID_DBSQL, wszBuffer)) )
  1715.             {
  1716.                 GetDetailedErrorInfo(hr, pICommandText, IID_ICommandText, "ICommandText->SetCommandText FAILED!!");
  1717.                 goto error;
  1718.             }
  1719.         }
  1720.  
  1721.         // From the command object, get a rowset object by executing command
  1722.         if( FAILED(hr = pICommand->Execute(
  1723.                             NULL,                            // pUnkOuter
  1724.                             IID_IRowset,                    // refiid
  1725.                             NULL,                            // disp parms
  1726.                             NULL,                            // rows affected
  1727.                              (IUnknown**)ppIRowset_out)) )      // IRowset pointer
  1728.         {
  1729.             GetDetailedErrorInfo(hr, pICommand, IID_ICommand, "ICommand->Execute FAILED!!");
  1730.             goto error;
  1731.         }
  1732.     }
  1733.  
  1734.     // NO Rowset Returning Statement
  1735.     if( !*ppIRowset_out )
  1736.         hr = ResultFromScode(S_FALSE);
  1737. error:
  1738.     if( pICommandText )
  1739.         pICommandText->Release();
  1740.     if( pIOpenRowset )
  1741.         pIOpenRowset->Release();
  1742.  
  1743.     if( FAILED(hr) )
  1744.         *ppIRowset_out = NULL;
  1745.  
  1746.     return hr;    
  1747. }
  1748.  
  1749. //**********************************************************************
  1750. // 
  1751. // GetDataFromRowset
  1752. // 
  1753. // Purpose:
  1754. // 
  1755. //     Pulls the data from a Rowset object.
  1756. //     
  1757. // Parameters:
  1758. // 
  1759. //     IRowset*    pIRowset    -  interface pointer on data provider's
  1760. //                             Rowset object
  1761. // 
  1762. // Return Value:
  1763. // 
  1764. //     S_OK        - Success
  1765. //     E_*         - Failure
  1766. // 
  1767. // Function Calls:
  1768. //     Function                    Location
  1769. // 
  1770. //       IRowset::QueryInterface       Clients Rowset pointer
  1771. //     SetupBindings               query.cpp
  1772. //     CreateAccessor              query.cpp
  1773. //     GetData                     query.cpp
  1774. //     CleanupRowset               query.cpp
  1775. // 
  1776. //     IMalloc::Free               OLE task memory allocator
  1777. // 
  1778. //     assert                      c runtime
  1779. // 
  1780. // Comments:      
  1781. // 
  1782. //     At a high level, a consumer pulls the data from a Rowset object by:
  1783. //     
  1784. //     1. getting metadata for the Rowset's columns
  1785. //     2. using that metadata, along with the consumer's own knowledge of
  1786. //        how it wants to recieve the data, to create bindings. Bindings
  1787. //        represent how the actual data in the Rowset's columns is
  1788. //        actually transferred to the consumer's buffer.
  1789. //     3. pass the bindings to the Rowset, and get in return an accessor
  1790. //        handle that represents that particular set of bindings   
  1791. //     4. get the actual data
  1792. //     5. clean up the rowset (at a minumum, release the accessor) 
  1793. //     
  1794. //     GetDataFromRowset performs these steps by calling GetColumnsInfo,
  1795. //     SetupBindings, CreateAccessor, GetData, and CleanupRowset
  1796. //       
  1797. //**********************************************************************
  1798. HRESULT GetDataFromRowset(
  1799.     IRowset*    pIRowset
  1800.     )
  1801. {
  1802.     char                szBuffer[MAXBUFLEN+1];        // String Buffer
  1803.     HWND                hList;                        // Result Listbox Handle
  1804.     DWORD                 dwText;                        // Tab Stop for Listbox
  1805.     unsigned short int    nCount;                        // Index
  1806.     signed short int    swColLength = MAXDATALEN;    // Column Data Length
  1807.     int                    cch;                        // Count of characters
  1808.     HRESULT                hr = S_OK;                            // HRESULTS
  1809.     ULONG                cCol;                        // # of Columns in Rowset
  1810.     DBCOLUMNINFO*        pColumnInfo;                // Array of DBCOLUMNINFO
  1811.     WCHAR*                pStringsBuffer;                // Storage for strings
  1812.  
  1813.     // BINDINGS
  1814.     ULONG                 cbMaxRowSize;        // buffer size for 1 row's data
  1815.     ULONG                 cBind;
  1816.     DBBINDING            rgBind[MAX_COL];
  1817.     HCURSOR                hOldCursor = NULL;
  1818.  
  1819.     // ACCESSORS
  1820.     HACCESSOR            hAccessor        = NULL;
  1821.  
  1822.     // Asserts
  1823.     assert(pIRowset   != NULL);
  1824.     assert(g_pIMalloc != NULL);
  1825.     
  1826.     // Change cursor shape to hour glass
  1827.     hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT));
  1828.     
  1829.     // Get the Columns Info
  1830.     GetColumnsInfo( pIRowset, &cCol, &pColumnInfo, &pStringsBuffer);
  1831.  
  1832.     // Call GetColumnsInfo to calculate the number of columns in
  1833.     // the result set, if more than the MAX_COL (the array boundary)
  1834.     // limit the number to MAX_COL and display truncation warning.
  1835.     // if it is 0, the statement probably was a non-SELECT simply return
  1836.     if (cCol >= MAX_COL)
  1837.     {
  1838.         cCol = MAX_COL;
  1839.         wsprintf(szDispBuffer, COLTRUNC_WARNG, MAX_COL);
  1840.         MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION);
  1841.     }
  1842.     else if (cCol == 0)
  1843.     {
  1844.         goto error;
  1845.     }
  1846.  
  1847.     // Reset the display in the list box. Set tabstops to display
  1848.     // multiple columns in the list box separated by tabs.
  1849.     hList = GetDlgItem((HWND)GetWindowLong(hWndActiveChild, GWLAPP_HDLG), IDLIST_RSLT);
  1850.  
  1851.     SendMessage(hList, LB_RESETCONTENT, 0, 0);
  1852.     SendMessage(hList, WM_SETREDRAW, FALSE, 0);
  1853.     dwText = LISTTABSTOP;
  1854.     SendMessage(hList, LB_SETTABSTOPS, (WPARAM)1, (LPARAM)(LPINT)&dwText);
  1855.  
  1856.     // Display a description of each column in the result set. 
  1857.     // Store the column name in the display buffer and make it
  1858.     // the first entry in the results list box of the MDI child window.
  1859.     for(nCount=0, szDispBuffer[0]='\0'; nCount < cCol; nCount++)
  1860.     {
  1861.         if (pColumnInfo[nCount].pwszName)
  1862.         {
  1863.             cch = WideCharToMultiByte(CP_ACP, 0, pColumnInfo[nCount].pwszName, -1, szBuffer, MAXBUFLEN+1, NULL, NULL);
  1864.  
  1865.             // Truncate if needed.
  1866.             // We should use GetTextExtents to determine width, but that's too complicated for now.
  1867.             szBuffer[MAXCOLNAMELEN] = '\0';
  1868.  
  1869.             // Might be empty string for column name.
  1870.             if (cch)
  1871.                 strcat(szDispBuffer, szBuffer);
  1872.             else
  1873.                 strcat(szDispBuffer, "<EMPTY STRING>");
  1874.         }
  1875.         else
  1876.         {
  1877.             // Missing the column name; it is unknown.
  1878.             strcat(szDispBuffer, "<NULL STRING>");
  1879.         }
  1880.  
  1881.         dwText = strlen(szDispBuffer);
  1882.         szDispBuffer[dwText++] = '\t';
  1883.         szDispBuffer[dwText] = '\0';
  1884.     }
  1885.  
  1886.     // NULL Terminate the Display Buffer
  1887.     if (*szDispBuffer)
  1888.         szDispBuffer[strlen(szDispBuffer)-1]='\0';
  1889.     
  1890.     // ADD the Column Info to the Screen
  1891.     SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szDispBuffer);
  1892.  
  1893.     // SetUp Bindings
  1894.     if( FAILED(hr = SetupBindings( cCol, pColumnInfo, rgBind, &cBind, &cbMaxRowSize)) )
  1895.         goto error;
  1896.     
  1897.     // Create the Accessor
  1898.     if( FAILED(hr = CreateAccessor( pIRowset, rgBind, cBind, &hAccessor)) )
  1899.         goto error;
  1900.  
  1901.     // GetData
  1902.     if( FAILED(hr = GetData( pIRowset, cbMaxRowSize, hAccessor, rgBind, cBind, pColumnInfo, 
  1903.         cCol, hList, dwText, LB_ADDSTRING)) )
  1904.         goto error;
  1905.  
  1906. error:    
  1907.     // restore the cursor to default value
  1908.     SetCursor(hOldCursor);
  1909.   
  1910.     // Release the IColumnsInfo Object
  1911.     if( pColumnInfo )
  1912.         g_pIMalloc->Free( pColumnInfo );
  1913.     if( pStringsBuffer )
  1914.         g_pIMalloc->Free( pStringsBuffer );            
  1915.         
  1916.     // Clean-up the Rowset
  1917.     CleanupRowset( pIRowset, hAccessor );
  1918.  
  1919.     return hr;    
  1920. }
  1921.  
  1922.  
  1923. //**********************************************************************
  1924. // 
  1925. // GetColumnsInfo
  1926. // 
  1927. // Purpose:
  1928. // 
  1929. //     Get the Columns metadata back for the provider to setup the bundings. 
  1930. //     
  1931. // Parameters:
  1932. //
  1933. //    IRowset*        pIRowset            - IRowset pointer to QI off of
  1934. //     ULONG             cCol                - number of columns in metadata
  1935. //     DBCOLUMNINFO*    pColumnInfo         - pointer to column metadata
  1936. //     WCHAR*            pStringsBuffer      - pointer through which to return
  1937. //                                        an array of string data, one
  1938. //                                        structure per column bound
  1939. // 
  1940. // Return Value:
  1941. //     S_OK         - Success
  1942. //     E_*          - Failure
  1943. // 
  1944. // Function Calls:
  1945. //     Function                    Location
  1946. // 
  1947. //     assert                      c runtime
  1948. //     IRowset::QueryInterface     provider's Rowset object
  1949. //     IColumnsInfo::GetColumnInfo provider's ColumnInfo object
  1950. //     IColumnsInfo::Release       provider's ColumnInfo object
  1951. // 
  1952. //     
  1953. // Comments:      
  1954. // 
  1955. // 
  1956. //**********************************************************************
  1957. HRESULT GetColumnsInfo
  1958.     (
  1959.     IRowset*        pIRowset,
  1960.     ULONG*             pcCol,
  1961.     DBCOLUMNINFO**    ppColumnInfo,
  1962.     WCHAR**            ppStringsBuffer
  1963.     )
  1964. {
  1965.  
  1966.     HRESULT                hr=NOERROR;                    // HRESULTS
  1967.     IColumnsInfo*         pIColumnsInfo = NULL;        // IColumnsInfo Object
  1968.  
  1969.     // QI for IColumnsInfo Object
  1970.     if( FAILED(hr = pIRowset->QueryInterface( IID_IColumnsInfo, (void **) &pIColumnsInfo)) )
  1971.     {
  1972.         GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "QI for IColumnsInfo FAILED!!");
  1973.         goto error;
  1974.     }
  1975.     
  1976.     // Get column information from the command object via IColumnsInfo::GetColumnsInfo 
  1977.     if( FAILED(hr = pIColumnsInfo->GetColumnInfo( pcCol, ppColumnInfo, ppStringsBuffer)) )
  1978.     {
  1979.         GetDetailedErrorInfo(hr, pIColumnsInfo, IID_IColumnsInfo, "IColumnsInfo->GetColumnsInfo FAILED!!");
  1980.         goto error;
  1981.     }
  1982.  
  1983. error:
  1984.     // Release the IColumnsInfo Object
  1985.     if( pIColumnsInfo )
  1986.         pIColumnsInfo->Release();
  1987.     return hr;
  1988.  
  1989. }
  1990.  
  1991. //**********************************************************************
  1992. // 
  1993. // SetupBindings
  1994. // 
  1995. // Purpose:
  1996. // 
  1997. //     Creates bindings that map the data in the rowset's columns to 
  1998. //     slots in the consumer's data buffer.
  1999. //     
  2000. // Parameters:
  2001. //
  2002. //     ULONG             cCol                - number of columns in rowset to bind
  2003. //     DBCOLUMNINFO*    pColumnInfo         - pointer to column metadata
  2004. //     DBBINDING*        rgBind_out          - out pointer through which to return
  2005. //                                        an array of binding structures, one
  2006. //                                        structure per column bound
  2007. //     ULONG*            pcBind_out          - out pointer through which to return   
  2008. //                                        the number of columns bound (number
  2009. //                                        of valid elements in rgBind_out)              
  2010. //     ULONG*            pcMaxRowSize_out    - out pointer through which to return
  2011. //                                        the buffer size necessary to hold
  2012. //                                        the largest row data
  2013. // 
  2014. // Return Value:
  2015. //     S_OK         - Success
  2016. //     E_*          - Failure
  2017. // 
  2018. // Function Calls:
  2019. //     Function                    Location
  2020. // 
  2021. //     assert                      c runtime
  2022. // 
  2023. //     
  2024. // Comments:      
  2025. // 
  2026. // 
  2027. //**********************************************************************
  2028. HRESULT SetupBindings
  2029.     (
  2030.     ULONG             cCol,
  2031.     DBCOLUMNINFO*    pColumnInfo,
  2032.     DBBINDING*        rgBind_out,
  2033.     ULONG*            pcBind_out,
  2034.     ULONG*            pcMaxRowSize_out
  2035.     )
  2036. {
  2037.     #define DEFAULT_CBMAXLENGTH 80    // cbMaxLength for binding
  2038.     ULONG dwOffset;                // Length of a Row
  2039.     ULONG iCol;                    // Column Count
  2040.     ULONG iBind;                // Binding Index
  2041.     
  2042.     // Asserts
  2043.     assert(pColumnInfo        != NULL);
  2044.     assert(rgBind_out         != NULL);
  2045.     assert(pcBind_out         != NULL);
  2046.     assert(pcMaxRowSize_out != NULL);
  2047.  
  2048.        // Create bindings.
  2049.     // Bind everything as a string just to keep things simple.
  2050.     dwOffset = 0;
  2051.     iBind=0;
  2052.     for (iCol=0; iCol < cCol; iCol++)
  2053.     {
  2054.         // Binding Structure
  2055.         rgBind_out[iBind].dwPart    = DBPART_VALUE | DBPART_LENGTH |
  2056.                                       DBPART_STATUS;
  2057.         rgBind_out[iBind].eParamIO  = DBPARAMIO_NOTPARAM;
  2058.         rgBind_out[iBind].iOrdinal    = pColumnInfo[iCol].iOrdinal;
  2059.         rgBind_out[iBind].wType     = DBTYPE_WSTR;
  2060.         rgBind_out[iBind].pTypeInfo = NULL;
  2061.         rgBind_out[iBind].obValue   = dwOffset + offsetof(COLUMNDATA,bData);
  2062.         rgBind_out[iBind].obLength  = dwOffset + offsetof(COLUMNDATA,dwLength);
  2063.         rgBind_out[iBind].obStatus  = dwOffset + offsetof(COLUMNDATA,wStatus);
  2064.  
  2065.         // If columns information is a STR, double buffer and 
  2066.         // add space for terminator
  2067.         if( ((pColumnInfo[iCol].wType == DBTYPE_STR) ||
  2068.              (pColumnInfo[iCol].wType == DBTYPE_WSTR)) && 
  2069.             (pColumnInfo[iCol].ulColumnSize != 0xffffffff) )
  2070.             rgBind_out[iBind].cbMaxLen = (pColumnInfo[iCol].ulColumnSize + sizeof(CHAR)) * 2;
  2071.         else
  2072.             rgBind_out[iBind].cbMaxLen = DEFAULT_CBMAXLENGTH;
  2073.         rgBind_out[iBind].pObject    = NULL;
  2074.         rgBind_out[iBind].pBindExt    = NULL;
  2075.         rgBind_out[iBind].dwFlags    = 0;
  2076.         rgBind_out[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  2077.         rgBind_out[iBind].bPrecision = 0;
  2078.         rgBind_out[iBind].bScale    = 0;
  2079.         
  2080.         // LONG DATA hack 
  2081.         if(rgBind_out[iBind].cbMaxLen > 1000)
  2082.             rgBind_out[iBind].cbMaxLen = 1000;
  2083.  
  2084.         dwOffset += rgBind_out[iBind].cbMaxLen + offsetof( COLUMNDATA, bData );
  2085.         dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  2086.         iBind++;
  2087.     }  
  2088.  
  2089.     // Return Values    
  2090.     *pcBind_out       = iBind;
  2091.     *pcMaxRowSize_out = dwOffset;
  2092.  
  2093.     return S_OK;
  2094. }
  2095.  
  2096.  
  2097.  
  2098. //**********************************************************************
  2099. // 
  2100. // CreateAccessor
  2101. // 
  2102. // Purpose:
  2103. //
  2104. //     Passes a set of bindings to the data provider and recieves in return
  2105. //     an accessor handle that represents those bindings. 
  2106. //      
  2107. // Parameters:
  2108. //     IRowset*    pIRowset        - interface pointer on data provider's Rowset
  2109. //                                object
  2110. //     DBBINDING*    rgBind          - array of binding structures
  2111. //     ULONG        cBind           - number of binding structures in rgBind
  2112. //     HACCESSOR*    phAccessor_out  - out pointer through which to return an 
  2113. //                                accessor handle that represents all the bindings
  2114. //                                in rgBind
  2115. // 
  2116. // Return Value:
  2117. //     S_OK        - Success
  2118. //     E_*         - Failure
  2119. // 
  2120. // Function Calls:
  2121. //     Function                    Location
  2122. // 
  2123. //     IRowset::QueryInterface     provider's Rowset object
  2124. //     IAccessor::CreateAccessor   provider's Rowset object
  2125. //     IAccessor::Release          provider's Rowset object
  2126. // 
  2127. //     assert                      c runtime
  2128. //     
  2129. // Comments:      
  2130. // 
  2131. // 
  2132. //**********************************************************************
  2133. HRESULT CreateAccessor
  2134.     (
  2135.     IRowset*    pIRowset,
  2136.     DBBINDING*    rgBind,
  2137.     ULONG        cBind,
  2138.     HACCESSOR*    phAccessor_out 
  2139.     )
  2140. {
  2141.     IAccessor*    pIAccessor = NULL;
  2142.     HRESULT     hr;
  2143.  
  2144.     // Asserts
  2145.     assert(pIRowset       != NULL);
  2146.     assert(rgBind           != NULL);
  2147.     assert(phAccessor_out != NULL);
  2148.  
  2149.       // Get an accessor for our bindings from the rowset, via IAccessor 
  2150.     if( FAILED(hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor)) )
  2151.     {
  2152.         GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "QI for IAccessor FAILED!!");
  2153.         goto error;
  2154.     }
  2155.  
  2156.     if( FAILED(hr = pIAccessor->CreateAccessor(
  2157.                         DBACCESSOR_ROWDATA, 
  2158.                         cBind, 
  2159.                         rgBind, 
  2160.                         0, 
  2161.                         phAccessor_out,
  2162.                         NULL)) )
  2163.     {
  2164.         GetDetailedErrorInfo(hr, pIAccessor, IID_IAccessor, "IAccessor->CreateAccessor FAILED!!");
  2165.         goto error;
  2166.     }
  2167.  
  2168.     hr = S_OK;    
  2169.  
  2170. error:
  2171.     if (pIAccessor)
  2172.         pIAccessor->Release();
  2173.  
  2174.     if( FAILED(hr) )
  2175.         *phAccessor_out = NULL;
  2176.                 
  2177.     return hr;    
  2178. }
  2179.  
  2180.  
  2181. //**********************************************************************
  2182. // 
  2183. // GetData
  2184. // 
  2185. // Purpose:
  2186. // 
  2187. //     Reads the data from a rowset.
  2188. // 
  2189. // Parameters:
  2190. //
  2191. //        IRowset*     pIRowset           - interface pointer on data provider's
  2192. //                                    Rowset object
  2193. //        ULONG        cMaxRowSize        - size of buffer needed to hold the data
  2194. //                                    for the largest row
  2195. //     HACCESSOR hAccessor          - accessor handle representing the set
  2196. //                                    of desired bindings
  2197. //     DBBINDING*        rgBind          - needed only for pretty printing    
  2198. //     ULONG            cBind          - for pretty printing  
  2199. //     DBCOLUMNINFO*    pColumnInfo - for pretty printing  
  2200. //     ULONG            cCol        - for pretty printing  
  2201. // 
  2202. // 
  2203. // Return Value:
  2204. //     S_OK        - Success
  2205. //     E_*         - Failure
  2206. // 
  2207. // Function Calls:
  2208. //     Function                    Location
  2209. // 
  2210. //     IRowset::GetNextRows        provider's Rowset object
  2211. //     IRowset::GetData            provider's Rowset object
  2212. //     IRowset::ReleaseRows        provider's Rowset object
  2213. // 
  2214. // 
  2215. //     malloc, free                c runtime
  2216. //     assert                      c runtime
  2217. // 
  2218. // 
  2219. //     
  2220. // Comments:      
  2221. //
  2222. //     GetData reads all the rows in the rowset, sequentially.
  2223. //  
  2224. // 
  2225. //**********************************************************************
  2226. HRESULT GetData
  2227.     (
  2228.     IRowset*        pIRowset,
  2229.     ULONG           cMaxRowSize,
  2230.     HACCESSOR       hAccessor,
  2231.     DBBINDING*        rgBind,            
  2232.     ULONG            cBind,            
  2233.     DBCOLUMNINFO*    pColumnInfo,  
  2234.     ULONG            cCol,
  2235.     HWND            hList,
  2236.     DWORD            dwText,
  2237.     DWORD            addString
  2238.     )
  2239. {
  2240.     #define NUMROWS_CHUNK       20    // Number of Rows to Grab at a Time
  2241.  
  2242.     ULONG     cRowsObtained;            // Number of rows obtained
  2243.     ULONG    iRow;                    // Row Count
  2244.     BYTE*    pRowData = NULL;        // Memory for Data
  2245.     HROW     rghRows[NUMROWS_CHUNK];    // Row Handles
  2246.     HROW*    pRows = &rghRows[0];    // Pointer to the Row Handles
  2247.     ULONG    cMaxColWidth = 0;          // Needed for Output
  2248.     HRESULT hr;                        // HRESULT
  2249.  
  2250.     // Asserts
  2251.     assert(pIRowset     != NULL);
  2252.     assert(rgBind         != NULL);
  2253.     assert(pColumnInfo  != NULL);
  2254.  
  2255.     // Create a buffer for row data, big enough to hold the biggest row
  2256.     pRowData = (BYTE *) malloc( cMaxRowSize );
  2257.     if (!pRowData)
  2258.         goto error;
  2259.  
  2260.     // Process all the rows, NUMROWS_CHUNK rows at a time
  2261.     while (1)
  2262.     {
  2263.         if( FAILED(hr = pIRowset->GetNextRows(
  2264.             0,                            // cbChapter
  2265.             0,                            // cRowsToSkip
  2266.             NUMROWS_CHUNK,                // cRowsDesired
  2267.             &cRowsObtained,                // cRowsObtained
  2268.             &pRows)) )                    // filled in w/ row handles
  2269.         {
  2270.             GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "IRowset->GetNextRows FAILED!!");
  2271.             goto error;
  2272.         }
  2273.  
  2274.         // All done, no more rows left to get
  2275.         if ( cRowsObtained == 0 )
  2276.             break;
  2277.  
  2278.         // Loop over rows obtained, getting data for each
  2279.         for ( iRow=0; iRow < cRowsObtained; iRow++ )
  2280.         {
  2281.             if( FAILED(hr = pIRowset->GetData(
  2282.                 rghRows[iRow],
  2283.                 hAccessor,
  2284.                 pRowData)) )
  2285.             {
  2286.                 GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "IRowset->GetData FAILED!!");
  2287.                 goto error;
  2288.             }
  2289.  
  2290.             
  2291.             // Print to the Screen
  2292.             DumpRow( rgBind, cBind, cMaxColWidth, pRowData, hList, dwText, addString );
  2293.  
  2294.             // See if you are over the limit of rows
  2295.             if ((iRow + 1) == MAX_ROW)
  2296.             {
  2297.                 wsprintf(szDispBuffer, ROWTRUNC_WARNG, MAX_ROW);
  2298.                 MessageBox(hWndFrame, szDispBuffer, TRUNCERR, MB_OK | MB_ICONINFORMATION);
  2299.                 break;
  2300.             }
  2301.  
  2302.         }
  2303.  
  2304.         // Release row handles
  2305.         if( FAILED(hr = pIRowset->ReleaseRows( cRowsObtained, rghRows, NULL, NULL, NULL)) )
  2306.         {
  2307.            GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "IRowset->ReleaseRows FAILED!!");
  2308.            goto error;
  2309.         }
  2310.  
  2311.     }    // end while
  2312.  
  2313.     hr = S_OK;
  2314. error:
  2315.     // Set the horizontal scroll extent in the list box and ask for repaint.
  2316.     SendMessage(hList, LB_SETHORIZONTALEXTENT, (WPARAM)(cBind*LISTHORZSCROLL+LISTHORZEXT), 0);
  2317.     SendMessage(hList, WM_SETREDRAW, TRUE, 0);
  2318.  
  2319.     if( cRowsObtained )
  2320.         pIRowset->ReleaseRows( cRowsObtained, rghRows, NULL, NULL, NULL);
  2321.     
  2322.     if( pRowData )
  2323.         free( pRowData );
  2324.                                 
  2325.     return hr;
  2326. }
  2327.  
  2328. //**********************************************************************
  2329. // 
  2330. // GetSchemaRowset
  2331. // 
  2332. // Purpose:
  2333. // 
  2334. //     Pulls the schema info out of the provider.
  2335. //     
  2336. // Parameters:
  2337. // 
  2338. //     GUID  rguidSchema        -  SchemaRowset IID
  2339. //
  2340. //
  2341. // Return Value:
  2342. // 
  2343. // Function Calls:
  2344. //     Function                              Location
  2345. // 
  2346. //       IDBCreateCommand::QueryInterface   QI
  2347. //       IDBSchemaRowset->GetRowset          Clients Rowset pointer
  2348. //     GetDataFromRowset                     query.cpp
  2349. // 
  2350. //     IMalloc::Free                         OLE task memory allocator
  2351. // 
  2352. //     assert                                c runtime
  2353. // 
  2354. // Comments:      
  2355. // 
  2356. //       
  2357. //**********************************************************************
  2358. void FAR PASCAL GetSchemaRowset(GUID rguidSchema)
  2359. {
  2360.     char                szBuffer[MAXBUFLEN+1];        // String Buffer
  2361.     HCURSOR                hOldCursor;                    // Default Cursor Handle
  2362.     IDBCreateCommand*     pIDBCreate          = NULL;    // IDBCreateCommand Object
  2363.     IDBSchemaRowset*    pIDBSchemaRowset = NULL;    // SchemaRowset Object
  2364.     ICommand*            pICommand         = NULL;    // Command Object
  2365.     IRowset*            pIRowset         = NULL;    // Rowset Object
  2366.     HRESULT                hr;                            // HRESULT
  2367.  
  2368.     // Check if there is an active window available
  2369.     if( !hWndActiveChild )
  2370.     {
  2371.         MessageBox( hWndFrame, 
  2372.                     ((SendMessage(hWndCrsrList, CB_GETCOUNT, 0, 0) <=0) ?
  2373.                     MAKECONNECT : OPENWINDOW ), 
  2374.                     NOCOMMANDERROR, MB_OK | MB_ICONHAND);
  2375.         return;
  2376.     }
  2377.  
  2378.     // Change cursor shape to hour glass
  2379.     hOldCursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT));
  2380.             
  2381.     // Scan hdbc, hstmt values
  2382.     GetWindowText(hWndActiveChild, (char*)szBuffer, MAXBUFLEN);
  2383.     sscanf(szBuffer, SCANSESSIONCOMMAND_FORMAT, &pIDBCreate, &pICommand);
  2384.     
  2385.     // QueryInterface for IDBSession::IDBSchemaRowset
  2386.     hr = pIDBCreate->QueryInterface( IID_IDBSchemaRowset,
  2387.                                     (LPVOID*)&pIDBSchemaRowset );
  2388.  
  2389.     if (FAILED(hr))
  2390.     {
  2391.         GetDetailedErrorInfo(hr, pIDBCreate, IID_IDBCreateCommand, "QI for IDBScemaRowset FAILED!!");
  2392.         goto error;
  2393.     }
  2394.     
  2395.     // Get a SchemaRowset back
  2396.     hr = pIDBSchemaRowset->GetRowset(
  2397.                             NULL,                        // punkOuter
  2398.                             rguidSchema,                // schema IID
  2399.                             0L,                            // # of restrictions
  2400.                             NULL,                        // array of restrictions
  2401.                             IID_IRowset,                // rowset interface
  2402.                             0L,                            // # of properties
  2403.                             NULL,                        // properties
  2404.                             (IUnknown**)&pIRowset);        // rowset pointer
  2405.  
  2406.     if (FAILED(hr))
  2407.     {
  2408.         GetDetailedErrorInfo(hr, pIDBSchemaRowset, IID_IDBSchemaRowset, "IDBSchemaRowset->GetRowset FAILED!!");
  2409.         goto error;
  2410.     }
  2411.  
  2412.     // Get Data from the IRowset Object
  2413.     hr = GetDataFromRowset( pIRowset );
  2414.  
  2415.     if (FAILED(hr))
  2416.     {
  2417. //        DumpErrorHResult( hr, (LPSTR)"GetDataFromRowset returned error!!" );
  2418.         goto error;
  2419.     }
  2420.  
  2421.     // Release Object
  2422.     pIDBSchemaRowset->Release();
  2423.     pIDBSchemaRowset = NULL;
  2424.     
  2425.     return;
  2426.  
  2427. error:    
  2428.     if( pIDBSchemaRowset )
  2429.         pIDBSchemaRowset->Release();
  2430.     
  2431.     return;
  2432. }
  2433.  
  2434.  
  2435. //**********************************************************************
  2436. // 
  2437. // CleanupRowset
  2438. // 
  2439. // Purpose:
  2440. //
  2441. //     Allows the rowset to perform any necessary cleanup.
  2442. //  
  2443. // Parameters:
  2444. //
  2445. //     IRowset*    pIRowset    - interface pointer on data provider's Rowset
  2446. //                            object
  2447. //     HACCESSOR     hAccessor   - accessor handle to release
  2448. // 
  2449. // Return Value:
  2450. //
  2451. //     S_OK        - Success
  2452. //     E_*         - Failure
  2453. //     
  2454. // Function Calls:
  2455. //     Function                    Location
  2456. // 
  2457. //     IRowset::QueryInterface     provider's Rowset object
  2458. //     IAccessor::ReleaseAccessor  provider's Rowset object
  2459. //     IAccessor::Release          provider's Rowset object
  2460. // 
  2461. //     assert                      c runtime
  2462. // 
  2463. //     
  2464. // Comments:      
  2465. //
  2466. //     In this sample, the only cleanup that the rowset needs to do is
  2467. //     release the accessor handle. 
  2468. // 
  2469. //**********************************************************************
  2470. HRESULT CleanupRowset
  2471.     (
  2472.     IRowset*    pIRowset,
  2473.     HACCESSOR     hAccessor
  2474.     )
  2475. {
  2476.     IAccessor*    pIAccessor = NULL;    // Pointer to an Accessor
  2477.     HRESULT        hr;                    // HRESULT
  2478.  
  2479.     // Assert    
  2480.     assert(pIRowset != NULL);
  2481.     
  2482.     if( hAccessor )
  2483.     {
  2484.         // Tell the rowset object it can release the accessor, via IAccessor
  2485.         hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor );
  2486.  
  2487.         if (FAILED(hr))
  2488.         {
  2489.             GetDetailedErrorInfo(hr, pIRowset, IID_IRowset, "QI for IAccessor FAILED!!");
  2490.             goto error;
  2491.         }
  2492.  
  2493.         hr = pIAccessor->ReleaseAccessor( hAccessor, NULL );
  2494.         if (FAILED(hr))
  2495.         {
  2496.             GetDetailedErrorInfo(hr, pIAccessor, IID_IAccessor, "IAccessor->ReleaseAccessor FAILED!!");
  2497.             goto error;
  2498.         }
  2499.  
  2500.         pIAccessor->Release();
  2501.         pIAccessor = NULL;
  2502.     }
  2503.  
  2504.     pIRowset->Release();
  2505.     pIRowset = NULL;
  2506.  
  2507.     return S_OK;
  2508.     
  2509. error:    
  2510.     if( pIAccessor )
  2511.         pIAccessor->Release();
  2512.     if( pIRowset )
  2513.         pIRowset->Release();
  2514.  
  2515.     return hr;    
  2516. }
  2517.  
  2518.  
  2519. //**********************************************************************
  2520. // 
  2521. // DumpRow
  2522. // 
  2523. // Purpose:
  2524. //
  2525. //     Display the row to the screen.
  2526. //  
  2527. // Parameters:
  2528. //
  2529. // 
  2530. // Return Value:
  2531. //
  2532. //     
  2533. // Function Calls:
  2534. //     Function                    Location
  2535. // 
  2536. //     assert                      c runtime
  2537. // 
  2538. //     
  2539. // Comments:      
  2540. //
  2541. // 
  2542. //**********************************************************************
  2543. void DumpRow
  2544.     (
  2545.     DBBINDING*     rgBind,
  2546.     ULONG        cBind,
  2547.     ULONG        cMaxColWidth,
  2548.     BYTE*         pData,
  2549.     HWND        hList,
  2550.     DWORD        dwText,
  2551.     DWORD        addString
  2552.     )
  2553. {
  2554.     ULONG         iBind;            // Binding Count
  2555.     COLUMNDATA*    pColumn;        // Data Structure
  2556.     int            cb;
  2557.     CHAR        szTempString[MAXDISPLAYSIZE+10];    // Temporary Display Buffer, used to check data length
  2558.  
  2559.     // Asserts
  2560.     assert(rgBind);
  2561.     assert( offsetof(COLUMNDATA, wStatus) == 0);    
  2562.     
  2563.     // Print each column we're bound to.
  2564.     for (iBind=0, szDispBuffer[0]='\0'; iBind < cBind; iBind++)
  2565.     {
  2566.         // Columns are bound differently; not so easy.
  2567.         // Print out to at least DEFAULT_CBMAXLENGTH width (pretty),
  2568.         // Limit to first dwLength characters.
  2569.         pColumn = (COLUMNDATA *) (pData + rgBind[iBind].obStatus);
  2570.         
  2571.         // Check Status for NULL / OK / CANTCONVERT.
  2572.         switch (pColumn->wStatus)
  2573.         {
  2574.             case DBSTATUS_S_ISNULL:
  2575.                 strcat(szDispBuffer, (LPSTR)"<NULL>");
  2576.                 break;
  2577.             case DBSTATUS_S_OK:
  2578.             case DBSTATUS_S_TRUNCATED:
  2579.                 // Truncate if needed.
  2580.                 // - calculate number of bytes needed
  2581.                 cb = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pColumn->bData, -1,
  2582.                             NULL, 0, NULL, NULL);
  2583.                 if( cb > MAXCOLNDATALENGTH )
  2584.                 {
  2585.                     cb = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pColumn->bData, -1,
  2586.                         szTempString, MAXCOLNDATALENGTH, NULL, NULL);
  2587.                     
  2588.                     szTempString[MAXCOLNDATALENGTH] = '\0';  
  2589.                     strcat(szTempString, "...");
  2590.                 }
  2591.                 else
  2592.                 {
  2593.                     cb = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pColumn->bData, -1,
  2594.                         szTempString, (MAXDISPLAYSIZE+1), NULL, NULL);
  2595.                 }
  2596.  
  2597.                 if(pColumn->wStatus == DBSTATUS_S_TRUNCATED)
  2598.                     strcat(szTempString, "...");
  2599.                 strcat(szDispBuffer,szTempString);
  2600.                 break;
  2601.  
  2602.             case DBSTATUS_E_CANTCONVERTVALUE:
  2603.                 strcat(szDispBuffer, "<can't convert value>");
  2604.                 break;
  2605.             default:
  2606.                 {
  2607.                 CHAR szChar[10] = "";
  2608.                 strcat(szDispBuffer, "<unknown status of ");
  2609.                 strcat(szDispBuffer, itoa(pColumn->wStatus, szChar, 10));
  2610.                 strcat(szDispBuffer, ">");
  2611.                 }
  2612.                 break;
  2613.         }
  2614.  
  2615.         dwText = strlen(szDispBuffer);
  2616.         szDispBuffer[dwText++] = '\t';
  2617.         szDispBuffer[dwText] = '\0';
  2618.     }
  2619.     // Take the last \t off the end
  2620.     szDispBuffer[--dwText] = '\0';
  2621.     SendMessage(hList, addString, 0, (LPARAM)(LPSTR)szDispBuffer);
  2622.  
  2623. }    
  2624.  
  2625. //**********************************************************************
  2626. // 
  2627. // GetDetailedErrorInfo
  2628. // 
  2629. // Purpose:
  2630. //
  2631. //    Reads error from the error collection and displays it in messageboxes
  2632. //  
  2633. // Parameters:
  2634. //
  2635. //     HRESULT        hr                    - OLE DB HRESULT
  2636. //     IUnknown    *  pBadObject       - Object that caused an error
  2637. //  GUID        IID_BadInterface    - Interface that contains method that caused the error
  2638. //     LPSTR         lpStrBuffer            - Title Bar text
  2639. //
  2640. // Return Value:
  2641. //     
  2642. // Comments:      
  2643. //     If any sort of failure is encountered the return values will be NULL
  2644. //   strings. Therefore no extended error info will be printed.
  2645. //**********************************************************************
  2646.  
  2647. HRESULT GetDetailedErrorInfo 
  2648.     (
  2649.     HRESULT        hresult, 
  2650.     IUnknown    *pBadObject,                  
  2651.     GUID        IID_BadIntereface,                 
  2652.     LPSTR        lpStrBuffer
  2653.     )
  2654. {
  2655.     IErrorInfo *        pErrorInfo = NULL; 
  2656.     IErrorInfo *        pErrorInfoRec = NULL;
  2657.     IErrorRecords *     pErrorRecords = NULL;
  2658.     ISupportErrorInfo * pSupportErrorInfo = NULL;
  2659.     HRESULT             hr = S_OK;
  2660.     ULONG               i,ulNumErrorRecs;
  2661.     BSTR                bstrDescriptionOfError = NULL;
  2662.     BSTR                bstrSourceOfError = NULL;
  2663.     CHAR                szBuffer [512];  //Error Info Buffer
  2664.    
  2665.     // Check to see if this interface posts error messages
  2666.     if( SUCCEEDED( pBadObject->QueryInterface(IID_ISupportErrorInfo, 
  2667.         (LPVOID FAR*)&pSupportErrorInfo)) ) 
  2668.     {
  2669.         if( pSupportErrorInfo->InterfaceSupportsErrorInfo(IID_BadIntereface) == S_OK )
  2670.         {
  2671.             //Get Error Object. Return if no object Exists
  2672.             if( !SUCCEEDED(hr = GetErrorInfo(0,&pErrorInfo)) )
  2673.                goto DisplayHResult;
  2674.  
  2675.             // If returned a NULL error Object, then just display HR
  2676.             if( pErrorInfo == NULL )
  2677.                 goto DisplayHResult;
  2678.  
  2679.             //Get the IErrorRecord interface and get the count of error recs.
  2680.             if( FAILED(hr = pErrorInfo->QueryInterface(IID_IErrorRecords,(LPVOID FAR*)&pErrorRecords)) )
  2681.                goto DisplayHResult;
  2682.  
  2683.             //Retrieve the number of Error Records
  2684.             if( FAILED(hr = pErrorRecords->GetRecordCount(&ulNumErrorRecs)) )
  2685.                goto DisplayHResult;
  2686.  
  2687.             //Go through and print messages
  2688.             for(i=0; i<ulNumErrorRecs; i++) 
  2689.             {
  2690.                 if( FAILED(hr = pErrorRecords->GetErrorInfo(i, GetUserDefaultLCID(), &pErrorInfoRec)) )
  2691.                     goto Exit;
  2692.                 if( FAILED(hr = pErrorInfoRec->GetDescription(&bstrDescriptionOfError)) )
  2693.                     goto Exit;
  2694.                 if( FAILED(hr = pErrorInfoRec->GetSource(&bstrSourceOfError)) )
  2695.                     goto Exit;
  2696.  
  2697.                 sprintf(szBuffer, "HResult of 0x%0x (%ld) returned\nError Source: %S\nError Description: %S\n", 
  2698.                     (long)hresult,(long)hresult, 
  2699.                     bstrSourceOfError ? bstrSourceOfError : L"No Source Description",
  2700.                     bstrDescriptionOfError ? bstrDescriptionOfError : L"No Error Description");
  2701.  
  2702.                 MessageBox( NULL, (LPCTSTR)szBuffer, lpStrBuffer, MB_OK);
  2703.  
  2704.                 if (pErrorInfoRec)                
  2705.                 {
  2706.                     pErrorInfoRec->Release();
  2707.                     pErrorInfoRec = NULL;
  2708.                 }
  2709.                 if( bstrSourceOfError )
  2710.                 {
  2711.                     SysFreeString(bstrSourceOfError);
  2712.                     bstrSourceOfError = NULL;
  2713.                 }
  2714.                 if( bstrDescriptionOfError )
  2715.                 {
  2716.                     SysFreeString(bstrDescriptionOfError);
  2717.                     bstrDescriptionOfError = NULL;
  2718.                 }
  2719.             }
  2720.             
  2721.             // if we've process all the records we can go to end
  2722.             goto Exit;
  2723.  
  2724.         } //S_OK
  2725.     } //if (SUCCEEDED)
  2726.  
  2727. DisplayHResult:
  2728.     // In some error cases we may not have extended error information and it still would be good to
  2729.     // post the error HRESULT
  2730.     sprintf(szBuffer, "HResult of 0x%0x (%ld) returned, no Extended Error Information posted or supported", 
  2731.         (long)hresult,(long)hresult);
  2732.     MessageBox( NULL, (LPCTSTR)szBuffer, lpStrBuffer, MB_OK);
  2733.  
  2734.  Exit : 
  2735.     if (pErrorInfo)
  2736.         pErrorInfo->Release();
  2737.     if (pErrorRecords)
  2738.         pErrorRecords->Release();
  2739.     if( pSupportErrorInfo )
  2740.         pSupportErrorInfo->Release();
  2741.     if( pErrorInfoRec )
  2742.         pErrorInfoRec->Release();
  2743.     if( bstrSourceOfError )
  2744.         SysFreeString(bstrSourceOfError);
  2745.     if( bstrDescriptionOfError )
  2746.         SysFreeString(bstrDescriptionOfError);
  2747.  
  2748.  return hr;
  2749. } //PrintErrorInfo
  2750.  
  2751.  
  2752. //**********************************************************************
  2753. // 
  2754. // DumpErrorHResult
  2755. // 
  2756. // Purpose:
  2757. //
  2758. //     Dump the OLE DB HRESULT in a Message Box with a text Title Bar.
  2759. //  
  2760. // Parameters:
  2761. //
  2762. //     HRESULT        hr            - OLE DB HRESULT
  2763. //
  2764. //     LPSTR         lpStrBuffer - Title Bar text
  2765. //
  2766. // 
  2767. // Return Value:
  2768. //
  2769. //     
  2770. // Function Calls:
  2771. //     Function                    Location
  2772. // 
  2773. //     assert                      c runtime
  2774. // 
  2775. //     
  2776. // Comments:      
  2777. //
  2778. // 
  2779. //**********************************************************************
  2780. void DumpErrorHResult( HRESULT hr,     LPSTR lpStrBuffer )
  2781. {
  2782.     LPVOID    lpMessageBuffer;
  2783.  
  2784.     if(0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  2785.                 FORMAT_MESSAGE_FROM_SYSTEM,
  2786.                 NULL,
  2787.                 hr,
  2788.                 GetUserDefaultLCID(),
  2789.                 (LPSTR)&lpMessageBuffer,
  2790.                 0,
  2791.                 NULL))
  2792.     {
  2793.         MessageBox( NULL, (LPCTSTR)lpMessageBuffer, lpStrBuffer, MB_OK);
  2794.         LocalFree(lpMessageBuffer);
  2795.     }
  2796.     else
  2797.     {
  2798.         lpMessageBuffer = LocalAlloc(LPTR, 256);
  2799.  
  2800.         if( lpMessageBuffer )
  2801.         {
  2802.             sprintf((LPSTR)lpMessageBuffer, "HResult of %ld returned", (long)hr);
  2803.             MessageBox( NULL, (LPCTSTR)lpMessageBuffer, lpStrBuffer, MB_OK);
  2804.             LocalFree(lpMessageBuffer);
  2805.         }
  2806.     }
  2807. }
  2808.  
  2809. //**********************************************************************
  2810. // 
  2811. // NewIOpenRowsetWindow
  2812. // 
  2813. // Purpose:
  2814. // 
  2815. //     Create a new ICommand Object on the current IDBCreateCommand.
  2816. //     
  2817. // Parameters:
  2818. // 
  2819. // Return Value:
  2820. // 
  2821. // Function Calls:
  2822. //     Function                         Location
  2823. // 
  2824. //       IDBCreateCommand::CreateCommand    provider's Command object
  2825. //     ICommand::Release                provider's Command object
  2826. //        
  2827. //     
  2828. // Comments:      
  2829. // 
  2830. // 
  2831. //**********************************************************************
  2832. void FAR PASCAL NewIOpenRowsetWindow()
  2833. {
  2834.     int                 nCurrenthdbc;            // Current PROVIDER
  2835.     char                szBuffer[MAXBUFLEN+1];    // String in PROVIDER ComboBox on Toolbar
  2836.     char                szProvName[MAXBUFLEN+1];// DSN String
  2837.     MDICREATESTRUCT        mcs;                    // MDI Child Window Create Struc
  2838.     
  2839.     IOpenRowset *         pIOpenRowset= NULL;        // IOpenRowset Object
  2840.  
  2841.         
  2842.     // check if there is PROVIDER selected in the Combo-Box
  2843.     if ((nCurrenthdbc = (int)SendMessage(hWndCrsrList, CB_GETCURSEL, 0, 0)) == CB_ERR)
  2844.     {
  2845.         MessageBox(hWndFrame, MAKECONNECT, NOSESSIONERROR, MB_OK | MB_ICONHAND);
  2846.         return;
  2847.     }
  2848.     
  2849.     // check if the number of windows exceeds MAXCHILDWNDS
  2850.     if (nChildCount >= MAXCHILDWNDS)
  2851.     {
  2852.         MessageBox(hWndFrame, MAXCHILDEXCEEDED, MAXCHLDERR, MB_OK | MB_ICONHAND);
  2853.         return;
  2854.     }
  2855.  
  2856.     // Scan PROVIDER string and IDBCreateCommand value from the combo-box
  2857.     SendMessage(hWndCrsrList, CB_GETLBTEXT, (WPARAM)nCurrenthdbc, (LPARAM)(LPSTR)szBuffer);
  2858.     
  2859.      sscanf(szBuffer, SCANPROVIDERSESSION_FORMAT, szProvName, &pIOpenRowset);
  2860.  
  2861.     // create a new MDI client window. maximized, if the previous is so.
  2862.     mcs.szClass = OLEDBMDICLASS;
  2863.     mcs.szTitle = UNTITLED;
  2864.     mcs.hOwner  = hAppInstance;
  2865.     mcs.style   = hWndActiveChild && IsZoomed(hWndActiveChild) ? WS_MAXIMIZE : 0;
  2866.     mcs.x = mcs.cx = mcs.y = mcs.cy = CW_USEDEFAULT;
  2867.     hWndActiveChild = (HWND)(UINT)SendMessage(hWndMDIClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mcs);
  2868.         
  2869.     // check if it was created, if it wasn't free up resource and flag warning
  2870.     if (!hWndActiveChild)
  2871.     {
  2872.         MessageBox(hWndFrame, CREATECHILDERR, EXECERROR, MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL);
  2873.         return;
  2874.     }
  2875.         
  2876.     // Display the Provider string, PROVIDER and IOpenRowset in the title
  2877.     // of newly created window. Increment the child window counter
  2878.     wsprintf(szBuffer, QUERY_STRING, pIOpenRowset);
  2879.         
  2880.     SendMessage(hWndStmtList, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  2881.     SendMessage(hWndStmtList, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)szBuffer);
  2882.     
  2883.     wsprintf(szBuffer, PROVIDER_SESSION_COMMAND_FORMAT, (LPSTR)szProvName, pIOpenRowset, NULL);
  2884.     
  2885.     SetWindowText(hWndActiveChild, szBuffer);
  2886.     nChildCount++;
  2887.     
  2888.     // Update the Command Combo-Box on the tool bar.
  2889.     ChangeCurrentICommand(hWndStmtList);
  2890. }
  2891.  
  2892.  
  2893.  
  2894.  
  2895.