-----Исходные данные: 1. Создаю устройство, эмулирующее дисковый накопитель(в драйвере). После этого ассоциирую с этим устройством символическую ссылку с помощью DefineDosDevice(в юзерском приложении.) - Код (Text): ... DefineDosDeviceW(DDD_RAW_TARGET_PATH, L'z', "\\device\\mydevdir\\mydisk0"); ... 2. Если диск нужно удалить, делаю Код (Text): ... DefineDosDeviceW(DDD_REMOVE_DEFINITION,L'z',NULL); ... (естественно, кроме этого в драйвере завершаю все IRP, удаляю устройство.) -----Проблема: Если юзерская программа завершена некоректно (сняли ее, или еще что), драйвер фиксирует это событие, и удаляет устройство ("\\device\\mydevdir\\mydisk0"). Но остается символическая ссылка, удалить которую можно вызовом х [ DefineDosDeviceW(DDD_REMOVE_DEFINITION,L'z',NULL); ]. Как получить такое же действие в дравере?
Хм... У меня эта ссылка появляется в \Sessions\0\DosDevice\00000000-00009648\z: Ка в таком случае выйти на это имя из драйвера?
\Sessions\0\ - это терминальная сессия на машине с Terminal Services. Точно не скажу, но должна быть ссылка \BaseNamedObjects\Session, которая указывает на раздел в пространстве имен менеджера объектов, где для каждой терминельной сессии есть свой подкаталог. Нужно перечислить все каталоги и вытереть ссылки DosDevice\00000000-00009648\z:. Используй ZwQueryDirectoryObject и т.п. функции (см. у Неббета 2 главу "Objects, Object Directories, and Symbolic Links" и DDK). И слей с этого сайта WinObjEx. Могу ошибиться в деталях, т.к. практически никогда такого не делал, но схема примерно такая.
Попробовал - ссылка удалилась. Но експлорер теперь показывает мой диск со знаком вопроса, и на попытку обращения говорит - --------------------------- My Computer --------------------------- E:\ refers to a location that is unavailable. It could be on a hard drive on this computer, or on a network. Check to make sure that the disk is properly inserted, or that you are connected to the Internet or your network, and then try again. If it still cannot be located, the information might have been moved to a different location. --------------------------- OK --------------------------- После юзерского DefineDosDevice такого не происходит. Я подозреваю, что как то експлорер (и ему подобных) нужно уведомить, послать кудато какую-то нотификацию... В юзер левеле, если верить гуглу, в таких случаях шлют броадкастом WM_DEVICECHANGE сообщение с типом DBT_DEVTYP_VOLUME , (некоторые предлагают WM_DEVICECHANGE,DBT_DEVICEARRIVAL). А что в дравере можно сделать? Сейчас пробую вариант с APC, предварительно создаю в юзере поток, потом ловлю TerminateProcess(& Ex), и делаю инсерт апц. Это думаю поможет. Или есть какой другой путь?
Насколько я знаю DefineDosDevice при добавлении ссылки сама бродкастит DBT_DEVICEARRIVAL, а при удалении DBT_DEVICEREMOVEPENDING/DBT_DEVICEREMOVECOMPLET. А потом ещё нужно сделать: BroadcastSystemMessage( BSF_NOHANG | BSF_QUERY, NULL, WM_DEVICECHANGE, DBT_QUERYCHANGECONFIG, 0 ); BroadcastSystemMessage( BSF_NOHANG | BSF_POSTMESSAGE, NULL, WM_DEVICECHANGE, DBT_CONFIGCHANGED, 0 ); BroadcastSystemMessage( BSF_NOHANG | BSF_POSTMESSAGE, NULL, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0 ); Уточнение насчет \Sessions\0\. Это только под w2k с Terminal Services, а под ХР+ эта ботва для каждого залогинившегося юзера создается свое локальное пространство имен в диспетчере объектов. Когда ты зовешь DefineDosDevice из юзерного процесса, то ссылка попадает в локальное пространство. Тебе нужно поместить её в глобальное. Сделать глобальную ссылку из юзер-моды, видимо, можно только находясь под аккаунтом LocalSystem, например из сервиса. Или из драйвера, находясь в контексте системного процесса (из DriverEntry, например). Если ссылка будет глобальной, то не надо будет париться с \Sessions\0\. Подробнее см. в DDK "Local and Global MS-DOS Device Names" или тут http://msdn.microsoft.com/library/default.asp?url=/library/en-us/Kernel_d/hh/Kernel_d/DevObjts_8f1d44af-b30c-434c-97ab-e5de5db16f07.xml.asp А зачем вообще удалять устройство при падении юзерного процесса? Пусть оно себе живёт. ЗЫ: Через APC - это изврат какой-то. Попробуй порыться в исходниках рам-дисков и поищи в конфе на osronline в разделе по файловым системам http://www.osronline.com/page.cfm?name=search
Попробуй посмотреть ещё в сторону диспетчера монтирования томов. См. в DDK "Mount Manager I/O Control Codes" и хидеры mountmgr.h и mountdev.h.
да, а как сделать это из драйвера? Даже если разобратся с этими ссылками и сессиями, удаление символической ссылки - только пол дела. Нужно броадкастить эти сообщения. А как это сделать из драйвера? (Есть подозрение что тоже через injection.) Дело в том, что этот юзерский процесс является источником данных для устройства. Без этого источника, бесполезность диска(вместе с устройством) как говорится, на лицо... Да, там все хорошо. У меня диски монтируются и так и так, и это такое требование...
Эти мессаги улетают через LPC в csrss.exe. Разбираться в том, что при этом происходит - очень гнилое занятие. Боюсь, что ты потратишь уйму времени впустую, пытаясь делать это из драйвера. IMHO, тебе нужно написАть сервис, единственной задачей которого будет монтирование/размонтирование тома. Сервис синхронизировать с драйвером (через событие, например). Смонтировав том, сервис засыпает на событии. После удаления устройства, драйвер сигналит событие и сервис размонтирует том. Как раз сервис будет в LocalSystem и гемор с сессиями пропадает автоматически.
в данный момент у меня этим занимается юзерская программа-источник. Лишний сервис - НУ ОЧЕНЬ ГРУСТНО... Кстати APC - очень даже работает. В ZwTerminateProcess, инсертим апц, ждем завершения по событию, вызываем оригинальный ZwTerminateProcess. Единственное - не работает кернельная роутина завершения апц. Не знаю почему, но обошел сигналом ивента с юзера. Сейчас код причешу, напишу про грабли которые найду.