如何显示不同文件夹中多个文件的系统上下文菜单? [英] How to display system context menu for multiple files in different folders?

查看:167
本文介绍了如何显示不同文件夹中多个文件的系统上下文菜单?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题与

  #define STRICT_TYPED_ITEMIDS 
#include< windows.h>
#include< windowsx.h>
#include< shlobj.h>
#include< shellapi.h>
#include< shlwapi.h>
#include< propkey.h>
#include< new>
#includeresource.h

#pragma comment(lib,shell32.lib)
#pragma comment(lib,shlwapi.lib)
#pragma comment(linker,/ manifestdependency:\type ='win32'name ='Microsoft.Windows.Common-Controls'version ='6.0.0.0'processorArchitecture ='*'publicKeyToken ='6595b64144ccf1df'language = *'\)

HINSTANCE g_hinst = 0;

UINT const KFD_SELCHANGE = WM_USER;

class CFillResultsOnBackgroundThread;

类CExplorerBrowserHostDialog:public IServiceProvider,public ICommDlgBrowser
{
public:
CExplorerBrowserHostDialog():_cRef(1),_hdlg(NULL),_peb _fEnumerated(FALSE),_prf(NULL)
{
}

HRESULT DoModal(HWND hwnd)
{
DialogBoxParam(g_hinst,MAKEINTRESOURCE(IDD_DIALOG1) ,hwnd,s_DlgProc,(LPARAM)this);
return S_OK;
}

// IUnknown
STDMETHODIMP QueryInterface(REFIID riid,void ** ppv)
{
static const QITAB qit [] =
{
QITABENT(CExplorerBrowserHostDialog,IServiceProvider),
QITABENT(CExplorerBrowserHostDialog,ICommDlgBrowser),
{0},
};
return QISearch(this,qit,riid,ppv);
}

STDMETHODIMP_(ULONG)AddRef()
{
return InterlockedIncrement(& _cRef);
}

STDMETHODIMP_(ULONG)Release()
{
long cRef = InterlockedDecrement(& _cRef);
if(!cRef)
delete this;
return cRef;
}

// IServiceProvider
STDMETHODIMP QueryService(REFGUID guidService,REFIID riid,void ** ppv)
{
HRESULT hr = E_NOINTERFACE;
* ppv = NULL;
if(guidService == SID_SExplorerBrowserFrame)
{
//响应这个SID允许我们连接我们的ICommDlgBrowser
//实现,所以我们从视图$获得选择更改事件b $ b hr = QueryInterface(riid,ppv);
}
return hr;
}

// ICommDlgBrowser
STDMETHODIMP OnDefaultCommand(IShellView * / * psv * /)
{
_OnExplore
return S_OK;
}

STDMETHODIMP OnStateChange(IShellView * / * psv * /,ULONG uChange)
{
if(uCha​​nge == CDBOSC_SELCHANGE)
{
PostMessage(_hdlg,KFD_SELCHANGE,0,0);
}
return S_OK;
}

STDMETHODIMP IncludeObject(IShellView * / * psv * /,PCUITEMID_CHILD / * pidl * /)
{
return S_OK;
}

void FillResultsOnBackgroundThread(IResultsFolder * prf);

private:
〜CExplorerBrowserHostDialog()
{
}
$ b静态INT_PTR CALLBACK s_DlgProc(HWND hdlg,UINT uMsg,WPARAM wParam, LPARAM lParam)
{
CExplorerBrowserHostDialog * pebhd = reinterpret_cast< CExplorerBrowserHostDialog *>(GetWindowLongPtr(hdlg,DWLP_USER));
if(uMsg == WM_INITDIALOG)
{
pebhd = reinterpret_cast< CExplorerBrowserHostDialog *>(lParam);
pebhd-> _hdlg = hdlg;
SetWindowLongPtr(hdlg,DWLP_USER,reinterpret_cast< LONG_PTR>(pebhd));
}
return pebhd? pebhd-> _DlgProc(uMsg,wParam,lParam):0;
}

INT_PTR _DlgProc(UINT uMsg,WPARAM wParam,LPARAM lParam);
HRESULT _FillViewWithKnownFolders(IResultsFolder * prf);
void _OnInitDlg();
void _OnDestroyDlg();
void _StartFolderEnum();
void _OnSelChange();
void _OnExplore();
void _OnRefresh();

long _cRef;
HWND _hdlg;

IExplorerBrowser * _peb;
IResultsFolder * _prf;
BOOL _fEnumerated;
static const UINT c_rgControlsShownOnEnum [3]; //控制将在已知文件夹列表填充时显示
static const UINT c_rgControlsHiddenOnEnum [4]; //已知文件夹列表被填充时将被隐藏的控件
};

