Обнаружить съемный диск (например, USB-накопитель) C / C ++ - PullRequest
7 голосов
/ 02 февраля 2010

Как я могу определить, когда съемный диск подключен к системе? Как получить путь монтирования (для Linux) и букву диска (для windows)?

РЕДАКТИРОВАТЬ: Есть ли способ обнаружить подключенные в настоящее время устройства?

Ответы [ 2 ]

4 голосов
/ 02 февраля 2010

Для Windows API RegisterDeviceNotification сообщит вам, когда будет добавлено USB-устройство.Информация о томе приведена в структуре DEV_BROADCAST_VOLUME .dbcv_unitmask дает букву диска.

1 голос
/ 02 февраля 2010

Вы можете получать уведомления об изменениях (для добавленных / удаленных дисков) из оболочки. Вы можете использовать этот код Delphi для использования в качестве документации:

unit UnitChangeNotify;

interface

uses
    Windows, Messages, SysUtils, Classes, ShlObj, Types;

type
    SHChangeNotifyEntry = record
        pidlPath      : PItemIDList;
        bWatchSubtree : Boolean;
    end;

    TChangeEventType = (
       cnAssocchanged,
       cnAttributes,
       cnCreate,
       cnDelete,
       cnDriveAdd,
       cnDriveAddGui,
       cnDriveRemoved,
       cnMediaInserted,
       cnMediaRemoved,
       cnMkdir,
       cnNetShare,
       cnNetUnshare,
       cnRenameFolder,
       cnRenameItem,
       cnRmdir,
       cnServerDisconnect,
       cnUpdateDir,
       cnUpdateImage,
       cnUpdateItem );

    TChangeNotifyEvent = procedure( Sender: TObject; Event: TChangeEventType; const Paths: TStringDynArray ) of object;

    TChangeNotify = class( TComponent )
    private
        FHWnd:             HWND;
        FRegID:            THandle;
        FEntry:            SHChangeNotifyEntry;
        FOnChange:         TChangeNotifyEvent;
        function    GetActive         (): Boolean;
        procedure   SetActive         ( const Value: Boolean );
        procedure   WndProc           ( var Msg: TMessage );
        procedure   DoEvent           ( Event: TChangeEventType; const Paths: TStringDynArray ); virtual;
    public
        constructor Create            ( Aowner: TComponent ); override;
        destructor  Destroy;          override;
        property    Active:           Boolean            read GetActive write SetActive;
        property    OnChange:         TChangeNotifyEvent read FOnChange write FOnChange;
    end;

const
    SHCNF_ACCEPT_INTERRUPTS      = $0001;
    SHCNF_ACCEPT_NON_INTERRUPTS  = $0002;
    SHCNF_NO_PROXY               = $8000;

function SHChangeNotifyRegister(   hWnd: HWND; fSources: Integer; wEventMask: DWORD; uMsg: UINT; cItems: integer; const Items: SHChangeNotifyEntry ): THandle; stdcall;
function SHChangeNotifyDeregister( hRegID: THandle ) : BOOL; stdcall;
function SHILCreateFromPath(       Path: Pointer; PIDL: PItemIDList; var Attributes: ULONG ): HResult; stdcall;

implementation

const Shell32DLL = 'shell32.dll';

function SHChangeNotifyRegister;   external Shell32DLL index 2;
function SHChangeNotifyDeregister; external Shell32DLL index 4;
function SHILCreateFromPath;       external Shell32DLL index 28;

{ TChangeNotify }

constructor TChangeNotify.Create( Aowner: TComponent );
begin
    inherited Create( AOwner );
end;

destructor TChangeNotify.Destroy;
begin
    Active := False;
    inherited Destroy;
end;

procedure TChangeNotify.DoEvent( Event: TChangeEventType; const Paths: TStringDynArray );
begin
    if Assigned( FOnChange ) then FOnChange( Self, Event, Paths );
end;

function TChangeNotify.GetActive(): Boolean;
begin
    Result := FHWnd <> 0;
end;

procedure TChangeNotify.SetActive( const Value: Boolean );
begin
    if Value = GetActive() then Exit;
    if Value then begin
        FHWnd := AllocateHWnd( WndProc );
        FEntry.pidlPath      := nil;
        FEntry.bWatchSubtree := True;
        FRegID := SHChangeNotifyRegister( FHWnd, SHCNF_ACCEPT_INTERRUPTS or SHCNF_ACCEPT_NON_INTERRUPTS,
                                          SHCNE_ALLEVENTS, WM_USER, 1, FEntry );
        if FRegID = 0 then begin
            DeallocateHWnd( FHWnd );
            FHWnd := 0;
            RaiseLastOSError();
        end;
    end else begin
        SHChangeNotifyDeregister( FRegID );
        FRegID := 0;
        DeallocateHWnd( FHWnd );
        FHWnd := 0;
    end;
end;

procedure TChangeNotify.WndProc( var Msg: TMessage );
type
    PPITEMIDLIST = ^PITEMIDLIST;
var
    Event: TChangeEventType;
    i:     Integer;
    Paths: TStringDynArray;
    P:     PPITEMIDLIST;
const
    EventBits: array [ TChangeEventType ] of DWORD = (
       SHCNE_ASSOCCHANGED,
       SHCNE_ATTRIBUTES,
       SHCNE_CREATE,
       SHCNE_DELETE,
       SHCNE_DRIVEADD,
       SHCNE_DRIVEADDGUI,
       SHCNE_DRIVEREMOVED,
       SHCNE_MEDIAINSERTED,
       SHCNE_MEDIAREMOVED,
       SHCNE_MKDIR,
       SHCNE_NETSHARE,
       SHCNE_NETUNSHARE,
       SHCNE_RENAMEFOLDER,
       SHCNE_RENAMEITEM,
       SHCNE_RMDIR,
       SHCNE_SERVERDISCONNECT,
       SHCNE_UPDATEDIR,
       SHCNE_UPDATEIMAGE,
       SHCNE_UPDATEITEM );
    EventPIDLCount: array [ TChangeEventType ] of Integer = (
       2,
       1,
       1,
       1,
       1,
       1,
       1,
       1,
       1,
       1,
       1,
       1,
       2,
       2,
       1,
       1,
       1,
       1,
       1 );
begin
    case Msg.Msg of
        WM_USER: begin
            // lParam = eventmask
            // wParam = array of PIDLs with
            for Event := Low( Event ) to High( Event ) do begin
                if EventBits[ Event ] and msg.LParam = EventBits[ Event ] then begin
                    SetLength( Paths, EventPIDLCount[ Event ] );
                    P := PPITEMIDLIST( Msg.WParam );
                    for i := 0 to High( Paths ) do begin
                        SetLength( Paths[ i ], MAX_PATH );
                        if not SHGetPathFromIDList( P^, PChar( Paths[ i ] ) ) then Paths[ i ] := '' else Paths[ i ] := PChar( Paths[ i ] );
                        Inc( P );
                    end;
                    DoEvent( Event, Paths );
                    Break;
                end;
            end;
        end;
    end;
    DefaultHandler( Msg );
end;

end.
...