【问题标题】:Receiving parent's window handle on IShellFolder/IShellFolder2 EnumObjects implementations while searching?在搜索时接收 IShellFolder/IShellFolder2 EnumObjects 实现的父窗口句柄?
【发布时间】:2018-02-08 09:23:04
【问题描述】:

在我正在处理的命名空间扩展项目中接收父窗口句柄时,我摸不着头脑。

用例如下:

  1. 用户通过 Windows 资源管理器浏览到虚拟文件夹
  2. 用户执行搜索(上面的搜索框)
  3. 我需要在搜索开始前检索搜索框的文本。

我已经设法在带有 ISearchBoxInfo 接口 (https://msdn.microsoft.com/en-us/library/windows/desktop/dd562062%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396) 的测试控制台应用程序上做到这一点

有两种方法可以接收指向此接口的指针:

  1. 使用 IObjectWithSite::SetSite 调用 - 这不相关,因为搜索是在不同的线程中进行的,我无法在这些线程之间共享 COM 对象
  2. 识别窗口句柄并通过 IWebBrowser2 接口检索 ISearchBox。

两种方法都不起作用,因为当我执行搜索时,EnumObjects 是通过不同的线程调用的,我无法找到识别谁是父资源管理器窗口的方法。

在进行搜索时,来的hwnd始终为null,如下:

这是 EnumObjects 代码:

//  Allows a client to determine the contents of a folder by
//  creating an item identifier enumeration object and returning
//  its IEnumIDList interface. The methods supported by that
//  interface can then be used to enumerate the folder's contents.
HRESULT CFolderViewImplFolder::EnumObjects(HWND  hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
{
    HRESULT hr;
    _fd = hwnd;

    if (hwnd != NULL) // NULL when performing a search
    {
        const int n = GetWindowTextLength(hwnd);
        wstring text(n + 1, L'#');
        if (n > 0)
        {
            GetWindowText(hwnd, &text[0], text.length());
        }
    }

    if (m_nLevel >= g_nMaxLevel)
    {
        *ppenumIDList = NULL;
        hr = S_FALSE; // S_FALSE is allowed with NULL out param to indicate no contents.
    }
    else
    {
        CFolderViewImplEnumIDList *penum = new (std::nothrow) CFolderViewImplEnumIDList(grfFlags, m_nLevel + 1, this);
        hr = penum ? S_OK : E_OUTOFMEMORY;
        if (SUCCEEDED(hr))
        {
            hr = penum->Initialize();
            if (SUCCEEDED(hr))
            {
                hr = penum->QueryInterface(IID_PPV_ARGS(ppenumIDList));
            }
            penum->Release();
        }
    }

    return hr;
}

除了我的测试之外,我还实现了 IShellFolderViewCB.MessageSFVCB,它在 正确 线程上运行,我可以在其中检索 IShellBrowser 和句柄 -当我进行搜索时,我遇到以下消息:

103, 103, 67, UnmergeMenu, WindowClosing, 106, ViewRelease, ViewRelease

之后,不再发布消息(无论我是否重新搜索) - 第一个断点始终位于 EnumObjects 方法,我没有关于父窗口的上下文。

任何光线脱落都会很好。

== 编辑 ==

我想出了一些解决方法 - 这并不适用于所有情况,但适用于大多数情况 - 其他选项仍然不错。

每当使用 hwnd = NULL 调用 EnumObjects 时,我都会执行以下操作:(它在 C# 中 - 但它也可以在 C++ 中轻松实现)

static public string PrepareSearch(string currentFolderName, IntPtr hwnd)
        {
            SHDocVw.ShellWindows shellWindows = new ShellWindows();

            SHDocVw.IWebBrowser2 foundBrowser = null;
            bool wasFound = false;
            string foundTxt = null;
            foreach (SHDocVw.IWebBrowser2 eie in shellWindows)
            {
                // as the search is conducted in another thread, while the main window is "free" and in a search mode, it should be first busy.
                string locName = eie.LocationName;
                string exeName = eie.FullName;

                if (!string.IsNullOrEmpty(exeName) && exeName.IndexOf("explorer.exe", StringComparison.OrdinalIgnoreCase) >= 0 &&
                    !string.IsNullOrEmpty(locName) &&
                    eie.Busy && eie.ReadyState == tagREADYSTATE.READYSTATE_LOADING)
                {
                    // in here we're ok, we would also want to get the window title to make sure we're searching correctly.
                    string title = NSEFolder.WindowText((IntPtr)eie.HWND);

                    if (!string.IsNullOrEmpty(title) &&
                        title.IndexOf(currentFolderName) >= 0)
                    {
                        // one or more windows were found, ignore the quick search.
                        if (wasFound)
                        {
                            return null;
                        }

                        wasFound = true;
                        foundTxt = locName;
                    }

                }                                             
            }

            if (wasFound && !string.IsNullOrEmpty(foundTxt))
            {
                return foundTxt;

            }


            return null;
        }

基本上我会遍历所有资源管理器窗口,试图找到一个确实是“explorer.exe”+ 非空搜索字符串 (LocationName) + 忙... + 标题包含当前文件夹名称的名称。

当 2 个窗口忙碌并且标题中具有相同的文件夹名称时,它会失败 - 但这可能已经足够了......这里不确定。

【问题讨论】:

    标签: c++ windows multithreading shell-namespace-extension


    【解决方案1】:

    所以,在与微软交谈之后 - 不可能这样做。 我添加的解决方法是有效的(虽然并不完美)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-30
      相关资源
      最近更新 更多