FMXでファイルをフォームへDrag and Dropする。 FMX版 その2 普通のやり方
FMXの場合は、VCLでやったようなMESSAGE_MAPを書くやり方が使えないので、自前のWndProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)を割り込ませて実現します。
Unit1.hから
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.Memo.hpp>
#include <FMX.Memo.Types.hpp>
#include <FMX.ScrollBox.hpp>
#include <FMX.Types.hpp>
#include <FMX.Platform.Win.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Objects.hpp>
#include <FMX.Edit.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TMemo *Memo1;
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
private: // ユーザー宣言
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
コンストラクタ以外は、FormCloseくらいが目立つ、というかそれしかない。
Unit1.cppは、
//---------------------------------------------------------------------------
#include <fmx.h>
#pragma hdrstop
#include <FMX.Platform.Win.hpp>
#include <ShellAPI.h>
#include <cstdlib>
#include <memory>
#include <vector>
#include <iostream>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
#if _WIN64
#define Parm GWLP_WNDPROC
#elif _WIN32
#define Parm GWL_WNDPROC
#elif __APPLE__
// macOS
#else
#error Not a supported platform
#endif
std::vector <AnsiString>filenames;
TForm1 *Form1;
HWND m_Hwnd;
WNDPROC m_WndOldProc;
long m_OldWndProc;
LRESULT CALLBACK WndProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
{
int count;
int i;
char fname[256];
TRect f;
if(Msg == WM_DROPFILES){
const unsigned int count = DragQueryFile((HDROP)wParam,-1,NULL,0);
for( unsigned int i = 0 ; i < count ; ++i ){
const unsigned int length = DragQueryFile((HDROP)wParam, i, NULL, 0);
std::unique_ptr<wchar_t[]> filename(new wchar_t[length + 1]);
DragQueryFile((HDROP)wParam, i, filename.get(), length + 1);
UnicodeString temp;
temp = filename.get();
Form1->Memo1->Lines->Add(temp);
}
}
return CallWindowProc(m_WndOldProc,hWnd,Msg,wParam,lParam);
}
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
m_Hwnd = Fmx::Platform::Win::FormToHWND(Form1);
DragAcceptFiles(m_Hwnd,true);
m_OldWndProc = GetWindowLongPtr(m_Hwnd, Parm);
m_WndOldProc = (WNDPROC)SetWindowLongPtr(m_Hwnd, Parm,(LONG)WndProc);
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
SetWindowLongPtr(m_Hwnd,Parm,m_OldWndProc);
}
一応プリプロセッサマクロで32bit版64bit版両対応しました。前の二つと同様に、フォームにTMemo一個だけ貼り付けて、上記のUnit1.hとUnit1.cppをプロジェクトに入れてbuildしてください。FormCloseをhookするのを忘れずに。
現在のWndProcを保存しておいて、自前のWndProcに差し替えて。所望の動作をさせ、FormCloseのタイミングで保存しておいたWndProcに戻すというロジックなんですが、GetWindowLongPtrとかSetWindowLongPtrとかいかにもなWin32ぽい関数を使っているところが、全然FMXらしくないですかね。そういう意味では2番目に示したやり方の方がスッキリしてますね。
コメント