Автор Тема: Определение флэшки в картридере  (Прочитано 15199 раз)

0 Пользователей и 1 Гость просматривают эту тему.

eriser

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 202
  • Карма: 1
  • Пол: Мужской
  • Да чтоб вы все были здоровы...
    • Просмотр профиля
Блин... Курю в сторонке...
Извеняюсь, что не совсем в тему.
 То pumpkin.
Не могу разобраться с одной штутой. Каким образом отследить момент появления флеши в кардридере?
WM_DEVICECHANGE исследовал вдоль и поперёк- не годится. Может приходилось сталкиваться с подобным?
« Последнее редактирование: 10 Ноября 2009, 17:14:39 от admin »
Не все йогурты одинаково полезны!

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
@ eriser
Не сталкивался с этим вопросом никогда. Надо будет покопаться.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
@ Andy  [smiley=thumbsup.gif]

@ eriser
Поковырялся в MSDN. Кое что вырисовывается, и как раз с WM_DEVICECHANGE. Вставка флэшки в картридер ловится, осталось только определить какой именно диск (буква) был вставлен.
« Последнее редактирование: 01 Ноября 2009, 09:39:01 от pumpkin »

eriser

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 202
  • Карма: 1
  • Пол: Мужской
  • Да чтоб вы все были здоровы...
    • Просмотр профиля
Не совсем так. Диск уже есть (и не один), и буква есть ( тоже не одна). По таймеру отслеживать есть ли Disk in Drive в логических дисках  считаю извращением. Виндоуз так не делает. Но тем не менее как-то отслеживает?  :-/
« Последнее редактирование: 01 Ноября 2009, 12:51:31 от eriser »
Не все йогурты одинаково полезны!

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Ты меня не понял. Картридер уже вставлен в USB, причем давно, даже до включения компа, и представлен в виде 4 дисков (например H: I: J: K:). Вставляю в слот (щель) карточку SD - получаю сообщение, вытаскиваю карточку SD из слота - снова получаю сообщение. Такое ведь нужно было?
Но есть еще одна проблемка, как решу - выложу, просто времени мало. Хотя, если хочешь, могу и то, что сейчас нарыл выложить.

PS: Так, к слову, посмотрел как работает ImaTouch. Он делает это ежесекундным опросом дисков.

PPS: Andy, наверное эти посты в отдельную тему лучше перенести.
« Последнее редактирование: 01 Ноября 2009, 13:07:08 от pumpkin »

Форум проекта "Минилаб-Мастер"


eriser

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 202
  • Карма: 1
  • Пол: Мужской
  • Да чтоб вы все были здоровы...
    • Просмотр профиля
Так я об этом и говорю. WM_DEVICECHANGE замечательно работает с CD и USB флешками. В первый версиях моей проги это использовалось. Но с кардридерами этот фокус не проходит. И не у одного у меня.

http://www.delphikingdom.com/asp/itemq.asp?MessageID=9
это я год назад писал
http://programmersforum.ru/showthread.php?t=13486

Цитировать
    PS: Так, к слову, посмотрел как работает ImaTouch. Он делает это ежесекундным опросом дисков.
  Это подтверждает данную проблему.
Не все йогурты одинаково полезны!

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Цитировать
PPS: Andy, наверное эти посты в отдельную тему лучше перенести.

Конечно, сделаю отделный раздел. Приглашаю в модераторы...  :)
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Пока не перенес продолжу тут :)
@ eriser. Я говорю именно о картридере и отлавливании вставки карточки. В данном случае тоже используется WM_DEVICECHANGE, но оно не приходит по умолчанию. Нотификацию надо регистрировать для каждого физического диска (\\\\.\\PhysicalDriveX), которыми и являются слоты картридера. Загвоздка пока у меня с соответствием букв дисков и номерами физических дисков. Мне не нравится то, как я это делаю, но лучшего пока не нашел.

Вот тестовый экзешник: http://hotfile.com/dl/16370701/49d357f/Project1.rar.html
Сделан с использованием WM_DEVICECHANGE. Введи букву слота картридера (SD например) и повтыкай карточку.

jumper_at_home

  • Профи
  • ****
  • Сообщений: 359
  • Карма: 1
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
    Попробуйте функцию WaitForSingleObject (WaitFormultipleObjects)

    По сути это тот же самый интервальный опрос устройств, но он системный, крутится в нулевом кольце процессора и не тормозит.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Все цитировать не буду. Вкратце, вопрос стоит следующий:
Как получить уведомление от windows о вставке флэш-карточки в картридер? Интересует не подключения USB-флэшки, или не самого картридера в USB, а именно карточки SD, MS и т.д. в слот картридера.


Форум проекта "Минилаб-Мастер"


pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
На данный момент результат поисков такой:
Надо получать и обрабатывать сообщение WM_DEVICECHANGE. Но данные сообщения на вставку карточки в картридер по дефолту не приходят. Надо подписаться на него для каждого физического диска, коими являются слоты картридера, отдельно. А для этого надо определить, какие физические диски каким буквам дисков соответствуют.
То есть порядок примерно такой:
1. Определить физический диск (в виде \\\\.\\PhysicalDriveX) для каждого диска (слота) в картридере.
2. Зарегистрировать notification-ы для каждого из этих физических дисков.
3. Ловить WM_DEVICECHANGE с определенными параметрами и определять, какой слот его прислал.

