yushui213
驱动小牛
驱动小牛
  • 注册日期2006-04-17
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分1015分
  • 威望115点
  • 贡献值0点
  • 好评度102点
  • 原创分0分
  • 专家分0分
阅读:1393回复:3

USB驱动程序造成关机不正常

楼主#
更多 发布于:2007-11-05 16:25
我的USB设备可以正常工作,但是在关机时却无法正常关机,请各位大大帮忙看看。
环境是XP,USB驱动采用DS中的一个例子,等时传输的例子。
关机时,屏幕一直停留在“Windows正在关机...”,如果这时把USB拔掉,马上就可以正常关机了。
USB设备采用的是外部供电。

驱动程序源码如下:(其实就是DS的例子)
#include <vdw.h>
#include <kusb.h>

#include "isochdev.h"
#include "isocioct.h"

extern KTrace Tracer;          // Global driver trace object

UsbIsocDevice::UsbIsocDevice(PDEVICE_OBJECT Pdo, ULONG Unit) :

    KPnpDevice(
        Pdo,
        KUnitizedName(L"UsbIsoc", Unit),
        FILE_DEVICE_UNKNOWN,
        KUnitizedName(L"UsbIsoc", Unit)
        )
{
    Tracer << "UsbIsocDevice::UsbIsocDevice() Entry\n";

    m_pReadFifo     = NULL;
    m_pReadContexts = NULL;

    m_readOverflow  = 0;
    
    m_unitNum = Unit;

    m_Usb.Initialize(this, Pdo);    // initialize the USB interface

        // initialize the USB interface
    m_Interface.Initialize(
                    m_Usb,    //KUsbLowerDevice
                    0,        //Interface Number
                    1,        //Configuration Value
                    0        //Initial Alternate Setting for the Interface
                    );  
    
        // initialize description of data in pipe (In Bulk)
    m_Pipe0.Initialize(
                m_Usb,    //KUsbLowerDevice
                0x88    //Endpoint Address
                );

    // initialize description of data out pipe (Out Bulk)
    m_Pipe1.Initialize(
                m_Usb,    //KUsbLowerDevice
                0x8        //Endpoint Address
                );

    SetLowerDevice(&m_Usb); // inform PnP code of our Top-of-stack device

    SetPnpPolicy();         // use the default Pnp policy
}

UsbIsocDevice::~UsbIsocDevice()
{
    Tracer << "UsbIsocDevice::~UsbIsocDevice() Entry\n";

    DeleteAllReadContexts();

    if ( m_pReadFifo ) {
        delete m_pReadFifo;
        m_pReadFifo = NULL;
    }
}

NTSTATUS UsbIsocDevice::DefaultPnp(KIrp I)
{
    static char* minors[] = {
        "IRP_MN_START_DEVICE",    
        "IRP_MN_QUERY_REMOVE_DEVICE",    
        "IRP_MN_REMOVE_DEVICE",    
        "IRP_MN_CANCEL_REMOVE_DEVICE",    
        "IRP_MN_STOP_DEVICE",    
        "IRP_MN_QUERY_STOP_DEVICE",    
        "IRP_MN_CANCEL_STOP_DEVICE",    
        "IRP_MN_QUERY_DEVICE_RELATIONS",    
        "IRP_MN_QUERY_INTERFACE",    
        "IRP_MN_QUERY_CAPABILITIES",    
        "IRP_MN_QUERY_RESOURCES",    
        "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",    
        "IRP_MN_QUERY_DEVICE_TEXT",    
        "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",    
        "IRP_MN_undefined",    
        "IRP_MN_READ_CONFIG",    
        "IRP_MN_WRITE_CONFIG",    
        "IRP_MN_EJECT",    
        "IRP_MN_SET_LOCK",    
        "IRP_MN_QUERY_ID",    
        "IRP_MN_QUERY_PNP_DEVICE_STATE",    
        "IRP_MN_QUERY_BUS_INFORMATION",    
        "IRP_MN_DEVICE_USAGE_NOTIFICATION",
        "IRP_MN_SURPRISE_REMOVAL"
    };

    ULONG Minor = I.MinorFunction();
    CHAR* IrpName;

    if ( Minor < IRP_MN_SURPRISE_REMOVAL )
        IrpName = minors[Minor];
    else
        IrpName = "<unknown>";

    DbgPrint("Pnp IRP minor function=%s\n", IrpName);

    I.ForceReuseOfCurrentStackLocationInCalldown();
    return m_Usb.PnpCall(this, I);
}


