[转载]ODBC 编程心得

原文:http://blog.csdn.net/haoyuenan/article/details/1525791

1.1
申请环境句柄(SQLAllocHandle)
设置环境句柄(SQLSetEnvAttr)
申请连接句柄(SQLAllocHandle)
连接数据源(SQLConnect)
设置连接属性(SQLSertConnect)
连接阶段
设置驱动程序信息(SQLGetInfo)
申请语句句柄(SQLAllocHandle)
设置语句属性(SQLSetStmt)
初始化阶段
程序主体
执行语句、处理结果和提交事务

ODBC应用程序结构
 
1.2
释放语句句柄(SQLFreeHandle)
断开数据源连接(SQLDisconnect)
 
释放连接句柄(SQLFreeHandle)
 
结束部分
释放环境句柄(SQLFreeHandle)

利用ODBC API函数完成对ODBC数据源的连接
int CManuODBC::InitODBC(SQLCHAR *szDsn, SQLCHAR *szUserID, SQLCHAR *szPassword)
{
       SQLRETURN retcode;
       SQLHENV hEnv;
       SQLHDBC hDbc;
       SQLHSTMT hStmt;
       retcode = SQLAllocHandle( SQL_HANDLE_ENV, NULL, &hEnv );
       if ( retcode != SQL_SUCCESS )
              return RT_ERROR;
       else
        SetEnv( hEnv );
      
       retcode = SQLSetEnvAttr( m_hEnv, SQL_ATTR_ODBC_VERSION,
                             ( SQLPOINTER )SQL_OV_ODBC3, SQL_IS_INTEGER );
       if ( retcode != SQL_SUCCESS )
              return RT_ERROR;    
       retcode = SQLAllocHandle( SQL_HANDLE_DBC, m_hEnv, &hDbc );
       if ( retcode != SQL_SUCCESS )
              return RT_ERROR;
       else
              SetDbc( hDbc );
       try
       {
           retcode = SQLConnect( m_hDbc,
                              szDsn, ( SWORD )strlen( ( char* )szDsn ),
                              szUserID, ( SWORD )strlen( ( char* )szUserID ),
                              szPassword, ( SWORD )strlen( ( char* )szPassword ) );
       }
       catch( ... )
       {
              DispErrMsg( hStmt, retcode );
              return RT_ERROR;
       }
    retcode = SQLAllocHandle( SQL_HANDLE_STMT, hDbc, &hStmt );
       if ( retcode != SQL_SUCCESS )
       {
              DispErrMsg( hStmt, retcode );
              return RT_ERROR;
       }
       else
              SetStmt( hStmt ); 
       return RT_OK;
}
1.3 利用ODBC API函数执行SQL语句
int CManuODBC::ExecSQL( CString strManuDB )
{
       SQLRETURN retcode;
       SQLHSTMT hstmt = this->GetStmt();    
             
       retcode = SQLPrepare( hstmt, ( SQLCHAR* )( LPSTR )( LPCSTR )strManuDB, SQL_NTS );      
      
       if ( retcode != SQL_SUCCESS )
       {
              return RT_ERROR;
       }
 
       try
       {
              retcode = SQLExecute( hstmt );
              if ( retcode != SQL_SUCCESS )
              {
                     throw retcode;
              }
       }
       catch( SQLRETURN &rtcde )
       {
        DispErrMsg( hstmt, retcode );
              return RT_ERROR;
       }
       catch( ... )
       {
              AfxMessageBox( "发生异常,中止导入!" );
              return RT_ERROR;
       }
      
       //retcode = SQLBindCol( hstmtNew, 1, SQL_C_CHAR, szName, MAXNAME, &cbName );
       //SQLNumResultCols( hstmtNew, &nNum );        
      
       /*while ( SQLFetch( hstmt ) != SQL_NO_DATA )
       {           
              if ( retcode == SQL_ERROR ) 
              {
            return; 
              }
              if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
              {                                                                             
              }           
       }*/
 
       return RT_OK;
}
1.4 自定义配置文件的读取
BOOL CTableInfo::ReadProfile(HANDLE hFile)
{        
    ULONG uBytesWrite = 0;
    ULONG uFileSize = 0;
      
       int nTbCnt;
       char szInitFile[ 128 ];
       CString strSecName, key1, key2, key3, strCurSecName;
       CArray< DBTableConfig, DBTableConfig> tbConfig;
       DBTableConfig tbConfigA;
 
       strcpy( szInitFile, ".//DispTableConfig.INI" );
       //strcpy( szInitFile, ".//EvtTableConfig.INI" );
  
//自定义配置文件格式如下
/*[Gerneral]
ODBCNum = 3
 
[001]
Dsn = DBHistory
UID = sa
PSD = 1
 
[002]
Dsn = DBData
UID = sa
PSD = 1
 
[003]
Dsn = DBEvt
UID = sa
PSD = 1*/
//读取自定义配置文件中的整形变量
    /* UINT GetPrivateProfileInt(
         LPCTSTR lpAppName, // address of section name
         LPCTSTR lpKeyName, // address of key name
         INT nDefault, // return value if key name is not found
         LPCTSTR lpFileName // address of initialization filename
);
   */
       nTbCnt = ::GetPrivateProfileInt( "General", "tbCount", NULL, szInitFile );
       tbConfig.SetSize( nTbCnt );   
 
    WriteFile( hFile, &nTbCnt, sizeof( int ), &uBytesWrite, NULL );
 
       for( int i=0; i<nTbCnt; i++ )
       {
              strSecName.Empty();
             
              if( i < 10 )
                     strCurSecName.Format( "00%d", i+1 );
              else
                     strCurSecName.Format( "0%d", i+1 );                 
             
              memset( &tbConfig[i], 0, sizeof( tbConfigA ) );
 
       //读取自定义配置文件中的字符串变量
       /* DWORD GetPrivateProfileString(
             LPCTSTR lpAppName,       // points to section name
             LPCTSTR lpKeyName,       // points to key name
             LPCTSTR lpDefault,    // points to default string
             LPTSTR lpReturnedString, // points to destination buffer
             DWORD nSize,         // size of destination buffer
             LPCTSTR lpFileName   // points to initialization filename
);*/
      //读取自定义配置文件中的结构体
      /*BOOL GetPrivateProfileStruct(
         LPCTSTR lpszSection, // address of section name
         LPCTSTR lpszKey,      // address of key name
         LPVOID lpStruct,      // address of return buffer
         UINT uSizeStruct,     // size of return buffer
         LPCTSTR szFile // address of initialization filename
);*/
              ::GetPrivateProfileString( strCurSecName, "TbName", "", tbConfig[i].szTbName, sizeof( tbConfig[i].szTbName), szInitFile );
              WriteFile( hFile, tbConfig[i].szTbName, sizeof( tbConfig[i].szTbName ), &uBytesWrite, NULL );
              ::GetPrivateProfileString( strCurSecName, "tbChiDesc", "", tbConfig[i].szTbChiDesc, sizeof( tbConfig[i].szTbChiDesc), szInitFile );
              WriteFile( hFile, tbConfig[i].szTbChiDesc, sizeof( tbConfig[i].szTbChiDesc ), &uBytesWrite, NULL );
 
              tbConfig[i].nTbSrcCount = ::GetPrivateProfileInt( strCurSecName, "tbSrcCount", NULL, szInitFile );
              WriteFile( hFile, &tbConfig[i].nTbSrcCount, sizeof( int ), &uBytesWrite, NULL );
 
              ::GetPrivateProfileString( strCurSecName, "tbSrcInfo", "", tbConfig[i].szTbSrcInfo, sizeof( tbConfig[i].szTbSrcInfo), szInitFile );
              GetFieldInfo( tbConfig[i].szTbSrcInfo, hFile );
 
              tbConfig[i].nTbFieldCount = ::GetPrivateProfileInt( strCurSecName, "tbFieldCount", NULL, szInitFile );
              WriteFile( hFile, &tbConfig[i].nTbFieldCount, sizeof( int ), &uBytesWrite, NULL );
 
              ::GetPrivateProfileString( strCurSecName, "tbFieldInfo", "", tbConfig[i].szTbFieldInfo, sizeof( tbConfig[i].szTbFieldInfo ), szInitFile );
              GetFieldInfo( tbConfig[i].szTbFieldInfo, hFile );
 
              /*for( int j=1; j<=tbConfig[i].CmdTran; j++ )
              {
                     key1.Format( "Tran_0%d_Sql", j );
                     key2.Format( "Tran_0%d_Para", j );
                     key3.Format( "Tran_0%d_Col", j );
                    
                     switch( j )
                     {
                     case 1:
                            {
                                   memset( tbConfig[i].Tran_01_Col, 0, 256 );
                                   memset( tbConfig[i].Tran_01_Para, 0, 256 );
                                   memset( tbConfig[i].Tran_01_Sql, 0, 1024 );
                                   ::GetPrivateProfileString( strCurSecName,key1, "", tbConfig[i].Tran_01_Sql, sizeof(tbConfig[i-1].Tran_01_Sql ), szInitFile );
                                   ::GetPrivateProfileString( strCurSecName,key2, "", tbConfig[i].Tran_01_Para, sizeof(tbConfig[i-1].Tran_01_Para ), szInitFile );
                                   //tbConfig[i-1].Para1_Len=GetParaNum(tbConfig[i-1].Tran_01_Para);
                                   ::GetPrivateProfileString(strCurSecName,key3, "", tbConfig[i].Tran_01_Col, sizeof( tbConfig[i-1].Tran_01_Col ), szInitFile );
                                   //取出配置文件中的命令参数
                                   break;
                            }
                     case 2:
                            {
                                   memset( tbConfig[i].Tran_02_Col, 0, 256 );
                                   memset( tbConfig[i].Tran_02_Para, 0, 256 );
                                   memset( tbConfig[i].Tran_02_Sql, 0, 1024 );
                                   ::GetPrivateProfileString( strCurSecName,key1, "", tbConfig[i].Tran_02_Sql, sizeof( tbConfig[i-1].Tran_02_Sql ), szInitFile );
                                   ::GetPrivateProfileString( strCurSecName,key2, "", tbConfig[i].Tran_02_Para, sizeof( tbConfig[i-1].Tran_02_Para ), szInitFile );
                                   //tbConfig[i-1].Para2_Len=GetParaNum(tbConfig[i-1].Tran_02_Para);
                                   ::GetPrivateProfileString( strCurSecName, key3,"", tbConfig[i].Tran_02_Col, sizeof( tbConfig[i-1].Tran_02_Col ), szInitFile );
                                   break;
                            }
                     case 3:
                            {
                                   memset( tbConfig[i].Tran_03_Col, 0, 256 );
                                   memset( tbConfig[i].Tran_03_Para, 0, 256 );
                                   memset( tbConfig[i].Tran_03_Sql, 0, 1024 );
                                   ::GetPrivateProfileString( strCurSecName,key1, "", tbConfig[i].Tran_03_Sql, sizeof( tbConfig[i-1].Tran_03_Sql ),szInitFile );
                                   ::GetPrivateProfileString( strCurSecName,key2, "", tbConfig[i].Tran_03_Para, sizeof( tbConfig[i-1].Tran_03_Para ),szInitFile );
                                   //tbConfig[i-1].Para3_Len=GetParaNum(tbConfig[i-1].Tran_03_Para);
                                   ::GetPrivateProfileString( strCurSecName,key3, "", tbConfig[i].Tran_03_Col, sizeof( tbConfig[i-1].Tran_03_Col ), szInitFile );
                                   break;
                            }
                     default:
                            break;
                     }
              }*/
       }
   
       return TRUE;
}
1.5 ODBC API函数中的对参数绑定的实现
/*SQLRETURN SQLBindParameter( SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber, SQLSMALLINT InputOutputType, SQLSMALLINT ValueType, SQLSMALLINT ParameterType, SQLUINTEGER ColumnSize, SQLSMALLINT DecimalDigits, SQLPOINTER ParameterValuePtr, SQLINTEGER BufferLength, SQLINTEGER StrLen_or_IndPtr);
*/
   /*注意:
参数一为申请的语句句柄;hStmt
参数二为参数编号;如SQL语句为INSERT INTO T1(value1,value2) VALUES(?,?),则1就代表对value1字段进行的绑定,2亦然
参数三为参数类型,输入或输出,通常为SQL_PARAM_INPUT或者SQL_PARAM_OUTPUT
参数四为参数的ODBC C类型;
参数五为参数的ODBC API类型;C和API类型必须一一对应,且与缓冲区数据类型对应;
参数六为其所在列的长度;一般整型和单精度浮点型为4,双精度浮点型为8等等,字符串类型为创建表是定义的该字段的字符串长度
参数七为参数所对应的小数点位数;
参数八为参数所对应的缓冲区;
参数九为缓冲区长度,整型、浮点型或者日期型等均为&nX(SQLINTEGER nX = 0;)
参数九在参数为整型、浮点型或日期型时为0,参数为字符串时为&nX (SQLINTEGER nX = SQL_NTS;);
*/
retcode = SQLPrepare( hstmt, ( SQLCHAR* )( LPSTR )( LPCSTR )strInsertSQL, SQL_NTS );
       if ( retcode != SQL_SUCCESS )
       {
              return RT_ERROR;
       }
