C++Builder: Ловушка в диалоге выбора файла


Как известно, используя API-функции GetOpenFileName и GetSaveFileName, мы можем вызывать стандартные диалоги выбора файлов. Функциональность этих диалогов можно расширить путём внедрения в них ловушки.

Для примера: допустим, вы хотите ввести в ваше приложение возможность воспроизведения звуковых файлов при их выделении в окне диалога (как, например, сделано в программе FruityLoops при выборе сэмпла). Для этого необходимо создать процедуру, в которую будут поступать уведомительные сообщения от окна диалога. При поступлении определённого сообщения мы получим имя файла и попытаемся его воспроизвести.

Единственный параметр вышеупомянутых функций - указатель на структуру OPENFILENAME. Чтобы установить ловушку, необходимо:

  1. Объявить саму процедуру ловушки
  2. Указать имя этой процедуры в поле lpfnHook структуры OPENFILENAME
  3. В поле Flags структуры добавить флаг OFN_ENABLEHOOK

Демонстрационный код:
#include <mmsystem.hpp> // для sndPlaySound и waveOutGetNumDevs

// процедура - ловушка
UINT APIENTRY OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
if(uiMsg==WM_NOTIFY && ((OFNOTIFY*)lParam)->hdr.code==CDN_SELCHANGE)
  {
  char fName[MAX_PATH];
  if(CommDlg_OpenSave_GetFilePath(((OFNOTIFY*)lParam)->hdr.hwndFrom,fName,MAX_PATH)>=0)
    {
    if(ExtractFileExt(fName).UpperCase()==".WAV" && waveOutGetNumDevs())
      sndPlaySound(fName, SND_ASYNC); // асинхронное воспроизведение
    }
  }
return 0;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
char buff[MAX_PATH] = {'\0'};
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof ofn);
ofn.lStructSize = sizeof ofn;
ofn.hwndOwner = Handle;
ofn.lpstrFilter = "Файлы WAVE (*.wav)\0*.wav\0\0";
ofn.lpstrFile = buff;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrTitle = "Выбор звукового файла";
ofn.Flags = OFN_HIDEREADONLY | OFN_EXPLORER |
	    OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ENABLEHOOK;
ofn.lpfnHook = OFNHookProc;
GetOpenFileName(&ofn);
sndPlaySound(NULL,0); // остановка воспроизведения
}

Итак, при нажатии на кнопку мы создаём и инициализируем структуру OPENFILENAME. Поле lpfnHook мы инициализировали адресом процедуры OFNHookProc. Далее мы вызываем саму функцию, и механизм запускается.

Теперь рассмотрим саму процедуру ловушки - OFNHookProc. Обратите внимание, что её прототип идентичен прототипу обычной оконной процедуры.

Мы обрабатываем сообщение WM_NOTIFY. В данном случае, lParam сообщения является указателем на структуру OFNOTIFY. Мы проверяем равенство параметра code вложенной структуры NMHDR значению CDN_SELCHANGE. Если условие равно true, это означает, что в диалоге изменился выбранный элемент. Далее мы получаем имя выбранного файла с помощью макроса CommDlg_OpenSave_GetFilePath, что эквивалентно отправке диалогу сообщения CDM_GETFILEPATH. После этого проверяем расширение файла и количество звуковых устройств, установленных в системе (waveOutGetNumDevs()). Если всё нормально, воспроизводим файл.

Недостаток этого примера:

  • проверяется расширение выбранного файла на равенство "WAV"; т. е., если изменить расширение, то файл не будет воспроизводиться. Более корректно будет проверять содержимое самого файла на соответствие формату Microsoft Wave. В данном случае этот недостаток не проявится, т. к. фильтр диалога допускает только выбор файлов с этим расширением.


    Hosted by uCoz