const UINT CExplorerBrowserHostDialog :: c_rgControlsShownOnEnum [] =
{
IDC_STATUS,
IDC_ENUMNAME,
IDC_ENUMPATH
};

const UINT CExplorerBrowserHostDialog :: c_rgControlsHiddenOnEnum [] =
{
IDC_FOLDERNAME,
IDC_FOLDERPATH,
IDC_LBLFOLDER,
IDC_LBLPATH
} ;

HRESULT CExplorerBrowserHostDialog :: _ FillViewWithKnownFolders(IResultsFolder * prf)
{
LPOLESTR pszFile = OLESTR(c:\\Windows\\\\
otepad.exe);
LPOLESTR pszFile2 = OLESTR(c:\\Windows \\System32\\\\
otepad.exe);
IShellFolder * pDesktop;
PIDLIST_RELATIVE pidl = NULL;
PIDLIST_RELATIVE pidl2 = NULL;
HRESULT hr;

hr = SHGetDesktopFolder(& pDesktop);
if(FAILED(hr)){
return E_FAIL;
}

hr = pDesktop-> ParseDisplayName(0,NULL,pszFile,NULL,& pidl,NULL);
if(FAILED(hr)){
pDesktop-> Release();
return E_FAIL;
}

hr = pDesktop-> ParseDisplayName(0,NULL,pszFile2,NULL,& pidl2,NULL);
if(FAILED(hr)){
pDesktop-> Release();
return E_FAIL;
}
prf-> AddIDList((PIDLIST_ABSOLUTE)pidl,0);
prf-> AddIDList((PIDLIST_ABSOLUTE)pidl2,0);
pDesktop-> Release();
IFolderView2 * pfv2;
IShellView * shellView;
hr = _peb-> GetCurrentView(IID_PPV_ARGS(& pfv2));
if(SUCCEEDED(hr)){
pfv2-> SelectItem(0,SVSI_SELECT);
pfv2-> SelectItem(1,SVSI_SELECT);
// hr = pfv2-> QueryInterface(IID_IOleWindow,(void **)& oleWnd);
hr = _peb-> GetCurrentView(IID_PPV_ARGS(& shellView));
if(SUCCEEDED(hr)){
HWND wnd = 0;
shellView-> GetWindow(& wnd);
// SendMessage(wnd,WM_CONTEXTMENU,0,MAKELPARAM(0,0));不工作
}
}

return S_OK;
}