switch ( pField->GetType() )
            {
            case DATA_INTEGER:
 
                if ( pField->GetLength() > 1 )
                {
                    CString strFieldName = pField->GetName();
                                   int nFieldSize = pField->GetSize();                              
                             }
                else
                {                            
                                   pIntType[nCurIntTypeCount] = *(int* )pData;
                                  
                                   retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 4, 0, &pIntType[nCurIntTypeCount], 0, &cbInteger );
                }
                nDataOffset = nDataOffset + pField->GetSize();
                            nCurIntTypeCount++;
                break;
            case DATA_FLOAT_SINGLE:
                if ( pField->GetLength() > 1 )
                {
                }
                else
                {
                    float fValue = *( float* )pData;                                
                                   retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 4, 0, &fValue, 0, &cbFloat );
                             }
                nDataOffset = nDataOffset + pField->GetSize();
                break;
            case DATA_DATETIME:
            case DATA_DATETIME_SECOND:
            case DATA_DATETIME_MINUTE:
            case DATA_DATETIME_MONTH:
            case DATA_DATETIME_HOUR:
            case DATA_DATETIME_WEEK:
            case DATA_DATETIME_USECOND:
            {               
                            strTime = ( char* )pData;
                            SQL_TIMESTAMP_STRUCT tm;
 
                            tm = FormatTime( strTime );                          
 
                            retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 8, 0, &tm, 0, &cbTime );
                nDataOffset = nDataOffset + SIZE_TIMESTR;
                break;
            }
            case DATA_STRING:    
                retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, pField->GetSize() - 1, 0, pData, pField->GetSize(), &cbChar );
                            nDataOffset = nDataOffset + pField->GetSize();
                break;
            case INVALID_FIELD_TYPE:
                return RT_ERROR;
            default:
                return RT_ERROR;
            }
retcode = SQLExecute( hstmt );
1.6 多线程编程
DWORD WINAPI DumpThread( LPVOID lpParam )
{
    CDumpDataToDBDlg* pThis = ( CDumpDataToDBDlg* )lpParam;
    CUsbDirectory* pUsbDirectory = NULL;   
       pThis->m_bStillRun = TRUE;    
    pUsbDirectory = new CUsbDirectory( pThis->m_strFilePath, NULL );
       pUsbDirectory->SetMonitorID( 231 );
 
       MSG Msg;
       char* pInfo = new char[20];
       int nMonitorID = 0;
       //创建消息队列
/*BOOL PeekMessage(
       LPMSG lpMsg,        // pointer to structure for message
       HWND hWnd,           // handle to window
       UINT wMsgFilterMin, // first message
       UINT wMsgFilterMax, // last message
       UINT wRemoveMsg      // removal flags
);*/
/*参数一为指向消息结构体的指针(MSG);
参数二为接收消息的窗体句柄;
参数三为所接收消息的下限值(WM_USER + 1);
参数四为所接收消息的上限值(WM_USER + 100),按上述设置则只接收范围在[WM_USER+1,WM_UESR+100]之间的消息;
参数五为是否将接收到的消息移出消息对列(PM_NOREMOVE/ PM_REMOVE)*/   
       PeekMessage( &Msg, NULL, WM_USER, WM_USER, PM_NOREMOVE );
 
       /*if ( !SetEvent( pThis->m_hThreadEvent ) )
       {
              return 0;
       }           
 
       //等待消息
       while( GetMessage( &Msg, 0, 0, 0 ) )
       {
              switch ( Msg.message )
              {
              case UDM_GET_FILE:
                     //pInfo = ( char* )Msg.wParam;
                     nMonitorID = ( int )Msg.wParam;*/
            //处理收到的消息
                     try
                     {
                            //pUsbDirectory->SetMonitorID( nMonitorID );   
                            pUsbDirectory->DumpDirectory();
                     }
                     catch(...)
                     {
                            AfxMessageBox( "发现异常,终止导入!" );
                     }                                
                           
                     delete pInfo;               
                     /*break;
              default:
                     break;
              }
       }*/
 
       delete pUsbDirectory;
      
       pThis->m_bStillRun = FALSE;
   
    return 0;
}
 
