搜索时在IShellFolder / IShellFolder2 EnumObjects实现上接收父窗口句柄?

时间:2018-02-08 09:23:05

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

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

用例如下:

  1. 用户通过Windows资源管理器浏览虚拟文件夹
  2. 用户执行搜索(上面的搜索框)
  3. 我需要在搜索开始之前检索搜索框的文字。
  4. 我已经设法在带有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。
    3. 这两种方法都不像我执行搜索那样工作, EnumObjects 是通过不同的线程调用的,我无法找到识别父浏览器窗口的方法。< / p>

      进行搜索时,来的hwnd总是为null,如下所示: EnumObjects while searching

      这是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;
              }
      

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

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

1 个答案:

答案 0 :(得分:0)

因此,在与微软谈话之后 - 不可能这样做。 我添加的解决方法是有效的(thoguh不完美)。