void CExplorerBrowserHostDialog :: _ OnInitDlg()
{
//隐藏初始文件夹信息
for(UINT i = 0; i {
ShowWindow(GetDlgItem(_hdlg,c_rgControlsHiddenOnEnum [i]),SW_HIDE);
}

HWND hwndStatic = GetDlgItem(_hdlg,IDC_BROWSER);
if(hwndStatic)
{
RECT rc;
GetWindowRect(hwndStatic,& rc);
MapWindowRect(HWND_DESKTOP,_hdlg,& rc);

HRESULT hr = CoCreateInstance(CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC,IID_PPV_ARGS(& _peb));
if(SUCCEEDED(hr))
{
IUnknown_SetSite(_peb,static_cast< IServiceProvider *>(this));

FOLDERSETTINGS fs = {0};
fs.ViewMode = FVM_DETAILS;
fs.fFlags = FWF_AUTOARRANGE | FWF_NOWEBVIEW;
hr = _peb->初始化(_hdlg,& rc,& fs);
if(SUCCEEDED(hr))
{
_peb-> SetOptions(EBO_NAVIGATEONCE); //不允许导航

//初始化浏览器浏览器,以便我们可以使用结果文件夹
//作为数据源。这使我们可以通过IResultsFolder编程
//视图的内容

hr = _peb-> FillFromObject(NULL,EBF_NODROPTARGET);
if(SUCCEEDED(hr))
{
IFolderView2 * pfv2;
hr = _peb-> GetCurrentView(IID_PPV_ARGS(& pfv2));
if(SUCCEEDED(hr))
{
IColumnManager * pcm;
hr = pfv2-> QueryInterface(IID_PPV_ARGS(& pcm));
if(SUCCEEDED(hr))
{
PROPERTYKEY rgkeys [] = {PKEY_ItemNameDisplay,PKEY_ItemFolderPathDisplay};
hr = pcm-> SetColumns(rgkeys,ARRAYSIZE(rgkeys));
if(SUCCEEDED(hr))
{
CM_COLUMNINFO ci = {sizeof(ci),CM_MASK_WIDTH | CM_MASK_DEFAULTWIDTH | CM_MASK_IDEALWIDTH};
hr = pcm-> GetColumnInfo(PKEY_ItemFolderPathDisplay,& ci);
if(SUCCEEDED(hr))
{
ci.uWidth + = 100;
ci.uDefaultWidth + = 100;
ci.uIdealWidth + = 100;
pcm-> SetColumnInfo(PKEY_ItemFolderPathDisplay,& ci);
}
}
pcm-> Release();
}

hr = pfv2-> GetFolder(IID_PPV_ARGS(& _prf));
if(SUCCEEDED(hr))
{
_StartFolderEnum();
}
pfv2-> Release();
}
}
}
}
//如果我们无法正确初始化,请关闭对话框
if(FAILED(hr))
{
EndDialog(_hdlg,IDCLOSE);
}
}
}

//为当前所选项目传递-1
//返回一个IShellItem类型对象

HRESULT GetItemFromView(IFolderView2 * pfv,int iItem,REFIID riid,void ** ppv)
{
* ppv = NULL;

HRESULT hr = S_OK;

if(iItem == -1)
{
hr = pfv-> GetSelectedItem(-1,&i; iItem); //如果没有选择就返回S_FALSE
}

if(S_OK == hr)
{
hr = pfv-> GetItem(iItem,riid,ppv) ;
}
else
{
hr = E_FAIL;
}
return hr;
}

void CExplorerBrowserHostDialog :: _ OnSelChange()
{
if(_fEnumerated)
{
IFolderView2 * pfv2;
HRESULT hr = _peb-> GetCurrentView(IID_PPV_ARGS(& pfv2));
if(SUCCEEDED(hr))
{
IShellItem2 * psi;
hr = GetItemFromView(pfv2,-1,IID_PPV_ARGS(& psi));
if(SUCCEEDED(hr))
{
PWSTR pszName;
hr = psi-> GetDisplayName(SIGDN_NORMALDISPLAY,& pszName);
if(SUCCEEDED(hr))
{
SetDlgItemText(_hdlg,IDC_FOLDERNAME,pszName);
CoTaskMemFree(pszName);
}

hr = psi-> GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,& pszName);
if(SUCCEEDED(hr))
{
SetDlgItemText(_hdlg,IDC_FOLDERPATH,pszName);
CoTaskMemFree(pszName);
}

psi-> Release();
}
else if(hr == S_FALSE)
{
SetDlgItemText(_hdlg,IDC_FOLDERNAME,TEXT());
SetDlgItemText(_hdlg,IDC_FOLDERPATH,TEXT());
}

EnableWindow(GetDlgItem(_hdlg,IDC_EXPLORE),hr == S_OK);

pfv2-> Release();
}
}
}

void CExplorerBrowserHostDialog :: _ OnDestroyDlg()
{
if(_peb)
{
IUnknown_SetSite(_peb,NULL);
_peb-> Destroy();
_peb-> Release();
_peb = NULL;
}

if(_prf)
{
_prf-> Release();
_prf = NULL;
}
}

void CExplorerBrowserHostDialog :: _OnExplore()
{
IFolderView2 * pfv2;
HRESULT hr = _peb-> GetCurrentView(IID_PPV_ARGS(& pfv2));
if(SUCCEEDED(hr))
{
IShellItem * psi;
hr = GetItemFromView(pfv2,-1,IID_PPV_ARGS(& psi));
if(SUCCEEDED(hr))
{
PIDLIST_ABSOLUTE pidl;
hr = SHGetIDListFromObject(psi,& pidl);
if(SUCCEEDED(hr))
{
SHELLEXECUTEINFO ei = {sizeof(ei)};
ei.fMask = SEE_MASK_INVOKEIDLIST;
ei.hwnd = _hdlg
ei.nShow = SW_NORMAL;
ei.lpIDList = pidl

ShellExecuteEx(& ei);

CoTaskMemFree(pidl);
}
psi-> Release();
}
pfv2-> Release();
}
}

void CExplorerBrowserHostDialog :: _OnRefresh()
{
_fEnumerated = FALSE;

//更新UI
EnableWindow(GetDlgItem(_hdlg,IDC_EXPLORE),FALSE);
EnableWindow(GetDlgItem(_hdlg,IDC_REFRESH),FALSE);

if(SUCCEEDED(_peb-> RemoveAll()))
{
_StartFolderEnum();
}
}

