紧急求救!!Windows 98下端口I/O出怪事!

SkyVense 2000-03-29 11:30:00
各位高手:

我正在编写一个数据采集程序(使用Visual C++6.0编程与数据采集卡进行端口通信),其通讯方式很简单:
先向310端口发初始化信号,通知仪器开始数据通讯,然后循环检测300端口,数据有效后读一个字节,然后再循环检测300端口,数据有效后再读下一个字节...,如此反复。
我使用的是VC的_inp()、_outp()函数来操作的,刚开始实验读少量数据是成功的,因为这是一种很可靠的通讯方式,所以我认为肯定没问题了!可是后来再实验接收大量数据时,问题出现了:每接收一段数据(大约一百多个字节),仪器就会莫名其妙的被重新初始化,又从头开始发送数据。
我以为是VC的_inp()、_outp()函数不好,就编了一个简单的动态加载Vxd进行I/O操作,以为这样不会再有问题了,可结果恰恰相反!
没办法了,只好又用Turbo C编了一个DOS程序,想在VC程序中需要通讯时调用一下,更奇怪的现象出现了:在纯DOS中,通讯一切正常,仪器没有被莫名其妙的重新初始化;可在Windows的DOS窗口中,却又出现了跟上面一样的问题!
这是为什么?还望各位高手指教!感激不尽!

张小峰
skyvense@online.sh.cn
...全文
159 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
SkyVense 2000-04-01
  • 打赏
  • 举报
回复
谢谢你的帮助,我的问题已经解决了!

我找到两种方法:
1. 在控制面板里把端口设成保留端口;
2.使用VtoolsD中的VIOPort类截获98的I/O,只匀许自己访问;
非常感谢!
SkyVense
@online.sh.cn
JJONY 2000-03-31
  • 打赏
  • 举报
回复
实不相瞒,我没做过什么数据采集的编程,你所说出现的现象,我想可以是因为Windows把端口给虚拟,也许,系统或者其它的程序都向你控制的那个端口做复位的操作使你的硬件就出错了。

你说在Ring 3环中用_inp()/_outp()两个函数会有错误,试一试在VxD中用这两个函数看看会不会再有你所说的情况出现,如果就用小ASM吧。_asm{.....}

VIOPort类是实现某个I/O端口虚拟化,应用程序(Ring 3)向此端口作I/O操作时,VMM就会通知VIOPort,所以VIOPort就可以接管和监控此端口。有一个建议:你可以重载这一个类,继续你大量数据的传输,在数据传输中监视端口看有没有其它应用程序企图复位你的端口。对,会不会是你在Ring 3环中老是循环而造成。怎么不用中断?非要用循环不可的话,你可以用DeviceIoControl函数来替代通知VxD监视端口。
在Vxd中开辟内存块可以简单的用 new 语句就可以了。
VxD只能在Ring 0中运行。
幸运这个小例子还在。

// IOPORT.h - include file for VxD IOPORT

#include <vtoolscp.h>

#define DEVICE_CLASS IoportDevice
#define IOPORT_DeviceID UNDEFINED_DEVICE_ID
#define IOPORT_Init_Order UNDEFINED_INIT_ORDER
#define IOPORT_Major 1
#define IOPORT_Minor 0
#define COUNT 65536
typedef struct tagPortStruct{
WORD wPort;
WORD wVal;
BOOL bInput;
} PORTSTRUCT,FAR *LPPORSTRUCT;

class MyPort: public VIOPort
{
public:
MyPort(WORD port);
~MyPort();
DWORD handler(VMHANDLE hVM,DWORD port,
CLIENT_STRUCT *pRegs,DWORD iotype,DWORD outdata);
static int Count;
static int Num;
static PORTSTRUCT *pBuffer;
};


class IoportDevice : public VDevice
{
public:
MyPort *p378,*p379,*p37a;
virtual BOOL OnSysDynamicDeviceInit();
virtual BOOL OnSysDynamicDeviceExit();
virtual DWORD OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams);
};

class IoportVM : public VVirtualMachine
{
public:
IoportVM(VMHANDLE hVM);
};

