//关机函数************************************************ 

void ShutDown(void)//2000 or NT 

OSVERSIONINFO osv; 
osv.dwOSVersionInfoSize=sizeof OSVERSIONINFO; 
GetVersionEx(&osv); 
if(osv.dwPlatformId==VER_PLATFORM_WIN32_NT)//VER_PLATFORM_WIN32_WINDOWS 98 Me用这个宏 

HANDLE hProcess,hToken; 
TOKEN_PRIVILEGES Privileges; 
LUID luid; 
hProcess=GetCurrentProcess(); 
OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES,&hToken); 
Privileges.PrivilegeCount=1; 
LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid); 
Privileges.Privileges[0].Luid=luid; 
Privileges.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; 
AdjustTokenPrivileges(hToken,FALSE,&Privileges,NULL,NULL,NULL); 

ExitWindowsEx(EWX_POWEROFF,0); 


//*************************************** 

//创建一个非模态对话框,如 
//1声明父对话框 
#include "Tx.h" 
//2在头文件中改为CTx* pParent = NULL,并声明CTx *tx; 
public: 
CInputmr(CTx* pParent = NULL); // standard constructor 
CTx *tx; 
//3在CPP文件中改为CTx* pParent /*=NULL*/,并声明ID:CDialog(CInputmr::IDD, pParent)和tx(pParent) 
CInputmr::CInputmr(CTx* pParent /*=NULL*/) 
: CDialog(CInputmr::IDD, pParent),tx(pParent) 

if(Create(CInputmr::IDD,pParent))//创建 
ShowWindow(SW_SHOW);//显示窗口 
//就可以使用 tx-> 了 




常用网络数据包报头结构->以太网、ARP、IP、TCP、UDP、ICMP、DNS、UDP伪报头*************************************** 

#pragma pack(1) 
typedef struct ethdr //以太网包头14字节 

unsigned char destination_mac[6];//目标MAC 6字节 
unsigned char source_mac[6];//源MAC 6字节 
unsigned short type;//后面的协议类型2字节 为0806表示后面跟的包为ARP包 
}ET_HEADER,*PETHDR; 

typedef struct arphdr //arp协议28字节 

unsigned short hard_tpye;//硬件类型2字节 通常为01 (以太网地址) 
unsigned short protocol;//协议类型2字节 通常为80 (IP地址) 
unsigned char hard_length;//硬件地址长度1字节 通常为6 
unsigned char protocol_length;//协议地址长度1字节 通常为4 (IP协议) 
unsigned short operation_type;//操作类型 1为ARP请求,2为ARP应答,3为RARP请求,4为RARP应答 
unsigned char source_mac[6];//源物理地址 
struct in_addr source_ip;//源IP地址 
unsigned char destination_mac[6];//目的物理地址 
struct in_addr destination_ip;//目的IP地址 
}ARP_HEADER,*PARPHDR; 


// IP Header -- RFC 791 IP数据报头 
typedef struct tagIPHDR 

u_char VIHL; // Version and IHL 版本4bit = 4 和 首部长度4bit = 5 
u_char TOS; // Type Of Service 服务类型 1字节 
short TotLen; // Total Length 总长度2字节,包括数据和报头 
short ID; // Identification 标识符2字节 
short FlagOff; // Flags and Fragment Offset 标志 3bit 和分段偏移量 13bit 
u_char TTL; // Time To Live 生存期1字节,为经过路由器的总次数 
u_char Protocol; // Protocol 协议类型1字节 
u_short Checksum; // Checksum 首部(只是IP首部!!不然就错了,过不了网关!!)校验和2字节 
struct in_addr source_ip; // Internet Address - Source 源IP地址 
struct in_addr destination_ip; // Internet Address - Destination 目的IP地址 
}IP_HEADER, *PIP_HEADER; 

//TCP Header TCP数据报头 
typedef struct tcp_hdr 

unsigned short source_port; //源端口 
unsigned short destination_port; //目的端口 
unsigned long index; //32位序号 
unsigned long makesuer_index; //32位确认序号 
unsigned short header_length_and_flags; //首部长度和标志位 
unsigned short window_size; //窗口大小 
unsigned short checksum; //检查和 
unsigned short exigency_pointer; //紧急指针 
}TCP_HEADER; 

//UDP Header --UDP数据报头 

typedef struct udp_hdr 

unsigned short source_port; //源端口 
unsigned short destination_port; //目的端口 
unsigned short length; //数据长度 
unsigned short checksum; //带数据!检查和 
} UDP_HEADER; 