void CExplorerBrowserHostDialog :: _ St​​artFolderEnum()
{
FillResultsOnBackgroundThread(_prf);
}

void CExplorerBrowserHostDialog :: FillResultsOnBackgroundThread(IResultsFolder * prf)
{
_FillViewWithKnownFolders(prf);

_fEnumerated = TRUE;
/ *
//调整对话框以显示正确的视图信息和按钮
(UINT k = 0; k {
ShowWindow(GetDlgItem(_hdlg,c_rgControlsShownOnEnum [k]),SW_HIDE);
}
for(UINT l = 0; l< ARRAYSIZE(c_rgControlsHiddenOnEnum); l ++)
{
ShowWindow(GetDlgItem(_hdlg,c_rgControlsHiddenOnEnum [1]),SW_SHOW);
} * /
EnableWindow(GetDlgItem(_hdlg,IDC_REFRESH),TRUE);
}

INT_PTR CExplorerBrowserHostDialog :: _DlgProc(UINT uMsg,WPARAM wParam,LPARAM / * lParam * /)
{
INT_PTR iRet = 1; //默认为所有处理的情况在switch下面

switch(uMsg)
{
case WM_INITDIALOG:
_OnInitDlg();
break;

case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
case IDC_CANCEL:
return EndDialog(_hdlg,TRUE);

case IDC_REFRESH:
_OnRefresh();
break;

case IDC_EXPLORE:
_OnExplore();
break;
}
break;

case KFD_SELCHANGE:
_OnSelChange();
break;

case WM_DESTROY:
_OnDestroyDlg();
break;

默认值:
iRet = 0;
break;
}
return iRet;
}

int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE,PWSTR,int)
{
g_hinst = hInstance;

HRESULT hr = CoInitializeEx(NULL,COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
如果(SUCCEEDED(hr))
{
OleInitialize(0); // for drag and drop

CExplorerBrowserHostDialog * pdlg = new(std :: nothrow)CExplorerBrowserHostDialog();
if(pdlg)
{
pdlg-> DoModal(NULL);
pdlg-> Release();
}

OleUninitialize();
CoUninitialize();
}

return 0;
}


This question is related to my previous question.

I need to obtain IContextMenu* interface pointer for files in different directories (or even drives).

See my code, which is not working properly (e.g. the file properties dialog shows wrong information), because I provide wrong relative PIDLs (as mentioned in this answer).

int main() {
    CoInitialize(NULL);
    LPOLESTR pszFile = OLESTR("c:\\Windows\\notepad.exe");
    LPOLESTR pszFile2 = OLESTR("c:\\Windows\\System32\\notepad.exe");
    //LPOLESTR pszDir = OLESTR("c:\\Windows\\");
    LPITEMIDLIST pidl = NULL;
    LPITEMIDLIST pidl2 = NULL;
    LPITEMIDLIST pidlDir;
    LPCITEMIDLIST pidlItem;
    LPCITEMIDLIST pidlItem2;
    HRESULT hr;
    IShellFolder* pFolder;
    //IShellFolder* pDir;
    IShellFolder* pDesktop;
    IContextMenu* pContextMenu;
    HMENU hMenu;
    CMINVOKECOMMANDINFO cmi;
    TCHAR szTemp[256];
    hr = SHGetDesktopFolder(&pDesktop);
    if (FAILED(hr)) {
        CoUninitialize();
        return 0;
    }

    HWND wnd = ::CreateWindowA("STATIC", "dummy", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL);

    /*hr = pDesktop->ParseDisplayName(wnd, NULL, pszDir, NULL, &pidlDir, NULL);
    if (FAILED(hr)) {
        goto clear;
    }

    hr = pDesktop->BindToObject(pidlDir, 0, IID_IShellFolder, (void**)&pDir);
        if (FAILED(hr)) {
            goto clear;
    }
    */

    hr = pDesktop->ParseDisplayName(wnd, NULL, pszFile, NULL, &pidl, NULL);
    if (FAILED(hr)) {
        goto clear;
    }

    hr = pDesktop->ParseDisplayName(wnd, NULL, pszFile2, NULL, &pidl2, NULL);
    if (FAILED(hr)) {
        goto clear;
    }

    hr = SHBindToParent(pidl, IID_IShellFolder, (void **)&pFolder, &pidlItem);
    if (FAILED(hr)) {
        goto clear;
    }
    pFolder->Release();

    hr = SHBindToParent(pidl2, IID_IShellFolder, (void **)&pFolder, &pidlItem2);
    if (FAILED(hr)) {
        goto clear;
    }

    LPCITEMIDLIST list[] = {pidlItem, pidlItem2};
    hr = pFolder->GetUIObjectOf(wnd, 2, (LPCITEMIDLIST *)list, IID_IContextMenu, NULL, (void **)&pContextMenu);
    pFolder->Release();
    if (SUCCEEDED(hr)) {
        hMenu = CreatePopupMenu();

        if (hMenu) {
            hr = pContextMenu->QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE);
            if (SUCCEEDED(hr)) {
                int idCmd = TrackPopupMenu(hMenu,
                                           TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
                                           1, 1, 0, wnd, NULL);

                if (idCmd) {
                    cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
                    cmi.fMask = 0;
                    cmi.hwnd = wnd;
                    cmi.lpVerb = MAKEINTRESOURCEA(idCmd-1);
                    cmi.lpParameters = NULL;
                    cmi.lpDirectory = NULL;
                    cmi.nShow = SW_SHOWNORMAL;
                    cmi.dwHotKey = 0;
                    cmi.hIcon = NULL;
                    hr = pContextMenu->InvokeCommand(&cmi);
                    if (!SUCCEEDED(hr)) {
                        wsprintf(szTemp, _T("InvokeCommand failed. hr=%lx"), hr);
                        MessageBox(0, szTemp, 0, 0);
                        PostQuitMessage(0);
                    }
                }
            }

            DestroyMenu(hMenu);
        }

        pContextMenu->Release();
    }

    MSG msg;
    BOOL bRet;

    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
            // Handle Error
        }
        else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

