matrixss
驱动牛犊
驱动牛犊
  • 注册日期2004-08-21
  • 最后登录2010-07-26
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望47点
  • 贡献值0点
  • 好评度14点
  • 原创分0分
  • 专家分0分
阅读:1973回复:7

在DriverWoks生成的框架中,如果AddDevice返回错误,会出现Page Fault,为什么?

楼主#
更多 发布于:2004-12-26 19:40
我正在学Windows驱动开发,在学习中遇到了一个问题,感觉与DriverWoks生成的WDM框架有关,为了说明问题,后来又建了一个工程,如下,现象我在原来的工程中出现的相同。

环境:windows2000+SP4
      Visual C++6.0 SP5
      DriverStudio 3.1
      DDK是XP的,在Build Setting中Target OS设置为了Windows 2000.
在VC中使用DriverWorks想到建立一个工程,选WDM,其它设置默认。
继承于KDriver的类记为Test,继承于KDevice的类记为TestDevice.
在Test类的AddDevice代码中,有如下代码:

NTSTATUS status = pDevice->ConstructorStatus();
if ( !NT_SUCCESS(status) )
{
t << "Error constructing device TestPCiDevice"
 << (ULONG) m_Unit << " status " << (ULONG) status << EOL;
delete pDevice;
}
else
{
m_Unit++;

pDevice->ReportNewDevicePowerState(PowerDeviceD0);
}

关于ConstructorStatus函数,按照在Kdevice文件中的注释,可以看出是用来得到在构造函数执行时保存的状态值。
///////////////////////////////////////////////////////////////////////////////
//
// KDevice::ConstructorStatus
// Get the status value from construction.
//
// Return Value:
// Returns the status data member set by the ctor.
//
// Comments:
// All ctors set data member m_ConstructorStatus, which this function just
// returns.
//

所以,如果我在
NTSTATUS status = pDevice->ConstructorStatus();
下面写
status = STATUS_NO_SUCH_DEVICE;
应该和在TestDevice构造函数中设置m_ConstructorStatus的值效果是一样的。(在这个位置设置只是为了排除其它可能的错误)。这样,!NT_SUCCESS(status)为TRUE,则会调用delete pDevice;
编译之后,如果安装该程序的话,我期望的结果是:安装不成功,然后就出现一个有问题的设备(我在DDK中试过,是可以的,在AddDevice中返回一个错误代码)
但是,我在调试时(使用EzDriverInstaller安装,在安装过程中出错),在执行完AddDevice之后,会出现Page Fault(被softice捕获)。从堆栈中也找不出明显的出错位置。

我想问的是:
1。这个错误是我的程序的问题吗?如果是,如果我想在DriverWorks生成的框架中,当在安装过程中返回一个错误(例如,没有找到硬件),如果实现?
2。这个驱动在你的环境中会不会出现相同的错误?是不是我的环境有问题?
3。如果在装驱动时出错,在Win2000下重新以正常模式启动时,Windows会再次安装该驱动,又导致出错。能不能禁止Windows的自动安装功能。我现在只能在安全模式下删掉该驱动,再以正常模式启动。(在XP下会弹出一个对话框,让你选择是否自动安装,所以还可以取消,在2000下,却是一登录就自动帮你安装了)
希望各位大侠能够指点一下,十分感谢。
matrixss
驱动牛犊
驱动牛犊
  • 注册日期2004-08-21
  • 最后登录2010-07-26
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望47点
  • 贡献值0点
  • 好评度14点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-12-29 12:11
是不是我的问题没有描述清楚??如果不清楚,请说明一下,我可以再描述.
或者是在各位的机器上没有这个错误?
如果在你的机器上没有出现错误,请说一下你用的操作系统和DriverStudio的版本号,十分感谢.
jgw2008
驱动小牛
驱动小牛
  • 注册日期2004-12-16
  • 最后登录2005-12-20
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望8点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2004-12-31 14:48
我不用这玩意,我同事说这是软件本身的问题,不妨用google搜搜相关专题,会有收获的.
我的mail:jgw2008@126.com
I'd like to make friends with you! And you?
Happy new year to you & Best Wishes to you
Best Wishes to you! MSN: jgw2008@hotmail.com E-Mail: jgw2008@126.com
matrixss
驱动牛犊
驱动牛犊
  • 注册日期2004-08-21
  • 最后登录2010-07-26
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望47点
  • 贡献值0点
  • 好评度14点
  • 原创分0分
  • 专家分0分
