【问题标题】:virtual folder is invisible in the CFileDialog in windows 7虚拟文件夹在 Windows 7 的 CFileDialog 中不可见
【发布时间】:2017-11-02 23:47:40
【问题描述】:

--------------更新第五次-------------------- ------------

            if (fIsFolder)
            {
                dwAttribs |= SFGAO_FOLDER;
            }
            else
            {
                dwAttribs |= SFGAO_SYSTEM;

                dwAttribs |= SFGAO_FILESYSTEM;
            }

            if (nLevel < g_nMaxLevel)
            {
                dwAttribs |= SFGAO_HASSUBFOLDER;

                dwAttribs |= SFGAO_FILESYSANCESTOR;
            }

现在这个在应用程序 A、stackoverflow 图片上传文件对话框和常规文件夹资源管理器中正常工作。

----------------------------------- -------更新第四次-------------------------------------------- ----------------- 添加 dwAttribs |= SFGAO_SYSTEM; 之后,现在至少对于应用程序 A,它在文件对话框中按预期工作。但该文件夹在常规文件夹对话框或CWFileDialog 中仍然不可点击。

            if (fIsFolder)
            {
                dwAttribs |= SFGAO_FOLDER;

                dwAttribs |= SFGAO_FILESYSTEM;

                dwAttribs |= SFGAO_FILESYSANCESTOR;
            }
            else
            {
                dwAttribs |= SFGAO_SYSTEM;// this line of code works better

                dwAttribs |= SFGAO_FILESYSTEM;
            }

------------------------更新第三次---------- ------------------------------------------- 这是虚拟文件夹的ISHellFolder中的代码:

