Asunto: Cerrar con seguridad dispositivos USB con Delphi
Estoy desarrollando una aplicación de gestión, facturación y contabilidad, he implementado una opción de copia de seguridad a lápiz de memoria (pendrive) y quisiera saber si desde mi aplicación Delphi puedo extraer con seguridad el dispositivo, simulando la opción de Windows de "Quitar hardware de forma segura".
Utilizo Microsoft Windows 7 como sistema operativo y Borland Delphi 6 como lenguaje de programación.
Publicado:
Sab May 22, 2010 7:13 pm
alonsojpd Administrador/Moderador
Registrado: Sep 16, 2003 Mensajes: 2687
Asunto: Re: Cerrar con seguridad dispositivos USB con Delphi
Anuncios
varios escribió:
Estoy desarrollando una aplicación de gestión, facturación y contabilidad, he implementado una opción de copia de seguridad a lápiz de memoria (pendrive) y quisiera saber si desde mi aplicación Delphi puedo extraer con seguridad el dispositivo, simulando la opción de Windows de "Quitar hardware de forma segura".
Utilizo Microsoft Windows 7 como sistema operativo y Borland Delphi 6 como lenguaje de programación.
Sí que es posible, a continuación te mostramos el código fuente de una de nuestras aplicaciones, que realiza justamente lo que nos indicas. Además, esta aplicación muestra los dispositivos conectados, incluso aunque ya esté abierta (mediante interrupciones):
DEV_BROADCAST_VOLUME = ^PDEV_BROADCAST_VOLUME;
PDEV_BROADCAST_VOLUME = packed record
dbcv_size : DWORD;
dbcv_devicetype : DWORD;
dbcv_reserved : DWORD;
dbcv_unitmask : DWORD;
dbcv_flags : WORD;
end;
var
C : Integer;
begin
//desconexión física
if Msg.wParam = $8004 then
begin
if DEV_BROADCAST_HDR(Msg.LParam)^.dbch_devicetype = 2 then
begin
if DEV_BROADCAST_VOLUME(Msg.LParam)^.dbcv_flags = 0 then
begin
Str(Ln(DEV_BROADCAST_VOLUME(Msg.LParam)^.dbcv_unitmask) / Ln(2) +
Ord('A'):2:0, letraVolumen);
letraVolumen := Char(StrToInt(letraVolumen));
for c := 0 to lsListaDispositivos.Count - 1 do
begin
//quitar dispositivo de la lista
volumen := lsListaDispositivos.Items.Strings[c];
if volumen[1] = letraVolumen then
begin
lsListaDispositivos.Items.Delete(c);
Break;
end;
end;
end;
end;
end;
//conexión física
if Msg.wParam = $8000 then
begin
if DEV_BROADCAST_HDR(Msg.LParam)^.dbch_devicetype = 2 then
begin
if DEV_BROADCAST_VOLUME(Msg.LParam)^.dbcv_flags = 0 then
begin
//añadir nuevo volumen a la lista
Str(Ln(DEV_BROADCAST_VOLUME(Msg.LParam)^.dbcv_unitmask) / Ln(2) +
Ord('A'):2:0, letraVolumen);
letraVolumen := Char(StrToInt(letraVolumen));
lsListaDispositivos.Items.Add(letraVolumen + ':\ -> Conectado');
end;
end;
end;
end;
function extraerDispositivoUSB (letraDispositivo : String;
intervaloTiempo : Integer = 0; numeroIntentos : Integer = 1) : Boolean;
const
//parámetros de WinIoCtl.h
FSCTL_LOCK_VOLUME = ($00000009 shl 16) or ($0000 shl 14) or (00006 shl 2) or 0;
FSCTL_DISMOUNT_VOLUME = ($00000009 shl 16) or ($0000 shl 14) or (00008 shl 2) or 0;
IOCTL_STORAGE_MEDIA_REMOVAL = ($0000002d shl 16) or ($0001 shl 14) or ($0201 shl 2) or 0;
IOCTL_STORAGE_EJECT_MEDIA = ($0000002d shl 16) or ($0001 shl 14) or ($0202 shl 2) or 0;
FSCTL_UNLOCK_VOLUME = ($00000009 shl 16) or ($0000 shl 14) or (00007 shl 2) or 0;
Type
TPREVENT_MEDIA_REMOVAL = record
PreventMediaRemoval : ByteBool;
end;
var
HandleVolume : THandle;
formatoLetraDispositivo : string;
lpBytesReturned : DWORD;
PreventRemoval : TPREVENT_MEDIA_REMOVAL;
T : Integer;
begin
letraDispositivo := Uppercase(letraDispositivo);
formatoLetraDispositivo := Format('%s:', [letraDispositivo]);
Result := False;
case GetDriveType(PChar(formatoLetraDispositivo)) of
DRIVE_REMOVABLE:
begin
//configurar el formato deseado
formatoLetraDispositivo := Format('\\.\%s:', [letraDispositivo]);
PreventRemoval.PreventMediaRemoval := False;
//creación del volumen
HandleVolume := CreateFile(PChar(formatoLetraDispositivo),
GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
//cierre del volumen
for T := 0 to numeroIntentos do
begin
if DeviceIoControl(HandleVolume, FSCTL_LOCK_VOLUME,
nil, 0, nil, 0, lpBytesReturned, nil) then
begin
//desmontar volumen
DeviceIoControl(HandleVolume, FSCTL_DISMOUNT_VOLUME,
nil, 0, nil, 0, lpBytesReturned, nil);
//control del volumen
DeviceIoControl(HandleVolume, IOCTL_STORAGE_MEDIA_REMOVAL,
@PreventRemoval, SizeOf(TPREVENT_MEDIA_REMOVAL),
nil, 0, lpBytesReturned, nil);
//retirar volumen
DeviceIoControl(HandleVolume, IOCTL_STORAGE_EJECT_MEDIA, nil,
0, nil, 0, lpBytesReturned, nil);
//liberar el volumen
Result := DeviceIoControl(HandleVolume, FSCTL_UNLOCK_VOLUME, nil,
0, nil, 0, lpBytesReturned, nil);
formatoLetraDispositivo := Format('%s:\',[letraDispositivo]);
//enviar al sistema aviso de que desmonte el dispositivo
ShChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATH,
PChar(formatoLetraDispositivo), Nil);
Break;
end
else
begin
Result := False;
Sleep(intervaloTiempo);
end;
end;
//liberar volumen
CloseHandle(HandleVolume);
end
else
Result := False;
end;
end;
Procedure listaDispositivos (dispositivos : TStrings; tipos : Integer);
var
i : integer;
bits : set of 0..25;
disco : String;
begin
//obtener nombre de los discos lógicos
integer(bits):= GetLogicalDrives;
//obtener letras si el dispositivo es removible DRIVE_REMOVABLE
for i := 0 to 25 do
begin
if i in bits then
begin
disco := Char(i + Ord('A')) + ':';
if tipos = GetDriveType(PChar(disco)) then
dispositivos.Append(Char(i + Ord('A')) + ':\ -> Conectado');
end;
end;
end;
procedure TformMenuPrincipal.FormActivate(Sender: TObject);
begin
lsListaDispositivos.Clear;
listaDispositivos(lsListaDispositivos.Items, DRIVE_REMOVABLE);
end;
procedure TformMenuPrincipal.btRetirarUSBClick(Sender: TObject);
var
i : Integer;
begin
volumen := '';
for i := 0 to lsListaDispositivos.Count - 1 do
begin
if lsListaDispositivos.Checked[i] then
begin
volumen := lsListaDispositivos.Items.Strings[i];
//retirar volúmenes seleccionados, con tres intentos
//con un intervalo de de 2000 ms cada uno
if extraerDispositivoUSB (volumen[1], 2000, 3) then
begin
MessageDlg('El dispositivo ' + volumen[1] +
' ya se puede retirar con seguridad.', mtInformation, [mbOk], 0);
lsListaDispositivos.Items.Strings[i] := volumen[1] +
':\ -> esperando ser extraído físicamente '
end
else
MessageDlg('El dispositivo ' + volumen[1] + ' no puede ser retirado.' +
chr(13) + chr(13) + 'Posible causa:' + chr(13) +
'- El dispositivo ' + volumen[1] + ' está siendo utilizado.' +
chr(13) +
'- El dispositivo ' + volumen[1] + ' ya no existe.' + chr(13) +
'- El dispositivo ' + volumen[1] + ' tiene algún problema.',
mtWarning, [mbOk], 0);
end;
end;
end;
Puede publicar nuevos temas en este foro No puede responder a temas en este foro No puede editar sus mensajes en este foro No puede borrar sus mensajes en este foro No puede votar en encuestas en este foro
Visita nuestro nuevo sitio web con programas y contenidos actualizados: Proyecto A