Microsoft KB Archive/168052

{|
 * width="100%"|

INF: ODBC 3.0 Driver Manager and Driver Installation

 * }

Q168052

-

The information in this article applies to:


 * Microsoft Open Database Connectivity, version 3.0

-

SUMMARY
There have been several changes to the Open Database Connectivity (ODBC) installation process from version 2.5 to version 3.0. SQLInstallDriver and SQLInstallODBC have been removed, and SQLInstallTranslator has been deprecated. These changes have made the Odbc.inf file unnecessary. The APIs below request data from, insert data, and make changes to the registry and the Odbc.ini and Odbcinst.ini files.

NOTE: These APIs do not copy files or perform any version checking of the drivers or driver manager. The source code included with this article has an example of how to perform the version checking and file copying, but is outside the scope of ODBC.

  SQLInstallDriverManager retrieves the path to install the ODBC core components. Also, it increments the component's usage count.

The following are the ODBC Core Components: Ds16gt.dll

Ds32gt.dll

Odbccp32.dll

Odbc32.dll

Odbcad32.exe

Odbccr32.dll

Odbccp32.cpl

Odbctrac.dll

Odbcint.dll

Odbcinst.cnt

Odbcinst.hlp

Mtxdm.dll (if you use connection pooling)  SQLInstallDriverEx installs the driver in the Odbcinst.ini file and in the registry. Also, it can be used to increment a driver's usage count or change a parameter of a driver. SQLConfigDriver configures the driver's setting in the Odbcinst.ini file and the registry. It must be called after the call to SQLInstallDriverEx to complete the driver's installation. SQLInstallTranslatorEx configures a translator if required by the driver. This is not done in the sample code below, but it is very similar to the SQLInstallDriverEx API. SQLConfigDataSource adds, configures, or removes a datasource from ODBC.

SQLInstallDriverEX, SQLInstallTranslatorEx, and SQLConfigDataSource each require strings of keyword pairs. Many of the ODBC keywords are described in Chapter 18, "Installing ODBC Components," in the Microsoft "ODBC 3.0 Programmer's Reference, Volume 1, and SDK Guide." It is important to note that keyword pairs end with two "\0"s, as in the following SQLInstallDriverEx keyword example:

My Datasource\0Server=bottles\0Database=\0;UID=sa\0 PWD=\0UseProcForPrepare=Yes\0Trusted_Connection=\0AnsiNPW=Yes\0\0 You can find detailed documentation for each of these functions in the "ODBC 3.0 Programmers Reference, Volume 1, and SDK Guide".

MORE INFORMATION
The following C program illustrates a minimal application's set of requirements for installing the driver manager and a driver.

#include 
 * 1) include 
 * 2) include <sqlext.h>
 * 3) include <odbcinst.h>
 * 4) include <winver.h>
 * 5) include <string.h>
 * 6) include <stdio.h>
 * 7) include <malloc.h>
 * 8) include "main.h"


 * 1) define DriverName "Bogus Driver"
 * 2) define DataSourceName "My Bogus Datasource"
 * 3) define DriverDLL "mysql32.dll"

void main {  if( ! Install ) printf( "ODBC Install Failed\n" ); printf( "The End" ); }

/* General error handler for installer functions. */ BOOL ProcessErrorMessages( char * func ) { WORD  iError = 1; DWORD  pfErrorCode; char  lpszErrorMsg[301]; WORD  cbErrorMsgMax = 300; WORD  pcbErrorMsg; int     rc; BOOL  func_rc = FALSE;

do  { lpszErrorMsg[0] = '\0'; rc = SQLInstallerError(        iError,         & pfErrorCode,         lpszErrorMsg,         cbErrorMsgMax,         & pcbErrorMsg ); if( rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO ) {        printf( "%s in function %s", lpszErrorMsg, func ); func_rc = TRUE; }     iError++; }  while( rc != SQL_NO_DATA );

return func_rc; }

BOOL Install { char  szPath[301]; WORD  cbPathMax = 300; WORD  cbPathOut; BOOL  rc; UINT  uVersionLength = 512;

/* First, retrieve the path the driver should be installed to in szPath*/ if( SQLInstallDriverManager( szPath, cbPathMax, & cbPathOut ) ) {     /* Now compare the version of the core component files and copy them if appropriate. NOTE: For the purposes of this sample code. only Odbc32.dll is        being copied. */      if( VersionCheckCopyFile( szPath, "C:\\TEMP\\ODBC", "ODBC32.DLL" ) ) {        /* Check to see if the driver is already installed. */         if( rc = IsMyDriverInstalled ) /* If the driver is already installed, increase the usage count and return. */            BumpUpDriverUsageCount; else /* If not, install the driver. */            rc = InstallMyDriver;

if( rc ) /* After the driver is installed, create the new DSN. */            AddMyDSN; }     else {        ProcessErrorMessages( "SQLInstallDriverManager" ); return FALSE; }  }   else {     ProcessErrorMessages( "SQLInstallDriverManager" ); return FALSE; }

return TRUE; }