NTSTATUS UsbIsocDevice::DefaultPower(KIrp I)
{
    I.IndicatePowerIrpProcessed();
    I.CopyParametersDown();
    return m_Usb.PnpPowerCall(this, I);
}

NTSTATUS UsbIsocDevice::SystemControl(KIrp I)
{
    I.ForceReuseOfCurrentStackLocationInCalldown();
    return m_Usb.PnpCall(this, I);
}


NTSTATUS UsbIsocDevice::OnStartDevice(KIrp I)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    AC_STATUS acStatus;

    Tracer << "UsbIsocDevice::OnStartDevice() Entry\n";
    
// The default Pnp policy has already cleared the IRP with the lower device
// Now we initialize the device object

    acStatus = m_Usb.ActivateConfiguration(1);

    switch (acStatus)
    {
    case AC_SUCCESS:
        Tracer << "Configuration OK\n";
        status = STATUS_SUCCESS;
        break;

    case AC_COULD_NOT_LOCATE_INTERFACE:
        Tracer << "Could not locate interface, endpoint address ";
        break;

    case AC_COULD_NOT_PRECONFIGURE_INTERFACE:
        Tracer << "Could not get configuration descriptor\n";
        break;

    case AC_CONFIGURATION_REQUEST_FAILED:
        Tracer << "Board did not accept configuration URB\n";
        break;

    case AC_FAILED_TO_INITIALIZE_INTERFACE_OBJECT:
        Tracer << "Failed to initialize interface for pipe[" ;
        break;

    case AC_FAILED_TO_LOCATE_ENDPOINT_ADDRESS:
        Tracer << "Failed to locate endpoint address for pipe[" ;
        break;
    }

    if ( !m_pReadFifo ) {
        m_pReadFifo =
          new (NonPagedPool) KLockableFifo<UCHAR>(ISOC_READ_FIFO_SIZE, NonPagedPool);

        if ( !m_pReadFifo ) {
          Tracer << "Allocation of Read FIFO failed!\n";
            
            status = STATUS_INSUFFICIENT_RESOURCES;
        }
    }

    ASSERT( m_pReadFifo );

    if ( NT_SUCCESS(status) )
        status = StartIsocReads();

    return status;  // base class completes the IRP
}



NTSTATUS UsbIsocDevice::OnStopDevice(KIrp I)
{
    Tracer << "UsbIsocDevice::OnStopDevice() Entry\n";

    DeleteAllReadContexts();

    if ( m_pReadFifo ) {
        delete m_pReadFifo;
        m_pReadFifo = NULL;
    }

    return m_Usb.Unconfigure();

    // base class passes to lower device
}


NTSTATUS UsbIsocDevice::OnRemoveDevice(KIrp I)
{
    Tracer << "UsbIsocDevice::OnRemoveDevice() Entry\n";

    // Our PnP policy will take care of
    // (1) giving the IRP to USBD
    // (2) detaching the PDO
    // (3) deleting the device object

    return STATUS_SUCCESS;
}


NTSTATUS UsbIsocDevice::Create(KIrp I)
{
    Tracer << "UsbIsocDevice::Create() Entry\n";

    I.ForceReuseOfCurrentStackLocationInCalldown();
    NTSTATUS status = m_Usb.PnpCall(this, I);

    Tracer << "UsbIsocDevice:Create Status " << (ULONG)status << "\n";

    return status;
}


NTSTATUS UsbIsocDevice::Close(KIrp I)
{
    Tracer << "UsbIsocDevice::Close() Entry\n";

    I.ForceReuseOfCurrentStackLocationInCalldown();
    NTSTATUS status = m_Usb.PnpCall(this, I);

    Tracer << "UsbIsocDevice:Close Status " << (ULONG)status << "\n";

    return status;
}


NTSTATUS UsbIsocDevice::InternalDeviceControl(KIrp I)
{
    Tracer << "UsbIsocDevice::InternalDeviceControl() Entry\n";

    I.ForceReuseOfCurrentStackLocationInCalldown();
    NTSTATUS status = m_Usb.PnpCall(this, I);

    Tracer << "UsbIsocDevice::InternalDeviceControl Status "
           << (ULONG)status << "\n";

    return status;
}


