CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
可用分押宝游戏火热进行中... 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  VC/MFC >  基础类

常见问题总结2

楼主yintongshun(左岸思雨)2003-12-02 11:53:22 在 VC/MFC / 基础类 提问

 
  15、Windows   管理规范   (WMI)   是可伸缩的系统管理结构,它采用一个统一的、基于标准的、可扩展的面向对象接口。WMI   为您提供与系统管理信息和基础   WMI   API   交互的标准方法。WMI   主要由系统管理应用程序开发人员和管理员用来访问和操作系统管理信息。  
  WMI   可用于生成组织和管理系统信息的工具,使管理员或系统管理人员能够更密切地监视系统活动。例如,可以使用   WMI   开发一个应用程序,用于在   Web   服务器崩溃时呼叫管理员。  
  将   WMI   与   .NET   框架一起使用  
  WMI   提供了大量的规范以便为许多高端应用程序(例如,Microsoft   Exchange、Microsoft   SQL   Server   和   Microsoft   Internet   信息服务   (IIS))实现几乎任何管理任务。管理员可以执行下列任务:    
  •   监视应用程序的运行状况。    
  •   检测瓶颈或故障。    
  •   管理和配置应用程序。    
  •   查询应用程序数据(使用对象关系的遍历和查询)。    
  •   执行无缝的本地或远程管理操作。    
  WMI   结构由以下三层组成:    
  •   客户端    
  使用   WMI   执行操作(例如,读取管理详细信息、配置系统和预订事件)的软件组件。    
  •   对象管理器    
  提供程序与客户端之间的中间装置,它提供一些关键服务,如标准事件发布和预订、事件筛选、查询引擎等。    
  •   提供程序    
  软件组件,它们捕获实时数据并将其返回到客户端应用程序,处理来自客户端的方法调用并将客户端链接到所管理的基础结构。    
  通过定义完善的架构向客户端和应用程序无缝地提供了数据和事件以及配置系统的能力。在   .NET   框架中,System.Management   命名空间提供了用于遍历   WMI   架构的公共类。  
  除了   .NET   框架,还需要在计算机上安装   WMI   才能使用该命名空间中的管理功能。如果使用的是   Windows   Millennium   Edition、Windows   2000   或   Windows   XP,那么已经安装了   WMI。否则,将需要从   MSDN   下载   WMI。  
  用   System.Management   访问管理信息  
  System.Management   命名空间是   .NET   框架中的   WMI   命名空间。此命名空间包括下列支持   WMI   操作的第一级类对象:    
  •   ManagementObject   或   ManagementClass:分别为单个管理对象或类。    
  •   ManagementObjectSearcher:用于根据指定的查询或枚举检索   ManagementObject   或   ManagementClass   对象的集合。    
  •   ManagementEventWatcher:用于预订来自   WMI   的事件通知。    
  •   ManagementQuery:用作所有查询类的基础。    
  System.Management   类的使用编码范例对   .NET   框架环境很适合,并且   WMI   在任何适当的时候均使用标准基框架。例如,WMI   广泛利用   .NET   集合类并使用推荐的编码模式,如   .NET   异步操作的“委托”模式。因此,使用   .NET   框架的开发人员可以使用他们的当前技能访问有关计算机或应用程序的管理信息。  
  请参见  
  使用   WMI   管理应用程序   |   检索管理对象的集合   |   查询管理信息   |   预订和使用管理事件   |   执行管理对象的方法   |   远程处理和连接选项   |   使用强类型对象  
     
  获取CPU序列号代码  
  string   cpuInfo   =   "";//cpu序列号  
        ManagementClass   cimobject   =   new   ManagementClass("Win32_Processor");  
        ManagementObjectCollection   moc   =   cimobject.GetInstances();  
        foreach(ManagementObject   mo   in   moc)  
        {  
          cpuInfo   =   mo.Properties["ProcessorId"].value.ToString();  
          Console.WriteLine(cpuInfo);  
          Console.ReadLine();  
        }  
  获取网卡硬件地址  
  using   System.Management;  
  ...  
  ManagementClass   mc   =   new   ManagementClass("Win32_NetworkAdapterConfiguration");  
  ManagementObjectCollection   moc   =   mc.GetInstances();  
  foreach(ManagementObject   mo   in   moc)  
  {  
  if((bool)mo["IPEnabled"]   ==   true)  
  Console.WriteLine("MAC   address\t{0}",   mo["MacAddress"].ToString());  
  mo.Dispose();  
  }  
  }  
  获取硬盘ID  
  String   HDid;  
  ManagementClass   cimobject   =   new   ManagementClass("Win32_DiskDrive");  
  ManagementObjectCollection   moc   =   cimobject.GetInstances();  
  foreach(ManagementObject   mo   in   moc)  
  {  
    HDid   =   (string)mo.Properties["Model"].value;  
    MessageBox.Show(HDid     );    
  }  
   
   
  16、在.NET中轻松获取系统信息(1)   -WMI篇  
  Montaque  
  申明:  
          1、个人的一点心得,仅供参考  
          2、转载时候,请保留原本。  
   
  概述:  
    不知道大家有没有这种体会?有时候为了获取系统一点点信息,比如考虑一下操作系统的版本号,或者当前屏幕的分辨率。其实说到底就是读操作系统某个方面的一个属性值而已,然后就看到我们的程序中密密麻麻的Win32   API申明,调用,代码的可读性和维护性不言而喻。到了.NET,微软提供了更为丰富的类,有很多以前要调用API的方法可以在.NET中轻而易举的调用实现。今天简单介绍一个在.NET中如何通过与WMI(Windows   管理规范)的通讯,从而得到获取信息的目的。  
  主要思路:  
    举一个获取操作系统共享目录和获取主板号的例子,介绍如何利用System.Managment下面的类获取系统相关的信息:  
   
  正文:  
    WMI(Windows管理规范:Windows   Management   Instrumentation)是Microsoft基于Web的企业管理(WBEM)的实现,同时也是一种基于标准的系统管理接口。WMI最早出现在Microsoft   Windows   2000系统上,但它同样可以安装在Windows   NT   4和Windows   9x计算机上。WMI是一种轻松获取系统信息的强大工具。  
    在.NET中,有一个System.Management名空间(系统默认没有引用,我们可以手动添加引用),通过下面的Class的操作,可以查询系统软硬件的信息,先看一个简单的例子:  
   
  Imports   System.Management  
  Dim   searcher   As   New   ManagementObjectSearcher("SELECT   *   FROM   Win32_share")  
  Dim   share   As   ManagementObject  
    For   Each   share   In   searcher.Get()  
                MessageBox.Show(share.GetText(TextFormat.Mof))  
    Next   share  
  运行的结果是列出了所有系统当前共享的目录、以及描述等等。  
   
  分析一下上面的代码,可以看到一下几点:  
  1、似乎是在进行数据库操作,有点像SQL语句。其实就是SQL操作,这种语句被成WQL(WMI   Query   Language),实际上是标准SQL的一个子集加上了WMI的扩展.  
  2、WQL是个只读的查询语言,我们只能查询响应的数据,不能用UPDATE,INSERT等更新操作  
  3、代码很简单、通俗易懂  
  4、我们采用了一种MOF(托管对象格式)的显示。  
   
  例子二:获取当前主板的信息  
    上面的例子是一个软件方面的信息,下面看一个获取硬件信息的例子,获取主板的序列号以及制造商:  
  Dim   searcher   As   New   ManagementObjectSearcher("SELECT   *   FROM   Win32_BaseBoard")  
  Dim   share   As   ManagementObject  
        For   Each   share   In   searcher.Get()  
              Debug.WriteLine("主板制造商:"   &   share("Manufacturer"))  
              Debug.WriteLine("型号:"   &   share("Product"))  
              Debug.WriteLine("序列号:"   &   share("SerialNumber"))  
        Next   share  
  总结以及补充:  
    WMI类也是分层次的,具体可以参考msdn中的WMI;转向.NET平台开发的时候,最好能多看一些关于.NET新特性的介绍,这样可以大幅度的提升代码的开发效率以及运行效率。  
   
   
  问题点数:0、回复次数:10Top

1 楼yintongshun(左岸思雨)回复于 2003-12-02 11:53:39 得分 0

