C++打开文件夹对话框-通用文件对话框

此文介绍如何打开本地文本文件、文件夹对话框

方法一:

效果图:

 

 源码

#include <iostream>
#include <objbase.h>
#include <ShObjIdl.h>
using namespace std;
int main()
{
    cout << "start=====" << endl;
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED |
        COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr))
    {
        IFileOpenDialog* pFileOpen;

        // Create the FileOpenDialog object.
        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
            IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));

        if (SUCCEEDED(hr))
        {
            // Show the Open dialog box.
            hr = pFileOpen->Show(NULL);

            // Get the file name from the dialog box.
            if (SUCCEEDED(hr))
            {
                IShellItem* pItem;
                hr = pFileOpen->GetResult(&pItem);
                if (SUCCEEDED(hr))
                {
                    PWSTR pszFilePath;
                    hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);

                    // Display the file name to the user.
                    if (SUCCEEDED(hr))
                    {
                        MessageBoxW(NULL, pszFilePath, L"File Path", MB_OK);
                        CoTaskMemFree(pszFilePath);
                    }
                    pItem->Release();
                }
            }
            pFileOpen->Release();
        }
        CoUninitialize();
    }
    return 0;
}

出现错误

1、2、IID_IFileOpenDialog' was not declared in this scope

  hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
            IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));

改为 

 hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen));

2、 error: invalid use of incomplete type 'IFileDialog {aka struct IFileDialog}'

原因:默认情况下,MinGW将NTDDI_VERSION宏的值设置为0x05020000 (NTDDI_WS03),这会禁用shobjidl.h中的IFileDialog定义。宏的值必须至少为0x06000000 (NTDDI_VISTA)才能启用定义。下面列出了这些宏的可能值及其含义:

将以下内容放在源文件的开头(在include之前)应该可以修复编译错误:

#define NTDDI_VERSION 0x0A000006 //NTDDI_WIN10_RS5
#define _WIN32_WINNT 0x0A00 // _WIN32_WINNT_WIN10, the _WIN32_WINNT macro must also be defined when defining NTDDI_VERSION

如果您没有链接所需的库,则可能仍然存在链接错误。你列出的程序需要ole32.dll和uuid.dll,所以编译命令看起来像这样:

 

方法二:

效果图:

选择要尝试的文件对话框类型

 打开对话框效果

 

 

 

源码

ShellHelpers.h

#pragma once
#pragma once

#define STRICT_TYPED_ITEMIDS    // in case you do IDList stuff you want this on for better type saftey
#define UNICODE 1

#include <windows.h>
#include <windowsx.h>           // for WM_COMMAND handling macros
#include <shlobj.h>             // shell stuff
#include <shlwapi.h>            // QISearch, easy way to implement QI
#include <propkey.h>
#include <propvarutil.h>
#include <strsafe.h>
#include <objbase.h>

#pragma comment(lib, "shlwapi.lib")     // link to this
#pragma comment(lib, "comctl32.lib")    // link to this
#pragma comment(lib, "propsys.lib")     // link to this

// set up common controls v6 the easy way
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

__inline HRESULT ResultFromKnownLastError() { const DWORD err = GetLastError(); return err == ERROR_SUCCESS ? E_FAIL : HRESULT_FROM_WIN32(err); }

// map Win32 APIs that follow the return BOOL/set last error protocol
// into HRESULT
//
// example: MoveFileEx()

__inline HRESULT ResultFromWin32Bool(BOOL b)
{
    return b ? S_OK : ResultFromKnownLastError();
}

#if (NTDDI_VERSION >= NTDDI_VISTA)

__inline HRESULT ShellExecuteItem(HWND hwnd, PCWSTR pszVerb, IShellItem* psi)
{
    // how to activate a shell item, use ShellExecute().
    PIDLIST_ABSOLUTE pidl;
    HRESULT hr = SHGetIDListFromObject(psi, &pidl);
    if (SUCCEEDED(hr))
    {
        SHELLEXECUTEINFO ei = { sizeof(ei) };
        ei.fMask = SEE_MASK_INVOKEIDLIST;
        ei.hwnd = hwnd;
        ei.nShow = SW_NORMAL;
        ei.lpIDList = pidl;
        ei.lpVerb = pszVerb;

        hr = ResultFromWin32Bool(ShellExecuteEx(&ei));

        CoTaskMemFree(pidl);
    }
    return hr;
}

__inline 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;
}

