Хорошо известный и уже довольно поднадоевший прием открытия файлов - через перетаскивание в целевое окно. Для приложения неплохо бы его иметь. В общем, здесь главное делают функции WinAPI под названием DragAcceptFiles() и DragQueryFile(). Функция DragAcceptFiles() сообщает Windows, что окно готово к приему файлов. Его (обращение к функции) обычно засовывают в самый старт программы - в FormCreate(). Впрочем, всяк ищет место по-разному. А DragQueryFile() выдает информацию о поднятых (то есть кинутых) файлах.
Вообще-то здесь есть один узкий момент - чтобы можно было отреагировать на это событие Windows придется сделать таблицу откликов MESSAGE_MAP в стиле Visual C++ или OWL. Но выхода другого нет. Опять немного теории: таблица откликов включается в описание класса. При возникновении какого-либо события, Windows передает управление процедуре-обработчику события. В принципе, для тех, кто программировал под DOS, это должно напоминать таблицу векторов прерываний для BIOS. В таблице указывается имя процедуры, тип события, которое она обрабатывает и тип сообщения, передаваемое обработчику. Общий синтаксис таблицы будет подробно рассмотрен в следующих шагах, а именно для этого примера нужно сделать вот что.
В секцию private класса TMainForm нужно вставить описание функции-обработчика, функции-диспетчера и таблицу откликов:
private: void __fastcall CreateMDIChild(const String Name,bool img); void __fastcall WmDropFiles(TWMDropFiles& Message); void __fastcall ReadFile(AnsiString FileName); public: virtual __fastcall TMainForm(TComponent *Owner); BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_DROPFILES,TWMDropFiles,WmDropFiles) END_MESSAGE_MAP(TForm);
Диспетчер ReadFile() нужен, чтобы два раза код не писать. Вообще-то вид у него громоздкий, зато от фильтра диалога не зависит. Вот изменения в главном файле:
#include <dir.h> __fastcall TMainForm::TMainForm(TComponent *Owner) : TForm(Owner) { DragAcceptFiles(Handle,true); } void __fastcall TMainForm::WmDropFiles(TWMDropFiles& Message) { HDROP drop_handle=(HDROP)Message.Drop; char fName[MAXPATH]; int filenum=DragQueryFile(drop_handle,-1,NULL,NULL); for (int i=0;i<filenum;i++) { DragQueryFile(drop_handle,i,fName,MAXPATH); ReadFile(fName); }; DragFinish(drop_handle); }; void __fastcall TMainForm::ReadFile(AnsiString FileName) { String str=ExtractFileExt(FileName); if((str==".avi")||(str==".wav")||(str==".mid")||(str==".mov")) { MediaPlayer1->FileName=FileName; MediaPlayer1->Open(); MediaPlayer1->Play(); } else if((str==".bmp")||(str==".ico")||(str==".wmf")) CreateMDIChild(FileName,true); else CreateMDIChild(FileName,false); }; void __fastcall TMainForm::FileOpen1Execute(TObject *Sender) { if (OpenDialog->Execute()) ReadFile(OpenDialog->FileName); }
Тут, по-моему, легко разобраться. Обратите внимание, как сократился код FileOpen1Execute() - вот что создатель языка Алгол называл структурным программированием! Функцию DragAcceptFiles() я поместил в объектный конструктор, что допустимо, хотя все-таки лучше использовать FormCreate() (если забыли, для автосоздания этого метода достаточно два раза щелкнуть кнопкой по форме). Параметр Handle - свойство, отражающее "window handle", как же это по-русски будет, что-то вроде объектного указателя на windowed control. Второй параметр - разрешить или запретить бросание файлов. Еще о DragQueryFile(). Message.Drop - это handle для параметров, переданных Windows. Он указывается в качестве первого аргумента. Если второй параметр unsigned int равен 0xFFFFFFFF или -1 (что проще записать), то функция возвращает число файлов, иначе имя соответствующее номеру файла. В первом случае два вторых параметра NULL, во втором строка как char str[n] и размер массива (unsigned int). MAXPATH - наибольший размер имени файла, определен в файле <dir.h>. DragFinish() - освобождает ресурсы.
Функция ExtractFileExt() возвращает расширение файла из пути к файлу (легче сделать, чем сказать). Например, для "C:\Мои документы\super.jpg" результат будет ".jpg".
Вот вроде бы и все. Как-нибудь надо будет еще рассмотреть String [AnsiString], но я Шаг с ним случайно стер, так что в следующий раз.