12 марта 2009

Прибирайте за собой

Довольно просто на стороне клиента открыть полученный с сервера файл в его родном приложении: ShellExecute(..., FileName, ...)

Единственное, перед этим нужно сохранить файл на диск. Например, во временную папку. Вопрос только - когда его удалять? Сразу же после вызова ShellExecute() это делать вряд ли разумно - запущенное приложение может не успеть еще забрать данные из файла. А может успеть открыть файл, и оставить его заблокированным на время просмотра.

Ничего красивее чем MoveFileEx(FileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) в голову не приходит. Правда до ближайшего ребута может быть много лет, но на клиентских машинах такое редко бывает. С другой стороны - многие вообще не прибирают за собой временные файлы, так что это лучше чем ничего.

Интересно, есть ли более элегантное решение?

9 комментариев:

AnToXa комментирует...

не сохранять файл на диск вообще?
или сделать мааааленький рамдрайв?

Raider комментирует...

Не сохранять файл на диск - это, конечно, самое лучшее решение. Но тогда нужно, правильно, либо виртуальный диск эмулировать, либо ставить хуки на операции чтения-записи. Все это слишком большая цена... как из пушки по воробьям

CTpaHHoe комментирует...

а FILE_FLAG_DELETE_ON_CLOSE не помогает?

Raider комментирует...

А чем он нам может помочь?

Анонимный комментирует...

ShellExecuteEx, SEE_MASK_NOCLOSEPROCESS, WaitForSingleObject, DeleteFile?

Raider комментирует...

К сожалению, не все так просто. Вначале может стартануть один процесс (например, Visual Studio Version Selector или XML Selector), потом он открывает файл, выясняет какое приложение должно быть открыто для этого файла, закрывает файл и запускает другой процесс (например Visual Studio 2005 или Word 2007), которому пеередает имя файла. Тот другой процесс опять открывает файл... а к этому моменту можно успеть уже удалить этот файл.

Уж лучше пусть файл полежит до ребута, чем в некоторых случаях не будет открываться. Для пользователя первое - это меньшее из зол, чем второе.

alek86 комментирует...

можно создавать батник типа такого

@echo Open file
"1.exe"
@echo File closed
del "1.exe"
@echo File deleted

и запускать его, чтоб он и запускал нужную прогу и удалил

ЗЫ. конечно, решение написано "на коленке" и там может появиться куча нюансов. в крайнем случае можно создавать специальную минипрогу :)

Artem комментирует...

Мне кажется, даже удалять файл на ребуте может быть излишне. А что, если это вордовский файл, и юзер его подредактировал важными изменениями? То-то юзер удивится когда на ребуте всё удалится.
Разве что делать файл "рид-онли" или удалять его только если он не был изменён... но всё равно возможны нюансы.

Raider комментирует...

Artem, меня интересует случай, когда файл открывается для просмотра. То есть ставим read-only флаг и после ребута можно удалять.

В случае, если нужно редактирование, а потом commit изменений в базу данных, то тут еще бОльший гемморой будет. Неплохо это реализовано в WinZip-е, когда открываешь файл из архива, то после изменений он предлагает его обновить в архиве.