// ICMP Header - RFC 792 ICMP数据报头 
typedef struct tagICMPHDR 

u_char Type; // Type 类型 
u_char Code; // Code 代码 
u_short Checksum; // Checksum 校验和 
u_short ID; // Identification 标识符 
u_short Seq; // Sequence 序列号 
char Data; // Data 数据(依情况而定) 
}ICMP_HEADER, *PICMP_HEADER; 


// ICMP Echo Request ICMP 请求数据报 
typedef struct tagECHOREQUEST 

ICMPHDR icmpHdr; 
DWORD dwTime; 
char cData[32]; 
}IMCP_REQUEST, *PIMCP_REQUEST; 


// ICMP Echo Reply ICMP 回响数据报 
typedef struct tagECHOREPLY 

IPHDR ipHdr; 
ECHOREQUEST echoRequest; 
char cFiller[256]; 
}ICMP_REPLY, *ICMP_REPLY; 


typedef struct dns //DNS数据报: 

unsigned short id;//标识,通过它客户端可以将DNS的请求与应答相匹配; 
unsigned short flags;//标志:[QR | opcode | AA| TC| RD| RA | zero | rcode ] 
unsigned short quests;//问题数目; 
unsigned short answers;//资源记录数目; 
unsigned short author;//授权资源记录数目; 
unsigned short addition;//额外资源记录数目; 
}DNS,*PDNS; 
//在16位的标志中:QR位判断是查询/响应报文,opcode区别查询类型,AA判断是否为授权回答,TC判断 
//是否可截断,RD判断是否期望递归查询,RA判断是否为可用递归,zero必须为0,rcode为返回码字段。 

typedef struct psd //伪报头,用于计算UDP校验和 

unsigned int source_ip; //源IP 
unsigned int destination_ip; //目的IP 
char mbz; // 0 
char protocol; //协议 UDP = 17 
unsigned short udp_length; //UDP 长度 
}PSD,*PPSD; 

//DNS查询数据报: 
typedef struct query 

unsigned short type; //查询类型,大约有20个不同的类型 
unsigned short classes; //查询类,通常是A类既查询IP地址。 
}QUERY,*PQUERY; 

//DNS响应数据报: 
typedef struct response 

unsigned short name; //查询的域名 
unsigned short type; //查询类型 
unsigned short classes; //类型码 
unsigned int ttl; //生存时间 
unsigned short length; //资源数据长度 
unsigned int addr; //资源数据 
}RESPONSE,*PRESPONSE; 

#pragma pack() 


网络编程部分源码->校验和、隐藏IP方法、取得本地MAC******************************** 

//注意!!!!!! 
//IP的检查和只是IP头部的20个字节,不然过不了网关!!!! 
//而TCP和UDP和检查和是数据和头部都包括!! 
//在计算检查和之前IP或UDP或TCP报头中 所有的成员 必须被初始化,包括 checksum!!! 


//为了保证系统和机器的******兼容性******,在定义网络结构体或共用体时要加上 
#pragma pack(1) 
#pragma pack() 
//如: 
#pragma pack(1) 
typedef struct response 

unsigned short name; 
unsigned short type; 
unsigned short classes; 
unsigned int ttl; 
unsigned short length; 
unsigned int addr; 
}RESPONSE,*PRESPONSE; 
#pragma pack() 
//sizeof(RESPONSE)==16,如果不加#pragma pack那么sizeof(RESPONSE)==20 

//局域网内相同网段下的IP地址,数据包直接发给该主机的MAC地址,不同网段下的,数据包发给网关, 
//如:202.198.153.17->202.198.153.64 以太包目的地址为202.198.153.64 的MAC地址 
//如:202.198.153.17->202.198.159.139 以太包目的地址为202.198.153.254(网关) 的MAC地址 

//隐藏IP的方法************************************************************************ 

WSADATA wsd; 
SOCKET s; 
BOOL bOpt; 
struct sockaddr_in remote; 
USHORT *buf=NULL; 
ECHOREQUEST icmpHdr; 
int ret; 
unsigned short iTotalSize, 
iIPVersion, 
iIPSize, 
cksum = 0; 

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)//打开WSA网络函数 

MessageBox("WSAStartup() failed: "); 
return ; 


s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0);//建立SOCKET,注意第二个一定为SOCK_RAW 
if (s == INVALID_SOCKET) 

MessageBox("WSASocket() failed: "); 
return ; 

bOpt = TRUE; 
//设置SOCKET属性 
ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt, sizeof(bOpt)); 

if (ret == SOCKET_ERROR) 

MessageBox("setsockopt(IP_HDRINCL) failed: %d/n"); 
return ; 