// set the icon for your window using WM_SETICON from one of the set of stock system icons
// caller must call ClearDialogIcon() to free the HICON that is created
__inline void SetDialogIcon(HWND hdlg, SHSTOCKICONID siid)
{
    SHSTOCKICONINFO sii = { sizeof(sii) };
    if (SUCCEEDED(SHGetStockIconInfo(siid, SHGFI_ICON | SHGFI_SMALLICON, &sii)))
    {
        SendMessage(hdlg, WM_SETICON, ICON_SMALL, (LPARAM)sii.hIcon);
    }
    if (SUCCEEDED(SHGetStockIconInfo(siid, SHGFI_ICON | SHGFI_LARGEICON, &sii)))
    {
        SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)sii.hIcon);
    }
}
#endif

// free the HICON that was set using SetDialogIcon()
__inline void ClearDialogIcon(HWND hdlg)
{
    DestroyIcon((HICON)SendMessage(hdlg, WM_GETICON, ICON_SMALL, 0));
    DestroyIcon((HICON)SendMessage(hdlg, WM_GETICON, ICON_BIG, 0));
}

__inline HRESULT SetItemImageImageInStaticControl(HWND hwndStatic, IShellItem* psi)
{
    HBITMAP hbmp = NULL;
    HRESULT hr = S_OK;
    if (psi)
    {
        IShellItemImageFactory* psiif;
        hr = psi->QueryInterface(IID_PPV_ARGS(&psiif));
        if (SUCCEEDED(hr))
        {
            RECT rc;
            GetWindowRect(hwndStatic, &rc);
            const UINT dxdy = min(rc.right - rc.left, rc.bottom - rc.top);    // make it square
            const SIZE size = { dxdy, dxdy };

            hr = psiif->GetImage(size, SIIGBF_RESIZETOFIT, &hbmp);
            psiif->Release();
        }
    }

    if (SUCCEEDED(hr))
    {
        HGDIOBJ hgdiOld = (HGDIOBJ)SendMessage(hwndStatic, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
        if (hgdiOld)
        {
            DeleteObject(hgdiOld);  // if there was an old one clean it up
        }
    }

    return hr;
}


__inline HRESULT SHILCloneFull(PCUIDLIST_ABSOLUTE pidl, PIDLIST_ABSOLUTE* ppidl)
{
    *ppidl = ILCloneFull(pidl);
    return *ppidl ? S_OK : E_OUTOFMEMORY;
}

__inline HRESULT SHILClone(PCUIDLIST_RELATIVE pidl, PIDLIST_RELATIVE* ppidl)
{
    *ppidl = ILClone(pidl);
    return *ppidl ? S_OK : E_OUTOFMEMORY;
}

__inline HRESULT SHILCombine(PCIDLIST_ABSOLUTE pidl1, PCUIDLIST_RELATIVE pidl2, PIDLIST_ABSOLUTE* ppidl)
{
    *ppidl = ILCombine(pidl1, pidl2);
    return *ppidl ? S_OK : E_OUTOFMEMORY;
}

__inline HRESULT GetItemAt(IShellItemArray* psia, DWORD i, REFIID riid, void** ppv)
{
    *ppv = NULL;
    IShellItem* psi = NULL;     // avoid error C4701
    HRESULT hr = psia ? psia->GetItemAt(i, &psi) : E_NOINTERFACE;
    if (SUCCEEDED(hr))
    {
        hr = psi->QueryInterface(riid, ppv);
        psi->Release();
    }
    return hr;
}

#define MAP_ENTRY(x) {L#x, x}

__inline HRESULT ShellAttributesToString(SFGAOF sfgaof, PWSTR* ppsz)
{
    *ppsz = NULL;

    static const struct { PCWSTR pszName; SFGAOF sfgaof; } c_rgItemAttributes[] =
    {
        // note, SFGAO_HASSUBFOLDER is too expesnive to compute
        // and has been excluded from this list
        MAP_ENTRY(SFGAO_STREAM),
        MAP_ENTRY(SFGAO_FOLDER),
        MAP_ENTRY(SFGAO_FILESYSTEM),
        MAP_ENTRY(SFGAO_FILESYSANCESTOR),
        MAP_ENTRY(SFGAO_STORAGE),
        MAP_ENTRY(SFGAO_STORAGEANCESTOR),
        MAP_ENTRY(SFGAO_LINK),
        MAP_ENTRY(SFGAO_CANCOPY),
        MAP_ENTRY(SFGAO_CANMOVE),
        MAP_ENTRY(SFGAO_CANLINK),
        MAP_ENTRY(SFGAO_CANRENAME),
        MAP_ENTRY(SFGAO_CANDELETE),
        MAP_ENTRY(SFGAO_HASPROPSHEET),
        MAP_ENTRY(SFGAO_DROPTARGET),
        MAP_ENTRY(SFGAO_ENCRYPTED),
        MAP_ENTRY(SFGAO_ISSLOW),
        MAP_ENTRY(SFGAO_GHOSTED),
        MAP_ENTRY(SFGAO_SHARE),
        MAP_ENTRY(SFGAO_READONLY),
        MAP_ENTRY(SFGAO_HIDDEN),
        MAP_ENTRY(SFGAO_REMOVABLE),
        MAP_ENTRY(SFGAO_COMPRESSED),
        MAP_ENTRY(SFGAO_BROWSABLE),
        MAP_ENTRY(SFGAO_NONENUMERATED),
        MAP_ENTRY(SFGAO_NEWCONTENT),
    };

    WCHAR sz[512] = {};
    PWSTR psz = sz;
    size_t cch = ARRAYSIZE(sz);

    StringCchPrintfEx(psz, cch, &psz, &cch, 0, L"0x%08X", sfgaof);

    for (int i = 0; i < ARRAYSIZE(c_rgItemAttributes); i++)
    {
        if (c_rgItemAttributes[i].sfgaof & sfgaof)
        {
            StringCchPrintfEx(psz, cch, &psz, &cch, 0, L", %s", c_rgItemAttributes[i].pszName);
        }
    }
    return SHStrDup(sz, ppsz);
}

template <class T> void SafeRelease(T** ppT)
{
    if (*ppT)
    {
        (*ppT)->Release();
        *ppT = NULL;
    }
}

// assign an interface pointer, release old, capture ref to new, can be used to set to zero too

template <class T> HRESULT SetInterface(T** ppT, IUnknown* punk)
{
    SafeRelease(ppT);
    return punk ? punk->QueryInterface(ppT) : E_NOINTERFACE;
}

// remote COM methods are dispatched in the context of an exception handler that consumes
// all SEH exceptions including crahses and C++ exceptions. this is undesirable as it
// means programs will continue to run after such an exception has been thrown,
// leaving the process in a inconsistent state.
//
// this applies to COM methods like IDropTarget::Drop()
//
// this code turns off that behavior

__inline void DisableComExceptionHandling()
{
    IGlobalOptions* pGlobalOptions;
    HRESULT hr = CoCreateInstance(CLSID_GlobalOptions, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGlobalOptions));
    if (SUCCEEDED(hr))
    {
#if (NTDDI_VERSION >= NTDDI_WIN7)
        hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE_ANY);
#else
        hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE);
