论文部分内容阅读
[摘要]介绍C++Builder在Windows 95/98操作系统平台IO端口没有受到保护的情况下,实现IO端口读写操作的两种方法,在Windows NT/2000/XP操作系统平台IO端口受到保护的情况下,应用WinIO程序库实现IO端口读写的方法。对于应用C++Builder进行硬件开发的编程人员有重要参考价值。
[关键词]C++Builder IO端口读写 WinIO程序库
中图分类号:TP3文献标识码:A文章编号:1671-7597(2009)0910070-02
C++Builder继承了C语言简洁、快速的优点,采用面向对象的软件工程设计方法和可视化界面设计技术,融合了Windows编程、数据库编程、网络编程等技术,使得程序员可以快速高效地开发出高质量的Windows应用程序。但在C++Builder中,不能够使用Turbo C中的outputb和inputb端口读写函数。给工业控制方面的开发带来不便,特别是不利于IO卡的直接输入输出操作。笔者为在C++Builder中实现这个功能专门在Windows的不同版本下进行了尝试取得了成功。现就具体方法介绍如下供C++Builder编程人员参考。
一、在Windows 95/98操作系统平台下实现端口读写操作
共有两种方法,一种为内嵌汇编语言,另一种为使用__emit__函数。
(一)通过内嵌汇编语言实现端口的读写
在C++Builder中,汇编语句必须被包含在以关键字asm为起始的一对大括号中:
asm {
汇编语句1
……
}
利用内嵌汇编语言编制端口输出函数如下:
void OutPort(unsigned short port,unsigned char value)
//port参数为输出端口地址,value参数为输出值
{
asm{
mov dx , port //把端口地址送到处理器DX寄存器中
mov al , value // 把value 送到处理器AL寄存器中
out dx , al // 把AL寄存器中的值送到端口
};
}
该函数将无符号字符型8位的数据value写入地址为port的端口上,port的数据类型是unsigned short,16位无符号短整形。
利用内嵌汇编语言编制端口输入函数如下:
unsigned char InPort(unsigned short port)
//port参数为输入端口地址,返回为输入值
{
unsigned char value ;
asm{
mov dx, port // 把端口地址送到处理器DX寄存器中
in al, dx // 从DX指定端口中将一数据送到AL寄存器中
mov value,al // 把AL寄存器中的值赋给value
};
return value; //返回端口数据
}
函数InPort从地址为port的端口读入一个无符号8位的字符型数据,其其参数只一个,即端口号。返回的数据为unsigned char类型的,为从端口读取的值。
(二)通过__emit__函数实现端口的读写
__emit__ 函数一般极少用到。其用法如下:
void _ _emit_ _(argument, . . .);
该函数为C++Builder 的一个内部函数,调用的参数为机器语言指令。它在编译的时候,将机器语言指令直接嵌入目标码中,不必借助于汇编语言和汇编编译程序。
利用__emit__函数编制端口输出函数如下:
void OutPort(unsigned short port,unsigned char value)
//port参数为输出端口地址,value参数为输出值
{
__emit__(0x8b,0x95,&port); // 把端口地址送到处理器EDX寄存器中
__emit__(0x8a,0x85,&value); // 把value 送到处理器AL寄存器中
__emit__(0x66,0xee); // 把AL寄存器中的值送到端口
}
利用__emit__函数编制端口输入函数如下:
unsigned char InPort(unsigned short port)
//port参数为输入端口地址,返回为输入值
{
unsigned char value;
__emit__(0x8b,0x95,&port) ; // 把端口地址送到处理器DX寄存器中
__emit__(0x66,0xec); // 从DX指定端口中将一数据送到AL寄存器中
__emit__(0x88,0x85,&value); // 把AL寄存器中的值赋给value
return value; //返回端口数据
}
由这两种方法所编制的函数注释可以看出,它们每一句的功能都是一样的,只是一个是嵌入了汇编语言,另一个是直接使用机器语言。
二、在Windows NT/2000/XP操作系统平台下实现端口读写操作
上述介绍的实现端口读写操作两种方法,在Windows 95/98下面工作很正常,但是在Windows NT/2000/XP上就会出现非法指令调用的问题。这些非法指令来自于底层对IO端口的直接地址访问。在Windows 95/98时代,这些操作都没有受到保护的,而在Windows NT/2000/XP下就会出现保护问题。为了解决这个问题需要使用第三方提供的WinIO程序库。
(一)WinIO程序库简介
WinIO程序库允许在32位的Windows应用程序中直接对I/O端口和物理内存进行存取操作。通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Windows系统的保护机制。
WindowsNT/2000/XP下,WinIO函数库只允许被具有管理者权限的应用程序调用。如果使用者不是以管理者的身份进入的,则WinIO.DLL不能够被安装,也不能激活WinIO驱动器。通过在管理者权限下安装驱动器软件就可以克服这种限制。然而,在这种情况下,ShutdownWinIo函数不能在应用程序结束之前被调用,因为该函数将WinIO驱动程序从系统注册表中删除。
该函数库提供8个函数功能调用,其中直接对I/O端口操作有4个函数:
bool _stdcall InitializeWinIo();
本函数初始化WioIO函数库。
必须在调用所有其它功能函数之前调用本函数。
如果函数调用成功,返回值为非零值。
如果调用失败,则返回值为0。
void _stdcall ShutdownWinIo();
本函数在内存中清除WinIO库
本函数必须在中止应用函数之前或者不再需要WinIO库时调用,
bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize);
使用此函数从一个输入或输出端口读取一个字节/字/双字数据。
参数:
wPortAddr输入输出端口地址
pdwPortVal指向双字变量的指针,接收从端口得到的数据。
bSize需要读的字节数,可以是1 (BYTE), 2 (WORD) or 4 (DWORD).
如果调用成功,则返回非零值。
如果函数调用失败,则函数返回值为零。
bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize);
使用本函数将一个字节/字/双字的数据写入输入或输出接口。
参数:
wPortAddr输入输出口地址
dwPortVal要写入口的数据
bSize要写的数据个数,可以是 1 (BYTE), 2 (WORD) or 4 (DWORD).
如果调用成功,则返回非零值。
如果函数调用失败,则函数返回值为零。
(二)WinIO程序库的应用
在C++Builder中应用WinIO程序库需要做如下工作。
1.首先将 winio.dll, winio.vxd 和 winio.sys三个文件拷贝到用C++Builder开发的工程文件目录下;
2.在DOS提示符下用 implib 命令创建导入库。implib 命令格式如下:
implibwinio.libwinio.dll;
3.将winio.lib 添加到用C++Builder开发的工程中。其操作方法是,在C++BuilderIDE 中选择 Project→Add to project…命令,在弹出的Add to project对话框中“文件类型”下拉列表框中选择Library file (*.lib)项,会出现 .lib文件。选择winio.lib文件并单击“打开”按钮,添加操作成功;
4.将winio.h中的WINIO_API删除;
5.在源文件中添加头文件“#include winio.h”;
6.调用初始化命令函数 InitializeWinIo();
7.调用库函数GetPortVal、SetPortVal实现端口的输入输出操作;
8.当所有的端口输入输出操作全部完成,调用库函数ShutdownWinIo
在内存中清除WinIO库。
上述的几种方法笔者在不同的应用环境下使用都是正常的没有发现异常现象,其中内嵌汇编语言和使用__emit__函数的方法编制IO端口读写函数,在Windows 98操作系统和C++Builder5.0编程语言环境下使用多年,工作一直很稳定,没有出现任何问题。后来因操作系统升级为Windows XP发现原有的函数不能用了,后在C++Builder6.0编程语言环境下,改用WinIO程序库的输入或输出函数进行端口的直接操作工作一切正常。
[关键词]C++Builder IO端口读写 WinIO程序库
中图分类号:TP3文献标识码:A文章编号:1671-7597(2009)0910070-02
C++Builder继承了C语言简洁、快速的优点,采用面向对象的软件工程设计方法和可视化界面设计技术,融合了Windows编程、数据库编程、网络编程等技术,使得程序员可以快速高效地开发出高质量的Windows应用程序。但在C++Builder中,不能够使用Turbo C中的outputb和inputb端口读写函数。给工业控制方面的开发带来不便,特别是不利于IO卡的直接输入输出操作。笔者为在C++Builder中实现这个功能专门在Windows的不同版本下进行了尝试取得了成功。现就具体方法介绍如下供C++Builder编程人员参考。
一、在Windows 95/98操作系统平台下实现端口读写操作
共有两种方法,一种为内嵌汇编语言,另一种为使用__emit__函数。
(一)通过内嵌汇编语言实现端口的读写
在C++Builder中,汇编语句必须被包含在以关键字asm为起始的一对大括号中:
asm {
汇编语句1
……
}
利用内嵌汇编语言编制端口输出函数如下:
void OutPort(unsigned short port,unsigned char value)
//port参数为输出端口地址,value参数为输出值
{
asm{
mov dx , port //把端口地址送到处理器DX寄存器中
mov al , value // 把value 送到处理器AL寄存器中
out dx , al // 把AL寄存器中的值送到端口
};
}
该函数将无符号字符型8位的数据value写入地址为port的端口上,port的数据类型是unsigned short,16位无符号短整形。
利用内嵌汇编语言编制端口输入函数如下:
unsigned char InPort(unsigned short port)
//port参数为输入端口地址,返回为输入值
{
unsigned char value ;
asm{
mov dx, port // 把端口地址送到处理器DX寄存器中
in al, dx // 从DX指定端口中将一数据送到AL寄存器中
mov value,al // 把AL寄存器中的值赋给value
};
return value; //返回端口数据
}
函数InPort从地址为port的端口读入一个无符号8位的字符型数据,其其参数只一个,即端口号。返回的数据为unsigned char类型的,为从端口读取的值。
(二)通过__emit__函数实现端口的读写
__emit__ 函数一般极少用到。其用法如下:
void _ _emit_ _(argument, . . .);
该函数为C++Builder 的一个内部函数,调用的参数为机器语言指令。它在编译的时候,将机器语言指令直接嵌入目标码中,不必借助于汇编语言和汇编编译程序。
利用__emit__函数编制端口输出函数如下:
void OutPort(unsigned short port,unsigned char value)
//port参数为输出端口地址,value参数为输出值
{
__emit__(0x8b,0x95,&port); // 把端口地址送到处理器EDX寄存器中
__emit__(0x8a,0x85,&value); // 把value 送到处理器AL寄存器中
__emit__(0x66,0xee); // 把AL寄存器中的值送到端口
}
利用__emit__函数编制端口输入函数如下:
unsigned char InPort(unsigned short port)
//port参数为输入端口地址,返回为输入值
{
unsigned char value;
__emit__(0x8b,0x95,&port) ; // 把端口地址送到处理器DX寄存器中
__emit__(0x66,0xec); // 从DX指定端口中将一数据送到AL寄存器中
__emit__(0x88,0x85,&value); // 把AL寄存器中的值赋给value
return value; //返回端口数据
}
由这两种方法所编制的函数注释可以看出,它们每一句的功能都是一样的,只是一个是嵌入了汇编语言,另一个是直接使用机器语言。
二、在Windows NT/2000/XP操作系统平台下实现端口读写操作
上述介绍的实现端口读写操作两种方法,在Windows 95/98下面工作很正常,但是在Windows NT/2000/XP上就会出现非法指令调用的问题。这些非法指令来自于底层对IO端口的直接地址访问。在Windows 95/98时代,这些操作都没有受到保护的,而在Windows NT/2000/XP下就会出现保护问题。为了解决这个问题需要使用第三方提供的WinIO程序库。
(一)WinIO程序库简介
WinIO程序库允许在32位的Windows应用程序中直接对I/O端口和物理内存进行存取操作。通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Windows系统的保护机制。
WindowsNT/2000/XP下,WinIO函数库只允许被具有管理者权限的应用程序调用。如果使用者不是以管理者的身份进入的,则WinIO.DLL不能够被安装,也不能激活WinIO驱动器。通过在管理者权限下安装驱动器软件就可以克服这种限制。然而,在这种情况下,ShutdownWinIo函数不能在应用程序结束之前被调用,因为该函数将WinIO驱动程序从系统注册表中删除。
该函数库提供8个函数功能调用,其中直接对I/O端口操作有4个函数:
bool _stdcall InitializeWinIo();
本函数初始化WioIO函数库。
必须在调用所有其它功能函数之前调用本函数。
如果函数调用成功,返回值为非零值。
如果调用失败,则返回值为0。
void _stdcall ShutdownWinIo();
本函数在内存中清除WinIO库
本函数必须在中止应用函数之前或者不再需要WinIO库时调用,
bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize);
使用此函数从一个输入或输出端口读取一个字节/字/双字数据。
参数:
wPortAddr输入输出端口地址
pdwPortVal指向双字变量的指针,接收从端口得到的数据。
bSize需要读的字节数,可以是1 (BYTE), 2 (WORD) or 4 (DWORD).
如果调用成功,则返回非零值。
如果函数调用失败,则函数返回值为零。
bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize);
使用本函数将一个字节/字/双字的数据写入输入或输出接口。
参数:
wPortAddr输入输出口地址
dwPortVal要写入口的数据
bSize要写的数据个数,可以是 1 (BYTE), 2 (WORD) or 4 (DWORD).
如果调用成功,则返回非零值。
如果函数调用失败,则函数返回值为零。
(二)WinIO程序库的应用
在C++Builder中应用WinIO程序库需要做如下工作。
1.首先将 winio.dll, winio.vxd 和 winio.sys三个文件拷贝到用C++Builder开发的工程文件目录下;
2.在DOS提示符下用 implib 命令创建导入库。implib 命令格式如下:
implibwinio.libwinio.dll;
3.将winio.lib 添加到用C++Builder开发的工程中。其操作方法是,在C++BuilderIDE 中选择 Project→Add to project…命令,在弹出的Add to project对话框中“文件类型”下拉列表框中选择Library file (*.lib)项,会出现 .lib文件。选择winio.lib文件并单击“打开”按钮,添加操作成功;
4.将winio.h中的WINIO_API删除;
5.在源文件中添加头文件“#include winio.h”;
6.调用初始化命令函数 InitializeWinIo();
7.调用库函数GetPortVal、SetPortVal实现端口的输入输出操作;
8.当所有的端口输入输出操作全部完成,调用库函数ShutdownWinIo
在内存中清除WinIO库。
上述的几种方法笔者在不同的应用环境下使用都是正常的没有发现异常现象,其中内嵌汇编语言和使用__emit__函数的方法编制IO端口读写函数,在Windows 98操作系统和C++Builder5.0编程语言环境下使用多年,工作一直很稳定,没有出现任何问题。后来因操作系统升级为Windows XP发现原有的函数不能用了,后在C++Builder6.0编程语言环境下,改用WinIO程序库的输入或输出函数进行端口的直接操作工作一切正常。