9X下查询一个逻辑驱动器是否可以被安全断开(RING0)
作者:陆麟
转载请征得作者同意.
2000.10.21


有时候我们需要删除一个盘符.这时,我们需要查询是否该盘可以断开联接.查询断开联接的函数乃是IFS的分内事.但是该函数在DDK文档中确明确告知开发者们,该函数不可以被使用.我们先看一下该函数在DDK中的描述:
QueryVolumeRemoval
QueryVolumeRemoval(
 unsigned int drive
 )
 
This service is called by the IOS to notify the IFS manager of the pending removal of a plug-and-play drive. This service should not be called by other VxDs directly. VxDs should interface with the IOS and let the IOS do the notification to the IFS manager. This service calls IOS_Requestor_Service with IRS_QUERY_VOLUME_LOCK, to obtain the bitmap of drive letters associated with the volume. The member IRS_q_v_l_designtr contains the logical drive number 0=A: etc. Next, QueryVolumeRemoval tests for any open file handles (except those handles opened as type FIND_CHANGE_NOTIFY) on any of the drive letters (in other words, partitions) associated with the volume.

This service is called in the following places:

ISP_Query_Remove
CONFIG_START (sets CR_NEED_RESTART if any open files on RMM volumes)
CONFIGMG_QueryRemoveSubtree

drive
Supplies the 0-based logical drive number of the new device.
Returns 0 if the query was successful. Returns a non-zero value if the query was failed.
当然,我们既然需要断开一个盘,必定需要查询是否可以安全断开,因为核心的问题乃是不使已打开的文件受损,所以当盘上有文件打开,就绝对不要断开联接.查询仍然需要用到上述函数.下面就给出接口.大家可要仔细看,因为在发出该查询之前,的确有小小的要求.就是要发出一个查询广播.

BeginProc Query_remove_logical_DCB
;
; (ebx) = logical unit number
;
   SaveReg <edi, edx>
   xor edi, edi   ; not MEDIA
   mov edx, CM_BROADCAST_QUERY  ; query
   mov eax, DBT_DEVICEQUERYREMOVE ; set message
   call send_shell_broadcast ; send message
   RestoreReg <edx, edi>
   Cmp eax, CR_QUERY_VETOED
   je query_failed   ; if error, jump
;
; Query the ifsmgr
;
   push edx
   mov eax, ebx
   push eax
   VxDCall QueryVolumeRemoval  ; ask Mr. IFSMGR
   add esp, 4
   pop edx    ; restore (edx)

   or eax, eax   ; error?
   jnz query_failed  ; if so, jump
query_good:
   clc
   ret

query_failed:
   stc
   ret
EndProc Query_remove_logical_DCB

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; send_shell_broadcast
;
; Routine sends shell system message with appropriate parameters
;
;       Entry: edx = QUERY flag
;        eax = message type
;        ebx = logical unit number being removed
;        edi NZ => media, not device
;
;       Exit: eax is CR_QUERY_VETOED if failure, succeed otherwise
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BeginProc send_shell_broadcast, esp

LocalVar Components, dword
LocalVar pBroadcastHeader, <size _DEV_BROADCAST_VOLUME>

 EnterProc
 SaveReg <edx, ecx>

 ;
 ; assemble the broadcast packet
 ;

 lea ecx, pBroadcastHeader
 mov [ecx].dbcv_size, size _DEV_BROADCAST_VOLUME
 mov [ecx].dbcv_devicetype, DBT_DEVTYP_VOLUME
 mov [ecx].dbcv_unitmask, 0  ;
;; AssertDCB <esi>
;; movzx ebx, [esi].DCB_drive_lttr_equiv ; set unit # bit in mask
ifdef DEBUG
 cmp ebx, MAX_LOGICAL_DRIVES
 DEBUG_OUTa "IOS: Invalid logical unit."
endif

 bts [ecx].dbcv_unitmask, ebx ;
 mov [ecx].dbcv_flags, 0  ; zero flags
 
 ;
 ; if media only, so indicate
 ;

 or edi, edi   ; media?
 jz IOS_ssb_set_components  ; if so, jump

 SetFlag [ecx].dbcv_flags, DBTF_MEDIA ; set media flag

IOS_ssb_set_components:
 VxdCall _CONFIGMG_Broadcast_Device_Change_Message <eax, ecx, edx>

 RestoreReg <ecx, edx>
 LeaveProc
 Return

EndProc send_shell_broadcast