用什么办法,调用什么函数,可以实现让windows系统的光驱停用,效果和在设备管理器中让某个设备停用一样,并且可以恢复。有多个光驱可以让多个光驱都停用。
找了好多资料都是让光驱打开或关闭的,或者判断是否正常等,没有发现如何禁用(停用)某个设备的API,也不知道和注册表有没有关系,
哪位大虾知道请指点迷经!!!

解决方案 »

  1.   

    我觉得可以通过修改注册表实现:
    HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer 
    在右边的窗口中创建一个DWORD值:“NoDrives”,其值跟对应的盘符有关,如A盘就是1,B盘就是2,C盘就是4,....假如光驱是G盘,那就是40(16进制)
    至于怎么在程序里修改注册表,以前的帖子很多...
      

  2.   

    //只工作在win9x下,对nt无效
    type 
    TRegDWord = packed record 
    case Integer of 
    0 : (Lo,Hi : Word); 
    1 : (X : DWord); 
    end; TDevIoCtl_Reg = packed record 
    Reg_BX : DWord; 
    Reg_DX : DWord; 
    Reg_CX : DWord; 
    Reg_AX : DWord; 
    Reg_DI : DWord; 
    Reg_SI : DWord; 
    Reg_Flags : DWord; 
    end; TParamBlock = packed record 
    PB_Operation : Byte; 
    PB_NumLocks : Byte; 
    end; const 
    VWin32_DIOC_DOS_IoCtl = 1; // interrupt 21h function DriveCharToNum(Drivechar : Char) : Word; 
    begin 
    DriveChar:=Upcase(DriveChar); 
    Result:= Ord(DriveChar)-Ord('A')+1; 
    end; function AccessDevice(Var Reg : TDevIoCtl_Reg) : Integer; 
    var 
    DevIoHandle : THandle; 
    BytesReturned : DWord; 
    Res : Boolean; 
    begin 
    Result:=-1; 
    Reg.Reg_Flags:=$0001; 
    DevIoHandle := 
    CreateFile('\\.\vwin32',0,0,nil,0,File_Flag_Delete_On_Close,0); 
    if DevIoHandle <> Invalid_Handle_Value then begin 
    Res := 
    DeviceIoControl(DevIoHandle,VWin32_DIOC_DOS_IoCtl,@Reg,SizeOf(Reg),@Reg,SizeOf(Reg),BytesReturned,nil); if (Res and ((Reg.Reg_Flags and $0001) = 0)) Then Result:=0 
    else Result:=Reg.Reg_AX; 
    CloseHandle(DevIoHandle); 
    end; 
    end; function DriveEject(DriveChar : Char) : Integer; 
    Var 
    Reg : TDevIoCtl_Reg; 
    begin 
    with Reg do begin 
    Reg_AX := $440d; 
    Reg_CX := $0849; 
    Reg_BX := DriveCharToNum(Drivechar); 
    Reg_Flags := $0001; 
    end; 
    Result:=AccessDevice(Reg); 
    end; function DriveLock(DriveChar : Char) : Integer; 
    Var 
    Reg : TDevIoCtl_Reg; 
    Param : TParamBlock; 
    begin 
    With Param DO begin 
    PB_Operation:=0; 
    PB_NumLocks :=0; 
    end; 
    with Reg do begin 
    Reg_AX := $440d; 
    Reg_BX := DriveCharToNum(Drivechar); 
    Reg_CX := $0848; 
    Reg_DX := Integer(@Param); 
    end; 
    Result:=AccessDevice(Reg); 
    end; 
    /////////////////////////////////////////
    //对也nt有效
    HANDLE h=CreateFile("\\\\.\\E:",GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
    if(h==INVALID_HANDLE_VALUE)
      RaiseLastWin32Error();DWORD n;
    PREVENT_MEDIA_REMOVAL s={true};
    //要是开锁
    //PREVENT_MEDIA_REMOVAL s={false};
    if(!DeviceIoControl(h,IOCTL_STORAGE_MEDIA_REMOVAL,&s,sizeof s,NULL,0,&n,NULL))
      RaiseLastWin32Error();
    CloseHandle(h);
    ///////////////////////////////////////
    unit eLanCDRom;
      

  3.   

    { You are free to use, modify and distribute this code }
    { as you like. But I ask you to send me a copy of new  }
    { versions. And please give me credit when you use     }
    { parts of my code in other components or applications.}{ ==================================================== }
    { Properties, Methods and Events :                               }
    { ---------------------------------------------------- }
    { DrvName
      MonitorState
      Close
      Eject
      StartMonitor
      EndMonitor
      Lock
      StartOnMonitor
      OnDiscArrive
      OnDiscRemove{ ---------------------------------------------------- }
    interface
    uses
      MMSystem, Classes, Messages, Controls, SysUtils, Windows,
      WinProcs, Forms;const
       DBT_DeviceArrival       =32768;
       DBT_DeviceRemoveComplete=32772;
       DBT_DEVTYP_OEM          =1;    //OEM- or IHV-defined device type
       DBT_DEVTYP_VOLUME       =2;    //Logical volume.
       DBT_DEVTYP_PORT         =3;    //Port device (serial or parallel)
       DBTF_MEDIA              =1;type
      DEVIOCTL_REGISTERS = packed record
        reg_EBX   : DWORD;
        reg_EDX   : DWORD;
        reg_ECX   : DWORD;
        reg_EAX   : DWORD;
        reg_EDI   : DWORD;
        reg_ESI   : DWORD;
        reg_Flags : DWORD;
      end;
      PDEVIOCTL_REGISTERS = ^DEVIOCTL_REGISTERS;{  MID = packed record //Interrupt 21h Function 440Dh Minor Code 66h
        midInfoLevel : WORD  ;
        midSerialNum : DWORD ;
        midVolLabel : array[0..10] of byte;
        midFileSysType: array[0..8] of byte;
      end;
      PMID = ^ MID;}  PARAMBLOCK = packed record
        Operation : WORD;     //Interrupt 21h Function 440Dh Minor Code 48h
        NumLocks  : WORD;
      end;const
      WIN95_IOCTL_DEV = '\\.\vwin32';
      VWIN32_DIOC_DOS_IOCTL  = 1;Type
       TCDRomAct  = (eEject, eClose);
       TMonitorState = (eMonitorOn, eMonitorOff);   TDEV_BROADCAST_VOLUME = record
          dbcv_Size      :Byte ;
          dbcv_DeviceType:Integer ;
          dbcv_Reserved  :Integer ;
          dbcv_UnitMask  :Integer ;
          dbcv_Flags     :Smallint ;
       end;
       PDEV_BROADCAST_VOLUME =^TDEV_BROADCAST_VOLUME;   TCDNotifyEvent = procedure(Sender: TObject;Drv:String) of object;   TeLanCDRomMonitor = Class(TComponent)
       private
          MyOwner        : TForm;
          MyOwnerHandle  : THandle;
          fDrvName       : String;
          fOnDiscArrive  : TCDNotifyEvent;
          fOnDiscRemove  : TCDNotifyEvent;
          fMonitorState  : TMonitorState;
          fStartOnMonitor: Boolean;
          fLocked        : Boolean;
          //fP             : PDEV_BROADCAST_VOLUME;
          function   GetDrvName(fDrvMask:Integer):String;
          procedure  CDRomAction(Action:TCDRomAct);
          procedure  SetStartOnMonitor(const Value: Boolean);
          procedure  DoLockCDRom(const fLock:Boolean; const Drv:String);
       protected
          OldWndProc : TFarProc;
          NewWndProc : Pointer;
          procedure    HookWin;
          procedure    UnhookWin;
          procedure    HookWndProc(var AMsg: TMessage);
       public
          procedure   Eject;
          procedure   Close;
          procedure   Lock; overload;
          procedure   Lock(const DrvName:Char);overload;
          procedure   Unlock;overload;
          procedure   Unlock(const DrvName:Char);overload;
          procedure   StartMonitor;
          procedure   EndMonitor;
          property    MonitorState :TMonitorState read fMonitorState;
          property    DrvName : String read FDrvName;
          constructor Create(AOwner:tComponent);Override;
          destructor  Destroy;Override;
          procedure   Loaded;override;
       published
          property    OnDiscArrive:TCDNotifyEvent read fOnDiscArrive Write fOnDiscArrive;
          property    OnDiscRemove:TCDNotifyEvent read fOnDiscRemove write fOnDiscRemove;
          property    StartOnMonitor:Boolean  read FStartOnMonitor write SetStartOnMonitor default True;
          property    Locked:boolean read fLocked;
       end;   procedure Register;implementationprocedure Register;
    begin
      RegisterComponents('eLan Soft',[TeLanCDRomMonitor]);
    end;{ TeLanCDRom }procedure TeLanCDRomMonitor.CDRomAction(Action: TCDRomAct);
    var
       MCIDevice:TMCI_Open_Parms;
    begin
       MCIDevice.lpstrDeviceType :='CDAudio';
       mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE ,Integer(@MCIDevice ));
       case Action of
            eEject: mciSendCommand(MCIDevice.wDeviceID,MCI_SET, MCI_SET_DOOR_OPEN ,0);
            eClose: mciSendCommand(MCIDevice.wDeviceID,MCI_SET, MCI_SET_DOOR_CLOSED ,0);
       end;
       mciSendCommand(MCIDevice.wDeviceID,MCI_CLOSE,0,0);
    end;procedure TeLanCDRomMonitor.Close;
    begin
       CDRomAction(eClose);
    end;procedure TeLanCDRomMonitor.Eject;
    begin
       CDRomAction(eEject);
    end;
      

  4.   

    constructor TeLanCDRomMonitor.Create(AOwner: tComponent);
    var I:Integer;
    begin
       for I:=0 to AOwner.ComponentCount -1 do
         if AOwner.Components[I] is Self.ClassType then
           raise Exception.Create(
             Self.ClassName + ' component Duplicated');   inherited Create(aOwner);
       with AOwner as TForm do
       begin
         MyOwner := TForm(AOwner);  { My pointer to my owner form }
         MyOwnerHandle := MyOwner.Handle;
         //New(fP);
         FStartOnMonitor :=true;
       end;  fLocked:=False;
    end;destructor TeLanCDRomMonitor.Destroy;
    begin
      if fLocked then Unlock;
      if fMonitorState = eMonitorOn then UnhookWin;
      //if Assigned(fP) then Dispose(fP);
      inherited Destroy;  {Call default processing.}
    end;procedure TeLanCDRomMonitor.Loaded;
    begin
      if (fStartOnMonitor) and not (csDesigning in MyOwner.ComponentState) then
      begin
        HookWin;
        fMonitorState :=eMonitorOn;
      end
      else
        fMonitorState :=eMonitorOff;end;procedure TeLanCDRomMonitor.EndMonitor;
    begin
       if fMonitorState = eMonitorOn then
       begin
          UnhookWin;
          fMonitorState := eMonitorOff;
       end;
    end;procedure TeLanCDRomMonitor.StartMonitor;
    begin
       if fMonitorState = eMonitorOff then
       begin
          HookWin;
          fMonitorState :=eMonitorOn;
       end;
    end;function TeLanCDRomMonitor.GetDrvName(fDrvMask: Integer): String;{ 用于将 TDEV_BROADCAST_VOLUME 结构的 dbcv_unitmask 成员}
    { 掩码转换成 000001 格式的字符串,按顺序分别代表 A、B、 }
    { D、… 驱动器,其中 1 表示该对应的驱动器发生变化。     }
    { 在弹出或关闭光驱时返回光驱所在的盘符                  }
    { ----------------------------------------------------- }
    var
      TemStr:string;
      iPos  :integer;
    begin
      //MessageBox(0,pchar(IntToStr(fdrvmask)),'',mb_OK);
      while fDrvMask>1 do
      begin
        TemStr   := TemStr+IntToStr(fDrvMask mod 2);
        fDrvMask := fDrvMask div 2;
      end;
      TemStr := TemStr+IntToStr(fDrvMask);
      { 找到第一个 1 出现的位置 }
      iPos   := Integer(StrPos(PChar(TemStr),'1')) - Integer(Pchar(TemStr));
      iPos   := iPos+65;           {A 的ASCII值为65}
      Result := Char(iPos)+':\';
    end;procedure TeLanCDRomMonitor.SetStartOnMonitor(const Value: Boolean);
    begin
      //if (csDesigning in MyOwner.ComponentState) then
      FStartOnMonitor := Value;
    end;procedure TeLanCDRomMonitor.HookWin;
    begin
      OldWndProc := TFarProc(GetWindowLong(MyOwnerHandle, GWL_WNDPROC));
      NewWndProc := MakeObjectInstance(HookWndProc);
      SetWindowLong(MyOwnerHandle, GWL_WNDPROC, LongInt(NewWndProc));
    end;  { HookWin }procedure TeLanCDRomMonitor.HookWndProc(var AMsg: TMessage);
    var fP : PDEV_BROADCAST_VOLUME;
    begin
       New(fP);
       try
       if AMsg.Msg = WM_DeviceChange then
       begin
          if (AMsg.LParam <> 0) then
          begin
            fP:=PDEV_BROADCAST_VOLUME(AMsg.LParam);      case AMsg.WParam of
             DBT_DeviceArrival :
             begin
             if (fP.dbcv_DeviceType = dbt_DEVTYP_VOLUME) and
                (Assigned(fOnDiscArrive)) then
                begin
                  fDrvName :=GetDrvName(fP.dbcv_UnitMask);
                  fOnDiscArrive(self,fDrvName);
                end;
             end;         DBT_DeviceRemoveComplete:
             begin
             if (fP.dbcv_DeviceType = dbt_DEVTYP_VOLUME) and
                (Assigned(fOnDiscRemove)) then
                begin
                  fDrvName :=GetDrvName(fP.dbcv_UnitMask);
                  fOnDiscRemove(self,fDrvName);
                end;
             end;
          end;
          end;
       end;
       finally
         fP:=nil;
         Dispose(fP);
       end;
       AMsg.Result := CallWindowProc(OldWndProc,MyOwnerHandle, AMsg.Msg, AMsg.wParam, AMsg.lParam);
    end;procedure TeLanCDRomMonitor.UnhookWin;
    begin
      if Assigned(NewWndProc) then
      begin
        SetWindowLong(MyOwnerHandle, GWL_WNDPROC, LongInt(OldWndProc));
        FreeObjectInstance(NewWndProc);
        NewWndProc := nil;
      end;
    end;  { UnHookWin }procedure TeLanCDRomMonitor.Lock;
    var DrvName : Char;
    begin
      if fLocked then Exit;
      DrvName:='a';
      repeat
        if GetDriveType(pchar(drvname+':\')) = DRIVE_CDROM then
          DoLockCDRom(True,DrvName);
        Inc(DrvName);
      until DrvName = 'z';
    end;procedure TeLanCDRomMonitor.Lock(const DrvName: Char);
    begin
      if fLocked then Exit;
      DoLockCDRom(True,DrvName);
    end;procedure TeLanCDRomMonitor.Unlock;
    var DrvName : Char;
    begin
      if not fLocked then Exit;
      DrvName:='a';
      repeat
        if GetDriveType(pchar(drvname+':\')) = DRIVE_CDROM then
          DoLockCDRom(FAlse,DrvName);
        Inc(DrvName);
      until DrvName = 'z';
    end;procedure TeLanCDRomMonitor.Unlock(const DrvName: Char);
    begin
      if not fLocked then Exit;
      DoLockCDRom(FAlse,DrvName);
    end;procedure TeLanCDRomMonitor.DoLockCDRom(const fLock: Boolean;
      const Drv: String);  function DoIOCTL(Reg : DEVIOCTL_REGISTERS):BOOL;
    var
      hDevice : THandle;
      fResult : BOOL;
      cb      : DWORD ;
    begin
      Result:=False;
      hDevice :=0;
      Reg.reg_Flags := $8000; // assume error (carry flag set)
      try
      hDevice := CreateFile('\\.\vwin32',
                   GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
                   nil, OPEN_EXISTING,
                   FILE_ATTRIBUTE_NORMAL, 0);
      if hDevice = 0 then
        Exit
      else
      begin
        fResult := DeviceIoControl(hDevice,
                                   VWIN32_DIOC_DOS_IOCTL,
                                   @reg, sizeof(reg),
                                   @reg, sizeof(reg), cb, nil);
        if not fResult then Exit;
        Result:= TRUE;
      end;
      finally
        CloseHandle(hDevice);
      end;
    end;var
      reg : DEVIOCTL_REGISTERS;
      ParamB : PARAMBLOCK;
    begin
      if fLock then ParamB.Operation :=0
         else ParamB.Operation :=1;  reg.reg_EAX := $440D;      // IOCTL for block devices
      reg.reg_EBX := Integer(LowerCase(Drv)) - Integer('a') + 1;     // zero-based drive ID
      reg.reg_ECX := $0848;      // Get LockStatus
      reg.reg_EDX := DWORD(@ParamB); // receives media ID info
      DoIOCTL(reg);
      fLocked :=not fLocked;
    end;end.
      

  5.   

    这种方法机器不重启好像不可以吧,我试了一下,没有什么效果,有没有什么编程序的方法,做一个可执行文件,点击 按钮 后马上就让光驱消失(停用),再点一个按钮,光驱又恢复工作。效果最好能像硬件设备管理器中,点到光驱上,然后右键--停用。
    有没有什么法子,对硬件IDE口控制的??
    我想在2000和98下都能用的。谢谢楼上的兄台 费心了!!