BOOL IsMyDriverInstalled { char  szBuf[2001]; WORD  cbBufMax = 2000; WORD  cbBufOut; char *  pszBuf = szBuf;

/* Call SQLGetInstalledDrivers to retrieve an array with the names of the installed drivers. */   if( SQLGetInstalledDrivers( szBuf, cbBufMax, & cbBufOut) ) if( ProcessErrorMessages( "SQLGetInstalledDrivers" ) ) return FALSE;

/* Now loop through the array and search for the driver being installed. */   do   { if( strcmp( DriverName, pszBuf ) == 0 ) return TRUE; pszBuf = strchr( pszBuf, '\0' ) + 1; }  while( pszBuf[1] != '\0' );

return FALSE; }

void BumpUpDriverUsageCount { char   szDriver[300]; char   szPathIn[301]; char  szPathOut[301]; WORD  cbPathOutMax = 300; WORD  cbPathOut; DWORD  dwUsageCount;

/* The correct format of driver keywords are: "DriverName\0Driver=MyDriver.DLL\0Setup=MySetup.DLL\0\0" */

/* Also, note that the driver's setup routines can be in the same DLL. */   sprintf( szDriver, "Bogus Driver\0Driver=mysql32.dll\0Setup=mysql32.dll\0\0" );

/* Inquire about the current usage count. */   SQLInstallDriverEx(         szDriver,         NULL,         szPathIn,         cbPathOutMax,         & cbPathOut,         ODBC_INSTALL_INQUIRY, /* this gets information about                    the pre-existing driver */          & dwUsageCount );

/* Now increment the usage count. */   ++dwUsageCount;

/* Then call SQLInstallDriverEx with the new usage count. */   if( ! SQLInstallDriverEx( szDriver, szPathIn, szPathOut, cbPathOutMax, & cbPathOut, ODBC_INSTALL_COMPLETE, & dwUsageCount ) ) ProcessErrorMessages( "SQLInstallDriverEx" ); }

BOOL InstallMyDriver { char   szDriver[300]; char   szPathIn[301]; char  szPathOut[301]; WORD  cbPathOutMax = 300; WORD  cbPathOut; DWORD  dwUsageCount;

/* The correct format of driver keywords are: "DriverName\0Driver=xxxxxx.DLL\0Setup=xxxxxx.DLL\0\0" */

sprintf( szDriver, "Bogus Driver\0Driver=mysql32.dll\0Setup=mysql32.dll\0\0" );

/* The szDriver array is filled in before calling SQLInstallDriverEx so that SQLInstallDriverEx will return where to install the driver in  the szPathIn */

SQLInstallDriverEx(        szDriver,         NULL,         szPathIn,         cbPathOutMax,         & cbPathOut,         ODBC_INSTALL_INQUIRY,         & dwUsageCount );

/* The correct format of driver keywords are: "DriverName\0Driver=c:\winnt\system32\xxxxxx.DLL\0        Setup=c:\winnt\system32\xxxxxx.DLL\0\0" */

sprintf( szDriver,     "Bogus Driver\0Driver=%s\\mysql32.dll\0Setup=%s\\mysql32.dll\0\0",      szPathIn, szPathIn );

/* Compare the version of the driver and copy it if appropriate; the following files are required for the SQL Server driver: sqlsrv32_dll dbnmpntw_dll drvssrvr_hlp instcat_sql NOTE: For the purposes of this sample code, only Odbc32.dll is        being copied. */   if( ! VersionCheckCopyFile( szPathIn, "C:\\TEMP\\ODBC", DriverDLL ) ) if( ProcessErrorMessages( "SQLInstallDriverEx" ) ) return FALSE;

/* Call SQLInstallDriverEx to install the driver in     Odbcinst.ini and the registry. */   if( ! SQLInstallDriverEx( szDriver, szPathIn, szPathOut, cbPathOutMax, & cbPathOut, ODBC_INSTALL_COMPLETE, & dwUsageCount ) ) if( ProcessErrorMessages( "SQLInstallDriverEx" ) ) return FALSE;

/* Call SQLConfigDriver to exercise the driver's setup functions; some drivers have their setup routines built in, and others require a seperate DLL */ SQLConfigDriver(     NULL,      ODBC_CONFIG_DRIVER,      DriverName,      "CPTimeout=60\0\0",      szPathOut,      cbPathOutMax,      & cbPathOut );

return TRUE; }

BOOL AddMyDSN { char  szDriver[300] = DriverName; char  szAttributes[400];

CreateAttributeString( szAttributes );

/* I choose to remove the DSN if it already existed */ SQLConfigDataSource(        NULL,         ODBC_REMOVE_SYS_DSN,         szDriver,         szAttributes );

/* then create a new DSN */ if( ! SQLConfigDataSource( NULL, ODBC_ADD_SYS_DSN, szDriver, szAttributes ) ) if( ProcessErrorMessages( "SQLConfigDataSource" ) ) return FALSE;

return TRUE; }

/************************************************************* /  This function builds the keyword pair string required by /   SQLConfigDataSource. /*************************************************************/ void CreateAttributeString( char * pszAttributes ) { sprintf( pszAttributes,  "DSN=My Bogus DS\0Server=bottles\0Database=pubs\0UID=sa\0PWD=\0      UseProcForPrepare=yes\0\0" ); }