编辑以下代码添加dwAttribs |= SFGAO_FILESYSTEM;后,在文件夹视图中双击该文件夹时无法浏览该文件夹。但是可以在树形视图中左键打开它。

 HRESULT CFolderViewImplFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, ULONG *rgfInOut)
{
// If SFGAO_FILESYSTEM is returned, GetDisplayNameOf(SHGDN_FORPARSING) on that item MUST
// return a filesystem path.
HRESULT hr = E_INVALIDARG;

DWORD dwAttribs = 0;

dwAttribs |= SFGAO_FILESYSTEM;

if (1 == cidl)
{
    int nLevel = 0;
    hr = _GetLevel(apidl[0], &nLevel);
    if (SUCCEEDED(hr))
    {
        BOOL fIsFolder = FALSE;
        hr = _GetFolderness(apidl[0], &fIsFolder);
        if (SUCCEEDED(hr))
        {
            
            if (fIsFolder)
            {
                dwAttribs |= SFGAO_FOLDER;
            }
            if (nLevel < g_nMaxLevel)
            {
                dwAttribs |= SFGAO_HASSUBFOLDER;
            }
  
        }
    }
}

*rgfInOut &= dwAttribs;

return hr;
}` 

或者

DWORD dwAttribs = 0;

if (1 == cidl)
{
    int nLevel = 0;
    hr = _GetLevel(apidl[0], &nLevel);
    if (SUCCEEDED(hr))
    {
        BOOL fIsFolder = FALSE;
        hr = _GetFolderness(apidl[0], &fIsFolder);
        if (SUCCEEDED(hr))
        {
            
            if (fIsFolder)
            {
                dwAttribs |= SFGAO_FOLDER;

                dwAttribs |= SFGAO_FILESYSTEM;

                dwAttribs |= SFGAO_FILESYSANCESTOR;
            }
            else
            {
                dwAttribs |= SFGAO_SYSTEM;
            }

            if (nLevel < g_nMaxLevel)
            {
                dwAttribs |= SFGAO_HASSUBFOLDER;
            }
        }
    }
 }

*rgfInOut &= dwAttribs;

其他代码同update 2nd。 奇怪的是,在我编辑这些代码之后,通常使用CFileDialog 的应用程序A(不包装它,未将m_bPickNonFileSysFoldersMode 设置为true)可以按我的预期正常显示所有虚拟文件夹。 但在所有其他应用程序中(包括使用CWFileDilaom_bPickNonFileSysFoldersMode 设置为true 的应用程序仍然无法查看虚拟文件夹。

---------------------------------------更新第二次------ -------------------

我编写了一个派生自 CFileDialog 的简单类:

class CWFileDlg : public CFileDialog
{
public:
CWFileDlg(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
    LPCTSTR lpszDefExt = NULL,
    LPCTSTR lpszFileName = NULL,
    DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
    LPCTSTR lpszFilter = NULL,
    CWnd* pParentWnd = NULL,
    DWORD dwSize = 0,
    BOOL bVistaStyle = TRUE);

~CWFileDlg();
};

CWFileDlg::CWFileDlg(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
                    LPCTSTR lpszDefExt,
                    LPCTSTR lpszFileName,
                    DWORD dwFlags,
                    LPCTSTR lpszFilter,
                    CWnd* pParentWnd,
                    DWORD dwSize,
                    BOOL bVistaStyle) : CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd, dwSize, bVistaStyle)
{
    m_bPickNonFileSysFoldersMode = TRUE;
}

CWFileDlg::~CWFileDlg()
{

}

那我这样称呼它:

CWFileDlg dlg(TRUE, NULL, 0, OFN_SHAREAWARE | OFN_ENABLESIZING | OFN_ALLOWMULTISELECT, L"all(*.*)|*.*||", this);

BOOL IsPickNonFileSysFoldersMode = dlg.IsPickNonFileSysFoldersMode();
//the value it gets is 1, which is TRUE

INT_PTR result = dlg.DoModal();

但在弹出的对话框中,虚拟文件​​夹仍然不可见。它的树视图也是不可见的。 - - - - - - - - - - - - - - - - - - - - - 更新 - - - - ---------------------

protected:

BOOL m_bVistaStyle;
BOOL m_bPickFoldersMode;
BOOL m_bPickNonFileSysFoldersMode;
DWORD m_dwCookie;
void* m_pIFileDialog;
void* m_pIFileDialogCustomize;

m_bPickNonFileSysFoldersMode 不是公共类型。我怎样才能将其设置为 TRUE ?

Error   1   error C2248: 'CFileDialog::m_bPickNonFileSysFoldersMode' : cannot access protected member declared in class 'CFileDialog'   c:\users\liyuan.liu\documents\dp-dll\testvirtualfolder\browser2\browser2\browser2dlg.cpp    166 1   browser2

通过使用 Microsoft windows 示例代码,我使用 shell 命名空间扩展在 windows 7 上安装了一个虚拟文件夹。 以下屏幕截图是使用常规文件夹浏览器打开它:

然后我写了一个可以创建文件对话框的项目:

CFileDialog dlg(TRUE, NULL, 0, OFN_SHAREAWARE | OFN_ENABLESIZING | OFN_ALLOWMULTISELECT, L"all(*.*)|*.*||", this);
INT_PTR result = dlg.DoModal();

但是,在文件浏览器中,虚拟文件​​夹是不可见的:

但是!当我尝试将屏幕截图上传到 StackOverflow(我使用的网络浏览器是 chrome)时,用于选择文件的文件对话框可以显示虚拟文件夹的树视图(仅树视图):

通过谷歌搜索,似乎 CFileDialog 不支持显示虚拟文件夹,因为它实际上并不存在于系统中。有什么解决方案可以解决这个问题吗? 我也试过

bi.pidlRoot = pidlVirtual;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_RETURNFSANCESTORS | BIF_BROWSEINCLUDEFILES | BIF_BROWSEFILEJUNCTIONS;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);

也不行。

【问题讨论】:

  • 您是否创建并注册了 32 位和 64 位 NSE?
  • CFileDialog 在 Visual Studio 2008 及更高版本中默认包装 IFileDialogIFileDialog 绝对支持虚拟文件夹和 SNE(这是它对旧的 Get(Open|Save)FileName() API 的重大改进)。您使用的是什么版本的 Visual Studio?也许您的版本中的 CFileDialog 正在使用较旧的仅文件系统 API。你试过直接使用IFileDialog吗?

标签: c++ windows registry shell-extensions shell-namespace-extension


【解决方案1】:

不幸的是,文件对话框显示的是打开它的应用程序的功能。从Vista开始,使用的是IFileDialog接口,它通过IFileDialog::SetOptions method定义了一组选项。

FOS_FORCEFILESYSTEM 标志确保返回的项目是文件系统项目 (SFGAO_FILESYSTEM),这取决于您如何编写扩展程序。 SFGAO_FILESYSTEM 应该响起,这是IShellFolder::GetAttributesOf method 可以返回的标志之一。如果你所做的是真的是虚拟的(即:如果你不返回这个标志),当 IFileDialog 像这样配置时,它们将不会显示。

如果您使用不同的应用程序(记事本、word、excel、浏览器等)测试您的扩展程序,您会发现有时会看到,有时不会。

深入研究 MFC 的代码 (dlgfile.cpp),您会发现:

    // We only expect and handle file system paths (for compatibility with GetOpenFileName functionality), so set the
    // "force file system" flag which enables GetOpenFileName-like download behavior for non file system paths, unless
    // the m_bPickNonFileSysFoldersMode is set to allow picking non-file system folders (like libraries in Windows 7).
    dwFlags |= FOS_FORCEFILESYSTEM;
    if (m_bPickNonFileSysFoldersMode)
    {
        dwFlags &= ~FOS_FORCEFILESYSTEM;
    }

因此,您需要将 m_bPickNonFileSysFoldersMode 设置为 TRUE,CFileDialog 才能显示您的扩展名。在 MFC 中,您必须从 CFileDialog 派生,因为该成员受到保护(顺便说一句,这是一个愚蠢的 MFC 设计决策),例如:

class MyFileDialog : public CFileDialog
{
public:
    MyFileDialog(LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL);
};

MyFileDialog::MyFileDialog(LPCTSTR lpszDefExt, LPCTSTR lpszFileName, DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) : CFileDialog(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
    m_bPickNonFileSysFoldersMode = TRUE;
}

要记住的最后一件事:确保您的虚拟文件夹(命名空间扩展名等)与使用 CFileDialog 的应用注册的位数(x86 与 x64)相同。

但它不会修复您不拥有但使用此标志的其他应用...

【讨论】:

  • 如何将 CFileDialog 的 m_bPickNonFileSysFoldersMode 设置为 TRUE ?似乎这个变量无法从 CFileDialog 中访问。当我检查 CFileDialog 的定义时,它是 class CFileDialog : public CCommonDialog
  • 该成员受保护,因此您必须从 CFileDialog 派生并在构造函数中将值设置为 TRUE。
  • 我将它包装起来,并将标志设置为 TRUE,但它仍然不可见。请查看我的更新。
  • GetAttributesOf 中的根文件夹返回什么?
  • 我添加了SFGAO_FILESYSTEM,请查看我在第三个中的更新
猜你喜欢
  • 2011-12-08
  • 2012-06-22
  • 2010-10-26
  • 1970-01-01
  • 2010-11-21
  • 2016-02-10
  • 1970-01-01
  • 1970-01-01
  • 2013-10-22
相关资源
最近更新 更多