用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;  
  } 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章