Blog. Just Blog
Тюнинг функции SHBrowseForFolder
Функция API SHBrowseForFolder предназначена для выбора какой-нибудь папки из дерева каталогов всех дисков системы. Со своей задачей она, в принципе, справляется неплохо, но имеет ряд недостатков: окно выбора открывается в произвольных местах экрана, нельзя задать начальный каталог, нельзя менять заголовок окна и т.п. Если посмотреть внимательно на структуру BROWSEINFO, которую функция использует в работе, то в ней обнаруживается интересный параметр - указатель на callback-функцию BrowseCallbackProc. Эта функция получает управление при возникновении различных событий в окне выбора папок. Попробуем с ее помощью немного расширить базовый функционал SHBrowseForFolder. Сперва в сегменте данных определим необходимые значения для создания самого диалога выбора.Code (Assembler) : Убрать нумерацию
- ; Описание структуры BROWSEINFO
- struct BROWSEINFO
- hwndOwner dd ?
- pidlRoot dd ?
- pszDisplayName dd ?
- lpszTitle dd ?
- ulFlags dd ?
- lpfn dd ?
- lParam dd ?
- iImage dd ?
- ends
- ; Структура для работы с папками
- bi BROWSEINFO
- ; Буфер, который получит выбранных путь
- szDisplayName rb MAX_PATH
- ; Текст подсказки в окне выбора папки
- szTitle db 'Please select folder',0
Code (Assembler) : Убрать нумерацию
- ...
- ; Заполнить структуру
- mov [bi.hwndOwner],NULL
- mov [bi.ulFlags],BIF_RETURNONLYFSDIRS+BIF_DONTGOBELOWDOMAIN
- mov [bi.pszDisplayName],szDisplayName
- mov [bi.lpszTitle],szTitle
- ; Указатель на callback-функцию
- mov [bi.lpfn],BrowseCallbackProc
- ; Открыть диалог выбора папки
- invoke SHBrowseForFolder,bi
- ...
Теперь перейдем к самому обработчику функции BrowseCallbackProc. В FASM не определены константы, которые в ней используются, сделаем это самостоятельно. Также нам потребуются некоторые дополнительные данные.
Code (Assembler) : Убрать нумерацию
- ; Неообходимые константы для callback-функции
- BFFM_INITIALIZED = 1
- BFFM_SELCHANGED = 2
- BFFM_ENABLEOK = (WM_USER + 101)
- BFFM_SETSELECTION = (WM_USER + 102)
- BFFM_SETOKTEXT = (WM_USER + 105)
- ; Временный буфер для задания начального пути
- tmp_buff rb MAX_PATH
- ; Текст заголовка окна
- szMainTitle db 'FASM - Simple and powerful',0
- ; Текст кнопки OK (должен быть в юникоде)
- szOkButton du 'Yes, my Lord',0
Code (Assembler) : Убрать нумерацию
- ;---------------------------------------------
- ; Обработчик callback-функции
- ;---------------------------------------------
- proc BrowseCallbackProc hwnd:DWORD,uMsg:DWORD,lParam:DWORD,lpData
- cmp [uMsg],BFFM_INITIALIZED
- je .loc_init
- cmp [uMsg],BFFM_SELCHANGED
- je .loc_change
- .loc_ret:
- xor eax,eax
- ret
- .loc_init:
- ; Установить иконку окна
- invoke GetModuleHandle,0
- invoke LoadIcon,eax,1
- invoke SendMessage,[hwnd],WM_SETICON,ICON_BIG,eax
- ; Получить текущий каталог
- invoke GetCurrentDirectory,MAX_PATH,tmp_buff
- ; Установить начальный каталог в окне
- invoke SendMessage,[hwnd],BFFM_SETSELECTION,TRUE,tmp_buff
- ; Изменить стиль окна
- invoke GetWindowLong,[hwnd],GWL_EXSTYLE
- add eax,WS_EX_LAYERED
- invoke SetWindowLong,[hwnd],GWL_EXSTYLE,eax
- ; Установить атрибут прозрачности
- invoke SetLayeredWindowAttributes,[hwnd],0,200,LWA_ALPHA
- ; Изменить текст в заголовке окна
- invoke SetWindowText,[hwnd],szMainTitle
- ; Изменить текст на кнопке OK
- invoke SendMessage,[hwnd],BFFM_SETOKTEXT,NULL,szOkButton
- ; Заблокировать кнопку OK
- invoke SendMessage,[hwnd],BFFM_ENABLEOK,NULL,FALSE
- ; Субклассировать обработчик окна
- invoke SetWindowLong,[hwnd],GWL_WNDPROC,NewWindowProc
- ; Сохранить адрес предыдущего обработчика
- invoke SetWindowLong,[hwnd],GWL_USERDATA,eax
- ; Установить окно по центру экрана
- stdcall WindowToCenter,[hwnd],0
- jmp .loc_ret
- .loc_change:
- ; Разблокировать кнопку OK
- invoke SendMessage,[hwnd],BFFM_ENABLEOK,NULL,TRUE
- jmp .loc_ret
- endp
Code (Assembler) : Убрать нумерацию
- proc NewWindowProc hwnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
- ; Нажатие левой клавиши мыши?
- cmp [uMsg],WM_LBUTTONDOWN
- je .loc_drag
- ; Передать управление предыдущему обработчику
- invoke GetWindowLong,[hwnd],GWL_USERDATA
- invoke CallWindowProc,eax,[hwnd],[uMsg],[wParam],[lParam]
- ret
- .loc_drag:
- ; Перетаскивание окна
- invoke ReleaseCapture
- invoke SendMessage,[hwnd],WM_SYSCOMMAND,61458,0
- .exit_proc:
- ; Подавить сообщение и вернуть из обработчика FALSE
- xor eax,eax
- ret
- endp
В приложении пример программы, реализующей все вышеперечисленные новые функции. Для сравнения в нее добавлена функция открытия обычного диалога выбора папки.
Просмотров: 2571 | Комментариев: 4
Комментарии
Отзывы посетителей сайта о статье
Puk
(02.05.2010 в 17:15):
Так и писали бы что рефералы нужны! Я их отключаю в браузере, разрешаю только в экстренных случаях, когда без них сайт неадекватен.
Zummenix
(10.02.2010 в 19:53):
Отличный пример :)
в обработчик .loc_change добавил проверку
.loc_change:
; Заблокировать кнопку OK
invoke SendMessage,[hwnd],BFFM_ENABLEOK,NULL,FALSE
; Проверить выбранный путь
invoke SHGetPathFromIDList,[lParam],szDisplayName
cmp byte [szDisplayName],0
je .loc_ret
; Если все в порядке, то разблокировать кнопку OK
invoke SendMessage,[hwnd],BFFM_ENABLEOK,NULL,TRUE
jmp .loc_ret
в обработчик .loc_change добавил проверку
.loc_change:
; Заблокировать кнопку OK
invoke SendMessage,[hwnd],BFFM_ENABLEOK,NULL,FALSE
; Проверить выбранный путь
invoke SHGetPathFromIDList,[lParam],szDisplayName
cmp byte [szDisplayName],0
je .loc_ret
; Если все в порядке, то разблокировать кнопку OK
invoke SendMessage,[hwnd],BFFM_ENABLEOK,NULL,TRUE
jmp .loc_ret
SAY
(09.02.2010 в 08:10):
Здорово!
Добавить комментарий
Заполните форму для добавления комментария
Пример программы с исходным текстом (FASM)
Самое противное что есть, это беспорядочные окна! Всегда борюсь за порядок на рабочем столе...