地板#
发布于:2005-01-04 12:14
谢谢jgw2008的回复.问题已解决,前面一部分是jgw2008在邮件中描述的.我重新又实验了一下.解决过程总结如下:
    在WinXP下使用DDKXP,在Windows DDK 2600\tools中启动Driver Verifier。使用Create Standard Setting。然后在下一步中选择最后一项"Select driver names from a list".选择需要调试的驱动。"OK"后重新启动计算机。(注在Win2000下DDKXP也可以使用,但是Driver Verifier的操作界面有所不同,而且看不到下面提到的提示信息.).
    重新启动计算机之后,启动Softice,使用EzDriverInstaller安装驱动程序,会出现错误,并被softice截获,会看到Driver Verifier输出的信息:
    WDM DRIVER ERROR: [TestDevice.sys@0xF4B3CE36] A device is deleting itself while there is another device beneath it in the driver stack.This may be because the caller has forgotten to call IoDetachDevice first,or the lower driver may have incorrectly delete itself.
   所以,问题的原因是因为没有调用IoDetechDevice。
   那么在DriverWorks中框架中那个位置调用的IoAttachDeviceToDeviceStack呢?开始我以为在new或者构造函数中,跟踪发现,在其中只是调用了IoCreateDevice和IoCreateSymbolicLink等函数,并初始化了一堆成员变量。所以不在这些函数中。
   后来看生成的TestDeviceDevice的构造函数,才发现有一行代码。
   // Initialize the lower device
   m_Lower.Initialize(this, Pdo);
   看名子就应该是调用IoAttachDeviceToDeviceStack的地方。跟踪进入,果然。
   NTSTATUS KPnpLowerDevice::Initialize(
KDevice* AttachingDevice,
PDEVICE_OBJECT PhysicalDeviceObject
)
  {
// The device should not already be initialized
ASSERT(m_pDeviceObject == NULL);

m_pDeviceObject =
IoAttachDeviceToDeviceStack(
*AttachingDevice,
PhysicalDeviceObject
);
m_pFileObject = NULL;
if (m_pDeviceObject != NULL)
{
m_PhysicalDeviceObject = PhysicalDeviceObject;
}
else
{
m_PhysicalDeviceObject = NULL;
m_ConstructorStatus = STATUS_NO_SUCH_DEVICE;
}

BOUNDS_CHECKER(CONSTRUCTED_PNP_LOWER_DEVICE, (this, m_ConstructorStatus));

return m_ConstructorStatus;
  }
  所以,我想IoDetechDevice也应该在该类中,但是却没有找到。搜索m_pDeviceObject,发现为父类KLowerDevice的成员变量,在KLowerDevice中搜索,也没有发现IoDetechDevice。按照我的理解,KPnpLowerDevice应该在析构函数中调用IoDetechDevice,但是却没有发现竟然没有定义KPnpLowerDevice的析构函数,继续查找KLowerDevice的析构函数,存在析构函数,但是却没有希望的代码。而且KLowerDevice的析构函数竟然还不是虚拟的。一般来说,析构函数不是虚拟的类如果被继承是比较危险的(容易导致子类的析构函数不会被调用),不知道在此为什么在此会把KLowerDevice的析构函数设为非虚拟的。
   没办法,只好再搜索m_pDeviceObject,发现可以使用成员函数DeviceObject()返回m_pDeviceObject。那样就只能直接使用该对象来调用IoDetechDevice。在TestDeviceDevice的析构函数中加入:

   if (m_Lower.DeviceObject())