#endif
        pGlobalOptions->Release();
    }
}

__inline void GetWindowRectInClient(HWND hwnd, RECT* prc)
{
    GetWindowRect(hwnd, prc);
    MapWindowPoints(GetDesktopWindow(), GetParent(hwnd), (POINT*)prc, 2);
}

// retrieve the HINSTANCE for the current DLL or EXE using this symbol that
// the linker provides for every module, avoids the need for a global HINSTANCE variable
// and provides access to this value for static libraries
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
__inline HINSTANCE GetModuleHINSTANCE() { return (HINSTANCE)&__ImageBase; }

FileName2.cpp



// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved

#include <windows.h>
#define STRICT_TYPED_ITEMIDS
#include <shlobj.h>
#include <shlwapi.h>
#include "ShellHelpers.h"
#include <strsafe.h>
#include <new>

const DWORD c_idAdd = 601;
const DWORD c_idDone = 602;

#define IDC_PICKITEM              100
#define IDC_PICKCONTAINER         101
#define IDC_FILEOPENBASKETPICKER  102
#define IDC_PICKFILESANDFOLDERS   103

/* Utility Classes and Functions *************************************************************************************************/

/*
    Usage:
    CItemIterator itemIterator(psi);
    while (itemIterator.MoveNext())
    {
        IShellItem2 *psi;
        hr = itemIterator.GetCurrent(IID_PPV_ARGS(&psi));
        if (SUCCEEDED(hr))
        {
            // Perform action on psi
            psi->Release();
        }
    }
*/
class CItemIterator
{
public:
    CItemIterator(IShellItem* psi) : _hr(SHGetIDListFromObject(psi, &_pidlFull)), _psfCur(NULL)
    {
        _Init();
    }