clear:

    pDesktop->Release();
    SHFree(pidl);
    SHFree(pidl2);
    CoUninitialize();
    return 0;
}

Maybe it is possible to achieve using SHCreateDefaultContextMenu or CDefFolderMenu_Create2 but I don't know how.

解决方案

It is possible if you embed IExplorerBrowser UI object into your app, which is available since Windows Vista. The you can fill it with any PIDLs through IResultsFolder. Here is sample code, which is just slightly modified example from Win7 Platform SDK (C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\winui\shell\appplatform\ExplorerBrowserCustomContents\ExplorerBrowserCustomContents.sln)

There is definitely an another method using IShellView which works on Windows XP but I didn't find it anyway.

#define STRICT_TYPED_ITEMIDS
#include <windows.h>
#include <windowsx.h>
#include <shlobj.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <propkey.h>
#include <new>
#include "resource.h"

#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "shlwapi.lib")
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

HINSTANCE g_hinst = 0;

UINT const KFD_SELCHANGE = WM_USER;

class CFillResultsOnBackgroundThread;

class CExplorerBrowserHostDialog : public IServiceProvider, public ICommDlgBrowser
{
public:
    CExplorerBrowserHostDialog() : _cRef(1), _hdlg(NULL), _peb(NULL), _fEnumerated(FALSE), _prf(NULL)
    {
    }

    HRESULT DoModal(HWND hwnd)
    {
        DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, s_DlgProc, (LPARAM)this);
        return S_OK;
    }

    // IUnknown
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
    {
        static const QITAB qit[] =
        {
            QITABENT(CExplorerBrowserHostDialog, IServiceProvider),
            QITABENT(CExplorerBrowserHostDialog, ICommDlgBrowser),
            { 0 },
        };
        return QISearch(this, qit, riid, ppv);
    }

    STDMETHODIMP_(ULONG) AddRef()
    {
        return InterlockedIncrement(&_cRef);
    }

    STDMETHODIMP_(ULONG) Release()
    {
        long cRef = InterlockedDecrement(&_cRef);
        if (!cRef)
            delete this;
        return cRef;
    }

    // IServiceProvider
    STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv)
    {
        HRESULT hr = E_NOINTERFACE;
        *ppv = NULL;
        if (guidService == SID_SExplorerBrowserFrame)
        {
            // responding to this SID allows us to hook up our ICommDlgBrowser
            // implementation so we get selection change events from the view
            hr = QueryInterface(riid, ppv);
        }
        return hr;
    }

    // ICommDlgBrowser
    STDMETHODIMP OnDefaultCommand(IShellView * /* psv */)
    {
        _OnExplore();
        return S_OK;
    }

    STDMETHODIMP OnStateChange(IShellView * /* psv */, ULONG uChange)
    {
        if (uChange == CDBOSC_SELCHANGE)
        {
            PostMessage(_hdlg, KFD_SELCHANGE, 0, 0);
        }
        return S_OK;
    }

    STDMETHODIMP IncludeObject(IShellView * /* psv */, PCUITEMID_CHILD /* pidl */)
    {
        return S_OK;
    }

    void FillResultsOnBackgroundThread(IResultsFolder *prf);

