Диалог открытия файлов и юзабилити Windows

При всех удобствах Windows некоторые моменты меня очень сильно раздражают. Особенно поведение системы при вызове диалогов открытия файлов. Сперва немного предыстории. При работе с файлами через функцию GetOpenFileName или GetSaveFileName в структуре OPENFILENAME есть возможность указать путь, который должен открыться по умолчанию. Если это значение не задано, то система сама где-то запоминает папку, в которой последний раз был удачно открыт файл (то есть окно выбора файла было закрыто через кнопку "Ok"). Где именно хранится эта информация - я пока не выяснил, да и не особо надо. Второй вариант. Предположим, что некоторая программа самостоятельно запоминает путь к папке, в которой последний раз ею выполнялись какие-то действия с файлами. Это может быть, например, текстовый редактор, просмотрщик графики и т.п., не суть. Главное, что задумка очень хорошая и правильная. При следующем запуске или вызове диалога выбора файла в соответствующее поле OPENFILENAME будет подставлен сохраненный путь и пользователь продолжит работу с того места, где он в прошлый раз остановился. Что-то типа такого:
        ...
        invoke  GetModuleHandle,0
        mov     [ofn.hInstance],eax
        mov     [ofn.lStructSize], sizeof.OPENFILENAME
        mov     [ofn.hwndOwner],0
        mov     [ofn.nMaxFile],MAX_PATH
        mov     [ofn.lpstrFile],buff
        ; Открывать с последней сохраненной папки
        mov     [ofn.lpstrInitialDir],saved_dir
        mov     [ofn.Flags],OFN_EXPLORER+OFN_FILEMUSTEXIST
        invoke  GetOpenFileName,ofn
        ...

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

После очередной серии чудесатых чудес я решил сделать для себя небольшую вспомогательную функцию. Она проверяет сохраненный путь и возвращает последнюю папку максимального уровня вложенности, которая существует на диске в текущий момент. Например, если ваша программа в последнем сеансе работы сохранила, а затем пытается открыть путь
D:\PICTURES\Путешествия\2011\Разобрать\Китай\NIKOND90\001

но при этом папки "\Китай" и, соответственно, вложенных в нее папок уже не существует, то должна открываться папка
D:\PICTURES\Путешествия\2011\Разобрать

и никак иначе! По-моему, это единственно правильное поведение системы. Почему разработчики Windows до сих пор открывают непонятно что вместо ПОСЛЕДНЕЙ ДОСТУПНОЙ папки из запрошенного пути - непонятно. Какая-то дефолтная папка может открываться только в одном единственном случае - когда ВЕСЬ запрошенный путь, включая букву диска, недоступен.
;------------------------------------------------------------
; Функция проверки доступности пути в файловой системе
; (C) ManHunter / PCL
; http://www.manhunter.ru
;------------------------------------------------------------
; Параметры:
; lpRaw - указатель на буфер размером MAX_PATH, в который
; записан проверяемый путь
; lpGood - указатель на буфер размером MAX_PATH, в который
; будет записан максимально доступный путь
;
; На выходе:
; EAX=0 - ни один из составляющих пути, включая носитель, не
; доступен
; EAX=1 - по крайней мере один из составляющих пути доступен,
; результат без финального слеша записан в буфер lpGood
;------------------------------------------------------------
proc    GetLastValidFolder lpRaw:DWORD, lpGood:DWORD
        locals
                result  dd ?
                old_dir rb MAX_PATH
                new_dir rb MAX_PATH
        endl
 
        pusha
 
        ; Сохранить текущую директорию
        lea     eax,[old_dir]
        invoke  GetCurrentDirectory,MAX_PATH,eax
 
        ; Скопировать поверяемый путь
        lea     esi,[new_dir]
        invoke  lstrcpy,esi,[lpRaw]
        mov     edi,esi
        invoke  lstrlen,esi
        or      eax,eax
        jz      .loc_bad
        dec     eax
        add     edi,eax
 
        ; Исправить слеши
.loc_fix_slash:
        cmp     byte [esi+eax],'/'
        jne     @f
        mov     byte [esi+eax],'\'
@@:
        dec     eax
        or      eax,eax
        jnz     .loc_fix_slash
 
.loc_chk:
        ; Попробовать установить текущую директорию
        invoke  SetCurrentDirectory,esi
        or      eax,eax
        jne     .loc_ok
.loc_scan:
        mov     byte [edi],0
        dec     edi
 
        ; Сканируем с конца до ближайшего слеша
        cmp     byte [edi],'\'
        je      .loc_chk
 
        ; Добрались до начала строки?
        cmp     edi,esi
        jne     .loc_scan
.loc_bad:
        ; Результат - ошибка
        mov     [result],0
        ; Обнулить строку
        mov     eax,[lpGood]
        mov     byte [eax],0
        jmp     .loc_ret
.loc_ok:
        ; Убрать финальный слеш
        cmp     byte [edi],'\'
        jne     @f
        mov     byte [edi],0
@@:
        ; Скопировать последний правильный путь
        invoke  lstrcpy,[lpGood],esi
        ; Результат - успешно
        mov     [result],1
.loc_ret:
        ; Вернуть на место текущую директорию
        lea     eax,[old_dir]
        invoke  SetCurrentDirectory,eax
 
        popa
        ; Записать результат в EAX
        mov     eax,[result]
        ret
endp

На входе передаются два указателя: lpRaw - указатель на исходную строку пути, lpGood - указатель на буфер-приемник, куда будет записан последний максимально доступный путь. Исходный путь может содержать не только папки, но и имя файла, в этом случае функция вернет только папки. Также функция исправляет слеши, приводя их к принятому в Windows виду "\". Результат выполнения возвращается в регистре EAX, если он равен 0, то не доступен ни один элемент проверяемого пути, включая диск. Если EAX=1, то доступный путь найден. Функция самодостаточная и не требует наличия каких-либо дополнительных переменных для своей работы.

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

В приложении пример программы с исходным текстом, в которой используется описанная выше функция для проверки доступности пути.
Теги:
файл, Windows
Добавлено: 10 Апреля 2018 20:05:34 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...