Как сделать встроенный проводник IShellView доступным для просмотра (то есть запускать событие BrowseObject)

Я «встраиваю Windows Explorer» в свое приложение Win32. (Технически я размещаю ShellView папки в моем приложении, что и делает проводник Windows).

Проблема в том, что представление никогда не вызывает IShellBrowser.BrowseObject. Вместо того, чтобы просить меня перейти в новое место (через событие BrowseObject), представление оболочки запускает копию проводника Windows для просмотра папки.

Я хочу, чтобы вид оболочки по умолчанию (в просторечии известный как DefView) был доступен для просмотра.


Пример кода руководства

Сначала нам нужно получить IShellFolder для некоторой папки, которую я хочу отобразить. Самая простая папка - это папка рабочего стола, поскольку для нее есть SHGetDesktopFolder API :

folder: IShellFolder;

SHGetDesktopFolder({out} folder);

Затем мы просим папку рабочего стола передать ее IShellView :

view: IShellView;

folder.CreateViewObject(Self.Handle, IID_IShellView, {out}view);

Теперь, когда у нас есть IShellView папки (в отличие от IContextMenu или IExtractIcon ), мы теперь хотим показать представление оболочки вызвав IShellView.CreateViewWindow :

hostRect: TRect; //where the view is to display itself
folderSettings: TFolderSettings; //display settings for the view
hwndView: HWND; //the newly created view's window handle

folderSettings.ViewMode := FVM_DETAILS; //details mode please, rather than icon/list/etc
folderSettings.fFlags := 0;
hostRect := Rect(20, 20, 660, 500); //the view can position itself there

view.CreateViewWindow(nil, folderSettings, shellBrowser, {var}hostRect, {out}hView);
view.UIActivate(SVUIA_ACTIVATE_NOFOCUS);

и вуаля, узнаваемый список оболочки, показывающий мой рабочий стол:

enter image description here

в комплекте с обработчиками контекстного меню:

enter image description here

За исключением того, что когда я нажимаю Открыть , а не отправляю мне Событие BrowseObject через предоставленный мной интерфейс IShellBrowser открывает новое окно:

enter image description here

То же самое происходит, когда я дважды щелкаю.

Как сделать Microsoft DefView доступным для просмотра?


Обновление Реализация ShellBrowser

При создании IShellView вы должны предоставить ему объект, реализующий IShellBrowser . Этот объект ShellBrowser используется для обратной связи представления с размещающим контейнером.

Из 15 методов я внимательно рассмотрю только четыре - остальные могут вернуть E_NOTIMPL (что, конечно, может быть проблемой):