NTSTATUS UsbIsocDevice::DeviceControl(KIrp I)
{
    Tracer << "UsbIsocDevice::DeviceControl() Entry\n";

    NTSTATUS status = STATUS_SUCCESS;

    switch (I.IoctlCode())
    {
        // Placeholder for real IOCTL calls
        case ISOC_FIRST_IOCTL:
            return I.PnpComplete(this, STATUS_SUCCESS);

        default:
            Tracer << "UNKNOWN [ID=" << I.IoctlCode() << "] );\n";
            I.Information() = 0;
            return I.PnpComplete(this, STATUS_INVALID_PARAMETER);
    }
}


VOID UsbIsocDevice::DeleteAllReadContexts()
{
    while ( m_pReadContexts )
    {
        PISOC_CONTEXT pContext = m_pReadContexts;

        m_pReadContexts = pContext->pNext;
        
        ASSERT( !pContext->bUsed );

        if ( !pContext->bUsed )
        {
            if ( pContext->pIrp )
                delete pContext->pIrp;
            
            if ( pContext->pUrb )
                delete pContext->pUrb;
            
            if ( pContext->pData )
                delete pContext->pData;
            
            delete pContext;
        }
    }
}

// iread.cpp - read operation for USB Isoc Sample Driver
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060  USA
//
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================

#include <vdw.h>
#include <kusb.h>
#include "isochdev.h"
#include "isocioct.h"

extern KTrace Tracer;          // Global driver trace object

////////////////////////////////////////////////////////////////////////////////
// Default handler for IRP_MJ_READ - Using USB Isoc Pipe
//
// This routine is the default handler for IRP_MJ_READ.
// Incoming IRPs read from a FIFO, filled by constantly
//   running Isoc URBs.  When FIFO fills, it is emptied
//   enough to put the new data into it!
//
// The KPnpDevice class handles restricting IRP flow
// if the device is stopping or being removed.
//
NTSTATUS UsbIsocDevice::Read(KIrp I)
{
    NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;

    Tracer << "UsbIsocDevice::Read() Entry\n";

    PUCHAR pBuffer      = (PUCHAR)I.BufferedReadDest();

    ULONG  dwTotalSize = I.ReadSize(CURRENT);
    ULONG  dwBytesRead = 0;

    if ( !m_pReadFifo ) {
        I.Information() = 0;
        I.PnpComplete(this, STATUS_UNSUCCESSFUL, IO_NO_INCREMENT);
        return STATUS_UNSUCCESSFUL;
    }

    // Get all data waiting in m_pReadFifo
    status = STATUS_SUCCESS;

    m_pReadFifo->Lock();
    
    if ( m_pReadFifo->NumberOfItemsAvailableForRead() == 0 )
    {
        m_pReadFifo->Unlock();
        I.Information() = 0;
        I.PnpComplete(this, status, IO_NO_INCREMENT);
        return status;
    }

    dwBytesRead = m_pReadFifo->Read(pBuffer, dwTotalSize);
    m_pReadFifo->Unlock();
    
    if ( dwBytesRead != dwTotalSize ) {
        Tracer << "Read FIFO Read of "
                    << dwBytesRead << "/" << dwTotalSize << " Bytes\n";
    } else {
        Tracer << "Read FIFO Read of " << dwBytesRead << " Bytes\n";
    }

    I.Information() = dwBytesRead;
    I.PnpComplete(this, status, IO_NO_INCREMENT);

    return status;
}




