Получение дескриптора родительского окна в реализациях IShellFolder / IShellFolder2 EnumObjects при поиске?

Я ломаю голову при получении дескриптора родительского окна в проекте расширения пространства имен, над которым я работаю.

Вариант использования выглядит следующим образом:

  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. Идентификация дескриптора окна и получение ISearchBox через интерфейс IWebBrowser2.

Оба метода не работают, как при выполнении поиска, EnumObjects вызывается через другой поток, и я не могу найти способ определить, кто является родительским окном проводника.

При выполнении поиска значение hwnd всегда равно нулю следующим образом:
EnumObjects при поиске

Это код 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, у меня нет контекста о родительском окне.

Любая потеря света была бы хороша.

== РЕДАКТИРОВАТЬ ==

Я придумал обходной путь — это не идеально для всех случаев, но работает для большинства из них — другие варианты все равно будут хорошими.

Всякий раз, когда EnumObjects вызывается с hwnd = NULL, я делаю следующее: (это в 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) + busy … + title содержит имя текущего имени папки.

он потерпит неудачу, когда 2 окна заняты и имеют одно и то же имя папки в заголовке — но это может быть достаточно хорошо … Не уверен, что здесь.

0

Решение

Итак, после разговора с Microsoft — сделать это невозможно.
Обходной путь, который я добавил, является допустимым (хотя и не идеальным).

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]