    CItemIterator(PCIDLIST_ABSOLUTE pidl) : _hr(SHILCloneFull(pidl, &_pidlFull)), _psfCur(NULL)
    {
        _Init();
    }

    ~CItemIterator()
    {
        CoTaskMemFree(_pidlFull);
        SafeRelease(&_psfCur);
    }

    bool MoveNext()
    {
        bool fMoreItems = false;
        if (SUCCEEDED(_hr))
        {
            if (NULL == _pidlRel)
            {
                fMoreItems = true;
                _pidlRel = _pidlFull;   // First item - Might be empty if it is the desktop
            }
            else if (!ILIsEmpty(_pidlRel))
            {
                PCUITEMID_CHILD pidlChild = (PCUITEMID_CHILD)_pidlRel;  // Save the current segment for binding
                _pidlRel = ILNext(_pidlRel);

                // If we are not at the end setup for the next iteration
                if (!ILIsEmpty(_pidlRel))
                {
                    const WORD cbSave = _pidlRel->mkid.cb;  // Avoid cloning for the child by truncating temporarily
                    _pidlRel->mkid.cb = 0;                  // Make this a child

                    IShellFolder* psfNew;
                    _hr = _psfCur->BindToObject(pidlChild, NULL, IID_PPV_ARGS(&psfNew));
                    if (SUCCEEDED(_hr))
                    {
                        _psfCur->Release();
                        _psfCur = psfNew;   // Transfer ownership
                        fMoreItems = true;
                    }

                    _pidlRel->mkid.cb = cbSave; // Restore previous ID size
                }
            }
        }
        return fMoreItems;
    }

    HRESULT GetCurrent(REFIID riid, void** ppv)
    {
        *ppv = NULL;
        if (SUCCEEDED(_hr))
        {
            // Create the childID by truncating _pidlRel temporarily
            PUIDLIST_RELATIVE pidlNext = ILNext(_pidlRel);
            const WORD cbSave = pidlNext->mkid.cb;  // Save old cb
            pidlNext->mkid.cb = 0;                  // Make _pidlRel a child

            _hr = SHCreateItemWithParent(NULL, _psfCur, (PCUITEMID_CHILD)_pidlRel, riid, ppv);

            pidlNext->mkid.cb = cbSave;             // Restore old cb
        }
        return _hr;
    }

    HRESULT GetResult() const { return _hr; }
    PCUIDLIST_RELATIVE GetRelativeIDList() const { return _pidlRel; }

private:
    void _Init()
    {
        _pidlRel = NULL;

        if (SUCCEEDED(_hr))
        {
            _hr = SHGetDesktopFolder(&_psfCur);
        }
    }

    HRESULT _hr;
    PIDLIST_ABSOLUTE _pidlFull;
    PUIDLIST_RELATIVE _pidlRel;
    IShellFolder* _psfCur;
};