////////////////////////////////////////////////////////////////////////////////
// Starts a single ISOC read - allocating structures and submitting URB
//
NTSTATUS UsbIsocDevice::StartIsocReads()
{
    NTSTATUS status;

    for (int i=0; i<ISOC_NUM_READ_URBS; i++)
    {
        UCHAR *p = new (NonPagedPool) UCHAR[ISOC_URB_DATA_SIZE];
        ASSERT(p);
        if ( !p )  break;
        
        PURB pUrb =
            m_Pipe0.BuildIsochronousTransfer(
                ISOC_NUM_PACKETS_PER_URB,    // # packets
                ISOC_PACKET_SIZE,            // packet size
                TRUE,                        // bIn
                TRUE,                        // bASAP
                USBD_ISO_START_FRAME_RANGE,// Start Frame
                p,                            // pBuffer
                ISOC_URB_DATA_SIZE            // Length
                );

        ASSERT(pUrb);
        if ( !pUrb ) {
            delete p;
            break;
        }

        // Do not get an error on short or zero length packets
        pUrb->UrbIsochronousTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;

        PISOC_CONTEXT pContext = new (NonPagedPool) ISOC_CONTEXT;
        ASSERT(pContext);
        if ( !pContext ) {
            delete pUrb;
            delete p;
            break;
        }

        // Create the accompanying IRP once, since the kernel
        //   does not like us deleting and allocating IRPs
        //   on every completion routine.
        CCHAR stackSize = m_Usb.StackRequirement() + 1;
        PIRP pIrp = IoAllocateIrp(stackSize, FALSE);

        pContext->pNext = m_pReadContexts;
        pContext->bUsed = TRUE;
        pContext->pDev  = this;
        pContext->pIrp  = pIrp;
        pContext->pUrb  = pUrb;
        pContext->pData = p;
        pContext->pMdl  = NULL;
            
        m_pReadContexts = pContext;

        IncrementOutstandingRequestCount();

        status = QueueIsocRead(pContext);

        if ( !NT_SUCCESS(status) )
            break;
    }

    if ( i != ISOC_NUM_READ_URBS )
    {
        Tracer << "StartReads() allocation FAILURE!\n";
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    return STATUS_SUCCESS;
}



NTSTATUS
UsbIsocDevice::QueueIsocRead(PISOC_CONTEXT pContext)
{
    NTSTATUS status;
    _URB_HEADER         *pUHdr = (_URB_HEADER *)pContext->pUrb;
    _URB_ISOCH_TRANSFER *pIsoc = &pContext->pUrb->UrbIsochronousTransfer;

    pUHdr->UsbdDeviceHandle     = NULL;
    pUHdr->UsbdFlags            = 0;
    pIsoc->TransferBufferLength = ISOC_URB_DATA_SIZE;
    pIsoc->TransferBufferMDL    = NULL;
    pIsoc->StartFrame           = 0;

    memset(&pIsoc->hca, 0, sizeof(_URB_HCD_AREA));

    status = m_Pipe0.SubmitUrb(
                pContext->pIrp,
                pContext->pUrb,
                LinkTo(UsbIsocReadComplete),
                pContext
                );

    if ( !NT_SUCCESS(status) )
    {
        Tracer << "Submission of Isoc Read URB FAILED (status="
                    << (ULONG)status << ")!\n";
    }

    return status;
}


NTSTATUS
UsbIsocDevice::UsbIsocReadComplete(KIrp I, PISOC_CONTEXT pContext)
{
    NTSTATUS status;

    if ( m_State.m_StopPending ||
         m_State.m_RemovePending ||
         m_State.m_Removed ||
         m_State.m_SurpriseRemoval
       )
    {
        // Do not re-submit this URB
        pContext->bUsed = FALSE;
        DecrementOutstandingRequestCount();
        return STATUS_MORE_PROCESSING_REQUIRED;
    }

    if ( !NT_SUCCESS(I.Status()) )
    {
        // URB submission FAILED!
        Tracer << "Isoc Read IRP FAILED (status="<< (ULONG)I.Status() << ")!\n";

        pContext->bUsed = FALSE;
        DecrementOutstandingRequestCount();
        return STATUS_MORE_PROCESSING_REQUIRED;
    }

    // If we have nowhere to put its data, just re-cycle this buffer.
    if ( !m_pReadFifo ) {
        status = QueueIsocRead(pContext);
        return STATUS_MORE_PROCESSING_REQUIRED;
    }
    

    _URB_ISOCH_TRANSFER *pIsoc = &pContext->pUrb->UrbIsochronousTransfer;
    
    PUSBD_ISO_PACKET_DESCRIPTOR ppd;

    UCHAR   temp[ISOC_PACKET_SIZE];

    BOOLEAN bOverflow   = FALSE;
    ULONG   dwDataCount = 0;

    // Take data from URB completion, and copy it into our FIFO
    //   If our FIFO fills up, then clear out enough for the new data!
    for (int i=0; i<ISOC_NUM_PACKETS_PER_URB; i++)
    {
        ppd = &pIsoc->IsoPacket;

        // We ignore zero length packets in the data stream for now.
        //   You might want to have a zero length packet signal the
        //   end of a large block of data.  If so, then you need to
        //   handle a zero length packet arriving at any time!
        if ( USBD_SUCCESS(ppd->Status) && (ppd->Length > 0) )
        {

            PUCHAR p = ((UCHAR *)pIsoc->TransferBuffer) + ppd->Offset;

            m_pReadFifo->Lock();
            if ( ISOC_PACKET_SIZE > m_pReadFifo->NumberOfItemsAvailableForWrite() )
            {
                bOverflow = TRUE;

                // Discard oldest data from the Read FIFO
                m_pReadFifo->Read(temp, ppd->Length);
            }

            m_pReadFifo->Write(p, ppd->Length);
            m_pReadFifo->Unlock();

            dwDataCount += ppd->Length;
        }
    }

    if ( bOverflow )
    {
        Tracer << "Read FIFO overflow!\n";
        m_readOverflow++;
    }

    if ( (dwDataCount > 0))
        Tracer << "Isoc Read received " << dwDataCount    << " bytes\n";

    
    // Resubmit this URB.
    status = QueueIsocRead(pContext);

    return STATUS_MORE_PROCESSING_REQUIRED;
}
// iwrite.cpp - device class implementation for USB Isoc Sample Driver
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060  USA
//
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================

#include <vdw.h>
#include <kusb.h>
#include "isochdev.h"
#include "isocioct.h"


extern KTrace Tracer;          // Global driver trace object


////////////////////////////////////////////////////////////////////////////////
// Default handler for IRP_MJ_WRITE - Using USB Isoc Pipe
//
// This routine is the default handler for IRP_MJ_WRITE.
// Incoming IRPs just send data down to the USB device, synchronously.
//
// The KPnpDevice class handles restricting IRP flow
// if the device is stopping or being removed.
//
// The application doing these writes MUST limit the amount of
// data being written to ISOC_NUM_PACKETS_PER_URB * ISOC_PACKET_SIZE,
// or 2048 bytes - to be compatible with all Host Controller drivers
// in Win95 and Win98.
//
// If you want to write more data at once, consider creating multiple
// URBs and IRPs that would span the entire data block you wish to
// write.  Care must be taken that the original IRP is not completed
// until all of the URBs are done.
//
NTSTATUS UsbIsocDevice::Write(KIrp I)
{
    NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;

    I.Information() = 0;

    Tracer << "UsbIsocDevice::Write() Entry\n";

    // Send down a Pipe Reset.
    //
    // Since these writes are queued from Ring 3, assume
    //   that the previous write has finished, and the
    //   pipe did not have more data queued up to it in time!
    m_Pipe1.Reset();

    PVOID pBuffer     = I.BufferedWriteSource();
    ULONG dwTotalSize = I.WriteSize(CURRENT);
    ULONG dwBytesSent = 0;

    // Create an URB to do actual Bulk read from Pipe0
    KMemory *pMdl = new (NonPagedPool) KMemory(pBuffer, dwTotalSize);
    if ( !pMdl )
    {
        ASSERT( pMdl != 0 );
        return I.PnpComplete(STATUS_INSUFFICIENT_RESOURCES, IO_NO_INCREMENT);
    }
    pMdl->SetPageArray();    // tells system to set phys page addrs inside MDL

    PISOC_CONTEXT pContext = new (NonPagedPool) ISOC_CONTEXT;
    if ( !pContext )
    {
        ASSERT ( pContext != 0 );
        delete pMdl;
        return I.PnpComplete(STATUS_INSUFFICIENT_RESOURCES, IO_NO_INCREMENT);
    }

    memset(pContext, 0, sizeof(ISOC_CONTEXT));

    // NOTE: This assumes you are passing a total size that is
    //       an even multiple of the hard-coded packet size (now
    //       64), is 2048 bytes or less. Packet size is hardware
    //         dependent.
    //
    //       If USBD gets a "short" packet for transfer, your
    //       pipe will be shut down.
    //
    ULONG numPackets = dwTotalSize / ISOC_PACKET_SIZE;

    if ( (numPackets * ISOC_PACKET_SIZE) != dwTotalSize )
        numPackets++;

    ASSERT( numPackets <= ISOC_NUM_PACKETS_PER_URB );
    
    PURB pUrb =
        m_Pipe1.BuildIsochronousTransfer( numPackets,        // # of Packets
                                          ISOC_PACKET_SIZE,    // Packet Size
                                          FALSE,            // Output, not in
                                          TRUE,                // send ASAP
                                          0,                // Start frame (unused if ASAP)
                                          pMdl,
                                          dwTotalSize
                                        );

    // Submit the URB to our USB device, asynchronously
    if ( pUrb != 0 )
    {
        // Fill in the USBD_ISO_PACKET_DESCRIPTORs
        for (ULONG i=0; i<numPackets; i++)
            pUrb->UrbIsochronousTransfer.IsoPacket.Offset = i*ISOC_PACKET_SIZE;

        pContext->pDev = this;
        pContext->pIrp = I;
        pContext->pUrb = pUrb;
        pContext->pMdl = pMdl;

        // clean up is always done in UsbIsocWriteComplete if SubmitUrb is called
        NTSTATUS status = m_Pipe1.SubmitUrb(pUrb, LinkTo(UsbIsocWriteComplete), pContext);
        
        if(status == STATUS_PENDING)
            I.MarkPending();  //This is the normal case.
        else if(!NT_SUCCESS(status))
            I.PnpComplete(status);
        return status;
    }
    else
    {
        ASSERT ( pUrb != 0 );
        delete pMdl;
        delete pContext;
        return I.PnpComplete(STATUS_INSUFFICIENT_RESOURCES, IO_NO_INCREMENT);
    }
}

NTSTATUS UsbIsocDevice::UsbIsocWriteComplete(KIrp I, PISOC_CONTEXT pContext)
{
// The only field in the IRP that this routine may examine is the status.

    NTSTATUS status = I.Status();

// NOTE: We created this IRP.  We do not have to mark it pending
//       because we are also the last driver to deal with this IRP!
//    if ( I->PendingReturned )
//        I.MarkPending();

    ASSERT ( pContext != NULL );

    ULONG dwBytesSent =
        pContext->pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;

    if ( dwBytesSent > 0 ) {
        Tracer << "Write() sent "
                << dwBytesSent
                << " bytes to USB (status="
                << (ULONG)status << ")!\n";
    }

    KIrp origI(pContext->pIrp);

    // Clean up all the allocations we did
    if ( pContext->pUrb )
        delete pContext->pUrb;
    
    if ( pContext->pMdl )
        delete pContext->pMdl;
    
    delete pContext;

    // Now complete the IRP that started this write
    origI.Information() = dwBytesSent;

    if (origI->PendingReturned)
        origI.MarkPending();

    origI.PnpComplete(status, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}




采用WinDbg调试时,发现在调试模式下只要在Read的完成例程里所有的URB都提交失败后,就可以正常关机了。
这个例子中的URB数目最多是4个。
也就是说如果输出了4次的
        // URB submission FAILED!
        Tracer << "Isoc Read IRP FAILED (status="<< (ULONG)I.Status() << ")!\n";
之后,就可以正常关机了。
如果只输出3次或者更少,就不能正常关机了,就会出现文章开头描述的问题了。

麻烦各位大大了。
我都不知道该如何下手了。

谢谢谢谢!!

yushui213
驱动小牛
驱动小牛
  • 注册日期2006-04-17
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分1015分
  • 威望115点
  • 贡献值0点
  • 好评度102点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-11-06 09:40
大大们有没有遇到这种问题呢???

谢谢大家啊
yushui213
驱动小牛
驱动小牛
  • 注册日期2006-04-17
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分1015分
  • 威望115点
  • 贡献值0点
  • 好评度102点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-11-06 15:45
大家不要责怪我,我实在没办法啊

沉得好快,所以只好自己顶了

请大家帮帮忙,谢谢!
yushui213
驱动小牛
驱动小牛
  • 注册日期2006-04-17
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分1015分
  • 威望115点
  • 贡献值0点
  • 好评度102点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-11-07 12:17
。。。。

郁闷了
游客

返回顶部