Ответ

Предупреждение: в данной теме не было сообщений более 730 дней.
Если не уверены, что хотите ответить, то лучше создайте новую тему.
Имя:
E-mail:
Тема:
Иконка:

Визуальная проверка:
Без рук и топоренка построена избенка:
4x50 (цифрой):
Ломай меня ...:

подсказка: нажмите alt+s для отправки или alt+p для предварительного просмотра сообщения


Сообщения в этой теме

Автор: eriser
« : 02 Ноября 2009, 22:01:20 »

Блин. Разжевал и в рот положил. Теперь  голово ломать нечем...
Спасибо!  :)
Автор: pumpkin
« : 02 Ноября 2009, 21:09:06 »

@ eriser
Прилагаю исходник тестовой проги. Недостающие библиотеки Jedi WinAPI (стандартные хидеры WinAPI переведенные на паскаль) можно скачать здесь http://sourceforge.net/projects/jedi-apilib/
Автор: pumpkin
« : 02 Ноября 2009, 20:44:00 »

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;

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

Ну вот примерно так. Если будут исправления/улучшения буду только рад.
Автор: pumpkin
« : 02 Ноября 2009, 20:30:28 »

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;
Автор: eriser
« : 02 Ноября 2009, 20:27:22 »

Спасибо за совет!  Пища для резмышлений есть. Думаю дальше справлюсь.

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

Программу поюзал- вроде работает... Чудеса!  :)
Автор: pumpkin
« : 02 Ноября 2009, 20:07:14 »

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;
Автор: pumpkin
« : 02 Ноября 2009, 19:43:46 »

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

См. далее.
Автор: pumpkin
« : 02 Ноября 2009, 19:18:44 »

Все цитировать не буду. Вкратце, вопрос стоит следующий:
Как получить уведомление от windows о вставке флэш-карточки в картридер? Интересует не подключения USB-флэшки, или не самого картридера в USB, а именно карточки SD, MS и т.д. в слот картридера.

Автор: jumper_at_home
« : 02 Ноября 2009, 12:00:47 »

    Попробуйте функцию WaitForSingleObject (WaitFormultipleObjects)

    По сути это тот же самый интервальный опрос устройств, но он системный, крутится в нулевом кольце процессора и не тормозит.
Автор: pumpkin
« : 01 Ноября 2009, 18:48:27 »

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

Вот тестовый экзешник: http://hotfile.com/dl/16370701/49d357f/Project1.rar.html
Сделан с использованием WM_DEVICECHANGE. Введи букву слота картридера (SD например) и повтыкай карточку.
Автор: Andy
« : 01 Ноября 2009, 14:42:59 »

Цитировать
PPS: Andy, наверное эти посты в отдельную тему лучше перенести.

Конечно, сделаю отделный раздел. Приглашаю в модераторы...  :)
Автор: eriser
« : 01 Ноября 2009, 13:43:23 »

Так я об этом и говорю. WM_DEVICECHANGE замечательно работает с CD и USB флешками. В первый версиях моей проги это использовалось. Но с кардридерами этот фокус не проходит. И не у одного у меня.

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

Цитировать
    PS: Так, к слову, посмотрел как работает ImaTouch. Он делает это ежесекундным опросом дисков.
  Это подтверждает данную проблему.
Автор: pumpkin
« : 01 Ноября 2009, 13:03:23 »

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

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

PPS: Andy, наверное эти посты в отдельную тему лучше перенести.
Автор: eriser
« : 01 Ноября 2009, 12:46:47 »

Не совсем так. Диск уже есть (и не один), и буква есть ( тоже не одна). По таймеру отслеживать есть ли Disk in Drive в логических дисках  считаю извращением. Виндоуз так не делает. Но тем не менее как-то отслеживает?  :-/
Автор: pumpkin
« : 01 Ноября 2009, 09:38:06 »

@ Andy  [smiley=thumbsup.gif]

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