VC数据库编程分析  
  2001-02-05·   胡朝晖·yesky  
   
  --------------------------------------------------------------------------------  
   
  7     1   2   3     下一页8  
   
   
    我们知道,在VB下进行基于ADO的编程相对比较简单,只要我们通过reference加载了适当的类型库以后,我们就可以正常的调用ADO对象,但是可能很多开发人员对于VC下的基于ADO,OLE   DB的数据库开发就没有很多经验了。所以我们有必要先讨论一下VC下基于ADO开发的几种模式。  
   
    VC下关于ADO的操作分析  
   
    一般来说,用VC++有三种方法可以实现对ADO的操作:  
   
    1.   通过#import方法  
   
    2.   通过利用MFC   OLE的ClassWizard  
   
    3.   通过Windows   API中COM相关的函数  
   
  在所有这三种方法种,#import是最方便的方法,它允许你产生一个类似VB的类结构。使你的开发变的很方便。  
   
    #import方法  
   
    在#import中,你需要提供所包含的类型库的路径和名称,它能够自动产生一个对GUIDs的定义,同时对自动生成对ADO对象的封装。同时,能够列举它在类型库中所能找到的类型,对任何你所引用的类型库,VC++会在编译的时候自动生成两个文件:  
   
    一个头文件(.tlh),它包含了列举的类型和对类型库中对象的定义  
   
    一个实现文件(.tli)对类型库对象模型中的方法产生封装。  
   
  比如,你在stdafx.h文件中增加对msado15.dd的import以后,VC++会产生msado15.tlh和msado15.tli两个文件。  
   
    #import也能够使用一个新的类,_com_ptr_t,也被称为智能指针。智能指针能够自动执行QuyerInterface,AddRef和Release函数。对一个COM对象模型使用#import产生代码和VBA很类似。  
   
    下面的代码演示了如何使用#import在你的应用中实现对ADO的操作:  
   
    #import   "c:\program   files\common   files\system\ado\msado15.dll"   \  
   
    no_namespace  
   
    rename   (   "EOF",   "adoEOF"   )  
   
  对EOF进行该名是必要的,因为典型的VC++应用都已经定义了EOF作为常数-1。  
   
    下面分析用#import定义和初始化ADO对象  
   
    通常来说,操作一个自动化对象需要两个步骤:定义和初始化一个用来操作COM对象的变量。通过#import你可以在一行代码完成这个工作,通过使用智能指针(_com_ptr_t)的构造函数传递一个有效的CLSID或者是PROGID。开发人员也可以通过_com_ptr_t::CreateInstance()方法来定义对象的一个示例。具体代码如下所示:  
   
    _ConnectionPtr   Conn1(   __uuidof(   Connection   )   );  
   
  也可以采用下面的代码实现同样的功能  
   
    _ConnectionPtr   Conn1   =   NULL;   file://定义对象  
   
    HRESULT   hr   =   S_OK;  
   
    hr   =   Conn1.CreateInstance(   __uuidof(   Connection   )   );   file://创建实例  
   
  推荐采用第二种方法,因为如果用第一种方法的话不能返回一个失败的HRESULT,所以也就不能判断ADO连接对象是成功还是失败。注意这里的__uuidof(   Connection)中的Connection是在.tlh文件中定义的。通过把它传递给方法CreateInstance,实际上就是创建了一个有效的ADOConnection对象。  
   
    需要注意到的是#import中有一个属性为no_namespace,这是告诉编译器该类不在一个单独的名字空间中,使用no_namespace意味着你不需要在初始化变量的时候引用名字空间。当然如果在你的应用中需要倒入多个类型库的话,最后不要使用no_namespace,以免引起名字冲突。  
   
    下面是简单的基于ADO应用的代码,采用了#import方法:  
   
    #include    
   
    #import   rename("EOF",   "adoEOF")  
   
    void   main()  
   
     {  
   
      HRESULT   hr   =   S_OK;  
   
      file://因为没有在#import中指定no_namespace,所以必须采用ADODB::这样的形式  
   
      file://来作为变量类型  
   
      ADODB::_RecordsetPtr   Rs1   =   NULL;  
   
      file://通过ODBC建立ADO连接  
   
      _bstr_t   Connect(   "DSN=AdoDemo;UID=sa;PWD=;"   );  
   
      _bstr_t   Source   (   "SELECT   *   FROM   Authors"   );  
   
      CoInitialize();  
   
      file://初始化Rs1对象  
   
      hr   =   Rs1.CreateInstance(   __uuidof(   ADODB::Recordset   )   );  
   
      file://对hr的返回正确性判断省略  
   
      Rs1->Open(   Source,   Connect,    
   
      ADODB::adOpenForwardOnly,    
   
      ADODB::adLockReadOnly,   -1   );  
   
      file://这里可以对记录集Rs1进行操作  
   
      Rs1->Close();  
   
      Rs1   =   NULL;  
   
      ::MessageBox(   NULL,   "Success!",   "",   MB_OK   );  
   
      CoUninitialize();  
   
     }  
   
  Top

2 楼yintongshun(左岸思雨)回复于 2003-12-02 11:53:51 得分 0

VC数据库编程分析  
  2001-02-05·   胡朝晖·yesky  
   
  --------------------------------------------------------------------------------  
   
  7上一页     1   2   3     下一页8  
   
   
    用MFC   OLE创建ADO应用  
   
    MFC   OLE类似于#import,能够对一个类型库产生一个封装(wrapper),但是不象#import,MFC   OLE不能够从类型库中产生枚举类型,但是它能够更干净的实现ADO。MFC类CString和COleVariant隐藏了BSTRS和Variants的细节。需要注意的是,有MFC   OLE产生的类封装都是继承了类ColeDispatchDriver,由ADO产生的失败的HRESULTS被封装在类ColeDispatchException中。  
   
    首先我们需要说明一下用MFC   OLE   ClassWizard创建ADO应用的几个不可缺少的步骤:  
   
    从Tools菜单中,选择Options,然后选择Directories   tab,在Show   Directories中,选择Library   Files,然后在directories增加路径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应用的自己编写的代码:  
   
    AfxOleInit();   file://初始化COM对象  
   
    ...  
   
    _Recordset   Rs1;   file://定义数据集对象  
   
    COleException   e;    
    COleVariant   Connect(   "DSN=AdoDemo;UID=sa;PWD=;"   );  
   
    COleVariant   Source   (   "SELECT   *   FROM   Authors"   );  
   
    file://创建数据集对象  
   
    Rs1.CreateDispatch(   "ADODB.Recordset.2.0",   &e   );  
   
    Rs1.Open(   (VARIANT)   Source,   (VARIANT)   Connect,   0,   1,   -1   );  
   
    file://这里可以对结果集Rs1进行处理  
   
    Rs1.Close();  
   
    Rs1.ReleaseDispatch();  
   
    AfxMessageBox("Success!");  
   
    #import和MFC   OLE都围绕着一个给定的自动化对象产生了一个封装类,它们分别继承自_com_ptr_t和ColeDispatchDriver。但是事实上,你可以通过使用Windows   API函数直接初始化ADO对象,下面讨论直接用Win32   API函数来操作COM对象。  
   
  Top

3 楼yintongshun(左岸思雨)回复于 2003-12-02 11:54:05 得分 0

VC数据库编程分析  
  2001-02-05·   胡朝晖·yesky  
   
  --------------------------------------------------------------------------------  
   
  7上一页     1   2   3     8  
   
   
    用COM   API创建ADO工程  
   
    为了直接使用ADO和COM对象,需要添加两个头文件adoid.h和adoint.h,这两个头文件定义了CLSIDs,接口定义和你操作ADO类型库所需要的枚举类型。同时你也需要增加头文件INITGUID.H。  
   
    为了能够编译用COM   API创建的ADO工程文件,你需要安装OLE   DB   SDK或者是MSDASDK工具。下面是简单的示例代码:  
   
    #include    
   
    #include    
   
    #include   "adoid.h"   //   ADO的GUID's  
   
    #include   "adoint.h"   //   ADO的类、枚举等等  
   
    void   main()  
   
    {  
   
     HRESULT   hr   =   S_OK;  
   
     ADORecordset*   Rs1   =   NULL;   //   ADORecordset   是在adoint.h中定义的  
   
     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   );  
   
     file://这里你可以对记录集Rs1进行处理  
   
     if(   SUCCEEDED(   hr   )   )   hr   =   Rs1->Close();  
   
     if(   SUCCEEDED(   hr   )   )   {   Rs1->Release();   Rs1   =   NULL;   }  
   
     if(   SUCCEEDED(   hr   )   )   ::MessageBox(   NULL,   "Success!",   "",   MB_OK   );  
   
    }  
   
   
  Top

4 楼yintongshun(左岸思雨)回复于 2003-12-02 11:54:15 得分 0

