Хорошо известный и уже довольно поднадоевший прием открытия файлов - через перетаскивание в целевое окно. Для приложения неплохо бы его иметь. В общем, здесь главное делают функции 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], но я Шаг с ним случайно стер, так что в следующий раз.