{IShellBrowser}
  • BrowseObject (PCUIDLIST_RELATIVE pidl, UINT wFlags);

     // Сообщает проводнику Windows перейти к другой папке. 
     // Это уведомление, которое я хочу! 
    Result: = BrowseToAnotherFolder (pidl, wFlags); 
     
  • GetControlWindow (UINT id, HWND * lphwnd);

     // Получает дескриптор окна для элемента управления браузера. 
     // Поскольку у меня нет панели инструментов, дерева, окна состояния или выполнения, возвращаем 0 {{ 1}} lphwnd: = 0; 
    Result: = S_OK; 
     
  • SendControlMsg (UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT * pret);

     // Отправляет управляющие сообщения либо на панель инструментов, либо в строку состояния в Windows 
     // Из MSDN: Примечания для разработчиков 
     // Если в вашем проводнике Windows нет этих элементов управления, вы можете вернуть E_NOTIMPL.
    Result: = E_NOTIMPL; 
     
  • GetViewStateStream (DWORD grfMode, IStream ** ppStrm);

     // Получает интерфейс IStream, который можно использовать для хранения информации о состоянии конкретного представления . 
    Результат: = E_NOTIMPL; // у меня нет потока, который я мог бы передать вам 
     
  • TranslateAcceleratorSB (LPMSG lpmsg, WORD wID);

     // Переводит нажатия клавиш ускорителя, предназначенные для фрейма браузера 
     / / пока вид активен. 
    Результат: = E_NOTIMPL; // я не буду переводить 
     
  • OnViewWindowActive (IShellView * ppshv);

     // Вызывается представлением оболочки, когда окно просмотра или одно из его дочерних 
     / / windows получает фокус или становится активным. 
    Результат: = S_OK; // я получил уведомление, спасибо 
     
  • QueryActiveShellView (IShellView ** ppshv);

     // Извлекает текущий активный (отображаемый) объект представления оболочки. 
    ppshv: = view; 
    Результат: = S_OK; // я бы никогда не посмотрел другой, вы знаете, что 
     
  • EnableModelessSB (BOOL fEnable);

     // Указывает проводнику Windows включить или отключить его немодальные диалоговые окна. 
    Результат: = S_OK; // Вы хотите включить немодальные диалоговые окна? Интересно. 
     
  • InsertMenusSB (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);

     // Позволяет контейнеру вставлять свои группы меню в составное 
     // меню, которое отображается, когда расширенное пространство имен просматривается или используется. 
    Результат: = E_NOTIMPL; // у меня нет меню 
     
  • RemoveMenusSB (HMENU hmenuShared);

     // Разрешает контейнеру удалить любой из своих элементов меню 
     // из составного меню на месте и чтобы освободить все связанные ресурсы.
    Результат: = E_NOTIMPL; // у меня нет меню 
     
  • SetMenuSB (HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject);

     // Устанавливает составное меню в окно просмотра. 
    Результат: = E_NOTIMPL; // у меня нет меню 
     
  • SetStatusTextSB

     // Устанавливает и отображает текст состояния о текущем объекте 
     // в строке состояния окна фрейма контейнера. {{1 }} Результат: = E_NOTIMPL; // у меня нет строки состояния 
     
  • SetToolbarItems (LPTBBUTTONSB lpButtons, UINT nButtons, UINT uFlags);

     // Добавляет элементы панели инструментов на панель инструментов Проводника Windows. 
    Результат: = E_NOTIMPL;// у меня нет панели инструментов 
     

Затем есть предок IOleWindow :

  • GetWindow ([out] HWND * phwnd);

     // Извлекает дескриптор одного из окна, участвующие в 
     // активации на месте (окно фрейма, документа, родителя или объекта на месте). 
    phwnd: = Self.Handle; // это снова дескриптор вашего родителя 
    Result: = S_OK; 
     
  • `ContextSensitiveHelp ([в] BOOL fEnterMode);

     // Определяет, нужно ли переходить в режим контекстно-зависимой помощи 
     // во время сеанса активации на месте. 
     
    Result: = S_OK; // Хорошо, спасибо, я запомню это 
     

IServiceProvider

function TShellBrowser.QueryService(const rsid, iid: TGuid; out Obj): HResult;
var
    sb: IShellBrowser;
    s: string;
const
    SID_SInPlaceBrowser: TGUID = '{1D2AE02B-3655-46CC-B63A-285988153BCA}';
    SID_IShellBrowser: TGUID = '{000214E2-0000-0000-C000-000000000046}';
begin
    {
        This code is executed when you double click a folder.
        It's needed to implement inline browsing.
        If you double click a folder the default action of IShellBrowser is to open a new Windows Explorer.
        To open the folder in the current window you must implement IServiceProvider.

        http://blogs.msdn.com/b/ieinternals/archive/2009/12/30/windows-7-web-browser-control-will-not-browse-file-system.aspx
    }
    Result := E_NOINTERFACE; //Return $E_NOINTERFACE

    OutputDebugString(PChar('TShellBrowser.QueryService: '+IIDToString(rsid)));
    {
        Make a small change to your application to enable the filesystem object to navigate in-place within the WebOC
        when running on Windows 7.
        To do so, your hosting application will implement the IServiceProvider interface,
        and hand back the WebBrowser control’s SID_SShellBrowser when asked for SID_SInPlaceBrowser
    }
    if IsEqualGUID(rsid, SID_SInPlaceBrowser) then
    begin
        sb := Self as IShellBrowser;
        Pointer(Obj) := Pointer(sb);
        sb._AddRef;
        Result := S_OK;
    end;
end;

Bonus Reading


См. Также

9
задан Community 23 May 2017 в 12:01
поделиться