ContentsC++ Labo.>1-1


C++Builder研究所

【1-1:ウィンドウにドロップしたファイルを操作したい】


戻る⊂(・ω・⊂)(つ・ω・)つ次へ

実行中のアプリケーションのウィンドウに関連したファイルをドロップすると、
勝手にファイルがオープンされますが、その機能の実装方法です。

この機能はC++Builderにはありませんので、WindowsAPIを直接弄る事になります。
「えー?WindowsAPIを使うの〜??」とおっしゃるかも知れませんが、
かなり楽にコーディング出来ますので、お試しあれ。

まずは、フォームのヘッダファイルに以下の赤い文を挿入します。
------------------------------
class TForm1 : public TForm
{
__published:	// IDE 管理のコンポーネント

private:	// ユーザー宣言
public:		// ユーザー宣言
__fastcall DropFiles(TWMDropFiles &Msg);
BEGIN_MESSAGE_MAP
	MESSAGE_HANDLER(WM_DROPFILES ,TWMDropFiles ,DropFiles)
END_MESSAGE_MAP(TForm)

	__fastcall TForm1(TComponent* Owner);
};
------------------------------
【メソッド:DropFiles】はファイルがドロップされた場合に実行される関数です。
次の【BEGIN_MESSAGE_MAP 〜 END_MESSAGE_MAP】の3行は、Windowsのメッセージを取得・処理の振り分けをするマクロです。
○BEGIN_MESSAGE_MAP…メッセージキャッチ宣言開始!

○END_MESSAGE_MAP…メッセージキャッチ宣言終了!
文法:END_MESSAGE_MAP(コンポーネント名)
ドラッグ&ドロップするファイルを受け取るコンポーネントをここで指定します。
上の例では、フォーム全体で受け取るようになります。

○MESSAGE_HANDLER…メッセージキャッチの動作を宣言します。
文法:MESSAGE_HANDLER(メッセージ , 取得するメッセージをカプセル化するための構造体 , 実行する関数名)
(VCLでは、これの代わりにVCL_MESSAGE_HANDLERを使う事を推奨しています。)

ドロップ待ち状態を指定します。
FormCreateメソッドかFormShowメソッド辺りに、以下の関数を記述しましょう。
------------------------------
void __fastcall TForm1::FormCreate(TObject* Sender)
{
	DragAcceptFiles( Form1->Handle , true );
}
------------------------------
他のコントロールが受け取る場合は、Form1->Handleの部分をクラス名->Handleで良いはずです。

次は実際にファイルをドロップされた場合の処理です。
------------------------------
__fastcall TForm1::DropFiles(TWMDropFiles &Msg)
{
	//ドロップされたファイルの個数
	int num = DragQueryFile((void *)(Msg.Drop), -1, NULL, NULL);

	for(int i = 0;i < num; i++)
	{
		char *filename;
		//ドロップされたファイル名の長さを取得する
		int size = DragQueryFile((void*)(Msg.Drop), i, NULL, NULL);
		//容量確保
		filename =(vhar*)(malloc(size+1));
		//順番にドロップされたファイルの名前を取得する
		DragQueryFile((void *)(Msg.Drop), i, filename, size);
		Application->MessageBox(filename, NULL, MB_OK);
	}
	return 0;
}
------------------------------
順を追ってみましょうか。

基本的にDragQueryFileと言うAPIで、ドロップされてきたファイル関連の処理を行います。
第1引数は全てを通して、 (void*)(Msg.Drop) を指定します。
複数個のファイルをドロップする事が出来るので、まずはドロップされたファイル数を取得します。
------------------------------
//ドロップされたファイルの個数(1)
int num = DragQueryFile((void *)(Msg.Drop), -1, NULL, NULL);
------------------------------
ドロップされたファイル数を取得するには、第2引数に -1 、第3第4引数に NULL を指定すると、
関数の戻り値にドロップされたファイル数が返ってきます。

次は、ドロップされたファイルの名前の長さを取得して、容量を確保します。
------------------------------
//ドロップされたファイル名の長さを取得する
int size = DragQueryFile((void*)(Msg.Drop), i, NULL, NULL);
------------------------------
まず、第2引数に取得したいファイル名の通し番号を指定します。
これは、1番目が 0 2番目が 1 と言う様に、取得したい順を n とするとn-1の値を指定してあげます。
そして、第3第4引数は NULL を指定します。
こうすると、関数の戻り値に指定したファイル名の長さが返ってきます。
この値を使って、容量を確保しましょう。

前もってファイル名を格納する場所を確保しておいても構いませんが、ドロップされたファイル名はフルパスで入ってきます。
その為、場合によっては 確保しておいた領域を超える可能性も出てきます 。
そうなると、ファイルの ドラッグ&ドロップは失敗 と言う事になりかねません。


最後が実際にファイル名を取得します。
------------------------------
//順番にドロップされたファイルの名前を取得する
DragQueryFile((void*)(Msg.Drop), i, filename, size);
------------------------------
第1第2引数は、ファイル名の長さを取得する時と同じです。
異なる点は、第3第4引数です。
第3引数には ファイル名を格納する場所 、第4引数には 格納する場所の文字の長さ を指定します。

これで、文字ポインタ filename にドロップしてきたファイルのフルパス が格納されているはずです。
後は、このパスを利用して自分の思った処理を記述すればOKです。

戻る⊂(・ω・⊂)(つ・ω・)つ次へ

douglas@ax.powerzoo.net
PostPet: