我没有判断的程序但是我有用API打开和关闭光驱的程序但愿对你有用:
声明API
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long打开:
retvalue = mciSendString("set CDAudio door open", returnstring, 127, 0)关闭:
retvalue = mciSendString("set CDAudio door closed", returnstring, 127, 0)如果没有用就笑笑算了!! ^)^

解决方案 »

  1.   

    retvalue = mciSendString("set CDAudio door closed", returnstring, 127, 0)
    执行这句话后cd-rom肯定是关着的想些什么播放软件马?
    有知道cd-rom状态的必要吗?
      

  2.   

    我想一般程序中不必判断是否关门,只需判断光驱是否准备好(放了光盘并且关上了),除非你需要用它放茶杯(开个玩笑),写了个函数放在你的另一个帖子里了上面两位老兄的方法只是让cdrom自己关上,但到底是否成功,还不一定,比如我的笔记本电脑,光驱没有自动关闭的机械结构,必须要手推。我想一定要判断光驱是否关门的话,这个问题可能是无解的。不知大家有没有注意到,windows中光驱快捷菜单中只有弹出命令,而没有关闭命令,我觉得很不方便,早在几年前,我就想自己在弹出菜单里加个菜单,来关闭光驱(设想就是当光驱关闭的时候,菜单显示弹出,光驱弹出时,显示关闭),但就是没办法判断光驱门的状态,后来我一直注意这个问题(当时用解压卡播放VCD,驱动软件里似乎可以模拟光驱的开关,但仔细研究一下,就可以发现它也是判断光驱是否准备好来做的),至今还没有发现哪个软件可以实现这个功能(这可能也是m$不做关闭功能的原因吧)。
      

  3.   

    但是可以拦截新盘插入,新盘抽出等状态,下面是我原来写的一篇小文章:Step by step:使用VB控制CD-ROM(Author:tief)关键字:EJECT API mciSendString Microsoft VC MCI WindProc CD-ROM CDROM(1) 使用命令弹出、关闭CD-ROM。
    使用MCI命令字符串可以控制CD-ROM的弹出和弹入,VB提供了MCI控件,最初我考虑它应该是支持所有MCI命令的,但经试验未果,最后只能把原始的MCI APIs抬出来(大家可以参考MSDN – MCI Command strings,这里包含了所有MCI控制命令的字符串描述)。这样我们就必须要在项目中添加一个API的声明,为了这个声明对任何模块和窗体都有效,我们要把它放置到模块文件中作为Public声明出现,步骤如下:
    1. 在窗体上添加cmdEject和cmdClose两个按钮。
    2. 选择工程菜单——添加模块,然后将新添加的模块命名为APIs。
    3. 在模块中添加如下声明:Public Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long
    4. 处理cmdEject的Click事件,加入如下代码:
        Dim strSend As String * 80
        Dim strRecv As String * 80
        strSend = "set cdaudio door open"
        mciSendString strSend, strRecv, 80, 0
    Debug.Print "Recv = " + strRecv
    5. 处理cmdClose的Click事件,加入如下代码:
        Dim strSend As String * 80
        Dim strRecv As String * 80
        strSend = "set cdaudio door closed"
        mciSendString strSend, strRecv, 80, 0
    Debug.Print "Recv = " + strRecv
    这样就可以有效的控制CD-ROM的弹出和弹入了。
    (2) 如何感知CD-ROM中的碟片变化
    处理WM_DEVICECHANGE消息可以获得碟片变化的信息,比如新的碟片被弹入,或者碟片被从CD-ROM中移除。这些消息由Windows发送到窗体的消息队列中,既然需要拦截窗体消息,我们就必须重建Window Procdure,在这个函数中判断各种到来的消息。重建Windows Procdure所用的API分别为SetWindowLong和CallWindowProc,那么我们在模块APIs中添加声明如下:
    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
        (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
        (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, _
        ByVal wParam As Long, ByVal lParam As Long) As Long
    Public Const GWL_WNDPROC = -4&
    这些声明很烦,但是原文都可以在Visual Studio中提供的“API阅览器”中找到。
    然后我们把窗体过程(Window Procdure)的框架实现:
    1. 由于在窗体过程中务必调用默认窗体过程,所以我们有必要保存frmMain的默认窗体过程的入口地址,我们采取全局变量glOldWndProc来存储这个信息,同时使用ghWnd来存储主窗体的句柄:hWnd。
    在模块APIs中添加如下声明:
    Public glOldWndProc As Long
    Public ghWnd As Long
    2. 在模块APIs中添加窗体过程的框架代码:
    Public Function VbWndProc(ByVal hWnd As Long, ByVal uMsg As Long, _
        ByVal wParam As Long, ByVal lParam As Long) As Long
    Select Case uMsg
    Case Else
        End Select
        VbWndProc = CallWindowProc(glOldWndProc, ghWnd, uMsg, wParam, lParam)
    End Function
    3. 捕捉frmMain的Form_Load事件,在这个事件中完成窗体过程的重新设定。
    Private Sub Form_Load()
    ghWnd = Me.hWnd ‘保存窗体句柄hWnd
    ‘设置新的窗体过程,同时保存默认窗体过程的入口地址
        glOldWndProc=SetWindowLong(hWnd,GWL_WNDPROC, AddressOf VbWndProc)
    End Sub
    好,此时似乎已经大功告成(我当时就是这样想的),只需要在窗体过程的SELECT语句中判断消息类型uMsg就可以了。不过我查阅了“API阅览器”,却没有发现WM_DEVICECHANGE的声明,最终在VC中试验出了WM_DEVICECHANGE常量值为537,那么我们在APIs中添加如下常量说明:
    Public Const WM_DEVICECHANGE = 537&
    同时在Select语句中添加相应的判断:
        Select Case uMsg
            Case Is = WM_DEVICECHANGE
                Debug.Print "WM_DEVICECHANGE"
                Debug.Print "wParam = " & wParam
            Case Else
    End Select
    注意出现在Case中的Debug.Print语句,这是VB程序员进行调试的常用方法,使用VB而不用Debug.Assert和Debug.Print是难以想象的,在VC中提供断言以及变量监视的方法就更多一些,甚至类型(比如RTTI)。
    这个消息捕捉到了,我们还要继续判断这个消息说明的是碟片被移除还是新碟片被插入,在WINDOWs SDK程序设计标准中这是由wParam参数决定的,定义的宏分别为DBT_DEVICEARRIVAL和DBT_DEVICEREMOVECOMPLETE,但是这两个宏所代表的常量值依然无法在“API阅览器”中找到,而且在VC中也没有相应的宏声明,此时上面CASE语句中的Debug.Print "wParam = " & wParam就发挥了作用,在光盘的插拔过程中通过立即窗口的显示我们可以得知DBT_DEVICEARRIVAL对应的常量为32768,而DBT_DEVICEREMOVECOMPLETE对应的常量为32772。那么我们在模块APIs中再添加对这两个消息的声明(注意,声明中没有使用默认的宏名字):
    Public Const CD_REMOVED = 32772
    Public Const CD_INSERTED = 32768
    然后扩充CASE语句:
        Select Case uMsg
            Case Is = WM_DEVICECHANGE
                Debug.Print "WM_DEVICECHANGE"
                Debug.Print "wParam = " & wParam
                Select Case wParam
                    Case Is = CD_REMOVED
                        MsgBox "CD_REMOVED"
                    Case Is = CD_INSERTED
                        MsgBox "CD_INSERTED"
                End Select
            Case Else
    End Select
    这样我们就完成了对碟片变化这个事件的捕捉。
    写这篇文章主要是由于网友ygrobin问起了是否可以在VB中利用API锁定光驱(就是让光驱变成是不可弹出的)的问题,但是由于本人才疏学浅,还是没能解决,还望同行赐教。2001年12月11日星期二
      

  4.   

    看一下 Windows 2000 的附件-娱乐-CD 唱机,就可以知道各位的说法不对,不是做不到,而是各位想不到。你把 CD 托盘打开,然后启动 CD 唱机,按一下 Eject 按钮,CD 托盘关闭了吧?如果本来就是关闭的,你启动 CD 唱机,按一下 Eject 按钮,CD 托盘就会打开。它是怎么知道的?
      我不是菜鸟,我们认真一点玩,好不好?:)
      

  5.   

    tief(但求中庸),你的代码文章可以更进一步:下面是我自己写的一个 VCD AutoPlay 程序的片段:Dim tDevHdr As DEV_BROADCAST_HEADER
    Dim tDevVol As DEV_BROADCAST_VOLUME
    Dim tmpBuffer As String
    ……
    Case WM_DEVICECHANGE
      If wParam = DBT_DEVICEARRIVAL Then     ' 检测是否是光驱。
        CopyMemory tDevHdr, ByVal lParam, Len(tDevHdr)    If tDevHdr.dbcd_devicetype = DBT_DEVTYP_VOLUME Then
          CopyMemory tDevVol, ByVal lParam, tDevHdr.dbcd_size      With tDevVol
            tmpBuffer = String(4, vbNullChar)
            PathBuildRoot tmpBuffer, TestDriveBit(.dbcv_unitmask)
            If GetDriveType(tmpBuffer) = DRIVE_CDROM Then PlayVCD (tmpBuffer)
          End With
        End If
      End If
    ……' 获得 WM_DEVICECHANGE 消息中 DEV_BROADCAST_VOLUME 设置的驱动器符号。
    Public Function TestDriveBit(ByVal dwValue As Long) As Long
      Dim i As Long
        
      For i = 0 To 25
        If (dwValue And (2 ^ i)) = (2 ^ i) Then
          TestDriveBit = i
          Exit For
        End If
      Next i
    End Function
      

  6.   

    现在我用了一个不准确的方法:先用 mciSendString 关闭光驱,加 wait 关键词。如果光驱本身已经关闭,函数将立即返回;如果光驱本来是打开的,那么从关闭到判断是否有盘,必然要一定时间函数才能返回。我就通过判断第一条指令的消耗时间,来决定是否执行下一条指令:如果时间很短,就说明光驱本来是关闭的,就用 mciSendString 打开光驱;如果时间超过 1 秒,就不执行第二条打开光驱的指令。
      我觉得这种方法虽然可行,却不完美,所以才悬赏 200 分,希望明确获得光驱托盘状态。能够解决的话还可以加分。Come On!
      

  7.   

    其实这个判断很重要!表示极为关注!有了这个判断,“eject”功能只要一个按钮即可。还有,在Windows 2000下,如果光驱门已经打开,那么再发送打开指令,那么,你的程序就会非法操作……即使你用了on error resume next
      

  8.   

    看看 这个是否对你 有 启发:http://www.codeguru.com/system/cdr.html
      

  9.   

    ===========================================
    请参考 Windows Media Player SDK用 Player Object 的 playState 属性
    ===========================================
    Syntaxplayer.playState=========================
    Possible ValuesThis property is a read-only Number (long).Value State Description 
    0 Undefined Windows Media Player is in an undefined state. 
    1 Stopped Playback of the current media clip is stopped. 
    2 Paused Playback of the current media clip is paused. When media is paused, resuming playback begins from the same location. 
    3 Playing The current media clip is playing. 
    4 ScanForward The current media clip is fast forwarding. 
    5 ScanReverse The current media clip is fast rewinding. 
    6 Buffering The current media clip is getting additional data from the server. 
    7 Waiting Connection is established, however the server is not sending bits. Waiting for session to begin. 
    8 MediaEnded Media has completed playback and is at its end.  
    9 Transitioning Preparing new media. 
    10 Ready Ready to begin playing. ==============================================================
    Sample:// Test if Windows Media Player is in the playing state.
    if (3 == Player.playState)
      myText.value = "Windows Media Player is playing!";
    else
      myText.value = "Windows Media Player is NOT playing!";
      

  10.   

    而且可以检查光去里有没有文件,
    就是dir "driver:\*" 出错就弹出光驱。
    好像bleem似的,
    不用理会里面有没有什么和光驱状态没有需要的文件就弹出光驱要求放入指定盘。
    或者象CD播放器一样,乐观选择一下,
    如果dir "driver:\*"出错就认为光驱是打开的,然后就执行关闭光驱。
    如果没有错就弹出光驱。
      

  11.   

    为什么这么多人都只会凑热闹?光驱弹出的时候你 Dir 也出错的,再弹个头啊~~~~~思路太不严密了,怎么混下去?
    自己没有办法,就说“不用那么复杂吧”——什么叫精益求精?只会说废话。200 分这么好拿?
      

  12.   

    试我的 方法了吗?=================================================================
    ===========================================
    请参考 Windows Media Player SDK用 Player Object 的 playState 属性
    ===========================================
    Syntaxplayer.playState=========================
    Possible ValuesThis property is a read-only Number (long).Value State Description 
    0 Undefined Windows Media Player is in an undefined state. 
    1 Stopped Playback of the current media clip is stopped. 
    2 Paused Playback of the current media clip is paused. When media is paused, resuming playback begins from the same location. 
    3 Playing The current media clip is playing. 
    4 ScanForward The current media clip is fast forwarding. 
    5 ScanReverse The current media clip is fast rewinding. 
    6 Buffering The current media clip is getting additional data from the server. 
    7 Waiting Connection is established, however the server is not sending bits. Waiting for session to begin. 
    8 MediaEnded Media has completed playback and is at its end. 
    9 Transitioning Preparing new media. 
    10 Ready Ready to begin playing. ==============================================================
    Sample:// Test if Windows Media Player is in the playing state.
    if (3 == Player.playState)
    myText.value = "Windows Media Player is playing!";
    else
    myText.value = "Windows Media Player is NOT playing!";
      

  13.   

    获得分区信息并判断是否有CD 
    声明:
    Declare Function GetVolumeInformation Lib _
    "kernel32" Alias "GetVolumeInformationA" _
    (ByVal lpRootPathName As String, _
    ByVal lpVolumeNameBuffer As String, _
    ByVal nVolumeNameSize As Long, _
    lpVolumeSerialNumber As Long, _
    lpMaximumComponentLength As Long, _
    lpFileSystemFlags As Long, _
    ByVal lpFileSystemNameBuffer As String, _
    ByVal nFileSystemNameSize As Long) As LongDeclare Function GetDriveType Lib "kernel32" _
    Alias "GetDriveTypeA" (ByVal nDrive As String) As LongPublic Const DRIVE_CDROM = 5
    使用:
    Dim VolName As String, FSys As String, erg As Long
    Dim VolNumber As Long, MCM As Long, FSF As Long
    Dim Drive As String, DriveType As Long
    VolName = Space(127)
    FSys = Space(127)
    Drive = "F:\" 'Enter the driverletter you want 
    DriveType& = GetDriveType(Drive$)
    erg& = GetVolumeInformation(Drive$, VolName$, 127&, _
    VolNumber&, MCM&, FSF&, FSys$, 127&)
    Print "分区名称:" & vbTab & VolName$
    Print "序列号:" & vbTab & VolNumber&
    Print "最大文件名称长:" & vbTab & vbTab & MCM&
    Print "文件系统标志:" & vbTab & vbTab & FSF&
    Print "文件系统名称:" & vbTab & FSys$
    Print "类型:" & vbTab & DriveType&;
    'Is the drive a CDROM, if so, check for a CD
    If DriveType& = DRIVE_CDROM Then 
    Print " (CDROM, "; 
    If erg& = 0 Then 
    Print "没有 CD )" 
    Else
    Print "有 CD )" 
    End If
    Else 
    Print " (非 CDROM)" 
    End If 
      

  14.   


    我还是坚持原来的意见:无解!!
    前两天放假,我只有笔记本电脑,没法试(关门必须手推),今天我试了一下win2k的CD唱机,我们来作个实验:cdrom中不要放光碟,并且把门关上,然后启动cd唱机,点击eject,你可以发现,第一次点击,cdrom并无反应,第二次点击,cdrom才开门,然后继续点击,就可以正常实现开关门动作。由此可见,cd唱机实现eject的逻辑:
    '首先有一个逻辑变量表示cdrom门的状态,假设为:
    dim bolCdOpen 'true开,false关
    'eject功能的代码:(其中用到一个函数cd_isready,一个过程cd_eject,写在后面)
    private sub cmdEject_Click()if cd_isready() then
    cd_eject "open"
    bolCdOpen=true
    else
    eject "close"
    cd_end if
    bolCdOpen=false
    end sub
    '判断cdrom是否准备好的函数
    private function cd_isready () as boolend
    '判断方法上次在你的另一个同样问题的帖子里我已经写了一个functionend function'开关门的过程,实现方法很多人已经讲过了就不抄了
    private sub cd_eject(mode as string)
    select case lcase(mode)
    case 'open''开门case 'close''关门end sub由此可见,win2k的cd唱机也只不过是通过判断cdrom是否准备好来模拟eject,并不能判断光驱门的状态。
      

  15.   

    这个程序:http://www.greatmidnight.com/redir.asp?id=superstuttererhome目前在测试阶段,使用了我前面说的 wait 方法,没有在笔记本电脑上测试过,但是在台式机上基本没有问题。只有个别光驱会导致系统停止反应一段时间。
      

  16.   

    我认为,可以在程序启动的时候发送一个关门的命令,然后用tief(但求中庸)的方法拦截新盘插入,新盘抽出等事件,来判断光驱门当前状况。
      

  17.   

    '希望这个实例对你有用,请看command1的字符
    >>步骤1----建立新工程,在窗体上放置一个CommandButton按钮.设置其Caption = "打开"
    >>步骤2----编写如下代码:Private Declare Function mciSendString Lib "winmm.dll" Alias _
        "mciSendStringA" (ByVal lpstrCommand As String, ByVal _
        lpstrReturnString As String, ByVal uReturnLength As Long, _
        ByVal hwndCallback As Long) As LongPrivate Sub Command1_Click()
        Static bOpen As Boolean
        Dim strStr As String    If Not bOpen Then
            Screen.MousePointer = vbHourglass
            strStr = "set CDAudio door open"
        Command1.Caption = "关闭"
        Else
            Screen.MousePointer = vbHourglass
            strStr = "set CDAudio door closed"
         Command1.Caption = "打开"
        End If    Call mciSendString(strStr, vbNull, 127, 0)
        Screen.MousePointer = vbDefault
        DoEvents
        bOpen = Not bOpen
    End Sub>>步骤3----编译运行,点击"打开",光驱弹出;点击"关闭",光驱关上.