//修改IP包的值 
iTotalSize = sizeof(icmpHdr) ; 

iIPVersion = 4; 
iIPSize = sizeof(IP_HDR) / sizeof(unsigned long); 

icmpHdr.ipHdr.ip_verlen = (iIPVersion << 4) | iIPSize; 
icmpHdr.ipHdr.ip_tos = 0; 
icmpHdr.ipHdr.ip_totallength = htons(iTotalSize); 
icmpHdr.ipHdr.ip_id = 0; 
icmpHdr.ipHdr.ip_offset = 0; 
icmpHdr.ipHdr.ip_ttl = 128; 
icmpHdr.ipHdr.ip_protocol = 1; //ICMP 
buf=(USHORT *)&icmpHdr; 
icmpHdr.ipHdr.ip_checksum = checksum(buf,sizeof(IP_HDR)); 
icmpHdr.ipHdr.ip_srcaddr = inet_addr(m_source_ip); 
icmpHdr.ipHdr.ip_destaddr = inet_addr(m_destinition); 

icmpHdr.icmpHdr.Type=8; 
icmpHdr.icmpHdr.Code=0; 
icmpHdr.icmpHdr.ID=1; 
icmpHdr.icmpHdr.Seq=1; 
buf=(USHORT *)&icmpHdr; 
icmpHdr.icmpHdr.Checksum=checksum(buf+sizeof(IP_HDR),sizeof(icmpHdr)-sizeof(IP_HDR)); 
icmpHdr.dwTime=GetTickCount(); 

remote.sin_family = AF_INET; 
remote.sin_port = 0; 
remote.sin_addr.s_addr = inet_addr(m_destinition); 

struct timeval Timeout; 
fd_set readfds; 

readfds.fd_count = 1; 
readfds.fd_array[0] = s; 
Timeout.tv_sec = 1; 
Timeout.tv_usec = 0; 
int nRet; 
int nAddrLen = sizeof(struct sockaddr_in); 
ECHOREPLY echoReply; 

CString cs; 