HRESULT GetIDListName(IShellItem* psi, PWSTR* ppsz)
{
    *ppsz = NULL;
    HRESULT hr = E_FAIL;

    WCHAR szFullName[2048];
    szFullName[0] = 0;
    PWSTR pszOutput = szFullName;
    size_t cchOutput = ARRAYSIZE(szFullName);

    CItemIterator itemIterator(psi);
    while (itemIterator.MoveNext())
    {
        IShellItem2* psi;
        hr = itemIterator.GetCurrent(IID_PPV_ARGS(&psi));
        if (SUCCEEDED(hr))
        {
            PWSTR pszName;
            hr = psi->GetDisplayName(SIGDN_PARENTRELATIVE, &pszName);
            if (SUCCEEDED(hr))
            {
                // Ignore errors, this is for debugging only
                StringCchCatEx(pszOutput, cchOutput, L"[", &pszOutput, &cchOutput, 0);
                StringCchCatEx(pszOutput, cchOutput, pszName, &pszOutput, &cchOutput, 0);
                StringCchCatEx(pszOutput, cchOutput, L"]", &pszOutput, &cchOutput, 0);
                CoTaskMemFree(pszName);
            }
            psi->Release();
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = SHStrDup(szFullName, ppsz);
    }
    return hr;
}

HRESULT GetSelectionFromSite(IUnknown* punkSite, BOOL fNoneImpliesFolder, IShellItemArray** ppsia)
{
    *ppsia = NULL;
    IFolderView2* pfv;
    HRESULT hr = IUnknown_QueryService(punkSite, SID_SFolderView, IID_PPV_ARGS(&pfv));
    if (SUCCEEDED(hr))
    {
        hr = pfv->GetSelection(fNoneImpliesFolder, ppsia);
        pfv->Release();
    }
    return hr;
}

void DeletePerUserDialogState()
{
    IFileDialog* pfd;
    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
    if (SUCCEEDED(hr))
    {
        // Delete window size, MRU and other saved data for testing initial case
        pfd->ClearClientData();
        pfd->Release();
    }
}

void ReportSelectedItems(IUnknown* punkSite, IShellItemArray* psia)
{
    DWORD cItems;
    HRESULT hr = psia->GetCount(&cItems);
    for (DWORD i = 0; SUCCEEDED(hr) && (i < cItems); i++)
    {
        IShellItem* psi;
        hr = psia->GetItemAt(i, &psi);
        if (SUCCEEDED(hr))
        {
            PWSTR pszName;
            hr = GetIDListName(psi, &pszName);
            if (SUCCEEDED(hr))
            {
                HWND hwnd;
                IUnknown_GetWindow(punkSite, &hwnd);
                int nButton;
                const TASKDIALOG_COMMON_BUTTON_FLAGS buttonFlags = (i == (cItems - 1)) ? TDCBF_OK_BUTTON : TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON;
                WCHAR szMsg[128];
                StringCchPrintf(szMsg, ARRAYSIZE(szMsg), L"Item %d of %d added to basket", i + 1, cItems);
                if (SUCCEEDED(TaskDialog(hwnd, 0, L"Items Addded to Basket", szMsg, pszName, buttonFlags, NULL, &nButton)))
                {
                    hr = (nButton == IDCANCEL) ? HRESULT_FROM_WIN32(ERROR_CANCELLED) : S_OK;
                }
                CoTaskMemFree(pszName);
            }
            psi->Release();
        }
    }
}

void ReportSelectedItemsFromSite(IUnknown* punkSite)
{
    IShellItemArray* psia;
    HRESULT hr = GetSelectionFromSite(punkSite, TRUE, &psia);
    if (SUCCEEDED(hr))
    {
        ReportSelectedItems(punkSite, psia);
        psia->Release();
    }
}

/* Picking a file ****************************************************************************************************************/

void PickItem()
{
    IFileDialog* pfd;
    if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
    {
        if (SUCCEEDED(pfd->Show(NULL)))
        {
            IShellItem* psi;
            if (SUCCEEDED(pfd->GetResult(&psi)))
            {
                PWSTR pszPath;
                if (SUCCEEDED(GetIDListName(psi, &pszPath)))
                {
                    MessageBox(NULL, pszPath, L"Selected Item", MB_OK);
                    CoTaskMemFree(pszPath);
                }
                psi->Release();
            }
        }
        pfd->Release();
    }
}

/* Picking a container ***********************************************************************************************************/

void PickContainer()
{
    IFileDialog* pfd;
    if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
    {
        DWORD dwOptions;
        if (SUCCEEDED(pfd->GetOptions(&dwOptions)))
        {
            pfd->SetOptions(dwOptions | FOS_PICKFOLDERS);
        }

        if (SUCCEEDED(pfd->Show(NULL)))
        {
            IShellItem* psi;
            if (SUCCEEDED(pfd->GetResult(&psi)))
            {
                PWSTR pszPath;
                if (SUCCEEDED(GetIDListName(psi, &pszPath)))
                {
                    MessageBox(NULL, pszPath, L"Selected Container", MB_OK);
                    CoTaskMemFree(pszPath);
                }
                psi->Release();
            }
        }
        pfd->Release();
    }
}

/* Picking Files in Basket Mode **************************************************************************************************/

class CFileOpenBasketPickerCallback : public IFileDialogEvents, public IFileDialogControlEvents
{
public:
    CFileOpenBasketPickerCallback()
    {
    }

    // IUnknown
    IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        static const QITAB qit[] = {
            QITABENT(CFileOpenBasketPickerCallback, IFileDialogEvents),
            QITABENT(CFileOpenBasketPickerCallback, IFileDialogControlEvents),
            { 0 },
        };
        return QISearch(this, qit, riid, ppv);
    }

    // This class makes special assumptions about how it is used, specifically
    // 1) This class will only reside on the stack.
    // 2) Components that consume this object have well-defined reference lifetimes.
    //    In this case, this is only consumed by the file dialog advise and unadvise.
    //    Unadvising will release the file dialog's only reference to this object.
    //
    // Do not do this for heap allocated objects.
    IFACEMETHODIMP_(ULONG) AddRef() { return 3; }
    IFACEMETHODIMP_(ULONG) Release() { return 2; }

    // IFileDialogEvents
    IFACEMETHODIMP OnFileOk(IFileDialog* pfd)
    {
        // if this button is in the "Add" mode then do this, otherwise return S_OK
        IFileOpenDialog* pfod;
        HRESULT hr = pfd->QueryInterface(IID_PPV_ARGS(&pfod));
        if (SUCCEEDED(hr))
        {
            IShellItemArray* psia;
            hr = pfod->GetSelectedItems(&psia);
            if (SUCCEEDED(hr))
            {
                ReportSelectedItems(pfd, psia);
                psia->Release();
            }
            pfod->Release();
        }
        return S_FALSE; // S_FALSE keeps the dialog up; return S_OK to allow it to dismiss.
    }

    IFACEMETHODIMP OnFolderChanging(IFileDialog* /* pfd */, IShellItem* /* psi */)
    {
        return E_NOTIMPL;
    }

    IFACEMETHODIMP OnFolderChange(IFileDialog* /* pfd */)
    {
        return E_NOTIMPL;
    }

    IFACEMETHODIMP OnSelectionChange(IFileDialog* pfd)
    {
        // Update the text of the Open/Add button here based on the selection
        IShellItem* psi;
        HRESULT hr = pfd->GetCurrentSelection(&psi);
        if (SUCCEEDED(hr))
        {
            SFGAOF attr;
            hr = psi->GetAttributes(SFGAO_FOLDER | SFGAO_STREAM, &attr);
            if (SUCCEEDED(hr) && (SFGAO_FOLDER == attr))
            {
                pfd->SetOkButtonLabel(L"Open");
            }
            else
            {
                pfd->SetOkButtonLabel(L"Add");
            }
            psi->Release();
        }
        return S_OK;
    }

    IFACEMETHODIMP OnShareViolation(IFileDialog* /* pfd */, IShellItem* /* psi */, FDE_SHAREVIOLATION_RESPONSE* /* pResponse */) { return E_NOTIMPL; }
    IFACEMETHODIMP OnTypeChange(IFileDialog* /* pfd */) { return E_NOTIMPL; }
    IFACEMETHODIMP OnOverwrite(IFileDialog* /* pfd */, IShellItem* /* psi */, FDE_OVERWRITE_RESPONSE* /* pResponse */) { return E_NOTIMPL; }

    // IFileDialogControlEvents
    IFACEMETHODIMP OnItemSelected(IFileDialogCustomize* /* pfdc */, DWORD /* dwIDCtl */, DWORD /* dwIDItem */) { return E_NOTIMPL; }

    IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize* pfdc, DWORD dwIDCtl)
    {
        switch (dwIDCtl)
        {
        case c_idDone:
            IFileDialog* pfd;
            if (SUCCEEDED(pfdc->QueryInterface(&pfd)))
            {
                pfd->Close(S_OK);
                pfd->Release();
            }
            break;

        default:
            break;
        }

        return S_OK;
    }

    IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize* /* pfdc */, DWORD /* dwIDCtl */, BOOL /* bChecked */) { return E_NOTIMPL; }
    IFACEMETHODIMP OnControlActivating(IFileDialogCustomize* /* pfdc */, DWORD /* dwIDCtl */) { return E_NOTIMPL; }
};

