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 / sampclnt / sampclnt.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-12  |  30.2 KB  |  1,134 lines

  1. //--------------------------------------------------------------------
  2. // Microsoft OLE DB Sample Consumer
  3. // (C) Copyright 1995 - 1998 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File name: SAMPCLNT.CPP
  6. //
  7. //      Implementation file for a simple OLE DB consumer.
  8. //      Dump\output routines for SAMPCLNT are in DUMP.CPP
  9. //      SAMPCLNT.H is the header file.
  10. //
  11. //      See OLE DB SDK Guide for information on building and running 
  12. //        this sample, as well as notes concerning the implementation of 
  13. //        a simple OLE DB consumer.
  14. //
  15. // Functions:
  16. //
  17. //      See SAMPCLNT.H for function prototypes
  18. //
  19. // 
  20. // SampClnt is structured to match the steps required for simple OLE DB data access:
  21. // 
  22. //     DoTests
  23. //         GetSampprovDataSource
  24. //      GetDBSessionFromDataSource
  25. //      GetRowsetFromDBSession
  26. //         GetDataFromRowset
  27. //             GetColumnsInfo
  28. //             SetupBindings
  29. //             CreateAccessor
  30. //             GetData
  31. //             CleanupRowset
  32. // 
  33.  
  34.  
  35.  
  36.  
  37. #define INITGUID
  38. #define DBINITCONSTANTS
  39. #include "sampclnt.h"
  40.  
  41.  
  42. IMalloc* g_pIMalloc = NULL;
  43. FILE*    g_fpLogFile = NULL;    // our log file
  44.  
  45.  
  46.  
  47.  
  48. //**********************************************************************
  49. // 
  50. // main
  51. // 
  52. // Purpose:
  53. //
  54. //     Entry point for this program.
  55. // 
  56. // Parameters:
  57. //
  58. //     none
  59. //     
  60. // Return Value:
  61. //
  62. //     none
  63. // 
  64. // Comments:      
  65. //
  66. //     Main does some initializing, then calls DoTests, then cleans up.
  67. //     All of the interesting action in this program happens in DoTests.
  68. // 
  69. //**********************************************************************
  70.  
  71.  
  72. void main()
  73. {
  74.     DWORD   dwVersion;
  75.     HRESULT hr;
  76.     time_t    ttime;
  77.     BOOL     fOleInitialized = FALSE;
  78.     char    ch;
  79.     
  80.       g_fpLogFile = fopen( "sampclnt.out", "at");
  81.     if (!g_fpLogFile)
  82.         {
  83.         DumpErrorMsg( "Warning: cannot open log file sampclnt.out\n" );
  84.         }
  85.   
  86.       time(&ttime);
  87.     
  88.     DumpStatusMsg( "\n-------------------------\n\n");
  89.     DumpStatusMsg( "running sampclnt.exe\n%s\n\n", ctime(&ttime) );
  90.  
  91.     dwVersion = OleBuildVersion();
  92.     if (HIWORD(dwVersion) != rmm)
  93.         {
  94.         DumpErrorMsg( "Error: OLE version mismatch. Build version %ld, current version %ld\n",
  95.             rmm, HIWORD(dwVersion) );
  96.         goto error;    
  97.         }
  98.  
  99.     hr = OleInitialize( NULL );
  100.     if (FAILED(hr))
  101.         {
  102.         DUMP_ERROR_LINENUMBER();
  103.         DumpErrorMsg("Error: OleInitialize failed\n");
  104.         goto error;
  105.         }
  106.     fOleInitialized = TRUE;
  107.      
  108.     hr = CoGetMalloc( MEMCTX_TASK, &g_pIMalloc );
  109.      if (FAILED(hr))
  110.         {
  111.         DUMP_ERROR_LINENUMBER();
  112.         DumpErrorMsg("Error: CoGetMalloc failed\n");
  113.         goto error;
  114.         }
  115.    
  116.     hr = DoTests();
  117.     if (FAILED(hr))
  118.         {
  119.         DUMP_ERROR_LINENUMBER();
  120.         DumpErrorHResult( hr, "DoTests");
  121.         goto error;
  122.         }
  123.     
  124.     g_pIMalloc->Release();
  125.     OleUninitialize();
  126.  
  127.     if (g_fpLogFile)
  128.         fclose(g_fpLogFile);
  129.  
  130.     /* Pause before we quit, in case user ran from an icon, so they can see our messages. */
  131.     printf("\n\n>>> Output has gone into 'sampclnt.out'.");
  132.     printf("\n>>> You may wish to use a wide-column editor to view this file.\n\n");
  133.     printf("<press any key to continue>");
  134.     ch = _getch();
  135.     return;
  136.     
  137. error:
  138.     if (g_pIMalloc)
  139.         g_pIMalloc->Release();    
  140.     if (fOleInitialized)
  141.         OleUninitialize();
  142.     if (g_fpLogFile)
  143.         fclose(g_fpLogFile);
  144.     
  145.     /* Pause before we quit, in case user ran from an icon, so they can see our messages. */
  146.     printf("\n\n>>> Output has gone into 'sampclnt.out'.");
  147.     printf("\n>>> You may wish to use a wide-column editor to view this file.\n\n");
  148.     printf("<press any key to continue>");
  149.     ch = _getch();
  150.  
  151.     return;    
  152. }    
  153.  
  154.  
  155.  
  156. //**********************************************************************
  157. //  
  158. //  DoTests
  159. //  
  160. //  Purpose:
  161. //
  162. //     Hooks up to the SAMPPROV OLE DB provider application, asks the provider
  163. //     for all data in the CSV file CUSTOMER.CSV, and logs the resulting data 
  164. //     to sampclnt.out        
  165. //  
  166. //  Parameters:
  167. //  
  168. //      none
  169. //      
  170. //  Return Value:
  171. //  
  172. //      S_OK        - Success
  173. //      E_*            - Failure
  174. //      
  175. //      
  176. //  Comments:      
  177. //  
  178. //     At a high level, an OLE DB data consumer obtains data by 
  179. //     
  180. //     1. Getting hooked up to a data provider's Data Source object,
  181. //        and initializing that object
  182. //     2. Getting a DBSession object from the Data Source object
  183. //     3. Getting the data from the Rowset object.
  184. //     
  185. //     DoTests follows these steps by making calls to GetSampprovDataSource,
  186. //     GetDBSessionDataSource, and GetDataFromRowset    
  187. //  
  188. //**********************************************************************
  189.  
  190.  
  191. HRESULT DoTests
  192.     (
  193.     )
  194. {
  195.     IDBInitialize*        pIDBInitialize     = NULL;
  196.     IOpenRowset*        pIOpenRowset    = NULL;
  197.     IRowset*            pIRowset        = NULL;
  198.     LPWSTR                pwszTableName   =     L"customer.csv";
  199.     HRESULT                hr;
  200.  
  201.  
  202.     hr = GetSampprovDataSource( &pIDBInitialize );
  203.     if (FAILED(hr))
  204.         {
  205.         DUMP_ERROR_LINENUMBER();
  206.         DumpErrorHResult( hr, "GetSampprovDataSource" );
  207.         goto error;
  208.         }
  209.  
  210.     hr = GetDBSessionFromDataSource( pIDBInitialize, &pIOpenRowset );
  211.     if (FAILED(hr))
  212.         {
  213.         DUMP_ERROR_LINENUMBER();
  214.         DumpErrorHResult( hr, "GetDBSessionFromDataSource" );
  215.         goto error;
  216.         }
  217.  
  218.     pIDBInitialize->Release();
  219.     pIDBInitialize = NULL;    
  220.  
  221.     hr = GetRowsetFromDBSession( pIOpenRowset, pwszTableName, &pIRowset );
  222.     if (FAILED(hr))
  223.         {
  224.         DUMP_ERROR_LINENUMBER();
  225.         DumpErrorHResult( hr, "GetRowsetFromDBCreateSession" );
  226.         goto error;
  227.         }
  228.         
  229.     pIOpenRowset->Release();
  230.     pIOpenRowset = NULL;    
  231.  
  232.     hr = GetDataFromRowset( pIRowset );
  233.     if (FAILED(hr))
  234.         {
  235.         DUMP_ERROR_LINENUMBER();
  236.         DumpErrorHResult( hr, "GetDataFromRowset" );
  237.         goto error;
  238.         }
  239.     pIRowset->Release(); 
  240.     pIRowset = NULL;
  241.     CoFreeUnusedLibraries();
  242.  
  243.     DumpStatusMsg( "\nDone! ");
  244.     printf("\n\nFor more data from this run, see the log file sampclnt.out\n" );    
  245.     return ResultFromScode( S_OK );
  246.     
  247. error:    
  248.     if (pIRowset) 
  249.         pIRowset->Release();
  250.     if (pIOpenRowset)
  251.         pIOpenRowset->Release();    
  252.     if (pIDBInitialize)
  253.         pIDBInitialize->Release();        
  254.     
  255.     return ResultFromScode( hr );
  256. }                            
  257.  
  258.  
  259.  
  260.  
  261.  
  262. //**********************************************************************
  263. //  
  264. // GetSampprovDataSource
  265. // 
  266. // Purpose:
  267. //
  268. //     Calls OLE to find and load the SAMPPROV data provider. 
  269. //     Returns an IDBInitialize interface pointer on SAMPPROV's 
  270. //     Data Source object.
  271. //
  272. // Parameters:
  273. //     
  274. //   IDBInitialize** ppIDBInitialize_out  - out pointer through which to return
  275. //                                             IDBInitialize pointer on data 
  276. //                                            provider's Data Source object     
  277. // 
  278. // Return Value:
  279. // 
  280. //     S_OK        - Success
  281. //  E_*            - Failure
  282. //     
  283. //
  284. // Comments:      
  285. // 
  286. //     The call to CoCreateInstance is hard-coded with SAMPPROV's CLSID.
  287. //     The pointer returned through ppIDBInitialize_out has been AddRef'ed,
  288. //     it must be Release'd later by the caller.
  289. //  
  290. //**********************************************************************
  291.  
  292. HRESULT GetSampprovDataSource
  293.     (
  294.     IDBInitialize**    ppIDBInitialize_out
  295.     )
  296. {
  297.     IDBInitialize*    pIDBInit = NULL;
  298.     IDBProperties*    pIDBProperties = NULL;
  299.     DBPROPSET        dbPropSet[1];
  300.     DBPROP            dbProp[1];
  301.  
  302.     HRESULT    hr;
  303.  
  304.  
  305.     DumpStatusMsg( "Connecting to the SampProv sample data provider...\n" );
  306.  
  307.     assert(ppIDBInitialize_out != NULL);
  308.  
  309.     VariantInit(&(dbProp[0].vValue));
  310.  
  311.     // Create an instance of the SampProv sample data provider
  312.     hr = CoCreateInstance( CLSID_SampProv, NULL, CLSCTX_INPROC_SERVER, 
  313.                 IID_IDBInitialize, (void **)&pIDBInit ); 
  314.     if (FAILED(hr))
  315.         {
  316.         DUMP_ERROR_LINENUMBER();
  317.         DumpErrorHResult( hr, "CoCreateInstance" );
  318.         goto error;
  319.         }
  320.  
  321.     // Initialize this provider with the path to the customer.csv file
  322.     dbPropSet[0].rgProperties        = &dbProp[0];
  323.     dbPropSet[0].cProperties        = 1;
  324.     dbPropSet[0].guidPropertySet    = DBPROPSET_DBINIT;
  325.     
  326.     dbProp[0].dwPropertyID            = DBPROP_INIT_DATASOURCE;
  327.     dbProp[0].dwOptions                = DBPROPOPTIONS_REQUIRED;
  328.     dbProp[0].colid                    = DB_NULLID;
  329.     V_VT(&(dbProp[0].vValue))        = VT_BSTR;
  330.     V_BSTR(&(dbProp[0].vValue))        = SysAllocString( L"." );
  331.     if ( NULL == V_BSTR(&(dbProp[0].vValue)) )
  332.         {
  333.         DUMP_ERROR_LINENUMBER();
  334.         DumpErrorMsg( "SysAllocString failed\n" );
  335.         goto error;
  336.         }
  337.  
  338.     hr = pIDBInit->QueryInterface( IID_IDBProperties, (void**)&pIDBProperties);
  339.     if (FAILED(hr))
  340.         {
  341.         DUMP_ERROR_LINENUMBER();
  342.         DumpErrorHResult( hr, "IDBInitialize::QI for IDBProperties");
  343.         goto error;
  344.         }
  345.  
  346.     hr = pIDBProperties->SetProperties( 1, &dbPropSet[0]);
  347.     if (FAILED(hr))
  348.         {
  349.         DUMP_ERROR_LINENUMBER();
  350.         DumpErrorHResult( hr, "IDBProperties::SetProperties" );
  351.         goto error;
  352.         }
  353.         
  354.     hr = pIDBInit->Initialize();
  355.     if (FAILED(hr))
  356.         {
  357.         DUMP_ERROR_LINENUMBER();
  358.         DumpErrorHResult( hr, "IDBInitialize::Initialize" );
  359.         goto error;
  360.         }
  361.  
  362.     *ppIDBInitialize_out = pIDBInit;
  363.  
  364.     hr = ResultFromScode( S_OK );
  365.  
  366. error:    
  367.     VariantClear( &(dbProp[0].vValue) );
  368.  
  369.     if( pIDBProperties )
  370.         pIDBProperties->Release();
  371.  
  372.     if( FAILED(hr) )
  373.     {
  374.         if (pIDBInit)
  375.             pIDBInit->Release();
  376.         *ppIDBInitialize_out = NULL;
  377.     }
  378.  
  379.     return hr;    
  380. }
  381.  
  382.  
  383.  
  384.  
  385. //  **********************************************************************
  386. //
  387. // GetDBSessionFromDataSource
  388. //
  389. // Purpose:
  390. //      Calls the provider's Data Source object to get an IOpenRowset interface
  391. //      pointer on a DBSession object.  
  392. //      
  393. // Parameters:
  394. //      pIDBInitialize      - pointer to Data Source object
  395. //      ppIOpenRowset_out   - out pointer through which to return 
  396. //                            IOpenRowset pointer on DBSession object
  397. //
  398. // Return Value: 
  399. //
  400. //     S_OK        - Success
  401. //  E_*            - Failure
  402. //
  403. //
  404. // Comments:
  405. //
  406. //      The interface pointer returned through ppIOpenRowset_out has been 
  407. //      AddRef'ed, the caller must Release it later.
  408. //
  409. //**********************************************************************
  410.  
  411. HRESULT GetDBSessionFromDataSource
  412.     (
  413.     IDBInitialize*      pIDBInitialize,      // [in]
  414.     IOpenRowset**       ppIOpenRowset_out    // [out]
  415.     )
  416. {
  417.     IDBCreateSession*   pIDBCreateSession;
  418.     IOpenRowset*        pIOpenRowset;
  419.     HRESULT             hr;
  420.  
  421.  
  422.     DumpStatusMsg( "Getting a DBSession object from the data source object...\n" );
  423.     
  424.     assert(pIDBInitialize != NULL);
  425.     assert(ppIOpenRowset_out  != NULL );
  426.  
  427.     hr = pIDBInitialize->QueryInterface( IID_IDBCreateSession, (void**)&pIDBCreateSession);
  428.     if (FAILED(hr))
  429.         {
  430.         DUMP_ERROR_LINENUMBER();
  431.         DumpErrorHResult( hr, "IDBInitialize::QI for IDBCreateSession");
  432.         goto error;
  433.         }
  434.         
  435.     hr = pIDBCreateSession->CreateSession( NULL, IID_IOpenRowset, (IUnknown**)&pIOpenRowset );    
  436.     if (FAILED(hr))
  437.         {
  438.         DUMP_ERROR_LINENUMBER();
  439.         DumpErrorHResult( hr, "IDBCreateSession::CreateSession");
  440.         goto error;
  441.         }
  442.      pIDBCreateSession->Release();
  443.      pIDBCreateSession = NULL;
  444.      
  445.      // all went well
  446.      *ppIOpenRowset_out = pIOpenRowset;
  447.      return ResultFromScode( S_OK );
  448.      
  449. error:
  450.     if (pIDBCreateSession)
  451.         pIDBCreateSession->Release();
  452.         
  453.     *ppIOpenRowset_out = NULL;    
  454.     return ResultFromScode( hr );
  455. }
  456.  
  457.  
  458.  
  459. //**********************************************************************
  460. //
  461. // GetRowsetFromDBSession
  462. //
  463. // Purpose:
  464. //      Calls the provider's DBSession object to get an IRowset interface
  465. //      pointer on a Rowset object.  
  466. //      
  467. // Parameters:
  468. //      pIOpenRowset        - interface pointer on DBSession object
  469. //      pwszTableName       - name of "table" (in this case text file)
  470. //      ppIRowset_out       - out pointer through which to return 
  471. //                            IRowset pointer on Rowset object
  472. //
  473. // Return Value: 
  474. //
  475. //     S_OK        - Success
  476. //  E_*            - Failure
  477. //
  478. // Comments:
  479. //
  480. //      The interface pointer returned through ppIRowset_out has been 
  481. //      AddRef'ed, the caller must Release it later.
  482. //
  483. ///**********************************************************************
  484.  
  485. HRESULT GetRowsetFromDBSession
  486.     (
  487.     IOpenRowset*   pIOpenRowset,    // [in]
  488.     LPWSTR         pwszTableName,   // [in] 
  489.     IRowset**      ppIRowset_out    // [out]
  490.     )
  491. {
  492.     DBID            dbcolid;
  493.     IRowset*        pIRowset = NULL;
  494.     HRESULT         hr;
  495.  
  496.     DumpStatusMsg( "Getting a rowset object from the DBSession object...\n" );
  497.     
  498.     assert(pIOpenRowset != NULL);
  499.     assert(ppIRowset_out  != NULL );
  500.     
  501.     // tell the provider which table to open
  502.     dbcolid.eKind           = DBKIND_NAME;
  503.     dbcolid.uName.pwszName  = pwszTableName;
  504.     
  505.     hr = pIOpenRowset->OpenRowset
  506.                         (
  507.                         NULL,                   // pUnkOuter - we are not aggregating
  508.                         &dbcolid,               // pTableID -  the table we want
  509.                         NULL,                    // pIndexID - the index we want
  510.                         IID_IRowset,            // riid - interface we want on the rowset object
  511.                         0,                      // cProperties - we are niave about props for now
  512.                         NULL,                   // prgProperties[]
  513.                         (IUnknown**)&pIRowset   // ppRowset
  514.                         );
  515.     if (FAILED(hr))
  516.         {
  517.         DUMP_ERROR_LINENUMBER();
  518.         DumpErrorHResult( hr, "IOpenRowset::OpenRowset" );
  519.         goto error;
  520.         }
  521.     
  522.     // all went well
  523.     *ppIRowset_out = pIRowset;
  524.     return ResultFromScode( S_OK );
  525.  
  526. error:
  527.     if (pIRowset)
  528.         pIRowset->Release();
  529.     *ppIRowset_out = NULL;            
  530.     
  531.     return ResultFromScode( hr );
  532. }    
  533.  
  534.  
  535. //**********************************************************************
  536. // 
  537. // GetDataFromRowset
  538. // 
  539. // Purpose:
  540. // 
  541. //     Pulls the data from a Rowset object.
  542. //     
  543. // Parameters:
  544. // 
  545. //     IRowset*    pIRowset    -  interface pointer on data provider's
  546. //                             Rowset object
  547. // 
  548. // Return Value:
  549. // 
  550. //     S_OK        - Success
  551. //     E_*         - Failure
  552. // 
  553. // Comments:      
  554. // 
  555. //     At a high level, a consumer pulls the data from a Rowset object by:
  556. //     
  557. //     1. getting metadata for the Rowset's columns
  558. //     2. using that metadata, along with the consumer's own knowledge of
  559. //        how it wants to recieve the data, to create bindings. Bindings
  560. //        represent how the actual data in the Rowset's columns is
  561. //        actually transferred to the consumer's buffer.
  562. //     3. pass the bindings to the Rowset, and get in return an accessor
  563. //        handle that represents that particulr set of bindings   
  564. //     4. get the actual data
  565. //     5. clean up the rowset (at a minumum, release the accessor) 
  566. //     
  567. //     GetDataFromRowset performs these steps by calling GetColumnsInfo,
  568. //     SetupBindings, CreateAccessor, GetData, and CleanupRowset
  569. //       
  570. //**********************************************************************
  571.  
  572. HRESULT GetDataFromRowset
  573.     (
  574.     IRowset*    pIRowset
  575.     )
  576. {
  577.     ULONG             cCol;
  578.     ULONG             cbMaxRowSize;        // buffer size for 1 row's data
  579.     ULONG             cBind;
  580.     DBBINDING        rgBind[MAX_BINDINGS];
  581.     HACCESSOR        hAccessor        = NULL;
  582.     DBCOLUMNINFO*    pColumnInfo     = NULL;
  583.     WCHAR*            pStringsBuffer  = NULL;
  584.     HRESULT         hr;
  585.     
  586.  
  587.  
  588.     DumpStatusMsg( "Reading all the data in the rowset...\n" );
  589.  
  590.     assert(pIRowset != NULL);
  591.     assert(g_pIMalloc != NULL);
  592.     
  593.     hr = GetColumnsInfo( pIRowset, &cCol, &pColumnInfo, &pStringsBuffer );
  594.     if (FAILED(hr))
  595.         {
  596.         DUMP_ERROR_LINENUMBER();
  597.         DumpErrorHResult( hr,  "GetColumnsInfo");
  598.         goto error;
  599.         }
  600.     
  601.     hr = SetupBindings( cCol, pColumnInfo, rgBind, &cBind, &cbMaxRowSize );
  602.     if (FAILED(hr))
  603.         {
  604.         DUMP_ERROR_LINENUMBER();
  605.         DumpErrorHResult( hr,  "SetupBindings");
  606.         goto error;
  607.         }
  608.     
  609.     hr = CreateAccessor( pIRowset, rgBind, cBind, &hAccessor );
  610.     if (FAILED(hr))
  611.         {
  612.         DUMP_ERROR_LINENUMBER();
  613.         DumpErrorHResult( hr,  "CreateAccessor" );
  614.         goto error;
  615.         }
  616.  
  617.     hr = GetData( pIRowset, cbMaxRowSize, hAccessor, rgBind, cBind, pColumnInfo, cCol );
  618.     if (FAILED(hr))
  619.         {
  620.         DUMP_ERROR_LINENUMBER();
  621.         DumpErrorHResult( hr,  "GetData" );
  622.         goto error;
  623.         }
  624.  
  625.     g_pIMalloc->Free( pColumnInfo );
  626.     pColumnInfo = NULL;
  627.     g_pIMalloc->Free( pStringsBuffer );
  628.     pStringsBuffer = NULL;
  629.     
  630.     hr = CleanupRowset( pIRowset, hAccessor );
  631.     if (FAILED(hr))
  632.         {
  633.         DUMP_ERROR_LINENUMBER();
  634.         DumpErrorHResult( hr,  "CleanupRowset" );
  635.         goto error;
  636.         }
  637.     
  638.     return ResultFromScode( S_OK );        
  639.     
  640. error:    
  641.     if (pColumnInfo)
  642.         g_pIMalloc->Free( pColumnInfo );
  643.     if (pStringsBuffer)
  644.         g_pIMalloc->Free( pStringsBuffer );            
  645.         
  646.     return ResultFromScode( hr );    
  647. }
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654. //**********************************************************************
  655. // 
  656. // GetColumnsInfo
  657. //
  658. // Purpose:
  659. // 
  660. //     Obtains information (metadata) about the columns in the rowset - the types
  661. //     of the data and so on.
  662. //
  663. // 
  664. // Parameters:
  665. //     IRowset*        pIRowset            - interface pointer on data provider's
  666. //                                        Rowset object  
  667. //     ULONG*            pcCol_out           - out pointer through which to return
  668. //                                        number of columns in the rowset
  669. //     DBCOLUMNINFO**    ppColumnInfo_out    - out pointer through which to return
  670. //                                        pointer to structure containing
  671. //                                        metadata for the columns in the rowset
  672. //     WCHAR**            ppStringsBuffer_out - out pointer through which to return
  673. //                                        pointer to table of strings. see comments. 
  674. // 
  675. // Return Value:
  676. //     S_OK        - Success
  677. //     E_*         - Failure
  678. //     
  679. //     
  680. // Comments:      
  681. // 
  682. //     ppColumnInfo_out and ppStringsBuffer_out are used to return pointers
  683. //     to two buffers. These buffers are allocated by the data provider
  684. //     (when GetColumnsInfo calls IColumnsInfo::GetColumnInfo). The data
  685. //     provider uses IMalloc to allocate the buffers; therefore, the caller
  686. //     of this routine must at a later point use IMalloc::Free to free
  687. //     both of these buffers. The StringsBuffer contains strings pointed
  688. //     to by pointers in the ColumnInfo buffer, therefore the StringsBuffer
  689. //     should be freed *after* the ColumnInfo pointer.    
  690. //
  691. //     GetColumnsInfo calls DumpColumnsInfo to dump the column metadata to
  692. //     the log file.
  693. // 
  694. //**********************************************************************
  695.  
  696. HRESULT GetColumnsInfo
  697.     (
  698.     IRowset*        pIRowset,
  699.     ULONG*            pcCol_out,
  700.     DBCOLUMNINFO**    ppColumnInfo_out,
  701.     WCHAR**            ppStringsBuffer_out
  702.     )
  703. {
  704.     IColumnsInfo*     pIColumnsInfo = NULL;
  705.     ULONG            cCol;
  706.     DBCOLUMNINFO*    pColumnInfo;
  707.     WCHAR*            pStringsBuffer;
  708.     HRESULT         hr;
  709.     
  710.  
  711.     assert(pIRowset != NULL);
  712.     assert(pcCol_out != NULL);
  713.     assert(ppColumnInfo_out != NULL);
  714.     assert(ppStringsBuffer_out != NULL);
  715.  
  716.     // get column information from the command object via IColumnsInfo 
  717.     hr = pIRowset->QueryInterface( IID_IColumnsInfo, (void **) &pIColumnsInfo );
  718.     if (FAILED(hr))
  719.         {
  720.         DUMP_ERROR_LINENUMBER();
  721.         DumpErrorHResult( hr, "IRowset::QI for IID_IColumnsInfo" );
  722.         goto error;
  723.         }
  724.     hr = pIColumnsInfo->GetColumnInfo( 
  725.             &cCol, 
  726.             &pColumnInfo,
  727.             &pStringsBuffer );
  728.     if (FAILED(hr))
  729.         {
  730.         DUMP_ERROR_LINENUMBER();
  731.         DumpErrorHResult( hr, "pIColumnsInfo->GetColumnInfo" );
  732.         goto error;
  733.         }
  734.     pIColumnsInfo->Release();
  735.     pIColumnsInfo = NULL;
  736.  
  737.     DumpColumnsInfo( pColumnInfo, cCol );
  738.     
  739.     // fill out-params
  740.     *pcCol_out = cCol;
  741.     *ppColumnInfo_out = pColumnInfo;
  742.     *ppStringsBuffer_out = pStringsBuffer;
  743.     
  744.     return ResultFromScode( S_OK );
  745.  
  746. error:
  747.     if (pIColumnsInfo)
  748.         pIColumnsInfo->Release();
  749.         
  750.     *pcCol_out = 0;
  751.     *ppColumnInfo_out = NULL;
  752.     *ppStringsBuffer_out = NULL;
  753.     
  754.     return ResultFromScode( hr );
  755. }
  756.  
  757.  
  758. //**********************************************************************
  759. // 
  760. // SetupBindings
  761. // 
  762. // Purpose:
  763. // 
  764. //     Creates bindings that map the data in the rowset's columns to 
  765. //     slots in the consumer's data buffer.
  766. //     
  767. // Parameters:
  768. //
  769. //     ULONG             cCol                - number of columns in rowset to bind
  770. //     DBCOLUMNINFO*    pColumnInfo         - pointer to column metadata
  771. //     DBBINDING*        rgBind_out          - out pointer through which to return
  772. //                                        an array of binding structures, one
  773. //                                        structure per column bound
  774. //     ULONG*            pcBind_out          - out pointer through which to return   
  775. //                                        the number of columns bound (number
  776. //                                        of valid elements in rgBind_out)              
  777. //     ULONG*            pcMaxRowSize_out    - out pointer through which to return
  778. //                                        the buffer size necessary to hold
  779. //                                        the largest row data
  780. // 
  781. // Return Value:
  782. //     S_OK         - Success
  783. //     E_*          - Failure
  784. // 
  785. //     
  786. // Comments:      
  787. // 
  788. // 
  789. //**********************************************************************
  790.  
  791. HRESULT SetupBindings
  792.     (
  793.     ULONG             cCol,
  794.     DBCOLUMNINFO*    pColumnInfo,
  795.     DBBINDING*        rgBind_out,
  796.     ULONG*            pcBind_out,
  797.     ULONG*            pcMaxRowSize_out
  798.     )
  799. {
  800.     ULONG dwOffset;
  801.     ULONG iCol;
  802.     ULONG iBind;
  803.     
  804.     
  805.     assert(pColumnInfo != NULL);
  806.     assert(rgBind_out != NULL);
  807.     assert(pcBind_out != NULL);
  808.     assert(pcMaxRowSize_out != NULL);
  809.     
  810.     // Create bindings.
  811.     // Bind everything as a string just to keep things simple.
  812.     dwOffset = 0;
  813.     iBind=0;
  814.     for (iCol=0; iCol < cCol; iCol++)
  815.     {
  816.         // Skip columns of type _VECTOR. Probably binary data.
  817.         if (pColumnInfo[iCol].wType & DBTYPE_VECTOR)
  818.             continue;
  819.  
  820.         rgBind_out[iBind].dwPart    = DBPART_VALUE | DBPART_LENGTH |
  821.                                       DBPART_STATUS;
  822.         rgBind_out[iBind].eParamIO  = DBPARAMIO_NOTPARAM;                              
  823.         rgBind_out[iBind].iOrdinal  = pColumnInfo[iCol].iOrdinal;
  824.         rgBind_out[iBind].wType        = DBTYPE_STR;
  825.         rgBind_out[iBind].pTypeInfo = NULL;
  826.         rgBind_out[iBind].obValue   = dwOffset + offsetof(COLUMNDATA,bData);
  827.          rgBind_out[iBind].obLength  = dwOffset + offsetof(COLUMNDATA,dwLength);
  828.         rgBind_out[iBind].obStatus  = dwOffset + offsetof(COLUMNDATA,dwStatus);
  829.         rgBind_out[iBind].cbMaxLen  = pColumnInfo[iCol].wType == DBTYPE_STR ? 
  830.                                         pColumnInfo[iCol].ulColumnSize + sizeof(char) : DEFAULT_CBMAXLENGTH;
  831.         rgBind_out[iBind].pObject    = NULL;
  832.         dwOffset += rgBind_out[iBind].cbMaxLen + offsetof( COLUMNDATA, bData );
  833.         dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  834.         iBind++;
  835.     }  
  836.     
  837.     *pcBind_out       = iBind;
  838.     *pcMaxRowSize_out = dwOffset;
  839.  
  840.     return ResultFromScode( S_OK );
  841. }
  842.  
  843.  
  844.  
  845. //**********************************************************************
  846. // 
  847. // CreateAccessor
  848. // 
  849. // Purpose:
  850. //
  851. //     Passes a set of bindings to the data provider and recieves in return
  852. //     an accessor handle that represents those bindings. 
  853. //      
  854. // Parameters:
  855. //     IRowset*    pIRowset        - interface pointer on data provider's Rowset
  856. //                                object
  857. //     DBBINDING*    rgBind          - array of binding structures
  858. //     ULONG        cBind           - number of binding structures in rgBind
  859. //     HACCESSOR*    phAccessor_out  - out pointer through which to return an 
  860. //                                accessor handle that represents all the bindings
  861. //                                in rgBind
  862. // 
  863. // Return Value:
  864. //     S_OK        - Success
  865. //     E_*         - Failure
  866. // 
  867. //     
  868. // Comments:      
  869. // 
  870. // 
  871. //**********************************************************************
  872.  
  873. HRESULT CreateAccessor
  874.     (
  875.     IRowset*    pIRowset,
  876.     DBBINDING*    rgBind,
  877.     ULONG        cBind,
  878.     HACCESSOR*    phAccessor_out 
  879.     )
  880. {
  881.     IAccessor*    pIAccessor = NULL;
  882.     HACCESSOR   hAccessor;
  883.     HRESULT     hr;
  884.  
  885.  
  886.     assert(pIRowset != NULL);
  887.     assert(rgBind != NULL);
  888.     assert(phAccessor_out != NULL);
  889.  
  890.       // Get an accessor for our bindings from the rowset, via IAccessor 
  891.     hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor );
  892.     if (FAILED(hr))       
  893.         {
  894.         DUMP_ERROR_LINENUMBER();
  895.         DumpErrorHResult( hr, "pIRowset->QI for IID_IAccessor" );    
  896.         goto error;
  897.         }
  898.     hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, cBind, rgBind, 0, 
  899.                                      &hAccessor, NULL );
  900.     if (FAILED(hr))       
  901.         {
  902.         DUMP_ERROR_LINENUMBER();
  903.         DumpErrorHResult( hr, "pIAccessor->CreateAccessor" );    
  904.         goto error;
  905.         }
  906.     pIAccessor->Release();
  907.     pIAccessor = NULL;
  908.  
  909.     *phAccessor_out = hAccessor;
  910.  
  911.     return ResultFromScode( S_OK );    
  912.  
  913. error:
  914.     if (pIAccessor)
  915.         pIAccessor->Release();
  916.     *phAccessor_out = NULL;
  917.     
  918.     return ResultFromScode( hr );
  919. }
  920.  
  921.  
  922. //**********************************************************************
  923. // 
  924. // GetData
  925. // 
  926. // Purpose:
  927. // 
  928. //     Reads the data from a rowset.
  929. // 
  930. // Parameters:
  931. //
  932. //        IRowset*     pIRowset           - interface pointer on data provider's
  933. //                                    Rowset object
  934. //        ULONG        cMaxRowSize        - size of buffer needed to hold the data
  935. //                                    for the largest row
  936. //     HACCESSOR hAccessor          - accessor handle representing the set
  937. //                                    of desired bindings
  938. //     DBBINDING*        rgBind          - needed only for pretty printing    
  939. //     ULONG            cBind          - for pretty printing  
  940. //     DBCOLUMNINFO*    pColumnInfo - for pretty printing  
  941. //     ULONG            cCol        - for pretty printing  
  942. // 
  943. // 
  944. // Return Value:
  945. //     S_OK        - Success
  946. //     E_*         - Failure
  947. // 
  948. // 
  949. //     
  950. // Comments:      
  951. //
  952. //     GetData reads all the rows in the rowset, sequentially.
  953. //     
  954. //     GetData calls CalcPrettyPrintMaxColWidth, DumpColumnHeadings, and
  955. //     DumpRow to dump the row data to a log file.
  956. //  
  957. // 
  958. //**********************************************************************
  959.  
  960. HRESULT GetData
  961.     (
  962.     IRowset*    pIRowset,
  963.     ULONG       cMaxRowSize,
  964.     HACCESSOR   hAccessor,
  965.     DBBINDING*        rgBind,            
  966.     ULONG            cBind,            
  967.     DBCOLUMNINFO*    pColumnInfo,  
  968.     ULONG            cCol          
  969.     )
  970. {
  971.     ULONG     cRowsObtained;
  972.     ULONG    iRow;
  973.     BYTE*    pRowData = NULL;
  974.     HROW     rghRows[NUMROWS_CHUNK];
  975.     HROW*    pRows = &rghRows[0];
  976.     ULONG    cMaxColWidth;          // needed for pretty printing
  977.     HRESULT hr;
  978.     
  979.  
  980.     assert(pIRowset != NULL);
  981.     assert(rgBind != NULL);
  982.     assert(pColumnInfo != NULL);
  983.  
  984.     // create a buffer for row data, big enough to hold the biggest row
  985.     pRowData = (BYTE *) malloc( cMaxRowSize );
  986.     if (!pRowData)
  987.         {
  988.         DUMP_ERROR_LINENUMBER();
  989.         DumpErrorMsg("GetData: malloc failed\n");
  990.         goto error;
  991.         }    
  992.  
  993.     // pretty print
  994.     cMaxColWidth = CalcPrettyPrintMaxColWidth( rgBind, cBind );
  995.     
  996.     // pretty print
  997.     DumpColumnHeadings( rgBind, cBind, pColumnInfo, cCol, cMaxColWidth );
  998.         
  999.     // process all the rows, NUMROWS_CHUNK rows at a time
  1000.     while (1)
  1001.         {
  1002.         hr = pIRowset->GetNextRows(
  1003.             NULL,                        // hChapter
  1004.             0,                            // cRowsToSkip
  1005.             NUMROWS_CHUNK,                // cRowsDesired
  1006.             &cRowsObtained,             // pcRowsObtained
  1007.             &pRows );                    // filled in w/ row handles
  1008.         if (FAILED(hr))
  1009.             {
  1010.             DUMP_ERROR_LINENUMBER();
  1011.             DumpErrorHResult( hr, "pIRowset->GetNextRows" );
  1012.             goto error;
  1013.             }        
  1014.  
  1015.         if ( cRowsObtained == 0 )            // all done, no more rows left to get
  1016.             break;
  1017.  
  1018.         // loop over rows obtained, getting data for each
  1019.         for ( iRow=0; iRow < cRowsObtained; iRow++ )
  1020.             {
  1021.             hr = pIRowset->GetData(
  1022.                 rghRows[iRow],
  1023.                 hAccessor,
  1024.                 pRowData );
  1025.              if (FAILED(hr))
  1026.                  {
  1027.                 DUMP_ERROR_LINENUMBER();
  1028.                 DumpErrorHResult( hr, "pIRowset->GetData" );
  1029.                 goto error;
  1030.                  }   
  1031.             
  1032.             // pretty print
  1033.             DumpRow( rgBind, cBind, cMaxColWidth, pRowData );
  1034.             }
  1035.         // release row handles
  1036.         hr = pIRowset->ReleaseRows( cRowsObtained, rghRows, NULL, NULL, NULL );
  1037.         if (FAILED(hr))
  1038.                  {
  1039.                 DUMP_ERROR_LINENUMBER();
  1040.                 DumpErrorHResult( hr, "pIRowset->ReleaseRows" );
  1041.                 goto error;
  1042.                  } 
  1043.         }    // end while
  1044.  
  1045.     // free row data buffer
  1046.     free( pRowData );
  1047.     return ResultFromScode( S_OK );
  1048.     
  1049. error:
  1050.     if (pRowData)
  1051.         free( pRowData );
  1052.             
  1053.     return ResultFromScode( hr );
  1054. }
  1055.  
  1056.  
  1057.  
  1058. //**********************************************************************
  1059. // 
  1060. // CleanupRowset
  1061. // 
  1062. // Purpose:
  1063. //
  1064. //     Allows the rowset to perform any necessary cleanup.
  1065. //  
  1066. // Parameters:
  1067. //
  1068. //     IRowset*    pIRowset    - interface pointer on data provider's Rowset
  1069. //                            object
  1070. //     HACCESSOR     hAccessor   - accessor handle to release
  1071. // 
  1072. // Return Value:
  1073. //
  1074. //     S_OK        - Success
  1075. //     E_*         - Failure
  1076. //     
  1077. //     
  1078. // Comments:      
  1079. //
  1080. //     In this sample, the only cleanup that the rowset needs to do is
  1081. //     release the accessor handle. 
  1082. // 
  1083. //**********************************************************************
  1084.  
  1085. HRESULT CleanupRowset
  1086.     (
  1087.     IRowset*    pIRowset,
  1088.     HACCESSOR     hAccessor
  1089.     )
  1090. {
  1091.     IAccessor*    pIAccessor = NULL;
  1092.     HRESULT        hr;
  1093.     
  1094.     assert(pIRowset != NULL);
  1095.     
  1096.     // tell the rowset object it can release the accessor, via IAccessor
  1097.     hr = pIRowset->QueryInterface( IID_IAccessor, (void**)&pIAccessor );
  1098.     if (FAILED(hr))
  1099.         {
  1100.         DUMP_ERROR_LINENUMBER();
  1101.         DumpErrorHResult( hr, "pIRowset->QI for IID_IAccessor" );
  1102.         goto error;
  1103.         } 
  1104.     hr = pIAccessor->ReleaseAccessor( hAccessor, NULL );
  1105.     if (FAILED(hr))
  1106.         {
  1107.         DUMP_ERROR_LINENUMBER();
  1108.         DumpErrorHResult( hr, "pIAccessor->ReleaseAccessor" );
  1109.         goto error;
  1110.         }    
  1111.     pIAccessor->Release();
  1112.     pIAccessor = NULL;
  1113.  
  1114.     return ResultFromScode( S_OK );
  1115.     
  1116. error:    
  1117.     if (pIAccessor)
  1118.         pIAccessor->Release();
  1119.  
  1120.     return ResultFromScode( hr );    
  1121. }
  1122.  
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128.  
  1129.  
  1130.  
  1131.  
  1132.  
  1133.  
  1134.