Безопасное извлечение флешки - Free Pascal
Формулировка задачи:
Добрый день! Помогите написать программу для безопасного извлечение определенной флешки. Спасибо!
Решение задачи: «Безопасное извлечение флешки»
textual
Листинг программы
program EjectFlesh; {$MODE OBJFPC} Uses Windows, strings; Const setupapi = 'SetupApi.dll'; GUID_DEVCLASS_DISKDRIVE: TGUID = (D1: $4D36E967; D2: $E325; D3: $11CE; D4: ($BF, $C1, $08, $00, $2B, $E1, $03, $18)); // GUID класса накопителей GUID_DEVCLASS_USB: TGUID = (D1: $36FC9E60; D2: $C465; D3: $11CF; D4: ($44, $45, $53, $54, $00, $00 , $00, $00)); // GUID класса хост-контроллера и USB хабов; Type HDEVINFO = THandle; PSP_DEVINFO_DATA = ^SP_DEVINFO_DATA; SP_DEVINFO_DATA = packed record cbSize : DWORD; ClassGuid : TGUID; DevInst : DWORD; Reserved : DWORD; end; Var q: char; hDevInfoSet: HDEVINFO; DevInfo: SP_DEVINFO_DATA; i: Integer; Parent: DWORD; VetoName: PChar; VetoNameString: String; // функции из SetupApi.dll function SetupDiGetClassDevsA(ClassGuid: PGUID; Enumerator: PChar; hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall; external setupapi; function SetupDiEnumDeviceInfo(DeviceInfoSet: HDEVINFO; MemberIndex: DWORD; DeviceInfoData: PSP_DEVINFO_DATA): boolean; stdcall; external setupapi; function SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO): boolean; stdcall; external setupapi; function CM_Get_Parent(pdnDevInst: PDWORD; dnDevInst: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Get_Device_ID_Size(pulLen: PDWORD; dnDevInst: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Get_Device_IDA(dnDevInst: DWORD; Buffer: PChar; BufferLen: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Locate_DevNodeA(pdnDevInst: PDWORD; pDeviceID: PChar; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CM_Request_Device_EjectA(dnDevInst: DWORD; pVetoType: Pointer; pszVetoName: PChar; ulNameLength: DWORD; ulFlags: DWORD): DWORD; stdcall; external setupapi; function CompareMem(p1, p2: Pointer; len: DWORD): boolean; Var i: DWORD; Begin result := false; if len = 0 then exit; for i := 0 to len-1 do if PByte(DWORD(p1) + i)^ <> PByte(DWORD(p2) + i)^ then exit; result := true; End; function IsUSBDevice(DevInst: DWORD): boolean; Var IDLen: DWORD; ID: PChar; IDString: String; Begin result := false; IDString := ''; if (CM_Get_Device_ID_Size(@IDLen, DevInst, 0) <> 0) or (IDLen = 0) then exit; inc(IDLen); ID := GetMemory(IDLen); if ID = nil then exit; if ((CM_Get_Device_IDA(DevInst, ID, IDLen, 0) <> 0) or (not (CompareMem(ID, PChar('USBSTOR'), 7)))) then begin IDString := StrPas(ID); FreeMemory(ID); exit; end; IDString := StrPas(ID); Write('Eject flash-disk?(y - yes; Any other key - no)'); ReadLn(q); if q = 'y' then result := true; FreeMemory(ID); End; BEGIN DevInfo.cbSize := sizeof(SP_DEVINFO_DATA); hDevInfoSet := SetupDiGetClassDevsA(@GUID_DEVCLASS_DISKDRIVE, nil, 0, 2); if hDevInfoSet = INVALID_HANDLE_VALUE then exit; i := 0; while (SetupDiEnumDeviceInfo(hDevInfoSet, i, @DevInfo)) do begin if IsUSBDevice(DevInfo.DevInst) then begin if CM_Get_Parent(@Parent, DevInfo.DevInst, 0) = 0 then begin VetoName := GetMemory(260); if (CM_Request_Device_EjectA(Parent, nil, VetoName, 260, 0) <> 0) then begin if (CM_Locate_DevNodeA(@Parent, VetoName, 0) <> 0) then begin FreeMemory(VetoName); continue; end; FreeMemory(VetoName); if (CM_Request_Device_EjectA(Parent, nil, nil, 0, 0) <> 0) then continue; end; VetoNameString := StrPas(VetoName); FreeMemory(VetoName); break; end; end; inc(i); end; SetupDiDestroyDeviceInfoList(hDevInfoSet); END.
Объяснение кода листинга программы
- В коде используется язык программирования Free Pascal.
- Задача программы - безопасное извлечение флешки.
- В коде используются следующие константы:
- GUID_DEVCLASS_DISKDRIVE: GUID класса накопителей.
- GUID_DEVCLASS_USB: GUID класса хост-контроллера и USB хабов.
- Типы данных, используемые в коде:
- HDEVINFO: THandle.
- PSP_DEVINFO_DATA: ^SP_DEVINFO_DATA.
- SP_DEVINFO_DATA: packed record.
- Переменные, используемые в коде:
- q: char.
- hDevInfoSet: HDEVINFO.
- DevInfo: SP_DEVINFO_DATA.
- i: Integer.
- Parent: DWORD.
- VetoName: PChar.
- VetoNameString: String.
- В коде используются функции из SetupApi.dll:
- SetupDiGetClassDevsA.
- SetupDiEnumDeviceInfo.
- SetupDiDestroyDeviceInfoList.
- CM_Get_Parent.
- CM_Get_Device_ID_Size.
- CM_Get_Device_IDA.
- CM_Locate_DevNodeA.
- CM_Request_Device_EjectA.
- В функции CompareMem сравниваются две памяти, начиная с указанных адресов и длиной в указанное количество байт.
- Функция IsUSBDevice проверяет, является ли устройство USB-накопителем.
- В основном цикле программы происходит перебор всех устройств выбранного класса.
- Если устройство является USB-накопителем, то выполняется запрос на безопасное извлечение устройства.
- Если устройство не может быть безопасно извлечено, то программа продолжает работу до тех пор, пока не будет получен другой ввод пользователя.
- Ввод пользователя запрашивается с помощью функции ReadLn.
- Если пользователь вводит 'y', то выполняется запрос на безопасное извлечение устройства.
- Если пользователь вводит любой другой символ, то запрос на безопасное извлечение устройства не выполняется.
- В конце программы выполняется функция SetupDiDestroyDeviceInfoList для освобождения ресурсов.