// This sample demonstrates how to use the file dialog in a modal way such that
// users can easily pick multiple files. It does this by overriding the normal "Open" button
// with an "Add" button that passes the selection back to this app.
//
// One case this sample does not support is selecting folders this way. This has
// the issue of the "Open" button being overloaded for "navigate into the folder" and "add the folder."
// One way to deal with this is to add a new button, "Add Folder", the PickFilesAndFolders sample demonstrates this.
void FileOpenBasketPicker()
{
    IFileOpenDialog* pfd;
    if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
    {
        CFileOpenBasketPickerCallback foacb;
        DWORD dwCookie;
        if (SUCCEEDED(pfd->Advise(&foacb, &dwCookie)))
        {
            DWORD dwOptions;
            if (SUCCEEDED(pfd->GetOptions(&dwOptions)))
            {
                pfd->SetOptions(dwOptions | FOS_ALLOWMULTISELECT | FOS_ALLNONSTORAGEITEMS);
            }

            IFileDialog2* pfd2;
            if (SUCCEEDED(pfd->QueryInterface(&pfd2)))
            {
                pfd2->SetCancelButtonLabel(L"Done");
                pfd2->Release();
            }
            else
            {
                IFileDialogCustomize* pfdc;
                if (SUCCEEDED(pfd->QueryInterface(&pfdc)))
                {
                    pfdc->AddPushButton(c_idDone, L"Done");
                    pfdc->Release();
                }
            }

            pfd->SetTitle(L"File Open Modal Basket Picker Sample");

            // We do not process the results of the dialog since
            // the selected items are passed back via OnFileOk()
            pfd->Show(NULL); // hr intentionally ignored

            pfd->Unadvise(dwCookie);
        }
        pfd->Release();
    }
}

