Windowsのアプリケーションを作成していると、エクスプローラー (File Explorer) やAs/R等のファイラーからファイルやフォルダをDrag&Dropして使用したい事があるのではないかと思います。C++Builderで、ファイルやフォルダのドロップ(Drop)処理の方法を説明します。
プロジェクトの準備
C++Builderで、初めてのプロジェクト作成でも説明しました、SDIアプリケーションをベースに説明します。メインフォームには、TMemoを配置して、確認用のメッセージを表示します。C++Builder 12で作成しています。
ファイルのドロップ(Drop)を受付可能とする
アプリケーションのフォームで、ファイルのファイルのドロップ(Drop)を受付可能とするには、DragAcceptFiles関数を使用します。DragAcceptFiles関数を使用するには、shellapi.h をインクルードします。
DragAcceptFiles関数は、コンストラクタ、OnCreateイベント、OnShowイベントのどれかでコールします。それから、DragAcceptFiles関数を使用できるように、shellapi.h をインクルードする必要があります。
#include <shellapi.h>
__fastcall TSDIAppForm::TSDIAppForm(TComponent *AOwner) : TForm(AOwner)
{
// for Drop --------------------------
DragAcceptFiles(Handle, true);
}
WM_DROPFILESメッセージの処理関数を追加する
DragAcceptFiles(Handle, true); をコールすると、フォームにファイルやフォルダをドロップすると、WM_DROPFILESメッセージが、発生します。
C++Builderで、WM_DROPFILESメッセージを処理するには、フォームのヘッダファイル(ここでは、SDIMAIN.h)に、以下のコードを追加します。これで、WM_DROPFILESメッセージが発生すると、WMDropFiles関数が実行されるようになります。
private:
void __fastcall WMDropFiles(TWMDropFiles MSG); // for Drop
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_DROPFILES, TWMDropFiles, WMDropFiles) // for Drop
END_MESSAGE_MAP(TForm)
ファイル名を格納するTStringListを用意する
ファイル名を格納する為に、TStringListを使用してみます。
ヘッダファイルに定義を追加する
ヘッダファイルに、TStringList *DrpoFileInfo; を追加します。
private:
TStringList *DrpoFileInfo; // Drop
DrpoFileInfoの生成と、削除処理を追加する
今回は、コンストラクタとOnDEstroyイベントに記述します。
__fastcall TSDIAppForm::TSDIAppForm(TComponent *AOwner) : TForm(AOwner)
{
// for Drop --------------------------
DrpoFileInfo = new TStringList;
DragAcceptFiles(Handle, true);
}
void __fastcall TSDIAppForm::FormDestroy(TObject *Sender)
{
delete DrpoFileInfo;
}
ファイル名の取得
ファイル名の取得する処理を関数化しました。
int __fastcall TSDIAppForm::GetDropFiles(TWMDropFiles MSG, TStringList *FileList, bool clear)
{
// Dropされたファイル情報の取得
TCHAR FileName[MAX_PATH + 1];
String fname = "";
try
{
if(clear) { FileList->Clear(); } // リストのデータのクリア
int DragNo = DragQueryFile((HDROP)MSG.Drop, 0xFFFFFFFF, nullptr, 0);
if( DragNo != 0 )
{
for(int i=0;i<DragNo;i++)
{
DragQueryFile((HDROP)MSG.Drop, i, FileName, sizeof(FileName)/sizeof(_TCHAR));
fname = FileName;
if(TFile::Exists(fname)) // ファイルが存在すれば、格納する
{
if(FileList->IndexOf(fname) == -1) // 重複チェック
{
FileList->Add(fname);
}
}
}
// Dropされたファイル情報の取得
DragFinish((HDROP)MSG.Drop);
}
} __finally {
//
}
return FileList->Count;
}
- MAX_PATH を使用する為に、stdlib.h をインクルードします。
- DragQueryFile((HDROP)MSG.Drop, 0xFFFFFFFF, nullptr, 0); で、ドロップされたファイルの数を取得します。
- DragQueryFile((HDROP)MSG.Drop, i, FileName, sizeof(FileName)/sizeof(_TCHAR)); で、順番にFileNameに、ファイル名を取得します。
- この関数では、フォルダと区別する為に、TFile::Exists()関数を使用しています。System.IOUtils.hppを使用できるように、System.IOUtils.hpp をインクルードしておきます。
- 重複チェックを行い、新しいファイル名の時はFileListに追加します。
- 処理が終わったら、DragFinish((HDROP)MSG.Drop) をコールします。
- この関数は、取得したファイル名の数(FileList->Count)を返します。
フォルダ名の取得
フォルダ名の取得する処理も関数化しました。
int __fastcall TSDIAppForm::GetDropFolders(TWMDropFiles MSG, TStringList *FileList, bool clear)
{
// Dropされたファイル情報の取得
TCHAR FileName[MAX_PATH + 1];
String fname = "";
try
{
if(clear) { FileList->Clear(); } // リストのデータのクリア
int DragNo = DragQueryFile((HDROP)MSG.Drop, 0xFFFFFFFF, nullptr, 0);
if( DragNo != 0 )
{
for(int i=0;i<DragNo;i++)
{
DragQueryFile((HDROP)MSG.Drop, i, FileName, sizeof(FileName)/sizeof(_TCHAR));
fname = FileName;
if( TDirectory::Exists(fname) )
{
if(FileList->IndexOf(fname) == -1) // 重複チェック
{
FileList->Add(fname);
}
} else if( TFile::Exists(fname) ) {
// ファイルがDropさっれたら、そのフォルダ名の取得し格納する
fname = TPath::GetDirectoryName(fname);
if(FileList->IndexOf(fname) == -1) // 重複チェック
{
FileList->Add(fname);
}
}
}
DragFinish((HDROP)MSG.Drop);
}
} __finally {
//
}
return FileList->Count;
}
基本的な処理は、GetDropFiles関数と同じです。相違点は、フォルダ名の処理を行うのに、TDirectory::Exists() 関数で、フォルダかどうかチェックし、フォルダ名ではない時は、TPath::GetDirectoryName()関数で、フォルダ名を取得してそのフォルダ名をFileListに格納しているところです。
WMDropFiles関数の処理
WMDropFiles関数内の処理は、先ほど作成した関数を呼び出します。
void __fastcall TSDIAppForm::WMDropFiles(TWMDropFiles MSG)
{
int DragNo = GetDropFiles(MSG, DrpoFileInfo); // ファイル名を取得
// int DragNo = GetDropFolders(MSG, DrpoFileInfo); // フォルダ名を取得
if(DrpoFileInfo->Count > 0)
{
for(int i=0;i<DrpoFileInfo->Count;i++)
{
Memo1->Lines->Add(DrpoFileInfo->Strings[i]); // 取得したファイル名をTMemoに表示
}
}
// Memo1->Lines->Add("WMDropFiles");
}
参考URL
以下のHPも参考にしてください。