void CDumpDataToDBDlg::OnBtnStart()
{
m_hDumpData = CreateThread( NULL, 0, DumpThread, ( void* )this, 0, NULL );      
}
1.7 获取当前目录
/*DWORD GetModuleFileName(
HMODULE hModule,//handle to module to find filename for
      LPTSTR lpFilename, // pointer to buffer to receive module path
      DWORD nSize         // size of buffer, in characters
); */
GetModuleFileName( NULL, szDtFilePath, MAX_PATH ),返回值大于或等于0时函数执行成功!
1.8 利用ODBCAPI函数插入或修改二进制数据
BOOL main()
CString strInsertSQL = "Update ";
       strInsertSQL += strTableName;
    strInsertSQL += strTypeSuffix;
       strInsertSQL += " Set ";
    strInsertSQL += strFieldName;
       strInsertSQL += " = ? Where f_Time = ?";   
 
       void* pData = NULL;
       SQLHSTMT hstmt = pODBC->GetStmt();
       SQLRETURN retcode;
       SQL_TIMESTAMP_STRUCT tmNew;
       SDWORD cbBinary = SQL_LEN_DATA_AT_EXEC( MAX_BLOB_DATA_LENGTH );
      
   //准备执行SQL语句
       retcode = SQLPrepare( hstmt, ( SQLCHAR* )( LPSTR )( LPCSTR )strInsertSQL, SQL_NTS );
 
       SDWORD cbTime = 0;
 
   //绑定参数列
       retcode = SQLBindParameter( hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, MAX_BLOB_DATA_LENGTH, 0, pData, 0, &cbBinary );
       retcode = SQLBindParameter( hstmt, 2, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 8, 0, &tmNew, 0, &cbTime );
      
       tmNew = tm;
       pData = data;
 
   //执行SQL语句
       retcode = SQLExecute( hstmt );
       SQLPOINTER pToken;
       SQLINTEGER cbData = MAX_BLOB_DATA_LENGTH;
       //向绑定的参数列传递数据
