//--------------------------------------------------------------------------- // Microsoft OLE DB Programmer's Reference Sample // Copyright (C) 1998 By Microsoft Corporation. // // @doc // // @module MAIN.CPP // //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////// // Includes // ///////////////////////////////////////////////////////////////// #define DBINITCONSTANTS // Store all OLE DB consts inside this .obj file #include "prsample.h" // Programmer's Reference Sample includes ///////////////////////////////////////////////////////////////// // Globals // ///////////////////////////////////////////////////////////////// DWORD g_dwFlags = USE_PROMPTDATASOURCE | DISPLAY_METHODCALLS; ///////////////////////////////////////////////////////////////// // main // // This is a simple OLE DB application that will display a // rowset and will allow basic navigation of that rowset by the // user. // // In the sample, functions that begin with 'my' are implemented // in the sample code; all other functions are either OLE DB // methods or are standard system methods. In addition, two // macros are used repeatedly throughout the sample: // - CHECK_HR(hr) - this macro goes to the CLEANUP label if // FAILED(hr), where hr is usually a method call // - XCHECK_HR(hr) - this macro prints the string // representation of hr to stderr and if FAILED(hr), attempts // to obtain and display any extended error information // posted by the last method call, then jumps to the CLEANUP // label // // This is the entry point for the sample. This function will: // - parse command line arguments passed to the sample // - display appropriate instructions based on these arguments // - create an OLE DB DataSource object for a user-chosen // provider // - create an OLE DB Session object from the provider's // DataSource object // - create an OLE DB Rowset object, over a table specified by // the user, from the provider's Session object // - display the rowset data and will allow the user to // navigate over the rowset // ///////////////////////////////////////////////////////////////// int main() { HRESULT hr; IUnknown * pUnkDataSource = NULL; IUnknown * pUnkSession = NULL; IUnknown * pUnkRowset = NULL; // Parse command line arguments, if any; this will update // the value of g_dwFlags as appropriate for the arguments if( !myParseCommandLine() ) return EXIT_FAILURE; // Display instructions for the given command line arguments myDisplayInstructions(); // Initialize OLE hr = CoInitialize(NULL); if( FAILED(hr) ) return EXIT_FAILURE; // Create the Data Source object using the OLE DB service components CHECK_HR(hr = myCreateDataSource(&pUnkDataSource)); // Create a Session object from the Data Source object CHECK_HR(hr = myCreateSession(pUnkDataSource, &pUnkSession)); // Create a Rowset object from the Session object, either directly // from the Session or through a Command object CHECK_HR(hr = myCreateRowset(pUnkSession, &pUnkRowset)); // Display the Rowset object data to the user CHECK_HR(hr = myDisplayRowset(pUnkRowset, NULL, 0, NULL)); CLEANUP: if( pUnkRowset ) pUnkRowset->Release(); if( pUnkSession ) pUnkSession->Release(); if( pUnkDataSource ) pUnkDataSource->Release(); CoUninitialize(); if( FAILED(hr) ) return EXIT_FAILURE; return EXIT_SUCCESS; } ///////////////////////////////////////////////////////////////// // myParseCommandLine // // This function parses the application's command line arguments // and sets the appropriate bits in g_dwFlags. If an invalid // argument is encountered, a usage message is displayed and // the function returns FALSE; otherwise TRUE is returned. // ///////////////////////////////////////////////////////////////// BOOL myParseCommandLine ( void ) { int iArg; CHAR * psz; // Set the locale for all C runtime functions setlocale(LC_ALL, ".ACP"); // Go through each command line argument and set the appropriate // bits in g_dwFlags, depending on the chosen options for( iArg = 1; iArg < __argc; iArg++ ) { // Inspect the current argument string psz = __argv[iArg]; // Valid options begin with '-' or '/' if( psz[0] == '-' || psz[0] == '/' ) { // The next character is the option switch( tolower(psz[1]) ) { case 'u': // Use the service components UI to prompt for and create // the DataSource object; the enumerator is not used g_dwFlags |= USE_PROMPTDATASOURCE; g_dwFlags &= ~USE_ENUMERATOR; continue; case 'e': // Use the enumerator to select the provider, then use // IDataInitialize to create the DataSource object; // don't use the UI to prompt for the DataSource g_dwFlags |= USE_ENUMERATOR; g_dwFlags &= ~USE_PROMPTDATASOURCE; continue; case 'c': // Use ICommand instead of IOpenRowset g_dwFlags |= USE_COMMAND; continue; case 'b': // Use ISequentialStream to fetch BLOB column data g_dwFlags |= USE_ISEQSTREAM; continue; case 'n': // Don't display method call strings as part of // the extended error checking macro g_dwFlags &= ~DISPLAY_METHODCALLS; continue; } } // Invalid argument; show the usage flags to the user fprintf(stderr, "Usage: %s [-u] [-e] [-c] [-b] [-n]\n\nWhere:\n\t" \ "u = Use the Microsoft Data Links UI " \ "to create the DataSource\n\t" \ "e = Use the Enumerator and IDataInitialize " \ "to create the DataSource\n\t" \ "c = Use ICommand instead of IOpenRowset to create the Rowset\n\t" \ "b = Use ISequentialStream for BLOB columns\n\t" \ "n = Don't display method call strings\n", __argv[0]); return FALSE; } return TRUE; } ///////////////////////////////////////////////////////////////// // myDisplayInstructions // // This function asks the user whether they would like // instructions displayed for the application. If so, it // displays the instructions appropriate to the flags set // in g_dwFlags. // ///////////////////////////////////////////////////////////////// void myDisplayInstructions ( void ) { CHAR ch; // Display header and ask the user if they want instructions printf("\nOLE DB Programmer's Reference Sample\n" \ "====================================\n\n"); printf("Display instructions [Y or N]? "); do { ch = myGetChar(); } while( ch != 'y' && ch != 'n' ); printf("%c\n\n", ch); // No instructions, so we're done if( ch == 'n' ) return; // Display basic instructions printf("This application is a simple OLE DB sample that will display\n" \ "a rowset and will allow basic navigation of that rowset by\n" \ "the user. The application will perform the following steps:\n\n"); // Display DataSource creation instructions if( g_dwFlags & USE_PROMPTDATASOURCE ) { printf(" - Creates a DataSource object through the Microsoft Data\n" \ " Links UI. This allows the user to select the OLE DB\n" \ " provider to use and to set connection properties.\n"); } else { printf(" - Creates a DataSource object through IDataInitialize::\n" \ " CreateDBInstance, which allows the OLE DB service\n" \ " component manager to add additional functionality to\n" \ " the provider as requested. The user will select the\n" \ " provider to use from a rowset obtained from the OLE DB\n" \ " enumerator.\n"); } // Display Session creation and table-selection instructions printf(" - Creates a Session object from the DataSource object.\n"); printf(" - If the provider supports the schema rowset interface,\n" \ " creates a TABLES schema rowset and allows the user to\n" \ " select a table name from this rowset.\n"); // Display Rowset creation instructions if( g_dwFlags & USE_COMMAND ) { printf(" - Creates a Command object from the Session object and\n" \ " allows the user to specify command text for this Command,\n" \ " then executes the command to create the final rowset.\n"); } else { printf(" - Creates the final rowset over the table specified by the\n" \ " user.\n"); } printf(" - Displays this rowset and allows the user to perform basic\n" \ " navigation of that rowset.\n\n"); // Wait for the user to press a key before continuing printf("Press a key to continue..."); myGetChar(); printf("\n\n"); } ///////////////////////////////////////////////////////////////// // myGetInputFromUser // // This function prompts the user with the contents of pwszFmt // and any accompanying variable arguments, then gets a string // as input from the user. If the string is non-empty, it is // copied into pwszInput and the function returns TRUE; // otherwise this function returns FALSE. // ///////////////////////////////////////////////////////////////// BOOL myGetInputFromUser ( LPWSTR pwszInput, size_t nInputBufferSize, LPCWSTR pwszFmt, ... ) { va_list vargs; WCHAR wszBuffer[MAX_NAME_LEN + 1] = {0}; // Create the string with variable arguments... va_start(vargs, pwszFmt); _vsnwprintf_s(wszBuffer, _countof(wszBuffer), MAX_NAME_LEN, pwszFmt, vargs); va_end(vargs); // Output the string... wprintf(wszBuffer); // Now get the Input from the user... _getws_s(wszBuffer, _countof(wszBuffer)); if( wszBuffer[0] ) { wcscpy_s(pwszInput, nInputBufferSize, wszBuffer); return TRUE; } return FALSE; } ///////////////////////////////////////////////////////////////// // myGetChar // // This function gets a character from the keyboard and // converts it to lowercase before returning it. // ///////////////////////////////////////////////////////////////// CHAR myGetChar ( void ) { CHAR ch; // Get a character from the keyboard ch = _getch(); // Re-read for the actual key value if necessary if( !ch || ch == 0xE0 ) ch = _getch(); return tolower(ch); }