/* Picking Files and Folders in Basket Mode **************************************************************************************/

class CPickFilesAndFoldersCallback : public IFileDialogEvents, public IFileDialogControlEvents
{
public:
    CPickFilesAndFoldersCallback()
    {
    }

    // IUnknown
    IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        static const QITAB qit[] = {
            QITABENT(CPickFilesAndFoldersCallback, IFileDialogEvents),
            QITABENT(CPickFilesAndFoldersCallback, IFileDialogControlEvents),
            { 0 },
        };
        return QISearch(this, qit, riid, ppv);
    }

    // This class makes special assumptions about how it is used, specifically
    // 1) This class will only reside on the stack.
    // 2) Components that consume this object have well-defined reference lifetimes.
    //    In this case, this is only consumed by the file dialog advise and unadvise.
    //    Unadvising will release the file dialog's only reference to this object.
    //
    // Do not do this for heap allocated objects.
    IFACEMETHODIMP_(ULONG) AddRef() { return 3; }
    IFACEMETHODIMP_(ULONG) Release() { return 2; }

    // IFileDialogEvents
    IFACEMETHODIMP OnFileOk(IFileDialog* pfd)
    {
        ReportSelectedItemsFromSite(pfd);
        return S_FALSE; // S_FALSE keeps the dialog up, return S_OK to allows it to dismiss
    }

    IFACEMETHODIMP OnFolderChanging(IFileDialog* /* pfd */, IShellItem* /* psi */)
    {
        return E_NOTIMPL;
    }

    IFACEMETHODIMP OnFolderChange(IFileDialog* /* pfd */)
    {
        return E_NOTIMPL;
    }

    IFACEMETHODIMP OnSelectionChange(IFileDialog* pfd)
    {
        // Design for the text of the "Add" button
        // ---------------------------------------
        // Single select item      "Add file"
        // Single select folder    "Add folder"
        // Multiselect             "Add items"
        // Null select             "Add current folder"
        IFileDialogCustomize* pfdc;
        if (SUCCEEDED(pfd->QueryInterface(&pfdc)))
        {
            // GetSelectionFromSite() fails on no selection
            // When that happens, default to the current folder.
            PCWSTR pszLabel = L"Add current folder";
            IShellItemArray* psia;
            if (SUCCEEDED(GetSelectionFromSite(pfd, FALSE, &psia)))
            {
                DWORD count;
                if (SUCCEEDED(psia->GetCount(&count)))
                {
                    if (count == 1)
                    {
                        IShellItem* psi;
                        if (SUCCEEDED(psia->GetItemAt(0, &psi)))
                        {
                            SFGAOF attributes;
                            if (S_OK == psi->GetAttributes(SFGAO_FOLDER, &attributes))
                            {
                                pszLabel = L"Add folder";
                            }
                            else
                            {
                                pszLabel = L"Add file";
                            }
                            psi->Release();
                        }
                    }
                    else if (count > 1)
                    {
                        pszLabel = L"Add items";
                    }
                }
                psia->Release();
            }
            pfdc->SetControlLabel(c_idAdd, pszLabel);
            pfdc->Release();
        }

        return S_OK;
    }

    IFACEMETHODIMP OnShareViolation(IFileDialog* /* pfd */, IShellItem* /* psi */, FDE_SHAREVIOLATION_RESPONSE* /* pResponse */) { return E_NOTIMPL; }
    IFACEMETHODIMP OnTypeChange(IFileDialog* /* pfd */) { return E_NOTIMPL; }
    IFACEMETHODIMP OnOverwrite(IFileDialog* /* pfd */, IShellItem* /* psi */, FDE_OVERWRITE_RESPONSE* /* pResponse */) { return E_NOTIMPL; }

    // IFileDialogControlEvents
    IFACEMETHODIMP OnItemSelected(IFileDialogCustomize* /* pfdc */, DWORD /* dwIDCtl */, DWORD /* dwIDItem */) { return E_NOTIMPL; }

    IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize* pfdc, DWORD dwIDCtl)
    {
        switch (dwIDCtl)
        {
        case c_idAdd:
            // Instead of using IFileDialog::GetCurrentSelection(), we need to get the
            // selection from the view to handle the "no selection implies folder" case
            ReportSelectedItemsFromSite(pfdc);
            break;

        case c_idDone:
        {
            IFileDialog* pfd;
            if (SUCCEEDED(pfdc->QueryInterface(&pfd)))
            {
                pfd->Close(S_OK);
                pfd->Release();
            }
        }
        break;

        default:
            break;
        }

        return S_OK;
    }

    IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize* /* pfdc */, DWORD /* dwIDCtl */, BOOL /* bChecked */) { return E_NOTIMPL; }
    IFACEMETHODIMP OnControlActivating(IFileDialogCustomize* /* pfdc */, DWORD /* dwIDCtl */) { return E_NOTIMPL; }
};