retcode = SQLParamData( hstmt, &pToken );     
 
       while ( retcode == SQL_NEED_DATA )
       {
       //开始传递                                     
              retcode = SQLPutData( hstmt, pData, cbData );
              //pData = ( char* )data + MAX_BLOB_DATA_LENGTH;
       //完成数据传递
              retcode = SQLParamData( hstmt, &pToken );             
       }
 
       return RT_OK;

}  

1.9 代码撰写原则
l        尽量不要乱用指针,如果非要用到指针,在进行动态内存申请时,必须对指针进行初始化,并且在使用完毕后释放指针所指向的内存。例如:
int* p = NULL;
p = new int;
……
delete p;
 
float* p = NULL;
p = new float[10];
……
delete []p; //注意:此处的[]必须要有,否则不能完全释放掉p指向的内存区域,会造成内存泄漏
 
class A
{
public:
char szName[128],szPsd[128];
A()
{
    memset( szName, 0, sizeof( szName ) );
    memeset( szPsd, 0, sizeof( szPsd ) );
}
};
A* p = NULL;
P = new A[3];
……
delete []p;
l        软件运行的初始化工作必须在撰写代码之前做详细的规划。例如程序在执行一段循环程序,在每一步的循环中都要用到注册表中的一个或几个键值,此时可以在程序初始化时定义一个全局变量,在程序启动时就将要用到的注册表键值全部读入一个结构体中;再比如用ODBC编写数据库程序,则只需建立一个ODBC连接,每次执行新的SQL语句时只需重新申请语句句柄即可,这样即可以节省数据库操作时间,又使程序出错机会大大减少。
l        变量命名的规则必须自始至终保持一贯性
1.10 读取注册表
bool ReadHKey( void )
{
HKEY hkey = HKEY_LOCAL_MACHINE;
       DWORD len;
       DWORD type;
    Char szKey1[128], szKey2[128];
       //打开键
       if ( ::RegOpenKeyEx( hkey, "Software//WSPQMC//WSPQMCS", 0, KEY_ALL_ACCESS, &hkey ) == ERROR_SUCCESS )
       {
              len = 128; //设置读取键值的最大长度
              type = REG_SZ; //设置读取键值的类型
       //读取键值
              if ( ::RegSetValueEx( hkey, "DSNHistory", NULL, &type, szKey1, &len ) != ERROR_SUCCESS )
{
                     ::RegCloseKey( hkey );
                     return FALSE;
              }
       //读取新键值,首先重新设置键值长度和类型
              len = 128;
              type = REG_SZ;
              if ( ::RegSetValueEx( hkey, "DSNData", NULL, &type, ( unsigned char* ) szKey2, &len ) != ERROR_SUCCESS )
              {
                     ::RegCloseKey( hkey );
                     return FALSE;
              }
Cstring strKey1,strKey2;
strKey1 = szKey1;
strKey2 = szKey2;
}
return true;
}
1.11 写注册表
bool WriteHKey(void)
{
//打开键
HKEY hkey = HKEY_LOCAL_MACHINE;
DWORD len;
DWORD type;
char szKey[128];
DWORD dwKey = 10;
memset( szKey, 0, 128 );
CString strKey = "NewKey";
memcpy( szKey, ( LPCTSTR )strKey, strKey.GetLength() );
   if ( ::RegOpenKeyEx( hkey, "Software//WSPQMC//WSPQMCS", 0, KEY_ALL_ACCESS, &hkey ) == ERROR_SUCCESS )
   {
      len = sizeof( szKey ); //设置读取键值的最大长度
              type = REG_SZ; //设置读取键值的类型
              //写键值
if ( ::RegSetValueEx( hkey, "myOwnStr", NULL, type, ( unsigned char* )szKey, len ) != ERROR_SUCCESS )
 {
     ::RegCloseKey( hkey );
     return false;
 }
              //写键值,首先重新设置键值长度和类型
 len = sizeof( DWORD );
 type = REG_DWORD;
 if ( ::RegSetValueEx( hkey, "myOwnInt", NULL, type, ( BYTE* )&dwKey, len ) != ERROR_SUCCESS )
 {
     ::RegCloseKey( hkey );
     return false;
 }
   return true;
}
1.12 编译Release版本
在Debug版本中设定的link项,也要在Release下面设置,另外函数体不要写在#ifdef DEBUG与#endif之间,否则程序编译找不到函数的函数体,只定义了函数,而没有函数的实现代码,因为编译Release版本过程中编译器忽略#ifdef DEBUG与#endif之间的所有内容。
1.13 在VC中使用ADO
首先要在CMyApp::InitInstance()函数中加入初始化Com环境
if ( FAILED(::CoInitialize(NULL)) )
{
     ::AfxMessageBox( "Com Init Fail !" );
     ::exit(0);
}
在CMyApp::ExitInstance()函数中加入
::CoUninitialize();
       然后引入ADO库文件,一般是在stdAfx.h文件中添加
#import <msado15.dll> no_namespace rename( "EOF", "adoEOF" )
       这条语句会在工程所在目录生成msado15.tlh和msado15.tli两个文件。
在你的类声明文件中加入智能指针对象实例的定义,做为成员变量,
_ConnectionPtr m_pConn;
_RecordsetPtr m_pRs;
使用之前先初始化,
//初始化ADO成员
TESTHR( m_pConn.CreateInstance(     __uuidof( Connection ) ) );
TESTHR( m_pRs.CreateInstance(    __uuidof( Recordset ) ) );
其中TESTHR定义如下:
void TESTHR(HRESULT x)
{
 if FAILED(x)
        _com_issue_error(x);
};
然后就是连接数据库,获取Recordset……用不着我多说了吧,代码如下:
//Open Connection
TESTHR( m_pConn->Open( strConn/*连接字符串*/, "", "", adConnectUnspecified ) );
//Open table
TESTHR( m_pRs->Open( SQL/*SQL查询语句*/
                 _variant_t((IDispatch*)m_pConn, true),
                 adOpenKeyset,//adOpenForwardOnly,
                 adLockReadOnly,
                 adCmdText) );
1.14 写注册表动态创建SQL Server ODBC数据源
各个参数的意义:
DBServer: 数据库所在主机
DBName:  数据库名称
DSN:   数据源名称
UID:   登陆用户
返回值:
-1: 没有安装SQL Server驱动程序
-2: 其他错误
0: 成功
 
实现函数:
int MakeSQLServerODBCDSN(LPCTSTR DBServer,LPCTSTR DBName,LPCTSTR DSN,LPCTSTR UID)
{
BOOL  bInstallDriver = TRUE;
CRegKey  regKey;
 
LONG lRet = regKey.Open( HKEY_LOCAL_MACHINE, "Software//ODBC//ODBCINST.INI//SQL Server" );
If ( lRet != ERROR_SUCCESS )
{
bInstallDriver = FALSE;
}
else
{
char  szDirverPath[MAX_PATH] = "";
DWORD  dwCount = 100;
lRet=regKey.QueryValue(szDirverPath,"Driver",&dwCount);
if ( ( lRet != ERROR_SUCCESS ) || ( dwCount < 1 ) )
{
       DWORD dwErr = GetLastError();
       BinstallDriver = FALSE;
   }
regKey.Close();
}
if ( !bInstallDriver )
{
return -1;
}
CString  strKeyValueName="Software//ODBC//ODBC.INI//";
StrKeyValueName += DSN;
lRet=regKey.Create(HKEY_LOCAL_MACHINE,strKeyValueName);
if ( lRet != ERROR_SUCCESS )
{
return -2;
}
regKey.SetValue(DBName,"Database");
regKey.SetValue("SQLSrv32.dll","Driver");
regKey.SetValue(DBServer,"Server");
regKey.SetValue(UID,"LastUser");
regKey.m_hKey=HKEY_LOCAL_MACHINE;
regKey.SetKeyValue("Software//ODBC//ODBC.INI//ODBC Data Sources","SQL Server",DSN);
regKey.Close();
return 0;
}
posted @ 2016-01-04 19:46  YBHello  阅读(526)  评论(0编辑  收藏  举报