IoDetachDevice(m_Lower.DeviceObject());
   可以返回正确的代码。Page Fault错误也没有出现。

   还有一些东西没有想明白。
   1。为什么compuware不在KPnpLowerDevice类的析构函数中调用IoDetechDevice。感觉这样在结构上会更好一些。
   2。直接使用了DeviceObject(),并对其进行了操作,感觉这样做并不是太好。而且帮助文档中也说"drives do not normally modify the value.".
   2。为什么原来在卸载驱动程序时没有出现该错误,是否因为在正常卸载时某个高层的函数(或者是系统的函数)删除了相关的堆栈,所以也不会有代码再引用这个DeviceObject,这样的也就没有出错??而直接在AddDevice中删除,则由于没有调用IoDetechDevice,此时相关堆栈并没有删除。所以该DeviceObject还在被引用,则会导致出错。只是猜测,学习中.....
  
matrixss
驱动牛犊
驱动牛犊
  • 注册日期2004-08-21
  • 最后登录2010-07-26
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望47点
  • 贡献值0点
  • 好评度14点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2005-01-04 21:30
又研究了一下,发现这样改了还是不行,如果TestDeviceDevice的析构函数当正常安装时就会出现错误。分析发现在VOID KPnpDevice::SetPnpPolicy(void)函数中有这样一句代码:
   m_Policies.m_GeneralPolicy.m_WaitForSafeRemove = TRUE;
m_Policies.m_GeneralPolicy.m_DetachPdoOnRemove = TRUE;
m_Policies.m_GeneralPolicy.m_DeletePdoOnRemove = TRUE;
在KDevice中存在一个Detach函数(上午没有注意到):
inline VOID KDevice::Detach(KLowerDevice* pLowerDevice)
{
IoDetachDevice(pLowerDevice->DeviceObject());
BOUNDS_CHECKER(DETACHED_LOWER_DEVICE, (this, pLowerDevice));
}
在NTSTATUS KPnpDevice::Pnp(KIrp I)函数中调用了Detach。
case IRP_MN_REMOVE_DEVICE:
 ...
          if ( m_Policies.m_GeneralPolicy.m_DetachPdoOnRemove && m_TopOfStackDevice )
          {
               Detach(m_TopOfStackDevice);
               m_TopOfStackDevice = NULL;
          }
所以,正常卸载时,将会调用Detach函数,从而调用IoDetachDevice。

这样,在析构函数中再次调用,则是不正确的。
那么,原来的问题怎么解决呢?我想因为该问题由于 m_Lower.Initialize(this, Pdo);而起,所以不能在其它地方解决,也就是说,不能在AddDevice中直接设置status使NTSUCCESS(status)为FALSE。如果要返回一个错误代码,例如STATUS_NO_SUCH_DEVICE,可以在m_Lower.Initialize(this, Pdo);之前设置后返回即可,这样可以在错误时不执行m_Lower.Initialize(this, Pdo);
有问题的话继续讨论。
jgw2008
驱动小牛
驱动小牛
  • 注册日期2004-12-16
  • 最后登录2005-12-20
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望8点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2005-01-05 11:12
十分敬佩你的钻研精神,值得我学习 :)你的英语也十分棒,我可以拜你为师了,收下我吧... ;)
只是下次不要给我分了,俺对那没欲望 :D给那些有这种需求的ggjjddmm们.
你提了好多问题,有一本书可以很好地回答你的所有问题,
"Programming the Microsoft Windows Driver Model,2nd Ed",大师手笔,绝对经典.

读这本书要求你要对os有相当程度的了解,这本书看的会更容易,推荐os:
"Inside Windows 2000",同样十分经典,可从本网站下载

如有问题,继续ding

Good luck to you
Best Wishes to you! MSN: jgw2008@hotmail.com E-Mail: jgw2008@126.com
jgw2008
驱动小牛
驱动小牛
  • 注册日期2004-12-16
  • 最后登录2005-12-20
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望8点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2005-01-05 11:14
上面推荐的两本书均可从本网站下载
Best Wishes to you! MSN: jgw2008@hotmail.com E-Mail: jgw2008@126.com
cekonglizhen
驱动牛犊
驱动牛犊
  • 注册日期2008-07-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分22分
  • 威望128点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2008-12-31 10:03
分析的很棒。顶了~
游客

返回顶部