用c++实现在局域网中客户机端对服务器数据库的访问

VC中实现对ADO操作通常有三种方法:    
   
  #import方法;    
   
  利用MFC   OLE的ClassWizard;    
   
  通过Windows   API中COM相关的函数。    
   
  在这三种方法中,#import是最方便的方法,它允许产生一个类似VB的类结构,使程序开发变得很方便。下面分别介绍这三种方法。    
   
  1.#import方法    
   
  在#import方法中,需要提供所要包含的类型库的路径和名称,VC能够自动产生一个对GUIDs的定义,以及自动生成对ADO对象的封装。对任何引用的类型库,VC会在编译的时候自动生成两个文件:    
   
  头文件(.tlh):包含了所列举的类型和对类型库中对象的定义;    
   
  实现文件(.tli):对类型库对象模型中的方法产生封装。    
   
  例如,在stdafx.h文件中增加对msado15.dd的    
   
  #import之后,VC会产生msado15.tlh和msado15.tli两个文件。    
   
  #import能够使用一个新的类_com_ptr_t,它也被称为智能指针。智能指针能够自动执行QuyerInterface、AddRef和Release函数。    
   
  下面的代码演示了如何使用#import在应用中实现对ADO的操作:    
   
  #import   “c:/program   files/common   files/system/ado/msado15.dll”   /no_namespace    
   
  rename   (   “EOF”,   “adoEOF”   )    
   
  重命名EOF是必要的,因为典型的VC应用都已经定义了EOF作为常数-1。    
   
  通常来说,操作一个自动化对象需要定义和初始化一个用来操作的变量。可以通过使用智能指针    
   
  (_com_ptr_t)的构造函数传递一个有效的CLSID或者是PROGID,也可以通过_com_ptr_t::CreateInstance()方法来定义对象。具体代码如下所示:    
   
  _ConnectionPtr   Conn1(   __uuidof(   Connection   )   );    
   
  也可以采用下面的代码实现同样的功能:    
   
  _ConnectionPtr   Conn1   =   NULL;   //定义对象    
   
  HRESULT   hr   =   S_OK;    
   
  //创建实例    
   
  hr   =Conn1.CreateInstance(   __uuidof(   Connection   )   );    
   
  推荐采用第二种方式,因为用第一种方式不能返回一个失败的HRESULT,所以也就不能判断ADO连接对象是成功还是失败,以及失败的原因。注意这里的__uuidof(   Connection)中的Connection是在.tlh文件中定义的。通过把它传递给方法CreateInstance,就可以创建一个有效的ADOConnection对象。    
   
  需要注意的是#import的no_namespace属性,它告诉编译器该类在不在一个单独的名字空间中。使用no_namespace意味着不需要在初始化变量时引用名字空间。当然如果在应用中需要导入多个类型库时,最好不要使用no_namespace,以免引起名字冲突。    
   
  下面是一个简单的采用了#import方法的基于ADO应用的示例代码:    
   
  #include   <windows.h>    
   
  #import   <msado15.dll>   rename(“EOF”,   “adoEOF”)    
   
  void   main()    
   
  {    
   
  HRESULT   hr   =   S_OK;    
   
  //因为没有在#import中指定no_namespace,所以必须采用ADODB::这样的形式来定义变量类型    
   
  ADODB::_RecordsetPtr   Rs1   =   NULL;    
   
  //通过ODBC建立ADO连接    
   
  _bstr_t   Connect(   “DSN=AdoDemo;UID=sa;PWD=;”   );    
   
  _bstr_t   Source   (   “SELECT   *   FROM   Authors”   );    
   
  CoInitialize();    
   
  //初始化Rs1对象    
   
  hr   =   Rs1.CreateInstance(   __uuidof(   ADODB::Recordset   )   );    
   
  //省略对返回值hr的判断    
   
  Rs1->Open(   Source,    
   
          Aonnect,    
   
          ADODB::adOpenForwardOnly,    
   
          ADODB::adLockReadOnly,    
   
        -1   );    
   
  //此处可以添加对记录集Rs1进行操作的代码    
   
  Rs1->Close();    
   
  Rs1   =   NULL;    
   
  ::MessageBox(   NULL,“Success!”,“”,MB_OK   );    
   
  CoUninitialize();    
   
  }    
   
  2.用MFC   OLE创建ADO应用    
   
  MFC   OLE同样能够封装(wrapper)一个类型库,但是与#import不同,它不能从类型库中产生枚举类型。MFC类CString和COleVariant隐藏了BSTRS和Variants的细节。由MFC   OLE产生的类都继承了类ColeDispatchDriver,由ADO产生的失败的HRESULTS被封装在类ColeDispatchException中。    
   
  用MFC   OLE   ClassWizard创建ADO应用的步骤如下:    
   
  从Tools菜单中,选择Options选项中的Directories   tab条目,在Show   Directories中的Library   Files中增加路径C:/program   files/common   files/system/ado,设置包含ADO类型库的路径。    
   
  从View菜单中,激活ClassWizard,点击Add   Class按钮并选择“From   A   Type   Library...”选项,然后在Type   Library   dialog   box对话框中,从C:/program   files/common   files/system/ado中选择文件msado15.dll,在Confirm   Classes对话框中,选择所有列出的类并按OK按钮退出ClassWizard。这样,ClassWizard便生成了两个文件msado15.h和msado15.cpp。    
   
  下面是实现ADO应用的示例代码:    
   
  //初始化COM对象    
   
  AfxOleInit();    
   
  ...    
   
  //定义数据集对象    
   
  _Recordset   Rs1;    
   
  COleException   e;    
   
  COleVariant   Connect(   “DSN=AdoDemo;UID=sa;PWD=;”   );    
   
  COleVariant   Source   (   “SELECT   *   FROM   Authors”   );    
   
  //创建数据集对象    
   
  Rs1.CreateDispatch(“ADODB.Recordset.2.0”,&e   );    
   
  Rs1.Open(   (VARIANT)   Source,    
   
  (VARIANT)   Connect,    
   
  0,   1,   -1   );    
   
  //此处可以添加对结果集Rs1进行处理的代码    
   
  Rs1.Close();    
   
  Rs1.ReleaseDispatch();    
   
  AfxMessageBox(“Success!”);    
   
  3.用COM   API创建ADO工程    
   
  #import和MFC   OLE都围绕着一个给定的自动化对象产生了一个封装类,它们分别继承自_com_ptr_t和ColeDispatchDriver。其实也可以通过使用Windows   API函数直接初始化ADO对象。为了直接使用ADO和COM对象,需要添加两个头文件adoid.h和adoint.h,这两个头文件定义了CLSIDs、接口定义和操作ADO类型库所需要的枚举类型。此外,还需要增加头文件INITGUID.H。    
   
  为了能够编译用COM   API创建的ADO工程文件,还需要在机器中安装OLE   DB   SDK或者是MSDASDK工具。下面是利用API创建ADO的简单的示例代码:    
   
  #include   <windows.h>    
   
  #include   <initguid.h>    
   
  #include   “adoid.h”   //   ADO的GUID's    
   
  #include   “adoint.h”   //   ADO的类、枚举等等    
   
  void   main()    
   
  {    
   
  HRESULT   hr   =   S_OK;    
   
  //   ADORecordset   是在adoint.h中定义的    
   
  ADORecordset*Rs1   =   NULL;    
   
  VARIANT   Source;    
   
  VARIANT   Connect;    
   
  VariantInit(   &Source   );    
   
  VariantInit(   &Connect   );    
   
  Source.vt   =   VT_BSTR;    
   
  Source.bstrVal   =   ::SysAllocString(   L“SELECT   *   FROM   Authors”);    
   
  Connect.vt   =   VT_BSTR;    
   
  Connect.bstrVal   =   ::SysAllocString(   L“DSN=AdoDemo;UID=sa;PWD=;”   );    
   
  hr   =   CoCreateInstance(   CLSID_CADORecordset,    
   
  NULL,    
   
  CLSCTX_INPROC_SERVER,    
   
  IID_IADORecordset,    
   
  (LPVOID   *)   &Rs1   );    
   
  if(   SUCCEEDED(   hr   )   )   hr   =   Rs1->Open    
   
  (Source,    
   
  Connect,    
   
  adOpenForwardOnly,    
   
  adLockReadOnly,    
   
  -1   );    
   
  //对记录集Rs1进行处理    
   
  if(   SUCCEEDED(   hr   )   )   hr   =   Rs1->Close();    
   
  if(   SUCCEEDED(   hr   )   )   {   Rs1->Release();   Rs1   =   NULL;   }    
   
  if(   SUCCEEDED(   hr   )   )   ::MessageBox(   NULL,   “Success!”,   “”,   MB_OK   );    
   
  }    
   
  C++   Extensions    
   
  如果用C++进行ADO应用程序开发,应该使用ADO   C++   Extensions。我们知道,用VB或者VBScript来操作ADO是非常方便的,但是如果使用C++或者是Java,就必须要处理类似Variants这样的数据结构以实现和C++数据结构的转换,而这种处理无疑是所有C++开发人员都很头疼的事情。但如果使用C++   Extensions的话,ADO就不需要从数据提供者处得到列信息,而是在设计时刻使用开发人员提供的列信息。以下是一个简单的示例:    
   
  //创建和具体记录相对应的类    
   
  class   CAuthor   :   public   CADORecordBinding    
   
  {    
   
  BEGIN_ADO_BINDING(CCustomRs1)    
   
  ADO_VARIABLE_LENGTH_ENTRY4(1,    
   
  adVarChar,   m_szau_id,   sizeof(m_szau_id),   FALSE)    
   
  ADO_VARIABLE_LENGTH_ENTRY4(2,    
   
  adVarChar,m_szau_fname,sizeof(m_szau_fname),   FALSE)    
   
  ADO_VARIABLE_LENGTH_ENTRY4(3,    
   
  adVarChar,m_szau_lname,sizeof(m_szau_lname),   FALSE)    
   
  END_ADO_BINDING()    
   
  protected:    
   
  char   m_szau_id[12];    
   
  char   m_szau_fname[21];    
   
  char   m_szau_lname[41];    
   
  };    
   
  void   FetchAuthorData()    
   
  {    
   
  CAuthor   author;    
   
  //记录集对象    
   
  _RecordsetPtr   pRs;    
   
  IADORecordBinding   *piAdoRecordBinding;    
   
  //获取COM对象接口指针    
   
  pRs.CreateInstance(__uuidof(Recordset));    
   
  //得到需要的记录集    
   
  pRs->Open(“select   au_id,au_fname,au_lname   from   Employees”,“Provider=SQLOLEDB;Data   Source=sureshk1;Database=pubs;User   Id=sa;Password=;”,    
   
  adOpenForwardOnly,    
   
  adLockReadOnly,    
   
  adCmdText);    
   
  //查询接口IADORecordBinding    
   
  pRs->QueryInterface(__uuidof(IADORecordBinding),(LPVOID*)&piAdoRecordBinding);    
   
  //绑定对象    
   
  piAdoRecordBinding->BindToRecordset(&author);    
   
  //得到记录中的相关内容    
   
  while   (VARIANT_FALSE   ==   pRs->EOF)   {    
   
  printf(“%s   %s   %s”,   author.m_szau_id,    
   
  author.m_szau_fname,   author.m_szau_lname);    
   
  pRs->MoveNext();    
   
  }    
   
  //释放对象    
   
  piAdoRecordBinding->Release();    
   
  }   
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------1.配置ODBC,建立ODBC和SQL   SERVER的连接ODBCTEST  
  2.在VC++通过该ODBC调用SQL   SERVER的STORED   PROCEDURE(szTypes   )  
  #include   "stdafx.h"  
  #include   "DatabaseServer.h"  
  #include   <stdarg.h>  
   
  #ifdef   _DEBUG  
  #undef   THIS_FILE  
  static   char   THIS_FILE[]=__FILE__;  
  #define   new   DEBUG_NEW  
  #endif  
   
  //  
  //   Construction/Destruction  
  //  
   
  CDatabaseServer::CDatabaseServer()  
  {  
   
  }  
   
  CDatabaseServer::~CDatabaseServer()  
  {  
   
  }  
   
  bool   CDatabaseServer::getConnectionString(char   *szConnectionString)  
  {  
  char   szServerName[MAX_COMPUTERNAME_LENGTH   +   1];  
  DWORD   dwSize=sizeof(szServerName)   ;  
  if(!GetComputerName(szServerName,&dwSize))  
  return   false   ;  
   
   
  if(!szConnectionString)  
  return   false   ;  
   
  char   szUserName[]   =   "SA";  
  char   szPassword[]   =   "";  
  char   szDatabase[]   =   "IPLOMA";//ADD   YOU   DATEBASE   NAME  
   
  sprintf(szConnectionString,"DSN=ODBCTEST;uid=%s;pwd=%s;",szServerName,szDatabase,szUserName,szPassword);   //建立CONNECTION   STRING  
   
  return   true;  
  }  
   
  VARIANT   CDatabaseServer::getExecStoredProcedure(char   *szTypes,SAFEARRAY   *pSPFields)  
  {  
          _variant_t   vtResultRows;  
          try  
          {  
  _CommandPtr       pCmdPtr;  
                  _RecordsetPtr   pRecordset;  
                  HRESULT   hr   ;    
   
  hr   =   pCmdPtr.CreateInstance(__uuidof(Command));  
   
  char   szConnectionString[255];  
  getConnectionString(szConnectionString);  
  _variant_t   vtConnectionString(szConnectionString);  
  pCmdPtr->put_ActiveConnection(vtConnectionString);  
   
                  pCmdPtr->CommandType   =   adCmdStoredProc;   //CALL   SQL   SP  
  pCmdPtr->CommandText   =     szTypes   ;   //YOU   SP   NAME  
  hr   =   pCmdPtr->Parameters->Refresh();  
   
        long   lBound,uBound   ;  
        HRESULT   hresult   ;  
        //   Getting   Safe   Array's   Lower   and   Upper   Bounds  
        hresult   =   SafeArrayGetLBound(pSPFields,   1,   &lBound);  
              hresult   =   SafeArrayGetUBound(pSPFields,   1,   &uBound);  
   
        variant_t   vtParamVal;  
  _variant_t   Index;  
  Index.vt   =   VT_I2;  
  Index.iVal   =   1   ;  
        for   (long   iElements=lBound;iElements<=uBound;iElements++)  
        {  
  hresult   =   SafeArrayGetElement(pSPFields,   &iElements,   &vtParamVal);  
  pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal)   ;  
  Index.iVal++   ;  
        }  
   
        //Execute   current   Stored   Procedure  
                  _variant_t   vEffected   ;  
  pRecordset   =   pCmdPtr->Execute(&vEffected,NULL,NULL);  
  if   (pRecordset->BOF   ||   pRecordset->EndOfFile)  
  throw   ;  
  //   Get   result   set   in   the   form   of   array  
                  vtResultRows   =   pRecordset->GetRows(-1);  
                  return   vtResultRows.Detach()   ;  
  }  
  catch(_com_error   &e)  
          {  
  ATLTRACE((LPCSTR)e.Description());  
          }  
  vtResultRows.vt   =   VT_EMPTY   ;  
          return   vtResultRows.Detach();  
  }  
   
  long   CDatabaseServer::setExecStoredProcedure(char   *szTypes,SAFEARRAY   *pSPFields)  
  {  
          _variant_t   vtResultRows;  
          try  
          {  
                  _CommandPtr       pCmdPtr;  
                  _RecordsetPtr   pRecordset;  
                  HRESULT   hr   ;    
   
  hr   =   pCmdPtr.CreateInstance(__uuidof(Command));  
   
  char   szConnectionString[255];  
  getConnectionString(szConnectionString);  
  _variant_t   vtConnectionString(szConnectionString);  
  pCmdPtr->put_ActiveConnection(vtConnectionString);  
   
                  pCmdPtr->CommandType   =   adCmdStoredProc;  
  pCmdPtr->CommandText   =     szTypes   ;  
  hr   =   pCmdPtr->Parameters->Refresh();  
   
        long   lBound,uBound;  
        HRESULT   hresult;  
        //   Getting   Safe   Array's   Lower   and   Upper   Bounds  
        hresult   =   SafeArrayGetLBound(pSPFields,   1,   &lBound);  
              hresult   =   SafeArrayGetUBound(pSPFields,   1,   &uBound);  
   
        variant_t   vtParamVal;  
  _variant_t   Index;  
  Index.vt   =   VT_I2;  
  Index.iVal   =   1   ;  
        for   (long   iElements=lBound;iElements<=uBound;iElements++)  
        {  
  hresult   =   SafeArrayGetElement(pSPFields,   &iElements,   &vtParamVal);  
  pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal)   ;  
  Index.iVal++   ;  
        }  
   
                  _variant_t   vEffected   ;  
  pCmdPtr->Execute(&vEffected,NULL,NULL);  
   
  //   We   Are   Expecting   That   Stored   Procedures   Return   ID   for   Entity   to   which    
  //   NSERT/UPDATE/DELETE     operation   is   being   performed  
                  return   (long)pCmdPtr->Parameters->Item["RETURN_VALUE"]->Value     ;  
          }  
          catch(_com_error   &e)  
          {  
                ATLTRACE((LPCSTR)e.Description());  
          }  
          return   0;  
  } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值