Форум проекта "Минилаб-Мастер"
Клуб по интересам - отдыхаем от фотобизнеса => Программирование => Тема начата: eriser от 26 Октября 2009, 21:21:30
-
Блин... Курю в сторонке...
Извеняюсь, что не совсем в тему.
То pumpkin.
Не могу разобраться с одной штутой. Каким образом отследить момент появления флеши в кардридере?
WM_DEVICECHANGE исследовал вдоль и поперёк- не годится. Может приходилось сталкиваться с подобным?
-
@ eriser
Не сталкивался с этим вопросом никогда. Надо будет покопаться.
-
@ Andy [smiley=thumbsup.gif]
@ eriser
Поковырялся в MSDN. Кое что вырисовывается, и как раз с WM_DEVICECHANGE. Вставка флэшки в картридер ловится, осталось только определить какой именно диск (буква) был вставлен.
-
Не совсем так. Диск уже есть (и не один), и буква есть ( тоже не одна). По таймеру отслеживать есть ли Disk in Drive в логических дисках считаю извращением. Виндоуз так не делает. Но тем не менее как-то отслеживает? :-/
-
Ты меня не понял. Картридер уже вставлен в USB, причем давно, даже до включения компа, и представлен в виде 4 дисков (например H: I: J: K:). Вставляю в слот (щель) карточку SD - получаю сообщение, вытаскиваю карточку SD из слота - снова получаю сообщение. Такое ведь нужно было?
Но есть еще одна проблемка, как решу - выложу, просто времени мало. Хотя, если хочешь, могу и то, что сейчас нарыл выложить.
PS: Так, к слову, посмотрел как работает ImaTouch. Он делает это ежесекундным опросом дисков.
PPS: Andy, наверное эти посты в отдельную тему лучше перенести.
-
Так я об этом и говорю. WM_DEVICECHANGE замечательно работает с CD и USB флешками. В первый версиях моей проги это использовалось. Но с кардридерами этот фокус не проходит. И не у одного у меня.
http://www.delphikingdom.com/asp/itemq.asp?MessageID=9
это я год назад писал
http://programmersforum.ru/showthread.php?t=13486
PS: Так, к слову, посмотрел как работает ImaTouch. Он делает это ежесекундным опросом дисков.
Это подтверждает данную проблему.
-
PPS: Andy, наверное эти посты в отдельную тему лучше перенести.
Конечно, сделаю отделный раздел. Приглашаю в модераторы... :)
-
Пока не перенес продолжу тут :)
@ eriser. Я говорю именно о картридере и отлавливании вставки карточки. В данном случае тоже используется WM_DEVICECHANGE, но оно не приходит по умолчанию. Нотификацию надо регистрировать для каждого физического диска (\\\\.\\PhysicalDriveX), которыми и являются слоты картридера. Загвоздка пока у меня с соответствием букв дисков и номерами физических дисков. Мне не нравится то, как я это делаю, но лучшего пока не нашел.
Вот тестовый экзешник: http://hotfile.com/dl/16370701/49d357f/Project1.rar.html
Сделан с использованием WM_DEVICECHANGE. Введи букву слота картридера (SD например) и повтыкай карточку.
-
Попробуйте функцию WaitForSingleObject (WaitFormultipleObjects)
По сути это тот же самый интервальный опрос устройств, но он системный, крутится в нулевом кольце процессора и не тормозит.
-
Все цитировать не буду. Вкратце, вопрос стоит следующий:
Как получить уведомление от windows о вставке флэш-карточки в картридер? Интересует не подключения USB-флэшки, или не самого картридера в USB, а именно карточки SD, MS и т.д. в слот картридера.
-
На данный момент результат поисков такой:
Надо получать и обрабатывать сообщение WM_DEVICECHANGE. Но данные сообщения на вставку карточки в картридер по дефолту не приходят. Надо подписаться на него для каждого физического диска, коими являются слоты картридера, отдельно. А для этого надо определить, какие физические диски каким буквам дисков соответствуют.
То есть порядок примерно такой:
1. Определить физический диск (в виде \\\\.\\PhysicalDriveX) для каждого диска (слота) в картридере.
2. Зарегистрировать notification-ы для каждого из этих физических дисков.
3. Ловить WM_DEVICECHANGE с определенными параметрами и определять, какой слот его прислал.
См. далее.
-
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;
-
Спасибо за совет! Пища для резмышлений есть. Думаю дальше справлюсь.
2. Зарегистрировать notification-ы для каждого из этих физических дисков.
(тут возможно загвоздка будет)
Программу поюзал- вроде работает... Чудеса! :)
-
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;
-
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;
-----------------------------------------
Ну вот примерно так. Если будут исправления/улучшения буду только рад.
-
@ eriser
Прилагаю исходник тестовой проги. Недостающие библиотеки Jedi WinAPI (стандартные хидеры WinAPI переведенные на паскаль) можно скачать здесь http://sourceforge.net/projects/jedi-apilib/
-
Блин. Разжевал и в рот положил. Теперь голово ломать нечем...
Спасибо! :)