private:
    ~CExplorerBrowserHostDialog()
    {
    }

    static INT_PTR CALLBACK s_DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        CExplorerBrowserHostDialog *pebhd = reinterpret_cast<CExplorerBrowserHostDialog *>(GetWindowLongPtr(hdlg, DWLP_USER));
        if (uMsg == WM_INITDIALOG)
        {
            pebhd = reinterpret_cast<CExplorerBrowserHostDialog *>(lParam);
            pebhd->_hdlg = hdlg;
            SetWindowLongPtr(hdlg, DWLP_USER, reinterpret_cast<LONG_PTR>(pebhd));
        }
        return pebhd ? pebhd->_DlgProc(uMsg, wParam, lParam) : 0;
    }

    INT_PTR _DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
    HRESULT _FillViewWithKnownFolders(IResultsFolder *prf);
    void _OnInitDlg();
    void _OnDestroyDlg();
    void _StartFolderEnum();
    void _OnSelChange();
    void _OnExplore();
    void _OnRefresh();

    long _cRef;
    HWND _hdlg;

    IExplorerBrowser *_peb;
    IResultsFolder *_prf;
    BOOL _fEnumerated;
    static const UINT c_rgControlsShownOnEnum[3];  // controls that will be shown while known folder list is populated
    static const UINT c_rgControlsHiddenOnEnum[4]; // controls that will be hidden while known folder list is populated
};

const UINT CExplorerBrowserHostDialog::c_rgControlsShownOnEnum[] =
{
    IDC_STATUS,
    IDC_ENUMNAME,
    IDC_ENUMPATH
};

const UINT CExplorerBrowserHostDialog::c_rgControlsHiddenOnEnum[] =
{
    IDC_FOLDERNAME,
    IDC_FOLDERPATH,
    IDC_LBLFOLDER,
    IDC_LBLPATH
};

HRESULT CExplorerBrowserHostDialog::_FillViewWithKnownFolders(IResultsFolder *prf)
{
    LPOLESTR pszFile = OLESTR("c:\\Windows\\notepad.exe");
    LPOLESTR pszFile2 = OLESTR("c:\\Windows\\System32\\notepad.exe");
    IShellFolder* pDesktop;
    PIDLIST_RELATIVE pidl = NULL;
    PIDLIST_RELATIVE pidl2 = NULL;
    HRESULT hr;

    hr = SHGetDesktopFolder(&pDesktop);
    if (FAILED(hr)) {
        return E_FAIL;
    }

    hr = pDesktop->ParseDisplayName(0, NULL, pszFile, NULL, &pidl, NULL);
    if (FAILED(hr)) {
        pDesktop->Release();
        return E_FAIL;
    }

    hr = pDesktop->ParseDisplayName(0, NULL, pszFile2, NULL, &pidl2, NULL);
    if (FAILED(hr)) {
        pDesktop->Release();
        return E_FAIL;
    }
    prf->AddIDList((PIDLIST_ABSOLUTE)pidl, 0);
    prf->AddIDList((PIDLIST_ABSOLUTE)pidl2, 0);
    pDesktop->Release();
    IFolderView2 *pfv2;
    IShellView *shellView;
    hr = _peb->GetCurrentView(IID_PPV_ARGS(&pfv2));
    if (SUCCEEDED(hr)) {
        pfv2->SelectItem(0, SVSI_SELECT);
        pfv2->SelectItem(1, SVSI_SELECT);
        //hr = pfv2->QueryInterface(IID_IOleWindow, (void**)&oleWnd);
        hr = _peb->GetCurrentView(IID_PPV_ARGS(&shellView));
        if (SUCCEEDED(hr)) {
            HWND wnd = 0;
            shellView->GetWindow(&wnd);
            //SendMessage(wnd, WM_CONTEXTMENU, 0, MAKELPARAM(0,0)); not working
        }
    }

    return S_OK;
}

void CExplorerBrowserHostDialog::_OnInitDlg()
{
    // Hide initial folder information
    for (UINT i = 0; i < ARRAYSIZE(c_rgControlsHiddenOnEnum); i++)
    {
        ShowWindow(GetDlgItem(_hdlg, c_rgControlsHiddenOnEnum[i]), SW_HIDE);
    }

    HWND hwndStatic = GetDlgItem(_hdlg, IDC_BROWSER);
    if (hwndStatic)
    {
        RECT rc;
        GetWindowRect(hwndStatic, &rc);
        MapWindowRect(HWND_DESKTOP, _hdlg, &rc);

        HRESULT hr = CoCreateInstance(CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&_peb));
        if (SUCCEEDED(hr))
        {
            IUnknown_SetSite(_peb, static_cast<IServiceProvider *>(this));

            FOLDERSETTINGS fs = {0};
            fs.ViewMode = FVM_DETAILS;
            fs.fFlags = FWF_AUTOARRANGE | FWF_NOWEBVIEW;
            hr = _peb->Initialize(_hdlg, &rc, &fs);
            if (SUCCEEDED(hr))
            {
                _peb->SetOptions(EBO_NAVIGATEONCE); // do not allow navigations

                // Initialize the explorer browser so that we can use the results folder
                // as the data source. This enables us to program the contents of
                // the view via IResultsFolder

                hr = _peb->FillFromObject(NULL, EBF_NODROPTARGET);
                if (SUCCEEDED(hr))
                {
                    IFolderView2 *pfv2;
                    hr = _peb->GetCurrentView(IID_PPV_ARGS(&pfv2));
                    if (SUCCEEDED(hr))
                    {
                        IColumnManager *pcm;
                        hr = pfv2->QueryInterface(IID_PPV_ARGS(&pcm));
                        if (SUCCEEDED(hr))
                        {
                            PROPERTYKEY rgkeys[] = {PKEY_ItemNameDisplay, PKEY_ItemFolderPathDisplay};
                            hr = pcm->SetColumns(rgkeys, ARRAYSIZE(rgkeys));
                            if (SUCCEEDED(hr))
                            {
                                CM_COLUMNINFO ci = {sizeof(ci), CM_MASK_WIDTH | CM_MASK_DEFAULTWIDTH | CM_MASK_IDEALWIDTH};
                                hr = pcm->GetColumnInfo(PKEY_ItemFolderPathDisplay, &ci);
                                if (SUCCEEDED(hr))
                                {
                                    ci.uWidth += 100;
                                    ci.uDefaultWidth += 100;
                                    ci.uIdealWidth += 100;
                                    pcm->SetColumnInfo(PKEY_ItemFolderPathDisplay, &ci);
                                }
                            }
                            pcm->Release();
                        }

                        hr = pfv2->GetFolder(IID_PPV_ARGS(&_prf));
                        if (SUCCEEDED(hr))
                        {
                            _StartFolderEnum();
                        }
                        pfv2->Release();
                    }
                }
            }
        }
        // If we fail to initialize properly, close the dialog
        if (FAILED(hr))
        {
            EndDialog(_hdlg, IDCLOSE);
        }
    }
}

// pass -1 for the current selected item
// returns an IShellItem type object

HRESULT GetItemFromView(IFolderView2 *pfv, int iItem, REFIID riid, void **ppv)
{
    *ppv = NULL;

    HRESULT hr = S_OK;

    if (iItem == -1)
    {
        hr = pfv->GetSelectedItem(-1, &iItem); // Returns S_FALSE if none selected
    }

    if (S_OK == hr)
    {
        hr = pfv->GetItem(iItem, riid, ppv);
    }
    else
    {
        hr = E_FAIL;
    }
    return hr;
}

void CExplorerBrowserHostDialog::_OnSelChange()
{
    if (_fEnumerated)
    {
        IFolderView2 *pfv2;
        HRESULT hr = _peb->GetCurrentView(IID_PPV_ARGS(&pfv2));
        if (SUCCEEDED(hr))
        {
            IShellItem2 *psi;
            hr = GetItemFromView(pfv2, -1, IID_PPV_ARGS(&psi));
            if (SUCCEEDED(hr))
            {
                PWSTR pszName;
                hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &pszName);
                if (SUCCEEDED(hr))
                {
                    SetDlgItemText(_hdlg, IDC_FOLDERNAME, pszName);
                    CoTaskMemFree(pszName);
                }

                hr = psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &pszName);
                if (SUCCEEDED(hr))
                {
                    SetDlgItemText(_hdlg, IDC_FOLDERPATH, pszName);
                    CoTaskMemFree(pszName);
                }

                psi->Release();
            }
            else if (hr == S_FALSE)
            {
                SetDlgItemText(_hdlg, IDC_FOLDERNAME, TEXT(""));
                SetDlgItemText(_hdlg, IDC_FOLDERPATH, TEXT(""));
            }

            EnableWindow(GetDlgItem(_hdlg, IDC_EXPLORE), hr == S_OK);

            pfv2->Release();
        }
    }
}