void PickFilesAndFolders()
{
    IFileOpenDialog* pfd;
    if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
    {
        CPickFilesAndFoldersCallback foacb;
        DWORD dwCookie;
        if (SUCCEEDED(pfd->Advise(&foacb, &dwCookie)))
        {
            DWORD dwOptions;
            if (SUCCEEDED(pfd->GetOptions(&dwOptions)))
            {
                pfd->SetOptions(dwOptions | FOS_ALLOWMULTISELECT | FOS_ALLNONSTORAGEITEMS);
            }

            IFileDialogCustomize* pfdc;
            if (SUCCEEDED(pfd->QueryInterface(&pfdc)))
            {
                // The spacing pads the button a bit.
                pfdc->AddPushButton(c_idAdd, L" Add current folder ");
                pfdc->Release();
            }

            IFileDialog2* pfd2;
            if (SUCCEEDED(pfd->QueryInterface(&pfd2)))
            {
                pfd2->SetCancelButtonLabel(L"Done");
                pfd2->Release();
            }
            else
            {
                // pre Win7 we need to add a 3rd button, ugly but workable
                IFileDialogCustomize* pfdc;
                if (SUCCEEDED(pfd->QueryInterface(&pfdc)))
                {
                    pfdc->AddPushButton(c_idDone, L"Done");
                    pfdc->Release();
                }
            }

            pfd->SetTitle(L"Pick Files and Folder Sample");

            // the items selected are passed back via OnFileOk()
            // so we don't process the results of the dialog
            pfd->Show(NULL); // hr intentionally ignored
            pfd->Unadvise(dwCookie);
        }
        pfd->Release();
    }
}

// Application entry point
//int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
int main()
{
    HRESULT hr = OleInitialize(0);
    if (SUCCEEDED(hr))
    {
        TASKDIALOGCONFIG taskDialogParams = { sizeof(taskDialogParams) };
        taskDialogParams.dwFlags = TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION;

        TASKDIALOG_BUTTON const buttons[] =
        {
            { IDC_PICKITEM,             L"Pick File" },
            { IDC_PICKCONTAINER,        L"Pick Folder" },
            { IDC_FILEOPENBASKETPICKER, L"Pick Files (Basket Mode)" },
            { IDC_PICKFILESANDFOLDERS,  L"Pick Files and Folders (Basket Mode)" },
        };

        taskDialogParams.pButtons = buttons;
        taskDialogParams.cButtons = ARRAYSIZE(buttons);
        taskDialogParams.pszMainInstruction = L"Pick the file dialog samples you want to try";
        taskDialogParams.pszWindowTitle = L"Common File Dialog Modes";

        while (SUCCEEDED(hr))
        {
            int selectedId;
            hr = TaskDialogIndirect(&taskDialogParams, &selectedId, NULL, NULL);
            if (SUCCEEDED(hr))
            {
                if (selectedId == IDCANCEL)
                {
                    break;
                }
                else if (selectedId == IDC_PICKITEM)
                {
                    PickItem();
                }
                else if (selectedId == IDC_PICKCONTAINER)
                {
                    PickContainer();
                }
                else if (selectedId == IDC_FILEOPENBASKETPICKER)
                {
                    FileOpenBasketPicker();
                }
                else if (selectedId == IDC_PICKFILESANDFOLDERS)
                {
                    PickFilesAndFolders();
                }
            }
        }
        OleUninitialize();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值