SDK Index Previous page Next page

エクスプローラーを作る その5(送るの実装)


はじめる前に

と書かれた.CDFファイルがあると不正な処理をして終了することがあるようです。原因は不明ですがOleInitializeをしておくと大丈夫なようなので、その処理を追加します。

WinMain関数に次のコードを追加します。

    /* OLEの初期化を行います。 */
    if(OleInitialize(NULL) != S_OK){
        MessageBox(NULL,"OLEの初期化に失敗しました。","Error",MB_OK | MB_ICONERROR);
        return FALSE;
    }

はじめに

かなり前のエクスプローラーを作るでつくったエクスプローラーの右クリックメニューには送るがありませんでした。今回は、送るメニューを実装する方法を説明します。なんだかすごいことのようですが、何のことはないIContextMenuではなくIContextMenu2を使えばいいだけの話でした。前やったときは気づきませんでした。ちなみにIContextMenu3っていうのもあります。 今回のサンプルファイル

IContextMenu2を使う

IContextMenu2を使うのですが、このインターフェースは直接取得できないのでIContextMenuからQueryInterfaceを使って取得します。インターフェースの使い方は変わらないので、変更点はほとんどありません。
一つだけ違うのはg_lpcm2 = lpcm2としてIContextMenu2をグローバル変数に保存していることです。なぜこれが必要かというと、IContextMenu2を使にはWM_INITMENUPOPUP,WM_DRAWITEM,WM_MEASUREITEMという3つのメッセージをインターフェースメソッドのHandleMenuMsgで処理しなければならないのですが、このメソッドを実行するのにIContextMenu2のポインタが必要になってくるからです。
//ICONTEXTMENU2
static LPCONTEXTMENU2    g_lpcm2 = NULL;

//コンテキストメニューの表示とコマンドの実行

BOOL DoTheMenuThing(HWND hWnd, 
                    LPSHELLFOLDER lpShellFolder,
                    LPITEMIDLIST  *lpIDLArray,
                    int           num,
                    LPPOINT lppt)
{
    LPCONTEXTMENU lpcm = NULL;
    LPCONTEXTMENU2 lpcm2 = NULL;
    HRESULT       hr;
    CMINVOKECOMMANDINFO cmi;
    DWORD               dwAttribs = 0;
    int                 idCmd;
    HMENU               hMenu;
    BOOL                bSuccess = FALSE;

    //IContextMenuを取得します。
    //第三引数に、ファイルの数
    //第四引数に、ファイルのアイテムIDリスト配列のアドレスをいれます。
    hr = lpShellFolder->lpVtbl->GetUIObjectOf(lpShellFolder, hWnd,
                                            num,
                                            lpIDLArray,
                                            &IID_IContextMenu,
                                            0,
                                            (LPVOID *)&lpcm);

    if(FAILED(hr)) return FALSE;

    hr = lpcm->lpVtbl->QueryInterface(lpcm, &IID_IContextMenu2, (void **)&lpcm2);
    lpcm->lpVtbl->Release(lpcm);

    if(SUCCEEDED(hr)){
        hMenu = CreatePopupMenu();

        if(hMenu){
            //これでメニューを作る。詳細は不明
            hr = lpcm2->lpVtbl->QueryContextMenu(lpcm2, hMenu,
                                            0,
                                            1,
                                            0x7fff,
                                            CMF_EXPLORE);
            if (SUCCEEDED(hr)){
                bSuccess = TRUE;
                g_lpcm2 = lpcm2;
                idCmd = TrackPopupMenu(hMenu, 
                                    TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON, 
                                    lppt->x, 
                                    lppt->y,
                                    0,
                                    hWnd,
                                    NULL);
                g_lpcm2 = NULL;

                if (idCmd){
                    //開くファイルのオプションとか表示サイズとかの設定です。
                    cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
                    cmi.fMask  = 0;
                    cmi.hwnd   = hWnd;
                    cmi.lpVerb = MAKEINTRESOURCE(idCmd-1);
                    cmi.lpParameters = NULL;
                    cmi.lpDirectory  = NULL;
                    cmi.nShow        = SW_SHOWNORMAL;
                    cmi.dwHotKey     = 0;
                    cmi.hIcon        = NULL;
                    //次のコマンドで実行します
                    hr = lpcm2->lpVtbl->InvokeCommand(lpcm2, &cmi);
                    if (!SUCCEEDED(hr))  bSuccess = FALSE;
                }
            }
    
            DestroyMenu(hMenu);
        }

        lpcm2->lpVtbl->Release(lpcm2);
    }

    return bSuccess;
}

メッセージの処理を追加する

メインウインドウのプロシージャにメッセージの処理を追加します。 DoHandleMenuMsgは、HandleMenuMsgメソッドを実行してくれる関数です。
        case WM_INITMENUPOPUP:
            DoHandleMenuMsg(wMessage, wParam, lParam);
            return  FALSE;

        case WM_DRAWITEM:
        case WM_MEASUREITEM:
            DoHandleMenuMsg(wMessage, wParam, lParam);
            return  TRUE;

DoHandleMenuMsg

HandleMenuMsgを呼び出しています。そのときに使うインターフェースは、DoTheMenuThingで保存したポインタです。
HRESULT DoHandleMenuMsg(UINT wMessage, WPARAM wParam, LPARAM lParam)
{
    if(g_lpcm2){
        return g_lpcm2->lpVtbl->HandleMenuMsg(g_lpcm2, wMessage, wParam, lParam);
    }else{
        return -1;
    }
}

おわりに

その4の修正みたいなものですが、かなり時間がたってるので新しいページにしました。


to sdk prev next