void CExplorerBrowserHostDialog::_OnDestroyDlg()
{
    if (_peb)
    {
        IUnknown_SetSite(_peb, NULL);
        _peb->Destroy();
        _peb->Release();
        _peb = NULL;
    }

    if (_prf)
    {
        _prf->Release();
        _prf = NULL;
    }
}

void CExplorerBrowserHostDialog::_OnExplore()
{
    IFolderView2 *pfv2;
    HRESULT hr = _peb->GetCurrentView(IID_PPV_ARGS(&pfv2));
    if (SUCCEEDED(hr))
    {
        IShellItem *psi;
        hr = GetItemFromView(pfv2, -1, IID_PPV_ARGS(&psi));
        if (SUCCEEDED(hr))
        {
            PIDLIST_ABSOLUTE pidl;
            hr = SHGetIDListFromObject(psi, &pidl);
            if (SUCCEEDED(hr))
            {
                SHELLEXECUTEINFO ei = { sizeof(ei) };
                ei.fMask        = SEE_MASK_INVOKEIDLIST;
                ei.hwnd         = _hdlg;
                ei.nShow        = SW_NORMAL;
                ei.lpIDList     = pidl;

                ShellExecuteEx(&ei);

                CoTaskMemFree(pidl);
            }
            psi->Release();
        }
        pfv2->Release();
    }
}

void CExplorerBrowserHostDialog::_OnRefresh()
{
    _fEnumerated = FALSE;

    // Update UI
    EnableWindow(GetDlgItem(_hdlg, IDC_EXPLORE), FALSE);
    EnableWindow(GetDlgItem(_hdlg, IDC_REFRESH), FALSE);

    if (SUCCEEDED(_peb->RemoveAll()))
    {
        _StartFolderEnum();
    }
}

void CExplorerBrowserHostDialog::_StartFolderEnum()
{
    FillResultsOnBackgroundThread(_prf);
}

void CExplorerBrowserHostDialog::FillResultsOnBackgroundThread(IResultsFolder *prf)
{
    _FillViewWithKnownFolders(prf);

    _fEnumerated = TRUE;
/*
    // Adjust dialog to show proper view info and buttons
    for (UINT k = 0; k < ARRAYSIZE(c_rgControlsShownOnEnum); k++)
    {
        ShowWindow(GetDlgItem(_hdlg, c_rgControlsShownOnEnum[k]), SW_HIDE);
    }
    for (UINT l = 0; l < ARRAYSIZE(c_rgControlsHiddenOnEnum); l++)
    {
        ShowWindow(GetDlgItem(_hdlg, c_rgControlsHiddenOnEnum[l]), SW_SHOW);
    }*/
    EnableWindow(GetDlgItem(_hdlg, IDC_REFRESH), TRUE);
}

INT_PTR CExplorerBrowserHostDialog::_DlgProc(UINT uMsg, WPARAM wParam, LPARAM /* lParam */)
{
    INT_PTR iRet = 1;   // default for all handled cases in switch below

    switch (uMsg)
    {
    case WM_INITDIALOG:
        _OnInitDlg();
        break;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDOK:
        case IDCANCEL:
        case IDC_CANCEL:
            return EndDialog(_hdlg, TRUE);

        case IDC_REFRESH:
            _OnRefresh();
            break;

        case IDC_EXPLORE:
            _OnExplore();
            break;
        }
        break;

    case KFD_SELCHANGE:
        _OnSelChange();
        break;

    case WM_DESTROY:
        _OnDestroyDlg();
        break;

    default:
        iRet = 0;
        break;
    }
    return iRet;
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int)
{
    g_hinst = hInstance;

    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr))
    {
        OleInitialize(0);   // for drag and drop

        CExplorerBrowserHostDialog *pdlg = new (std::nothrow) CExplorerBrowserHostDialog();
        if (pdlg)
        {
            pdlg->DoModal(NULL);
            pdlg->Release();
        }

        OleUninitialize();
        CoUninitialize();
    }

    return 0;
}

这篇关于如何显示不同文件夹中多个文件的系统上下文菜单?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