unit UnidadMenuPrincipal;
{$R WinXP.res}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Forms,
Dialogs, StdCtrls, ShlObj, Controls, CheckLst, ExtCtrls, Buttons,
shellapi, ThemeMgr;
type
TformMenuPrincipal = class(TForm)
lsListaDispositivos: TCheckListBox;
Label1: TLabel;
LWEB: TLabel;
ThemeManager1: TThemeManager;
btRetirarUSB: TBitBtn;
btSalir: TBitBtn;
procedure FormActivate(Sender: TObject);
procedure btRetirarUSBClick(Sender: TObject);
procedure LWEBClick(Sender: TObject);
procedure btSalirClick(Sender: TObject);
private
Procedure estadoConexionDispositivo (var Msg: TMessage); Message $0219;
public
end;
var
vRetirarDispositivo : TformMenuPrincipal;
letraVolumen, volumen : string;
implementation
{$R *.dfm}
Procedure TformMenuPrincipal.estadoConexionDispositivo (var Msg: TMessage);
//Dbt.h
Type
DEV_BROADCAST_HDR = ^PDEV_BROADCAST_HDR;
PDEV_BROADCAST_HDR = packed record
dbch_size : DWORD;
dbch_devicetype : DWORD;
dbch_reserved : DWORD;
end;
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;
procedure TformMenuPrincipal.LWEBClick(Sender: TObject);
begin
ShellExecute(Handle, Nil, PChar('[url=http://www.ajpdsoft.com]http://www.ajpdsoft.com[/url]'),
Nil, Nil, SW_SHOWNORMAL);
end;
procedure TformMenuPrincipal.btSalirClick(Sender: TObject);
begin
close;
end;
end.