VC开发数据库基础之ADO篇      
  一、ADO简介  
  ADO(ActiveX   Data   Object)是Microsoft数据库应用程序开发的新接口,是建立在OLE   DB之上的高层数据库访问技术,请不必为此担心,即使你对OLE   DB,COM不了解也能轻松对付ADO,因为它非常简单易用,甚至比你以往所接触的ODBC   API、DAO、RDO都要容易使用,并不失灵活性。本文将详细地介绍在VC下如何使用ADO来进行数据库应用程序开发,并给出示例代码。  
  本文示例代码    
   
  二、基本流程  
  万事开头难,任何一种新技术对于初学者来说最重要的还是“入门”,掌握其要点。让我们来看看ADO数据库开发的基本流程吧!  
  (1)初始化COM库,引入ADO库定义文件  
  (2)用Connection对象连接数据库  
  (3)利用建立好的连接,通过Connection、Command对象执行SQL命令,或利用Recordset对象取得结果记录集进行查询、处理。  
  (4)使用完毕后关闭连接释放对象。  
   
  准备工作:  
  为了大家都能测试本文提供的例子,我们采用Access数据库,您也可以直接在我们提供的示例代码中找到这个test.mdb。  
  下面我们将详细介绍上述步骤并给出相关代码。  
  【1】COM库的初始化  
  我们可以使用AfxOleInit()来初始化COM库,这项工作通常在CWinApp::InitInstance()的重载函数中完成,请看如下代码:  
   
   
  BOOL   CADOTest1App::InitInstance()  
  {  
  AfxOleInit();  
  ......    
   
  【2】用#import指令引入ADO类型库  
  我们在stdafx.h中加入如下语句:(stdafx.h这个文件哪里可以找到?你可以在FileView中的Header   Files里找到)  
  #import   "c:\program   files\common   files\system\ado\msado15.dll"   no_namespace   rename("EOF","adoEOF")  
  这一语句有何作用呢?其最终作用同我们熟悉的#include类似,编译的时候系统会为我们生成msado15.tlh,ado15.tli两个C++头文件来定义ADO库。  
   
  几点说明:  
  (1)   您的环境中msado15.dll不一定在这个目录下,请按实际情况修改  
  (2)   在编译的时候肯能会出现如下警告,对此微软在MSDN中作了说明,并建议我们不要理会这个警告。  
  msado15.tlh(405)   :   warning   C4146:   unary   minus   operator   applied   to   unsigned   type,   result   still   unsigned    
   
  【3】创建Connection对象并连接数据库  
  首先我们需要添加一个指向Connection对象的指针:  
  _ConnectionPtr   m_pConnection;  
  下面的代码演示了如何创建Connection对象实例及如何连接数据库并进行异常捕捉。  
   
   
  BOOL   CADOTest1Dlg::OnInitDialog()  
  {  
  CDialog::OnInitDialog();  
  HRESULT   hr;  
  try  
  {  
  hr   =   m_pConnection.CreateInstance("ADODB.Connection");///创建Connection对象  
  if(SUCCEEDED(hr))  
  {  
  hr   =   m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data   Source=test.mdb","","",adModeUnknown);///连接数据库  
  ///上面一句中连接字串中的Provider是针对ACCESS2000环境的,对于ACCESS97,需要改为:Provider=Microsoft.Jet.OLEDB.3.51;   }  
  }  
  catch(_com_error   e)///捕捉异常  
  {  
  CString   errormessage;  
  errormessage.Format("连接数据库失败!\r\n错误信息:%s",e.ErrorMessage());  
  AfxMessageBox(errormessage);///显示错误信息  
  }    
   
  在这段代码中我们是通过Connection对象的Open方法来进行连接数据库的,下面是该方法的原型  
  HRESULT   Connection15::Open   (   _bstr_t   ConnectionString,   _bstr_t   UserID,   _bstr_t   Password,   long   Options   )  
  ConnectionString为连接字串,UserID是用户名,   Password是登陆密码,Options是连接选项,用于指定Connection对象对数据的更新许可权,  
  Options可以是如下几个常量:  
  adModeUnknown:缺省。当前的许可权未设置  
  adModeRead:只读  
  adModeWrite:只写  
  adModeReadWrite:可以读写  
  adModeShareDenyRead:阻止其它Connection对象以读权限打开连接  
  adModeShareDenyWrite:阻止其它Connection对象以写权限打开连接  
  adModeShareExclusive:阻止其它Connection对象打开连接  
  adModeShareDenyNone:允许其它程序或对象以任何权限建立连接  
   
  我们给出一些常用的连接方式供大家参考:  
  (1)通过JET数据库引擎对ACCESS2000数据库的连接  
   
  m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data   Source=C:\\test.mdb","","",adModeUnknown);  
   
  (2)通过DSN数据源对任何支持ODBC的数据库进行连接:  
  m_pConnection->Open("Data   Source=adotest;UID=sa;PWD=;","","",adModeUnknown);  
   
  (3)不通过DSN对SQL   SERVER数据库进行连接:   m_pConnection->Open("driver={SQL   Server};Server=127.0.0.1;DATABASE=vckbase;UID=sa;PWD=139","","",adModeUnknown);  
   
  其中Server是SQL服务器的名称,DATABASE是库的名称  
   
  Connection对象除Open方法外还有许多方法,我们先介绍Connection对象中两个有用的属性ConnectionTimeOut与State  
  ConnectionTimeOut用来设置连接的超时时间,需要在Open之前调用,例如:   m_pConnection->ConnectionTimeout   =   5;///设置超时时间为5秒  
  m_pConnection->Open("Data   Source=adotest;","","",adModeUnknown);  
   
   
  State属性指明当前Connection对象的状态,0表示关闭,1表示已经打开,我们可以通过读取这个属性来作相应的处理,例如:  
  if(m_pConnection->State)  
  m_pConnection->Close();   ///如果已经打开了连接则关闭它  
   
   
  【4】执行SQL命令并取得结果记录集  
  为了取得结果记录集,我们定义一个指向Recordset对象的指针:_RecordsetPtr   m_pRecordset;  
  并为其创建Recordset对象的实例:   m_pRecordset.CreateInstance("ADODB.Recordset");  
  SQL命令的执行可以采用多种形式,下面我们一进行阐述。  
   
  (1)利用Connection对象的Execute方法执行SQL命令  
  Execute方法的原型如下所示:  
  _RecordsetPtr   Connection15::Execute   (   _bstr_t   CommandText,   VARIANT   *   RecordsAffected,   long   Options   )   其中CommandText是命令字串,通常是SQL命令。参数RecordsAffected是操作完成后所影响的行数,   参数Options表示CommandText中内容的类型,Options可以取如下值之一:  
  adCmdText:表明CommandText是文本命令  
  adCmdTable:表明CommandText是一个表名  
  adCmdProc:表明CommandText是一个存储过程  
  adCmdUnknown:未知  
   
  Top

5 楼yintongshun(左岸思雨)回复于 2003-12-02 11:54:31 得分 0

 
  Execute执行完后返回一个指向记录集的指针,下面我们给出具体代码并作说明。   _variant_t   RecordsAffected;  
  ///执行SQL命令:CREATE   TABLE创建表格users,users包含四个字段:整形ID,字符串username,整形old,日期型birthday  
  m_pConnection->Execute("CREATE   TABLE   users(ID   INTEGER,username   TEXT,old   INTEGER,birthday   DATETIME)",&RecordsAffected,adCmdText);  
  ///往表格里面添加记录  
  m_pConnection->Execute("INSERT   INTO   users(ID,username,old,birthday)   valueS   (1,   ''''''''Washington'''''''',25,''''''''1970/1/1'''''''')",&RecordsAffected,adCmdText);  
  ///将所有记录old字段的值加一  
  m_pConnection->Execute("UPDATE   users   SET   old   =   old+1",&RecordsAffected,adCmdText);  
  ///执行SQL统计命令得到包含记录条数的记录集  
  m_pRecordset   =   m_pConnection->Execute("SELECT   COUNT(*)   FROM   users",&RecordsAffected,adCmdText);  
  _variant_t   vIndex   =   (long)0;  
  _variant_t   vCount   =   m_pRecordset->GetCollect(vIndex);///取得第一个字段的值放入vCount变量  
  m_pRecordset->Close();///关闭记录集  
  CString   message;  
  message.Format("共有%d条记录",vCount.lVal);  
  AfxMessageBox(message);///显示当前记录条数  
   
   
  (2)利用Command对象来执行SQL命令  
  _CommandPtr   m_pCommand;  
  m_pCommand.CreateInstance("ADODB.Command");  
  _variant_t   vNULL;  
  vNULL.vt   =   VT_ERROR;  
  vNULL.scode   =   DISP_E_PARAMNOTFOUND;///定义为无参数  
  m_pCommand->ActiveConnection   =   m_pConnection;///非常关键的一句,将建立的连接赋值给它  
  m_pCommand->CommandText   =   "SELECT   *   FROM   users";///命令字串  
  m_pRecordset   =   m_pCommand->Execute(&vNULL,&vNULL,adCmdText);///执行命令,取得记录集  
   
  在这段代码中我们只是用Command对象来执行了SELECT查询语句,Command对象在进行存储过程的调用中能真正体现它的作用。下次我们将详细介绍。    
   
   
  (3)直接用Recordset对象进行查询取得记录集    
  例如    
   
  m_pRecordset->Open("SELECT   *   FROM   users",_variant_t((IDispatch   *)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);  
   
  Open方法的原型是这样的:  
  HRESULT   Recordset15::Open   (   const   _variant_t   &   Source,   const   _variant_t   &   ActiveConnection,   enum   CursorTypeEnum   CursorType,   enum   LockTypeEnum   LockType,   long   Options   )    
  其中:  
  ①Source是数据查询字符串  
  ②ActiveConnection是已经建立好的连接(我们需要用Connection对象指针来构造一个_variant_t对象)    
  ③CursorType光标类型,它可以是以下值之一,请看这个枚举结构:  
  enum   CursorTypeEnum  
  {  
  adOpenUnspecified   =   -1,///不作特别指定  
  adOpenForwardOnly   =   0,///前滚静态光标。这种光标只能向前浏览记录集,比如用MoveNext向前滚动,这种方式可以提高浏览速度。但诸如BookMark,RecordCount,AbsolutePosition,AbsolutePage都不能使用  
  adOpenKeyset   =   1,///采用这种光标的记录集看不到其它用户的新增、删除操作,但对于更新原有记录的操作对你是可见的。  
  adOpenDynamic   =   2,///动态光标。所有数据库的操作都会立即在各用户记录集上反应出来。  
  adOpenStatic   =   3///静态光标。它为你的记录集产生一个静态备份,但其它用户的新增、删除、更新操作对你的记录集来说是不可见的。  
  };  
  ④LockType锁定类型,它可以是以下值之一,请看如下枚举结构:  
  enum   LockTypeEnum  
  {  
  adLockUnspecified   =   -1,///未指定  
  adLockReadOnly   =   1,///只读记录集  
  adLockPessimistic   =   2,悲观锁定方式。数据在更新时锁定其它所有动作,这是最安全的锁定机制  
  adLockOptimistic   =   3,乐观锁定方式。只有在你调用Update方法时才锁定记录。在此之前仍然可以做数据的更新、插入、删除等动作  
  adLockBatchOptimistic   =   4,乐观分批更新。编辑时记录不会锁定,更改、插入及删除是在批处理模式下完成。  
  };    
  ⑤Options请参考本文中对Connection对象的Execute方法的介绍  
   
   
  【5】记录集的遍历、更新  
  根据我们刚才通过执行SQL命令建立好的users表,它包含四个字段:ID,username,old,birthday  
  以下的代码实现:打开记录集,遍历所有记录,删除第一条记录,添加三条记录,移动光标到第二条记录,更改其年龄,保存到数据库。  
   
   
  _variant_t   vUsername,vBirthday,vID,vOld;  
  _RecordsetPtr   m_pRecordset;  
  m_pRecordset.CreateInstance("ADODB.Recordset");  
  m_pRecordset->Open("SELECT   *   FROM   users",_variant_t((IDispatch*)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);  
  while(!m_pRecordset->adoEOF)///这里为什么是adoEOF而不是EOF呢?还记得rename("EOF","adoEOF")这一句吗?  
  {  
  vID   =   m_pRecordset->GetCollect(_variant_t((long)0));///取得第1列的值,从0开始计数,你也可以直接给出列的名称,如下一行  
  vUsername   =   m_pRecordset->GetCollect("username");///取得username字段的值  
  vOld   =   m_pRecordset->GetCollect("old");  
  vBirthday   =   m_pRecordset->GetCollect("birthday");  
  ///在DEBUG方式下的OUTPUT窗口输出记录集中的记录  
  if(vID.vt   !=   VT_NULL   &&   vUsername.vt   !=   VT_NULL   &&   vOld.vt   !=   VT_NULL   &&   vBirthday.vt   !=   VT_NULL)  
  TRACE("id:%d,姓名:%s,年龄:%d,生日:%s\r\n",vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday);  
  m_pRecordset->MoveNext();///移到下一条记录  
  }  
  m_pRecordset->MoveFirst();///移到首条记录  
  m_pRecordset->Delete(adAffectCurrent);///删除当前记录  
  ///添加三条新记录并赋值  
  for(int   i=0;i<3;i++)  
  {  
  m_pRecordset->AddNew();///添加新记录  
  m_pRecordset->PutCollect("ID",_variant_t((long)(i+10)));  
  m_pRecordset->PutCollect("username",_variant_t("叶利钦"));  
  m_pRecordset->PutCollect("old",_variant_t((long)71));  
  m_pRecordset->PutCollect("birthday",_variant_t("1930-3-15"));  
  }  
  m_pRecordset->Move(1,_variant_t((long)adBookmarkFirst));///从第一条记录往下移动一条记录,即移动到第二条记录处  
  m_pRecordset->PutCollect(_variant_t("old"),_variant_t((long)45));///修改其年龄  
  m_pRecordset->Update();///保存到库中  
   
  【6】关闭记录集与连接    
  记录集或连接都可以用Close方法来关闭  
  m_pRecordset->Close();///关闭记录集  
  m_pConnection->Close();///关闭连接  
   
  至此,我想您已经熟悉了ADO操作数据库的大致流程,也许您已经胸有成竹,也许您还有点胡涂,不要紧!建议你尝试写几个例子,这样会更好地熟悉ADO,最后我给大家写了一个小例子,例子中读出所有记录放到列表控件中、并可以添加、删除、修改记录。  
  点这里下载示例代码  
   
  后记:限于篇幅ADO中的许多内容还没有介绍,下次我们将详细介绍Recordset对象的属性、方法并解决几个关键的技术:绑定方式处理记录集数据、存储过程的调用、事务处理、图象在数据库中的保存与读取、与表格控件的配合使用等    
   
  Top

6 楼yintongshun(左岸思雨)回复于 2003-12-02 11:54:45 得分 0

在无绑定模式下使用DBGrid      
       
     
  作者:Adrian   Roman           翻译:白鹤  
   
          我花了好长时间来注意这件事情,因为我不能在其他任何文件中找到关于  
  DBGrid   在无绑定模式下的VC++编程内容(只有VB的)。我想把我的心得与别人  
  分享会是一个好主意。    
   
        首先,尽管连随机文档都说它能接受任何类型的变量作为书签,但是好象并不  
  是那么回事儿。DaoRecordset把SAFEARRAY作为书签(GetBookmark返回包含  
  VT_ARRAY   |   VT_UI1的变量),但它不能与DBGrid一起工作(DBGrid把变量转变  
  为VT_BSTR)。   它可能会与VT_I4工作的很好,但据说字符串是最好的,所以我  
  用他们。当然,我把书签转换成字符串再转换回来。   SchedQ是一个通过查询得  
  来的动态集(CDaoRecordset),如果关于他你有任何bug或是好想法,请跟我分  
  享您的发现。   啊,对,我几乎忘了!极其重要!如果你从OCX的类库中继承了  
  RowBuffer类,请修改构造函数,原构造函数得到LPDISPACH作为参数去调用基类  
  的构造函数,这时第二个参数要设为FALSE(原来隐性地设置为TRUE)。如果不  
  这样做,当RowBuffer对象被消除时整个程序会崩溃。   补充技巧:记着使用  
  BeforeColUpdate   和KeyPress事件去验证一个域的输入及相应地过滤键盘的输入。    
   
      请不要给我来e-mails,问我关于如何在绑定模式下使用他们的问题。在加入  
  DBGrid之前加上一个Microsoft   Remote   Data   Control   的对话框,然后花点时  
  间调整一下它的属性,你就会弄明白如何使用它。   致那些想在运行时改变列  
  的人:由DBGrid类生成的GetColumns()成员函数是一个真正的GetColumn函数  
  (返回一个指向单个列的LPDISPATCH---这样你就可以用这个LPDISPATCH来构造  
  单个列对象,而不是列集的对象)。如果你想获得指向列集的LPDISPATCH,  
  把GetColumns()该名为GetColumn,然后象下面这样重新写一个GetColumns():  
   
   
  LPDISPATCH   CMsDgridCtrl::GetColumns()  
  {  
  LPDISPATCH   result;  
  InvokeHelper(0x8,DISPATCH_PROPERTYGET,VT_DISPATCH,(void*)&result,NULL,NULL);  
  return   result;  
  }   
      这样你就可以用返回的LPDISPATCH来构造列集对象。   那么现在,往网格中输  
  入数据、删除纪录、当网格中写操作发生时从网格中获取数据的代码如下所示:  
   
   
  void   CMyView::OnUnboundReadDataDbgridMy(LPDISPATCH   RowBuf,   VARIANT   FAR*   StartLocation,   BOOL   ReadPriorRows)    
   
  {  
  //   TODO:   Add   your   control   notification   handler   code   here  
  RowBuffer   buf(RowBuf);    
  VARIANT   varbok;  
  varbok.vt=VT_ARRAY   |   VT_UI1;  
  long   Row,RowsFetched;  
  VARIANT   var;  
  RowsFetched=0;  
  if(StartLocation->vt==VT_NULL){  
  if(ReadPriorRows){  
  try{  
  SchedQ->MoveLast();  
  }catch(CDaoException*   e){  
  e->Delete();  
  }  
  }else{  
  try{  
  SchedQ->MoveFirst();  
  }catch(CDaoException*   e){  
  e->Delete();  
  }  
  }  
  }else{  
  //根据StartLocation书签和ReadPriorRows参数找到开始读数据的位置  
   
  try{  
  VectorFromBstr(StartLocation->bstrVal,&varbok.parray);  
  SchedQ->SetBookmark(COleVariant(varbok));  
  if(ReadPriorRows)SchedQ->MovePrev();  
  else   SchedQ->MoveNext();  
  }catch(CDaoException*   e){  
  e->Delete();  
  }  
  }  
  //把我们的数据集数组转换为DBGrid   用来显示数据的RowBuf对象,  
  for(Row   =   0;   Row<buf.GetRowCount()   ;Row++){  
  if(SchedQ->IsEOF()   ||   SchedQ->IsBOF())break;  
  var.vt=VT_I4;  
  var.lVal=SchedQ->m_WorkCodeID;  
  if(buf.GetColumnCount()>0)buf.SetValue(Row,   0,var);  
  COleVariant   olvi(SchedQ->m_TimeIn);  
  var=*((LPVARIANT)olvi);  
  if(buf.GetColumnCount()>1)buf.SetValue(Row,   1,var);  
  COleVariant   olvo(SchedQ->m_TimeOut);  
  var=*((LPVARIANT)olvo);  
  if(buf.GetColumnCount()>2)buf.SetValue(Row,   2,var);  
  //   Set   bookmark   using   CurRow   which   is   also   our  
  //   array   index  
  var.vt=VT_BSTR;  
  BstrFromVector(((LPVARIANT)SchedQ->GetBookmark())->parray,&var.bstrVal);  
  buf.SetBookmark(Row,var);  
  RowsFetched++;  
  if(ReadPriorRows)SchedQ->MovePrev();  
  else   SchedQ->MoveNext();  
  }  
  buf.SetRowCount(RowsFetched);  
  }  
   
     
  void   CMyView::OnUnboundWriteDataDbgridMy(LPDISPATCH   RowBuf,   VARIANT   FAR*   WriteLocation)  
  {  
  //   TODO:   Add   your   control   notification   handler   code   here  
  RowBuffer   buf(RowBuf);  
  VARIANT   varbok;  
  varbok.vt=VT_ARRAY   |   VT_UI1;  
  COleVariant   var;  
  CString   str;  
  try{  
  VectorFromBstr(WriteLocation->bstrVal,&varbok.parray);  
  SchedQ->SetBookmark(COleVariant(varbok));  
  }catch(CDaoException*   e){  
  e->Delete();  
  buf.SetRowCount(0);  
  return;  
  }  
     
  //**********************************************************************  
  //Here   was   a   portion   of   code   that   validated   the   record  
     
  //************************************************  
   
  //只有被修改过的列更新,否则,值被设置为NULL  
  try{  
  SchedQ->Edit();  
  }  
  catch(CDaoException*   e){  
  e->Delete();  
  buf.SetRowCount(0);  
  return;  
  }    
  if(buf.GetValue(0L,   0).vt!=VT_NULL){  
  var=buf.GetValue(0,   0);  
  str=CString(var.bstrVal);  
  SchedQ->m_WorkCodeID=atol(str);  
  }  
  if(buf.GetValue(0L,   1).vt!=VT_NULL){  
  var=buf.GetValue(0,   1);  
  str=CString(var.bstrVal);  
  SchedQ->m_TimeIn.ParseDateTime(str);  
  }  
  if(buf.GetValue(0L,   2).vt!=VT_NULL){  
  var=buf.GetValue(0,   2);  
  str=CString(var.bstrVal);  
  SchedQ->m_TimeOut.ParseDateTime(str);  
  }  
  try{  
  SchedQ->Update();  
  }catch(CDaoException   *e){  
  SchedQ->CancelUpdate();  
  e->Delete();  
  buf.SetRowCount(0);  
  }  
  }  
   
   
  void   CMyView::OnUnboundAddDataDbgridMy(LPDISPATCH   RowBuf,   VARIANT   FAR*   NewRowBookmark)    
  {  
  //   TODO:   Add   your   control   notification   handler   code   here  
  RowBuffer   buf(RowBuf);  
  COleVariant   var;  
  CString   str;  
  NewRowBookmark->vt=VT_NULL;  
     
  //**********************************************************************  
  //Here   was   a   portion   of   code   that   validated   the   record  
  //**********************************************************************  
  try{  
  SchedQ->AddNew();  
  SchedQ->Update();  
  SchedQ->SetBookmark(SchedQ->GetLastModifiedBookmark());  
  SchedQ->Edit();  
  }catch(CDaoException*   e){  
  e->Delete();  
  buf.SetRowCount(0);  
  return;  
  }    
  SchedQ->m_EmployeeID=m_pSet->m_EmployeeID;  
  try{  
  if(buf.GetValue(0L,   0).vt!=VT_NULL){    
  var=buf.GetValue(0,   0);  
  }else{  
  var.vt=VT_I4;    
  var.lVal=0;  
  Column   col(m_SchedGrid.GetColumns(var));  
  var=col.GetDefaultValue();  
  }  
  str=(char*)_bstr_t(var.bstrVal);  
  SchedQ->m_WorkCodeID=atol(str);  
  if(buf.GetValue(0L,   1).vt!=VT_NULL){  
  var=buf.GetValue(0,   1);  
  }else{  
  var.vt=VT_I4;    
  var.lVal=1;  
  Column   col(m_SchedGrid.GetColumns(var));  
  var=col.GetDefaultValue();  
  }  
  str=(char*)_bstr_t(var.bstrVal);  
  SchedQ->m_TimeIn.ParseDateTime(str);  
  if(buf.GetValue(0L,   2).vt!=VT_NULL){  
  var=buf.GetValue(0,   2);  
  }else{  
  var.vt=VT_I4;    
  var.lVal=2;  
  Column   col(m_SchedGrid.GetColumns(var));  
  var=col.GetDefaultValue();  
  }  
  str=(char*)_bstr_t(var.bstrVal);  
  SchedQ->m_TimeOut.ParseDateTime(str);  
  var.vt=VT_I4;  
  SchedQ->Update();  
  }catch(CDaoException   *e){  
  e->Delete();  
  SchedQ->CancelUpdate();  
  SchedQ->Delete();  
  buf.SetRowCount(0);  
  }  
  NewRowBookmark->vt=VT_BSTR;  
  BstrFromVector(((LPVARIANT)SchedQ->GetBookmark())->parray,&(NewRowBookmark->bstrVal));  
  }  
   
     
  void   CMyView::OnUnboundDeleteRowDbgridMy(VARIANT   FAR*   Bookmark)    
  {  
  //   TODO:   Add   your   control   notification   handler   code   here  
  VARIANT   varbok;  
  varbok.vt=VT_ARRAY   |   VT_UI1;  
  VectorFromBstr(Bookmark->bstrVal,&varbok.parray);  
  try{  
  SchedQ->SetBookmark(COleVariant(varbok));  
  SchedQ->Delete();  
  }catch(CDaoException*   e){  
  Bookmark->vt=VT_NULL;  
  e->Delete();  
  }    
  }   
     
   
  Top

7 楼yintongshun(左岸思雨)回复于 2003-12-02 11:55:18 得分 0

 
  在VC++中建立自定义数据库类      
       
     
  作者:李健萍  
  摘要    
  ----   本文较为详细的介绍了一个使用ODBC对数据库进行操作的  
  CdataBaseOperate类的建立,并给出了几个主要函数的具体实现,以及该类  
  在实际的应用程序中的使用。    
   
  ----   众所周知VC++的MFC类库为编程者编制好了对数据库操作的类,编程者可  
  以使用向导建立一个与数据库联结并对数据库进行操作的应用程序,不需要编  
  制任何代码,这无疑为编程人员提供了一个捷径。但是,使用向导时只有选用基  
  于单文档或多文档的项目才能选择数据源,与指定的的数据库相连,对用向导生成  
  的基于对话框的应用程序不提供数据库的支持。即使是基于单文档或多文档的  
  应用程序,当需要一些特殊的操作,例如,打开一个表,要求返回满足一定条件  
  的记录集时,MFC并没有提供完全符合要求的现成函数。如果,能利用MFC所提  
  供的数据库操作,再加上自己设计的函数,也就是说,设计一个对数据库操作  
  的类,在程序中手工加入这个类,那么就可以在基于对话框的应用程序中实现对  
  数据库的操作,而且,也可以针对自己应用程序的具体需要来设计类的函数,为  
  特定功能的实现提供了很大的方便。    
   
  ----   在一个涉及数据库操作的应用程序中,常用到的MFC类有CdaoDatabase类、  
  CdaoTableDef类、CdaoRecordset类和   CdaoQueryDef类,当对数据库进行操作  
  时,需要先打开数据库,然后打开数据库中的表,再得到查询集和记录集。在自  
  己定义的类中综合这四个类的操作,设计一个打开表得到查询集和记录集的函  
  数,以后,在应用程序中使用该类时只需包含该类的头文件,所设计的函数就  
  可以直接调用了。    
   
  ----   建立数据库类的过程可分为如下四步:    
   
  ----   一、定义一个无基类的CdataBaseOperate类    
   
  ----   1、在Workspace窗口选择ClassView选项卡,在树型类结构图的根部单击  
  鼠标右键,选择New   Class…,系统将弹出建立新类的对话框;    
   
  ----   2、在Class   type中选择Generic   Class;    
   
  ----   3、在Name中填写要建的新类的名称,要以大写字母C开头,系统会自动建立  
  新类的头文件和实现文件,文件的名称为类名去掉第一个大写字母C,如果想改变  
  文件的名称,可以单击change按钮.    
   
  ----   4、在填写好各项后,按OK按钮确定,一个无基类的新类建立成功,但,他  
  还是一个空类,下一步,就要给类添加内容.    
   
  ----   二、在自定义的类中加入有关的定义    
   
  ----   1、在本应用程序中,使用ODBC与SQL   SERVER的数据库相连,因而,在类的  
  实现文件构造函数前加入如下的定义:   #define   SQL_DATABASE   _T("ODBC;  
  DSN=sql-database;UID=sa;PWD=pass;")   DSN=sql-database表示建立的ODBC联  
  接的名称是sql-database,如果选用其他数据库,只需在此改变与所需数据库建  
  立的联接,或是重新配置sql-database   使之联接新的数据库。UID=sa;PWD=pass  
  表示登录数据库的用户名是sa,密码是pass,如果密码是空则表示为PWD=""。    
   
  ----   2、在该类中综合使用到了MFC类库提供的有关数据库的几个类  
  CdaoDatabase类、CdaoTableDef类、CdaoRecordset类和CdaoQueryDef类,  
  而这四个类的定义和实现都包括在头文件afxdao.h中,因此,在新定义的类  
  的头文件中一定要加上语句:    
   
    #include   <   afxdao.h   >;  
   
  ----   3、对要用到的四个类各声明一个对象如下:    
      CDaoDatabase*   loc_pDataBase;      
          CDaoTableDef*   loc_pTable;  
  CDaoRecordset   loc_pRecordset;      
          CDaoQueryDef*   loc_pQueryDef;  
   
  ----   其中CdaoDatabase类、CdaoTableDef类和CdaoQueryDef类定义了对象指针,  
  在使用时要先new,最后要delete。以CdaoDatabase类为例,在  
  CdataBaseOperate类的构造函数中初始化对象指针   loc_pDataBase=new   CDaoDatabase;在析构函数中要释放该指针delete   loc_pDataBase;    
  ----   三、在自定义的类中加入所需的函数和变量    
   
  ----   手工加入函数包括两项工作,首先在头文件中加入函数的声明,然后,在  
  实现文件中加入函数的具体实现,声明与实现一定要统一;    
   
  ----   使用向导加入函数和变量:    
   
  ----   1、在Workspace窗口选择ClassView选项卡;    
   
  ----   2、在树型类结构图的要添加函数和变量的类上单击鼠标右键,如果加入成  
  员函数则单击Add   Member   Function,加入虚函数单击Add   Virtual   Function,  
  加入成员变量单击   Add   Member   Variable;    
   
  ----   3、出现对话框后,填写成员函数或变量的名称、类型,系统会自动添加函  
  数的声明与实现;    
   
  ----   4、添加函数的具体操作,可以通过编辑代码进一步填写;    
   
  ----   这些操作将会在Workspace窗口的ClassView选项中立即体现出来,并且,  
  单击ClassView中的相应函数就可进入该函数的实现部分,进行进一步编写代码,  
  如果做不到这一点,说明添加成员函数的操作有误。    
   
  ----   下面以本应用程序为例,给出具体的表结构和几个主要函数的实现,读者  
  可以根据自己的实际情况设计函数。    
   
  ----   本应用程序中的一个典型表的结构是:    
   
  序号     正题内容     难度系数     分值             答案             备注  
  整型     字符型         长整型         双精度         字符型         字符型  
   
  ----   打开数据库的函数实现如下:    
  if   (!loc_pDataBase->IsOpen())  
  loc_pDataBase->Open(   NULL,   FALSE,    
  FALSE,   SQL_DATABASE);  
   
  ----   该函数中用到了CdaoDatabase类的两个函数IsOpen()和Open(NULL,   FALSE,  
    FALSE,   SQL_DATABASE),因为已经声明了该类的指针对象loc_pDataBase,所以  
  可以直接调用CdaoDatabase类的函数。其中,Open()函数中的最后一个参数  
  SQL_DATABASE在前面已经介绍过,通过他打开相关的数据库。    
  ----   由于程序中打开表后,不仅要返回所有的记录集,还用到返回满足一定条  
  件的记录集,因此打开表的函数除了带入表名外还有一个参数难度系数,  
  lNDXS=0时,选择表中全部数据,   lNDXS=1~n时,表示选择难度系数=1~n的记录。    
   
  bool   CDataBaseOperate::OpenTable  
  (Cstring   strTableName,long   lNDXS)  
  {  
  Cstring   strFieldNumber;  
  loc_pTable=new   CdaoTableDef  
  (loc_pDataBase);    
  if   (!loc_pTable->IsOpen())  
  loc_pTable->Open(strTableName);    
                  //打开指定的表名  
  strFieldNumber.Format("%d",loc_pTable-   >  
  GetFieldCount());                 //得到字段数  
  Cstring   Sqlstr,Sqlstr1,Sqlstr2;  
  loc_pQueryDef=new   CDaoQueryDef(loc_pDataBase);    
                //得到查询集和记录集  
  if   (lNDXS==0)  
                  {      
          Sqlstr=_T("SELECT   *   FROM   "+strTableName);  
                  }  
  else    
        {   Sqlstr1="SELECT   *   FROM   "+strTableName   ;  
      Sqlstr2.Format("WHERE   难度系数=   %d",lNDXS);  
                      Sqlstr=_T(Sqlstr1+Sqlstr2);    
                    }  
  loc_pQueryDef->Create(NULL,Sqlstr);  
  loc_pRecordset.Open(loc_pQueryDef);  
  m_nRecordNumber=0;  
  while(!loc_pRecordset.IsEOF())    
                  {          
                            m_nRecordNumber++;    
                            loc_pRecordset.MoveNext(   );    
                    }  
          return   TRUE;    
  }  
   
   
  ----   为了维护数据库的安全,表用过后应该关闭,关闭表的同时,要释放在打  
  开表的操作时初始化的对象指针,例如:delete   loc_pQueryDef。同样要注意,  
  在构造函数中初始化的对象指针,在析构函数中一定要释放。对象指针的初始化  
  和释放是成对出现的。    
          loc_pDataBase=new   CDaoDatabase;    
          //在构造函数中初始化对象指针。  
          Delete   loc_pDataBase;                            
          //在析构函数中释放该对象指针。  
   
  ----   四、CdataBaseOperate类的应用    
  ----   1、使用VC++的向导生成一个应用程序,可以根据需要选择基于对话框或  
  是基于单、多文档,选择单文档或多文档时不要选择数据库支持。    
   
  ----   2、在应用程序的主头文件中加入#include   "DataBaseOperate.h",并且还  
  要声明一个CdataBaseOperate类的对象,public:   CDataBaseOperate   m_CDataBaseOperate;    
   
   
  ----   3、有了指向CdataBaseOperate类的对象后,刚刚在CdataBaseOperate类中  
  编制的函数都可以通过  
  "m_CdataBaseOperate .函数名"来调用。    
   
  小结:    
   
  ----   本文是VC++6.0下的CdataBaseOperate类建立与应用的一个初步探讨,  
  CdataBaseOperate类所实现的功能是很强大的。除了介绍的CdataBaseOperate类  
  的几个基本而又常用的函数之外,CdataBaseOperate还有很多用于其他方面的功  
  能函数,在此不一一介绍。CdataBaseOperate类的函数,实现了数据库内容的显  
  示、修改、添加、删除等功能,基本上满足了数据库操作人员的需要。除了这  
  些,编程人员还可以根据程序的需要定义自己的特有的函数。    
   
  Top

8 楼yintongshun(左岸思雨)回复于 2003-12-02 11:55:31 得分 0

1、取得系统时间  
  方法:  
  SYSTEMTIME   systime;  
  ::GetSystemTime(&systime);  
  CTime   time(systime);  
   
   
   
  2、在程序中添加ODBC数据源  
  方法:使用SQLConfigDataSource函数。例如:  
  SQLConfigDataSource(NULL,ODBC_ADD_DSN,  
  (LPSTR)"SQL   Server",  
  (LPSTR)"DSN=medicine1998\0"  
  "SERVER=DEC\0"  
  "DATABASE=medicine1998\0"))//添加一个ODBC数据源,其类型为  
  //SQL   Server,服务器为DEC,名字为medicine1998,数据库为medicine1998  
   
   
   
  3、在Visual   C++中使用DBGrid控件的方法  
  (1)、插入一个MicrosoftRemoteData控件;  
  (2)、设定其DataSource为所需要的ODBC数据源;  
  (3)、设定用户名和密码;  
  (4)、写入SQL查询语句;  
  (5)、插入一个DBGrid控件;  
  (6)、设定为绑定方式;  
  (7)、设定其绑定的数据源为前面插入的MicrosoftRemoteData控件的ID;  
  (8)、由于只能修改前两列的列头显示(至少我不知道如何去修改第3列),所以为了重新设定每一列的列头显示,同时也是为了指定显示的列,应该修改前面MicrosoftRemoteData控件中的查询语句,指定获取列和更改列名,例如:select   name   as   姓名,phone   as   电话   from   address。此语句就是从表address中选取name和phone两列,并指定了显示的列名为“姓名”和“电话”。  
   
   
   
  4、去掉在主窗口标题上显示"Untitled   -   MyApp."  
  方法一:重载CDocument的虚函数"SetTitle":  
  void   CMyDoc::SetTitle(LPCTSTR   lpszTitle)    
  {  
  CDocument::SetTitle("MyTitle");  
  }  
  *这个方法是将标题改为"MyTitle   -   MyApp"  
  方法二:在程序中的任何位置调用下面的函数:  
  (AfxGetMainWnd(   ))->SetWindowText("MyApp");  
  *这个方法是将标题改为"MyApp",但是每当一个文档对象被创建时,MFC就会加上文档名  
  方法三:重载CFrameWnd的虚函数"OnUpdateFrameTitle"  
  void   CMainFrame::OnUpdateFrameTitle(BOOL   Nada)    
  {  
  //   get   app   name   from   string   table   resource  
  //----------------------------------------  
  CString   csAppName;  
  csAppName.Format(AFX_IDS_APP_TITLE);    
  //   Set   caption   of   main   frame   window  
  //---------------------------------  
  SetWindowText(csAppName);  
  }  
  *注意,在微软的联机帮助中是找不到这个函数的,在新的版本中也可能不支持这个函数,所以要慎用  
  方法四:最好的和最安全的方法,就是改写窗口的属性  
  BOOL   CMainFrame::PreCreateWindow(CREATESTRUCT&   cs)  
  {  
  cs.style   &=   ~(LONG)   FWS_ADDTOTITLE;  
   
  return   CFrameWnd::PreCreateWindow(cs);  
  }  
   
   
   
  5、在ODBC编程中,在过滤器中可以用参数取代过滤字符串,以便在运行时动态改变过滤器,但是该参数必须用如下方法声明:  
  (1)在记录集的定义中添加成员参数:  
  class   CStudentSet   :   public   CRecordset  
  {  
  //   Field/Param   Data  
  //{{AFX_FIELD(CStudentSet,   CRecordset)  
  CString   m_strFirstName;  
  CString   m_strLastName;  
  CString   m_strStudentID;  
  CString   m_strGradYear;  
  //}}AFX_FIELD  
   
  CString   m_strGradYrParam;   //成员参数  
  };  
  (2)改变在CPP文件中的DoFieldExchange成员函数,并且对每一个你添加在类中的成员参数都调用一次RFX函数,如下:  
  pFX->SetFieldType(   CFieldExchange::param   );//指示以下给出的是参数绑定  
  //   RFX   calls   for   parameter   data   members  
  //在此处加入RFX调用:,例如:  
  pFX->RFX_Text(pFX,"bookname",   m_strGradYrParam);  
  *其中,bookname是要在其上添加参数的列名,后面是参数名。  
  (3)在你的recordset类的构建函数中,增加反映参数个数的m_nParams成员变量的值。  
  (4)然后可以在你的SQL过滤串中以?代替可变过滤参数了,这种对应是一一对应的,即?的顺序要严格遵守RFX调用的顺序。然后给出过滤参数的值,就可以用此值代替?了。注意,该过滤参数的值一定要在数据源打开之前给定。  
   
   
   
   
  Top

9 楼yintongshun(左岸思雨)回复于 2003-12-02 11:55:43 得分 0

用Visual   C++操作INI文件    
     
  在我们写的程序当中,总有一些配置信息需要保存下来,以便完成程序的功能,最简单的办法就是将这些信息写入INI文件中,程序初始化时再读入.具体应用如下:  
   
    一.将信息写入.INI文件中.  
   
    1.所用的WINAPI函数原型为:    
   
  BOOL   WritePrivateProfileString(  
  LPCTSTR   lpAppName,  
  LPCTSTR   lpKeyName,  
  LPCTSTR   lpString,  
  LPCTSTR   lpFileName  
  );    
   
    其中各参数的意义:  
   
     LPCTSTR   lpAppName   是INI文件中的一个字段名.  
   
     LPCTSTR   lpKeyName   是lpAppName下的一个键名,通俗讲就是变量名.  
   
     LPCTSTR   lpString   是键值,也就是变量的值,不过必须为LPCTSTR型或CString型的.  
   
     LPCTSTR   lpFileName   是完整的INI文件名.  
   
    2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入   c:\stud\student.ini   文件中.    
   
  CString   strName,strTemp;  
  int   nAge;  
  strName="张三";  
  nAge=12;  
  ::WritePrivateProfileString("StudentInfo","Name",strName,"c:\\stud\\student.ini");    
   
    此时c:\stud\student.ini文件中的内容如下:  
   
     [StudentInfo]  
     Name=张三  
   
    3.要将学生的年龄保存下来,只需将整型的值变为字符型即可:  
   
  strTemp.Format("%d",nAge);  
  ::WritePrivateProfileString("StudentInfo","Age",strTemp,"c:\\stud\\student.ini");    
   二.将信息从INI文件中读入程序中的变量.  
   
    1.所用的WINAPI函数原型为:  
   
  DWORD   GetPrivateProfileString(  
  LPCTSTR   lpAppName,    
  LPCTSTR   lpKeyName,    
  LPCTSTR   lpDefault,    
  LPTSTR   lpReturnedString,    
  DWORD   nSize,    
  LPCTSTR   lpFileName    
  );    
   
    其中各参数的意义:    
   
     前二个参数与   WritePrivateProfileString中的意义一样.  
   
     lpDefault   :   如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量.    
   
     lpReturnedString   :   接收INI文件中的值的CString对象,即目的缓存器.  
   
     nSize   :   目的缓存器的大小.  
   
     lpFileName   :   是完整的INI文件名.  
   
    2.具体使用方法:现要将上一步中写入的学生的信息读入程序中.  
   
  CString   strStudName;  
  int   nStudAge;    
  GetPrivateProfileString("StudentInfo","Name","默认姓名",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"c:\\stud\\student.ini");    
   
    执行后   strStudName   的值为:"张三",若前两个参数有误,其值为:"默认姓名".  
   
    3.读入整型值要用另一个WINAPI函数:    
   
  UINT   GetPrivateProfileInt(  
  LPCTSTR   lpAppName,    
  LPCTSTR   lpKeyName,    
  INT   nDefault,    
  LPCTSTR   lpFileName    
  );    
   
    这里的参数意义与上相同.使用方法如下:  
   
  nStudAge=GetPrivateProfileInt("StudentInfo","Age",10,"c:\\stud\\student.ini");    
  三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下:  
   
    1.写入:  
   
  CString   strTemp,strTempA;  
  int   i;  
  int   nCount=6;  
  file://共有6个文件名需要保存  
  for(i=0;i   {strTemp.Format("%d",i);  
  strTempA=文件名;  
  file://文件名可以从数组,列表框等处取得.  
  ::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA,  
  "c:\\usefile\\usefile.ini");  
  }  
  strTemp.Format("%d",nCount);  
  ::WritePrivateProfileString("FileCount","Count",strTemp,"c:\\usefile\\usefile.ini");  
  file://将文件总数写入,以便读出.    
   
    2.读出:  
   
  nCount=::GetPrivateProfileInt("FileCount","Count",0,"c:\\usefile\\usefile.ini");  
  for(i=0;i   {strTemp.Format("%d",i);  
  strTemp="FileName"+strTemp;  
  ::GetPrivateProfileString("CurrentIni",strTemp,"default.fil",   strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c:\\usefile\\usefile.ini");  
   
  file://使用strTempA中的内容.  
   
  }    
   
    补充四点:  
   
     1.INI文件的路径必须完整,文件名前面的各级目录必须存在,否则写入不成功,该函数返回   FALSE   值.  
   
     2.文件名的路径中必须为   \\   ,因为在VC++中,   \\   才表示一个   \   .  
   
     3.也可将INI文件放在程序所在目录,此时   lpFileName   参数为:   ".\\student.ini".  
   
     
     
   
  Top

10 楼yintongshun(左岸思雨)回复于 2003-12-02 11:55:57 得分 0

C++指针使用方法解惑    
   
   
  在下列函数声明中,为什么要同时使用*和&符号?以及什么场合使用这种声明方式?    
   
    void   func1(   MYCLASS   *&pBuildingElement   );    
   
    论坛中经常有人问到这样的问题。本文试图通过一些实际的指针使用经验来解释这个问题。  
  仔细看一下这种声明方式,确实有点让人迷惑。在某种意义上,"*"和"&"是意思相对的两个东西,把它们放在一起有什么意义呢?。为了理解指针的这种做法,我们先复习一下C/C++编程中无所不在的指针概念。我们都知道MYCLASS*的意思:指向某个对象的指针,此对象的类型为MYCLASS。   Void   func1(MYCLASS   *pMyClass);    
   
  //   例如:   MYCLASS*   p   =   new   MYCLASS;  
  func1(p);    
  上面这段代码的这种处理方法想必谁都用过,创建一个MYCLASS对象,然后将它传入func1函数。现在假设此函数要修改pMyClass:   void   func1(MYCLASS   *pMyClass)  
  {  
  DoSomething(pMyClass);  
  pMyClass   =   //   其它对象的指针  
  }    
   
   
    第二条语句在函数过程中只修改了pMyClass的值。并没有修改调用者的变量p的值。如果p指向某个位于地址0x008a00的对象,当func1返回时,它仍然指向这个特定的对象。(除非func1有bug将堆弄乱了,完全有这种可能。)  
   
    现在假设你想要在func1中修改p的值。这是你的权利。调用者传入一个指针,然后函数给这个指针赋值。以往一般都是传双指针,即指针的指针,例如,CMyClass**。  
   
   
  MYCLASS*   p   =   NULL;  
  func1(&p);  
   
  void   func1(MYCLASS**   pMyClass);  
  {  
  *pMyClass   =   new   MYCLASS;  
  ……  
  }  
     
   
   
    调用func1之后,p指向新的对象。在COM编程中,你到处都会碰到这样的用法--例如在查询对象接口的QueryInterface函数中:  
   
   
  interface   ISomeInterface   {    
  HRESULT   QueryInterface(IID   &iid,   void**   ppvObj);    
  ……    
  };    
  LPSOMEINTERFACE   p=NULL;    
  pOb->QueryInterface(IID_SOMEINTERFACE,   &p);      
   
   
    此处,p是SOMEINTERFACE类型的指针,所以&p便是指针的指针,在QueryInterface返回的时候,如果调用成功,则变量p包含一个指向新的接口的指针。  
   
    如果你理解指针的指针,那么你肯定就理解指针引用,因为它们完全是一回事。如果你象下面这样声明函数:  
   
   
  void   func1(MYCLASS   *&pMyClass);  
  {  
  pMyClass   =   new   MYCLASS;    
  ……  
  }    
   
   
    其实,它和前面所讲得指针的指针例子是一码事,只是语法有所不同。传递的时候不用传p的地址&p,而是直接传p本身:  
   
    MYCLASS*   p   =   NULL;  
    func1(p);  
   
    在调用之后,p指向一个新的对象。一般来讲,引用的原理或多或少就象一个指针,从语法上看它就是一个普通变量。所以只要你碰到*&,就应该想到**。也就是说这个函数修改或可能修改调用者的指针,而调用者象普通变量一样传递这个指针,不使用地址操作符&。  
   
    至于说什么场合要使用这种方法,我会说,极少。MFC在其集合类中用到了它--例如,CObList,它是一个Cobjects指针列表。  
   
   
   
  Class   CObList   :   public   Cobject   {  
  ……  
   
  //   获取/修改指定位置的元素  
  Cobject*&   GetAt(POSITION   position);  
  Cobject*   GetAt(POSITION   position)   const;  
  };  
     
   
   
    这里有两个GetAt函数,功能都是获取给定位置的元素。区别何在呢?  
   
    区别在于一个让你修改列表中的对象,另一个则不行。所以如果你写成下面这样:   Cobject*   pObj   =   mylist.GetAt(pos);  
   
    则pObj是列表中某个对象的指针,如果接着改变pObj的值:   pObj   =   pSomeOtherObj;  
   
    这并改变不了在位置pos处的对象地址,而仅仅是改变了变量pObj。但是,如果你写成下面这样:   Cobject*&   rpObj   =   mylist.GetAt(pos);  
   
    现在,rpObj是引用一个列表中的对象的指针,所以当改变rpObj时,也会改变列表中位置pos处的对象地址--换句话说,替代了这个对象。这就是为什么CObList会有两个GetAt函数的缘故。一个可以修改指针的值,另一个则不能。注意我在此说的是指针,不是对象本身。这两个函数都可以修改对象,但只有*&版本可以替代对象。    
   
    在C/C++中引用是很重要的,同时也是高效的处理手段。所以要想成为C/C++高手,对引用的概念没有透彻的理解和熟练的应用是不行的。  
     
   
  Top

相关问题

  • SQL SERVER中一些常见性能问题的总结
  • 请高手总结一下常见的Web服务器有哪些?谢谢
  • 大家能帮我总结一下m_pMainWnd的一些常见用法吗??谢谢!
  • 再当次义工:VB高手搜集-常见问题总结(立华软件园)
  • 年终总结
  • mfc总结
  • ***2005年总结***
  • 常见错误!!!!!!
  • VB常见问题?
  • VB常见问题?

关键词

  • .net
  • c++
  • c/c++
  • vc++
  • visual c++
  • win32
  • win32 api
  • 函数
  • 指针
  • 数据库

得分解答快速导航

  • 帖主:yintongshun

相关链接

  • Visual C++类图书
  • Visual C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo