之前一直使用微软官方提供的MFC串口控件来实现PC端与嵌入式端的串口通讯,但是最近发现Win7系统以上的默认已经不支持这个串口库了,需要自行加载,为了方便发布和代码高效,我找了一个空闲的时间去重新封装了一个基于WIN32 API的一个串口 类,主要是发现网上大部分都是通过Write()来阻塞的,不能说你不高效什么的,但是Windows是基于事件驱动的,这样你只能读到数据,而串口还有很多事件发生你是不知道的,例如振铃、或出错那些,(虽然现在已经没人用),但我是MFC的热衷玩家,我还是把它做成了基于事件响应,其他窗口随时可以接收串口IO消息。
MFC串口消息监听请移步我下一篇文章,此部分为WIN32 API基础
以下是一些过程大概(有引用网络上的各部分资料)
在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序简单,但欠灵活。其二是调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。
串口的操作可以有两种操作方式:同步操作方式和重叠操作方式(又称为异步操作方式)。
同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程);而重叠操作方式,API函数会立即返回,操作在后台进行,避免线程的阻塞。
无论那种操作方式,一般都通过四个步骤来完成:
(1)打开串口
(2)配置串口
(3)读写串口
(4)关闭串口
1、打开串口
Win32系统把文件的概念进行了扩展。无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。该函数的原型为:
C++代码
1
HANDLE CreateFile( LPCTSTR lpFileName,DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLEhTemplateFile);
lpFileName:将要打开的串口逻辑名,如"COM1";
dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;
dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0;
lpSecurityAttributes:引用安全性属性结构,缺省值为NULL;
dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING;
dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作;
hTemplateFile:对串口而言该参数必须置为NULL。
同步I/O方式打开串口的示例代码:C++代码
HANDLE hCom; //全局变量,串口句柄
hCom=CreateFile("COM1",//COM1口
GENERIC_READ|GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
0, //同步方式
NULL);
if(hCom==(HANDLE)-1)
{
AfxMessageBox("打开COM失败!");
return FALSE;
}
return TRUE;
重叠I/O打开串口的示例代码:
C++代码
HANDLE hCom; //全局变量,串口句柄
hCom =CreateFile("COM1", //COM1口
GENERIC_READ|GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//重叠方式
NULL);
if(hCom ==INVALID_HANDLE_VALUE)
{
AfxMessageBox("打开COM失败!");
return FALSE;
}
return TRUE;
2、配置串口
在打开通讯设备句柄后,常常需要对串口进行一些初始化配置工作。这需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区。
一般用CreateFile打开串口后,可以调用GetCommState函数来获取串口的初始配置。要修改串口的配置,应该先修改DCB结构,然后再调用SetCommState函数设置串口。
DCB结构包含了串口的各项参数设置,下面仅介绍几个该结构常用的变量:
typedef struct _DCB{ ………
DWORD BaudRate;//波特率,指定通信设备的传输速率。这个成员可以是实际波特率值或者下面的常量值之一: CBR_110,CBR_300,CBR_600,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_19200, CBR_38400, CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000, CBR_14400
DWORD fParity; // 指定奇偶校验使能。若此成员为1,允许奇偶校验检查…
BYTE ByteSize; // 通信字节位数,4—8
BYTE Parity; //指定奇偶校验方法。此成员可以有下列值: EVENPARITY 偶校验 NOPARITY 无校验 MARKPARITY 标记校验 ODDPARITY 奇校验
BYTE StopBits; //指定停止位的位数。此成员可以有下列值: ONESTOPBIT 1位停止位 TWOSTOPBITS 2位停止位
ON 5STOPBITS 1.5位停止位
GetCommState函数可以获得COM口的设备控制块,从而获得相关参数:
BOOLGetCommState(
HANDLEhFile,//标识通讯端口的句柄
LPDCBlpDCB//指向一个设备控制块(DCB结构)的指针 );
SetCommState函数设置COM口的设备控制块:
BOOLSetCommState(HANDLEhFile,LPDCBlpDCB);
除了在BCD中的设置外,程序一般还需要设置I/O缓冲区的大小和超时。Windows用I/O缓冲区来暂存串口输入和输出的数据。如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。
BOOL SetupComm( HANDLE hFile, // 通信设备的句柄
DWORD dwInQueue, // 输入缓冲区的大小(字节数)
DWORD dwOutQueue // 输出缓冲区的大小(字节数));
在用ReadFile和WriteFile读写串行口时,需要考虑超时问题。超时的作用是在指定的时间内没有读入或发送指定数量的字符,ReadFile或WriteFile的操作仍然会结束。
要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。调用SetCommTimeouts可以用某一个COMMTIMEOUTS结构的内容来设置超时。
读写串口的超时有两种:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延。总超时是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。用COMMTIMEOUTS结构可以规定读写操作的超时。
COMMTIMEOUTS结构的定义为:
typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout; //读间隔超时
DWORD ReadTotalTimeoutMultiplier; //读时间系数
DWORD ReadTotalTimeoutConstant; //读时间常量
DWORD WriteTotalTimeoutMultiplier; // 写时间系数
DWORD WriteTotalTimeoutConstant; //写时间常量
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
COMMTIMEOUTS结构的成员都以毫秒为单位。
总超时的计算公式是:总超时=时间系数×要求读/写的字符数+时间常量
例如,要读入10个字符,那么读操作的总超时的计算公式为:
读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant
可以看出:间隔超时和总超时的设置是不相关的,这可以方便通信程序灵活地设置各种超时。
如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时。如果ReadTotalTimeoutMultiplier 和 ReadTotalTimeoutConstant都为0,则不使用读总超时。如果读间隔超时被设置成MAXDWORD并且读时间系数和读时间常量都为0,那么在读一次输入缓冲区的内容后读操作就立即返回,而不管是否读入了要求的字符。
在用重叠方式读写串口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile和WriteFile的返回时间。
配置串口的示例代码:
SetupComm(hCom,1024,1024);//输入缓冲区和输出缓冲区的大小都是1024
COMMTIMEOUTS TimeOuts;//设定读超时
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=500;
TimeOuts.ReadTotalTimeoutConstant=5000;//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=500;
TimeOuts.WriteTotalTimeoutConstant=2000;
SetCommTimeouts(hCom,&TimeOuts);//设置超时
DCBdcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600;//波特率为9600
dcb.ByteSize=8;//每个字节有8位
dcb.Parity=NOPARITY;//无奇偶校验位
dcb.StopBits=TWOSTOPBITS;//两个停止位
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
在读写串口之前,还要用PurgeComm()函数清空缓冲区,该函数原型:
BOOL PurgeComm( HANDLE hFile, //串口句柄
DWORD dwFlags // 需要完成的操作 );
参数dwFlags指定要完成的操作,可以是下列值的组合:
PURGE_TXABORT 中断所有写操作并立即返回,即使写操作还没有完成。
PURGE_RXABORT 中断所有读操作并立即返回,即使读操作还没有完成。
PURGE_TXCLEAR 清除输出缓冲区
PURGE_RXCLEAR 清除输入缓冲区
3、读写串口
我们使用ReadFile和WriteFile读写串口,下面是两个函数的声明:
BOOL ReadFile( HANDLE hFile, //串口的句柄
// 读入的数据存储的地址,
// 即读入的数据将存储在以该指针的值为首地址的一片内存区
LPVOID lpBuffer,
// 要读入的数据的字节数
DWORD nNumberOfBytesToRead,
// 指向一个DWORD数值,该数值返回读操作实际读入的字节数
LPDWORD lpNumberOfBytesRead,
// 重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL。
LPOVERLAPPED lpOverlapped );
BOOL WriteFile( HANDLE hFile, //串口的句柄
// 写入的数据存储的地址,
// 即以该指针的值为首地址的
LPCVOID lpBuffer,
//要写入的数据的字节数
DWORD nNumberOfBytesToWrite,
// 指向指向一个DWORD数值,该数值返回实际写入的字节数
LPDWORD lpNumberOfBytesWritten,
// 重叠操作时,该参数指向一个OVERLAPPED结构,
// 同步操作时,该参数为NULL。
LPOVERLAPPED lpOverlapped );
在用ReadFile和WriteFile读写串口时,既可以同步执行,也可以重叠执行。在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,这两个函数也会立即返回,费时的I/O操作在后台进行。
ReadFile和WriteFile函数是同步还是异步由CreateFile函数决定,如果在调用CreateFile创建句柄时指定了FILE_FLAG_OVERLAPPED标志,那么调用ReadFile和WriteFile对该句柄进行的操作就应该是重叠的;如果未指定重叠标志,则读写操作应该是同步的。ReadFile和WriteFile函数的同步或者异步应该和CreateFile函数相一致。
ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作。而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastError函数分析返回的结果。例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING。这说明重叠操作还未完成。
同步方式读写串口比较简单,下面先例举同步方式读写串口的代码:
//同步读串口
Char str[100];
DWOR DwCount;//读取的字节数
BOOL bReadStat;
bReadStat=ReadFile(hCom,str,100,&wCount,NULL);
if(!bReadStat){AfxMessageBox("读串口失败!");returnFALSE;}returnTRUE;//同步写串口
char lpOutBuffer[100];
DWOR DdwBytesWrite=100;
COMSTATComStat;
DWORDdwErrorFlags;
BOOLbWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,&dwBytesWrite,NULL);
if(!bWriteStat){AfxMessageBox("写串口失败!");}
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
在重叠操作时,操作还未完成函数就返回。
重叠I/O非常灵活,它也可以实现阻塞(例如我们可以设置一定要读取到一个数据才能进行到下一步操作)。有两种方法可以等待操作完成:一种方法是用象WaitForSingleObject这样的等待函数来等待OVERLAPPED结构的hEvent成员;另一种方法是调用GetOverlappedResult函数等待,后面将演示说明。
下面我们先简单说一下OVERLAPPED结构和GetOverlappedResult函数:
OVERLAPPED结构
OVERLAPPED结构包含了重叠I/O的一些信息,定义如下:
typedef struct _OVERLAPPED { // o
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
在使用ReadFile和WriteFile重叠操作时,线程需要创建OVERLAPPED结构以供这两个函数使用。线程通过OVERLAPPED结构获得当前的操作状态,该结构最重要的成员是hEvent。hEvent是读写事件。当串口使用异步通讯时,函数返回时操作可能还没有完成,程序可以通过检查该事件得知是否读写完毕。
当调用ReadFile, WriteFile 函数的时候,该成员会自动被置为无信号状态;当重叠操作完成后,该成员变量会自动被置为有信号状态。
GetOverlappedResult函数 BOOLGetOverlappedResult( HANDLE hFile, // 串口的句柄
// 指向重叠操作开始时指定的OVERLAPPED结构LPOVERLAPPED lpOverlapped,
// 指向一个32位变量,该变量的值返回实际读写操作传输的字节数。
LPDWORD lpNumberOfBytesTransferred,
// 该参数用于指定函数是否一直等到重叠操作结束。
// 如果该参数为TRUE,函数直到操作结束才返回。
// 如果该参数为FALSE,函数直接返回,这时如果操作没有完成,
BOOL bWait );
// 通过调用GetLastError()函数会返回ERROR_IO_INCOMPLETE。
该函数返回重叠操作的结果,用来判断异步操作是否完成,它是通过判断OVERLAPPED结构中的hEvent是否被置位来实现的。
异步读串口的示例代码:
charlpInBuffer[1024];
DWORDdwBytesRead=1024;
COMSTATComStat;
DWORDdwErrorFlags;
OVERLAPPEDm_osRead;
memset(&m_osRead,0,sizeof(OVERLAPPED));
m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
ClearCommError(hCom,&dwErrorFlags,&ComStat);
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
if(!dwBytesRead)returnFALSE;
BOOLbReadStatus;
bReadStatus=ReadFile(hCom,lpInBuffer,dwBytesRead,&dwBytesRead,&m_osRead);
if(!bReadStatus)
//如果ReadFile函数返回FALSE
{
if(GetLastError()==ERROR_IO_PENDING)
//GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作
{
WaitForSingleObject(m_osRead.hEvent,2000);
//使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟
//当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
returndwBytesRead;
}
return0;
}
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
returndwBytesRead;
对以上代码再作简要说明:
在使用ReadFile 函数进行读操作前,应先使用ClearCommError函数清除错误。
ClearCommError函数的原型如下:
BOOL ClearCommError( HANDLE hFile,
// 串口句柄LPDWORD lpErrors,// 指向接收错误码的变量
LPCOMSTAT lpStat // 指向通讯状态缓冲区 );
该函数获得通信错误并报告串口的当前状态,同时,该函数清除串口的错误标志以便继续输入、输出操作。
参数lpStat指向一个COMSTAT结构,该结构返回串口状态信息。
COMSTAT结构 COMSTAT结构包含串口的信息,
结构定义如下:
typedef struct _COMSTAT { // cst DWORDfCtsHold : 1; // Tx waiting for CTS signal DWORD fDsrHold : 1; // Tx waitingfor DSR signal DWORD fRlsdHold : 1; // Tx waiting for RLSD signal DWORDfXoffHold : 1; // Tx waiting, XOFF char rec''d DWORD fXoffSent : 1; // Txwaiting, XOFF char sent DWORD fEof : 1; // EOF character sent DWORD fTxim : 1;// character waiting for Tx DWORD fReserved : 25; // reserved DWORD cbInQue; //bytes in input buffer DWORD cbOutQue; // bytes in output buffer } COMSTAT,*LPCOMSTAT;
本文只用到了cbInQue成员变量,该成员变量的值代表输入缓冲区的字节数。
最后用PurgeComm函数清空串口的输入输出缓冲区。
这段代码用WaitForSingleObject函数来等待OVERLAPPED结构的hEvent成员,下面我们再演示一段调用GetOverlappedResult函数等待的
异步读串口示例代码:
charlpInBuffer[1024];
DWORDdwBytesRead=1024;
BOOLbReadStatus;
DWORDdwErrorFlags;
COMSTATComStat;
OVERLAPPEDm_osRead;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
if(!ComStat.cbInQue)return0;
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
bReadStatus=ReadFile(hCom,lpInBuffer,dwBytesRead,&dwBytesRead,&m_osRead);
if(!bReadStatus)//如果ReadFile函数返回FALSE
{if(GetLastError()==ERROR_IO_PENDING)
{GetOverlappedResult(hCom,&m_osRead,&dwBytesRead,TRUE);
// GetOverlappedResult函数的最后一个参数设为TRUE,
//函数会一直等待,直到读操作完成或由于错误而返回。
returndwBytesRead;}
return0;}
returndwBytesRead;
异步写串口的示例代码:
char buffer[1024];
DWORD dwBytesWritten=1024;
DWORD dwErrorFlags;
COMSTAT ComStat;
OVERLAPPED m_osWrite;
BOOL bWriteStat;
bWriteStat=WriteFile(hCom,buffer,dwBytesWritten,&dwBytesWritten,&m_OsWrite);
if(!bWriteStat)
{ if(GetLastError()==ERROR_IO_PENDING)
{WaitForSingleObject(m_osWrite.hEvent,1000);
return dwBytesWritten; }
return 0; }
return dwBytesWritten;
4、关闭串口
利用API函数关闭串口非常简单,只需使用CreateFile函数返回的句柄作为参数调用CloseHandle即可:
BOOLCloseHandle(
HANDLEhObject;//handle to object to close
);
〖0〗-操作成功完成。
〖1〗-功能错误。
〖2〗-系统找不到指定的文件。
〖3〗-系统找不到指定的路径。
〖4〗-系统无法打开文件。
〖5〗-拒绝访问。
〖6〗-句柄无效。
〖7〗-存储控制块被损坏。
〖8〗-存储空间不足,无法处理此命令。
〖9〗-存储控制块地址无效。
〖10〗-环境错误。
〖11〗-试图加载格式错误的程序。
〖12〗-访问码无效。
〖13〗-数据无效。
〖14〗-存储器不足,无法完成此操作。
〖15〗-系统找不到指定的驱动器。
〖16〗-无法删除目录。
〖17〗-系统无法将文件移到不同的驱动器。
〖18〗-没有更多文件。
〖19〗-介质受写入保护。
〖20〗-系统找不到指定的设备。
〖21〗-设备未就绪。
〖22〗-设备不识别此命令。
〖23〗-数据错误 (循环冗余检查)。
〖24〗-程序发出命令,但命令长度不正确。
〖25〗-驱动器无法找出磁盘上特定区域或磁道的位置。
〖26〗-无法访问指定的磁盘或软盘。
〖27〗-驱动器找不到请求的扇区。
〖28〗-打印机缺纸。
〖29〗-系统无法写入指定的设备。
〖30〗-系统无法从指定的设备上读取。
〖31〗-连到系统上的设备没有发挥作用。
〖32〗-进程无法访问文件,因为另一个程序正在使用此文件。
〖33〗-进程无法访问文件,因为另一个程序已锁定文件的一部分。
〖36〗-用来共享的打开文件过多。
〖38〗-到达文件结尾。
〖39〗-磁盘已满。
〖50〗-不支持该请求。
〖51〗-远程计算机不可用。
〖52〗-在网络上已有重复的名称。
〖53〗-找不到网络路径。
〖54〗-网络忙。
〖55〗-指定的网络资源或设备不再可用。
〖56〗-已到达网络 BIOS 命令限制。
〖57〗-网络适配器硬件出错。
〖58〗-指定的服务器无法运行请求的操作。
〖59〗-发生意外的网络错误。
〖60〗-远程适配器不兼容。
〖61〗-打印机队列已满。
〖62〗-无法在服务器上获得用于保存待打印文件的空间。
〖63〗-删除等候打印的文件。
〖64〗-指定的网络名不再可用。
〖65〗-拒绝网络访问。
〖66〗-网络资源类型错误。
〖67〗-找不到网络名。
〖68〗-超过本地计算机网卡的名称限制。
〖69〗-超出网络 BIOS 会话限制。
〖70〗-远程服务器已暂停,或正在启动过程中。
〖71〗-当前已无法再同此远程计算机连接,因为已达到计算机的连接数目极限。
〖72〗-已暂停指定的打印机或磁盘设备。
〖80〗-文件存在。
〖82〗-无法创建目录或文件。
〖83〗-INT 24 失败。
〖84〗-无法取得处理此请求的存储空间。
〖85〗-本地设备名已在使用中。
〖86〗-指定的网络密码错误。
〖87〗-参数错误。
〖88〗-网络上发生写入错误。
〖89〗-系统无法在此时启动另一个进程。
〖100〗-无法创建另一个系统信号灯。
〖101〗-另一个进程拥有独占的信号灯。
〖102〗-已设置信号灯且无法关闭。
〖103〗-无法再设置信号灯。
〖104〗-无法在中断时请求独占的信号灯。
〖105〗-此信号灯的前一个所有权已结束。
〖107〗-程序停止,因为替代的软盘未插入。
〖108〗-磁盘在使用中,或被另一个进程锁定。
〖109〗-管道已结束。
〖110〗-系统无法打开指定的设备或文件。
〖111〗-文件名太长。
〖112〗-磁盘空间不足。
〖113〗-无法再获得内部文件的标识。
〖114〗-目标内部文件的标识不正确。
〖117〗-应用程序制作的 IOCTL 调用错误。
〖118〗-验证写入的切换参数值错误。
〖119〗-系统不支持请求的命令。
〖120〗-此功能只被此系统支持。
〖121〗-信号灯超时时间已到。
〖122〗-传递到系统调用的数据区太小。
〖123〗-文件名、目录名或卷标语法不正确。
〖124〗-系统调用级别错误。
〖125〗-磁盘没有卷标。
〖126〗-找不到指定的模块。
〖127〗-找不到指定的程序。
〖128〗-没有等候的子进程。
〖130〗-试图使用操作(而非原始磁盘 I/O)的已打开磁盘分区的文件句柄。
〖131〗-试图移动文件指针到文件开头之前。
〖132〗-无法在指定的设备或文件上设置文件指针。
〖133〗-包含先前加入驱动器的驱动器无法使用 JOIN 或 SUBST 命令。
〖134〗-试图在已被合并的驱动器上使用 JOIN 或 SUBST 命令。
〖135〗-试图在已被合并的驱动器上使用 JOIN 或 SUBST 命令。
〖136〗-系统试图解除未合并驱动器的 JOIN。
〖137〗-系统试图解除未替代驱动器的 SUBST。
〖138〗-系统试图将驱动器合并到合并驱动器上的目录。
〖139〗-系统试图将驱动器替代为替代驱动器上的目录。
〖140〗-系统试图将驱动器合并到替代驱动器上的目录。
〖141〗-系统试图替代驱动器为合并驱动器上的目录。
〖142〗-系统无法在此时运行 JOIN 或 SUBST。
〖143〗-系统无法将驱动器合并到或替代为相同驱动器上的目录。
〖144〗-目录并非根目录下的子目录。
〖145〗-目录非空。
〖146〗-指定的路径已在替代中使用。
〖147〗-资源不足,无法处理此命令。
〖148〗-指定的路径无法在此时使用。
〖149〗-企图将驱动器合并或替代为驱动器上目录是上一个替代的目标的驱动器。
〖150〗-系统跟踪信息未在 CONFIG.SYS 文件中指定,或不允许跟踪。
〖151〗-为 DosMuxSemWait 指定的信号灯事件个数错误。
〖152〗-DosMuxSemWait 不可运行。已设置过多的信号灯。
〖153〗-DosMuxSemWait 清单错误。
〖154〗-输入的卷标超过目标文件系统的长度限制
〖155〗-无法创建另一个线程。
〖156〗-接收进程已拒绝此信号。
〖157〗-段已被放弃且无法锁定。
〖158〗-段已解除锁定。
〖159〗-线程标识的地址错误。
〖160〗-传递到 DosExecPgm 的参数字符串错误。
〖161〗-指定的路径无效。
〖162〗-信号已暂停。
〖164〗-无法在系统中创建更多的线程。
〖167〗-无法锁定文件区域。
〖170〗-请求的资源在使用中。
〖173〗-对于提供取消区域进行锁定的请求不明显。
〖174〗-文件系统不支持锁定类型的最小单元更改。
〖180〗-系统检测出错误的段号。
〖183〗-当文件已存在时,无法创建该文件。
〖186〗-传递的标志错误。
〖187〗-找不到指定的系统信号灯名称。
〖196〗-操作系统无法运行此应用程序。
〖197〗-操作系统当前的配置不能运行此应用程序。
〖199〗-操作系统无法运行此应用程序。
〖200〗-代码段不可大于或等于 64K。
〖203〗-操作系统找不到已输入的环境选项。
〖205〗-命令子树中的进程没有信号处理程序。
〖206〗-文件名或扩展名太长。
〖207〗-第 2 环堆栈已被占用。
〖208〗-没有正确输入文件名通配符 * 或 ?,或指定过多的文件名通配符。
〖209〗-正在发送的信号错误。
〖210〗-无法设置信号处理程序。
〖212〗-段已锁定且无法重新分配。
〖214〗-连到该程序或动态链接模块的动态链接模块太多。
〖215〗-无法嵌套调用 LoadModule。
〖230〗-管道状态无效。
〖231〗-所有的管道实例都在使用中。
〖232〗-管道正在关闭中。
〖233〗-管道的另一端上无任何进程。
〖234〗-更多数据可用。
〖240〗-取消会话。
〖254〗-指定的扩展属性名无效。
〖255〗-扩展属性不一致。
〖258〗-等待的操作过时。
〖259〗-没有可用的数据了。
〖266〗-无法使用复制功能。
〖267〗-目录名无效。
〖275〗-扩展属性在缓冲区中不适用。
〖276〗-装在文件系统上的扩展属性文件已损坏。
〖277〗-扩展属性表格文件已满。
〖278〗-指定的扩展属性句柄无效。
〖282〗-装入的文件系统不支持扩展属性。
〖288〗-企图释放并非呼叫方所拥有的多用户终端运行程序。
〖298〗-发向信号灯的请求过多。
〖299〗-仅完成部分的 ReadProcessMemoty 或 WriteProcessMemory 请求。
〖300〗-操作锁定请求被拒绝。
〖301〗-系统接收了一个无效的操作锁定确认。
〖487〗-试图访问无效的地址。
〖534〗-算术结果超过 32 位。
〖535〗-管道的另一端有一进程。
〖536〗-等候打开管道另一端的进程。
〖994〗-拒绝访问扩展属性。
〖995〗-由于线程退出或应用程序请求,已放弃 I/O 操作。
〖996〗-重叠 I/O 事件不在信号状态中。
〖997〗-重叠 I/O 操作在进行中。
〖998〗-内存分配访问无效。
〖999〗-错误运行页内操作。
〖1001〗-递归太深;栈溢出。
〖1002〗-窗口无法在已发送的消息上操作。
〖1003〗-无法完成此功能。
〖1004〗-无效标志。
〖1005〗-此卷不包含可识别的文件系统。请确定所有请求的文件系统驱动程序已加载,且此卷未损坏。
〖1006〗-文件所在的卷已被外部改变,因此打开的文件不再有效。
〖1007〗-无法在全屏幕模式下运行请求的操作。
〖1008〗-试图引用不存在的令牌。
〖1009〗-配置注册表数据库损坏。
〖1010〗-配置注册表项无效。
〖1011〗-无法打开配置注册表项。
〖1012〗-无法读取配置注册表项。
〖1013〗-无法写入配置注册表项。
〖1014〗-注册表数据库中的某一文件必须使用记录或替代复制来恢复。恢复成功完成。
〖1015〗-注册表损坏。包含注册表数据的某一文件结构损坏,或系统的文件内存映像损坏,或因为替代副本、日志缺少或损坏而无法恢复文件。
〖1016〗-由注册表启动的 I/O 操作恢复失败。注册表无法读入、写出或清除任意一个包含注册表系统映像的文件。
〖1017〗-系统试图加载或还原文件到注册表,但指定的文件并非注册表文件格式。
〖1018〗-试图在标记为删除的注册表项上运行不合法的操作。
〖1019〗-系统无法配置注册表日志中所请求的空间。
〖1020〗-无法在已有子项或值的注册表项中创建符号链接。
〖1021〗-无法在易变父项下创建稳定子项。
〖1022〗-通知更改请求正在完成中,且信息并未返回到呼叫方的缓冲区中。当前呼叫方必须枚举文件来查找更改。
〖1051〗-已发送停止控制到服务,该服务被其它正在运行的服务所依赖。
〖1052〗-请求的控件对此服务无效
〖1053〗-服务并未及时响应启动或控制请求。
〖1054〗-无法创建此服务的线程。
〖1055〗-锁定服务数据库。
〖1056〗-服务的实例已在运行中。
〖1057〗-帐户名无效或不存在,或者密码对于指定的帐户名无效。
〖1058〗-无法启动服务,原因可能是它被禁用或与它相关联的设备没有启动。
〖1059〗-指定了循环服务依存。
〖1060〗-指定的服务并未以已安装的服务存在。
〖1061〗-服务无法在此时接受控制信息。
〖1062〗-服务未启动。
〖1063〗-服务进程无法连接到服务控制器上。
〖1064〗-当处理控制请求时,在服务中发生异常。
〖1065〗-指定的数据库不存在。
〖1066〗-服务已返回特定的服务错误码。
〖1067〗-进程意外终止。
〖1068〗-依存服务或组无法启动。
〖1069〗-由于登录失败而无法启动服务。
〖1070〗-启动后,服务停留在启动暂停状态。
〖1071〗-指定的服务数据库锁定无效。
〖1072〗-指定的服务已标记为删除。
〖1073〗-指定的服务已存在。
〖1074〗-系统当前以最新的有效配置运行。
〖1075〗-依存服务不存在,或已被标记为删除。
〖1076〗-已接受使用当前引导作为最后的有效控制设置。
〖1077〗-上次启动之后,仍未尝试引导服务。
〖1078〗-名称已用作服务名或服务显示名。
〖1079〗-此服务的帐户不同于运行于同一进程上的其它服务的帐户。
〖1080〗-只能为 Win32 服务设置失败操作,不能为驱动程序设置。
〖1081〗-这个服务所运行的处理和服务控制管理器相同。所以,如果服务处理程序意外中止的话,服务控制管理器无法进行任何操作。
〖1082〗-这个服务尚未设置恢复程序。
〖1083〗-配置成在该可执行程序中运行的这个服务不能执行该服务。
〖1100〗-已达磁带的实际结尾。
〖1101〗-磁带访问已达文件标记。
〖1102〗-已达磁带或磁盘分区的开头。
〖1103〗-磁带访问已达一组文件的结尾。
〖1104〗-磁带上不再有任何数据。
〖1105〗-磁带无法分区。
〖1106〗-在访问多卷分区的新磁带时,当前的块大小不正确。
〖1107〗-当加载磁带时,找不到分区信息。
〖1108〗-无法锁定媒体弹出功能。
〖1109〗-无法卸载介质。
〖1110〗-驱动器中的介质可能已更改。
〖1111〗-复位 I/O 总线。
〖1112〗-驱动器中没有媒体。
〖1113〗-在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符。
〖1114〗-动态链接库 (DLL) 初始化例程失败。
〖1115〗-系统关机正在进行。
〖1116〗-因为没有任何进行中的关机过程,所以无法中断系统关机。
〖1117〗-因为 I/O 设备错误,所以无法运行此项请求。
〖1118〗-没有串行设备被初始化成功。串行驱动程序将卸载。
〖1119〗-无法打开正在与其他设备共享中断请求(IRQ)的设备。至少有一个使用该 IRQ 的其他设备已打开。
〖1120〗-序列 I/O 操作已由另一个串行口的写入完成。(IOCTL_SERIAL_XOFF_COUNTER 已达零。)
〖1121〗-因为已过超时时间,所以串行 I/O 操作完成。(IOCTL_SERIAL_XOFF_COUNTER 未达零。)
〖1122〗-在软盘上找不到 ID 地址标记。
〖1123〗-软盘扇区 ID 字符域与软盘控制器磁道地址不相符。
〖1124〗-软盘控制器报告软盘驱动程序不能识别的错误。
〖1125〗-软盘控制器返回与其寄存器中不一致的结果。
〖1126〗-当访问硬盘时,重新校准操作失败,重试仍然失败。
〖1127〗-当访问硬盘时,磁盘操作失败,重试仍然失败。
〖1128〗-当访问硬盘时,即使失败,仍须复位磁盘控制器。
〖1129〗-已达磁带结尾。
〖1130〗-服务器存储空间不足,无法处理此命令。
〖1131〗-检测出潜在的死锁状态。
〖1132〗-指定的基址或文件偏移量没有适当对齐。
〖1140〗-改变系统供电状态的尝试被另一应用程序或驱动程序否决。
〖1141〗-系统 BIOS 改变系统供电状态的尝试失败。
〖1142〗-试图在一文件上创建超过系统允许数额的链接。
〖1150〗-指定程序要求更新的 Windows 版本。
〖1151〗-指定程序不是 Windows 或 MS-DOS 程序。
〖1152〗-只能启动该指定程序的一个实例。
〖1153〗-该指定程序适用于旧的 Windows 版本。
〖1154〗-执行该应用程序所需的库文件之一被损坏。
〖1155〗-没有应用程序与此操作的指定文件有关联。
〖1156〗-在输送指令到应用程序的过程中出现错误。
〖1157〗-执行该应用程序所需的库文件之一无法找到。
〖1158〗-当前程序已使用了 Window 管理器对象的系统允许的所有句柄。
〖1159〗-消息只能与同步操作一起使用。
〖1160〗-指出的源元素没有媒体。
〖1161〗-指出的目标元素已包含媒体。
〖1162〗-指出的元素不存在。
〖1163〗-指出的元素是未显示的存储资源的一部分。
〖1164〗-显示设备需要重新初始化,因为硬件有错误。
〖1165〗-设备显示在尝试进一步操作之前需要清除。
〖1166〗-设备显示它的门仍是打开状态。
〖1167〗-设备没有连接。
〖1168〗-找不到元素。
〖1169〗-索引中没有同指定项相匹配的项。
〖1170〗-在对象上不存在指定的属性集。
〖1171〗-传递到 GetMouseMovePoints 的点不在缓冲区中。
〖1172〗-跟踪(工作站)服务没运行。
〖1173〗-找不到卷 ID。
〖1175〗-无法删除要被替换的文件。
〖1176〗-无法将替换文件移到要被替换的文件。要被替换的文件保持原来的名称。
〖1177〗-无法将替换文件移到要被替换的文件。要被替换的文件已被重新命名为备份名称。
〖1178〗-卷更改记录被删除。
〖1179〗-卷更改记录服务不处于活动中。
〖1180〗-找到一份文件,但是可能不是正确的文件。
〖1181〗-日志项从日志中被删除。
〖1200〗-指定的设备名无效。
〖1201〗-设备当前未连接上,但其为一个记录连接。
〖1202〗-企图记录先前已被记录的设备。
〖1203〗-无任何网络提供程序接受指定的网络路径。
〖1204〗-指定的网络提供程序名称无效。
〖1205〗-无法打开网络连接配置文件。
〖1206〗-网络连接配置文件损坏。
〖1207〗-无法枚举空载体。
〖1208〗-发生扩展错误。
〖1209〗-指定的组名格式无效。
〖1210〗-指定的计算机名格式无效。
〖1211〗-指定的事件名格式无效。
〖1212〗-指定的域名格式无效。
〖1213〗-指定的服务名格式无效。
〖1214〗-指定的网络名格式无效。
〖1215〗-指定的共享名格式无效。
〖1216〗-指定的密码格式无效。
〖1217〗-指定的消息名格式无效。
〖1218〗-指定的消息目标格式无效。
〖1219〗-提供的凭据与已存在的凭据集冲突。
〖1220〗-企图创建网络服务器的会话,但已对该服务器创建过多的会话。
〖1221〗-工作组或域名已由网络上的另一部计算机使用。
〖1222〗-网络未连接或启动。
〖1223〗-操作已被用户取消。
〖1224〗-请求的操作无法在使用用户映射区域打开的文件上执行。
〖1225〗-远程系统拒绝网络连接。
〖1226〗-网络连接已被适当地关闭了。
〖1227〗-网络传输终结点已有与其关联的地址。
〖1228〗-地址仍未与网络终结点关联。
〖1229〗-企图在不存在的网络连接上进行操作。
〖1230〗-企图在使用中的网络连接上进行无效的操作。
〖1231〗-不能访问网络位置。有关网络排除故障的信息,请参阅 Windows 帮助。
〖1232〗-不能访问网络位置。有关网络排除故障的信息,请参阅 Windows 帮助。
〖1233〗-不能访问网络位置。有关网络排除故障的信息,请参阅 Windows 帮助。
〖1234〗-没有任何服务正在远程系统上的目标网络终结点上操作。
〖1235〗-请求被终止。
〖1236〗-由本地系统终止网络连接。
〖1237〗-操作无法完成。应该重试。
〖1238〗-因为已达到此帐户的最大同时连接数限制,所以无法连接服务器。
〖1239〗-试图在这个帐户未被授权的时间内登录。
〖1240〗-此帐户并未得到从这个工作站登录的授权。
〖1241〗-请求的操作不能使用这个网络地址。
〖1242〗-服务器已经注册。
〖1243〗-指定的服务不存在。
〖1244〗-因为用户还未被验证,不能执行所要求的操作。
〖1245〗-因为用户还未登录网络,不能执行所要求的操作。指定的服务不存在。
〖1246〗-正在继续工作。
〖1247〗-试图进行初始操作,但是初始化已完成。
〖1248〗-没有更多的本地设备。
〖1249〗-指定的站点不存在。
〖1250〗-具有指定名称的域控制器已经存在。
〖1251〗-只有连接到服务器上时,该操作才受支持。
〖1252〗-即使没有改动,组策略框架也应该调用扩展。
〖1253〗-指定的用户没有一个有效的配置文件。
〖1254〗-Microsoft Small Business Server 不支持此操作。
〖1300〗-并非所有被引用的特权都指派给呼叫方。
〖1301〗-帐户名和安全标识间的某些映射未完成。
〖1302〗-没有为该帐户特别设置系统配额限制。
〖1303〗-没有可用的加密密钥。返回了一个已知加密密钥。
〖1304〗-密码太复杂,无法转换成 LAN Manager 密码。返回的 LAN Manager 密码为空字符串。
〖1305〗-修订级别未知。
〖1306〗-表明两个修订级别是不兼容的。
〖1307〗-这个安全标识不能指派为此对象的所有者。
〖1308〗-这个安全标识不能指派为对象的主要组。
〖1309〗-当前并未模拟客户的线程试图操作模拟令牌。
〖1310〗-组可能未被禁用。
〖1311〗-当前没有可用的登录服务器来服务登录请求。
〖1312〗-指定的登录会话不存在。可能已被终止。
〖1313〗-指定的特权不存在。
〖1314〗-客户没有所需的特权。
〖1315〗-提供的名称并非正确的帐户名形式。
〖1316〗-指定的用户已存在。
〖1317〗-指定的用户不存在。
〖1318〗-指定的组已存在。
〖1319〗-指定的组不存在。
〖1320〗-指定的用户帐户已是指定组的成员,或是因为组包含成员所以无法删除指定的组。
〖1321〗-指定的用户帐户不是指定组帐户的成员。
〖1322〗-无法禁用或删除最后剩余的系统管理帐户。
〖1323〗-无法更新密码。提供作为当前密码的值不正确。
〖1324〗-无法更新密码。提供给新密码的值包含密码中不允许的值。
〖1325〗-无法更新密码。为新密码提供的值不符合字符域的长度、复杂性或历史要求。
〖1326〗-登录失败: 未知的用户名或错误密码。
〖1327〗-登录失败: 用户帐户限制。
〖1328〗-登录失败: 违反帐户登录时间限制。
〖1329〗-登录失败: 不允许用户登录到此计算机。
〖1330〗-登录失败: 指定的帐户密码已过期。
〖1331〗-登录失败: 禁用当前的帐户。
〖1332〗-帐户名与安全标识间无任何映射完成。
〖1333〗-一次请求过多的本地用户标识符(LUIDs)。
〖1334〗-无更多可用的本地用户标识符(LUIDs)。
〖1335〗-对于该特别用法,安全 ID 的次级授权部分无效。
〖1336〗-访问控制列表(ACL)结构无效。
〖1337〗-安全 ID 结构无效。
〖1338〗-安全描述符结构无效。
〖1340〗-无法创建固有的访问控制列表(ACL)或访问控制项目(ACE)。
〖1341〗-服务器当前已禁用。
〖1342〗-服务器当前已启用。
〖1343〗-提供给识别代号颁发机构的值为无效值。
〖1344〗-无更多可用的内存以更新安全信息。
〖1345〗-指定属性无效,或与整个群体的属性不兼容。
〖1346〗-指定的模拟级别无效,或所提供的模拟级别无效。
〖1347〗-无法打开匿名级安全令牌。
〖1348〗-请求的验证信息类别无效。
〖1349〗-令牌的类型对其尝试使用的方法不适当。
〖1350〗-无法在与安全性无关联的对象上运行安全性操作。
〖1351〗-未能从域控制器读取配置信息,或者是因为机器不可使用,或者是访问被拒绝。
〖1352〗-安全帐户管理器(SAM)或本地安全颁发机构(LSA)服务器处于运行安全操作的错误状态。
〖1353〗-域处于运行安全操作的错误状态。
〖1354〗-此操作只对域的主要域控制器可行。
〖1355〗-指定的域不存在,或无法联系。
〖1356〗-指定的域已存在。
〖1357〗-试图超出每服务器域个数的限制。
〖1358〗-无法完成请求操作,因为磁盘上的严重介质失败或数据结构损坏。
〖1359〗-出现了内部错误。
〖1360〗-通用访问类型包含于已映射到非通用类型的访问掩码中。
〖1361〗-安全描述符格式不正确 (绝对或自相关的)。
〖1362〗-请求操作只限制在登录进程中使用。调用进程未注册为一个登录进程。
〖1363〗-无法使用已在使用中的标识启动新的会话。
〖1364〗-未知的指定验证数据包。
〖1365〗-登录会话并非处于与请求操作一致的状态中。
〖1366〗-登录会话标识已在使用中。
〖1367〗-登录请求包含无效的登录类型值。
〖1368〗-在使用命名管道读取数据之前,无法经由该管道模拟。
〖1369〗-注册表子树的事务处理状态与请求状态不一致。
〖1370〗-安全性数据库内部出现损坏。
〖1371〗-无法在内置帐户上运行此操作。
〖1372〗-无法在内置特殊组上运行此操作。
〖1373〗-无法在内置特殊用户上运行此操作。
〖1374〗-无法从组中删除用户,因为当前组为用户的主要组。
〖1375〗-令牌已作为主要令牌使用。
〖1376〗-指定的本地组不存在。
〖1377〗-指定的帐户名不是本地组的成员。
〖1378〗-指定的帐户名已是本地组的成员。
〖1379〗-指定的本地组已存在。
〖1380〗-登录失败: 未授予用户在此计算机上的请求登录类型。
〖1381〗-已超过在单一系统中可保存机密的最大个数。
〖1382〗-机密的长度超过允许的最大长度。
〖1383〗-本地安全颁发机构数据库内部包含不一致性。
〖1384〗-在尝试登录的过程中,用户的安全上下文积累了过多的安全标识。
〖1385〗-登录失败: 未授予用户在此计算机上的请求登录类型。
〖1386〗-更改用户密码时需要交叉加密密码。
〖1387〗-由于成员不存在,无法将成员添加到本地组中,也无法从本地组将其删除。
〖1388〗-无法将新成员加入到本地组中,因为成员的帐户类型错误。
〖1389〗-已指定过多的安全标识。
〖1390〗-更改此用户密码时需要交叉加密密码。
〖1391〗-表明 ACL 未包含任何可承继的组件。
〖1392〗-文件或目录损坏且无法读取。
〖1393〗-磁盘结构损坏且无法读取。
〖1394〗-无任何指定登录会话的用户会话项。
〖1395〗-正在访问的服务有连接数目标授权限制。这时候已经无法再连接,原因是已经到达可接受的连接数目上限。
〖1396〗-登录失败: 该目标帐户名称不正确。
〖1397〗-相互身份验证失败。该服务器在域控制器的密码过期。
〖1398〗-在客户机和服务器之间有一个时间差。
//注意:异步通信中一定要初始化OVERLAPPED结构体,否则会报错句柄无效