for(int i=0;i<m_ping_times;i++) 
{ //发送IP包 
ret = sendto(s, (char *)&icmpHdr, iTotalSize, 0, (SOCKADDR *)&remote, sizeof(remote)); 
if (ret == SOCKET_ERROR) 
MessageBox("sendto() failed:"); 
/* 
select(1, &readfds, NULL, NULL, &Timeout); 

//接收请求回应 
nRet = recvfrom(s, 
(LPSTR)&echoReply, 
sizeof(ECHOREPLY), 
0, 
(LPSOCKADDR)&remote, 
&nAddrLen); 

//检查返回值 
if (nRet == SOCKET_ERROR) 
MessageBox("recvfrom()"); 
cs.Format("%d",echoReply.ipHdr.ip_ttl); 
MessageBox(cs); 
//返回发送的时间 
*/ 
Sleep(m_separete); 


closesocket(s) ; 
WSACleanup() ;//关闭WSA 



//校验和程序***************************************************************************** 

USHORT CFffDlg::checksum(USHORT *buffer, int size) 

unsigned long cksum=0; 

while (size > 1) 

cksum += *buffer++; 
size -= sizeof(USHORT); 

if (size) 

cksum += *(UCHAR*)buffer; 

cksum = (cksum >> 16) + (cksum & 0xffff); 
cksum += (cksum >>16); 

return (USHORT)(~cksum); 


//取得本地机器IP地址********************************************************************************************* 

WORD wv=MAKEWORD(1,1); 
WSADATA ws; 
WSAStartup(wv,&ws); 
char name[256]; 
gethostname(name,256); 
HOSTENT *hos=gethostbyname(name); 
CString cs; 
for(int i=0;hos!=NULL&&hos->h_addr_list[i]!=NULL;i++) 

cs=inet_ntoa(*(struct in_addr*)hos->h_addr_list[i]); 
MessageBox(cs); 


WSACleanup(); 

//取得本地MAC地址********************************************************************************************* 
#include <lm.h> 
NetApi32.lib 
unsigned char macdata[8]; 
WKSTA_TRANSPORT_INFO_0 * pwkti; 
DWORD dwe,dwt; 
BYTE *pb; 
NET_API_STATUS dws=NetWkstaTransportEnum( 
NULL, 
0, 
&pb, 
MAX_PREFERRED_LENGTH, 
&dwe, 
&dwt, 
NULL); 
pwkti=(WKSTA_TRANSPORT_INFO_0 *)pb; 
CString cs; 
for(DWORD i=1;i<dwe;i++) 

swscanf((wchar_t *)pwkti[i].wkti0_transport_address,L"%2hx%2hx%2hx%2hx%2hx%2hx",&macdata[0], 
&macdata[1],&macdata[2],&macdata[3],&macdata[4],&macdata[5]); 
cs.Format("%02x%02x%02x%02x%02x%02x",macdata[0], 
macdata[1],macdata[2],macdata[3],macdata[4],macdata[5]); 
MessageBox(cs); 

NetApiBufferFree(pb); 
//ADO连接代码************************************************************** 
//用#import引用msado15.dll。可以直接在Stdafx.h文件中加入 
#import "c:/program files/common files/system/ado/msado15.dll" / 
no_namespace / 
rename ("EOF", "adoEOF") 

// 定义ADO连接、命令、记录集变量指针 
_ConnectionPtr m_pConnection; 
_CommandPtr m_pCommand; 
_RecordsetPtr m_pRecordset; 

//初始化连接 
AfxOleInit(); 
m_pConnection.CreateInstance(__uuidof(Connection)); 
m_pRecordset.CreateInstance(__uuidof(Recordset)); 

// 在ADO操作语句中要常用try...catch()来捕获错误信息, 
// 因为它会经常出现一些意想不到的错误。 
try //打开库 

// 打开本地Access库Demo.mdb 
m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Demo.mdb","","",adModeUnknown); 

catch(_com_error e) 

AfxMessageBox("数据库连接失败,确认数据库Demo.mdb是否在当前路径下!"); 
return FALSE; 

try //打开表 

m_pRecordset->Open("Select * FROM DemoTable", // 查询DemoTable表中所有字段 
m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针 
adOpenDynamic, 
adLockOptimistic, 
adCmdText); 

catch(_com_error *e) 

AfxMessageBox(e->ErrorMessage()); 

//m_CListBox.AddString((LPCSTR)_bstr_t(m_pRecordset->GetCollect("Name")));//获得Name字段的值 
//m_pRecordset->PutCollect("Name", _variant_t(m_Name)); // 写入各字段值 


第一部分:记录集 


记录集是从数据库中按一定查询条件读入到内存中的一批记录,以供快速的操作。 
记录集recordset对象的属性,方法: 
BOF:当记录集记录指针指到起始记录(第1条记录)再向前移(即超过第1条记录),这时返回true.常用来对付一些出错情况。注:在BOF或EOF时使用update方法会出错。 
EOF:当记录指针指到最后一条记录之后(即超过了最后1条记录)时,该属性返回true.注:当一个记录集为空时,其BOF和EOF属性都为True,可据此检测一个记录集是否为空。 
AbsolutePosition:返回当前记录指针,即当前记录是第几条记录,只读。 
BookMark: 设置/返回当前记录指针的书签,为字符串。如: 
在当前记录处设置书签:lxn=Adodc1.Recordset.BookMark 
当指针移动后回到指定书签位置:Adodc1.Recordset.BookMark=lxn. 
返回记录集中记录的总数:RecordCount属性。该属性对于表形式的记录集将返回精确数目,但对于仅向前型记录集(adOpenForwardOnly),返回-1。动态记录集(adOpenDynamic)则不一定,可能返回-1,与记录集的CursorLocation有关;而对于静态记录集(adOpenStatic),也总能返回精确数目。附:在DAO中,对动态集和快照集需要先用MoveFirst和Movelast方法,再用RecordCount取得记录精确数目。 
Move方法:移动记录集指针。该方法有两个参数,第一个参数指定要向前或向后移动多少条记录,第二个参数指定一个相对书签位置,表明从当前记录还是从第1条或最后1条记录开始算,缺省为0从当前记录开始移,将指针从当前位置向前(负数)或向后(正数)移动指定条记录(第二个‘按书签移动’参数设为0-adBookMarkCurrent从当前记录开始,缺省)或将指针从第1条记录算起移动指定条记录(第二个参数设为1-adBookMarkFirst从首记录)。或将指针从最后1条记录算起移动指定条记录(第二个参数设为adBookMarkLast),如:Adodc1.Recordset.Move -12,将指针从当前位置向前移动12条记录,再如Adodc1.Recordset.Move 6 , 1表示指针从首记录开始后移6条记录,即使指针移到第7条记录。Move方法有几个引申的方法,如下: 
movefirst,记录集指针移到第1条记录; 
movelast,记录集指针移到最后1条记录; 
moveprevious,记录集指针移到上一条记录; 
movenext,记录集指针移到下一条记录。 
Find方法:查找满足条件的记录。 
find方法简略格式为: 
adodc对象.recordset.find 查找表达式(为“字段 比较符号 值”) 
其他参数采用缺省,find工作方式是:从当前记录指针位置开始(含当前记录)向后逐条检索记录,遇到满足条件的1条记录就停下来,指针指到此记录。 
因此,若要实现“继续寻找下1个”的功能,只要将记录指针移到下1条记录(用movenext一下),再照原样使用find即可。 而重新查找必须先用movefirst将指针指到开头。 
Adodc1.Recordset.find "姓名 = '李长春'" 
其中查找表达式的样子为“字段 比较符号 值”,比较符号不仅可以是等号,还可以是>,<,<=,>=,<>,like等。其中Like和 = 很相近,只不过like专用于字符串比较,不区分字母的大小写可用通配符,而 = 号会区分字母大小写不能用通配符。 
一般情况下,查找表达式常采用变量表示,由用户来确定,如下: 
Dim lxn As String 
Static a As String 
a = InputBox("请输入查找姓名","查找") 
lxn = "NAME like '" & a & "'" 
.Find lxn 

LockType属性:设置记录集中的记录锁定方式,是否可修改及修改方式:有1-adLockReadOnly(只读);2-adLockPessimistic(保守式修改),当修改记录后立即将更改保存到数据源,3-adLockOptimistic(开放式修改),当修改记录后只有调用Update方法才将更改保存到数据源;4-adLockBatchOptimistic(开放式批处理修改)。当修改记录后只有调用UpdateBatch方法才将更改保存到数据源。对于ADO对象而言,该属性的缺省值为1-adLockReadOnly只读,要编辑记录则必须加以改变。 
Update方法:对记录集当前记录的更改进行保存到数据库。 
UpdateBatch方法:成批保存更改的多条记录。只有当记录集使用锁定方式为adLockBatchOptimistic打开时该方法才有效。使用该方法,可以加快更新速度。因为一条一条更新的话,速度慢,而多条一起更新的话,其实等同于一个更新操作,因此更快。该方法有个可选参数AffectRecords提一下,它可设为:adAffectCurrent只更新当前记录;adAffectGroup只更新当前Filter属性满足的记录;adAffectAll(缺省)全部更新,包括被当前Filter属性隐藏的记录。 
CancelUpdate方法:放弃保存对当前记录自上次Update后的更改,即不保存当前所作的修改。通常在WillChangeRecord事件中进行数据验证时用。当然一般是直接将事件提供的参数adStatus设为adStatusCancel即可取消保存。这里要注意,在WillChangeRecord事件中取消一个操作,将发生“操作已取消”的错误。照我的感觉,还不如直接在要Update的代码前面去验证输入的数据。 
在记录集中添加新记录,用addnew方法先在缓存中添加一个新的空记录,这时它自动成为当前记录,通过修改,然后用update方法保存,data1.recordset.update,说明:如果用Movenext等方法将记录指针移开时记录集会自动保存缓存中的记录(等于调用Update方法)。 
修改当前记录,只要直接给字段赋值就可以了,注意赋值后也要用Update方法将缓存中的数据保存,否则不会自动更新,除非用MoveNext等方法将指针移开让它自动调用。 
删除当前记录用Delete方法就行了。有一点要注意,删除后,记录指针仍在被删除的记录上,因此要用MoveNext等方法将指针移开,或干脆Requery刷新一下。 
Sort:指定用来对全部记录排序的参照字段。 
Fields:包含记录集中各字段的集合。指定某个字段格式为:fields("字段名")。可省略。如有:m$=data1.recordset.fields("姓名").value为读当前记录(用value表示)的“姓名”字段值。还可用来在代码中修改(写)记录值(不是用绑定控件),如修改记录值为“李新能”:data1.recordset.fields("姓名").value="李新能"。也可写为data1.recordset("姓名").value,括号内写明字段名或“字段索引值”,第1个字段索引值从0开始。如data1.recordset(0).value. 
关闭记录集用close方法,格式为“记录集.close”。 
要读或写当前记录的某个字段值,只要用“记录集("字段名")”就可以了,Fields和Value都是缺省属性,但当值是一个记录集的除外,如数据环境中Command命令对象的子命令对象。 
刷新记录集(即重新打开记录集):Requery方法。在记录集打开的情况下,迅速关闭又打开一次,以达到确保记录集始终处于激活状态。 
返回/设置记录集当前编辑状态:EditMode属性。有以下三个可能返回值:adEditNone没有编辑;adEditInProgress正在编辑(即当前记录已修改但未保存);adEditAdd已经用AddNew方法添加新记录但还未存盘,在缓存中的是新记录。这个属性通常用来检测某些操作状态,比如可在窗体的Unload事件中防止修改了的记录未保存就卸载。 
★ AbsolutePage属性:指定当前记录所在的页。其值的范围在1—PageCount值之间,所谓页,是把Recordset对象按PageSize为标准分为若干页面,每一页(除最后一页)记录数相等(等于PageSize)。有三个特殊值:adPosUnkown未知位置;adPosBOF在文件头;adPosEOF在文件尾。 
★ ActiveCommand:属性:只读属性。返回关联的Command对象,如果记录集不是由Command对象创建的,则返回Null. 
★ ActiveConnection属性:设置/返回记录集基于哪个Connection对象,如果没有Connection对象,则直接指定一个连接字符串。 
★ Cancel: 取消执行异步 Execute(对Connection和Command对象而言) 或 异步Open 方法调用(即通过 adAsyncConnect、adAsyncExecute 或 adAsyncFetch 参数选项调用这些方法)。 
★ CacheSize属性:本地内存缓存的大小。 
★ CancelBatch方法: 取消批更新模式下记录集中所有还未执行的更新。 
★ Clone方法:复制一个记录集。格式:Set 记录集变量=记录集.Clone [adLockReadOnly]当指定可选参数adLockReadOnly表示创建只读的记录集副本。使用 Clone 方法可创建多个 Recordset 对象副本,这对于希望在给定的记录组中保留多个当前记录十分有用。使用 Clone 方法比使用与初始定义相同的定义创建和打开新 Recordset 对象要有效得多。新创建副本的当前记录将设置为首记录。无论游标类型如何,对某个 Recordset 对象所作的修改在其所有副本中都是可见的。不过一旦在原始 Recordset 上执行了 Requery,副本将不再与原始 Recordset 同步。关闭原始 Recordset 时并不关闭它的副本,而关闭某个副本也将不关闭原始 Recordset 或任何其他副本。用户只允许复制支持书签的 Recordset 对象。书签值是可交换的,也就是说,来自一个 Recordset 对象的书签引用可引用其任何副本中的相同记录。 
★ CompareBookmarks: 比较两个书签并返回它们相差值的说明。即谁先谁后。 
★ CursorLocation: 设置或返回游标服务的位置。游标:可以简单理解为指向若干行的指针。有三种设置值:adUseNone 没有使用游标服务。(该常量已过时并且只为了向后兼容才出现,通常不用)。adUseClient 使用由本地游标库提供的客户端游标,通常使用这种游标。adUseServer 使用数据提供者的或驱动程序提供的游标。 
该属性应在建立连接之前设置,更改 CursorLocation 属性不会影响现有的连接。 
远程数据服务用法 当用于客户端 (ADOR) Recordset 或 Connection 对象时,只能将 CursorLocation 属性设置为 adUseClient。 
★ CursorType: 指示在 Recordset 对象中使用的游标类型。AdOpenForwardOnly 仅向前游标,默认值。除了只能在记录中向前滚动外,与静态游标相同。当只需要在记录集中单向移动时,使用它可提高性能。 
AdOpenKeyset 键集游标。尽管从您的记录集不能访问其他用户删除的记录,但除无法查看其他用户添加的记录外,键集游标与动态游标相似。仍然可以看见其他用户更改的数据。 
AdOpenDynamic 动态游标。可以看见其他用户所作的添加、更改和删除。允许在记录集中进行所有类型的移动,但不包括提供者不支持的书签操作。 
AdOpenStatic 静态游标。可以用来查找数据或生成报告的记录集合的静态副本。另外,对其他用户所作的添加、更改或删除不可见。 
说明:使用 CursorType 属性可指定打开 Recordset 对象时应该使用的游标类型。Recordset 关闭时 CursorType 属性为读/写,而 Recordset 打开时该属性为只读。 
如果将 CursorLocation 属性设置为 adUseClient 则只支持 adOpenStatic 的设置。 
★ Filter属性:过滤器。对记录集进行筛选,返回记录集中满足条件的所有记录,该属性指定一个筛选字符串,为一个“字段-比较符号-值”的条件表达式,当该属性赋值后,记录集立即变成筛选后的方式,包括如 AbsolutePosition、AbsolutePage、RecordCount 和 PageCount等属性都将改变,“变”成了一个“新”记录子集,当前记录移动到记录子集的第一个记录。而当清除 Filter 属性后,记录集立即恢复,当前记录位置将移动到原Recordset 的第一个记录。 
关于“字段-比较符号-值”的说明:“字段” 必须为 Recordset 中的有效字段名。如果字段名包含空格,必须用方括号将字段名括起来。 
“比较符号”必须使用的操作符为:<、>、<=、>=、<>、= 或 LIKE。 
“值” 是用于与字段值(如 'Smith'、#8/24/95#、12.345 或 $50.00)进行比较的值。字符串使用单引号而日期使用井号 #(注:在SQL中不用#号),对于数字,可以使用小数点、货币符号和科学记数法。如果 “比较符号” 为 LIKE,“值” 则可使用通配符。ADO和SQL只允许使用下划线(_) 和百分号 (%) 通配符,而且必须为字符串的尾字符。DAO只允许使用问号(?)和星号(*)作通配符.“值” 不可为 Null。在 LIKE 子句中,可在样式的开头和结尾使用通配符(如 LastName Like '*mit*'),或者只在结尾使用通配符(如,LastName Like 'Smit*') 
Filter属性还有几个特殊值可供选择:AdFilterNone 删除当前筛选条件并恢复查看所有记录。同空字符串””。 AdFilterPendingRecords 允许只查看已更改且尚未发送到服务器的记录。只能应用于批更新模式。 AdFilterAffectedRecords 允许只查看上一次 Delete、Resync、UpdateBatch 或 CancelBatch 调用所影响的记录。 AdFilterFetchedRecords 允许查看当前缓冲区中的记录,即上一次从数据库中检索记录的调用结果。 AdFilterConflictingRecords 允许查看在上一次批更新中失败的记录。 
★ GetRows方法: 将Recordset的多个记录值复制到数组中,应当先定义一个变体变量,然后将GetRows的返回值赋给它,这个变量就成了一个二维数组,其第一维下标标识原所在的列(字段),第二维下标标识原所在的行(记录),每一个交叉点就是一个值了,如: 
Dim VariData As Variant 
VariData = DataEnvironment1.rsCommand1.GetRows 
x = UBound(VariData, 1) 
y = UBound(VariData, 2) 
For m = 0 To x 
For n = 0 To y 
Print VariData(m, n); ‘用分号表示同一字段的数据打印在同一行。 
Next n 
Print 
Next m 
该方法格式:变体变量=记录集.GetRows([rows],[start],[fields])有三个可选参数,第一个参数Rows限制返回的记录数量,即要复制几行记录,它决定的是变体数组的第二维长度,缺省情况下,将读取记录集中的所有记录。第二个参数Start指定从哪个记录位置开始向数组复制记录,可以是一个记录书签字符串,或以下三个常数之一:adBookMarkCurrent(当前记录)adBookMarkFirst(首记录录)adBookMarkLast(尾记录);第三个参数Fields限制返回的记录字段,即要复制哪几列,它决定的是变体数组的第一维长度,缺省情况下,将读取记录集中的所有字段,该参数可设置为单个字段名字符串,或多个字段名字符串组成的数组。 
注意:使用该方法复制记录值时,记录指针将随之移动,每复制一行后,指针自动移动到下一行。 
★ GetString: 将 Recordset 按字符串值的变体型 (BSTR) 返回。 
★ MarshalOptions: 汇集选项。指示要被调度返回服务器的记录。可选设置值:AdMarshalAll 默认值。表明所有行将返回到服务器。 AdMarshalModifiedOnly 表明只有已修改的行返回到服务器。当使用客户端 (ADOR) Recordset 时,已在客户端被修改的记录将通过称作“调度”的技术写回中间层或 Web 服务器。 
★ MaxRecords: 指示通过一次查询返回 Recordset 的记录的最大数目。使用 MaxRecords 属性可对从数据源返回的记录数加以限制。该属性的默认设置为零,表明提供者返回所有所需的记录。Recordset 关闭时,MaxRecords 属性为读/写,打开时为只读。 
★ NextRecordset:清除当前Recordset对象,执行下一个命令返回新的Recordset对象。当一个命令语句是复合语句(即用分号隔开的多条命令)?时,用该方法依次执行下一条命令。格式:Set recordset2=recordset1.NextRecordset。例如: 
Dim rst As ADODB.Recordset 
Dim strCnn As String 
Dim strCmd As String 
strCnn = "Provider=Microsoft.Jet.OLEDB.3.51;Persist Security Info=False;Data Source=C:/工商所收费系统/MyDatabase.mdb" 
strCmd = "Select * FROM unitrecord;Select * FROM invoice" ‘AccessSQL不支持。 
Set rst = New ADODB.Recordset 
rst.Open strCmd, strCnn, adOpenDynamic, adLockOptimistic, adCmdText 
Print rst("Name") 
Set rst = rst.NextRecordset 
Print rst("Name") 
rst.Close 
★ Open:打开一个游标,即记录集。 
★ PageCount:页面数。 
★ PageSize:每页大小,缺省为10。 
★ Properties: 
★ Resync: 
★ Save: 
★ Seek方法:使用索引进行查询,比用Find方法速度更快,但只能用于以表形式打开的记录集,不能用于动态记录集或快照型记录集,不能在远程服务器表上使用Seek,因为远程数据源不能以表形式打开。而且这个表预先定义了索引字段,使用Seek方法前,要在代码中用Index属性指定当前要使用的索引,格式为:记录集对象.Index=索引名。索引名是在表的设计阶段定义好的。注意索引名不等于字段名,只不过是以某个字段为标准的。设置好要使用的索引后,使用Seek进行查找,格式:Recordset对象.Seek 值,这里的值参数指定按当前索引所属字段进行查找的值,若找到,则指针指到此记录,若没找到,则EOF为True. 
一般情况下,在ADO中都不用Seek进行定位,而是用SQL查询生成动态记录集。只是在DAO中有一些使用,如:
Private Sub Command2_Click() 
Data1.Recordset.Index = "indexName" 
Data1.Recordset.Seek "=", "李春生" 
Text1.Text = Data1.Recordset(2) 
End Sub 
其格式有一点不同,它的第一参数指定一个比较符号,第二个参数才是值,需要在属性窗口中将DATA1的RecordsetType属性设置为0-Table。 
★ Sort: 
★ Source:数据源。 
★ State:对象的当前状态,有adStateClosed(关闭)或adStateOpen(打开)。 
★ Status:批量操作或海量操作的状态。 
★ StayInSync: 
★ Supports方法:判断本记录集是否具有某个方面的功能。如:是否允许增添记录If rst.Supports(adAddnew)=True then rst.Addnew,如果具有某项功能则返回True,不具备则返回False,该方法的一个参数是指定哪个方面,如adDelete是否允许删除记录,adBookmark是否支持书签设置,adUpdate是否允许更新(即修改)数据源,adIndex是否可以使用index属性设置索引,adSeek是否可用Seek方法定位记录指针。再如判断是否支持索引:MsgBox DataEnvironment1.rsCommand1.Supports(adIndex)。 
记录集有五种不同的类型: 
Table:表示数据库中一张表,记录集与数据库中的数据同步,可通过记录集对数据库添加,删除等操作。 
Dynaset:一张查询结果集,可由多个表中不同数据组成,可通过记录集对数据库进行添加、删除等操作。 
Dynamic:与dynaset相似,但它有这样的功能:当其他用户修改记录集的基表(数据库表)时,会将修改反映到这个记录集中,主要用于多用户操作。 
SnapShot:一张只读的查询结果集,可包含不同表中数据记录,不能对记录添加,修改等,可用于浏览数据库。 
Forward-Only:一个没游标的SnapShot记录集,只能从头到尾顺序经过所有记录,不能任意移动。 

//ODBC动态创建数据源********************************************************* 

#define ODBC_ADD_DSN 1 // Add data source 
#define ODBC_CONFIG_DSN 2 // Configure (edit) data source 
#define ODBC_REMOVE_DSN 3 // Remove data source 
#include <odbcinst.h> 

CString sPath; 
GetModuleFileName(NULL,sPath.GetBufferSetLength(MAX_PATH+1),MAX_PATH); 
sPath.ReleaseBuffer (); 
int nPos; 
nPos=sPath.ReverseFind ('//'); 
sPath=sPath.Left (nPos); 
nPos=sPath.ReverseFind('//'); 
sPath=sPath.Left (nPos); 
CString lpszFile = sPath + "//DataBase.mdb"; 


char* szDesc; 
int mlen; 
szDesc=new char[256]; 
sprintf(szDesc,"DSN=%s? DESCRIPTION=TOC support source? DBQ=%s? FIL=MicrosoftAccess? DEFAULTDIR=%s?? ","zth",lpszFile,sPath); 



mlen = strlen(szDesc); 
for (int i=0; i<mlen; i++) 

if (szDesc[i] == '?') 
szDesc[i] = '/0'; 


if (FALSE == SQLConfigDataSource(NULL,ODBC_ADD_DSN,"Microsoft Access Driver (*.mdb)/0",(LPCSTR)szDesc)) 
AfxMessageBox("SQLConfigDataSource Failed");