/* The following functions are not required for ODBC driver and driver manager installation. They are for version checking and file copy of DLLs; they require NO part of the ODBC API. */

BOOL GetFileVersion( char * pFilePath, char * pVersion, UINT uMaxVersionLen ) { DWORD  dwHandle = 0; DWORD  dwVersionInfoSize; DWORD  dwError; PVOID  pFileInfo; PBYTE  pVersionInfo; PDWORD  pTranslation = NULL; UINT  uLength = 0; char  szString[512] = "";

dwVersionInfoSize = GetFileVersionInfoSize(     pFilePath,   /* pointer to filename string */       & dwHandle );   /* pointer to variable to receive zero */ if( ! dwVersionInfoSize ) {     dwError = GetLastError; return FALSE; }

pFileInfo = HeapAlloc( GetProcessHeap, HEAP_ZERO_MEMORY, dwVersionInfoSize ); pVersionInfo = HeapAlloc( GetProcessHeap, HEAP_ZERO_MEMORY, dwVersionInfoSize );

if( ! GetFileVersionInfo( pFilePath,  /* pointer to filename string */ ( DWORD ) dwHandle,  /* ignored */ dwVersionInfoSize,  /* size of buffer */ pFileInfo ) )   /* pointer to buffer to receive file-version info.*/ {     dwError = GetLastError; HeapFree( GetProcessHeap, 0, pFileInfo ); HeapFree( GetProcessHeap, 0, pVersionInfo ); return FALSE; }

if( ! VerQueryValue( pFileInfo,  /* address of buffer for version resource */ TEXT( "\\VarFileInfo\\Translation" ), /* address of value to retrieve & pTranslation,  /* address of buffer for version pointer */ & uLength )  /* address of version-value length buffer */       ) {     dwError = GetLastError; HeapFree( GetProcessHeap, 0, pFileInfo ); HeapFree( GetProcessHeap, 0, pVersionInfo ); return FALSE; }

wsprintf( szString, "\\StringFileInfo\\%04x%04x\\FileVersion",     LOWORD( ( DWORD ) * pTranslation, ), HIWORD( ( DWORD ) * pTranslation ) );

if( ! VerQueryValue( pFileInfo,  /* address of buffer for version resource */ szString, /* address of value to retrieve */ ( PVOID * ) & pVersionInfo,  /* address of buffer for version pointer */ & uLength )  /* address of version-value length buffer */       ) {     dwError = GetLastError; HeapFree( GetProcessHeap, 0, pFileInfo ); HeapFree( GetProcessHeap, 0, pVersionInfo ); return FALSE; }

if( lstrlen( pVersionInfo ) >= ( int ) uMaxVersionLen ) lstrcpyn( pVersion, pVersionInfo, uMaxVersionLen - 1 ); else lstrcpy( pVersion, pVersionInfo );

HeapFree( GetProcessHeap, 0, pFileInfo ); HeapFree( GetProcessHeap, 0, pVersionInfo );

return TRUE; }

BOOL CheckIfFileExists( char * szFilePath, char * szFileName ) { DWORD  nBufferLength = 300; char  szBuffer[300]; LPTSTR  lpFilePart; DWORD  rt;

rt= SearchPath(     szFilePath,   // address of search path      szFileName,   // address of filename      NULL, //LPCTSTR lpExtension,   // address of extension      nBufferLength,   // size, in characters, of buffer      szBuffer,   // address of buffer for found filename      & lpFilePart );    // address of pointer to file component

return rt; }

/********************************************************************* /  szOldPath  is the "to path" /  szNewPath  is the "from path" /  szFileName is the name of the file in the from path /*********************************************************************/ BOOL VersionCheckCopyFile( char * szOldPath, char * szNewPath, char * szFileName ) { char  szOldFile[512]; char  szNewFile[512]; char  szOldFileVersion[ 512 ]; char  szNewFileVersion[ 512 ]; UINT  uVersionLength = 512; int     rt;

if( CheckIfFileExists( szOldPath, szFileName ) ) {     sprintf( szOldFile, "%s\\%s", szOldPath, szFileName );

if( GetFileVersion( szOldFile, szOldFileVersion, uVersionLength ) ) {        sprintf( szNewFile, "%s\\%s", szNewPath, szFileName );

if( GetFileVersion( szNewFile, szNewFileVersion, uVersionLength ) ) {           rt = strcmp( szOldFileVersion, szNewFileVersion ); if( rt < 0 ) CopyFile( szNewFile, szOldFile, FALSE ); return TRUE; }        else return FALSE; }     else return FALSE; }  else {     sprintf( szOldFile, "%s\\%s", szOldPath, szFileName );

sprintf( szNewFile, "%s\\%s", szNewPath, szFileName );

CopyFile( szNewFile, szOldFile, FALSE ); }  return TRUE; } Additional query words: upgrade update

Keywords : kbcode kbprg SSrvProg odbcAPI

Issue type : kbinfo

Technology :