C++ API で Drop されたファイルを受け取る



C++ で OLE の API を使って、エクスプローラから Drop されたファイルを受け取ります。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. 新規プロジェクト(Dropcpp)で空のプロジェクトを作成して下さい。
  2. ページ先頭の画面を参考にして DialogBox に EditControl と ListBox を配置して下さい。
    IDを次のように設定して下さい。
    BOX ID
    DialogBox IDD_DIALOG1
    EditControl IDC_EDIT1
    ListBox IDC_LIST1
  3. [ビルド]から[実行]を選択するとビルドに続いて、エラーが無ければプログラムが実行されます。
    エクスプローラで幾つかのファイルを選択して、List Box にドラッグして下さい。
    ドラッグされたファイルリストが ListBox に追加されます。
    ただし ListBox に追加されるだけで、ファイルが実際にコピーされる訳ではありません。

プログラムの説明

  1. crtdbg.h を取り込んで下さい。
    関数の Prototype 宣言に続いて、IDropTarget を継承した DROPTAR Class の定義が行われています。
    長々とソースコードが続きますが、大部分はそのまま記述して下さい。
        #include <windows.h>
        #include <crtdbg.h>
        #include "resource.h"
    
        LRESULT CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
        int     DropFile(HWND hdlg, WPARAM WP);
    
        class DROPTAR :
            public IDropTarget
        {
        
  2. DROPTAR::Drop で Drop されたファイルリストを ListBox に登録します。
    最初のサンプルでは一個のファイル名だけを EditBox に表示していました。
            if (DragQueryFile( hDrop, -1, NULL, 0 ) == 1) {
                DragQueryFile( hDrop, 0, fn, MAX_PATH);
                SendDlgItemMessage(m_hWnd, IDC_EDIT1, WM_SETTEXT, strlen(fn), (LPARAM)fn);
            }
        
  3. エクスプローラからファイルリストが Drop されると、ここに制御が渡されます。
    複数のファイルリストを ListBox に登録するように修正しました。
        HRESULT STDMETHODCALLTYPE DROPTAR::Drop( 
            IDataObject __RPC_FAR* pDataObj,
            DWORD grfKeyState,
            POINTL pt,
            DWORD __RPC_FAR* pdwEffect )
        {
            HRESULT hr;
            FORMATETC fe;
            HDROP hDrop;
            STGMEDIUM stm;
            char fn[MAX_PATH];
            char    fname[24];
            int     i,j,fcnt;
    
            fe.cfFormat = CF_HDROP;
            fe.ptd = NULL;
            fe.dwAspect = NULL;
            fe.lindex = NULL;
            fe.tymed = TYMED_HGLOBAL;
            hr = pDataObj->QueryGetData( &fe );
            if ( hr != S_OK ) {     return S_OK;    }
    
            fe.cfFormat = CF_HDROP;
            fe.ptd = NULL;
            fe.dwAspect = NULL;
            fe.lindex = NULL;
            fe.tymed = TYMED_HGLOBAL;
            hr = pDataObj->GetData( &fe, &stm );
            _ASSERT( stm.tymed == TYMED_HGLOBAL );
            hDrop = (HDROP)stm.hGlobal;
            fcnt= DragQueryFile(hDrop,-1,NULL,0);   //ファイル数を取得
    //wsprintf(fn,"fcnt=%d",fcnt);
    //MessageBox(m_hWnd,fn,"Copy File Count",MB_OK);
            for(i=0; i<fcnt; i++)
            {   DragQueryFile(hDrop,i,fn,sizeof(fn));     //ファイル名を取得
    //MessageBox(m_hWnd,fn,"Drag File Name",MB_OK);
                for(j=strlen(fn-1); j>=0 && fn[j]!='\\' && fn[j]!=':'; j--);
                strcpy(fname,fn+j+1);
                SendMessage(GetDlgItem(m_hWnd,IDC_LIST1),LB_INSERTSTRING,0,(LPARAM)fname);  
            }
            if ( stm.pUnkForRelease ) {
                stm.pUnkForRelease->Release();
            } else {
                GlobalFree( stm.hGlobal );
            }
            return S_OK;
        }
    };
        
  4. DROPTAR *g_pDropTar が Drag&Drop のオブジェクトです。
    最初に OleInitialize() で OLE を初期化して下さい。
    プログラムの終了前に OleUninitialize() で後始末をします。
        DROPTAR *g_pDropTar;
    
        int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR lpCmdLine, int nCmdShow)
        {
            OleInitialize( NULL );
            DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)DlgProc);
            OleUninitialize();
            return TRUE;
        }
        
  5. WM_INITDIALOG: でオブジェクトを生成して RegisterDragDrop() で Drop を登録します。
    WM_DESTROY: で終了前に RevokeDragDrop() を実行して下さい。
        LRESULT CALLBACK DlgProc( HWND hDlg, UINT uMsg, WPARAM WP, LPARAM LP )
        {   static char szDir[32]= { "C:\\windows\\*.*" };
    
            switch(uMsg)
            {   case WM_INITDIALOG:
                    DlgDirList(hDlg,szDir,IDC_LIST1,IDC_EDIT1,DDL_DIRECTORY | DDL_DRIVES);
                    g_pDropTar = new DROPTAR(hDlg);
                    RegisterDragDrop(hDlg, g_pDropTar);
                    break;
                case WM_CLOSE:
                    DestroyWindow(hDlg);
                    break;
                case WM_DESTROY:
                    RevokeDragDrop(hDlg);
                    PostQuitMessage(0);
                    break;
                default:
                    return FALSE;
            }
            return TRUE;
        }
        

【演習】

エクスプローラからクリップボードに Drop したファイル名を取得して、実際にファイルを格納してみて下さい。

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

超初心者のプログラム入門(Win32API C++)