Флешки під контролем Дельфіна

Вже кілька разів до мене на пошту зверталися відвідувачі нашого сайту з проханням пояснити: «А як можна встановити той факт, коли у ПК вставили флешку?». Зазвичай, у відповіді я посилав того, хто звернувся (ні, не туди куди ти міг подумати?) в MSDN. Справа в тому, що переді мною ще жодного разу не вставала така задача, тобто. реальної практики був. А за її відсутності я рідко беруся писати цілі вихідні листи поштою. Краще вибрати час і написати невелику статтю і охопити більшу аудиторію, ніж нескінченно пересилати листа з відповіддю.

До написання статті я почав. Алгоритм визначення установки флешки я реалізував за допомогою спеціального класу DriveDetector. Користуватись цим класом одне задоволення. Біда в тому, що клас є суто для .NET мов, а значить, старий добрий Delphi курить осторонь. З такою несправедливістю я погодитися не міг, тому вирішив щоб щось не стало розібратися у всіх тонкощах цього сишарпного класу і зробити щось подібне для Delphi.

Windows API – усьому голова

Навіть не встигнувши зазирнути у вихідний код класу DriveDetector я знав, що в його основі лежить не що інше як банальний виклик відповідних WinAPI функцій. Не гаючись не секунди, я запряг вогненну лисицю і поскакав у чарівну долину MSDN. У цьому священному місці є дивовижна книга з описом усіх таємниць славного царства Windows. Діставшись до місця, я скомандував місцевій пошуковій пошукачці пару ключових слів і через кілька секунд вона принесла мені красиво оформлений сувій з результатами пошуку. Буквально перший запис у цьому священному писанні був саме тим, що потрібно, для вирішення мого завдання.

Читаючи священні письмена

Трохи почитавши знайдені сторінки, я зрозумів, що для виявленнямоменту підключення нового обладнання (чи то флещка чи ще що), мені необхідно реалізувати обробку повідомлення WM_DEVICECHANGE. Якщо ти працюєш з Delphi не перший день, то вже маєш знати про порядок обробки довільних повідомлень Windows, а якщо ні, то не сіпайся і читай далі.

Перейти в розділ private класу твоєї форми та оголоси нову процедуру:

Procedure WindowProc (var Msg: TMessage); message WM_DEVICECHANGE; stdcall;

Виклик цієї процедури відбуватиметься щоразу при отриманні головним вікном програми повідомлення WM_DEVICECHANGE.

Тепер натисніть три чарівні кнопки – GTRL+SHIFT+C та дельфін для тебе люб'язно створить шаблон порожньої процедури:

Спробуй зробити виклик звичайного діалогового повідомлення. Наприклад:

ShowMessage («Виявлено нове обладнання»);

Запусти програму та спробуй вставити флешку. При вдале розташування зірок, відразу після вставки диска ти побачиш своє повідомлення. Прикольно? А головне просто та швидко! Але як завжди не обійшлося без кількох «АЛЕ». Не закривай програму та спробуй витягнути флешку. Не пройде кількох секунд, як наша програма знову відобразить наше повідомлення. Тільки цього разу воно вводить в оману, чим приносить користь. Чому це відбувається? Як бачиш, повідомлення WM_DEVICECHANGE надсилається не тільки в момент виявлення нового обладнання, а також при зміні стану підключених пристроїв. Наприклад, при відключенні USB принтера, твоя програма також отримає повідомлення про зміну стану пристроїв. Як тоді бути? Не впадай у відчай! У чарівній долині є відповідь і це питання. Закривай нашу сиру програму і повертайся до коду.

Уважніше вдивившись у MSDN можна знайти опис констант, значення яких можезнаходиться у полі WParam об'єкта типу TMessage. Констант досить багато, але нас цікавлять лише:

DBT_DEVICEARRIVAL – виявлено нове обладнання DBT_DEVTYP_VOLUME – тип виявленого пристрою DBT_DEVICEREMOVECOMPLETE – пристрій повністю видалено із системи

Виходить, що трохи видозмінивши тіло процедури WindowProc(), ми зможемо вирішити проблему, виявлену при першому тестуванні. Але не поспішатимемо. Перша складність з якою ми зіткнемося – мати компілятора при зверненні до вищеописаних константів. Це цілком очевидно, адже Delphi нічого не знає про ці константи. Щоб ними скористатися, тобі доведеться їх самостійно оголосити. Не хвилюйся, робиться це дуже просто. Після опису класу форми, оголоси секцію const і приведи її до вигляду як у мене:

Ці кілька рядків коду не повинні викликати в тебе складнощів. Але якщо тебе бентежать значення, які я їм надав, то не поспішай ворушити мізками. Краще зазирни в MSDN і одразу зрозумієш, про що я говорю.

Отже, давай видозмінимо наш невеликий приклад. Перейди до опису процедури WindowProc та приведи її тіло до такого вигляду:

Не поспішай запускати цей код! Прямо зараз він у тебе не скомпілюється, т.к. у ньому є виклик невідомого методу AddToLog() та звернення до функції DriveMaskToString(). Я тобі про них розповім, але трохи згодом. Спочатку розберемося з константами, які ми застосували, а вже після, з чистою совістю рушимо далі.

Про призначення описаних нами констант я вже говорив, і повторюватися не стану. Краще відразу зверну увагу на звернення до поля LParam через покажчик на структуру DEV_BROADCAST_HDR. Виконавши цю нехитру дію, мені стає доступним поле dbch_devicetype. Не важко здогадатися, що в цій цій властивості міститьсячисло, за яким можна однозначно визначити тип пристрою, що підключається. Якщо підключили флешку, то значення цього поля дорівнюватиме значенням константи DBT_DEVTYP_VOLUME, а якщо так, то нам нічого не залишається, як повідомити цю новину користувачеві. Так само будемо діяти і при відключенні флешки.

Зверни увагу, що про ці структури Delphi також нічого не відомо, тому за їх описом доведеться відповідати тільки тобі. Код усіх необхідних структур дивися нижче.

Опис структур ми розглянули і вважатимуться, що завдання практично виконано. Нам залишається описати таємничий метод AddToLog() і DriveMaskToString(). Код обох методів наведено нижче. Переписуй їх та спробуй запустити програму.

флешки