private function isDoorOpen() as Boolean dim iRet as long iRet=MessageBox("你的光驱门是打开着的吗?",vbYesNo) if iRet=vbYes then isDoorOpen = true else isDoorOpen = false end if end function just fun :))
狂倒! To sunsatan(Solomon) : 只问你一句,光驱在啥状态下才允许驱动马达的?难道门开着也行?这个状态是如何确定的? 总有一个电子信号吧,难道是FSO给它的?现在只是要取得允许驱动马达的标志信号而已!(这时FSO还没生呢...)
'试试这个,在Win2000下测试没问题 Option Explicit Private 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 LongPrivate Declare Function GetDriveType Lib "kernel32" _ Alias "GetDriveTypeA" (ByVal nDrive As String) As Long Const DRIVE_CDROM = 5 Sub aaa() 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 = "M:\" '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 End Sub Sub ShowDriveList() Dim fs, d, dc, s, n, t Set fs = CreateObject("Scripting.FileSystemObject") Set dc = fs.Drives For Each d In dc Select Case d.DriveType Case 0: t = "Unknown" Case 1: t = "Removable" Case 2: t = "Fixed" Case 3: t = "Network" Case 4: t = "CD-ROM" Case 5: t = "RAM Disk" End Select s = "Drive " & d.DriveLetter & ": - " & t If d.IsReady Then s = s & vbCrLf & "Drive is Ready." Else s = s & vbCrLf & "Drive is not Ready." End If MsgBox s Next End SubPrivate Sub Command1_Click() aaa End Sub
'上面有乱码,看这个 Option Explicit Private 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 LongPrivate Declare Function GetDriveType Lib "kernel32" _ Alias "GetDriveTypeA" (ByVal nDrive As String) As Long Const DRIVE_CDROM = 5 Sub aaa() 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 = "M:\" '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 End Sub Sub ShowDriveList() Dim fs, d, dc, s, n, t Set fs = CreateObject("Scripting.FileSystemObject") Set dc = fs.Drives For Each d In dc Select Case d.DriveType Case 0: t = "Unknown" Case 1: t = "Removable" Case 2: t = "Fixed" Case 3: t = "Network" Case 4: t = "CD-ROM" Case 5: t = "RAM Disk" End Select s = "Drive " & d.DriveLetter & ": - " & t If d.IsReady Then s = s & vbCrLf & "Drive is Ready." Else s = s & vbCrLf & "Drive is not Ready." End If MsgBox s Next End SubPrivate Sub Command1_Click() aaa End Sub
不好意思,我理解错了。 这是C代码:'MCI_OPEN_PARMS lpOpen; 'MCI_STATUS_PARMS StatusParms; 'StatusParms.dwItem = MCI_STATUS_MODE; 'unsigned int wDeviceID; 'lpOpen.lpstrDeviceType = "cdaudio"; 'if(mciSendCommand(NULL,MCI_OPEN,MCI_WAIT|MCI_OPEN_TYPE|MCI_OPEN_SHAREABLE,(DWORD)&lpOpen)) '{ ' MessageBox(NULL,"光驱设备打开错误!","错误!",MB_OK); ' return 0; '} 'wDeviceID = lpOpen.wDeviceID; ' 'if(mciSendCommand(wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&StatusParms)) ' return 0; 'if(StatusParms.dwReturn == MCI_MODE_OPEN )//MCI_MODE_OPEN 门还是设备打开 '{ ' mciSendCommand(wDeviceID,MCI_SET,MCI_SET_DOOR_CLOSED,NULL); '} 'Else '{ ' mciSendCommand(wDeviceID,MCI_SET,MCI_SET_DOOR_OPEN,NULL); '} 'mciSendCommand(wDeviceID,MCI_CLOSE,NULL,NULL); 'return 0;这是Dephic 程序' program cdinout; ' uses mmSystem; ' ' Var ' MCIO : TMCI_Open_Parms; ' MCIS : TMCI_Status_Parms; ' ' begin ' ' MCIO.lpstrDeviceType := PChar(MCI_DEVTYPE_CD_AUDIO); ' if mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE or MCI_OPEN_TYPE_ID or ' MCI_OPEN_SHAREABLE, LongInt(@MCIO) )= 0 then ' begin ' MCIS.dwItem := MCI_STATUS_READY; ' mciSendCommand(MCIO.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM ' or MCI_WAIT, LongInt(@MCIS)); ' If MCIS.dwReturn <> 0 Then ' mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0) ' Else ' mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0); ' mciSendCommand(MCIO.wDeviceID, MCI_CLOSE, MCI_WAIT, 0); ' end; ' end.我改成VB后,不好使Private Const MCI_OPEN = &H803 Private Const MCI_OPEN_TYPE = &H2000& Private Const MCI_OPEN_TYPE_ID = &H1000& Private Const MCI_OPEN_SHAREABLE = &H100& Private Const MCI_STATUS_READY = &H7& Private Const MCI_STATUS = &H814 Private Const MCI_STATUS_ITEM = &H100& Private Const MCI_WAIT = &H2& Private Const MCI_SET = &H80D Private Const MCI_SET_DOOR_OPEN = &H100& Private Const MCI_SET_DOOR_CLOSED = &H200& Private Const MCI_CLOSE = &H804 Private Const MCI_DEVTYPE_CD_AUDIO = 516 Private Type MCI_OPEN_PARMS dwCallback As Long wDeviceID As Long lpstrDeviceType As String lpstrElementName As String lpstrAlias As String End TypePrivate Type MCI_STATUS_PARMS dwCallback As Long dwReturn As Long dwItem As Long dwTrack As Integer End TypePrivate Declare Function mciSendCommand Lib "winmm.dll" Alias "mciSendCommandA" (ByVal wDeviceID As Long, ByVal uMessage As Long, ByVal dwParam1 As Long, dwParam2 As Any) As Long Private Const MCI_STRING_OFFSET = 512 Private Const MCI_MODE_OPEN = (MCI_STRING_OFFSET + 18)Private Sub cmdTest_Click() Dim MCIO As MCI_OPEN_PARMS Dim MCIS As MCI_STATUS_PARMS Dim lFlags As Long MCIO.lpstrDeviceType = "cdaudio" MCIO.lpstrElementName = "M:"
lFlags = MCI_OPEN_TYPE Or MCI_OPEN_ELEMENT Or MCI_OPEN_SHAREABLE
If mciSendCommand(0, MCI_OPEN, lFlags, MCIO) = 0 Then MCIS.dwItem = MCI_STATUS_READY Call mciSendCommand(MCIO.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM Or MCI_WAIT, MCIS) MsgBox Str(MCIS.dwReturn) ' If MCIS.dwReturn <> 0 Then ' 'Call mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0) ' MsgBox "光驱门关闭" ' Else ' MsgBox "光驱门打开" ' 'Call mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0) ' 'Call mciSendCommand(MCIO.wDeviceID, MCI_CLOSE, MCI_WAIT, 0) ' End If End If end sub
If 检查门()=True Then MsgBox("门开着") Else MsgBox("门关着") End IfFunction 检查门() As Boolen '问如何编这个函数!!! '八个字!!!还不明白???还编程?! '光驱里没盘时,并不等于门一定开着(但有盘时一定是关着的)。 End Function
To sovom(谍路) & myjian(小马) : //晕.....实在是不好意思,真的是没有注意看过题!!!这回看题目了吗?咋又谈开关门啦???谁说一定要拆硬盘数磁道才知道容量? 不会看状态标签嘛!(不管是贴在盘上的,或开机后显示的,都属于状态显示)要显示光驱门的状态,难道一定要装个微动开关??? 那好吧,明天我去买一个,请你来帮我装, 装好后,那就能实现本主题了吧?——在电脑上显示光驱门的状态!:)
可怜的楼主,我怎么感觉有人是故意打岔啊,应该都能看清楼主的意思啊~~~呵呵,大家都是闲来无聊了吧~~~我赞同DemonLoveLizzy和starsoulxp的思路! 通过他的方法可以实现捕获盘近盘出的消息的。这样的话如果你的程序运行得比较早,在运行期间用户有弹出或关上光驱的动作的话,你的程序就可以及时地知道当前光驱门的状态。我下面这个程序可以捕获光驱门开关的动作: 在模块中写入:Public Const GWL_WNDPROC = (-4) Public Const WM_DEVICECHANGE As Long = &H219 Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As LongPublic lpPrevWndProc As LongFunction WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long If uMsg = WM_DEVICECHANGE Then If wParam And 4 Then MsgBox "光驱打开了!在下一次发现关闭之前都是开着的!" Else MsgBox "光驱关上了!在下一次发现打开之前都是关着的!" End If End If WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam) End Function 在窗体代码中写入: Private Sub Form_Load() lpPrevWndProc = SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf WindowProc) End SubPrivate Sub Form_Unload(Cancel As Integer) SetWindowLong Me.hwnd, GWL_WNDPROC, lpPrevWndProc End Sub 唯一的弊端就是如果软件不是一直运行的,用户没有在这期间开关光驱门,那这个方法就不起作用了。不知道还有什么高招没有。 不过我还有些“馊主意”可以作为弥补: 刚运行时,看一下光驱中有没有盘(dir之类的方法)。如果有,这可以说明光驱是关着的。 如果没有盘,就强行弹出光驱(mciSendString)。呵呵,光驱一弹出来后面就好办了。
我搞忘了多光驱的事情。我不知道VB里面怎么用指针好一些,所以只好用了这个比较笨的办法。楼主多参照starsoulxp的回复,他写得比较全面,我这个省略了很多东西,不是很准确。 模块里面的改为:Public Const GWL_WNDPROC = (-4) Public Const WM_DEVICECHANGE As Long = &H219 Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Declare Function CallWindowProc Lib "user32.dll" 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 Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, ByVal Source As Long, ByVal Length As Long)Public Type DEV_BROADCAST_VOLUME dbcv_size As Long dbcv_devicetype As Long dbcv_reserved As Long dbcv_unitmask As Long dbcv_flags As Long End TypePublic lpPrevWndProc As Long Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long If uMsg = WM_DEVICECHANGE Then Dim dbv As DEV_BROADCAST_VOLUME CopyMemory dbv, lParam, Len(dbv)
Dim i As Byte, m As Long i = 64 m = dbv.dbcv_unitmask Do While m i = i + 1 m = m \ 2 Loop
If wParam And 4 Then MsgBox Chr(i) & ":光驱打开了!" Else MsgBox Chr(i) & ":光驱关上了!" End If End If WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam) End Function
不过光驱打开或者闭合的时候,系统就会向各个进程广播一条WM_DEVICECHANGE消息,若是闭合,则
wParam是DBT_DEVICEARRIVAL,打开就是DBT_DEVICEREMOVECOMPLETE,你试试捕获这个消息的参数试试。我要出去玩,不试了。
dim iRet as long
iRet=MessageBox("你的光驱门是打开着的吗?",vbYesNo)
if iRet=vbYes then
isDoorOpen = true
else
isDoorOpen = false
end if
end function
just fun :))
即使没门的光驱,也肯定有一个部件,能感知是否有东西(类似光盘状)进来,然后就会锁定,开始驱动马达,测试是否为有效光盘。
对于普通光驱,至少能判断门有没有锁定(关上),然后才测试盘片种类。
任何光驱决不会先驱动马达,看有没有盘,再判断面板有没有锁定的,否则如果为了测试有无碟片FSO就可以办到何必如此费事
To sunsatan(Solomon) :
只问你一句,光驱在啥状态下才允许驱动马达的?难道门开着也行?这个状态是如何确定的?
总有一个电子信号吧,难道是FSO给它的?现在只是要取得允许驱动马达的标志信号而已!(这时FSO还没生呢...)
Option Explicit
Private 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 LongPrivate Declare Function GetDriveType Lib "kernel32" _
Alias "GetDriveTypeA" (ByVal nDrive As String) As Long Const DRIVE_CDROM = 5
Sub aaa() 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 = "M:\" '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
End Sub
Sub ShowDriveList()
Dim fs, d, dc, s, n, t
Set fs = CreateObject("Scripting.FileSystemObject")
Set dc = fs.Drives
For Each d In dc
Select Case d.DriveType
Case 0: t = "Unknown"
Case 1: t = "Removable"
Case 2: t = "Fixed"
Case 3: t = "Network"
Case 4: t = "CD-ROM"
Case 5: t = "RAM Disk"
End Select
s = "Drive " & d.DriveLetter & ": - " & t
If d.IsReady Then
s = s & vbCrLf & "Drive is Ready."
Else
s = s & vbCrLf & "Drive is not Ready."
End If
MsgBox s
Next
End SubPrivate Sub Command1_Click()
aaa
End Sub
Option Explicit
Private 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 LongPrivate Declare Function GetDriveType Lib "kernel32" _
Alias "GetDriveTypeA" (ByVal nDrive As String) As Long Const DRIVE_CDROM = 5
Sub aaa() 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 = "M:\" '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
End Sub
Sub ShowDriveList()
Dim fs, d, dc, s, n, t
Set fs = CreateObject("Scripting.FileSystemObject")
Set dc = fs.Drives
For Each d In dc
Select Case d.DriveType
Case 0: t = "Unknown"
Case 1: t = "Removable"
Case 2: t = "Fixed"
Case 3: t = "Network"
Case 4: t = "CD-ROM"
Case 5: t = "RAM Disk"
End Select
s = "Drive " & d.DriveLetter & ": - " & t
If d.IsReady Then
s = s & vbCrLf & "Drive is Ready."
Else
s = s & vbCrLf & "Drive is not Ready."
End If
MsgBox s
Next
End SubPrivate Sub Command1_Click()
aaa
End Sub
虽然与本主题不符,还是谢谢各位关心,继续关注!PWin98+VB5
这是C代码:'MCI_OPEN_PARMS lpOpen;
'MCI_STATUS_PARMS StatusParms;
'StatusParms.dwItem = MCI_STATUS_MODE;
'unsigned int wDeviceID;
'lpOpen.lpstrDeviceType = "cdaudio";
'if(mciSendCommand(NULL,MCI_OPEN,MCI_WAIT|MCI_OPEN_TYPE|MCI_OPEN_SHAREABLE,(DWORD)&lpOpen))
'{
' MessageBox(NULL,"光驱设备打开错误!","错误!",MB_OK);
' return 0;
'}
'wDeviceID = lpOpen.wDeviceID;
'
'if(mciSendCommand(wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&StatusParms))
' return 0;
'if(StatusParms.dwReturn == MCI_MODE_OPEN )//MCI_MODE_OPEN 门还是设备打开
'{
' mciSendCommand(wDeviceID,MCI_SET,MCI_SET_DOOR_CLOSED,NULL);
'}
'Else
'{
' mciSendCommand(wDeviceID,MCI_SET,MCI_SET_DOOR_OPEN,NULL);
'}
'mciSendCommand(wDeviceID,MCI_CLOSE,NULL,NULL);
'return 0;这是Dephic 程序' program cdinout;
' uses mmSystem;
'
' Var
' MCIO : TMCI_Open_Parms;
' MCIS : TMCI_Status_Parms;
'
' begin
'
' MCIO.lpstrDeviceType := PChar(MCI_DEVTYPE_CD_AUDIO);
' if mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE or MCI_OPEN_TYPE_ID or
' MCI_OPEN_SHAREABLE, LongInt(@MCIO) )= 0 then
' begin
' MCIS.dwItem := MCI_STATUS_READY;
' mciSendCommand(MCIO.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM
' or MCI_WAIT, LongInt(@MCIS));
' If MCIS.dwReturn <> 0 Then
' mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0)
' Else
' mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0);
' mciSendCommand(MCIO.wDeviceID, MCI_CLOSE, MCI_WAIT, 0);
' end;
' end.我改成VB后,不好使Private Const MCI_OPEN = &H803
Private Const MCI_OPEN_TYPE = &H2000&
Private Const MCI_OPEN_TYPE_ID = &H1000&
Private Const MCI_OPEN_SHAREABLE = &H100&
Private Const MCI_STATUS_READY = &H7&
Private Const MCI_STATUS = &H814
Private Const MCI_STATUS_ITEM = &H100&
Private Const MCI_WAIT = &H2&
Private Const MCI_SET = &H80D
Private Const MCI_SET_DOOR_OPEN = &H100&
Private Const MCI_SET_DOOR_CLOSED = &H200&
Private Const MCI_CLOSE = &H804
Private Const MCI_DEVTYPE_CD_AUDIO = 516
Private Type MCI_OPEN_PARMS
dwCallback As Long
wDeviceID As Long
lpstrDeviceType As String
lpstrElementName As String
lpstrAlias As String
End TypePrivate Type MCI_STATUS_PARMS
dwCallback As Long
dwReturn As Long
dwItem As Long
dwTrack As Integer
End TypePrivate Declare Function mciSendCommand Lib "winmm.dll" Alias "mciSendCommandA" (ByVal wDeviceID As Long, ByVal uMessage As Long, ByVal dwParam1 As Long, dwParam2 As Any) As Long
Private Const MCI_STRING_OFFSET = 512
Private Const MCI_MODE_OPEN = (MCI_STRING_OFFSET + 18)Private Sub cmdTest_Click()
Dim MCIO As MCI_OPEN_PARMS
Dim MCIS As MCI_STATUS_PARMS
Dim lFlags As Long MCIO.lpstrDeviceType = "cdaudio"
MCIO.lpstrElementName = "M:"
lFlags = MCI_OPEN_TYPE Or MCI_OPEN_ELEMENT Or MCI_OPEN_SHAREABLE
If mciSendCommand(0, MCI_OPEN, lFlags, MCIO) = 0 Then
MCIS.dwItem = MCI_STATUS_READY
Call mciSendCommand(MCIO.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM Or MCI_WAIT, MCIS)
MsgBox Str(MCIS.dwReturn)
' If MCIS.dwReturn <> 0 Then
' 'Call mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0)
' MsgBox "光驱门关闭"
' Else
' MsgBox "光驱门打开"
' 'Call mciSendCommand(MCIO.wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0)
' 'Call mciSendCommand(MCIO.wDeviceID, MCI_CLOSE, MCI_WAIT, 0)
' End If
End If
end sub
MsgBox("门开着")
Else
MsgBox("门关着")
End IfFunction 检查门() As Boolen
'问如何编这个函数!!!
'八个字!!!还不明白???还编程?!
'光驱里没盘时,并不等于门一定开着(但有盘时一定是关着的)。
End Function
对于这个问题,我知道的事实是:光驱内有一个专用的控制芯片,用于管理光驱的“基本功能”,如放CD,进出盒,驱动激光头进行读写等功能。由这个芯片组成的电路叫“控制/伺服电路”。而这个电路有没有对“光驱内是否有光盘”这个“信号”进行硬件上的接口性的设计,我就不知道了。
至少我从小学玩电脑到现在,共十多年了(今年我22),还没有见过有什么程序能给出“光驱内有无光盘”的提示。这样的功能,在光驱没有接IDE时,一样可以正常工作。而放CD这个功能,也是一样。进/出盒也是。只是,这些功能当中,有没有全部设计为“可编程控制”的呢?我认为,“有无光盘”这个功能应该是没有的。要不,你放一个暴花的盘进去,然后双击光盘,系统应该是提示“此光盘已损坏,无法读取”,而不是现在的“请插入光盘”!!!!
一、实现原理
Windows系统通过GDI(图形设备接口)将系统的硬件和用户可以操作的编程接口相分离,以保证系统的稳定型和安全性。当某一个设备的硬件配置发生变化时,Windows发送广播消息WM_DEVICECHANGE给相关的应用和设备驱动程序,此时在应用程序中可以截获该消息并分析其中的消息参数,先分辨当前的消息内容,然后调用不同的事件处理程序。本文中主要考虑的是光驱的弹出和送入事件,因此程序设计时只需对逻辑驱动器进行扫描,判断是哪个驱动器号发生变化即可。一般的外设(包括软、硬盘驱动器、光驱等)在Windows系统中按照逻辑上的驱动器名称进行管理,这样就屏蔽了用户和计算机硬件直接打交道。Windows中用掩码数字0代表驱动器“A”,1代表驱动器“B”,依此类推。其中每个逻辑驱动器又有0和1两种状态变化,如果驱动器一直未发生变化,则此值为0,否则置为1,一个逻辑驱动器状态可以响应多种事件,如打开、关闭、新添加、删除等事件,甚至可以响应用户自定义的事件。
本文中的程序主要是监测光驱的弹出和送入的状态改变,当应用程序启动后,弹出一个对话框,说明正在等待光驱事件的发生,此时如果将光驱弹出,应用程序会提示此时光盘驱动器已经弹出,在送入光驱之后,并且光驱中有CDROM碟片时,应用会提示光驱已经就绪。
二、程序实现
从Visual C++的IDE中的File菜单中选择New对话框,在Project属性页中选择Win32 Application,建立一个空的Win32应用程序,将StdAfx.h和StdAfx.cpp包含进来。建立一个新的对话框资源,在对话框上写上一句静态文本,“正在等待光驱事件”。下面实现监测光驱状态变化的主程序,在主程序cdchange.cpp中实现了三个函数。
第一个函数是chFirstDriveFromMask(ULONG unitmask),该函数的作用是将响应WM_DEVICECHANGE消息事件的内容(即驱动器掩码)作为输入,和系统定义的掩码相比较,从而返回发生变化事件的驱动器的逻辑名称,如“E盘”、“F盘”等。函数的源代码如下:
char chFirstDriveFromMask (ULONG unitmask)
{
char i;
for (i = 0; i < 26; ++i) //假设不会超过26个逻辑驱动器
{
if (unitmask & 0x1) //看该驱动器的状态是否发生了变化
break;
unitmask = unitmask >> 1;
}
return (i + 'A');
}
第二个函数是关键,它是对话框的事件处理函数,同时也是用来截获并处理Windows的WM_DEVICECHANGE事件。在该函数中首先声明了一个PDEV_BROADCAST_HDR类型的结构变量lpdb,该结构里存储了当WM_DEVICECHANGE消息产生时的设备事件信息,它的声明在VC98目录下面的Include目录中的dbt.h中。接着,进入事件和消息处理程序,当WM_DEVICECHANGE事件出现时,程序再判断该消息的附加消息参数以判断CDROM的事件类型。当一个设备被插入并变得可用时,系统会发送广播事件DBT_DEVICEARRIVAL,而当一个设备被除去并变得不可用时,系统会发送广播事件DBT_DEVICEREMOVECOMPLETE,根据这两种消息可以判断当前的光驱是否是开着的。处理完以上事件之后,还要检查一下光驱中是否由CDROM碟片,如有才弹出对话框表明光驱已经弹出或成功送入。同时为了防止于其他的自动识别光驱状态的应用产生冲突,本例中将暂时禁止光驱的自动播放功能。函数的源代码如下:
BOOL WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BOOL fRet = TRUE; // 返回值
//通过响应WM_DEVICECHANGE消息得到的设备事件信息结构
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
//对话框消息处理
switch (uMsg)
{
case WM_INITDIALOG:
fRet = TRUE;
break;
//对 WM_DEVICECHANGE 消息进行处理
case WM_DEVICECHANGE:
char szMsg[80]; // 对话框中要表示的字符串
switch (wParam)
{
//当一个设备变得被插入并变得可用时,
//系统会发送广播事件DBT_DEVICEARRIVAL
case DBT_DEVICEARRIVAL:
// 判断CDROM碟片是否已经插入到光驱中
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) {
PDEV_BROADCAST_VOLUME lpdbv=
(PDEV_BROADCAST_VOLUME) lpdb;
//判断是否有CDROM碟片
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
// 显示消息,获取光驱的逻辑驱动器号
wsprintf (szMsg, "驱动器 %c: 已经可用\n",
chFirstDriveFromMask(lpdbv ->dbcv_unitmask));
MessageBox (hwnd, szMsg, "光驱自动监测", MB_OK |
MB_ICONINFORMATION);
}
}
break;
//当一个设备变得被移走并变得不可用时,
//系统会发送广播事件DBT_ DEVICEREMOVECOMPLETE
case DBT_DEVICEREMOVECOMPLETE:
// 判断CDROM碟片是否从光驱中移走
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) {
PDEV_BROADCAST_VOLUME lpdbv =
(PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
//显示消息,获取光驱的逻辑驱动器号
wsprintf (szMsg, "驱动器 %c: 已经弹出\n",
chFirstDriveFromMask(lpdbv ->dbcv_unitmask));
MessageBox (hwnd, szMsg, "光驱自动监测", MB_OK
| MB_ICONINFORMATION);
}
}
break;
}
//处理其他Windows消息
case WM_COMMAND:
int wmId, wmEvent;
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDOK:
EndDialog(hwnd, 0);
break;
}
default:
fRet = FALSE;
break;
}
// 禁止光驱的AutoPlay功能
static UINT uMsgQueryCancelAutoPlay=
RegisterWindowMessage("QueryCancelAutoPlay");
if (uMsg==uMsgQueryCancelAutoPlay)
{
int n = MessageBox(hwnd, "你想禁止AutoPlay功能吗?", NULL,
MB_YESNO | MB_ICONQUESTION);
// 1代表取消 AutoPlay
// 0 t代表允许AutoPlay
SetDlgMsgResult(hwnd, uMsg, (n == IDYES) ? 1 : 0);
fRet = (n == IDYES) ? 1 : 0;
}
return(fRet);
}
第三个函数非常简单,产生一个模式对话框。代码如下:
int APIENTRY WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
//从对话框模版资源中创建一个模式对话框
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1),
NULL, DlgProc);
return 0;
}
发誓最后一次解释了,各位再不理解的话,拜托先找个小学生来解释一下题目吧。
(并非针对个人,只是实在是失望,对于编程者来说,连别人的要求都无法理解,那怎么编的出人家要的东东?)【问】决不要开关门!
解释:不好意思,原题目写了白字(惭愧),这句的意思就是俺不是想做开关光驱门的软件!也不管有无盘,
解释:光驱中有无盘,我根本不想了解,事实上也不可能全知!(鬼才知道,当光驱门开着的时候,你有没有放盘,或放杯子在光驱托盘上,要是哪个软件能做到:显示出,现在光驱中无盘,放的是亚马逊丛林什么纲什么科什么目什么属的什么食人蚁!???嗯,我出一百块买下,呵呵,当个生物鉴别器也不错^-^ )只想显示当前光驱门的状态,
解释:多光驱先免了吧,省得大家看不明白。这句的解释嘛,才是最关键的,嗯,实在想不出再白的解释了,请无法理解的朋友找个大于10岁的小朋友解释一下,或许更明白吧
(动词:显示。显示啥?光驱门!光驱门的啥?状态!啥状态?是开还是关!那盘呢?解释到饿,吃了!那现在干啥?显示,显示啥?光驱门!)如何做?
解释:唉,这也要解释?实在how do? /How to do?
原来你是学电子的,俺也喜欢呢,只是——不懂诶(惭愧)。
俺只想说:光驱凭啥驱动光头检测是否为暴花的盘?
不会是在门开着的时候就去转两圈吧?
当然啦,可以在光驱拆下门的时候,仍让它转,但也要去动个机关,模拟一下门关上吧?
呵呵,若你全拆了,只拿个马达套在盘上让它转,那无语 ^-!!至于那个感应门已关上的信号,能否传给操作系统,俺就真不知道了(知道的话还问啥?)
老兄能否帮忙看一下资料,是否系统真的无法收到这个信号?那俺也就死心了,谢谢!
To starsoulxp(星魂.NET) :
谢谢题点,只是俺老菜一个(俺也不想的,所以现在俺尽量少吃菜多吃肉 ^0^)
看不懂C的代码,能否帮忙改成VB的?先谢谢啦 :)
而打开光驱门时,光标一样是有反应的。所以,可以根据这个得出,在进/出盒时,一定是有事件发生,只是我们还不知道。
//晕.....实在是不好意思,真的是没有注意看过题!!!这回看题目了吗?咋又谈开关门啦???谁说一定要拆硬盘数磁道才知道容量?
不会看状态标签嘛!(不管是贴在盘上的,或开机后显示的,都属于状态显示)要显示光驱门的状态,难道一定要装个微动开关???
那好吧,明天我去买一个,请你来帮我装,
装好后,那就能实现本主题了吧?——在电脑上显示光驱门的状态!:)
通过他的方法可以实现捕获盘近盘出的消息的。这样的话如果你的程序运行得比较早,在运行期间用户有弹出或关上光驱的动作的话,你的程序就可以及时地知道当前光驱门的状态。我下面这个程序可以捕获光驱门开关的动作:
在模块中写入:Public Const GWL_WNDPROC = (-4)
Public Const WM_DEVICECHANGE As Long = &H219
Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As LongPublic lpPrevWndProc As LongFunction WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If uMsg = WM_DEVICECHANGE Then
If wParam And 4 Then
MsgBox "光驱打开了!在下一次发现关闭之前都是开着的!"
Else
MsgBox "光驱关上了!在下一次发现打开之前都是关着的!"
End If
End If
WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam)
End Function
在窗体代码中写入:
Private Sub Form_Load()
lpPrevWndProc = SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf WindowProc)
End SubPrivate Sub Form_Unload(Cancel As Integer)
SetWindowLong Me.hwnd, GWL_WNDPROC, lpPrevWndProc
End Sub
唯一的弊端就是如果软件不是一直运行的,用户没有在这期间开关光驱门,那这个方法就不起作用了。不知道还有什么高招没有。
不过我还有些“馊主意”可以作为弥补:
刚运行时,看一下光驱中有没有盘(dir之类的方法)。如果有,这可以说明光驱是关着的。
如果没有盘,就强行弹出光驱(mciSendString)。呵呵,光驱一弹出来后面就好办了。
模块里面的改为:Public Const GWL_WNDPROC = (-4)
Public Const WM_DEVICECHANGE As Long = &H219
Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32.dll" 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 Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, ByVal Source As Long, ByVal Length As Long)Public Type DEV_BROADCAST_VOLUME
dbcv_size As Long
dbcv_devicetype As Long
dbcv_reserved As Long
dbcv_unitmask As Long
dbcv_flags As Long
End TypePublic lpPrevWndProc As Long
Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If uMsg = WM_DEVICECHANGE Then
Dim dbv As DEV_BROADCAST_VOLUME
CopyMemory dbv, lParam, Len(dbv)
Dim i As Byte, m As Long
i = 64
m = dbv.dbcv_unitmask
Do While m
i = i + 1
m = m \ 2
Loop
If wParam And 4 Then
MsgBox Chr(i) & ":光驱打开了!"
Else
MsgBox Chr(i) & ":光驱关上了!"
End If
End If
WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam)
End Function