См. далее.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
1. Как определить физический диск (\\\\.\\PhysicalDriveX), соответствующий определенной букве диска.
Это пока что есть. Скорее всего есть более правильные способы, разберусь - напишу еще. Применение DeviceIoControl с IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS не работает с "неготовыми" дисками.
//*** GetFirstPhysicalDriveNumber
//*** возвращает номер физического диска для указанной буквы диска
function GetFirstPhysicalDriveNumber(DrvChar: Char): Integer;
var
  i: Cardinal;
  Buf: packed array[0..256]of Char;
  DriveName: String;
begin
  Result := -1;
  //*** получаем имя диска вида \\Device\\HardDiskX\\...
  QueryDosDevice(PChar(\'\'+DrvChar+\':\'), Buf, 256);
  //*** извлекаем номер X
  DriveName := AnsiLowerCase(StrPas(Buf));
  Form1.Memo1.Lines.Add( \'Drive \'+DrvChar+\': is a \'+Buf );
  i := Pos(\'\\device\\harddisk\', DriveName);
  if i = 1 then begin
    Delete(DriveName,1,Length(\'\\device\\harddisk\'));
    i := Pos(\'\\\',DriveName);
    if i > 0 then
      Delete(DriveName, i, MAXINT);
    try
      Result := StrToInt(DriveName);
    except
    end;
    end;
end;

eriser

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 202
  • Карма: 1
  • Пол: Мужской
  • Да чтоб вы все были здоровы...
    • Просмотр профиля
Спасибо за совет!  Пища для резмышлений есть. Думаю дальше справлюсь.

2. Зарегистрировать notification-ы для каждого из этих физических дисков.
(тут возможно загвоздка будет)

Программу поюзал- вроде работает... Чудеса!  :)
« Последнее редактирование: 02 Ноября 2009, 20:30:28 от eriser »
Не все йогурты одинаково полезны!

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
2. Регистрируем уведомление для каждого из этих физических дисков.
Регистрируем уведомление типа DBT_DEVTYP_HANDLE.
Функция возвращает хэндл зарегистрированного уведомления. Сравнив потом с этими хэндлами для каждого диска, хэндл полученный в сообщении можно определить, какой диск их прислал.
function RegNotif( Wnd: HWND; DriveChar: Char;
                   var Fltr: TDevBroadcastHandle): HDEVNOTIFY;
var
  PhysDrvH: THandle;
  PhysDrvName: String;
  PhysDrvNum: Integer;
begin
  Result := nil;
  FillChar(Fltr, SizeOf(Fltr), 0);
  //*** находим номер физического диска
  PhysDrvNum := GetFirstPhysicalDriveNumber(DriveChar);
  if PhysDrvNum = -1 then Exit;
  //*** имя физического диска
  PhysDrvName := \'\\\\.\\PhysicalDrive\'+IntToStr(PhysDrvNum);
  //*** открываем диск (неважно, вставлена ли карточка)
  PhysDrvH := CreateFile(PChar(PhysDrvName), 0, FILE_SHARE_WRITE,
                         nil, OPEN_EXISTING, 0, 0);
  //*** заполняем структуру TDevBroadcastHandle
  Fltr.dbch_size := SizeOf(Fltr);
  Fltr.dbch_devicetype := DBT_DEVTYP_HANDLE;  // тип
  Fltr.dbch_handle := PhysDrvH;  // хэндл диска
  //*** регистрируем для окна Wnd
  Result := RegisterDeviceNotification( Wnd, @Fltr,
                         DEVICE_NOTIFY_WINDOW_HANDLE );
  //*** освобождаем хэндл диска
  CloseHandle(PhysDrvH);
end;

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
3. Обрабатываем WM_DEVICECHANGE.
Ловим событие DBT_CUSTOMEVENT с GUID-ами GUID_IO_MEDIA_ARRIVAL и GUID_IO_MEDIA_REMOVAL.
procedure TForm1.WMDeviceChange(var Msg: TWMDeviceChange);
begin
  if (Msg.Event = DBT_CUSTOMEVENT) then
    with PDevBroadcastHandle(Msg.dwData)^ do begin
      if (dbch_devicetype = DBT_DEVTYP_HANDLE) then begin
        if IsEqualGUID( dbch_eventguid, GUID_IO_MEDIA_ARRIVAL)
          then begin
          //*** карточку воткнули
          Label1.Caption := \'Inserted\';
          end
        else if IsEqualGUID( dbch_eventguid, GUID_IO_MEDIA_REMOVAL)
          then begin
          //*** карточку выдернули
          Label1.Caption := \'Removed\';
          end;
        end;
      end;
end;

-----------------------------------------

Ну вот примерно так. Если будут исправления/улучшения буду только рад.

Форум проекта "Минилаб-Мастер"