class IoportThread : public VThread
{
public:
IoportThread(THREADHANDLE hThread);
};

// IOPORT.cpp - main module for VxD IOPORT

#define DEVICE_MAIN
#include "ioport.h"
Declare_Virtual_Device(IOPORT)
#undef DEVICE_MAIN

int MyPort::Count=0;
int MyPort::Num=0;
PORTSTRUCT *MyPort::pBuffer=NULL;

MyPort::MyPort(WORD port):VIOPort(port)
{
if(Num==0)pBuffer=new PORTSTRUCT[COUNT];
Num++;
hook();
}

MyPort::~MyPort()
{
Num--;
if(Num==0)delete pBuffer;
}

DWORD MyPort::handler(VMHANDLE hVM,DWORD port,CLIENT_STRUCT *pRegs,DWORD iotype,DWORD outdata)
{
char data;
switch(iotype)
{
case BYTE_INPUT:
pBuffer[Count].wPort=port;
data=_inp(port);
pBuffer[Count].bInput=TRUE;
if(++Count==COUNT) Count=COUNT;
return data;

case BYTE_OUTPUT:
pBuffer[Count].wPort=port;
data=_outp(port,outdata);
pBuffer[Count].wVal=outdata;
pBuffer[Count].bInput=FALSE;
if(++Count>=COUNT)Count=COUNT;
return data;
}
return 0;
}
IoportVM::IoportVM(VMHANDLE hVM) : VVirtualMachine(hVM) {}

IoportThread::IoportThread(THREADHANDLE hThread) : VThread(hThread) {}

BOOL IoportDevice::OnSysDynamicDeviceInit()
{
return TRUE;
}

BOOL IoportDevice::OnSysDynamicDeviceExit()
{
return TRUE;
}

DWORD IoportDevice::OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams)
{
int i;
switch(pDIOCParams->dioc_IOCtlCode)
{
case DIOC_OPEN:
p378=new MyPort(0x378);
p379=new MyPort(0x379);
p37a=new MyPort(0x37a);
break;

case DIOC_CLOSEHANDLE:
if(p378) {delete p378;p378=0;}
if(p379) {delete p379;p379=0;}
if(p37a) {delete p37a;p37a=0;}
break;

case 111:
int size=pDIOCParams->dioc_cbOutBuf;
size=MyPort::Count<size?MyPort::Count:size;
memcpy(pDIOCParams->dioc_OutBuf,MyPort::pBuffer,
size*sizeof(PORTSTRUCT));
*pDIOCParams->dioc_bytesret=size;
break;
}

return 0;
}


SkyVense 2000-03-30
  • 打赏
  • 举报
回复
谢谢JJONY的答复!
我用的是VToolsD, _inp();_outp();来实现I/O的(不要笑我), 我不知道怎么样使用
VIOPort类,能不能给我简单介绍一下?
是不是所有的Vxd都是运行在Ring0级的,只要是Vxd?
谢谢!
JJONY 2000-03-30
  • 打赏
  • 举报
回复
你在VxD中是怎么进行的。用VToolsD吗?
在VToolsD中可以用VIOPort类来真正进行端口数据交换的。
如果是一次性大量的数据传输的处理那就最好做了,可以在Ring0环中开辟一块内存块。
先把数据在Ring 0中存下来,完成后再用VWIN32_SetWin32Event服务通知Ring 3应用程序的一个等待线程,这个线程就去接收数据。
注意,Ring 0的Event句柄是由Ring 3t程序执行OpenVxDHandle得到的。执行VWIN32_SetWin32Event前要注意当前VM是不是Event句柄所在的那个VM。我有一篇文章你可以去看一看。
usage 2000-03-30
  • 打赏
  • 举报
回复
这是因为你的Windows的I/O,你的vxd也可能是运行于 Ring 3,在纯DOS中,通讯一切正常,说明你不能读写真正的端口数据,只有控制程序跳到Ring0或运行于Ring0的I/O才是正确的,有关Windows下Ring0的I/O比较麻烦,Please mail me:usage@263.net

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